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";
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<mastodon.v1.Status[], unknown>;
type Timeline<T extends mastodon.DefaultPaginationParams> = {
list(params?: T): mastodon.Paginator<mastodon.v1.Status[], unknown>;
};
export function createTimelineSnapshot(
timeline: Accessor<Timeline>,
limit: Accessor<number>,
) {
type TimelineParamsOf<T> = T extends Timeline<infer P> ? P : never;
export function createTimelineSnapshot<
T extends Timeline<mastodon.DefaultPaginationParams>,
>(timeline: Accessor<T>, limit: Accessor<number>) {
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<T extends mastodon.DefaultPaginationParams> = {
tl: Timeline<T>;
rebuilt: boolean;
chunk: readonly mastodon.v1.Status[];
done?: boolean;
direction: TimelineFetchDirection;
limit: number;
params: T;
};
type TreeNode<T> = {
@ -108,21 +100,21 @@ function collectPath<T>(node: TreeNode<T>) {
return path;
}
function createTimelineChunk(
timeline: Accessor<Timeline>,
limit: Accessor<number>,
function createTimelineChunk<T extends Timeline<mastodon.DefaultPaginationParams>>(
timeline: Accessor<T>,
params: Accessor<TimelineParamsOf<T>>,
) {
let vpMaxId: string | undefined, vpMinId: string | undefined;
const fetchExtendingPage = async (
tl: Timeline,
tl: T,
direction: TimelineFetchDirection,
limit: number,
params: TimelineParamsOf<T>,
) => {
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<TimelineChunk>,
Readonly<TimelineChunk<TimelineParamsOf<T>>>,
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<Timeline>,
limit: Accessor<number>,
) {
export function createTimeline<
T extends Timeline<mastodon.DefaultPaginationParams>,
>(timeline: Accessor<T>, params: Accessor<TimelineParamsOf<T>>) {
const lookup = new ReactiveMap<string, TreeNode<mastodon.v1.Status>>();
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));

View file

@ -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`

View file

@ -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<string>();
const [typing, setTyping] = createSignal(false);