255 lines
12 KiB
TypeScript
255 lines
12 KiB
TypeScript
import * as React from "react";
|
||
import {
|
||
Badge,
|
||
Button,
|
||
Card,
|
||
CardContent,
|
||
CardDescription,
|
||
CardHeader,
|
||
CardTitle,
|
||
Checkbox,
|
||
CommandPalette,
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogTrigger,
|
||
DropdownMenu,
|
||
DropdownMenuContent,
|
||
DropdownMenuItem,
|
||
DropdownMenuTrigger,
|
||
EmptyState,
|
||
FeatureGrid,
|
||
FormField,
|
||
Hero,
|
||
Input,
|
||
Label,
|
||
Pagination,
|
||
Pricing,
|
||
Select,
|
||
Skeleton,
|
||
Spinner,
|
||
StatCard,
|
||
Switch,
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableHead,
|
||
TableHeader,
|
||
TableRow,
|
||
Tabs,
|
||
TabsContent,
|
||
TabsList,
|
||
TabsTrigger,
|
||
Textarea,
|
||
Toaster,
|
||
Tooltip,
|
||
TooltipContent,
|
||
TooltipProvider,
|
||
TooltipTrigger,
|
||
AppShell,
|
||
useTheme,
|
||
} from "../src";
|
||
import {
|
||
BarChart3,
|
||
Blocks,
|
||
CheckCircle2,
|
||
Command,
|
||
CreditCard,
|
||
LayoutDashboard,
|
||
Moon,
|
||
MoreHorizontal,
|
||
Palette,
|
||
Plus,
|
||
Search,
|
||
Settings,
|
||
Sparkles,
|
||
Sun,
|
||
Users,
|
||
} from "lucide-react";
|
||
|
||
type Page = "overview" | "components" | "marketing";
|
||
|
||
function Section({
|
||
title,
|
||
description,
|
||
children,
|
||
}: {
|
||
title: string;
|
||
description: string;
|
||
children: React.ReactNode;
|
||
}) {
|
||
return (
|
||
<section className="space-y-4">
|
||
<div>
|
||
<h2 className="font-display text-xl font-semibold">{title}</h2>
|
||
<p className="mt-1 max-w-2xl text-sm text-muted">{description}</p>
|
||
</div>
|
||
{children}
|
||
</section>
|
||
);
|
||
}
|
||
|
||
function ThemeButton() {
|
||
const { resolvedTheme, toggleTheme } = useTheme();
|
||
return (
|
||
<Tooltip>
|
||
<TooltipTrigger asChild>
|
||
<Button type="button" variant="ghost" size="icon" onClick={toggleTheme} aria-label="Toggle color theme">
|
||
{resolvedTheme === "dark" ? <Sun /> : <Moon />}
|
||
</Button>
|
||
</TooltipTrigger>
|
||
<TooltipContent>Use {resolvedTheme === "dark" ? "light" : "dark"} mode</TooltipContent>
|
||
</Tooltip>
|
||
);
|
||
}
|
||
|
||
function Overview() {
|
||
return (
|
||
<div className="space-y-10">
|
||
<div>
|
||
<Badge variant="brand">Living design system</Badge>
|
||
<h1 className="mt-3 font-display text-3xl font-bold tracking-tight sm:text-4xl">Warm, clear, dependable interfaces.</h1>
|
||
<p className="mt-3 max-w-2xl text-muted">A single place to review brand tokens, responsive behavior, interaction states, and accessibility before changes reach consuming apps.</p>
|
||
</div>
|
||
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||
<StatCard label="Components" animate={28} icon={<Blocks />} />
|
||
<StatCard label="Accessibility" value="AA" intent="success" sub="Contrast-gated themes" icon={<CheckCircle2 />} />
|
||
<StatCard label="Themes" value="3 modes" intent="brand" sub="Dark, light, and system" icon={<Palette />} />
|
||
<StatCard label="Build" value="Typed" intent="brand" sub="ESM and declarations" icon={<Sparkles />} />
|
||
</div>
|
||
<Section title="Operational surface" description="Representative dashboard density, controls, and data presentation.">
|
||
<Card>
|
||
<CardHeader className="flex-row items-start justify-between">
|
||
<div>
|
||
<CardTitle>Recent workspaces</CardTitle>
|
||
<CardDescription>Tables remain legible and horizontally scroll when space is constrained.</CardDescription>
|
||
</div>
|
||
<Button size="sm"><Plus />New workspace</Button>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow><TableHead>Name</TableHead><TableHead>Owner</TableHead><TableHead>Status</TableHead><TableHead className="text-right">Members</TableHead></TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
<TableRow><TableCell className="font-medium">Forge inventory</TableCell><TableCell>Jordan Lee</TableCell><TableCell><Badge variant="success">Healthy</Badge></TableCell><TableCell className="text-right">18</TableCell></TableRow>
|
||
<TableRow><TableCell className="font-medium">Field operations</TableCell><TableCell>Sam Rivera</TableCell><TableCell><Badge variant="warning">Review</Badge></TableCell><TableCell className="text-right">12</TableCell></TableRow>
|
||
<TableRow><TableCell className="font-medium">Quality portal</TableCell><TableCell>Alex Morgan</TableCell><TableCell><Badge>Draft</Badge></TableCell><TableCell className="text-right">7</TableCell></TableRow>
|
||
</TableBody>
|
||
</Table>
|
||
</CardContent>
|
||
</Card>
|
||
</Section>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function Components() {
|
||
const [notifications, setNotifications] = React.useState(true);
|
||
const [page, setPage] = React.useState(2);
|
||
return (
|
||
<div className="space-y-12">
|
||
<div>
|
||
<h1 className="font-display text-3xl font-bold tracking-tight">Components</h1>
|
||
<p className="mt-2 text-muted">Every core state in one executable review surface.</p>
|
||
</div>
|
||
<Section title="Actions and status" description="Variants share predictable sizing, focus, disabled, and semantic foreground behavior.">
|
||
<div className="flex flex-wrap gap-3">
|
||
<Button>Primary</Button><Button variant="secondary">Secondary</Button><Button variant="outline">Outline</Button><Button variant="ghost">Ghost</Button><Button variant="danger">Delete</Button><Button disabled>Disabled</Button><Spinner label="Saving…" />
|
||
</div>
|
||
<div className="flex flex-wrap gap-2">
|
||
<Badge variant="brand">Brand</Badge><Badge>Neutral</Badge><Badge variant="success">Success</Badge><Badge variant="warning">Warning</Badge><Badge variant="danger">Danger</Badge><Badge variant="outline">Outline</Badge>
|
||
</div>
|
||
</Section>
|
||
<Section title="Forms" description="Field-level descriptions and errors are automatically associated with controls.">
|
||
<Card className="max-w-2xl">
|
||
<CardContent className="grid gap-5 pt-5 sm:grid-cols-2">
|
||
<FormField label="Workspace name" description="Shown in the primary navigation."><Input placeholder="Forge inventory" /></FormField>
|
||
<FormField label="Region" required>
|
||
<Select defaultValue="" placeholder="Choose a region">
|
||
<option value="">Not assigned</option>
|
||
<optgroup label="Americas"><option value="us">United States</option><option value="ca">Canada</option></optgroup>
|
||
<optgroup label="Europe"><option value="uk">United Kingdom</option></optgroup>
|
||
</Select>
|
||
</FormField>
|
||
<FormField label="Summary" error="Add at least 20 characters" className="sm:col-span-2"><Textarea placeholder="What is this workspace for?" /></FormField>
|
||
<Label className="mb-0 flex items-center gap-2 text-sm text-text"><Checkbox defaultChecked />Email weekly digest</Label>
|
||
<Label className="mb-0 flex items-center justify-between gap-3 text-sm text-text">Notifications<Switch checked={notifications} onCheckedChange={setNotifications} /></Label>
|
||
</CardContent>
|
||
</Card>
|
||
</Section>
|
||
<Section title="Disclosure and navigation" description="Keyboard-friendly Radix foundations with branded surfaces.">
|
||
<div className="flex flex-wrap gap-3">
|
||
<Dialog>
|
||
<DialogTrigger asChild><Button variant="outline">Open dialog</Button></DialogTrigger>
|
||
<DialogContent><DialogHeader><DialogTitle>Invite collaborators</DialogTitle><DialogDescription>Send a secure invitation to this workspace.</DialogDescription></DialogHeader><FormField label="Email"><Input type="email" placeholder="name@example.com" /></FormField><Button className="mt-5 w-full">Send invitation</Button></DialogContent>
|
||
</Dialog>
|
||
<DropdownMenu>
|
||
<DropdownMenuTrigger asChild><Button variant="outline">More actions<MoreHorizontal /></Button></DropdownMenuTrigger>
|
||
<DropdownMenuContent><DropdownMenuItem>Duplicate</DropdownMenuItem><DropdownMenuItem>Archive</DropdownMenuItem><DropdownMenuItem className="text-danger">Delete</DropdownMenuItem></DropdownMenuContent>
|
||
</DropdownMenu>
|
||
</div>
|
||
<Tabs defaultValue="details" className="max-w-2xl">
|
||
<TabsList><TabsTrigger value="details">Details</TabsTrigger><TabsTrigger value="activity">Activity</TabsTrigger><TabsTrigger value="settings">Settings</TabsTrigger></TabsList>
|
||
<TabsContent value="details"><Card><CardContent className="pt-5 text-sm text-muted">Overview content with a calm, raised surface.</CardContent></Card></TabsContent>
|
||
<TabsContent value="activity"><EmptyState title="No activity yet" hint="Changes will appear here." /></TabsContent>
|
||
<TabsContent value="settings"><div className="space-y-2"><Skeleton className="h-10 w-full" /><Skeleton className="h-24 w-full" /></div></TabsContent>
|
||
</Tabs>
|
||
<Pagination page={page} pageCount={6} onPageChange={setPage} className="max-w-xl" />
|
||
</Section>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function Marketing() {
|
||
return (
|
||
<div className="-m-4 sm:-m-6">
|
||
<Hero eyebrow="Shared foundation" title="Ship tools that look designed." subtitle="Product UI first, with a confident editorial brand layer when the moment calls for it." primaryCta={{ label: "Get started", href: "#pricing" }} secondaryCta={{ label: "View components", href: "#components" }} />
|
||
<FeatureGrid heading="Built for real work" features={[
|
||
{ icon: <Command />, title: "Fast by default", description: "Command-first patterns and predictable controls keep operators moving." },
|
||
{ icon: <Palette />, title: "One visual language", description: "Generated tokens keep product and marketing surfaces in sync." },
|
||
{ icon: <CheckCircle2 />, title: "Guarded quality", description: "Contrast, interaction, and packaging checks run before release." },
|
||
]} />
|
||
<div id="pricing">
|
||
<Pricing heading="Simple plans" tiers={[
|
||
{ name: "Starter", price: "$0", period: "month", features: ["One workspace", "Core components"], cta: { label: "Start free" } },
|
||
{ name: "Team", price: "$24", period: "month", featured: true, description: "For active operators", features: ["Unlimited workspaces", "Priority support", "Advanced blocks"], cta: { label: "Choose Team" } },
|
||
{ name: "Custom", price: "Let’s talk", features: ["Brand adaptation", "Migration support"], cta: { label: "Contact us" } },
|
||
]} />
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function Showcase() {
|
||
const [page, setPage] = React.useState<Page>("overview");
|
||
const nav = [
|
||
{ label: "Overview", icon: <LayoutDashboard />, active: page === "overview", onClick: () => setPage("overview") },
|
||
{ label: "Components", icon: <Blocks />, active: page === "components", onClick: () => setPage("components") },
|
||
{ label: "Marketing", icon: <CreditCard />, active: page === "marketing", onClick: () => setPage("marketing") },
|
||
];
|
||
return (
|
||
<TooltipProvider delayDuration={250}>
|
||
<AppShell
|
||
brand={<span className="flex items-center gap-2"><span className="size-2 rounded-full bg-brand shadow-glow" />UI Kit</span>}
|
||
nav={nav}
|
||
topbar={<><div className="flex min-w-0 items-center gap-2 text-sm text-muted"><Search className="size-4" /><span className="truncate">Review components, themes, and responsive states</span></div><div className="ml-auto flex items-center gap-1"><Badge variant="outline">v0.5 preview</Badge><ThemeButton /></div></>}
|
||
footer={<div className="flex items-center gap-2"><Settings className="size-4" />Design settings</div>}
|
||
>
|
||
{page === "overview" && <Overview />}
|
||
{page === "components" && <Components />}
|
||
{page === "marketing" && <Marketing />}
|
||
</AppShell>
|
||
<CommandPalette actions={[
|
||
{ id: "overview", label: "Open overview", group: "Navigate", icon: <BarChart3 />, onSelect: () => setPage("overview") },
|
||
{ id: "components", label: "Open components", group: "Navigate", icon: <Blocks />, onSelect: () => setPage("components") },
|
||
{ id: "marketing", label: "Open marketing blocks", group: "Navigate", icon: <Sparkles />, onSelect: () => setPage("marketing") },
|
||
{ id: "users", label: "Invite collaborator", group: "Actions", icon: <Users />, onSelect: () => undefined },
|
||
]} />
|
||
<Toaster />
|
||
</TooltipProvider>
|
||
);
|
||
}
|