import { type mastodon } from "masto"; import { Accessor, createEffect, createResource, createSignal } from "solid-js"; import { createStore } from "solid-js/store"; type TimelineFetchTips = { direction?: "new" | "old"; }; type Timeline = { list(params: { maxId?: string; minId?: string; }): mastodon.Paginator; }; export function useTimeline(timeline: Accessor) { let minId: string | undefined; let maxId: string | undefined; let otl: Timeline | undefined; const idSet = new Set(); const [snapshot, { refetch }] = createResource< { records: mastodon.v1.Status[]; direction: "old" | "new" }, [Timeline], TimelineFetchTips | undefined >( () => [timeline()] as const, async ([tl], info) => { if (otl !== tl) { minId = undefined; maxId = undefined; idSet.clear(); otl = tl; } const direction = typeof info.refetching !== "boolean" ? info.refetching?.direction : "old"; const pager = await tl.list( direction === "old" ? { maxId: minId, } : { minId: maxId, }, ); const diff = pager.filter((x) => !idSet.has(x.id)); for (const v of diff.map((x) => x.id)) { idSet.add(v); } if (direction === "old") { minId = pager[pager.length - 1]?.id; if (!maxId && pager.length > 0) { maxId = pager[0].id; } return { direction: "old" as const, records: diff, }; } else { maxId = pager.length > 0 ? pager[0].id : undefined; if (!minId && pager.length > 0) { minId = pager[pager.length - 1]?.id; } return { direction: "new" as const, records: diff }; } }, ); const [store, setStore] = createStore([] as mastodon.v1.Status[]); createEffect(() => { const shot = snapshot(); if (!shot) return; const { direction, records } = shot; if (direction == "new") { setStore((x) => [...records, ...x]); } else if (direction == "old") { setStore((x) => [...x, ...records]); } }); return [ store, snapshot, { refetch, mutate: setStore, }, ] as const; }