diff --git a/skills/gpui-kit-design-guides/references/design-guides.md b/skills/gpui-kit-design-guides/references/design-guides.md index 41f480d017..fc3dc0899d 100644 --- a/skills/gpui-kit-design-guides/references/design-guides.md +++ b/skills/gpui-kit-design-guides/references/design-guides.md @@ -575,6 +575,13 @@ In a segmented control, the selected fill and unselected surface must share the container's silhouette. Neither may square off an end corner or make a boundary appear heavier than its peers. +Show a selected navigation item, list row, or tab through the item's own +surface: a selected fill, stronger foreground, or heavier weight. Do not add a +leading-edge bar or one-sided border as the selection marker. It is a web +template habit, not a desktop convention; it breaks the item's rounded +silhouette and adds a second, competing edge to a column that already aligns +on its text. + For destructive actions, distinguish between reversible and irreversible work. Prefer undo or a temporary notification for reversible changes. Use an `AlertDialog` when the consequence is serious and cannot be undone; name the diff --git a/website/DESIGN.md b/website/DESIGN.md index 3889930fd0..bc550e125b 100644 --- a/website/DESIGN.md +++ b/website/DESIGN.md @@ -52,9 +52,13 @@ site and the documented components share one palette. Rules that follow from this: - **The brand colour is near-black (near-white in dark mode).** It is used for - primary buttons, focus rings and the active sidebar indicator — never as an + primary buttons and focus rings — never as an "accent" to add interest, because it is the same value as body text. Section kickers and captions use `--muted-foreground` instead. +- **The active sidebar item is a fill, not a bar.** It takes `--sidebar-accent` + (stronger than the `--secondary` hover fill) and a heavier weight. Never mark + it — or any selected item — with a leading-edge bar or one-sided border; see + the selection rule in the Design Guides. - **Never use `--brand` as a background behind text you did not also invert.** Text selection in particular uses `--selection`: black text on a near-black selection is unreadable. diff --git a/website/docs/design-guides.md b/website/docs/design-guides.md index 09f003e04a..9fdcbadcac 100644 --- a/website/docs/design-guides.md +++ b/website/docs/design-guides.md @@ -576,6 +576,13 @@ In a segmented control, the selected fill and unselected surface must share the container's silhouette. Neither may square off an end corner or make a boundary appear heavier than its peers. +Show a selected navigation item, list row, or tab through the item's own +surface: a selected fill, stronger foreground, or heavier weight. Do not add a +leading-edge bar or one-sided border as the selection marker. It is a web +template habit, not a desktop convention; it breaks the item's rounded +silhouette and adds a second, competing edge to a column that already aligns +on its text. + For destructive actions, distinguish between reversible and irreversible work. Prefer undo or a temporary notification for reversible changes. Use an `AlertDialog` when the consequence is serious and cannot be undone; name the diff --git a/website/src/components/Sidebar.astro b/website/src/components/Sidebar.astro index 9920dec524..6b49e76ae4 100644 --- a/website/src/components/Sidebar.astro +++ b/website/src/components/Sidebar.astro @@ -9,10 +9,27 @@ export interface Props { const { items, currentPath, lang = 'en' } = Astro.props; -function isActive(link: string): boolean { +function matches(link: string): boolean { return currentPath === link || currentPath.startsWith(link + '/'); } +function links(items: SidebarItem[]): string[] { + return items.flatMap(item => [ + ...(item.link ? [item.link] : []), + ...(item.items ? links(item.items) : []), + ]); +} + +// A section root such as `/docs` prefixes every page under it, so only the +// longest matching link is current; otherwise two items light up at once. +const activeLink = links(items) + .filter(matches) + .sort((a, b) => b.length - a.length)[0]; + +function isActive(link: string): boolean { + return link === activeLink; +} + ---