54 lines
2.3 KiB
TypeScript
54 lines
2.3 KiB
TypeScript
import { useEffect, useState, type CSSProperties, type ReactNode } from 'react'
|
||
import { Skeleton } from '@authportal/ui/components/skeleton'
|
||
import { SidebarInset, SidebarProvider } from '@authportal/ui/components/sidebar'
|
||
import { TooltipProvider } from '@authportal/ui/components/tooltip'
|
||
import { CommandPalette, PreviewHeader, PreviewSidebar } from './preview-chrome'
|
||
import { UnsavedBar } from './unsaved-bar'
|
||
import './design-preview.css'
|
||
|
||
/** Оболочка макета: сайдбар, шапка, палитра и панель «Не сохранено». Монтируется после гидрации. */
|
||
export function PreviewShell({ children }: { children: ReactNode }) {
|
||
const [mounted, setMounted] = useState(false)
|
||
const [open, setOpen] = useState(true)
|
||
useEffect(() => {
|
||
// До 1100px меню сворачивается в колонку иконок (на мобильных его заменяет Sheet).
|
||
const mq = window.matchMedia('(min-width: 1100px)')
|
||
const sync = () => setOpen(mq.matches)
|
||
sync()
|
||
mq.addEventListener('change', sync)
|
||
setMounted(true)
|
||
return () => mq.removeEventListener('change', sync)
|
||
}, [])
|
||
|
||
if (!mounted) {
|
||
return (
|
||
<div className="flex min-h-svh flex-col gap-4 p-6" aria-busy>
|
||
<Skeleton className="h-12 w-full" />
|
||
<Skeleton className="h-64 w-full" />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<TooltipProvider delay={0}>
|
||
<SidebarProvider open={open} onOpenChange={setOpen} style={{ '--sidebar-width': '240px' } as CSSProperties}>
|
||
<a
|
||
href="#main-content"
|
||
className="bg-background text-foreground ring-ring sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:z-50 focus:rounded-md focus:px-3 focus:py-2 focus:text-sm focus:font-medium focus:ring-2"
|
||
>
|
||
К содержимому
|
||
</a>
|
||
<PreviewSidebar />
|
||
<SidebarInset id="main-content" className="min-w-0">
|
||
<PreviewHeader />
|
||
<div className="mx-auto flex w-full min-w-0 max-w-[1480px] flex-1 flex-col gap-4 px-4 py-4 pb-24 md:gap-6 md:px-6 md:py-5 md:pb-24">
|
||
{children}
|
||
</div>
|
||
</SidebarInset>
|
||
<CommandPalette />
|
||
<UnsavedBar />
|
||
</SidebarProvider>
|
||
</TooltipProvider>
|
||
)
|
||
}
|