From 35a002a4412dbfaa41ea84d1b02dc9c1350f390f Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Mon, 27 Jul 2026 15:58:22 -0500 Subject: [PATCH] feat(desktop): mark the active pane tab with a primary underline The active tab was defined by absence: the strip painted a rule and the tab covered it, so inactive tabs stopped a pixel short to let it show. Draw the state instead. The tab carries its own 2px --theme-primary underline and the strip's rule goes away, which lets tabs run full height and removes PANE_TAB_STRIP_LINE along with it. --- .../src/app/chat/right-rail/preview.tsx | 9 ++------ .../pane-shell/tree/renderer/tree-group.tsx | 10 +++------ apps/desktop/src/components/ui/pane-tab.tsx | 21 ++++++++++--------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/apps/desktop/src/app/chat/right-rail/preview.tsx b/apps/desktop/src/app/chat/right-rail/preview.tsx index 219a28aacfc..9d9a6b3950e 100644 --- a/apps/desktop/src/app/chat/right-rail/preview.tsx +++ b/apps/desktop/src/app/chat/right-rail/preview.tsx @@ -10,7 +10,7 @@ import { ContextMenuSeparator, ContextMenuTrigger } from '@/components/ui/context-menu' -import { PANE_TAB_STRIP_LINE, PaneTab, PaneTabLabel } from '@/components/ui/pane-tab' +import { PaneTab, PaneTabLabel } from '@/components/ui/pane-tab' import { Tip } from '@/components/ui/tooltip' import { translateNow, useI18n } from '@/i18n' import { formatCombo } from '@/lib/keybinds/combo' @@ -131,12 +131,7 @@ export function ChatPreviewRail({ onRestartServer, setTitlebarToolGroup }: ChatP // titlebar-height so it opens below the band. 0px elsewhere → unchanged. style={{ paddingTop: 'var(--right-rail-top-inset, 0px)' }} > -
+
{ setMenuPane( diff --git a/apps/desktop/src/components/ui/pane-tab.tsx b/apps/desktop/src/components/ui/pane-tab.tsx index c7698bb944f..5606e9a7f28 100644 --- a/apps/desktop/src/components/ui/pane-tab.tsx +++ b/apps/desktop/src/components/ui/pane-tab.tsx @@ -2,9 +2,6 @@ import * as React from 'react' import { cn } from '@/lib/utils' -/** Inset bottom stroke for a horizontal tab strip — titlebar color, cut by the active tab. */ -export const PANE_TAB_STRIP_LINE = 'shadow-[inset_0_-1px_0_var(--ui-stroke-tertiary)]' - /** Inset stroke for a vertical tab rail — content-facing edge. */ export const PANE_TAB_STRIP_LINE_LEFT = 'shadow-[inset_1px_0_0_var(--ui-stroke-tertiary)]' export const PANE_TAB_STRIP_LINE_RIGHT = 'shadow-[inset_-1px_0_0_var(--ui-stroke-tertiary)]' @@ -12,18 +9,20 @@ export const PANE_TAB_STRIP_LINE_RIGHT = 'shadow-[inset_-1px_0_0_var(--ui-stroke const TAB = 'group/tab relative flex shrink-0 items-center border-transparent bg-(--tab-bg) text-[0.6875rem] font-medium [-webkit-app-region:no-drag]' -// Stop 1px short: the strip's rule is an INSET shadow painted in the -// container's own last pixel row, so a full-height tab covers it and reads as -// overhanging the bar. The container owns the line; nothing redraws it. -const TAB_HORIZONTAL = - 'h-[calc(100%-1px)] min-w-0 max-w-48 not-first:border-l not-first:border-l-(--ui-stroke-quaternary)' +// Full height: with the strip's rule removed there is no last-pixel row to +// leave uncovered, so tabs fill the bar and no sliver of gutter shows through. +const TAB_HORIZONTAL = 'h-full min-w-0 max-w-48 not-first:border-l not-first:border-l-(--ui-stroke-quaternary)' const TAB_VERTICAL = 'w-full max-h-48 justify-center not-first:border-t not-first:border-t-(--ui-stroke-quaternary) [writing-mode:vertical-rl]' -// Full height, so the active tab alone covers that row and cuts the rule. const TAB_ACTIVE = 'h-full text-foreground [--tab-bg:var(--pane-tab-active-bg,var(--ui-editor-surface-background))]' +// Horizontal only: the active tab is the sole seam on the strip — a +// theme-primary underline drawn as an inset shadow in its own last pixel row, +// so it costs no layout and can't shift the tab. +const TAB_ACTIVE_UNDERLINE = 'shadow-[inset_0_-2px_0_var(--pane-tab-active-accent,var(--theme-primary))]' + // Inactive = gutter. Hover DARKENS: active is the lighter content surface, so a // lightening wash made the two nearly indistinguishable. const TAB_IDLE = @@ -81,7 +80,9 @@ export const PaneTab = React.forwardRef(function P TAB, vertical ? TAB_VERTICAL : TAB_HORIZONTAL, edge, - active ? TAB_ACTIVE : cn(TAB_IDLE, edge && `${edge}-(--ui-stroke-tertiary)`), + active + ? cn(TAB_ACTIVE, !vertical && TAB_ACTIVE_UNDERLINE) + : cn(TAB_IDLE, edge && `${edge}-(--ui-stroke-tertiary)`), className )} data-active={active}