import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { Badge } from "../Badge/Badge.tsx" import { Button } from "../Button/Button.tsx" import { StoryCell, StorySection, } from "../board.storyHelpers.tsx" import { Main } from "../Main/Main.tsx" import { Shell } from "../Shell/Shell.tsx" import { HeaderSchemeToggle, PageContent, ScrollFiller, } from "../shell.storyHelpers.tsx" import { Header } from "./Header.tsx" const meta = { title: "Components/Layout/Header", component: Header, parameters: { layout: "fullscreen" }, argTypes: { headingLevel: { control: { type: "radio" }, options: [1, 2], }, }, args: { headingLevel: 1, isSticky: true, }, } satisfies Meta export default meta type Story = StoryObj /** * The fleet's header, as one component: the app's name, the * controls that belong to the frame, a real `
` landmark, * and a fill that is `surface-raised` rather than the page's own * colour. */ export const Playground: Story = { parameters: playgroundParameters, args: { heading: "Rip Deck" }, render: (headerProps) => (
} />
), } /** * The three slots, in the order they render: the heading, the * middle (`children` — a search field, a breadcrumb, a status * pill), and `actions`, which is pushed to the far end. * * Every one is optional. A header with only actions is the * image-viewer's `TitleBar`; a header with only a heading is * board-games'. */ export const AllStates: Story = { render: (headerProps) => (
} heading="Points Market" />
} heading="Mail Sifter" > 412 unread
), } /** * **`isSticky` sets `position` and `z-index` together, and that * is the point.** mux-magic's `PageHeader` is documented as a * sticky header and sets only the z-index, so it scrolls away * like any other block — valid CSS, stated intent, no effect. * * Scroll the panel below. The z-index is `--layer-sticky` (100) * from the token scale, so a `Menu` opened from the header — at * `--layer-modal` (400) — still paints over it. */ export const AllVariants: Story = { render: (headerProps) => (
} heading="Scroll me" />
), } /** * `isSticky={false}` — the header scrolls away with the page, and * takes its z-index with it rather than leaving a stacking * context nobody asked for. board-games' `AppShell.tsx` is this * one: the same structure as mail-sifter's and points-market's, * minus `sticky`. */ export const NotSticky: Story = { args: { heading: "Board Games", isSticky: false }, render: (headerProps) => (
} />
), } /** * The width contract. **The `
` is full-bleed and only its * inner row is capped**, which is what stops a constrained header * from looking like a floating island on an ultrawide — and the * cap it uses is `Shell`'s, so the title always sits directly * above the content it names. * * points-market is the app where those two disagree: its header * row is capped at 80rem and its `
` is not capped at all. */ export const Responsive: Story = { render: (headerProps) => (
} heading="Narrow by contract" />
), } /** * What an agent reaches for. The header is a landmark, so * `getByRole("banner")` scopes every query inside it — which is * how one of the three "Settings" buttons on a page becomes * addressable. */ export const Interactive: Story = { args: { heading: "Rip Deck" }, render: (headerProps) => (
} />
), }