From 447e43eac58155f5ddc4628731814b8f36a0fba0 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Mon, 24 Aug 2026 17:41:34 +0300 Subject: [PATCH] style(header): session tabs follow the titlebar tab design language Uniform compact tabs (h-7, 6px radius, 13px medium) that share the strip width and shrink before scrolling, thin separators between inactive neighbours that disappear around the active or hovered tab, a hover-revealed menu button anchored to the tab's end, a soft selection pill for the active tab, and hidden scrollbars with fade edges. The active tab is single-line: the project/branch meta row stays only in the VS Code header, which keeps the plain title. --- packages/ui/src/components/layout/Header.tsx | 27 +++------------ .../components/layout/SessionTabsStrip.tsx | 33 ++++++++++++------- packages/ui/src/index.css | 22 +++++++++++++ 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 82f3b5c1..39245efd 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -1739,6 +1739,7 @@ export const Header: React.FC = () => {
event.stopPropagation()} onSubmit={(event) => { event.preventDefault(); void saveHeaderSessionRename(); @@ -1755,7 +1756,7 @@ export const Header: React.FC = () => { } }} placeholder={t('sessions.sidebar.session.menu.rename')} - className="min-w-0 flex-1 bg-transparent typography-ui-label text-[14px] font-normal leading-tight outline-none placeholder:text-muted-foreground" + className="min-w-0 flex-1 bg-transparent text-[13px] font-medium leading-4 outline-none placeholder:text-muted-foreground" />
) : ( - + {isNewSessionDraftOpen ? t('sessions.switcher.draftTitle') : currentSessionTitle} )} - {showHeaderMetaRow ? ( - - {activeProjectLabel ? {activeProjectLabel} : null} - {currentBranchLabel ? ( - - - {currentBranchLabel} - - ) : null} - {!isNewSessionDraftOpen && worktreeBadgeKind ? ( - - - {worktreeBadge} - - ) : null} - - ) : null}
{currentSessionId && !isNewSessionDraftOpen && !isRenamingHeaderSession ? ( = ({ i
{children}
@@ -85,7 +86,8 @@ const InactiveSessionTab: React.FC<{
@@ -107,13 +109,19 @@ const InactiveSessionTab: React.FC<{ } }} className={cn( - 'group/session-tab flex h-8 max-w-[200px] cursor-pointer touch-none select-none items-center rounded-[10px] px-3', - 'text-muted-foreground transition-colors duration-150 hover:bg-interactive-hover/40 hover:text-foreground', - menuOpen && 'bg-interactive-hover/40 text-foreground', + 'group/session-tab relative flex h-7 w-full min-w-0 cursor-pointer touch-none select-none items-center rounded-md px-2', + 'text-muted-foreground transition-colors duration-150 hover:bg-interactive-hover hover:text-foreground', + menuOpen && 'bg-interactive-hover text-foreground', )} title={title} > - + {title} @@ -124,10 +132,10 @@ const InactiveSessionTab: React.FC<{ onClick={(event) => event.stopPropagation()} onPointerDown={(event) => event.stopPropagation()} className={cn( - 'ml-0 hidden w-0 shrink-0 items-center justify-center overflow-hidden rounded-md text-muted-foreground', + 'absolute right-1 top-1/2 hidden size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground', 'opacity-0 transition-opacity duration-150 hover:text-foreground', - 'group-hover/session-tab:ml-1.5 group-hover/session-tab:flex group-hover/session-tab:h-5 group-hover/session-tab:w-5 group-hover/session-tab:opacity-100', - menuOpen && 'ml-1.5 flex h-5 w-5 opacity-100', + 'group-hover/session-tab:flex group-hover/session-tab:opacity-100', + menuOpen && 'flex opacity-100', )} > @@ -298,7 +306,7 @@ export const SessionTabsStrip: React.FC<{ children: React.ReactNode }> = ({ chil
= ({ chil
{children}
diff --git a/packages/ui/src/index.css b/packages/ui/src/index.css index c487cd09..d37798cc 100644 --- a/packages/ui/src/index.css +++ b/packages/ui/src/index.css @@ -1781,3 +1781,25 @@ html.desktop-runtime [class*="cursor-pointer"] { html.desktop-runtime .markdown-content [data-openchamber-file-link="true"] { cursor: default; } + +/* Header session tabs: thin separators between inactive neighbours, hidden + around the active or hovered tab (mirrors the titlebar tab language). */ +.session-tab-slot { + position: relative; +} +.session-tab-slot:not(:first-child):not([data-active='true'])::before { + content: ''; + position: absolute; + top: 8px; + inset-inline-start: -2.75px; + width: 1.5px; + height: 12px; + border-radius: 9999px; + background: var(--border); + opacity: 0.6; +} +.session-tab-slot[data-active='true'] + .session-tab-slot::before, +.session-tab-slot:not([data-active='true']):hover::before, +.session-tab-slot:not([data-active='true']):hover + .session-tab-slot::before { + display: none; +}