fix: restructure icon rail to 5 grouped items (Sentry-style)

Home, Work, Knowledge, Insights, Help — each with hover flyout
showing sub-items. Sidebar now stretches to full viewport height.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-03-22 01:05:41 -04:00
parent 8efc443949
commit bef649bb9a

View File

@@ -5,6 +5,7 @@ import {
LayoutGrid, Clock, AlertTriangle, GitBranch, Layers, Code2, Wand2,
ListChecks, Download, BarChart3, Rocket, BookOpen, MessageSquare,
Settings, Pin, PinOff,
Zap, Database, HelpCircle,
} from 'lucide-react'
import { cn } from '@/lib/utils'
import { useUserPreferencesStore } from '@/store/userPreferencesStore'
@@ -62,6 +63,57 @@ export function Sidebar() {
/* ── Navigation data ──────────────────────────────── */
/* ── Grouped nav: 5 top-level icons (Sentry-style) ── */
const railGroups: NavEntry[] = [
{
href: '/', icon: LayoutGrid, label: 'Home', shortLabel: 'Home',
matchPaths: ['/'],
},
{
href: '/sessions', icon: Zap, label: 'Work', shortLabel: 'Work',
badge: (stats?.active_count || 0) + (stats?.escalation_count || 0) || undefined,
matchPaths: ['/sessions', '/escalations', '/pilot'],
children: [
{ href: '/sessions', label: 'Active Sessions', count: stats?.active_count || undefined },
{ href: '/escalations', label: 'Escalations', count: stats?.escalation_count || undefined },
],
},
{
href: '/trees', icon: Database, label: 'Knowledge', shortLabel: 'Know',
badge: stats?.tree_counts.total || undefined,
matchPaths: ['/trees', '/flows', '/my-trees', '/step-library', '/scripts', '/script-builder', '/review-queue'],
children: [
{ href: '/trees', label: 'All Flows', count: stats?.tree_counts.total || undefined },
{ href: '/trees?type=troubleshooting', label: 'Troubleshooting', count: stats?.tree_counts.troubleshooting || undefined },
{ href: '/trees?type=procedural', label: 'Projects', count: stats?.tree_counts.procedural || undefined },
{ href: '/trees?type=maintenance', label: 'Maintenance', count: stats?.tree_counts.maintenance || undefined },
{ href: '/step-library', label: 'Step Library' },
{ href: '/scripts', label: 'Scripts' },
{ href: '/script-builder', label: 'Script Builder' },
{ href: '/review-queue', label: 'Review Queue' },
],
},
{
href: '/analytics', icon: BarChart3, label: 'Insights', shortLabel: 'Data',
matchPaths: ['/analytics', '/shares'],
children: [
{ href: '/shares', label: 'Exports' },
{ href: '/analytics', label: 'Analytics' },
{ href: '/analytics/flowpilot', label: 'FlowPilot Analytics' },
],
},
{
href: '/guides', icon: HelpCircle, label: 'Help', shortLabel: 'Help',
matchPaths: ['/guides', '/feedback'],
children: [
{ href: '/guides', label: 'User Guides' },
{ href: '/feedback', label: 'Feedback' },
],
},
]
/* Pinned mode still uses the detailed section layout */
const sections: NavSection[] = [
{
title: 'RESOLVE',
@@ -102,8 +154,6 @@ export function Sidebar() {
]
const footerItems: NavEntry[] = [
{ href: '/guides', icon: BookOpen, label: 'User Guides', shortLabel: 'Guides' },
{ href: '/feedback', icon: MessageSquare, label: 'Feedback', shortLabel: 'Feedbk' },
{ href: '/account', icon: Settings, label: 'Account', shortLabel: 'Acct' },
]
@@ -167,7 +217,7 @@ export function Sidebar() {
return (
<div
key={key}
className="relative"
className="relative w-full"
onMouseEnter={() => hasChildren && !sidebarPinned ? openFlyout(key) : undefined}
onMouseLeave={() => hasChildren && !sidebarPinned ? closeFlyout() : undefined}
>
@@ -378,30 +428,27 @@ export function Sidebar() {
)
}
/* Icon Rail (default) */
/* Icon Rail (default) — 5 grouped icons, Sentry-style */
return (
<nav
ref={sidebarRef}
className="sidebar flex flex-col items-center"
style={{ background: '#0f1118', borderRight: '1px solid #1e2130' }}
className="sidebar flex flex-col items-center h-full"
style={{ background: '#0f1118', borderRight: '1px solid #1e2130', minHeight: '100vh' }}
onWheel={handleWheel}
>
{/* Nav sections */}
<div className="flex flex-col items-center w-full px-1.5 py-2 space-y-0.5">
{sections.map((section, si) => (
<div key={section.title} className="w-full">
{si > 0 && (
<div className="mx-3 my-2" style={{ borderTop: '1px solid #1e2130' }} />
)}
{section.items.map((item, ii) => renderRailItemWithRef(item, `${si}-${ii}`))}
{/* Grouped nav items */}
<div className="flex flex-col items-center w-full px-1.5 pt-3 space-y-1">
{railGroups.map((item, i) => (
<div key={`rail-${i}`} data-flyout-key={`rail-${i}`}>
{renderRailItem(item, `rail-${i}-inner`)}
</div>
))}
</div>
<div className="flex-1" />
{/* Footer */}
<div className="flex flex-col items-center w-full px-1.5 py-2 space-y-0.5" style={{ borderTop: '1px solid #1e2130' }}>
{/* Footer: Account + Pin */}
<div className="flex flex-col items-center w-full px-1.5 pb-3 space-y-1" style={{ borderTop: '1px solid #1e2130' }}>
{footerItems.map((item, i) => (
<div key={`footer-${i}`} data-flyout-key={`footer-${i}`}>
{renderRailItem(item, `footer-${i}-inner`)}