diff --git a/frontend/src/components/EditorLayout.tsx b/frontend/src/components/EditorLayout.tsx
index 9f5579d0..7a5266d1 100644
--- a/frontend/src/components/EditorLayout.tsx
+++ b/frontend/src/components/EditorLayout.tsx
@@ -17,10 +17,9 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Di
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from './ui/alert-dialog';
import { Tabs, TabsList, TabsTrigger, TabsHighlight, TabsHighlightItem } from './ui/tabs';
import { springs } from '@/lib/motion';
-import { Highlight, HighlightItem } from './animate-ui/primitives/effects/highlight';
import { CursorProvider, Cursor, CursorContainer, CursorFollow } from '@/components/animate-ui/primitives/animate/cursor';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
-import { Plus, Trash2, Play, Square, Save, Terminal, RotateCw, CloudDownload, Pencil, X, Home, ExternalLink, MoreVertical, BellRing, Rocket, HardDrive, ScrollText, Activity, Radar, Undo2, RefreshCw, Download, Clock, Menu, FolderSearch, Loader2, Tag, Check, ChevronDown, GitBranch, FileCode2, ShieldCheck, ArrowUpRight, Copy } from 'lucide-react';
+import { Plus, Trash2, Play, Square, Save, Terminal, RotateCw, CloudDownload, Pencil, X, Home, ExternalLink, MoreVertical, BellRing, Rocket, HardDrive, ScrollText, Activity, Radar, Undo2, RefreshCw, Download, Clock, FolderSearch, Loader2, Tag, Check, ChevronDown, GitBranch, FileCode2, ShieldCheck, ArrowUpRight, Copy } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import { LabelPill, LabelDot } from './LabelPill';
import { type Label as StackLabel } from './label-types';
@@ -39,7 +38,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/t
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from './ui/dropdown-menu';
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from './ui/context-menu';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
-import { Sheet, SheetContent, SheetTrigger } from './ui/sheet';
+import { TopBar } from './TopBar';
import { cn } from '@/lib/utils';
import { SettingsModal } from './SettingsModal';
import { StackAlertSheet } from './StackAlertSheet';
@@ -2482,60 +2481,14 @@ export default function EditorLayout() {
{/* Main Content Area */}
- {/* Top Header Bar — Three-zone layout: Node Pill | Navigation | Utilities */}
-
- {/* LEFT ZONE: Node Context Pill */}
-
- {activeNode?.type === 'remote' ? (
-
-
- {activeNode.name}
-
- ) : (
-
-
- {activeNode?.name ?? 'Local'}
-
- )}
-
-
- {/* CENTER ZONE: Navigation Group (hidden on mobile) */}
-
-
-
- {navItems.map(({ value, label, icon: Icon }) => (
-
-
-
- ))}
-
-
-
-
- {/* Spacer for mobile (when center nav is hidden) */}
-
-
- {/* RIGHT ZONE: Utilities */}
-
- {/* Notifications */}
+
-
-
- {/* User Profile Dropdown */}
+ }
+ userMenu={
setSettingsModalOpen(true)}
/>
-
- {/* Mobile Navigation Trigger */}
-
-
-
-
-
-
-
-
-
-
-
+ }
+ />
{/* Main Workspace */}
diff --git a/frontend/src/components/NotificationPanel.tsx b/frontend/src/components/NotificationPanel.tsx
index 7a36ce28..b12da6e7 100644
--- a/frontend/src/components/NotificationPanel.tsx
+++ b/frontend/src/components/NotificationPanel.tsx
@@ -132,11 +132,9 @@ export function NotificationPanel({
const bellBadge =
unreadCount > 0 ? (
-
- {unreadCount > 99 ? '99+' : unreadCount}
+
+
+
) : null;
@@ -154,7 +152,7 @@ export function NotificationPanel({
size="icon"
className="relative h-8 w-8 rounded-lg"
title="Notifications"
- aria-label="Notifications"
+ aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : 'Notifications'}
>
{bellBadge}
diff --git a/frontend/src/components/TopBar.tsx b/frontend/src/components/TopBar.tsx
new file mode 100644
index 00000000..ccc71a81
--- /dev/null
+++ b/frontend/src/components/TopBar.tsx
@@ -0,0 +1,128 @@
+import type { ReactNode } from 'react';
+import type { LucideIcon } from 'lucide-react';
+import { Menu } from 'lucide-react';
+import { Button } from './ui/button';
+import { Sheet, SheetContent, SheetTrigger } from './ui/sheet';
+import { Highlight, HighlightItem } from './animate-ui/primitives/effects/highlight';
+import { springs } from '@/lib/motion';
+import { cn } from '@/lib/utils';
+
+export interface TopBarNavItem {
+ value: string;
+ label: string;
+ icon: LucideIcon;
+}
+
+interface TopBarProps {
+ activeView: string;
+ navItems: TopBarNavItem[];
+ navTabValue: string | undefined;
+ onNavigate: (value: string) => void;
+ mobileNavOpen: boolean;
+ onMobileNavOpenChange: (open: boolean) => void;
+ notifications: ReactNode;
+ userMenu: ReactNode;
+}
+
+export function TopBar({
+ activeView,
+ navItems,
+ navTabValue,
+ onNavigate,
+ mobileNavOpen,
+ onMobileNavOpenChange,
+ notifications,
+ userMenu,
+}: TopBarProps) {
+ return (
+
+ {/* LEFT ZONE: reserved spacer (keeps nav visually centered) */}
+
+
+ {/* CENTER ZONE: Navigation (hidden on mobile) */}
+
+
+ {/* RIGHT ZONE: Utilities + identity pin */}
+
+ {notifications}
+ {userMenu}
+
+ {/* Mobile nav trigger */}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 0f81af3a..318191c5 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -148,6 +148,7 @@
/* Material simulation — inherent depth */
--card-bevel: inset 0 1px 0 0 oklch(1 0 0 / 0.04), 0 1px 2px 0 oklch(0 0 0 / 0.05);
--button-inner-glow: inset 0 1px 0 0 oklch(1 0 0 / 0.04);
+ --chrome-top-highlight: inset 0 1px 0 0 oklch(1 0 0 / 0.45);
/* Motion timing */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
@@ -304,6 +305,7 @@
/* Material simulation — inherent depth */
--card-bevel: inset 0 1px 0 0 oklch(1 0 0 / 0.05);
--button-inner-glow: inset 0 1px 0 0 oklch(1 0 0 / 0.06);
+ --chrome-top-highlight: inset 0 1px 0 0 oklch(1 0 0 / 0.08);
/* Shadows — near-zero, depth comes from surface tone */
--shadow-x: 0px;
@@ -413,6 +415,7 @@
--shadow-2xl: var(--shadow-2xl);
--shadow-card-bevel: var(--card-bevel);
--shadow-btn-glow: var(--button-inner-glow);
+ --shadow-chrome-top: var(--chrome-top-highlight);
}
/* ─────────────────────────────────────────────────────────────