From e668f3d8994543700853bafb52a2e69e4b88c183 Mon Sep 17 00:00:00 2001 From: Wes Date: Wed, 17 Jun 2026 13:52:09 -0700 Subject: [PATCH] Smooth deferred channel loading Keep timeline intro and empty affordances hidden while live messages are waiting for the deferred list commit, so channel entry shows the message skeleton until rows are ready instead of briefly flashing the channel intro. Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- .../features/messages/ui/MessageTimeline.tsx | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/desktop/src/features/messages/ui/MessageTimeline.tsx b/desktop/src/features/messages/ui/MessageTimeline.tsx index aaeaee7c4..06dc1a36e 100644 --- a/desktop/src/features/messages/ui/MessageTimeline.tsx +++ b/desktop/src/features/messages/ui/MessageTimeline.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { ArrowDown, ArrowUp, Hash } from "lucide-react"; +import { selectDeferredListRenderState } from "@/features/messages/lib/timelineSnapshot"; import { getDmParticipantPreview } from "@/features/channels/lib/dmParticipantDisplay"; import type { TimelineMessage } from "@/features/messages/types"; import type { UserProfileLookup } from "@/features/profile/lib/identity"; @@ -252,16 +253,27 @@ export const MessageTimeline = React.memo(function MessageTimeline({ sentinelRef: topSentinelRef, }); - const showDirectMessageIntro = !isLoading && directMessageIntro !== null; + const timelineRenderState = selectDeferredListRenderState( + deferredMessages.length, + messages.length, + ); + const isDeferredListPending = !isLoading && timelineRenderState === "pending"; + const showDirectMessageIntro = + !isLoading && + timelineRenderState !== "pending" && + directMessageIntro !== null; const showChannelIntro = - !isLoading && channelIntro !== null && directMessageIntro === null; + !isLoading && + timelineRenderState !== "pending" && + channelIntro !== null && + directMessageIntro === null; const showIntro = showDirectMessageIntro || showChannelIntro; const showGenericEmpty = !isLoading && - deferredMessages.length === 0 && + timelineRenderState === "empty" && directMessageIntro === null && channelIntro === null; - const showMessageList = !isLoading && deferredMessages.length > 0; + const showMessageList = !isLoading && timelineRenderState === "list"; const timelineSkeletonRows = useTimelineSkeletonRows({ channelId, isLoading, @@ -327,7 +339,7 @@ export const MessageTimeline = React.memo(function MessageTimeline({ "flex flex-col gap-2", (showIntro || showGenericEmpty) && "min-h-full", )} - loading={isLoading} + loading={isLoading || isDeferredListPending} skeleton={} > {showDirectMessageIntro ? (