import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { useState, type ReactNode } from 'react'; import { MobileNavPanel } from '../components/navigation/mobile-nav-panel'; import { Button } from '../components/ui/button'; import { StatusBadge } from '../components/ui/status-badge'; import type { MobileNavConfig } from '../types/navigation'; const meta: Meta = { title: 'Navigation/MobileNavPanel', component: MobileNavPanel, parameters: { layout: 'fullscreen', }, }; export default meta; type Story = StoryObj; const baseSections: MobileNavConfig['sections'] = [ { title: 'Product', items: [ { id: 'home', label: 'Home', href: '#', isActive: true }, { id: 'features', label: 'Features', href: '#' }, { id: 'pricing', label: 'Pricing', href: '#' }, ], }, { title: 'Community', items: [ { id: 'blog', label: 'Blog', href: '#' }, { id: 'podcasts', label: 'Podcasts', href: '#' }, ], }, ]; function PanelHarness({ config, children }: { config: Omit; children?: ReactNode }) { const [open, setOpen] = useState(true); return (
{children} setOpen(false) }} />
); } /** Default chrome (openmsp-style): bg-ods-card + border, auth footer. */ export const Default: Story = { render: function Render() { return ( Sign Up ), }} /> ); }, }; /** Flamingo-style custom chrome via config.className (mobileNavClassName knob). */ export const CustomChrome: Story = { render: function Render() { return ( ); }, }; /** TMCG-style disabled auth footer with a status badge. */ export const DisabledFooter: Story = { render: function Render() { return ( Member Login ), }} /> ); }, }; /** * Regression story for the reported bug shape: a SHORT visible viewport with * a long menu. The panel must fit inside the fold (svh-based max-height), the * footer must stay visible, and the list must scroll internally to the last * item. View in a ~660px-tall viewport (or the story's constrained frame). */ export const ShortViewportLongList: Story = { render: function Render() { const longSections: MobileNavConfig['sections'] = [ { title: 'All entries', items: Array.from({ length: 30 }, (_, i) => ({ id: `item-${i + 1}`, label: i === 29 ? 'Last entry (must be reachable)' : `Menu entry ${i + 1}`, href: '#', })), }, ]; return ( Sign Up ), }} >

Resize the viewport short (~660px): the footer stays pinned and the list scrolls to "Last entry".

); }, };