'use client';
import {AppShell} from '@astryxdesign/core/AppShell';
import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
import {AppSideNav} from '@/components/shell/AppSideNav';
import {AppTopNav} from '@/components/shell/AppTopNav';
import {MobileScopeNav} from '@/components/shell/MobileScopeNav';
import {CopilotPanel} from '@/features/copilot/CopilotPanel';
import {CopilotSlideOver} from '@/features/copilot/CopilotSlideOver';
import {useCopilot} from '@/features/copilot/CopilotProvider';
import {useBreakpoint, isPanelInline, copilotWidth} from '@/lib/breakpoints';
/**
* The three-column shell, and the reason the Copilot survives navigation.
*
* Next's App Router preserves a layout's element identity across sibling route
* changes, so /dashboard → /staff swaps only {children}. Everything else here —
* nav, scroll position, the Copilot — is untouched.
*
* Structure, and why AppShell alone is not enough: AppShell renders
* Layout{start, content} internally and exposes no end/panel slot. The Copilot
* column therefore comes from a NESTED Layout inside AppShell's children,
* using its `end` slot.
*
* AppShell(topNav, sideNav)
* └─ Layout(content = page, end = LayoutPanel > CopilotPanel)
*
* variant="elevated" is what produces the described visual for free: with both
* navs present the shell root and rails paint --color-background-body (#000),
* and the content area sits on an elevated --color-background-surface (#0F0F10)
* backdrop with --radius-page on the start corner.
*/
export default function WorkspaceLayout({
children,
}: {
children: React.ReactNode;
}) {
const bp = useBreakpoint();
const {isOpen} = useCopilot();
const inline = isPanelInline(bp);
const showInlinePanel = inline && isOpen;
return (
}
sideNav={}
// Supplied explicitly rather than auto-generated: the default drawer
// mirrors sideNav only, which would leave the store and range controls
// unreachable below 768px (they live in TopNav's collapsing start slot).
mobileNav={{breakpoint: 'md', content: }}
>
{children}}
end={
showInlinePanel ? (
) : undefined
}
/>
{/* Mounted only below the inline breakpoint. Because every piece of
Copilot state lives in CopilotProvider (above the route tree), moving
between these two presentations is lossless. */}
{!inline ? : null}
);
}