Files
zeekay 05fc512820 feat: sync upstream shadcn/ui — [email protected], v4 app, font system, chart improvements
Upstream sync from shadcn-ui/ui (1686 commits since last merge base).

Key changes:
- packages/shadcn upgraded to 4.1.0 (CLI font transformers, scaffold from github, chart colors)
- apps/v4 replaces apps/www as the primary docs/registry app
- Font system: 25+ heading font registries, font markers utility, @supports override
- Chart improvements: recharts v3 compat, radial chart fixes
- templates/ updated with monorepo variants (astro, vite, react-router, start)
- skills/shadcn AI skill definitions added
- deprecated/ removed (auth, auth-firebase, cli, www)

Preserved Hanzo-only paths: app/, pkg/, demo/, docs/, template/next/
2026-03-24 19:04:31 -07:00

368 lines
11 KiB
TypeScript

import Image from "next/image"
import {
Example,
ExampleWrapper,
} from "@/registry/bases/radix/components/example"
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
AvatarImage,
} from "@/registry/bases/radix/ui/avatar"
import { Button } from "@/registry/bases/radix/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/bases/radix/ui/card"
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
import { Input } from "@/registry/bases/radix/ui/input"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export default function CardExample() {
return (
<ExampleWrapper>
<CardDefault />
<CardSmall />
<CardHeaderWithBorder />
<CardFooterWithBorder />
<CardHeaderWithBorderSmall />
<CardFooterWithBorderSmall />
<CardWithImage />
<CardWithImageSmall />
<CardLogin />
<CardMeetingNotes />
</ExampleWrapper>
)
}
function CardLogin() {
return (
<Example title="Login">
<Card className="mx-auto w-full max-w-sm">
<CardHeader>
<CardTitle>Login to your account</CardTitle>
<CardDescription>
Enter your email below to login to your account
</CardDescription>
</CardHeader>
<CardContent>
<form>
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input
id="email"
type="email"
placeholder="[email protected]"
required
/>
</Field>
<Field>
<div className="flex items-center">
<FieldLabel htmlFor="password">Password</FieldLabel>
<a
href="#"
className="ml-auto inline-block underline-offset-4 hover:underline"
>
Forgot your password?
</a>
</div>
<Input id="password" type="password" required />
</Field>
</FieldGroup>
</form>
</CardContent>
<CardFooter className="flex-col gap-2">
<Button type="submit" className="w-full">
Login
</Button>
<Button variant="outline" className="w-full">
Login with Google
</Button>
<div className="mt-4 text-center style-nova:mt-2">
Don&apos;t have an account?{" "}
<a href="#" className="underline underline-offset-4">
Sign up
</a>
</div>
</CardFooter>
</Card>
</Example>
)
}
function CardMeetingNotes() {
return (
<Example title="Meeting Notes">
<Card className="mx-auto w-full max-w-sm">
<CardHeader>
<CardTitle>Meeting Notes</CardTitle>
<CardDescription>
Transcript from the meeting with the client.
</CardDescription>
<CardAction>
<Button variant="outline" size="sm">
<IconPlaceholder
lucide="CaptionsIcon"
tabler="IconTextCaption"
hugeicons="TextCheckIcon"
phosphor="TextTIcon"
remixicon="RiTextWrap"
data-icon="inline-start"
/>
Transcribe
</Button>
</CardAction>
</CardHeader>
<CardContent>
<p>
Client requested dashboard redesign with focus on mobile
responsiveness.
</p>
<ol className="mt-4 flex list-decimal flex-col gap-2 pl-6">
<li>New analytics widgets for daily/weekly metrics</li>
<li>Simplified navigation menu</li>
<li>Dark mode support</li>
<li>Timeline: 6 weeks</li>
<li>Follow-up meeting scheduled for next Tuesday</li>
</ol>
</CardContent>
<CardFooter>
<AvatarGroup>
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://github.com/maxleiter.png"
alt="@maxleiter"
/>
<AvatarFallback>LR</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
src="https://github.com/evilrabbit.png"
alt="@evilrabbit"
/>
<AvatarFallback>ER</AvatarFallback>
</Avatar>
<AvatarGroupCount>+8</AvatarGroupCount>
</AvatarGroup>
</CardFooter>
</Card>
</Example>
)
}
function CardWithImage() {
return (
<Example title="With Image">
<Card size="default" className="relative mx-auto w-full max-w-sm pt-0">
<div className="absolute inset-0 z-30 aspect-video bg-primary opacity-50 mix-blend-color" />
<img
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Photo by mymind on Unsplash"
title="Photo by mymind on Unsplash"
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
/>
<CardHeader>
<CardTitle>Beautiful Landscape</CardTitle>
<CardDescription>
A stunning view that captures the essence of natural beauty.
</CardDescription>
</CardHeader>
<CardFooter>
<Button className="w-full">
<IconPlaceholder
lucide="PlusIcon"
tabler="IconPlus"
hugeicons="Add01Icon"
phosphor="PlusIcon"
remixicon="RiAddLine"
data-icon="inline-start"
/>
Button
</Button>
</CardFooter>
</Card>
</Example>
)
}
function CardWithImageSmall() {
return (
<Example title="With Image (Small)">
<Card size="sm" className="relative mx-auto w-full max-w-sm pt-0">
<div className="absolute inset-0 z-30 aspect-video bg-primary opacity-50 mix-blend-color" />
<img
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Photo by mymind on Unsplash"
title="Photo by mymind on Unsplash"
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
/>
<CardHeader>
<CardTitle>Beautiful Landscape</CardTitle>
<CardDescription>
A stunning view that captures the essence of natural beauty.
</CardDescription>
</CardHeader>
<CardFooter>
<Button size="sm" className="w-full">
<IconPlaceholder
lucide="PlusIcon"
tabler="IconPlus"
hugeicons="Add01Icon"
phosphor="PlusIcon"
remixicon="RiAddLine"
data-icon="inline-start"
/>
Button
</Button>
</CardFooter>
</Card>
</Example>
)
}
function CardHeaderWithBorder() {
return (
<Example title="Header with Border">
<Card className="mx-auto w-full max-w-sm">
<CardHeader className="border-b">
<CardTitle>Header with Border</CardTitle>
<CardDescription>
This is a card with a header that has a bottom border.
</CardDescription>
</CardHeader>
<CardContent>
<p>
The header has a border-b class applied, creating a visual
separation between the header and content sections.
</p>
</CardContent>
</Card>
</Example>
)
}
function CardFooterWithBorder() {
return (
<Example title="Footer with Border">
<Card className="mx-auto w-full max-w-sm">
<CardContent>
<p>
The footer has a border-t class applied, creating a visual
separation between the content and footer sections.
</p>
</CardContent>
<CardFooter className="border-t">
<Button variant="outline" className="w-full">
Footer with Border
</Button>
</CardFooter>
</Card>
</Example>
)
}
function CardDefault() {
return (
<Example title="Default Size">
<Card size="default" className="mx-auto w-full max-w-sm">
<CardHeader>
<CardTitle>Default Card</CardTitle>
<CardDescription>
This card uses the default size variant.
</CardDescription>
</CardHeader>
<CardContent>
<p>
The card component supports a size prop that defaults to
&quot;default&quot; for standard spacing and sizing.
</p>
</CardContent>
<CardFooter>
<Button variant="outline" className="w-full">
Action
</Button>
</CardFooter>
</Card>
</Example>
)
}
function CardSmall() {
return (
<Example title="Small Size">
<Card size="sm" className="mx-auto w-full max-w-sm">
<CardHeader>
<CardTitle>Small Card</CardTitle>
<CardDescription>
This card uses the small size variant.
</CardDescription>
</CardHeader>
<CardContent>
<p>
The card component supports a size prop that can be set to
&quot;sm&quot; for a more compact appearance.
</p>
</CardContent>
<CardFooter>
<Button variant="outline" size="sm" className="w-full">
Action
</Button>
</CardFooter>
</Card>
</Example>
)
}
function CardHeaderWithBorderSmall() {
return (
<Example title="Header with Border (Small)">
<Card size="sm" className="mx-auto w-full max-w-sm">
<CardHeader className="border-b">
<CardTitle>Header with Border</CardTitle>
<CardDescription>
This is a small card with a header that has a bottom border.
</CardDescription>
</CardHeader>
<CardContent>
<p>
The header has a border-b class applied, creating a visual
separation between the header and content sections.
</p>
</CardContent>
</Card>
</Example>
)
}
function CardFooterWithBorderSmall() {
return (
<Example title="Footer with Border (Small)">
<Card size="sm" className="mx-auto w-full max-w-sm">
<CardContent>
<p>
The footer has a border-t class applied, creating a visual
separation between the content and footer sections.
</p>
</CardContent>
<CardFooter className="border-t">
<Button variant="outline" size="sm" className="w-full">
Footer with Border
</Button>
</CardFooter>
</Card>
</Example>
)
}