From 29f6ccf9e9c54acc05d106e0be33bb366ebf3f02 Mon Sep 17 00:00:00 2001 From: klopez4212 Date: Mon, 8 Jun 2026 15:03:06 +0100 Subject: [PATCH] Style channel header navigation (#889) --- .../channels/ui/AgentSessionThreadPanel.tsx | 40 ++++++++++++++----- .../channels/ui/ChannelMembersBar.tsx | 22 +++++----- .../features/channels/ui/ChannelScreen.tsx | 17 +++++++- .../channels/ui/ChannelScreenHeader.tsx | 4 +- desktop/src/features/chat/ui/ChatHeader.tsx | 19 +++++---- .../huddle/components/HuddleIndicator.tsx | 20 ++++++---- .../src/features/messages/ui/DayDivider.tsx | 4 +- .../features/messages/ui/MessageReactions.tsx | 2 +- .../messages/ui/MessageThreadPanel.tsx | 18 +++++---- .../features/messages/ui/MessageTimeline.tsx | 2 +- .../messages/ui/TimelineMessageList.tsx | 5 ++- .../features/profile/ui/UserProfilePanel.tsx | 37 ++++++++++++++--- .../features/sidebar/ui/SidebarSection.tsx | 1 + 13 files changed, 137 insertions(+), 54 deletions(-) diff --git a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx index 924e1c1e7..8f4e3f5a1 100644 --- a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx +++ b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx @@ -55,6 +55,7 @@ export function AgentSessionThreadPanel({ const avatarUrl = profiles?.[agent.pubkey.toLowerCase()]?.avatarUrl ?? null; const isOverlay = useIsThreadPanelOverlay(); const isFloatingOverlay = isOverlay && !isSinglePanelView; + const usesChannelSplitChrome = !isOverlay && !isSinglePanelView; useEscapeKey(onClose, isOverlay || isSinglePanelView); const { ref: scrollRef, onScroll } = useStickToBottom(); @@ -111,7 +112,10 @@ export function AgentSessionThreadPanel({ {!isOverlay ? ( @@ -186,14 +197,22 @@ export function AgentSessionThreadPanel({ ) : null} @@ -204,10 +223,13 @@ export function AgentSessionThreadPanel({ onScroll={onScroll} className={cn( "min-h-0 flex-1 overflow-y-auto px-3 pb-4", - // Match MessageThreadPanel: single-panel mode has a 76px header - // (min-h-[76px] with -mb-[76px]), so the body must clear it. Only - // the floating overlay (44px header) uses the smaller pt-4. - isSinglePanelView ? "pt-[76px]" : isOverlay ? "pt-4" : "pt-[76px]", + // Single-panel mode keeps the 76px local header; split panes sit + // under the channel screen's 92px top chrome. + usesChannelSplitChrome + ? "pt-[92px]" + : isOverlay + ? "pt-4" + : "pt-[76px]", )} > -
+
{ try { @@ -132,14 +132,14 @@ export function ChannelMembersBar({
diff --git a/desktop/src/features/channels/ui/ChannelScreen.tsx b/desktop/src/features/channels/ui/ChannelScreen.tsx index 383dcaa9a..7f2b81fbf 100644 --- a/desktop/src/features/channels/ui/ChannelScreen.tsx +++ b/desktop/src/features/channels/ui/ChannelScreen.tsx @@ -44,8 +44,12 @@ import { useChannelFind } from "@/features/search/useChannelFind"; import { ViewLoadingFallback } from "@/shared/ui/ViewLoadingFallback"; import { AgentSessionProvider } from "@/shared/context/AgentSessionContext"; import { ProfilePanelProvider } from "@/shared/context/ProfilePanelContext"; -import { useElementWidthBreakpoint } from "@/shared/hooks/use-mobile"; import { + useElementWidthBreakpoint, + useIsThreadPanelOverlay, +} from "@/shared/hooks/use-mobile"; +import { + THREAD_PANEL_MIN_WIDTH_PX, THREAD_PANEL_SINGLE_COLUMN_BREAKPOINT_PX, useThreadPanelWidth, } from "@/shared/hooks/useThreadPanelWidth"; @@ -87,6 +91,7 @@ export function ChannelScreen({ widthPx: threadPanelWidthPx, } = useThreadPanelWidth(); const [isMembersSidebarOpen, setIsMembersSidebarOpen] = React.useState(false); + const isThreadPanelOverlay = useIsThreadPanelOverlay(); const [channelContentRef, isNarrowPanelViewport] = useElementWidthBreakpoint( THREAD_PANEL_SINGLE_COLUMN_BREAKPOINT_PX, @@ -435,6 +440,15 @@ export function ChannelScreen({ Boolean( openThreadHeadMessage || openAgentSessionPubkey || profilePanelPubkey, ); + const hasSplitRightPanel = + !isSinglePanelView && + !isThreadPanelOverlay && + Boolean( + openThreadHeadMessage || openAgentSessionPubkey || profilePanelPubkey, + ); + const headerActionsRightInset = hasSplitRightPanel + ? `min(${threadPanelWidthPx}px, calc(100% - ${THREAD_PANEL_MIN_WIDTH_PX}px))` + : undefined; return ( @@ -443,6 +457,7 @@ export function ChannelScreen({ activeChannel={activeChannel} activeChannelEphemeralDisplay={activeChannelEphemeralDisplay} activeChannelTitle={activeChannelTitle} + actionsRightInset={headerActionsRightInset} activeDmPresenceStatus={activeDmPresenceStatus} currentPubkey={currentPubkey} isJoining={joinChannelMutation.isPending} diff --git a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx index 6670ace03..f8a807217 100644 --- a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx +++ b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx @@ -14,6 +14,7 @@ type ChannelScreenHeaderProps = { activeChannel: Channel | null; activeChannelEphemeralDisplay: EphemeralChannelDisplay | null; activeChannelTitle: string; + actionsRightInset?: string; activeDmPresenceStatus: PresenceStatus | null; currentPubkey?: string; isJoining?: boolean; @@ -27,6 +28,7 @@ export function ChannelScreenHeader({ activeChannel, activeChannelEphemeralDisplay, activeChannelTitle, + actionsRightInset, activeDmPresenceStatus, currentPubkey, isJoining = false, @@ -79,10 +81,10 @@ export function ChannelScreenHeader({ return (

@@ -137,7 +137,12 @@ export function ChatHeader({ createPortal(topRightActions, document.body) ) ) : ( -
+
{actions ?
{actions}
: null}
@@ -150,7 +155,7 @@ export function ChatHeader({ } return ( -
+
{header}
); diff --git a/desktop/src/features/huddle/components/HuddleIndicator.tsx b/desktop/src/features/huddle/components/HuddleIndicator.tsx index a63116a84..f74871232 100644 --- a/desktop/src/features/huddle/components/HuddleIndicator.tsx +++ b/desktop/src/features/huddle/components/HuddleIndicator.tsx @@ -230,15 +230,18 @@ export function HuddleIndicator({ <> {gateDialog} @@ -270,15 +273,18 @@ export function HuddleIndicator({
) : null} -

+

Thread

diff --git a/desktop/src/features/messages/ui/TimelineMessageList.tsx b/desktop/src/features/messages/ui/TimelineMessageList.tsx index 99f8fffb8..99c70c531 100644 --- a/desktop/src/features/messages/ui/TimelineMessageList.tsx +++ b/desktop/src/features/messages/ui/TimelineMessageList.tsx @@ -189,7 +189,10 @@ export const TimelineMessageList = React.memo(function TimelineMessageList({ } return dayGroups.map((group) => ( -
+
{group.elements}
diff --git a/desktop/src/features/profile/ui/UserProfilePanel.tsx b/desktop/src/features/profile/ui/UserProfilePanel.tsx index 0d2a8fa09..d2c66490c 100644 --- a/desktop/src/features/profile/ui/UserProfilePanel.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanel.tsx @@ -106,6 +106,8 @@ export function UserProfilePanel({ }: UserProfilePanelProps) { const isOverlay = useIsThreadPanelOverlay(); const isFloatingOverlay = isOverlay && !isSinglePanelView; + const usesChannelSplitChrome = + splitPaneClamp && !isOverlay && !isSinglePanelView; useEscapeKey(onClose, isOverlay || isSinglePanelView); const profileQuery = useUserProfileQuery(pubkey); @@ -239,7 +241,10 @@ export function UserProfilePanel({ {!isOverlay ? (
diff --git a/desktop/src/features/sidebar/ui/SidebarSection.tsx b/desktop/src/features/sidebar/ui/SidebarSection.tsx index 26e299751..d82cef0d6 100644 --- a/desktop/src/features/sidebar/ui/SidebarSection.tsx +++ b/desktop/src/features/sidebar/ui/SidebarSection.tsx @@ -328,6 +328,7 @@ export function SidebarSection({ {channel.channelType === "dm" && onHideDm ? ( onHideDm(channel.id)} showOnHover