diff --git a/components/dashboard/ContentHeader.tsx b/components/dashboard/ContentHeader.tsx index 91732f4..417fc13 100644 --- a/components/dashboard/ContentHeader.tsx +++ b/components/dashboard/ContentHeader.tsx @@ -1,67 +1,21 @@ 'use client' -import { useState, useEffect, useRef } from 'react' -import { MenuIcon, CollapseLeftIcon, formatUpdatedAgo } from '@ciphera-net/ui' -import { useSidebar } from '@/lib/sidebar-context' -import { useRealtime } from '@/lib/swr/dashboard' +import { MenuIcon } from '@ciphera-net/ui' export default function ContentHeader({ - siteId, onMobileMenuOpen, }: { - siteId: string onMobileMenuOpen: () => void }) { - const { collapsed, toggle } = useSidebar() - const { data: realtime } = useRealtime(siteId) - const lastUpdatedRef = useRef(null) - const [, setTick] = useState(0) - - // Track when realtime data last changed - useEffect(() => { - if (realtime) lastUpdatedRef.current = Date.now() - }, [realtime]) - - // Tick every second to keep "X seconds ago" fresh - useEffect(() => { - if (lastUpdatedRef.current == null) return - const timer = setInterval(() => setTick((t) => t + 1), 1000) - return () => clearInterval(timer) - }, [realtime]) - return ( -
- {/* Left — mobile hamburger or desktop collapse toggle */} -
- {/* Mobile hamburger */} - - - {/* Desktop collapse toggle */} - -
- - {/* Right — realtime indicator */} - {lastUpdatedRef.current != null && ( -
- - - - - Live · {formatUpdatedAgo(lastUpdatedRef.current)} -
- )} +
+
) } diff --git a/components/dashboard/DashboardShell.tsx b/components/dashboard/DashboardShell.tsx index 78ebcc3..0b5de5c 100644 --- a/components/dashboard/DashboardShell.tsx +++ b/components/dashboard/DashboardShell.tsx @@ -1,8 +1,11 @@ 'use client' -import { useState, useCallback } from 'react' +import { useState, useCallback, useEffect, useRef } from 'react' import dynamic from 'next/dynamic' -import { SidebarProvider } from '@/lib/sidebar-context' +import { formatUpdatedAgo } from '@ciphera-net/ui' +import { SidebarSimple } from '@phosphor-icons/react' +import { SidebarProvider, useSidebar } from '@/lib/sidebar-context' +import { useRealtime } from '@/lib/swr/dashboard' import ContentHeader from './ContentHeader' // Load sidebar only on the client — prevents SSR flash @@ -18,6 +21,47 @@ const Sidebar = dynamic(() => import('./Sidebar'), { ), }) +function GlassTopBar({ siteId }: { siteId: string }) { + const { collapsed, toggle } = useSidebar() + const { data: realtime } = useRealtime(siteId) + const lastUpdatedRef = useRef(null) + const [, setTick] = useState(0) + + useEffect(() => { + if (realtime) lastUpdatedRef.current = Date.now() + }, [realtime]) + + useEffect(() => { + if (lastUpdatedRef.current == null) return + const timer = setInterval(() => setTick((t) => t + 1), 1000) + return () => clearInterval(timer) + }, [realtime]) + + return ( +
+ {/* Collapse toggle */} + + + {/* Realtime indicator */} + {lastUpdatedRef.current != null && ( +
+ + + + + Live · {formatUpdatedAgo(lastUpdatedRef.current)} +
+ )} +
+ ) +} + export default function DashboardShell({ siteId, children, @@ -38,11 +82,16 @@ export default function DashboardShell({ onMobileClose={closeMobile} onMobileOpen={openMobile} /> -
- -
- {children} -
+
+ {/* Glass top bar — collapse toggle + realtime, in the margin above the content panel */} + + {/* Content panel */} +
+ +
+ {children} +
+