From 2d2b551d46263332c4bbe2a20594e9aafc2e0fbd Mon Sep 17 00:00:00 2001 From: John Coffey Date: Sat, 19 Sep 2026 00:47:48 -0700 Subject: [PATCH] Areas in the top bar, the collapse toggle at the top of the sidebar Management, Settings and Account move to the top bar, as icons with tooltips beside the theme toggle. The sidebar opens with its area's name and the collapse toggle, in both states. The source link lives in the user menu, the sign-in card and the version tooltip, so the sidebar no longer repeats it. --- src/components/layout/Sidebar.tsx | 141 ++++++------------------------ src/components/layout/TopBar.tsx | 40 ++++++++- 2 files changed, 65 insertions(+), 116 deletions(-) diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 21c445a..08df8ff 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -8,11 +8,10 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import * as LucideIcons from 'lucide-react'; -const { ChevronDown, Lock, PanelLeftClose, PanelLeftOpen, FileCode } = LucideIcons; +const { ChevronDown, Lock, PanelLeftClose, PanelLeftOpen } = LucideIcons; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { EnterpriseUpsell } from '@/components/common/EnterpriseUpsell'; -import { SourceLink } from '@/components/common/SourceLink'; import { IconTile } from '@/components/common/IconTile'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { @@ -22,25 +21,13 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; -import { sourceDownloadUrl } from '@/lib/sourceDownload'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { useUIStore } from '@/stores/uiStore'; import { useAccountStore } from '@/stores/accountStore'; import { useSchemaStore } from '@/stores/schemaStore'; import { visibleLayouts, isLinkEnterprise, isLinkVisible } from '@/lib/layout'; -import { sectionLandingLink } from '@/lib/lastVisited'; import type { Layout, LayoutItem, LayoutSubItem } from '@/types/schema'; -function LucideIcon({ name, className }: { name: string; className?: string }) { - const formatted = name - .split('-') - .map((s) => s[0].toUpperCase() + s.slice(1)) - .join(''); - const IconComp = (LucideIcons as Record)[formatted] as LucideIcons.LucideIcon | undefined; - if (!IconComp) return ; - return ; -} - function resolveViewPath(sectionName: string, viewName: string): string { return `/${sectionName}/${viewName}`; } @@ -404,7 +391,6 @@ export function Sidebar() { const navigate = useNavigate(); const location = useLocation(); const activeSection = useUIStore((s) => s.activeSection); - const setActiveSection = useUIStore((s) => s.setActiveSection); const sidebarOpen = useUIStore((s) => s.sidebarOpen); const setSidebarOpen = useUIStore((s) => s.setSidebarOpen); const sidebarCollapsed = useUIStore((s) => s.sidebarCollapsed); @@ -441,12 +427,6 @@ export function Sidebar() { const layout: Layout | undefined = layouts.find((l) => l.name === activeSection); if (!layout) return null; - const handleSectionClick = (target: Layout) => { - setActiveSection(target.name); - const canGet = (prefix: string) => permissions.includes(`${prefix}Get`); - const first = sectionLandingLink(schema, target, edition, canGet, hasPermission); - if (first) navigate(`/${target.name}/${first}`); - }; // Folding to a rail is for wide screens; a phone keeps the slide-over. const collapsed = sidebarCollapsed && typeof window !== 'undefined' && window.matchMedia('(min-width: 768px)').matches; @@ -455,57 +435,7 @@ export function Sidebar() { return ( ); @@ -533,6 +475,18 @@ export function Sidebar() { onClick={() => setSidebarOpen(false)} /> diff --git a/src/components/layout/TopBar.tsx b/src/components/layout/TopBar.tsx index 0730326..0bf29e8 100644 --- a/src/components/layout/TopBar.tsx +++ b/src/components/layout/TopBar.tsx @@ -26,10 +26,11 @@ import { EnterpriseUpsell } from '@/components/common/EnterpriseUpsell'; import { sourceDownloadUrl } from '@/lib/sourceDownload'; import { visibleLayouts } from '@/lib/layout'; import { sectionLandingLink } from '@/lib/lastVisited'; +import { cn } from '@/lib/utils'; import { useUIStore } from '@/stores/uiStore'; import { useAuthStore } from '@/stores/authStore'; import { buildEndSessionUrl, getPostLogoutRedirectUri } from '@/services/auth/oauth'; -import { useEffect, useState } from 'react'; +import { createElement, useEffect, useState } from 'react'; import { useAccountStore } from '@/stores/accountStore'; import { useSchemaStore } from '@/stores/schemaStore'; @@ -50,6 +51,7 @@ export function TopBar() { const toggleTheme = useUIStore((s) => s.toggleTheme); const toggleSidebar = useUIStore((s) => s.toggleSidebar); const setActiveSection = useUIStore((s) => s.setActiveSection); + const activeSection = useUIStore((s) => s.activeSection); const accounts = useAuthStore((s) => s.accounts); const activeAccountId = useAuthStore((s) => s.activeAccountId); const switchAccount = useAuthStore((s) => s.switchAccount); @@ -124,6 +126,42 @@ export function TopBar() { + {/* INBUXA: the three areas, one click away, where the eye already looks. */} + {schema && navigableLayouts.length > 1 && ( + +
+ {navigableLayouts.map((layout) => { + const isActive = layout.name === activeSection; + return ( + + + + + {layout.name} + + ); + })} +
+
+ )} +