Files
gridpilot.gg/apps/website/ui/Layout.tsx
2026-01-19 21:41:59 +01:00

85 lines
2.1 KiB
TypeScript

import { ReactNode } from 'react';
import { Box } from './Box';
export interface LayoutProps {
children: ReactNode;
header?: ReactNode;
footer?: ReactNode;
sidebar?: ReactNode;
/**
* Whether the sidebar should be fixed to the side.
* If true, the main content will be offset by the sidebar width.
*/
fixedSidebar?: boolean;
/**
* Whether the header should be fixed to the top.
* If true, the main content will be offset by the header height.
*/
fixedHeader?: boolean;
}
/**
* Layout is the canonical app frame component.
* It orchestrates the high-level structure: Header, Sidebar, Main Content, and Footer.
*/
export const Layout = ({
children,
header,
footer,
sidebar,
fixedSidebar = false,
fixedHeader = false
}: LayoutProps) => {
return (
<Box display="flex" flexDirection="col" minHeight="100vh">
{header && (
<Box
as="header"
position={fixedHeader ? "fixed" : "relative"}
top={fixedHeader ? 0 : undefined}
left={fixedHeader ? 0 : undefined}
right={fixedHeader ? 0 : undefined}
zIndex={50}
>
{header}
</Box>
)}
<Box display="flex" flex={1} marginTop={fixedHeader ? 14 : undefined}>
{sidebar && (
<Box
as="aside"
width="64"
display={{ base: 'none', lg: 'block' }}
position={fixedSidebar ? "fixed" : "relative"}
top={fixedSidebar ? (fixedHeader ? 14 : 0) : undefined}
bottom={fixedSidebar ? 0 : undefined}
left={fixedSidebar ? 0 : undefined}
zIndex={40}
>
{sidebar}
</Box>
)}
<Box
as="main"
flex={1}
display="flex"
flexDirection="col"
marginLeft={fixedSidebar ? { lg: 64 } : undefined}
>
<Box flex={1}>
{children}
</Box>
{footer && (
<Box as="footer">
{footer}
</Box>
)}
</Box>
</Box>
</Box>
);
};