Files

255 lines
12 KiB
TypeScript
Raw Permalink Normal View History

2026-07-23 04:23:19 -05:00
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: "Lets 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>
);
}