Files
fast-next-template/frontend/src/components/dev/ComponentShowcase.tsx
Felipe Cardoso 1439380126 Add Component Showcase and development preview page
- Introduce `ComponentShowcase` to display all design system components (buttons, cards, alerts, etc.) for development and testing purposes.
- Create a dedicated `/dev/components` route for accessing the showcase.
- Ensure reuse of existing `shadcn/ui` components with appropriate styling.
- Update `PasswordResetConfirmForm` to use `bg-muted` for the password strength indicator background.
2025-11-02 06:58:27 +01:00

555 lines
20 KiB
TypeScript

/**
* Component Showcase
* Comprehensive display of all design system components
*/
'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&apos;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&apos;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>
);
}