Files
pulse/components/dashboard/DashboardShell.tsx
Usman Baig 6d649d8dc4 fix: reserve sidebar space with placeholder during SSR
With ssr:false, the sidebar rendered nothing in server HTML, so the
content area took full width and page content (site name "Ciphera")
appeared in the sidebar zone. Now the dynamic import has a loading
placeholder — a 64px div with matching border/background that reserves
the sidebar space in the server HTML. Content area never occupies the
sidebar zone. Sidebar replaces the placeholder on client mount.
2026-03-18 20:01:01 +01:00

48 lines
1.3 KiB
TypeScript

'use client'
import { useState, useCallback } from 'react'
import dynamic from 'next/dynamic'
import ContentHeader from './ContentHeader'
// Load sidebar only on the client — prevents SSR flash
const Sidebar = dynamic(() => import('./Sidebar'), {
ssr: false,
// Placeholder reserves the sidebar's space in the server HTML
// so page content never occupies the sidebar zone
loading: () => (
<div
className="hidden md:block shrink-0 border-r border-neutral-200/60 dark:border-neutral-800/60 bg-white/90 dark:bg-neutral-900/90 backdrop-blur-xl"
style={{ width: 64 }}
/>
),
})
export default function DashboardShell({
siteId,
children,
}: {
siteId: string
children: React.ReactNode
}) {
const [mobileOpen, setMobileOpen] = useState(false)
const closeMobile = useCallback(() => setMobileOpen(false), [])
const openMobile = useCallback(() => setMobileOpen(true), [])
return (
<div className="flex h-screen overflow-hidden">
<Sidebar
siteId={siteId}
mobileOpen={mobileOpen}
onMobileClose={closeMobile}
onMobileOpen={openMobile}
/>
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
<ContentHeader onMobileMenuOpen={openMobile} />
<main className="flex-1 overflow-y-auto pt-6">
{children}
</main>
</div>
</div>
)
}