Files
myeasycms-v2/apps/dev-tool/app/components/components/bordered-navigation-menu-story.tsx
Giancarlo Buomprisco ad427365c9 Storybook (#328)
* feat(docs): add interactive examples and API references for Button, Card, and LoadingFallback components
- Updated dependencies
- Set `retries` to a fixed value of 3 for consistent test retries across environments.
- Increased `timeout` from 60 seconds to 120 seconds to allow more time for tests to complete.
- Reduced `expect` timeout from 10 seconds to 5 seconds for quicker feedback on assertions.
2025-08-22 07:35:44 +08:00

499 lines
17 KiB
TypeScript

'use client';
import { useState } from 'react';
import { BarChart3, FileText, Home, Settings, Users } from 'lucide-react';
import {
BorderedNavigationMenu,
BorderedNavigationMenuItem,
} from '@kit/ui/bordered-navigation-menu';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@kit/ui/card';
import { Label } from '@kit/ui/label';
import { Switch } from '@kit/ui/switch';
import { generatePropsString, useStoryControls } from '../lib/story-utils';
import { ComponentStoryLayout } from './story-layout';
interface BorderedNavigationMenuControls {
showIcons: boolean;
}
export function BorderedNavigationMenuStory() {
const { controls, updateControl } =
useStoryControls<BorderedNavigationMenuControls>({
showIcons: true,
});
const [activeTab, setActiveTab] = useState('#dashboard');
const generateCode = () => {
return `import { BorderedNavigationMenu, BorderedNavigationMenuItem } from '@kit/ui/bordered-navigation-menu';
import { usePathname } from 'next/navigation';
const pathname = usePathname();
<BorderedNavigationMenu>
<BorderedNavigationMenuItem
path="#dashboard"
label="Dashboard"
active={pathname === '#dashboard'}
/>
<BorderedNavigationMenuItem
path="#users"
label="Users"
active={pathname === '#users'}
/>
<BorderedNavigationMenuItem
path="#settings"
label="Settings"
active={pathname === '#settings'}
/>
</BorderedNavigationMenu>`;
};
const navigationItems = [
{
path: '#dashboard',
label: 'Dashboard',
icon: Home,
},
{
path: '#users',
label: 'Users',
icon: Users,
},
{
path: '#analytics',
label: 'Analytics',
icon: BarChart3,
},
{
path: '#reports',
label: 'Reports',
icon: FileText,
},
{
path: '#settings',
label: 'Settings',
icon: Settings,
},
];
const renderPreview = () => (
<div className="w-full">
<BorderedNavigationMenu>
{navigationItems.map((item) => (
<BorderedNavigationMenuItem
key={item.path}
path={item.path}
label={
controls.showIcons ? (
<div className="flex items-center space-x-2">
<item.icon className="h-4 w-4" />
<span>{item.label}</span>
</div>
) : (
item.label
)
}
active={activeTab === item.path}
/>
))}
</BorderedNavigationMenu>
<div className="bg-muted/20 mt-8 rounded-lg border p-4">
<h3 className="mb-2 font-semibold">Simulated Navigation</h3>
<p className="text-muted-foreground mb-4 text-sm">
Click tabs above to see active state changes:
</p>
<div className="flex flex-wrap gap-2">
{navigationItems.map((item) => (
<button
key={item.path}
onClick={() => setActiveTab(item.path)}
className={`rounded px-3 py-1 text-sm ${
activeTab === item.path
? 'bg-primary text-primary-foreground'
: 'bg-secondary text-secondary-foreground hover:bg-secondary/80'
}`}
>
{item.label}
</button>
))}
</div>
</div>
</div>
);
const renderControls = () => (
<>
<div className="flex items-center justify-between">
<Label htmlFor="showIcons">Show Icons</Label>
<Switch
id="showIcons"
checked={controls.showIcons}
onCheckedChange={(checked) => updateControl('showIcons', checked)}
/>
</div>
</>
);
const renderExamples = () => (
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Basic Navigation</CardTitle>
<CardDescription>Simple text-only navigation menu</CardDescription>
</CardHeader>
<CardContent>
<BorderedNavigationMenu>
<BorderedNavigationMenuItem
path="/home"
label="Home"
active={true}
/>
<BorderedNavigationMenuItem
path="/about"
label="About"
active={false}
/>
<BorderedNavigationMenuItem
path="/contact"
label="Contact"
active={false}
/>
</BorderedNavigationMenu>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Navigation with Icons</CardTitle>
<CardDescription>
Navigation menu items with icons and labels
</CardDescription>
</CardHeader>
<CardContent>
<BorderedNavigationMenu>
<BorderedNavigationMenuItem
path="/overview"
label={
<div className="flex items-center space-x-2">
<BarChart3 className="h-4 w-4" />
<span>Overview</span>
</div>
}
active={false}
/>
<BorderedNavigationMenuItem
path="/team"
label={
<div className="flex items-center space-x-2">
<Users className="h-4 w-4" />
<span>Team</span>
</div>
}
active={true}
/>
<BorderedNavigationMenuItem
path="/config"
label={
<div className="flex items-center space-x-2">
<Settings className="h-4 w-4" />
<span>Config</span>
</div>
}
active={false}
/>
</BorderedNavigationMenu>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Responsive Navigation</CardTitle>
<CardDescription>
How navigation adapts to different screen sizes
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<h4 className="mb-2 text-sm font-semibold">Desktop View</h4>
<BorderedNavigationMenu>
<BorderedNavigationMenuItem
path="/dashboard"
label="Dashboard"
active={true}
/>
<BorderedNavigationMenuItem
path="/projects"
label="Projects"
active={false}
/>
<BorderedNavigationMenuItem
path="/team"
label="Team Members"
active={false}
/>
<BorderedNavigationMenuItem
path="/billing"
label="Billing & Usage"
active={false}
/>
<BorderedNavigationMenuItem
path="/settings"
label="Account Settings"
active={false}
/>
</BorderedNavigationMenu>
</div>
<div>
<h4 className="mb-2 text-sm font-semibold">
Mobile View (Simulated)
</h4>
<div className="bg-muted/20 rounded-lg border p-2">
<p className="text-muted-foreground text-xs">
On smaller screens, only active and adjacent items are
typically shown, with overflow handled by the navigation
system.
</p>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
);
const renderApiReference = () => (
<Card>
<CardHeader>
<CardTitle>BorderedNavigationMenu Components</CardTitle>
<CardDescription>
Complete API reference for BorderedNavigationMenu components
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div>
<h4 className="mb-3 text-lg font-semibold">
BorderedNavigationMenu
</h4>
<p className="text-muted-foreground mb-3 text-sm">
Container component for navigation menu items with bordered active
state.
</p>
<div className="overflow-x-auto">
<table className="border-border w-full border-collapse border">
<thead>
<tr className="border-b">
<th className="p-3 text-left font-medium">Prop</th>
<th className="p-3 text-left font-medium">Type</th>
<th className="p-3 text-left font-medium">Default</th>
<th className="p-3 text-left font-medium">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td className="p-3 font-mono text-sm">children</td>
<td className="p-3 font-mono text-sm">ReactNode</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">
BorderedNavigationMenuItem components
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div>
<h4 className="mb-3 text-lg font-semibold">
BorderedNavigationMenuItem
</h4>
<p className="text-muted-foreground mb-3 text-sm">
Individual navigation menu item with automatic active state
detection.
</p>
<div className="overflow-x-auto">
<table className="border-border w-full border-collapse border">
<thead>
<tr className="border-b">
<th className="p-3 text-left font-medium">Prop</th>
<th className="p-3 text-left font-medium">Type</th>
<th className="p-3 text-left font-medium">Default</th>
<th className="p-3 text-left font-medium">Description</th>
</tr>
</thead>
<tbody>
<tr className="border-b">
<td className="p-3 font-mono text-sm">path</td>
<td className="p-3 font-mono text-sm">string</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">Navigation path/route</td>
</tr>
<tr className="border-b">
<td className="p-3 font-mono text-sm">label</td>
<td className="p-3 font-mono text-sm">
ReactNode | string
</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">Display label or component</td>
</tr>
<tr className="border-b">
<td className="p-3 font-mono text-sm">active</td>
<td className="p-3 font-mono text-sm">boolean</td>
<td className="p-3 font-mono text-sm">auto-detected</td>
<td className="p-3">Override active state</td>
</tr>
<tr className="border-b">
<td className="p-3 font-mono text-sm">end</td>
<td className="p-3 font-mono text-sm">
boolean | function
</td>
<td className="p-3 font-mono text-sm">false</td>
<td className="p-3">Exact path matching</td>
</tr>
<tr className="border-b">
<td className="p-3 font-mono text-sm">className</td>
<td className="p-3 font-mono text-sm">string</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">Additional CSS classes</td>
</tr>
<tr>
<td className="p-3 font-mono text-sm">buttonClassName</td>
<td className="p-3 font-mono text-sm">string</td>
<td className="p-3 font-mono text-sm">-</td>
<td className="p-3">CSS classes for button element</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</CardContent>
</Card>
);
const renderUsageGuidelines = () => (
<div className="grid gap-6">
<Card>
<CardHeader>
<CardTitle>When to Use BorderedNavigationMenu</CardTitle>
<CardDescription>
Best practices for bordered navigation
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<h4 className="text-sm font-semibold text-green-700">
Use BorderedNavigationMenu For
</h4>
<ul className="ml-4 space-y-1 text-sm">
<li> Primary navigation within sections</li>
<li> Tab-style navigation for related content</li>
<li> Dashboard and admin panel navigation</li>
<li> Settings and configuration sections</li>
<li> Multi-step form navigation</li>
</ul>
</div>
<div className="space-y-2">
<h4 className="text-sm font-semibold text-red-700">
Use Other Patterns For
</h4>
<ul className="ml-4 space-y-1 text-sm">
<li> Site-wide main navigation (use header navigation)</li>
<li> Deep hierarchical navigation (use sidebar)</li>
<li> Single-action buttons (use regular buttons)</li>
<li> Pagination (use pagination component)</li>
</ul>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Design Guidelines</CardTitle>
<CardDescription>
Creating effective navigation experiences
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<h4 className="text-sm font-semibold">Active State Indication</h4>
<p className="text-muted-foreground text-sm">
The bordered bottom line clearly indicates the current active
section. Use consistent active state styling across your
application.
</p>
</div>
<div className="space-y-2">
<h4 className="text-sm font-semibold">Label Clarity</h4>
<p className="text-muted-foreground text-sm">
Use clear, concise labels that accurately describe the
destination. Consider adding icons for better visual recognition.
</p>
</div>
<div className="space-y-2">
<h4 className="text-sm font-semibold">Responsive Behavior</h4>
<p className="text-muted-foreground text-sm">
On smaller screens, non-active items may be hidden to save space.
Plan your navigation hierarchy accordingly.
</p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Accessibility Features</CardTitle>
<CardDescription>Built-in accessibility support</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<h4 className="text-sm font-semibold">Keyboard Navigation</h4>
<p className="text-muted-foreground text-sm">
Full keyboard support with Tab navigation and Enter/Space
activation.
</p>
</div>
<div className="space-y-2">
<h4 className="text-sm font-semibold">Screen Reader Support</h4>
<p className="text-muted-foreground text-sm">
Proper ARIA attributes and semantic HTML for assistive
technologies.
</p>
</div>
<div className="space-y-2">
<h4 className="text-sm font-semibold">Focus Management</h4>
<p className="text-muted-foreground text-sm">
Clear focus indicators and proper focus management during
navigation.
</p>
</div>
</CardContent>
</Card>
</div>
);
return (
<ComponentStoryLayout
preview={renderPreview()}
controls={renderControls()}
generatedCode={generateCode()}
examples={renderExamples()}
apiReference={renderApiReference()}
usageGuidelines={renderUsageGuidelines()}
/>
);
}