feat: add a compact icon-only top navigation toggle (#1363)

* feat: add a compact icon-only top navigation toggle

Add a browser-local "Top navigation labels" preference under Settings >
Appearance. With it off, the desktop top navigation renders icon-only;
each destination keeps an aria-label, gains a hover/focus tooltip, and
stays reachable from the command palette. The setting defaults on, so
current behavior is preserved, and the mobile navigation always keeps
its labels.

Also left-align the desktop nav (previously centered) and shorten the
longest nav label from "Auto-Update" to "Update" so the bar scans faster.

* feat: let the icon-only top nav be left or centered

Add a "Top navigation alignment" preference under Settings > Appearance
that appears only when top navigation labels are off. It places the
icon-only bar against the left edge (the default) or centered. With
labels on, the nav always stays left so the longer labels read from the
edge. The choice is browser-local and persists per device.
This commit is contained in:
Anso
2026-06-12 10:49:36 -04:00
committed by GitHub
parent 2a4955f56d
commit 1b96f3b980
15 changed files with 391 additions and 38 deletions
@@ -2,11 +2,14 @@ import { Combobox } from '@/components/ui/combobox';
import { Checkbox } from '@/components/ui/checkbox';
import { Slider } from '@/components/ui/slider';
import { SegmentedControl } from '@/components/ui/segmented-control';
import { TogglePill } from '@/components/ui/toggle-pill';
import { useDensity } from '@/hooks/use-density';
import type { Density } from '@/hooks/use-density';
import { useDeployFeedbackEnabled } from '@/hooks/use-deploy-feedback-enabled';
import { useDeployFeedbackStyle, type DeployFeedbackStyle } from '@/hooks/use-deploy-feedback-style';
import { useComposeDiffPreviewEnabled } from '@/hooks/use-compose-diff-preview-enabled';
import { useTopNavLabels } from '@/hooks/use-top-nav-labels';
import { useTopNavAlign, type TopNavAlign } from '@/hooks/use-top-nav-align';
import { useTheme, THEME_MODE_OPTIONS, ACCENTS, CONTRAST, BORDER_BOOST, GLOW, TYPE_SCALE } from '@/hooks/use-theme';
import { AccentPicker } from '@/components/theme/AccentPicker';
import { ThemePreview } from '@/components/theme/ThemePreview';
@@ -31,6 +34,11 @@ const DEPLOY_STYLE_OPTIONS: { value: DeployFeedbackStyle; label: string }[] = [
{ value: 'inline', label: 'Inline' },
];
const TOP_NAV_ALIGN_OPTIONS: { value: TopNavAlign; label: string }[] = [
{ value: 'left', label: 'Left' },
{ value: 'center', label: 'Center' },
];
const fmtSigned = (v: number) => `${v > 0 ? '+' : ''}${v.toFixed(2)}`;
export function AppearanceSection() {
@@ -38,6 +46,8 @@ export function AppearanceSection() {
const [isEnabled, setEnabled] = useDeployFeedbackEnabled();
const [feedbackStyle, setFeedbackStyle] = useDeployFeedbackStyle();
const [diffPreviewEnabled, setDiffPreviewEnabled] = useComposeDiffPreviewEnabled();
const [topNavLabels, setTopNavLabels] = useTopNavLabels();
const [topNavAlign, setTopNavAlign] = useTopNavAlign();
const {
theme, accent, borderBoost, glow, contrast, uiFont, monoFont, typeScale,
setTheme, setAccent, setBorderBoost, setGlow, setContrast, setUiFont, setMonoFont, setTypeScale,
@@ -193,6 +203,27 @@ export function AppearanceSection() {
/>
</SettingsField>
<SettingsField
label="Top navigation labels"
helper="Show text labels beside top navigation icons. Turn off for a more compact navigation bar."
>
<TogglePill checked={topNavLabels} onChange={setTopNavLabels} />
</SettingsField>
{!topNavLabels && (
<SettingsField
label="Top navigation alignment"
helper="Place the icon-only navigation against the left edge or centered in the bar."
>
<SegmentedControl
value={topNavAlign}
options={TOP_NAV_ALIGN_OPTIONS}
onChange={setTopNavAlign}
ariaLabel="Top navigation alignment"
/>
</SettingsField>
)}
<SettingsField
label="Deploy progress"
helper="Stream live output for deploy, restart, update, install, and Git operations, with a warning when an operation goes quiet. On by default; turn it off to run operations without it."