From acc0d9de17ab629518f60b2f35a1b0dd00bec30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Wed, 11 Mar 2026 05:25:01 +0100 Subject: [PATCH] nicolium: try to not add empty timeline gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../src/queries/timelines/use-timeline.ts | 17 ++++++++++++----- .../src/queries/timelines/use-timelines.ts | 9 ++++++--- packages/nicolium/src/utils/strings.ts | 19 ++++++++++++++++++- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/packages/nicolium/src/queries/timelines/use-timeline.ts b/packages/nicolium/src/queries/timelines/use-timeline.ts index b123cf137..e80dcf6a6 100644 --- a/packages/nicolium/src/queries/timelines/use-timeline.ts +++ b/packages/nicolium/src/queries/timelines/use-timeline.ts @@ -21,7 +21,7 @@ const useTimeline = ( timelineId: string, fetcher: TimelineFetcher, streamConfig?: StreamConfig, - restoring?: boolean, + restoringMaxId?: string, ) => { const timeline = useStoreTimeline(timelineId); const timelineActions = useTimelinesActions(); @@ -34,23 +34,30 @@ const useTimeline = ( }, [timelineId]); const fetchInitial = useCallback( - async (isRestoring = restoring) => { + async (isRestoring = !!restoringMaxId) => { timelineActions.setLoading(timelineId, true); try { - const response = await fetcher(); + const [response, shouldInsertGap] = await Promise.all([ + fetcher(), + !restoringMaxId + ? Promise.resolve(false) + : fetcher({ since_id: restoringMaxId, limit: 1 }) + .then((res) => res.items.length > 0) + .catch(() => true), + ]); importEntities({ statuses: response.items }); timelineActions.expandTimeline( timelineId, response.items, !!response.next, true, - isRestoring, + isRestoring && shouldInsertGap, ); } catch (error) { timelineActions.setError(timelineId, true); } }, - [timelineId, restoring], + [timelineId, restoringMaxId], ); const fetchNextPage = useCallback(async () => { diff --git a/packages/nicolium/src/queries/timelines/use-timelines.ts b/packages/nicolium/src/queries/timelines/use-timelines.ts index bf5671db1..5ce76e61c 100644 --- a/packages/nicolium/src/queries/timelines/use-timelines.ts +++ b/packages/nicolium/src/queries/timelines/use-timelines.ts @@ -1,6 +1,7 @@ import { useRef } from 'react'; import { useClient } from '@/hooks/use-client'; +import { incrementId } from '@/utils/strings'; import { useTimeline } from './use-timeline'; @@ -30,8 +31,10 @@ const useHomeTimeline = ( return useTimeline( 'home', (paginationParams) => { - const initialPagination = restoreMaxId.current ? { max_id: restoreMaxId.current } : undefined; - if (paginationParams == null) { + const initialPagination = restoreMaxId.current + ? { max_id: incrementId(restoreMaxId.current) } + : undefined; + if (!paginationParams) { restoreMaxId.current = undefined; } @@ -41,7 +44,7 @@ const useHomeTimeline = ( }); }, { stream }, - !!maxId, + maxId, ); }; diff --git a/packages/nicolium/src/utils/strings.ts b/packages/nicolium/src/utils/strings.ts index 36dd95dc1..85b2d372a 100644 --- a/packages/nicolium/src/utils/strings.ts +++ b/packages/nicolium/src/utils/strings.ts @@ -2,4 +2,21 @@ // https://stackoverflow.com/a/1026087 const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1); -export { capitalize }; +const incrementId = (str: string): string => { + const CHARS = str.match(/[a-z]/i) + ? '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + : '0123456789'; + const chars = [...str]; + for (let i = chars.length - 1; i >= 0; i--) { + const idx = CHARS.indexOf(chars[i]); + if (idx === -1) continue; + if (idx < CHARS.length - 1) { + chars[i] = CHARS[idx + 1]; + return chars.join(''); + } + chars[i] = CHARS[0]; + } + return CHARS[1] + chars.join(''); +}; + +export { capitalize, incrementId };