diff --git a/src/masto/timelines.ts b/src/masto/timelines.ts index b8b38b6..bbc884e 100644 --- a/src/masto/timelines.ts +++ b/src/masto/timelines.ts @@ -7,6 +7,7 @@ import { createEffect, createResource, untrack, + type Resource, type ResourceFetcherInfo, } from "solid-js"; import { createStore } from "solid-js/store"; @@ -19,7 +20,7 @@ type TimelineParamsOf = T extends Timeline ? P : never; export function createTimelineControlsForArray( status: () => mastodon.v1.Status[] | undefined, -) { +): TimelineControls { const lookup = new ReactiveMap>(); const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]); @@ -84,7 +85,10 @@ export function createTimelineControlsForArray( export function createTimelineSnapshot< T extends Timeline, ->(timeline: Accessor, limit: Accessor) { +>( + timeline: Accessor, + limit: Accessor, +): TimelineResource { const [shot, { refetch }] = createResource( () => [timeline(), limit()] as const, async ([tl, limit]) => { @@ -198,9 +202,51 @@ function createTimelineChunk< ); } +export type TimelineControls = { + /** + * The threads. + * + * The identifiers here is the most-bottom toot id in the thread. + * + * @see You can use {@link TimelineControls.get} and {@link TimelineControls.getPath} to resolve them if + * the context is needed. + */ + list: readonly mastodon.v1.Status["id"][]; + /** + * Get the single node. + */ + get(id: string): TreeNode | undefined; + /** + * Collect the path from the node to the most-top node. + */ + getPath(id: string): TreeNode[] | undefined; + /** + * Set the node value. + */ + set(id: string, value: mastodon.v1.Status): void; +}; + +export type TimelineResource< + R, +> = [ + TimelineControls, + Resource, + { refetch(info?: TimelineFetchDirection): void }, +]; + +/** + * Create auto managed timeline controls. + * + * The error from the resource is not thrown in the + * {@link TimelineControls.list} and {@link TimelineControls}.get*. + * Use the second value from {@link TimelineResource} to catch the error. + */ export function createTimeline< T extends Timeline, ->(timeline: Accessor, params: Accessor>) { +>( + timeline: Accessor, + params: Accessor>, +): TimelineResource> | undefined> { const lookup = new ReactiveMap>(); const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]); diff --git a/src/timelines/TootList.tsx b/src/timelines/TootList.tsx index 3842d13..7c712b6 100644 --- a/src/timelines/TootList.tsx +++ b/src/timelines/TootList.tsx @@ -18,7 +18,7 @@ import { findElementActionable } from "./RegularToot"; const TootList: Component<{ ref?: Ref; - threads: string[]; + threads: readonly string[]; onUnknownThread: (id: string) => { value: mastodon.v1.Status }[] | undefined; onChangeToot: (id: string, value: mastodon.v1.Status) => void; }> = (props) => { diff --git a/src/timelines/TrendTimelinePanel.tsx b/src/timelines/TrendTimelinePanel.tsx index 8391e2d..04f98b0 100644 --- a/src/timelines/TrendTimelinePanel.tsx +++ b/src/timelines/TrendTimelinePanel.tsx @@ -40,7 +40,7 @@ const TrendTimelinePanel: Component<{ refetchTimeline({ direction: "new" })} + onRefresh={() => refetchTimeline("next")} />