fork
Configure Feed
Select the types of activity you want to include in your feed.
BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
fork
Configure Feed
Select the types of activity you want to include in your feed.
1import { getReplyRootPost } from "$/lib/feeds";
2import type { PostEngagementTab } from "$/lib/post-engagement-routes";
3import type { FeedViewPost, PostView } from "$/lib/types";
4import { For, Show } from "solid-js";
5import { EmptyFeedState, FeedSkeleton, LoadingMoreIndicator } from "./FeedEmpty";
6import { PostCard } from "./PostCard";
7import type { FeedState } from "./types";
8
9function FeedStatus(props: { activeFeedState: FeedState | undefined; visibleItems: FeedViewPost[] }) {
10 const loading = () => !props.activeFeedState || props.activeFeedState.loading;
11
12 return (
13 <>
14 <Show when={loading()}>
15 <FeedSkeleton />
16 </Show>
17 <Show when={props.activeFeedState?.error}>
18 {(message) => (
19 <div class="rounded-3xl bg-[rgba(138,31,31,0.2)] p-4 text-sm text-error shadow-[inset_0_0_0_1px_rgba(255,128,128,0.2)]">
20 {message()}
21 </div>
22 )}
23 </Show>
24 <Show when={!loading() && !props.activeFeedState?.error && props.visibleItems.length === 0}>
25 <EmptyFeedState />
26 </Show>
27 </>
28 );
29}
30
31export function FeedContent(
32 props: {
33 activeFeedId: string;
34 activeFeedState: FeedState | undefined;
35 bookmarkPendingByUri: Record<string, boolean>;
36 focusedIndex: number;
37 likePendingByUri: Record<string, boolean>;
38 likePulseUri: string | null;
39 onFocusIndex: (index: number) => void;
40 onBookmark: (post: PostView) => Promise<void> | void;
41 onLike: (post: PostView) => Promise<void> | void;
42 onOpenEngagement: (uri: string, tab: PostEngagementTab) => Promise<void> | void;
43 onOpenThread: (uri: string) => Promise<void> | void;
44 onQuote: (post: PostView) => void;
45 onReply: (post: PostView, root: PostView) => void;
46 onRepost: (post: PostView) => Promise<void> | void;
47 postRefs: Map<string, HTMLElement>;
48 repostPendingByUri: Record<string, boolean>;
49 repostPulseUri: string | null;
50 sentinelRef: (element: HTMLDivElement) => void;
51 visibleItems: FeedViewPost[];
52 },
53) {
54 return (
55 <div class="grid min-w-0 gap-3" data-feed-id={props.activeFeedId}>
56 <FeedStatus activeFeedState={props.activeFeedState} visibleItems={props.visibleItems} />
57 <For each={props.visibleItems}>
58 {(item, index) => (
59 <PostCard
60 bookmarkPending={!!props.bookmarkPendingByUri[item.post.uri]}
61 focused={props.focusedIndex === index()}
62 item={item}
63 likePending={!!props.likePendingByUri[item.post.uri]}
64 onBookmark={() => void props.onBookmark(item.post)}
65 onFocus={() => props.onFocusIndex(index())}
66 onLike={() => void props.onLike(item.post)}
67 onOpenEngagement={(tab) => void props.onOpenEngagement(item.post.uri, tab)}
68 onOpenThread={(uri) => void props.onOpenThread(uri)}
69 onQuote={() => props.onQuote(item.post)}
70 onReply={() => props.onReply(item.post, getReplyRootPost(item))}
71 onRepost={() => void props.onRepost(item.post)}
72 post={item.post}
73 pulseLike={props.likePulseUri === item.post.uri}
74 pulseRepost={props.repostPulseUri === item.post.uri}
75 registerRef={(element) => props.postRefs.set(item.post.uri, element)}
76 repostPending={!!props.repostPendingByUri[item.post.uri]} />
77 )}
78 </For>
79 <div ref={(element) => props.sentinelRef(element)} />
80 <LoadingMoreIndicator loading={!!props.activeFeedState?.loadingMore} />
81 </div>
82 );
83}