import type { Meta, StoryObj } from '@storybook/react-vite'
import { IconMenu2, IconSquareRounded } from '@tabler/icons-react'
import { AppShell } from './AppShell'
import { Banner } from './Banner'
import { EmptyState } from './EmptyState'
import { IconButton } from './IconButton'
import { NavItem } from './NavItem'
import { PersonTrigger } from './PersonTrigger'
import { Rail } from './Rail'
import { RailItem } from './RailItem'
import { Sidebar } from './Sidebar'
const meta = {
title: 'Frame/AppShell',
component: AppShell,
parameters: {
layout: 'fullscreen',
// axe color-contrast is off here until PLAN.md stage 0.10 is ruled:
// the count chip is muted text, 3.06:1 on the active row in signal, and the info
// banner reads 3.99:1 on its wash in ship (AA 4.5:1).
a11y: { config: { rules: [{ id: 'color-contrast', enabled: false }] } },
},
args: { nav: null, children: null },
argTypes: {
variant: { control: 'inline-radio', options: ['solid', 'floating'] },
menu: { control: false },
logo: { control: false },
search: { control: false },
onSearch: { control: false },
identity: { control: false },
banner: { control: false },
nav: { control: false },
children: { control: false },
},
decorators: [(Story) =>
{Story()}
],
} satisfies Meta
export default meta
type Story = StoryObj
const identity =
const menuButton = (
)
const placeholder =
const sidebar = (
)
const rail = (
)
/** The structured frame: solid bar, sidebar, content beside it. */
export const Solid: Story = {
render: (args) => (
{}} identity={identity} nav={sidebar}>
),
}
/** The banner belongs to the content area — at its top, never across the navigation. */
/** A page taller than the frame: it scrolls in the frame's own bar — the region every page passes through — never a native one. */
export const SolidScrolls: Story = {
render: (args) => (
{}} identity={identity} nav={sidebar}>
{Array.from({ length: 60 }, (_, i) => (
Row {i + 1}
))}
),
}
export const SolidWithBanner: Story = {
render: (args) => (
Public key copied.}>
),
}
/** The structured frame the other way round: the bar and the sidebar on the ground, the content a lighter card beside them. */
export const Inset: Story = {
args: { variant: 'inset' },
render: (args) => (
{}} identity={identity} nav={sidebar}>
),
}
export const InsetWithBanner: Story = {
args: { variant: 'inset' },
render: (args) => (
Public key copied.}>
),
}
/** The floating frame: the bar floats over the top edge, the rail stands on the background, and the content lives in the rounded card. */
export const Floating: Story = {
render: (args) => (
{}}
identity={identity}
nav={rail}
>
),
}
/** In the floating frame the banner draws inside the card, at its top. */
export const FloatingWithBanner: Story = {
render: (args) => (
A new version is available. Reload when convenient.}
>
),
}