masto/timelines: now the params is general typed

This commit is contained in:
thislight 2024-10-24 22:20:38 +08:00
parent 8d9e4b1c48
commit 3bc25786ca
No known key found for this signature in database
GPG key ID: A50F9451AC56A63E
3 changed files with 29 additions and 38 deletions

View file

@ -11,23 +11,15 @@ import {
} from "solid-js"; } from "solid-js";
import { createStore } from "solid-js/store"; import { createStore } from "solid-js/store";
type Timeline = { type Timeline<T extends mastodon.DefaultPaginationParams> = {
list(params: { list(params?: T): mastodon.Paginator<mastodon.v1.Status[], unknown>;
/** 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<mastodon.v1.Status[], unknown>;
}; };
export function createTimelineSnapshot( type TimelineParamsOf<T> = T extends Timeline<infer P> ? P : never;
timeline: Accessor<Timeline>,
limit: Accessor<number>, export function createTimelineSnapshot<
) { T extends Timeline<mastodon.DefaultPaginationParams>,
>(timeline: Accessor<T>, limit: Accessor<number>) {
const [shot, { refetch }] = createResource( const [shot, { refetch }] = createResource(
() => [timeline(), limit()] as const, () => [timeline(), limit()] as const,
async ([tl, limit]) => { async ([tl, limit]) => {
@ -80,13 +72,13 @@ export function createTimelineSnapshot(
export type TimelineFetchDirection = mastodon.Direction; export type TimelineFetchDirection = mastodon.Direction;
export type TimelineChunk = { export type TimelineChunk<T extends mastodon.DefaultPaginationParams> = {
tl: Timeline; tl: Timeline<T>;
rebuilt: boolean; rebuilt: boolean;
chunk: readonly mastodon.v1.Status[]; chunk: readonly mastodon.v1.Status[];
done?: boolean; done?: boolean;
direction: TimelineFetchDirection; direction: TimelineFetchDirection;
limit: number; params: T;
}; };
type TreeNode<T> = { type TreeNode<T> = {
@ -108,21 +100,21 @@ function collectPath<T>(node: TreeNode<T>) {
return path; return path;
} }
function createTimelineChunk( function createTimelineChunk<T extends Timeline<mastodon.DefaultPaginationParams>>(
timeline: Accessor<Timeline>, timeline: Accessor<T>,
limit: Accessor<number>, params: Accessor<TimelineParamsOf<T>>,
) { ) {
let vpMaxId: string | undefined, vpMinId: string | undefined; let vpMaxId: string | undefined, vpMinId: string | undefined;
const fetchExtendingPage = async ( const fetchExtendingPage = async (
tl: Timeline, tl: T,
direction: TimelineFetchDirection, direction: TimelineFetchDirection,
limit: number, params: TimelineParamsOf<T>,
) => { ) => {
switch (direction) { switch (direction) {
case "next": { case "next": {
const page = await tl const page = await tl
.list({ limit, sinceId: vpMaxId }) .list({ ...params, sinceId: vpMaxId })
.setDirection(direction) .setDirection(direction)
.next(); .next();
if ((page.value?.length ?? 0) > 0) { if ((page.value?.length ?? 0) > 0) {
@ -133,7 +125,7 @@ function createTimelineChunk(
case "prev": { case "prev": {
const page = await tl const page = await tl
.list({ limit, maxId: vpMinId }) .list({ ...params, maxId: vpMinId })
.setDirection(direction) .setDirection(direction)
.next(); .next();
if ((page.value?.length ?? 0) > 0) { if ((page.value?.length ?? 0) > 0) {
@ -145,11 +137,11 @@ function createTimelineChunk(
}; };
return createResource( return createResource(
() => [timeline(), limit()] as const, () => [timeline(), params()] as const,
async ( async (
[tl, limit], [tl, params],
info: ResourceFetcherInfo< info: ResourceFetcherInfo<
Readonly<TimelineChunk>, Readonly<TimelineChunk<TimelineParamsOf<T>>>,
TimelineFetchDirection TimelineFetchDirection
>, >,
) => { ) => {
@ -160,27 +152,26 @@ function createTimelineChunk(
vpMaxId = undefined; vpMaxId = undefined;
vpMinId = undefined; vpMinId = undefined;
} }
const posts = await fetchExtendingPage(tl, direction, limit); const posts = await fetchExtendingPage(tl, direction, params);
return { return {
tl, tl,
rebuilt: rebuildTimeline, rebuilt: rebuildTimeline,
chunk: posts.value ?? [], chunk: posts.value ?? [],
done: posts.done, done: posts.done,
direction, direction,
limit, params,
}; };
}, },
); );
} }
export function createTimeline( export function createTimeline<
timeline: Accessor<Timeline>, T extends Timeline<mastodon.DefaultPaginationParams>,
limit: Accessor<number>, >(timeline: Accessor<T>, params: Accessor<TimelineParamsOf<T>>) {
) {
const lookup = new ReactiveMap<string, TreeNode<mastodon.v1.Status>>(); const lookup = new ReactiveMap<string, TreeNode<mastodon.v1.Status>>();
const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]); const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]);
const [chunk, { refetch }] = createTimelineChunk(timeline, limit); const [chunk, { refetch }] = createTimelineChunk(timeline, params);
createEffect(() => { createEffect(() => {
const chk = catchError(chunk, (e) => console.error(e)); const chk = catchError(chunk, (e) => console.error(e));

View file

@ -60,14 +60,14 @@ const Profile: Component = () => {
const [recentToots] = createTimeline( const [recentToots] = createTimeline(
() => session().client.v1.accounts.$select(params.id).statuses, () => session().client.v1.accounts.$select(params.id).statuses,
() => 20, () => ({ limit: 20 }),
); );
const bannerImg = () => profile()?.header; const bannerImg = () => profile()?.header;
const avatarImg = () => profile()?.avatar; const avatarImg = () => profile()?.avatar;
const displayName = () => const displayName = () =>
resolveCustomEmoji(profile()?.displayName || "", profile()?.emojis ?? []); 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; const description = () => profile()?.note;
css` css`

View file

@ -32,7 +32,7 @@ const TimelinePanel: Component<{
const [timeline, snapshot, { refetch: refetchTimeline }] = createTimeline( const [timeline, snapshot, { refetch: refetchTimeline }] = createTimeline(
() => props.client.v1.timelines[props.name], () => props.client.v1.timelines[props.name],
() => 20, () => ({limit: 20}),
); );
const [expandedThreadId, setExpandedThreadId] = createSignal<string>(); const [expandedThreadId, setExpandedThreadId] = createSignal<string>();
const [typing, setTyping] = createSignal(false); const [typing, setTyping] = createSignal(false);