import { useState } from "react";
import { AppShell, Flex, PageContainer, Sidebar, Topbar } from "@godxjp/ui/layout";
import type { SidebarSectionProp } from "@godxjp/ui/layout";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
import { Button, Text } from "@godxjp/ui/general";
import { Input } from "@godxjp/ui/data-entry";
import {
Bell,
Building2,
FileText,
LayoutDashboard,
MessageSquare,
Plus,
Receipt,
Users,
} from "lucide-react";
/**
* AppShell · grid states, one per URL.
*
* The shell's grid is keyed on four attributes — `data-sidebar`, `data-nav-rail(-position)`,
* `data-collapsed` and `data-topbar-span` — and every combination is a real product shape. This
* frame renders ONE AppShell in whichever state the query names, so a browser gate can walk all of
* them (`scripts/check-app-shell-narrow-grid.mjs`) without stacking several `main` landmarks on a
* single page:
*
* ?topbarSpan=content|full ?navRail=start|end|top|bottom ?collapsed=1 ?sidebar=none
* ?responsive=docked ?measure=narrow|medium ?footer=1|row
*
* `measure` and `footer` feed `scripts/check-app-shell-page-width.mjs` (gh#672): the page is fluid
* in the main column at every sidebar state, and a sticky footer band always spans `.app-main`,
* even when a service caps content with `--app-shell-page-max-width` or the page sets `measure`.
* The footer's CONTENT sits in the same column as the body (gh#682), so the two shapes a footer
* takes are both rendered: `footer=1` an end-aligned action group, `footer=row` a full-row composer.
*
* With no query it is `topbarSpan="full"` without a rail — the state gh#474 found collapsing
* `main` into a 170px implicit track below 900px, with the page actions laid out past the edge.
*/
const SECTIONS: SidebarSectionProp[] = [
{
label: "会計",
items: [
{ id: "dashboard", label: "ダッシュボード", icon: LayoutDashboard },
{ id: "journal", label: "仕訳", icon: FileText },
{ id: "invoices", label: "請求書", icon: Receipt },
],
},
{
label: "管理",
items: [
{ id: "partners", label: "取引先", icon: Building2 },
{ id: "users", label: "ユーザー", icon: Users },
],
},
];
type RailPosition = "start" | "end" | "top" | "bottom";
function readState() {
const params = new URLSearchParams(window.location.search);
const rail = params.get("navRail");
return {
topbarSpan: params.get("topbarSpan") === "content" ? ("content" as const) : ("full" as const),
navRail: (["start", "end", "top", "bottom"] as const).find((p) => p === rail) as
RailPosition | undefined,
collapsed: params.get("collapsed") === "1",
hasSidebar: params.get("sidebar") !== "none",
responsiveNavigation:
params.get("responsive") === "docked" ? ("docked" as const) : ("drawer" as const),
measure: (["narrow", "medium"] as const).find((m) => m === params.get("measure")),
footer: (["1", "row"] as const).find((f) => f === params.get("footer")),
};
}
export default function Demo() {
const [{ topbarSpan, navRail, collapsed, hasSidebar, responsiveNavigation, measure, footer }] =
useState(readState);
const [activeId, setActiveId] = useState("dashboard");
const strip = navRail === "top" || navRail === "bottom";
return (
) : undefined
}
navRail={
navRail ? (
) : undefined
}
navRailPosition={navRail}
topbar={
CoreBooks}
end={
}
/>
}
>
) : footer === "row" ? (
) : undefined
}
stickyFooter={footer !== undefined}
extra={
}
>
今月の請求未送信 3 件 · 入金待ち 12 件
状態はクエリで切り替えます。どの状態でも 900px 以下では 1 列になり、main
は画面幅いっぱいに広がります。
);
}