diff --git a/web/src/components/AppSidebar/AppSidebar.tsx b/web/src/components/AppSidebar/AppSidebar.tsx index b31d964f..c44a0110 100644 --- a/web/src/components/AppSidebar/AppSidebar.tsx +++ b/web/src/components/AppSidebar/AppSidebar.tsx @@ -54,11 +54,20 @@ import { getSidebarRouteKind, routeSupportsCollectionScope } from "./routes"; import SidebarRow, { SIDEBAR_ROW_CLASSES, SIDEBAR_ROW_FOCUS_CLASSES, SidebarRowIconSlot, sidebarRowStateClasses } from "./SidebarRow"; import SidebarSection, { SIDEBAR_SECTION_STACK_CLASSES } from "./SidebarSection"; import SpaceSwitcher from "./SpaceSwitcher"; +import { + SIDEBAR_FOOTER_CLASSES, + SIDEBAR_LEADING_SLOT_CLASSES, + SIDEBAR_NAV_LEADING_SLOT_CLASSES, + SIDEBAR_RAIL_CLASSES, + sidebarSurfaceVariants, +} from "./sidebar-layout"; import TagsSection from "./TagsSection"; import ViewsSection from "./ViewsSection"; -const SIDEBAR_HORIZONTAL_PADDING = "px-3"; -const SIDEBAR_HEADER_ACTION_CLASSES = "size-7 shrink-0 rounded-md text-muted-foreground hover:text-foreground"; +const SIDEBAR_HEADER_ACTION_CLASSES = + "size-7 shrink-0 rounded-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/50"; +const SIDEBAR_HEADER_PRIMARY_ACTION_CLASSES = + "size-7 shrink-0 text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/50"; const NewMemoAction = ({ onClick }: { onClick: () => void }) => { const t = useTranslate(); @@ -69,9 +78,9 @@ const NewMemoAction = ({ onClick }: { onClick: () => void }) => { 1fr. That - * keeps the expand/collapse a single smooth motion with no padding jump. + * The compact navigator is intentionally horizontal. Its 16px glyph plus 8px padding + * on each side makes the collapsed control an exact 32px square. Expanding the + * label only opens the text track, so the artwork and surface never jump. */ const navPillClasses = (active: boolean) => - cn( - "relative flex h-[30px] min-w-0 items-center rounded-md px-[7px] transition-colors", - SIDEBAR_ROW_FOCUS_CLASSES, - sidebarRowStateClasses(active), - ); + cn(sidebarSurfaceVariants({ role: "navPill" }), SIDEBAR_ROW_FOCUS_CLASSES, sidebarRowStateClasses(active)); const NavPillLabel = ({ expanded, label, children }: { expanded: boolean; label: ReactNode; children?: ReactNode }) => ( - {/* Content is shrink-0 so the collapsing track clips it in place — a plain - left-to-right reveal instead of re-truncating the label on every frame. */} - - {label} + + + {label} + {children} @@ -401,9 +403,9 @@ const GlobalNavigation = () => { }, ]; - // Keep one textual anchor in the compact navigator. A real active destination - // takes precedence; routes outside this navigation default to its first item - // without presenting that fallback as the current page. + // Keep exactly one textual anchor in the compact horizontal navigator. The active + // destination expands; routes outside this navigator fall back to its first control + // without incorrectly marking that fallback as the current page. const activeNavigatorItemId = currentUser && scopeRouteActive ? "scope" : items.find((item) => item.active)?.id; const expandedNavigatorItemId = activeNavigatorItemId ?? (currentUser ? "scope" : items[0]?.id); const scopeExpanded = expandedNavigatorItemId === "scope"; @@ -416,10 +418,7 @@ const GlobalNavigation = () => { navigateToScope(item.id)} > @@ -432,12 +431,11 @@ const GlobalNavigation = () => { return ( -