diff --git a/src/masto/timelines.ts b/src/masto/timelines.ts index 8eb9c81..1483694 100644 --- a/src/masto/timelines.ts +++ b/src/masto/timelines.ts @@ -11,23 +11,15 @@ import { } from "solid-js"; import { createStore } from "solid-js/store"; -type Timeline = { - list(params: { - /** Return results older than this ID. */ - readonly maxId?: string; - /** Return results newer than this ID. */ - readonly sinceId?: string; - /** Get a list of items with ID greater than this value excluding this ID */ - readonly minId?: string; - /** Maximum number of results to return per page. Defaults to 40. NOTE: Pagination is done with the Link header from the response. */ - readonly limit?: number; - }): mastodon.Paginator; +type Timeline = { + list(params?: T): mastodon.Paginator; }; -export function createTimelineSnapshot( - timeline: Accessor, - limit: Accessor, -) { +type TimelineParamsOf = T extends Timeline ? P : never; + +export function createTimelineSnapshot< + T extends Timeline, +>(timeline: Accessor, limit: Accessor) { const [shot, { refetch }] = createResource( () => [timeline(), limit()] as const, async ([tl, limit]) => { @@ -80,13 +72,13 @@ export function createTimelineSnapshot( export type TimelineFetchDirection = mastodon.Direction; -export type TimelineChunk = { - tl: Timeline; +export type TimelineChunk = { + tl: Timeline; rebuilt: boolean; chunk: readonly mastodon.v1.Status[]; done?: boolean; direction: TimelineFetchDirection; - limit: number; + params: T; }; type TreeNode = { @@ -108,21 +100,21 @@ function collectPath(node: TreeNode) { return path; } -function createTimelineChunk( - timeline: Accessor, - limit: Accessor, +function createTimelineChunk>( + timeline: Accessor, + params: Accessor>, ) { let vpMaxId: string | undefined, vpMinId: string | undefined; const fetchExtendingPage = async ( - tl: Timeline, + tl: T, direction: TimelineFetchDirection, - limit: number, + params: TimelineParamsOf, ) => { switch (direction) { case "next": { const page = await tl - .list({ limit, sinceId: vpMaxId }) + .list({ ...params, sinceId: vpMaxId }) .setDirection(direction) .next(); if ((page.value?.length ?? 0) > 0) { @@ -133,7 +125,7 @@ function createTimelineChunk( case "prev": { const page = await tl - .list({ limit, maxId: vpMinId }) + .list({ ...params, maxId: vpMinId }) .setDirection(direction) .next(); if ((page.value?.length ?? 0) > 0) { @@ -145,11 +137,11 @@ function createTimelineChunk( }; return createResource( - () => [timeline(), limit()] as const, + () => [timeline(), params()] as const, async ( - [tl, limit], + [tl, params], info: ResourceFetcherInfo< - Readonly, + Readonly>>, TimelineFetchDirection >, ) => { @@ -160,27 +152,26 @@ function createTimelineChunk( vpMaxId = undefined; vpMinId = undefined; } - const posts = await fetchExtendingPage(tl, direction, limit); + const posts = await fetchExtendingPage(tl, direction, params); return { tl, rebuilt: rebuildTimeline, chunk: posts.value ?? [], done: posts.done, direction, - limit, + params, }; }, ); } -export function createTimeline( - timeline: Accessor, - limit: Accessor, -) { +export function createTimeline< + T extends Timeline, +>(timeline: Accessor, params: Accessor>) { const lookup = new ReactiveMap>(); const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]); - const [chunk, { refetch }] = createTimelineChunk(timeline, limit); + const [chunk, { refetch }] = createTimelineChunk(timeline, params); createEffect(() => { const chk = catchError(chunk, (e) => console.error(e)); diff --git a/src/profiles/Profile.tsx b/src/profiles/Profile.tsx index cdea9d5..2230f3d 100644 --- a/src/profiles/Profile.tsx +++ b/src/profiles/Profile.tsx @@ -60,14 +60,14 @@ const Profile: Component = () => { const [recentToots] = createTimeline( () => session().client.v1.accounts.$select(params.id).statuses, - () => 20, + () => ({ limit: 20 }), ); const bannerImg = () => profile()?.header; const avatarImg = () => profile()?.avatar; const displayName = () => resolveCustomEmoji(profile()?.displayName || "", profile()?.emojis ?? []); - const fullUsername = () => `@${profile()?.acct ?? "..."}`; // TODO: full user name + const fullUsername = () => `@${profile()?.acct ?? ""}`; // TODO: full user name const description = () => profile()?.note; css` diff --git a/src/timelines/TimelinePanel.tsx b/src/timelines/TimelinePanel.tsx index b1a014d..5c3e150 100644 --- a/src/timelines/TimelinePanel.tsx +++ b/src/timelines/TimelinePanel.tsx @@ -32,7 +32,7 @@ const TimelinePanel: Component<{ const [timeline, snapshot, { refetch: refetchTimeline }] = createTimeline( () => props.client.v1.timelines[props.name], - () => 20, + () => ({limit: 20}), ); const [expandedThreadId, setExpandedThreadId] = createSignal(); const [typing, setTyping] = createSignal(false);