diff --git a/desktop/src/features/messages/ui/MessageTimeline.tsx b/desktop/src/features/messages/ui/MessageTimeline.tsx index 46967673f..c184b54c4 100644 --- a/desktop/src/features/messages/ui/MessageTimeline.tsx +++ b/desktop/src/features/messages/ui/MessageTimeline.tsx @@ -326,6 +326,13 @@ export const MessageTimeline = React.memo(function MessageTimeline({ const showChannelIntro = !isLoading && channelIntro !== null && directMessageIntro === null; const showIntro = showDirectMessageIntro || showChannelIntro; + // The channel intro is an in-list HEADER: it must sit FLUSH at the top of the + // virtualized list (the `#` avatar / title / "beginning of…" / action cards), + // not float bottom-pinned in the viewport like the DM intro / empty state. So + // for the channel-intro case we drop the `min-h-full` fill + the intro's + // `mt-auto`, letting natural top-down flow place it at the top. Everything + // else (DM intro, generic empty) keeps the existing bottom-pin behavior. + const topAlignIntro = showChannelIntro; const showGenericEmpty = !isLoading && deferredMessages.length === 0 && @@ -355,7 +362,7 @@ export const MessageTimeline = React.memo(function MessageTimeline({ className={cn( "flex w-full flex-col gap-2", channelChrome.contentPadding, - (showIntro || showGenericEmpty) && "min-h-full", + (showIntro || showGenericEmpty) && !topAlignIntro && "min-h-full", )} >
@@ -369,12 +376,16 @@ export const MessageTimeline = React.memo(function MessageTimeline({ } @@ -402,7 +413,12 @@ export const MessageTimeline = React.memo(function MessageTimeline({ {showChannelIntro ? (