44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { Sidebar } from "@/components/Sidebar";
|
|
|
|
export function AppShell({
|
|
title,
|
|
description,
|
|
actions,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
description: string;
|
|
actions?: ReactNode;
|
|
children: ReactNode;
|
|
}) {
|
|
return (
|
|
<div className="app-shell">
|
|
<a href="#main-content" className="skip-link">
|
|
Skip to main content
|
|
</a>
|
|
<Sidebar />
|
|
<main id="main-content" className="main-panel" tabIndex={-1} aria-labelledby="page-title">
|
|
<div className="page-grid">
|
|
<header
|
|
className="surface-card"
|
|
style={{ padding: "var(--ml-space-6)", display: "flex", justifyContent: "space-between", gap: "var(--ml-space-4)", alignItems: "start", flexWrap: "wrap" }}
|
|
>
|
|
<div style={{ display: "grid", gap: "var(--ml-space-2)" }}>
|
|
<h1
|
|
id="page-title"
|
|
style={{ margin: 0, fontFamily: "var(--ml-font-display)", fontSize: "var(--ml-fs-2xl)", fontWeight: 700 }}
|
|
>
|
|
{title}
|
|
</h1>
|
|
<div style={{ color: "var(--ml-text-secondary)", maxWidth: 720 }}>{description}</div>
|
|
</div>
|
|
{actions ? <div aria-label="Page actions">{actions}</div> : null}
|
|
</header>
|
|
{children}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|