- **ThemeToggle:** Introduce comprehensive tests to validate button functionality, dropdown options, and active theme indicators. - **ThemeProvider:** Add tests for theme management, localStorage persistence, system preferences, and DOM updates. - **Header & Footer:** Verify header rendering, user menu functionality, and footer content consistency. - **AuthInitializer:** Ensure authentication state is correctly loaded from storage on mount.
558 lines
20 KiB
TypeScript
558 lines
20 KiB
TypeScript
/* istanbul ignore file */
|
|
|
|
/**
|
|
* Component Showcase
|
|
* Comprehensive display of all design system components
|
|
* This file is excluded from coverage as it's a demo/showcase page
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import {
|
|
Moon, Sun, Mail, User,
|
|
Settings, LogOut, Shield, AlertCircle, Info,
|
|
CheckCircle2, AlertTriangle, Trash2
|
|
} from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardFooter,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@/components/ui/card';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { Checkbox } from '@/components/ui/checkbox';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
|
import { Separator } from '@/components/ui/separator';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from '@/components/ui/dialog';
|
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCaption,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
|
|
/**
|
|
* Section wrapper component
|
|
*/
|
|
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<h2 className="text-2xl font-semibold text-foreground">{title}</h2>
|
|
<div className="rounded-lg border bg-card p-6">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Component showcase
|
|
*/
|
|
export function ComponentShowcase() {
|
|
const [isDark, setIsDark] = useState(false);
|
|
const [checked, setChecked] = useState(false);
|
|
|
|
const toggleTheme = () => {
|
|
setIsDark(!isDark);
|
|
document.documentElement.classList.toggle('dark');
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
{/* Header */}
|
|
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
|
<div>
|
|
<h1 className="text-xl font-bold">Component Showcase</h1>
|
|
<p className="text-sm text-muted-foreground">Development Preview</p>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={toggleTheme}
|
|
aria-label="Toggle theme"
|
|
>
|
|
{isDark ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
|
|
</Button>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Content */}
|
|
<main className="container mx-auto px-4 py-8">
|
|
<div className="space-y-12">
|
|
{/* Colors */}
|
|
<Section title="Colors">
|
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-background border"></div>
|
|
<p className="text-sm font-medium">Background</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-foreground"></div>
|
|
<p className="text-sm font-medium">Foreground</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-card border"></div>
|
|
<p className="text-sm font-medium">Card</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-primary"></div>
|
|
<p className="text-sm font-medium">Primary</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-secondary"></div>
|
|
<p className="text-sm font-medium">Secondary</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-muted"></div>
|
|
<p className="text-sm font-medium">Muted</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-accent"></div>
|
|
<p className="text-sm font-medium">Accent</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg bg-destructive"></div>
|
|
<p className="text-sm font-medium">Destructive</p>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<div className="h-20 rounded-lg border-2 border-border"></div>
|
|
<p className="text-sm font-medium">Border</p>
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Typography */}
|
|
<Section title="Typography">
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h1 className="text-4xl font-bold">Heading 1</h1>
|
|
<p className="text-sm text-muted-foreground">text-4xl font-bold</p>
|
|
</div>
|
|
<div>
|
|
<h2 className="text-3xl font-semibold">Heading 2</h2>
|
|
<p className="text-sm text-muted-foreground">text-3xl font-semibold</p>
|
|
</div>
|
|
<div>
|
|
<h3 className="text-2xl font-semibold">Heading 3</h3>
|
|
<p className="text-sm text-muted-foreground">text-2xl font-semibold</p>
|
|
</div>
|
|
<div>
|
|
<h4 className="text-xl font-medium">Heading 4</h4>
|
|
<p className="text-sm text-muted-foreground">text-xl font-medium</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-base">Body text - The quick brown fox jumps over the lazy dog</p>
|
|
<p className="text-sm text-muted-foreground">text-base</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Small text - The quick brown fox jumps over the lazy dog
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">text-sm text-muted-foreground</p>
|
|
</div>
|
|
<div>
|
|
<code className="rounded bg-muted px-2 py-1 font-mono text-sm">
|
|
const example = true;
|
|
</code>
|
|
<p className="text-sm text-muted-foreground mt-1">Code / Mono</p>
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Buttons */}
|
|
<Section title="Buttons">
|
|
<div className="space-y-6">
|
|
{/* Variants */}
|
|
<div>
|
|
<h3 className="mb-4 text-lg font-medium">Variants</h3>
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button variant="default">Primary</Button>
|
|
<Button variant="secondary">Secondary</Button>
|
|
<Button variant="outline">Outline</Button>
|
|
<Button variant="ghost">Ghost</Button>
|
|
<Button variant="destructive">Destructive</Button>
|
|
<Button variant="link">Link</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Sizes */}
|
|
<div>
|
|
<h3 className="mb-4 text-lg font-medium">Sizes</h3>
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<Button size="sm">Small</Button>
|
|
<Button size="default">Default</Button>
|
|
<Button size="lg">Large</Button>
|
|
<Button size="icon">
|
|
<Settings className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* With Icons */}
|
|
<div>
|
|
<h3 className="mb-4 text-lg font-medium">With Icons</h3>
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button>
|
|
<Mail className="mr-2 h-4 w-4" />
|
|
Email
|
|
</Button>
|
|
<Button variant="outline">
|
|
<User className="mr-2 h-4 w-4" />
|
|
Profile
|
|
</Button>
|
|
<Button variant="destructive">
|
|
<Trash2 className="mr-2 h-4 w-4" />
|
|
Delete
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* States */}
|
|
<div>
|
|
<h3 className="mb-4 text-lg font-medium">States</h3>
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button>Normal</Button>
|
|
<Button disabled>Disabled</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Form Inputs */}
|
|
<Section title="Form Inputs">
|
|
<div className="max-w-md space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="email">Email</Label>
|
|
<Input id="email" type="email" placeholder="you@example.com" />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="password">Password</Label>
|
|
<Input id="password" type="password" placeholder="••••••••" />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="message">Message</Label>
|
|
<Textarea id="message" placeholder="Type your message here..." rows={4} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="country">Country</Label>
|
|
<Select>
|
|
<SelectTrigger id="country">
|
|
<SelectValue placeholder="Select a country" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="us">United States</SelectItem>
|
|
<SelectItem value="uk">United Kingdom</SelectItem>
|
|
<SelectItem value="ca">Canada</SelectItem>
|
|
<SelectItem value="au">Australia</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox id="terms" checked={checked} onCheckedChange={(value) => setChecked(value as boolean)} />
|
|
<Label htmlFor="terms" className="text-sm font-normal cursor-pointer">
|
|
Accept terms and conditions
|
|
</Label>
|
|
</div>
|
|
|
|
<Button className="w-full">Submit</Button>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Cards */}
|
|
<Section title="Cards">
|
|
<div className="grid gap-4 sm:grid-cols-2">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Simple Card</CardTitle>
|
|
<CardDescription>Basic card with title and description</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm text-muted-foreground">
|
|
This is the card content area. You can put any content here.
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Card with Footer</CardTitle>
|
|
<CardDescription>Card with action buttons</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm text-muted-foreground">
|
|
Cards can have footers with actions.
|
|
</p>
|
|
</CardContent>
|
|
<CardFooter className="flex justify-between">
|
|
<Button variant="outline">Cancel</Button>
|
|
<Button>Save</Button>
|
|
</CardFooter>
|
|
</Card>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Badges */}
|
|
<Section title="Badges">
|
|
<div className="flex flex-wrap gap-2">
|
|
<Badge>Default</Badge>
|
|
<Badge variant="secondary">Secondary</Badge>
|
|
<Badge variant="outline">Outline</Badge>
|
|
<Badge variant="destructive">Destructive</Badge>
|
|
<Badge className="bg-green-600 hover:bg-green-700">Success</Badge>
|
|
<Badge className="bg-yellow-600 hover:bg-yellow-700">Warning</Badge>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Avatars */}
|
|
<Section title="Avatars">
|
|
<div className="flex flex-wrap items-center gap-4">
|
|
<Avatar>
|
|
<AvatarFallback>AB</AvatarFallback>
|
|
</Avatar>
|
|
<Avatar className="h-12 w-12">
|
|
<AvatarFallback>CD</AvatarFallback>
|
|
</Avatar>
|
|
<Avatar className="h-16 w-16">
|
|
<AvatarFallback>EF</AvatarFallback>
|
|
</Avatar>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Alerts */}
|
|
<Section title="Alerts">
|
|
<div className="space-y-4">
|
|
<Alert>
|
|
<Info className="h-4 w-4" />
|
|
<AlertTitle>Information</AlertTitle>
|
|
<AlertDescription>
|
|
This is an informational alert message.
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
<Alert variant="destructive">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertTitle>Error</AlertTitle>
|
|
<AlertDescription>
|
|
Something went wrong. Please try again.
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
<Alert className="border-green-600 text-green-600 dark:border-green-400 dark:text-green-400">
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
<AlertTitle>Success</AlertTitle>
|
|
<AlertDescription>
|
|
Your changes have been saved successfully.
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
<Alert className="border-yellow-600 text-yellow-600 dark:border-yellow-400 dark:text-yellow-400">
|
|
<AlertTriangle className="h-4 w-4" />
|
|
<AlertTitle>Warning</AlertTitle>
|
|
<AlertDescription>
|
|
Please review your changes before proceeding.
|
|
</AlertDescription>
|
|
</Alert>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Dropdown Menu */}
|
|
<Section title="Dropdown Menu">
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="outline">Open Menu</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="start" className="w-56">
|
|
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem>
|
|
<User className="mr-2 h-4 w-4" />
|
|
Profile
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<Settings className="mr-2 h-4 w-4" />
|
|
Settings
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem>
|
|
<Shield className="mr-2 h-4 w-4" />
|
|
Security
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem className="text-destructive">
|
|
<LogOut className="mr-2 h-4 w-4" />
|
|
Log out
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</Section>
|
|
|
|
{/* Dialog */}
|
|
<Section title="Dialog">
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
<Button>Open Dialog</Button>
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Are you sure?</DialogTitle>
|
|
<DialogDescription>
|
|
This action cannot be undone. This will permanently delete your account
|
|
and remove your data from our servers.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<DialogFooter>
|
|
<Button variant="outline">Cancel</Button>
|
|
<Button variant="destructive">Delete</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</Section>
|
|
|
|
{/* Tabs */}
|
|
<Section title="Tabs">
|
|
<Tabs defaultValue="account" className="w-full">
|
|
<TabsList className="grid w-full grid-cols-2 md:w-[400px]">
|
|
<TabsTrigger value="account">Account</TabsTrigger>
|
|
<TabsTrigger value="password">Password</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="account" className="space-y-4">
|
|
<p className="text-sm text-muted-foreground">
|
|
Make changes to your account here. Click save when you're done.
|
|
</p>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="name">Name</Label>
|
|
<Input id="name" placeholder="John Doe" />
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent value="password" className="space-y-4">
|
|
<p className="text-sm text-muted-foreground">
|
|
Change your password here. After saving, you'll be logged out.
|
|
</p>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="current">Current Password</Label>
|
|
<Input id="current" type="password" />
|
|
</div>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</Section>
|
|
|
|
{/* Table */}
|
|
<Section title="Table">
|
|
<Table>
|
|
<TableCaption>A list of your recent invoices.</TableCaption>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Invoice</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Method</TableHead>
|
|
<TableHead className="text-right">Amount</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell className="font-medium">INV001</TableCell>
|
|
<TableCell>
|
|
<Badge>Paid</Badge>
|
|
</TableCell>
|
|
<TableCell>Credit Card</TableCell>
|
|
<TableCell className="text-right">$250.00</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium">INV002</TableCell>
|
|
<TableCell>
|
|
<Badge variant="secondary">Pending</Badge>
|
|
</TableCell>
|
|
<TableCell>PayPal</TableCell>
|
|
<TableCell className="text-right">$150.00</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableCell className="font-medium">INV003</TableCell>
|
|
<TableCell>
|
|
<Badge variant="outline">Unpaid</Badge>
|
|
</TableCell>
|
|
<TableCell>Bank Transfer</TableCell>
|
|
<TableCell className="text-right">$350.00</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</Section>
|
|
|
|
{/* Skeletons */}
|
|
<Section title="Skeleton Loading">
|
|
<div className="space-y-4">
|
|
<Skeleton className="h-12 w-full" />
|
|
<Skeleton className="h-12 w-3/4" />
|
|
<Skeleton className="h-12 w-1/2" />
|
|
<div className="flex space-x-4">
|
|
<Skeleton className="h-12 w-12 rounded-full" />
|
|
<div className="space-y-2 flex-1">
|
|
<Skeleton className="h-4 w-full" />
|
|
<Skeleton className="h-4 w-4/5" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
|
|
{/* Separator */}
|
|
<Section title="Separator">
|
|
<div className="space-y-4">
|
|
<div>
|
|
<p className="text-sm text-muted-foreground">Section 1</p>
|
|
<Separator className="my-2" />
|
|
<p className="text-sm text-muted-foreground">Section 2</p>
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
</div>
|
|
</main>
|
|
|
|
{/* Footer */}
|
|
<footer className="mt-12 border-t py-6">
|
|
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
|
|
<p>Design System v1.0 • Built with shadcn/ui + Tailwind CSS 4</p>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|