forked from cardosofelipe/fast-next-template
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.
This commit is contained in:
17
frontend/src/app/dev/components/page.tsx
Normal file
17
frontend/src/app/dev/components/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Component Showcase Page
|
||||
* Development-only page to preview all shadcn/ui components
|
||||
* Access: /dev/components
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import { ComponentShowcase } from '@/components/dev/ComponentShowcase';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Component Showcase | Dev',
|
||||
description: 'Preview all design system components',
|
||||
};
|
||||
|
||||
export default function ComponentShowcasePage() {
|
||||
return <ComponentShowcase />;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ export function PasswordResetConfirmForm({
|
||||
{/* Password Strength Indicator */}
|
||||
{watchPassword && (
|
||||
<div className="space-y-2" id="password-requirements">
|
||||
<div className="h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
|
||||
<div className="h-2 bg-muted/30 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full transition-all ${
|
||||
passwordStrength.strength === 100
|
||||
|
||||
554
frontend/src/components/dev/ComponentShowcase.tsx
Normal file
554
frontend/src/components/dev/ComponentShowcase.tsx
Normal file
@@ -0,0 +1,554 @@
|
||||
/**
|
||||
* 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'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user