Retro Bulletin Board Systems on atproto. Web app and TUI. lazy mirror of alyraffauf/atbbs atbbs.xyz
forums python tui atproto bbs
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

web: fix activity pane names

+23 -23
+5 -5
web/src/components/InboxList.tsx web/src/components/ActivityList.tsx
··· 3 3 import { parseAtUri } from "../lib/util"; 4 4 import PostBody from "./post/PostBody"; 5 5 import PostMeta from "./post/PostMeta"; 6 - import type { InboxItem } from "../router/loaders"; 6 + import type { ActivityItem } from "../lib/activity"; 7 7 8 8 const PAGE_SIZE = 10; 9 9 10 - interface InboxListProps { 11 - items: InboxItem[]; 10 + interface ActivityListProps { 11 + items: ActivityItem[]; 12 12 userHandle: string; 13 13 } 14 14 15 - export default function InboxList({ items, userHandle }: InboxListProps) { 15 + export default function ActivityList({ items, userHandle }: ActivityListProps) { 16 16 const [shown, setShown] = useState(PAGE_SIZE); 17 17 18 18 if (items.length === 0) 19 - return <p className="text-neutral-500">No messages yet.</p>; 19 + return <p className="text-neutral-500">No activity yet.</p>; 20 20 21 21 return ( 22 22 <div>
+7 -7
web/src/lib/inbox.ts web/src/lib/activity.ts
··· 1 - /** Inbox data fetching — replies to your threads + quotes of your replies. */ 1 + /** Activity data — replies to your threads + quotes of your replies. */ 2 2 3 3 import { fetchAndHydrate, listRecords } from "./atproto"; 4 4 import { THREAD, REPLY } from "./lexicon"; ··· 7 7 import { mainSchema as replySchema } from "../lexicons/types/xyz/atboards/reply"; 8 8 import type { XyzAtboardsThread, XyzAtboardsReply } from "../lexicons"; 9 9 10 - export interface InboxItem { 10 + export interface ActivityItem { 11 11 type: "reply" | "quote"; 12 12 threadTitle: string; 13 13 threadUri: string; ··· 21 21 sourceUri: string, 22 22 backlinkSource: string, 23 23 excludeDid: string, 24 - type: InboxItem["type"], 24 + type: ActivityItem["type"], 25 25 threadTitle: string, 26 26 threadUri: string, 27 - ): Promise<InboxItem[]> { 27 + ): Promise<ActivityItem[]> { 28 28 try { 29 29 const { records } = await fetchAndHydrate(sourceUri, backlinkSource, { 30 30 limit: 50, ··· 44 44 } 45 45 } 46 46 47 - export async function fetchInbox( 47 + export async function fetchActivity( 48 48 did: string, 49 49 pdsUrl: string, 50 - ): Promise<InboxItem[]> { 50 + ): Promise<ActivityItem[]> { 51 51 const SCAN_LIMIT = 50; 52 52 const [allThreads, allReplies] = await Promise.all([ 53 53 listRecords(pdsUrl, did, THREAD, SCAN_LIMIT), ··· 82 82 ]); 83 83 84 84 // Deduplicate — prefer "quote" type when the same reply appears as both. 85 - const seen = new Map<string, InboxItem>(); 85 + const seen = new Map<string, ActivityItem>(); 86 86 for (const item of results.flat()) { 87 87 const key = item.handle + item.body + item.createdAt; 88 88 if (!seen.has(key) || item.type === "quote") seen.set(key, item);
+8 -8
web/src/pages/Dashboard.tsx
··· 7 7 import DialBBS, { type Suggestion } from "../components/DialBBS"; 8 8 import PinnedList from "../components/PinnedList"; 9 9 import MyThreadList from "../components/MyThreadList"; 10 - import InboxList from "../components/InboxList"; 10 + import ActivityList from "../components/ActivityList"; 11 11 import BBSPanel from "../components/BBSPanel"; 12 - import type { InboxItem, PinnedBBS, MyThread } from "../router/loaders"; 12 + import type { ActivityItem, PinnedBBS, MyThread } from "../router/loaders"; 13 13 import type { AuthUser } from "../lib/auth"; 14 14 15 15 export interface DashboardData { ··· 17 17 hasBBS: boolean; 18 18 pins: Promise<PinnedBBS[]>; 19 19 threads: Promise<MyThread[]>; 20 - items: Promise<InboxItem[]>; 20 + activity: Promise<ActivityItem[]>; 21 21 } 22 22 23 23 type Tab = "inbox" | "threads" | "pinned" | "bbs"; ··· 28 28 "py-2 border-b-2 text-neutral-500 hover:text-neutral-300 border-transparent whitespace-nowrap"; 29 29 30 30 export default function Dashboard({ data }: { data: DashboardData }) { 31 - const { user, hasBBS, pins, threads, items } = data; 31 + const { user, hasBBS, pins, threads, activity } = data; 32 32 const { agent } = useAuth(); 33 33 const revalidator = useRevalidator(); 34 34 const discovered = useDiscovery(); ··· 77 77 } 78 78 79 79 const tabs: { key: Tab; label: string }[] = [ 80 - { key: "inbox", label: "Replies" }, 80 + { key: "inbox", label: "Activity" }, 81 81 { key: "threads", label: "Threads" }, 82 82 { key: "pinned", label: "Pins" }, 83 83 { key: "bbs", label: "My BBS" }, ··· 105 105 106 106 {tab === "inbox" && ( 107 107 <Suspense fallback={loading}> 108 - <Await resolve={items}> 109 - {(resolved: InboxItem[]) => ( 110 - <InboxList items={resolved} userHandle={user.handle} /> 108 + <Await resolve={activity}> 109 + {(resolved: ActivityItem[]) => ( 110 + <ActivityList items={resolved} userHandle={user.handle} /> 111 111 )} 112 112 </Await> 113 113 </Suspense>
+2 -2
web/src/router/loaders/home.ts
··· 1 1 import { getRecord } from "../../lib/atproto"; 2 2 import { ensureAuthReady, getCurrentUser } from "../../lib/auth"; 3 - import { fetchInbox } from "../../lib/inbox"; 3 + import { fetchActivity } from "../../lib/activity"; 4 4 import { fetchPins } from "../../lib/pins"; 5 5 import { fetchMyThreads } from "../../lib/mythreads"; 6 6 import { SITE } from "../../lib/lexicon"; ··· 21 21 return { 22 22 user, 23 23 hasBBS, 24 - items: fetchInbox(user.did, user.pdsUrl), 24 + activity: fetchActivity(user.did, user.pdsUrl), 25 25 pins: fetchPins(user.pdsUrl, user.did), 26 26 threads: fetchMyThreads(user.pdsUrl, user.did), 27 27 };
+1 -1
web/src/router/loaders/index.ts
··· 4 4 export { boardLoader, hydrateThreadPage, type ThreadItem } from "./board"; 5 5 export { threadLoader, type ThreadObj } from "./thread"; 6 6 export { requireAuthLoader } from "./account"; 7 - export type { InboxItem } from "../../lib/inbox"; 7 + export type { ActivityItem } from "../../lib/activity"; 8 8 export type { PinnedBBS } from "../../lib/pins"; 9 9 export type { MyThread } from "../../lib/mythreads"; 10 10 export { sysopEditLoader, sysopModerateLoader, type HiddenInfo } from "./sysop";