Files
gh-hopeoverture-worldbuildi…/skills/tailwind-shadcn-ui-setup/assets/app/examples/theme/page.tsx
2025-11-29 18:46:58 +08:00

304 lines
9.8 KiB
TypeScript

'use client'
import * as React from 'react'
import { Button } from '@/components/ui/button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { Separator } from '@/components/ui/separator'
import { useTheme } from 'next-themes'
export default function ThemePage() {
const { theme, setTheme } = useTheme()
const [mounted, setMounted] = React.useState(false)
// Prevent hydration mismatch
React.useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
return (
<div className="container max-w-6xl py-8">
<div className="mb-8">
<h1 className="text-4xl font-bold">Theme & Design Tokens</h1>
<p className="mt-2 text-lg text-muted-foreground">
Explore the color system and design tokens
</p>
</div>
{/* Theme Switcher */}
<Card className="mb-8">
<CardHeader>
<CardTitle>Theme Switcher</CardTitle>
<CardDescription>
Current theme: <strong className="capitalize">{theme}</strong>
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex gap-2">
<Button
variant={theme === 'light' ? 'default' : 'outline'}
onClick={() => setTheme('light')}
>
Light
</Button>
<Button
variant={theme === 'dark' ? 'default' : 'outline'}
onClick={() => setTheme('dark')}
>
Dark
</Button>
<Button
variant={theme === 'system' ? 'default' : 'outline'}
onClick={() => setTheme('system')}
>
System
</Button>
</div>
</CardContent>
</Card>
{/* Color Tokens */}
<div className="space-y-8">
<Card>
<CardHeader>
<CardTitle>Semantic Colors</CardTitle>
<CardDescription>
Colors that describe purpose, not appearance
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4 sm:grid-cols-2">
<ColorSwatch
label="Background"
description="Main background color"
className="bg-background text-foreground"
/>
<ColorSwatch
label="Foreground"
description="Main text color"
className="bg-foreground text-background"
/>
<ColorSwatch
label="Primary"
description="Brand color for main actions"
className="bg-primary text-primary-foreground"
/>
<ColorSwatch
label="Secondary"
description="Less prominent actions"
className="bg-secondary text-secondary-foreground"
/>
<ColorSwatch
label="Muted"
description="Disabled states, subtle backgrounds"
className="bg-muted text-muted-foreground"
/>
<ColorSwatch
label="Accent"
description="Highlights, hover states"
className="bg-accent text-accent-foreground"
/>
<ColorSwatch
label="Destructive"
description="Errors, delete actions"
className="bg-destructive text-destructive-foreground"
/>
<ColorSwatch
label="Card"
description="Elevated surfaces"
className="border bg-card text-card-foreground"
/>
</div>
</CardContent>
</Card>
{/* Component Variants */}
<Card>
<CardHeader>
<CardTitle>Button Variants</CardTitle>
<CardDescription>
Different button styles using semantic colors
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex flex-wrap gap-2">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
<Separator className="my-4" />
<div className="flex flex-wrap gap-2">
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M5 12h14" />
<path d="m12 5 7 7-7 7" />
</svg>
</Button>
</div>
</CardContent>
</Card>
{/* Typography */}
<Card>
<CardHeader>
<CardTitle>Typography Scale</CardTitle>
<CardDescription>Text styles with proper hierarchy</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<h1 className="text-4xl font-bold">Heading 1 (4xl)</h1>
<p className="text-sm text-muted-foreground">
text-4xl font-bold
</p>
</div>
<div>
<h2 className="text-3xl font-bold">Heading 2 (3xl)</h2>
<p className="text-sm text-muted-foreground">
text-3xl font-bold
</p>
</div>
<div>
<h3 className="text-2xl font-semibold">Heading 3 (2xl)</h3>
<p className="text-sm text-muted-foreground">
text-2xl font-semibold
</p>
</div>
<div>
<h4 className="text-xl font-semibold">Heading 4 (xl)</h4>
<p className="text-sm text-muted-foreground">
text-xl font-semibold
</p>
</div>
<div>
<p className="text-base">Body text (base)</p>
<p className="text-sm text-muted-foreground">text-base</p>
</div>
<div>
<p className="text-sm">Small text (sm)</p>
<p className="text-sm text-muted-foreground">text-sm</p>
</div>
<div>
<p className="text-xs text-muted-foreground">
Extra small (xs)
</p>
<p className="text-sm text-muted-foreground">text-xs</p>
</div>
</div>
</CardContent>
</Card>
{/* Customization Guide */}
<Card>
<CardHeader>
<CardTitle>Customization</CardTitle>
<CardDescription>How to customize your theme</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<h4 className="mb-2 font-medium">1. Update CSS Variables</h4>
<p className="mb-2 text-sm text-muted-foreground">
Edit <code className="rounded bg-muted px-1">app/globals.css</code>:
</p>
<pre className="overflow-x-auto rounded-lg bg-muted p-4 text-sm">
<code>{`:root {
--primary: 270 80% 45%; /* Change to your brand color */
--radius: 0.75rem; /* Adjust border radius */
}`}</code>
</pre>
</div>
<div>
<h4 className="mb-2 font-medium">2. Use HSL Color Picker</h4>
<p className="text-sm text-muted-foreground">
Find HSL values using:{' '}
<a
href="https://hslpicker.com"
target="_blank"
rel="noopener noreferrer"
className="text-primary underline"
>
HSL Color Picker
</a>
</p>
</div>
<div>
<h4 className="mb-2 font-medium">3. Test Contrast</h4>
<p className="text-sm text-muted-foreground">
Ensure WCAG compliance using:{' '}
<a
href="https://webaim.org/resources/contrastchecker/"
target="_blank"
rel="noopener noreferrer"
className="text-primary underline"
>
WebAIM Contrast Checker
</a>
</p>
</div>
<div>
<h4 className="mb-2 font-medium">4. Test Both Themes</h4>
<p className="text-sm text-muted-foreground">
Always verify colors look good in both light and dark mode
</p>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
)
}
function ColorSwatch({
label,
description,
className,
}: {
label: string
description: string
className: string
}) {
return (
<div className="space-y-2">
<div
className={`flex h-20 items-center justify-center rounded-lg border ${className}`}
>
<span className="font-medium">{label}</span>
</div>
<div>
<p className="text-sm font-medium">{label}</p>
<p className="text-xs text-muted-foreground">{description}</p>
</div>
</div>
)
}