appview-less bluesky client
1<script lang="ts">
2 import { type State as PostComposerState } from './PostComposer.svelte';
3 import { AtpClient } from '$lib/at/client.svelte';
4 import { accounts } from '$lib/accounts';
5 import {
6 postCursors,
7 fetchTimeline,
8 allPosts,
9 timelines,
10 fetchInteractionsToTimelineEnd,
11 accountPreferences
12 } from '$lib/state.svelte';
13 import { buildThreadsFiltered } from '$lib/thread';
14 import type { Did } from '@atcute/lexicons/syntax';
15 import GenericTimelineView from './GenericTimelineView.svelte';
16
17 interface Props {
18 client?: AtpClient | null;
19 targetDid?: Did;
20 postComposerState: PostComposerState;
21 class?: string;
22 showReplies?: boolean;
23 }
24
25 let {
26 client = null,
27 targetDid = undefined,
28 showReplies = true,
29 postComposerState = $bindable(),
30 class: className = ''
31 }: Props = $props();
32
33 let viewOwnPosts = $state(true);
34 let displayCount = $state(10);
35
36 const userDid = $derived(client?.user?.did);
37 const did = $derived(targetDid ?? userDid);
38
39 const currentPrefs = $derived(userDid ? accountPreferences.get(userDid) : null);
40 const mutes = $derived(new Set(currentPrefs?.mutes ?? []));
41
42 const threads = $derived(
43 did && timelines.has(did)
44 ? buildThreadsFiltered(
45 did,
46 timelines.get(did)!,
47 allPosts,
48 mutes,
49 $accounts,
50 { viewOwnPosts },
51 displayCount
52 )
53 : []
54 );
55
56 let fetchingInteractions = $state(false);
57 let scheduledFetchInteractions = $state(false);
58
59 const loadMore = async () => {
60 if (!client || !userDid || !did) return;
61
62 await fetchTimeline(client, did, 7, showReplies, {
63 downwards: userDid === did ? 'sameAuthor' : 'none'
64 });
65 if (client.user && userDid) {
66 if (!fetchingInteractions) {
67 scheduledFetchInteractions = false;
68 fetchingInteractions = true;
69 await fetchInteractionsToTimelineEnd(client, userDid, did);
70 fetchingInteractions = false;
71 } else {
72 scheduledFetchInteractions = true;
73 }
74 }
75 };
76
77 $effect(() => {
78 if (client && scheduledFetchInteractions && userDid && did && did !== userDid) {
79 if (!fetchingInteractions) {
80 scheduledFetchInteractions = false;
81 fetchingInteractions = true;
82 fetchInteractionsToTimelineEnd(client, userDid, did).finally(
83 () => (fetchingInteractions = false)
84 );
85 } else {
86 scheduledFetchInteractions = true;
87 }
88 }
89 });
90</script>
91
92<GenericTimelineView
93 {client}
94 {threads}
95 timelineId={`replies:${did}`}
96 bind:postComposerState
97 bind:displayCount
98 class={className}
99 isLoggedIn={!!(did || $accounts.length > 0)}
100 canLoad={!!(client && userDid && did)}
101 onLoadMore={loadMore}
102 isComplete={did ? postCursors.get(did)?.end : false}
103/>