0
2
web: Profiles, galleries, feeds, stories and search read from grain-serve
Only what this pull adds. It is built on grain runs on a Rust server modelled on knotless, without hatk.
test/resolveRouteActor.test.ts+3−3
| @@ -11,9 +11,9 @@ const FOLLOW_URI = `at://did:plc:me/social.grain.graph.follow/1`; | ||
let following: string | undefined; | ||
let fetches = 0; | ||
| ||
// Mocked by resolved path: the $hatk and $lib aliases resolve before vi.mock matches. | ||
vi.mock("../hatk.generated.client.ts", () => ({ | ||
callXrpc: async (_nsid: string, _input: unknown) => { | ||
// Mocked by resolved path: the $lib alias resolves before vi.mock matches. | ||
vi.mock("../web/src/lib/xrpc/index.ts", () => ({ | ||
query: async (_nsid: string, _input: unknown) => { | ||
fetches++; | ||
return { | ||
did: ALICE, | ||
test/storyViews.test.ts+4−4
| @@ -7,9 +7,9 @@ import { QueryClient } from "@tanstack/svelte-query"; | ||
const calls: { nsid: string; input: unknown }[] = []; | ||
let fail = false; | ||
| ||
// Mocked by resolved path: the $hatk and $lib aliases resolve before vi.mock matches. | ||
vi.mock("../hatk.generated.client.ts", () => ({ | ||
callXrpc: async (nsid: string, input: unknown) => { | ||
// Mocked by resolved path: the $lib alias resolves before vi.mock matches. | ||
vi.mock("../web/src/lib/xrpc/index.ts", () => ({ | ||
call: async (nsid: string, input: unknown) => { | ||
calls.push({ nsid, input }); | ||
if (fail) throw new Error("offline"); | ||
return {}; | ||
| @@ -88,7 +88,7 @@ describe("markStoriesViewed", () => { | ||
| ||
expect(calls).toEqual([ | ||
{ | ||
nsid: "social.grain.unspecced.markStoriesViewed", | ||
nsid: "social.grain.story.markViewed", | ||
input: { stories: [a3.uri] }, | ||
}, | ||
]); | ||
web/src/lib/components/atoms/ExifInfo.svelte+1−1
| @@ -1,5 +1,5 @@ | ||
<script lang="ts"> | ||
import type { ExifView } from '$hatk/client' | ||
import type { ExifView } from '$lib/lexicons/social/grain/photo/defs.ts' | ||
import { Camera, Aperture } from 'lucide-svelte' | ||
import { cleanCameraName } from '$lib/utils/cameraName' | ||
| ||
web/src/lib/components/atoms/LocationInput.svelte+1−1
| @@ -2,7 +2,7 @@ | ||
import { MapPin, LoaderCircle } from 'lucide-svelte' | ||
import { searchLocations, formatLocationName, formatGeoContext, formatStreet, extractAddress, type NominatimResult } from '$lib/utils/nominatim' | ||
import { latLonToH3 } from '$lib/utils/h3' | ||
import type { Gallery } from '$hatk/client' | ||
import type { Main as Gallery } from '$lib/lexicons/social/grain/gallery.ts' | ||
| ||
export type AddressData = NonNullable<Gallery['address']> | ||
| ||
web/src/lib/components/molecules/Comment.svelte+6−4
| @@ -1,5 +1,6 @@ | ||
<script lang="ts"> | ||
import type { CommentView } from '$hatk/client' | ||
import type { CommentView } from '$lib/lexicons/social/grain/comment/defs.ts' | ||
import type { PhotoView } from '$lib/lexicons/social/grain/photo/defs.ts' | ||
import { callXrpc } from '$hatk/client' | ||
import { createMutation, useQueryClient } from '@tanstack/svelte-query' | ||
import Avatar from '../atoms/Avatar.svelte' | ||
| @@ -23,12 +24,13 @@ | ||
const isOwner = $derived($viewer?.did === comment.author?.did) | ||
const timeStr = $derived(relativeTime(comment.createdAt || '')) | ||
const isReply = $derived(!!comment.replyTo) | ||
const focus = $derived(comment.focus as PhotoView | undefined) | ||
const isMuted = $derived(!!comment.muted && !expanded) | ||
| ||
// Comment favorite state | ||
let favOverride: string | null | undefined = $state(undefined) | ||
const viewerFav = $derived(comment.viewer?.fav ?? null) | ||
const favUri = $derived(favOverride !== undefined ? favOverride : viewerFav) | ||
const favUri: string | null = $derived(favOverride !== undefined ? favOverride : viewerFav) | ||
const isFaved = $derived(!!favUri) | ||
const originallyFaved = $derived(!!viewerFav) | ||
const serverFavCount = $derived(comment.favCount ?? 0) | ||
| @@ -102,8 +104,8 @@ | ||
{/if} | ||
</div> | ||
</div> | ||
{#if comment.focus?.thumb} | ||
<img class="focus-thumb" src={comment.focus.thumb} alt={comment.focus?.alt ?? ''} /> | ||
{#if focus?.thumb} | ||
<img class="focus-thumb" src={focus.thumb} alt={focus.alt ?? ''} /> | ||
{/if} | ||
<button class="fav-btn" class:faved={isFaved} onclick={toggleFav} title={isFaved ? 'Unfavorite' : 'Favorite'}> | ||
<Heart size={16} fill={isFaved ? 'currentColor' : 'none'} /> | ||
web/src/lib/components/molecules/GalleryCard.svelte+2−1
| @@ -1,5 +1,6 @@ | ||
<script lang="ts"> | ||
import type { GalleryView, PhotoView, ExifView } from '$hatk/client' | ||
import type { GalleryView } from '$lib/lexicons/social/grain/gallery/defs.ts' | ||
import type { PhotoView, ExifView } from '$lib/lexicons/social/grain/photo/defs.ts' | ||
import { isCaughtUp } from '$lib/stories' | ||
import Avatar from '../atoms/Avatar.svelte' | ||
import FavedByFollowing from './FavedByFollowing.svelte' | ||
web/src/lib/components/molecules/GalleryMedia.svelte+1−1
| @@ -6,7 +6,7 @@ | ||
*/ | ||
import { browser } from '$app/environment' | ||
import { ChevronLeft, ChevronRight, Heart, Info } from 'lucide-svelte' | ||
import type { PhotoView } from '$hatk/client' | ||
import type { PhotoView } from '$lib/lexicons/social/grain/photo/defs.ts' | ||
| ||
let { | ||
photos, | ||
web/src/lib/components/molecules/GalleryMenu.svelte+1−1
| @@ -7,7 +7,7 @@ | ||
* since every item needs an account. | ||
*/ | ||
import type { Snippet } from 'svelte' | ||
import type { GalleryView } from '$hatk/client' | ||
import type { GalleryView } from '$lib/lexicons/social/grain/gallery/defs.ts' | ||
import { callXrpc } from '$hatk/client' | ||
import { goto } from '$app/navigation' | ||
import { useQueryClient } from '@tanstack/svelte-query' | ||
web/src/lib/components/molecules/GallerySectionRow.svelte+2−1
| @@ -2,7 +2,8 @@ | ||
import { profilePath, galleryPath } from '$lib/utils' | ||
import { createQuery } from '@tanstack/svelte-query' | ||
import { cameraFeedQuery, locationFeedQuery } from '$lib/queries' | ||
import type { GalleryView, PhotoView } from '$hatk/client' | ||
import type { GalleryView } from '$lib/lexicons/social/grain/gallery/defs.ts' | ||
import type { PhotoView } from '$lib/lexicons/social/grain/photo/defs.ts' | ||
import Avatar from '../atoms/Avatar.svelte' | ||
import { ChevronRight } from 'lucide-svelte' | ||
| ||
web/src/lib/components/molecules/ProfilePopover.svelte+2−1
| @@ -1,7 +1,8 @@ | ||
<script lang="ts"> | ||
import { profilePath } from '$lib/utils' | ||
import { createQuery } from '@tanstack/svelte-query' | ||
import type { GrainActorDefsProfileViewDetailed, GrainUnspeccedGetKnownFollowersFollowerItem as GetKnownFollowersFollowerItem } from '$hatk/client' | ||
import type { ProfileViewDetailed as GrainActorDefsProfileViewDetailed } from '$lib/lexicons/social/grain/actor/defs.ts' | ||
import type { KnownFollowerItem as GetKnownFollowersFollowerItem } from '$lib/lexicons/social/grain/graph/defs.ts' | ||
import { actorProfileQuery, knownFollowersQuery, storyAuthorsQuery } from '$lib/queries' | ||
import { isCaughtUp } from '$lib/stories' | ||
import { viewer } from '$lib/stores' | ||