snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
All checks were successful
Release / Create Version PR or Publish Stable Release (push) Has been skipped
Release / Publish Prerelease to NPM (push) Has been skipped
Monitor Registries / Monitor registry health (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:44:43 +05:00
commit 1416db152c
5727 changed files with 630238 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
"use client"
import * as React from "react"
import { MinusIcon, PlusIcon } from "lucide-react"
import { Bar, BarChart } from "recharts"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
ChartContainer,
type ChartConfig,
} from "@/registry/new-york-v4/ui/chart"
const data = [
{
goal: 400,
},
{
goal: 300,
},
{
goal: 200,
},
{
goal: 300,
},
{
goal: 200,
},
{
goal: 278,
},
{
goal: 189,
},
{
goal: 239,
},
{
goal: 300,
},
{
goal: 200,
},
{
goal: 278,
},
{
goal: 189,
},
{
goal: 349,
},
]
const chartConfig = {
goal: {
label: "Goal",
color: "var(--primary)",
},
} satisfies ChartConfig
export function CardsActivityGoal() {
const [goal, setGoal] = React.useState(350)
function onClick(adjustment: number) {
setGoal(Math.max(200, Math.min(400, goal + adjustment)))
}
return (
<Card className="h-full gap-5">
<CardHeader>
<CardTitle>Move Goal</CardTitle>
<CardDescription>Set your daily activity goal.</CardDescription>
</CardHeader>
<CardContent className="flex flex-1 flex-col">
<div className="flex items-center justify-center gap-4">
<Button
variant="outline"
size="icon"
className="size-7 rounded-full"
onClick={() => onClick(-10)}
disabled={goal <= 200}
>
<MinusIcon />
<span className="sr-only">Decrease</span>
</Button>
<div className="text-center">
<div className="text-4xl font-bold tracking-tighter tabular-nums">
{goal}
</div>
<div className="text-xs text-muted-foreground uppercase">
Calories/day
</div>
</div>
<Button
variant="outline"
size="icon"
className="size-7 rounded-full"
onClick={() => onClick(10)}
disabled={goal >= 400}
>
<PlusIcon />
<span className="sr-only">Increase</span>
</Button>
</div>
<div className="flex-1">
<ChartContainer
config={chartConfig}
className="aspect-auto h-full w-full"
>
<BarChart data={data}>
<Bar dataKey="goal" radius={4} fill="var(--color-goal)" />
</BarChart>
</ChartContainer>
</div>
</CardContent>
<CardFooter>
<Button className="w-full" variant="secondary">
Set Goal
</Button>
</CardFooter>
</Card>
)
}

View File

@@ -0,0 +1,26 @@
"use client"
import { addDays } from "date-fns"
import { Calendar } from "@/registry/new-york-v4/ui/calendar"
import { Card, CardContent } from "@/registry/new-york-v4/ui/card"
const start = new Date(2025, 5, 5)
export function CardsCalendar() {
return (
<Card className="hidden max-w-[260px] p-0 sm:flex">
<CardContent className="p-0">
<Calendar
numberOfMonths={1}
mode="range"
defaultMonth={start}
selected={{
from: start,
to: addDays(start, 8),
}}
/>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,273 @@
"use client"
import * as React from "react"
import { cn } from "cn"
import { ArrowUpIcon, CheckIcon, PlusIcon } from "lucide-react"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/new-york-v4/ui/avatar"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardFooter,
CardHeader,
} from "@/registry/new-york-v4/ui/card"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/registry/new-york-v4/ui/command"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/registry/new-york-v4/ui/dialog"
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
} from "@/registry/new-york-v4/ui/input-group"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/registry/new-york-v4/ui/tooltip"
const users = [
{
name: "Olivia Martin",
email: "m@example.com",
avatar: "/avatars/01.png",
},
{
name: "Isabella Nguyen",
email: "isabella.nguyen@email.com",
avatar: "/avatars/03.png",
},
{
name: "Emma Wilson",
email: "emma@example.com",
avatar: "/avatars/05.png",
},
{
name: "Jackson Lee",
email: "lee@example.com",
avatar: "/avatars/02.png",
},
{
name: "William Kim",
email: "will@email.com",
avatar: "/avatars/04.png",
},
] as const
type User = (typeof users)[number]
export function CardsChat() {
const [open, setOpen] = React.useState(false)
const [selectedUsers, setSelectedUsers] = React.useState<User[]>([])
const [messages, setMessages] = React.useState([
{
role: "agent",
content: "Hi, how can I help you today?",
},
{
role: "user",
content: "Hey, I'm having trouble with my account.",
},
{
role: "agent",
content: "What seems to be the problem?",
},
{
role: "user",
content: "I can't log in.",
},
])
const [input, setInput] = React.useState("")
const inputLength = input.trim().length
return (
<>
<Card>
<CardHeader className="flex flex-row items-center">
<div className="flex items-center gap-4">
<Avatar className="border">
<AvatarImage src="/avatars/01.png" alt="Image" />
<AvatarFallback>S</AvatarFallback>
</Avatar>
<div className="flex flex-col gap-0.5">
<p className="text-sm leading-none font-medium">Sofia Davis</p>
<p className="text-xs text-muted-foreground">m@example.com</p>
</div>
</div>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="secondary"
className="ml-auto size-8 rounded-full"
onClick={() => setOpen(true)}
>
<PlusIcon />
<span className="sr-only">New message</span>
</Button>
</TooltipTrigger>
<TooltipContent sideOffset={10}>New message</TooltipContent>
</Tooltip>
</TooltipProvider>
</CardHeader>
<CardContent>
<div className="flex flex-col gap-4">
{messages.map((message, index) => (
<div
key={index}
className={cn(
"flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm",
message.role === "user"
? "ml-auto bg-primary text-primary-foreground"
: "bg-muted"
)}
>
{message.content}
</div>
))}
</div>
</CardContent>
<CardFooter>
<form
onSubmit={(event) => {
event.preventDefault()
if (inputLength === 0) return
setMessages([
...messages,
{
role: "user",
content: input,
},
])
setInput("")
}}
className="relative w-full"
>
<InputGroup>
<InputGroupInput
id="message"
placeholder="Type your message..."
autoComplete="off"
value={input}
onChange={(event) => setInput(event.target.value)}
/>
<InputGroupAddon align="inline-end">
<InputGroupButton
type="submit"
size="icon-xs"
className="rounded-full"
>
<ArrowUpIcon />
<span className="sr-only">Send</span>
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</form>
</CardFooter>
</Card>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="gap-0 p-0 outline-none">
<DialogHeader className="px-4 pt-5 pb-4">
<DialogTitle>New message</DialogTitle>
<DialogDescription>
Invite a user to this thread. This will create a new group
message.
</DialogDescription>
</DialogHeader>
<Command className="overflow-hidden rounded-t-none border-t bg-transparent">
<CommandInput placeholder="Search user..." />
<CommandList>
<CommandEmpty>No users found.</CommandEmpty>
<CommandGroup>
{users.map((user) => (
<CommandItem
key={user.email}
data-active={selectedUsers.includes(user)}
className="data-[active=true]:opacity-50"
onSelect={() => {
if (selectedUsers.includes(user)) {
return setSelectedUsers(
selectedUsers.filter(
(selectedUser) => selectedUser !== user
)
)
}
return setSelectedUsers(
[...users].filter((u) =>
[...selectedUsers, user].includes(u)
)
)
}}
>
<Avatar className="border">
<AvatarImage src={user.avatar} alt="Image" />
<AvatarFallback>{user.name[0]}</AvatarFallback>
</Avatar>
<div className="ml-2">
<p className="text-sm leading-none font-medium">
{user.name}
</p>
<p className="text-sm text-muted-foreground">
{user.email}
</p>
</div>
{selectedUsers.includes(user) ? (
<CheckIcon className="ml-auto flex size-4 text-primary" />
) : null}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
<DialogFooter className="flex items-center border-t p-4 sm:justify-between">
{selectedUsers.length > 0 ? (
<div className="flex -space-x-2 overflow-hidden">
{selectedUsers.map((user) => (
<Avatar key={user.email} className="inline-block border">
<AvatarImage src={user.avatar} />
<AvatarFallback>{user.name[0]}</AvatarFallback>
</Avatar>
))}
</div>
) : (
<p className="text-sm text-muted-foreground">
Select users to add to this thread.
</p>
)}
<Button
disabled={selectedUsers.length < 2}
size="sm"
onClick={() => {
setOpen(false)
}}
>
Continue
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)
}

View File

@@ -0,0 +1,43 @@
"use client"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
Field,
FieldContent,
FieldDescription,
FieldLabel,
} from "@/registry/new-york-v4/ui/field"
import { Switch } from "@/registry/new-york-v4/ui/switch"
export function CardsCookieSettings() {
return (
<Card>
<CardHeader>
<CardTitle>Cookie Settings</CardTitle>
<CardDescription>Manage your cookie settings here.</CardDescription>
</CardHeader>
<CardContent className="grid gap-6">
<Field orientation="horizontal">
<FieldContent>
<FieldLabel htmlFor="necessary">Strictly Necessary</FieldLabel>
<FieldDescription>
These cookies are essential in order to use the website and use
its features.
</FieldDescription>
</FieldContent>
<Switch id="necessary" defaultChecked aria-label="Necessary" />
</Field>
<Field>
<Button variant="outline">Save preferences</Button>
</Field>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,72 @@
"use client"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
Field,
FieldGroup,
FieldLabel,
FieldSeparator,
} from "@/registry/new-york-v4/ui/field"
import { Input } from "@/registry/new-york-v4/ui/input"
export function CardsCreateAccount() {
return (
<Card>
<CardHeader>
<CardTitle className="text-2xl">Create an account</CardTitle>
<CardDescription>
Enter your email below to create your account
</CardDescription>
</CardHeader>
<CardContent>
<FieldGroup>
<Field className="grid grid-cols-2 gap-6">
<Button variant="outline">
<svg viewBox="0 0 438.549 438.549">
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
></path>
</svg>
GitHub
</Button>
<Button variant="outline">
<svg role="img" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
/>
</svg>
Google
</Button>
</Field>
<FieldSeparator className="*:data-[slot=field-separator-content]:bg-card">
Or continue with
</FieldSeparator>
<Field>
<FieldLabel htmlFor="email-create-account">Email</FieldLabel>
<Input
id="email-create-account"
type="email"
placeholder="m@example.com"
/>
</Field>
<Field>
<FieldLabel htmlFor="password-create-account">Password</FieldLabel>
<Input id="password-create-account" type="password" />
</Field>
<Field>
<Button>Create Account</Button>
</Field>
</FieldGroup>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,129 @@
"use client"
import { CartesianGrid, Line, LineChart, XAxis } from "recharts"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/registry/new-york-v4/ui/chart"
const data = [
{
average: 400,
today: 240,
day: "Monday",
},
{
average: 300,
today: 139,
day: "Tuesday",
},
{
average: 200,
today: 980,
day: "Wednesday",
},
{
average: 278,
today: 390,
day: "Thursday",
},
{
average: 189,
today: 480,
day: "Friday",
},
{
average: 239,
today: 380,
day: "Saturday",
},
{
average: 349,
today: 430,
day: "Sunday",
},
]
const chartConfig = {
today: {
label: "Today",
color: "var(--primary)",
},
average: {
label: "Average",
color: "var(--primary)",
},
} satisfies ChartConfig
export function CardsExerciseMinutes() {
return (
<Card>
<CardHeader>
<CardTitle>Exercise Minutes</CardTitle>
<CardDescription>
Your exercise minutes are ahead of where you normally are.
</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="w-full md:h-[200px]">
<LineChart
accessibilityLayer
data={data}
margin={{
top: 5,
right: 10,
left: 16,
bottom: 0,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="day"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
/>
<Line
type="monotone"
dataKey="today"
strokeWidth={2}
stroke="var(--color-today)"
dot={{
fill: "var(--color-today)",
}}
activeDot={{
r: 5,
}}
/>
<Line
type="monotone"
strokeWidth={2}
dataKey="average"
stroke="var(--color-average)"
strokeOpacity={0.5}
dot={{
fill: "var(--color-average)",
opacity: 0.5,
}}
activeDot={{
r: 5,
}}
/>
<ChartTooltip content={<ChartTooltipContent />} />
</LineChart>
</ChartContainer>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,140 @@
"use client"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import { Checkbox } from "@/registry/new-york-v4/ui/checkbox"
import {
Field,
FieldContent,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
FieldTitle,
} from "@/registry/new-york-v4/ui/field"
import { Input } from "@/registry/new-york-v4/ui/input"
import {
RadioGroup,
RadioGroupItem,
} from "@/registry/new-york-v4/ui/radio-group"
import { Textarea } from "@/registry/new-york-v4/ui/textarea"
const plans = [
{
id: "starter",
name: "Starter Plan",
description: "For small businesses.",
price: "$10",
},
{
id: "pro",
name: "Pro Plan",
description: "More features and storage.",
price: "$20",
},
] as const
export function CardsForms() {
return (
<Card>
<CardHeader>
<CardTitle className="text-lg">Upgrade your Subscription</CardTitle>
<CardDescription className="text-balance">
You are currently on the free plan. Upgrade to the pro plan to get
access to all features.
</CardDescription>
</CardHeader>
<CardContent>
<form>
<FieldGroup>
<FieldGroup className="grid grid-cols-2">
<Field>
<FieldLabel htmlFor="name">Name</FieldLabel>
<Input id="name" placeholder="Max Leiter" />
</Field>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" placeholder="mail@acme.com" />
</Field>
</FieldGroup>
<FieldGroup className="grid grid-cols-2 gap-3 md:grid-cols-[1fr_80px_60px]">
<Field>
<FieldLabel htmlFor="card-number">Card Number</FieldLabel>
<Input
id="card-number"
placeholder="1234 1234 1234 1234"
className="col-span-2 md:col-span-1"
/>
</Field>
<Field>
<FieldLabel htmlFor="card-number-expiry">
Expiry Date
</FieldLabel>
<Input id="card-number-expiry" placeholder="MM/YY" />
</Field>
<Field>
<FieldLabel htmlFor="card-number-cvc">CVC</FieldLabel>
<Input id="card-number-cvc" placeholder="CVC" />
</Field>
</FieldGroup>
<FieldSet>
<FieldLegend>Plan</FieldLegend>
<FieldDescription>
Select the plan that best fits your needs.
</FieldDescription>
<RadioGroup
defaultValue="starter"
className="grid grid-cols-2 gap-2"
>
{plans.map((plan) => (
<FieldLabel key={plan.id}>
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>{plan.name}</FieldTitle>
<FieldDescription className="text-xs">
{plan.description}
</FieldDescription>
</FieldContent>
<RadioGroupItem value={plan.id} id={plan.name} />
</Field>
</FieldLabel>
))}
</RadioGroup>
</FieldSet>
<Field>
<FieldLabel htmlFor="notes">Notes</FieldLabel>
<Textarea id="notes" placeholder="Enter notes" />
</Field>
<Field>
<Field orientation="horizontal">
<Checkbox id="terms" />
<FieldLabel htmlFor="terms" className="font-normal">
I agree to the terms and conditions
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="newsletter" defaultChecked />
<FieldLabel htmlFor="newsletter" className="font-normal">
Allow us to send you emails
</FieldLabel>
</Field>
</Field>
<Field orientation="horizontal">
<Button variant="outline" size="sm">
Cancel
</Button>
<Button size="sm">Upgrade Plan</Button>
</Field>
</FieldGroup>
</form>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,59 @@
import { CardsActivityGoal } from "@/components/cards/activity-goal"
import { CardsCalendar } from "@/components/cards/calendar"
import { CardsChat } from "@/components/cards/chat"
import { CardsCookieSettings } from "@/components/cards/cookie-settings"
import { CardsCreateAccount } from "@/components/cards/create-account"
import { CardsExerciseMinutes } from "@/components/cards/exercise-minutes"
import { CardsForms } from "@/components/cards/forms"
import { CardsReportIssue } from "@/components/cards/report-issue"
import { CardsShare } from "@/components/cards/share"
import { CardsStats } from "@/components/cards/stats"
import { CardsTeamMembers } from "@/components/cards/team-members"
export function CardsDemo() {
return (
<div className="md:grids-col-2 grid **:data-[slot=card]:shadow-none md:gap-4 lg:grid-cols-10 xl:grid-cols-11">
<div className="grid gap-4 lg:col-span-4 xl:col-span-6">
<CardsStats />
<div className="grid gap-1 sm:grid-cols-[auto_1fr] md:hidden">
<CardsCalendar />
<div className="pt-3 sm:pt-0 sm:pl-2 xl:pl-4">
<CardsActivityGoal />
</div>
<div className="pt-3 sm:col-span-2 xl:pt-4">
<CardsExerciseMinutes />
</div>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<div className="flex flex-col gap-4">
<CardsForms />
<CardsTeamMembers />
<CardsCookieSettings />
</div>
<div className="flex flex-col gap-4">
<CardsCreateAccount />
<CardsChat />
<div className="hidden xl:block">
<CardsReportIssue />
</div>
</div>
</div>
</div>
<div className="flex flex-col gap-4 lg:col-span-6 xl:col-span-5">
<div className="hidden gap-1 sm:grid-cols-[auto_1fr] md:grid">
<CardsCalendar />
<div className="pt-3 sm:pt-0 sm:pl-2 xl:pl-3">
<CardsActivityGoal />
</div>
<div className="pt-3 sm:col-span-2 xl:pt-3">
<CardsExerciseMinutes />
</div>
</div>
<CardsShare />
<div className="xl:hidden">
<CardsReportIssue />
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,134 @@
"use client"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import { Input } from "@/registry/new-york-v4/ui/input"
import { Label } from "@/registry/new-york-v4/ui/label"
import {
RadioGroup,
RadioGroupItem,
} from "@/registry/new-york-v4/ui/radio-group"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/new-york-v4/ui/select"
const plans = [
{
id: "starter",
name: "Starter Plan",
description: "Perfect for small businesses.",
price: "$10",
},
{
id: "pro",
name: "Pro Plan",
description: "Advanced features with more storage.",
price: "$20",
},
] as const
export function CardsPaymentMethod() {
return (
<Card>
<CardHeader>
<CardTitle>Payment Method</CardTitle>
<CardDescription>
Add a new payment method to your account.
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-6">
<div className="flex flex-col gap-3">
<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="First Last" />
</div>
<fieldset className="flex flex-col gap-3">
<legend className="text-sm font-medium">Plan</legend>
<p className="text-sm text-muted-foreground">
Select the plan that best fits your needs.
</p>
<RadioGroup defaultValue="starter" className="grid gap-3">
{plans.map((plan) => (
<Label
className="flex items-start gap-3 rounded-lg border p-3 has-[[data-state=checked]]:border-ring has-[[data-state=checked]]:bg-primary/5"
key={plan.id}
>
<RadioGroupItem
value={plan.id}
id={plan.name}
className="data-[state=checked]:border-primary"
/>
<div className="grid gap-1 font-normal">
<div className="font-medium">{plan.name}</div>
<div className="pr-2 text-xs leading-snug text-balance text-muted-foreground">
{plan.description}
</div>
</div>
</Label>
))}
</RadioGroup>
</fieldset>
<div className="flex flex-col gap-3">
<Label htmlFor="number">Card number</Label>
<Input id="number" placeholder="" />
</div>
<div className="grid grid-cols-3 gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="month">Expires</Label>
<Select>
<SelectTrigger id="month" aria-label="Month" className="w-full">
<SelectValue placeholder="Month" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">January</SelectItem>
<SelectItem value="2">February</SelectItem>
<SelectItem value="3">March</SelectItem>
<SelectItem value="4">April</SelectItem>
<SelectItem value="5">May</SelectItem>
<SelectItem value="6">June</SelectItem>
<SelectItem value="7">July</SelectItem>
<SelectItem value="8">August</SelectItem>
<SelectItem value="9">September</SelectItem>
<SelectItem value="10">October</SelectItem>
<SelectItem value="11">November</SelectItem>
<SelectItem value="12">December</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="year">Year</Label>
<Select>
<SelectTrigger id="year" aria-label="Year" className="w-full">
<SelectValue placeholder="Year" />
</SelectTrigger>
<SelectContent>
{Array.from({ length: 10 }, (_, i) => (
<SelectItem key={i} value={`${new Date().getFullYear() + i}`}>
{new Date().getFullYear() + i}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="cvc">CVC</Label>
<Input id="cvc" placeholder="CVC" />
</div>
</div>
</CardContent>
<CardFooter>
<Button className="w-full">Continue</Button>
</CardFooter>
</Card>
)
}

View File

@@ -0,0 +1,100 @@
"use client"
import * as React from "react"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import { Field, FieldGroup, FieldLabel } from "@/registry/new-york-v4/ui/field"
import { Input } from "@/registry/new-york-v4/ui/input"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/new-york-v4/ui/select"
import { Textarea } from "@/registry/new-york-v4/ui/textarea"
export function CardsReportIssue() {
const id = React.useId()
return (
<Card>
<CardHeader>
<CardTitle>Report an issue</CardTitle>
<CardDescription>
What area are you having problems with?
</CardDescription>
</CardHeader>
<CardContent>
<FieldGroup>
<FieldGroup className="grid gap-4 sm:grid-cols-2">
<Field>
<FieldLabel htmlFor={`area-${id}`}>Area</FieldLabel>
<Select defaultValue="billing">
<SelectTrigger
id={`area-${id}`}
aria-label="Area"
className="w-full"
>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent>
<SelectItem value="team">Team</SelectItem>
<SelectItem value="billing">Billing</SelectItem>
<SelectItem value="account">Account</SelectItem>
<SelectItem value="deployments">Deployments</SelectItem>
<SelectItem value="support">Support</SelectItem>
</SelectContent>
</Select>
</Field>
<Field>
<FieldLabel htmlFor={`security-level-${id}`}>
Security Level
</FieldLabel>
<Select defaultValue="2">
<SelectTrigger
id={`security-level-${id}`}
className="w-full [&_span]:block! [&_span]:truncate"
aria-label="Security Level"
>
<SelectValue placeholder="Select level" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">Severity 1 (Highest)</SelectItem>
<SelectItem value="2">Severity 2</SelectItem>
<SelectItem value="3">Severity 3</SelectItem>
<SelectItem value="4">Severity 4 (Lowest)</SelectItem>
</SelectContent>
</Select>
</Field>
</FieldGroup>
<Field>
<FieldLabel htmlFor={`subject-${id}`}>Subject</FieldLabel>
<Input id={`subject-${id}`} placeholder="I need help with..." />
</Field>
<Field>
<FieldLabel htmlFor={`description-${id}`}>Description</FieldLabel>
<Textarea
id={`description-${id}`}
placeholder="Please include all information relevant to your issue."
className="min-h-24"
/>
</Field>
<Field orientation="horizontal" className="justify-end">
<Button variant="ghost" size="sm">
Cancel
</Button>
<Button size="sm">Submit</Button>
</Field>
</FieldGroup>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,117 @@
"use client"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/new-york-v4/ui/avatar"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import { Input } from "@/registry/new-york-v4/ui/input"
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemGroup,
ItemTitle,
} from "@/registry/new-york-v4/ui/item"
import { Label } from "@/registry/new-york-v4/ui/label"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/new-york-v4/ui/select"
import { Separator } from "@/registry/new-york-v4/ui/separator"
const people = [
{
name: "Olivia Martin",
email: "m@example.com",
avatar: "/avatars/03.png",
},
{
name: "Isabella Nguyen",
email: "b@example.com",
avatar: "/avatars/04.png",
},
{
name: "Sofia Davis",
email: "p@example.com",
avatar: "/avatars/05.png",
},
{
name: "Ethan Thompson",
email: "e@example.com",
avatar: "/avatars/01.png",
},
]
export function CardsShare() {
return (
<Card>
<CardHeader>
<CardTitle>Share this document</CardTitle>
<CardDescription>
Anyone with the link can view this document.
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center gap-2">
<Label htmlFor="link" className="sr-only">
Link
</Label>
<Input
id="link"
value="http://example.com/link/to/document"
className="h-8"
readOnly
/>
<Button size="sm" variant="outline" className="shadow-none">
Copy Link
</Button>
</div>
<Separator className="my-4" />
<div className="flex flex-col gap-4">
<div className="text-sm font-medium">People with access</div>
<ItemGroup>
{people.map((person) => (
<Item key={person.email} className="px-0 py-2">
<Avatar>
<AvatarImage src={person.avatar} alt="Image" />
<AvatarFallback>{person.name.charAt(0)}</AvatarFallback>
</Avatar>
<ItemContent>
<ItemTitle>{person.name}</ItemTitle>
<ItemDescription>{person.email}</ItemDescription>
</ItemContent>
<ItemActions>
<Select defaultValue="edit">
<SelectTrigger
className="ml-auto pr-2"
aria-label="Edit"
size="sm"
>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent align="end">
<SelectItem value="edit">Can edit</SelectItem>
<SelectItem value="view">Can view</SelectItem>
</SelectContent>
</Select>
</ItemActions>
</Item>
))}
</ItemGroup>
</div>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,132 @@
"use client"
import { Area, AreaChart, Line, LineChart } from "recharts"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
ChartContainer,
type ChartConfig,
} from "@/registry/new-york-v4/ui/chart"
const data = [
{
revenue: 10400,
subscription: 40,
},
{
revenue: 14405,
subscription: 90,
},
{
revenue: 9400,
subscription: 200,
},
{
revenue: 8200,
subscription: 278,
},
{
revenue: 7000,
subscription: 89,
},
{
revenue: 9600,
subscription: 239,
},
{
revenue: 11244,
subscription: 78,
},
{
revenue: 26475,
subscription: 89,
},
]
const chartConfig = {
revenue: {
label: "Revenue",
color: "var(--primary)",
},
subscription: {
label: "Subscriptions",
color: "var(--primary)",
},
} satisfies ChartConfig
export function CardsStats() {
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<Card>
<CardHeader>
<CardDescription>Total Revenue</CardDescription>
<CardTitle className="text-3xl">$15,231.89</CardTitle>
<CardDescription>+20.1% from last month</CardDescription>
</CardHeader>
<CardContent className="pb-0">
<ChartContainer config={chartConfig} className="h-[80px] w-full">
<LineChart
data={data}
margin={{
top: 5,
right: 10,
left: 10,
bottom: 0,
}}
>
<Line
type="monotone"
strokeWidth={2}
dataKey="revenue"
stroke="var(--color-revenue)"
activeDot={{
r: 6,
}}
/>
</LineChart>
</ChartContainer>
</CardContent>
</Card>
<Card className="pb-0 lg:hidden xl:flex">
<CardHeader>
<CardDescription>Subscriptions</CardDescription>
<CardTitle className="text-3xl">+2,350</CardTitle>
<CardDescription>+180.1% from last month</CardDescription>
<CardAction>
<Button variant="ghost" size="sm">
View More
</Button>
</CardAction>
</CardHeader>
<CardContent className="mt-auto max-h-[124px] flex-1 p-0">
<ChartContainer config={chartConfig} className="size-full">
<AreaChart
data={data}
margin={{
left: 0,
right: 0,
}}
>
<Area
dataKey="subscription"
fill="var(--color-subscription)"
fillOpacity={0.05}
stroke="var(--color-subscription)"
strokeWidth={2}
type="monotone"
/>
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
</div>
)
}

View File

@@ -0,0 +1,142 @@
"use client"
import { ChevronDownIcon } from "lucide-react"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/new-york-v4/ui/avatar"
import { Button } from "@/registry/new-york-v4/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/new-york-v4/ui/card"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/registry/new-york-v4/ui/command"
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemGroup,
ItemTitle,
} from "@/registry/new-york-v4/ui/item"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/new-york-v4/ui/popover"
const teamMembers = [
{
name: "Sofia Davis",
email: "m@example.com",
avatar: "/avatars/01.png",
role: "Owner",
},
{
name: "Jackson Lee",
email: "p@example.com",
avatar: "/avatars/02.png",
role: "Developer",
},
{
name: "Isabella Nguyen",
email: "i@example.com",
avatar: "/avatars/03.png",
role: "Billing",
},
]
const roles = [
{
name: "Viewer",
description: "Can view and comment.",
},
{
name: "Developer",
description: "Can view, comment and edit.",
},
{
name: "Billing",
description: "Can view, comment and manage billing.",
},
{
name: "Owner",
description: "Admin-level access to all resources.",
},
]
export function CardsTeamMembers() {
return (
<Card className="gap-4">
<CardHeader>
<CardTitle>Team Members</CardTitle>
<CardDescription>
Invite your team members to collaborate.
</CardDescription>
</CardHeader>
<CardContent>
<ItemGroup>
{teamMembers.map((member) => (
<Item key={member.name} className="px-0 py-2">
<Avatar className="border">
<AvatarImage src={member.avatar} alt="Image" />
<AvatarFallback>{member.name.charAt(0)}</AvatarFallback>
</Avatar>
<ItemContent>
<ItemTitle>{member.name}</ItemTitle>
<ItemDescription>{member.email}</ItemDescription>
</ItemContent>
<ItemActions>
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
size="sm"
className="ml-auto shadow-none"
>
{member.role} <ChevronDownIcon />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="end">
<Command>
<CommandInput placeholder="Select role..." />
<CommandList>
<CommandEmpty>No roles found.</CommandEmpty>
<CommandGroup>
{roles.map((role) => (
<CommandItem key={role.name}>
<div className="flex flex-col">
<span className="text-sm font-medium">
{role.name}
</span>
<span className="text-sm text-muted-foreground">
{role.description}
</span>
</div>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</ItemActions>
</Item>
))}
</ItemGroup>
</CardContent>
</Card>
)
}