snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
1005
apps/v4/registry/bases/radix/examples/_registry.ts
Normal file
1005
apps/v4/registry/bases/radix/examples/_registry.ts
Normal file
File diff suppressed because it is too large
Load Diff
345
apps/v4/registry/bases/radix/examples/accordion-example.tsx
Normal file
345
apps/v4/registry/bases/radix/examples/accordion-example.tsx
Normal file
@@ -0,0 +1,345 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/registry/bases/radix/ui/accordion"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AccordionExample() {
|
||||
return (
|
||||
<ExampleWrapper className="w-full max-w-4xl lg:grid-cols-1 2xl:max-w-4xl 2xl:grid-cols-1">
|
||||
<AccordionBasic />
|
||||
<AccordionMultiple />
|
||||
<AccordionWithBorders />
|
||||
<AccordionInCard />
|
||||
<AccordionWithDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionBasic() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger: "Is it accessible?",
|
||||
content: "Yes. It adheres to the WAI-ARIA design pattern.",
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger: "Is it styled?",
|
||||
content:
|
||||
"Yes. It comes with default styles that matches the other components' aesthetic.",
|
||||
},
|
||||
{
|
||||
value: "item-3",
|
||||
trigger: "Is it animated?",
|
||||
content:
|
||||
"Yes. It's animated by default, but you can disable it if you prefer.",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Accordion type="single" collapsible className="mx-auto max-w-lg">
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} value={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionMultiple() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger:
|
||||
"What are the key considerations when implementing a comprehensive enterprise-level authentication system?",
|
||||
content:
|
||||
"Implementing a robust enterprise authentication system requires careful consideration of multiple factors. This includes secure password hashing and storage, multi-factor authentication (MFA) implementation, session management, OAuth2 and SSO integration, regular security audits, rate limiting to prevent brute force attacks, and maintaining detailed audit logs. Additionally, you'll need to consider scalability, performance impact, and compliance with relevant data protection regulations such as GDPR or HIPAA.",
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger:
|
||||
"How does modern distributed system architecture handle eventual consistency and data synchronization across multiple regions?",
|
||||
content:
|
||||
"Modern distributed systems employ various strategies to maintain data consistency across regions. This often involves using techniques like CRDT (Conflict-Free Replicated Data Types), vector clocks, and gossip protocols. Systems might implement event sourcing patterns, utilize message queues for asynchronous updates, and employ sophisticated conflict resolution strategies. Popular solutions like Amazon's DynamoDB and Google's Spanner demonstrate different approaches to solving these challenges, balancing between consistency, availability, and partition tolerance as described in the CAP theorem.",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Accordion type="multiple" className="mx-auto max-w-lg">
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} value={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionWithBorders() {
|
||||
const items = [
|
||||
{
|
||||
value: "billing",
|
||||
trigger: "How does billing work?",
|
||||
content:
|
||||
"We offer monthly and annual subscription plans. Billing is charged at the beginning of each cycle, and you can cancel anytime. All plans include automatic backups, 24/7 support, and unlimited team members. There are no hidden fees or setup costs.",
|
||||
},
|
||||
{
|
||||
value: "security",
|
||||
trigger: "Is my data secure?",
|
||||
content:
|
||||
"Yes. We use end-to-end encryption, SOC 2 Type II compliance, and regular third-party security audits. All data is encrypted at rest and in transit using industry-standard protocols. We also offer optional two-factor authentication and single sign-on for enterprise customers.",
|
||||
},
|
||||
{
|
||||
value: "integration",
|
||||
trigger: "What integrations do you support?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We integrate with 500+ popular tools including Slack, Zapier,
|
||||
Salesforce, HubSpot, and more. You can also build custom
|
||||
integrations using our REST API and webhooks.{" "}
|
||||
</p>
|
||||
<p>
|
||||
Our API documentation includes code examples in 10+ programming
|
||||
languages.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="With Borders">
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="mx-auto max-w-lg style-vega:gap-2 style-nova:gap-2 style-lyra:gap-2"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<AccordionItem
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
className="style-vega:rounded-lg style-vega:border style-nova:rounded-lg style-nova:border style-lyra:border"
|
||||
>
|
||||
<AccordionTrigger className="font-medium style-vega:px-4 style-vega:text-sm style-nova:px-2.5 style-nova:text-sm style-lyra:px-2 style-lyra:text-xs style-maia:text-sm style-mira:text-xs style-luma:text-sm">
|
||||
{item.trigger}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="text-muted-foreground style-vega:px-4 style-nova:px-2.5 style-nova:text-sm style-lyra:px-2 style-lyra:text-xs style-maia:px-0 style-mira:px-0 style-luma:px-0">
|
||||
{item.content}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionInCard() {
|
||||
const items = [
|
||||
{
|
||||
value: "plans",
|
||||
trigger: "What subscription plans do you offer?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We offer three subscription tiers: Starter ($9/month), Professional
|
||||
($29/month), and Enterprise ($99/month). Each plan includes
|
||||
increasing storage limits, API access, priority support, and team
|
||||
collaboration features.
|
||||
</p>
|
||||
<p>
|
||||
<a href="#">Annual billing is available</a> with a 20% discount. All
|
||||
plans include a 14-day free trial with no credit card required.
|
||||
</p>
|
||||
<Button size="sm">
|
||||
View plans
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "billing",
|
||||
trigger: "How does billing work?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
Billing occurs automatically at the start of each billing cycle. We
|
||||
accept all major credit cards, PayPal, and ACH transfers for
|
||||
enterprise customers.
|
||||
</p>
|
||||
<p>
|
||||
You'll receive an invoice via email after each payment. You can
|
||||
update your payment method or billing information anytime in your
|
||||
account settings. Failed payments will trigger automated retry
|
||||
attempts and email notifications.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "upgrade",
|
||||
trigger: "Can I upgrade or downgrade my plan?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
Yes, you can change your plan at any time. When upgrading,
|
||||
you'll be charged a prorated amount for the remainder of your
|
||||
billing cycle and immediately gain access to new features.
|
||||
</p>
|
||||
<p>
|
||||
When downgrading, the change takes effect at the end of your current
|
||||
billing period, and you'll retain access to premium features
|
||||
until then. No refunds are provided for downgrades.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "cancel",
|
||||
trigger: "How do I cancel my subscription?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
You can cancel your subscription anytime from your account settings.
|
||||
There are no cancellation fees or penalties. Your access will
|
||||
continue until the end of your current billing period.
|
||||
</p>
|
||||
<p>
|
||||
After cancellation, your data is retained for 30 days in case you
|
||||
want to reactivate. You can export all your data before or after
|
||||
canceling. We'd love to hear your feedback about why
|
||||
you're leaving.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "refund",
|
||||
trigger: "What is your refund policy?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We offer a 30-day money-back guarantee for new subscriptions. If
|
||||
you're not satisfied within the first 30 days, contact our
|
||||
support team for a full refund.
|
||||
</p>
|
||||
<p>
|
||||
After 30 days, we don't provide refunds for partial billing
|
||||
periods, but you can cancel anytime to avoid future charges.
|
||||
Enterprise customers have custom refund terms outlined in their
|
||||
contracts.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="mx-auto w-full max-w-lg gap-4">
|
||||
<CardHeader>
|
||||
<CardTitle>Subscription & Billing</CardTitle>
|
||||
<CardDescription>
|
||||
Common questions about your account, plans, and payments
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
defaultValue="plans"
|
||||
className="style-maia:rounded-md style-mira:rounded-md"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} value={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionWithDisabled() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger: "Can I access my account history?",
|
||||
content:
|
||||
"Yes, you can view your complete account history including all transactions, plan changes, and support tickets in the Account History section of your dashboard.",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger: "Premium feature information",
|
||||
content:
|
||||
"This section contains information about premium features. Upgrade your plan to access this content.",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
value: "item-3",
|
||||
trigger: "How do I update my email address?",
|
||||
content:
|
||||
"You can update your email address in your account settings. You'll receive a verification email at your new address to confirm the change.",
|
||||
disabled: false,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="With Disabled">
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="mx-auto max-w-lg overflow-hidden border style-vega:rounded-lg style-nova:rounded-lg style-lyra:rounded-none style-maia:rounded-lg style-mira:rounded-lg style-luma:rounded-xl style-sera:rounded-none"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<AccordionItem
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
disabled={item.disabled}
|
||||
className="p-1 data-open:bg-muted/50 style-sera:p-0"
|
||||
>
|
||||
<AccordionTrigger className="style-vega:px-4 style-nova:px-2.5 style-lyra:px-2 style-sera:px-4">
|
||||
{item.trigger}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="style-vega:px-4 style-nova:px-2.5 style-lyra:px-2 style-sera:px-4">
|
||||
{item.content}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
231
apps/v4/registry/bases/radix/examples/alert-dialog-example.tsx
Normal file
231
apps/v4/registry/bases/radix/examples/alert-dialog-example.tsx
Normal file
@@ -0,0 +1,231 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogMedia,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/alert-dialog"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AlertDialogExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<AlertDialogBasic />
|
||||
<AlertDialogSmall />
|
||||
<AlertDialogWithMedia />
|
||||
<AlertDialogSmallWithMedia />
|
||||
<AlertDialogDestructive />
|
||||
<AlertDialogInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">Default</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete your
|
||||
account and remove your data from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogSmall() {
|
||||
return (
|
||||
<Example title="Small" className="items-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">Small</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogWithMedia() {
|
||||
return (
|
||||
<Example title="With Media" className="items-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">Default (Media)</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will permanently delete your account and remove your data
|
||||
from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogSmallWithMedia() {
|
||||
return (
|
||||
<Example title="Small With Media" className="items-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">Small (Media)</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogDestructive() {
|
||||
return (
|
||||
<Example title="Destructive" className="items-center">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="destructive">Delete Chat</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia className="bg-destructive/10 text-destructive dark:bg-destructive/20 dark:text-destructive">
|
||||
<IconPlaceholder
|
||||
lucide="Trash2Icon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Delete chat?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will permanently delete this chat conversation. View{" "}
|
||||
<a href="#">Settings</a> delete any memories saved during this
|
||||
chat.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel variant="ghost">Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction variant="destructive">Delete</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog" className="items-center">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Alert Dialog Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to open an alert dialog.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button>Open Alert Dialog</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete
|
||||
your account and remove your data from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
325
apps/v4/registry/bases/radix/examples/alert-example.tsx
Normal file
325
apps/v4/registry/bases/radix/examples/alert-example.tsx
Normal file
@@ -0,0 +1,325 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Alert,
|
||||
AlertAction,
|
||||
AlertDescription,
|
||||
AlertTitle,
|
||||
} from "@/registry/bases/radix/ui/alert"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
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 {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AlertExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<AlertExample1 />
|
||||
<AlertExample2 />
|
||||
<AlertExample3 />
|
||||
<AlertExample4 />
|
||||
<AlertExample5 />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample1() {
|
||||
return (
|
||||
<Example title="Basic" className="style-sera:bg-transparent">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<AlertTitle>Success! Your changes have been saved.</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<AlertTitle>Success! Your changes have been saved.</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an alert with title and description.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
This one has a description only. No title. No icon.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample2() {
|
||||
return (
|
||||
<Example title="With Icons" className="style-sera:bg-transparent">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
Let's try one with icon, title and a <a href="#">link</a>.
|
||||
</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertDescription>
|
||||
This one has an icon and a description only. No title.{" "}
|
||||
<a href="#">But it has a link</a> and a <a href="#">second link</a>.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Success! Your changes have been saved</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an alert with icon, title and description.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
This is a very long alert title that demonstrates how the component
|
||||
handles extended text content and potentially wraps across multiple
|
||||
lines
|
||||
</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertDescription>
|
||||
This is a very long alert description that demonstrates how the
|
||||
component handles extended text content and potentially wraps across
|
||||
multiple lines
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
This is an extremely long alert title that spans multiple lines to
|
||||
demonstrate how the component handles very lengthy headings while
|
||||
maintaining readability and proper text wrapping behavior
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an equally long description that contains detailed
|
||||
information about the alert. It shows how the component can
|
||||
accommodate extensive content while preserving proper spacing,
|
||||
alignment, and readability across different screen sizes and
|
||||
viewport widths. This helps ensure the user experience remains
|
||||
consistent regardless of the content length.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample3() {
|
||||
return (
|
||||
<Example title="Destructive" className="style-sera:bg-transparent">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Something went wrong!</AlertTitle>
|
||||
<AlertDescription>
|
||||
Your session has expired. Please log in again.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Unable to process your payment.</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p>
|
||||
Please verify your <a href="#">billing information</a> and try
|
||||
again.
|
||||
</p>
|
||||
<ul className="list-inside list-disc">
|
||||
<li>Check your card details</li>
|
||||
<li>Ensure sufficient funds</li>
|
||||
<li>Verify billing address</li>
|
||||
</ul>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample4() {
|
||||
return (
|
||||
<Example title="With Actions" className="style-sera:bg-transparent">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>The selected emails have been marked as spam.</AlertTitle>
|
||||
<AlertAction>
|
||||
<Button size="xs">Undo</Button>
|
||||
</AlertAction>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>The selected emails have been marked as spam.</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is a very long alert title that demonstrates how the component
|
||||
handles extended text content.
|
||||
</AlertDescription>
|
||||
<AlertAction>
|
||||
<Badge variant="secondary">Badge</Badge>
|
||||
</AlertAction>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample5() {
|
||||
return (
|
||||
<Example title="Inside Card" className="style-sera:bg-transparent">
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<CardTitle>Create project</CardTitle>
|
||||
<CardDescription>
|
||||
Fill in the form below to create a new project.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4 style-sera:gap-8">
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
You have reached the limit of 3 free projects.
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
Upgrade to Pro to create unlimited projects.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="project-name">Name</FieldLabel>
|
||||
<Input id="project-name" placeholder="My project" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="project-framework">Framework</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="project-framework">
|
||||
<SelectValue placeholder="Select a framework" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="next">Next.js</SelectItem>
|
||||
<SelectItem value="remix">Remix</SelectItem>
|
||||
<SelectItem value="astro">Astro</SelectItem>
|
||||
<SelectItem value="nuxt">Nuxt</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<Item variant="outline">
|
||||
<ItemMedia variant="image" className="border">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>Project Alpha</ItemTitle>
|
||||
<ItemDescription>Created 2 days ago</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button className="w-full">Create project</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import Image from "next/image"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { AspectRatio } from "@/registry/bases/radix/ui/aspect-ratio"
|
||||
|
||||
export default function AspectRatioExample() {
|
||||
return (
|
||||
<ExampleWrapper className="max-w-4xl 2xl:max-w-4xl">
|
||||
<AspectRatio16x9 />
|
||||
<AspectRatio21x9 />
|
||||
<AspectRatio1x1 />
|
||||
<AspectRatio9x16 />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio16x9() {
|
||||
return (
|
||||
<Example title="16:9" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={16 / 9}
|
||||
className="rounded-lg bg-muted style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio1x1() {
|
||||
return (
|
||||
<Example title="1:1" className="items-start">
|
||||
<AspectRatio
|
||||
ratio={1 / 1}
|
||||
className="rounded-lg bg-muted style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio9x16() {
|
||||
return (
|
||||
<Example title="9:16" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={9 / 16}
|
||||
className="rounded-lg bg-muted style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio21x9() {
|
||||
return (
|
||||
<Example title="21:9" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={21 / 9}
|
||||
className="rounded-lg bg-muted style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-lyra:rounded-none style-luma:rounded-3xl style-sera:rounded-none"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
1614
apps/v4/registry/bases/radix/examples/attachment-example.tsx
Normal file
1614
apps/v4/registry/bases/radix/examples/attachment-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
511
apps/v4/registry/bases/radix/examples/avatar-example.tsx
Normal file
511
apps/v4/registry/bases/radix/examples/avatar-example.tsx
Normal file
@@ -0,0 +1,511 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarBadge,
|
||||
AvatarFallback,
|
||||
AvatarGroup,
|
||||
AvatarGroupCount,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/radix/ui/avatar"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AvatarExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<AvatarSizes />
|
||||
<AvatarWithBadge />
|
||||
<AvatarWithBadgeIcon />
|
||||
<AvatarGroupExample />
|
||||
<AvatarGroupWithCount />
|
||||
<AvatarGroupWithIconCount />
|
||||
<AvatarInEmpty />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarWithBadge() {
|
||||
return (
|
||||
<Example title="Badge">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarWithBadgeIcon() {
|
||||
return (
|
||||
<Example title="Badge with Icon">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupExample() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</AvatarGroup>
|
||||
<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>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupWithCount() {
|
||||
return (
|
||||
<Example title="Group with Count">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<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>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupWithIconCount() {
|
||||
return (
|
||||
<Example title="Group with Icon Count">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<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>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarInEmpty() {
|
||||
return (
|
||||
<Example title="In Empty">
|
||||
<Empty className="w-full flex-none border">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No Team Members</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Invite your team to collaborate on this project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
Invite Members
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
354
apps/v4/registry/bases/radix/examples/badge-example.tsx
Normal file
354
apps/v4/registry/bases/radix/examples/badge-example.tsx
Normal file
@@ -0,0 +1,354 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function BadgeExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<BadgeVariants />
|
||||
<BadgeWithIconLeft />
|
||||
<BadgeWithIconRight />
|
||||
<BadgeWithSpinner />
|
||||
<BadgeAsLink />
|
||||
<BadgeLongText />
|
||||
<BadgeCustomColors />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeVariants() {
|
||||
return (
|
||||
<Example title="Variants">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>Default</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="destructive">Destructive</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
<Badge variant="ghost">Ghost</Badge>
|
||||
<Badge variant="link">Link</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithIconLeft() {
|
||||
return (
|
||||
<Example title="Icon Left" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Default
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Secondary
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Destructive
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Outline
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Ghost
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Link
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithIconRight() {
|
||||
return (
|
||||
<Example title="Icon Right" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
Default
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
Secondary
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
Destructive
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
Outline
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
Ghost
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
Link
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithSpinner() {
|
||||
return (
|
||||
<Example title="With Spinner" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
<Spinner data-icon="inline-start" />
|
||||
Default
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Secondary
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Destructive
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Outline
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Ghost
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Link
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeAsLink() {
|
||||
return (
|
||||
<Example title="asChild">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge asChild>
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
<Badge asChild variant="secondary">
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
<Badge asChild variant="destructive">
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
<Badge asChild variant="outline">
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
<Badge asChild variant="ghost">
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
<Badge asChild variant="link">
|
||||
<a href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeLongText() {
|
||||
return (
|
||||
<Example title="Long Text">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge variant="secondary">
|
||||
A badge with a lot of text to see how it wraps
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeCustomColors() {
|
||||
return (
|
||||
<Example title="Custom Colors" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge className="bg-blue-600 text-blue-50 dark:bg-blue-600 dark:text-blue-50">
|
||||
Blue
|
||||
</Badge>
|
||||
<Badge className="bg-green-600 text-green-50 dark:bg-green-600 dark:text-green-50">
|
||||
Green
|
||||
</Badge>
|
||||
<Badge className="bg-sky-600 text-sky-50 dark:bg-sky-600 dark:text-sky-50">
|
||||
Sky
|
||||
</Badge>
|
||||
<Badge className="bg-purple-600 text-purple-50 dark:bg-purple-600 dark:text-purple-50">
|
||||
Purple
|
||||
</Badge>
|
||||
<Badge className="bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300">
|
||||
Blue
|
||||
</Badge>
|
||||
<Badge className="bg-green-50 text-green-700 dark:bg-green-950 dark:text-green-300">
|
||||
Green
|
||||
</Badge>
|
||||
<Badge className="bg-sky-50 text-sky-700 dark:bg-sky-950 dark:text-sky-300">
|
||||
Sky
|
||||
</Badge>
|
||||
<Badge className="bg-purple-50 text-purple-700 dark:bg-purple-950 dark:text-purple-300">
|
||||
Purple
|
||||
</Badge>
|
||||
<Badge className="bg-red-50 text-red-700 dark:bg-red-950 dark:text-red-300">
|
||||
Red
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
122
apps/v4/registry/bases/radix/examples/breadcrumb-example.tsx
Normal file
122
apps/v4/registry/bases/radix/examples/breadcrumb-example.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import Link from "next/link"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/registry/bases/radix/ui/breadcrumb"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
|
||||
export default function BreadcrumbExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<BreadcrumbBasic />
|
||||
<BreadcrumbWithDropdown />
|
||||
<BreadcrumbWithLink />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="icon-sm" variant="ghost">
|
||||
<BreadcrumbEllipsis />
|
||||
<span className="sr-only">Toggle menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem>Documentation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Themes</DropdownMenuItem>
|
||||
<DropdownMenuItem>GitHub</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbWithLink() {
|
||||
return (
|
||||
<Example title="With Link" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href="#">Home</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbEllipsis />
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href="#">Components</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
517
apps/v4/registry/bases/radix/examples/bubble-example.tsx
Normal file
517
apps/v4/registry/bases/radix/examples/bubble-example.tsx
Normal file
@@ -0,0 +1,517 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Bubble,
|
||||
BubbleContent,
|
||||
BubbleGroup,
|
||||
BubbleReactions,
|
||||
} from "@/registry/bases/radix/ui/bubble"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/radix/ui/collapsible"
|
||||
import { Marker, MarkerContent } from "@/registry/bases/radix/ui/marker"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function BubbleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<BubbleSizes />
|
||||
<BubbleVariants />
|
||||
<BubbleAlignment />
|
||||
<BubbleGrouped />
|
||||
<BubbleCollapsible />
|
||||
<BubbleButtonLinks />
|
||||
<BubbleWithReactions />
|
||||
<BubbleReactionsButtons />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleVariants() {
|
||||
return (
|
||||
<Example title="Variants">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Default bubbles use the primary color for the active user side of a
|
||||
chat.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
Secondary bubbles are the standard neutral surface for assistant and
|
||||
conversation content.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Muted bubbles lower the emphasis for quiet system notes or for
|
||||
displaying supporting content.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>
|
||||
Tinted bubbles use a softer primary tint when primary fill is too
|
||||
strong.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="outline">
|
||||
<BubbleContent>
|
||||
Outline bubbles can be used to frame message content and give it a
|
||||
border.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>
|
||||
Destructive bubbles flag errors or failed actions in a conversation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`Ghost bubbles work for assistant text and other content that should not be framed.
|
||||
|
||||
This is perfect for assistant messages that should not have a frame and can take the full width of the container.
|
||||
|
||||
Ghost bubbles are full width and can take the full width of the container.
|
||||
`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line bubble.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
This bubble has multiple lines. It should wrap to the next line and
|
||||
you should see a different radius on the corners.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
<p>This bubble has multiple lines.</p>
|
||||
<p>
|
||||
It should wrap to the next line and you should see a different
|
||||
radius on the corners.
|
||||
</p>
|
||||
<p>Here is some more text to see how it wraps.</p>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleGrouped() {
|
||||
return (
|
||||
<Example title="Grouped">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<BubbleGroup>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>I finished the audit pass.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
The registry output looks clean, but I found one stale route.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>Want me to remove it now?</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
<BubbleGroup>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>Yes, clean that up.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>Then rerun the registry build.</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const text = `The accessibility review found two focus states that were visually too subtle in dark mode.
|
||||
|
||||
I checked the dialog, menu, and drawer paths because each one renders focusable controls inside a layered surface.
|
||||
|
||||
The dialog and drawer are fine. The menu needs the hover and focus tokens split so keyboard focus stays visible when the pointer is not involved.
|
||||
|
||||
I also recommend keeping the change in the style file instead of the primitive so the other themes can choose their own focus treatment later.`
|
||||
|
||||
const previewLength = 180
|
||||
|
||||
function BubbleCollapsible() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const isLong = text.length > previewLength
|
||||
const preview = `${text.slice(0, previewLength)}...`
|
||||
|
||||
return (
|
||||
<Example title="Collapsible">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Collapsible open={open} onOpenChange={setOpen}>
|
||||
<Bubble variant="muted" align="end">
|
||||
<BubbleContent className="whitespace-pre-line">
|
||||
<div>{open || !isLong ? text : preview}</div>
|
||||
{isLong ? (
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button
|
||||
variant="link"
|
||||
className="gap-1 p-0 text-muted-foreground"
|
||||
>
|
||||
{open ? "Show less" : "Show more"}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
data-icon="inline-end"
|
||||
className="group-data-open/button:rotate-180"
|
||||
/>
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
) : null}
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</Collapsible>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`Ghost bubbles work for assistant text and other content that should not be framed.
|
||||
|
||||
This is perfect for assistant messages that should not have a frame and can take the full width of the container.
|
||||
|
||||
Use this for content that needs the whole row.`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleWithReactions() {
|
||||
return (
|
||||
<Example title="Reaction Placement">
|
||||
<div className="flex w-full max-w-md flex-col gap-12">
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=end</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reaction: thumbs up"
|
||||
>
|
||||
<span>👍</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary" align="end">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes, and 8 more"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
<span>+8</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=start</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reaction: fire"
|
||||
>
|
||||
<span>🔥</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=top align=start</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reaction: fire"
|
||||
>
|
||||
<span>🔥</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=end</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reaction: thumbs up"
|
||||
>
|
||||
<span>👍</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
className="px-1.5 py-0.5"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleReactionsButtons() {
|
||||
return (
|
||||
<Example title="Reactions Buttons">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() =>
|
||||
toast("You clicked the button in the bubble reaction")
|
||||
}
|
||||
>
|
||||
Button
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions align="start">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => toast("Confetti!")}
|
||||
>
|
||||
🎉
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
We are going to the movies first then dinner. Are you in?
|
||||
</BubbleContent>
|
||||
<BubbleReactions className="gap-1 bg-background">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon-xs"
|
||||
aria-label="Thumbs up"
|
||||
onClick={() => toast("You agree!")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsUpIcon"
|
||||
tabler="IconThumbUp"
|
||||
hugeicons="ThumbsUpIcon"
|
||||
phosphor="ThumbsUpIcon"
|
||||
remixicon="RiThumbUpLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon-xs"
|
||||
aria-label="Thumbs down"
|
||||
onClick={() => toast("You disagree!")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsDownIcon"
|
||||
tabler="IconThumbDown"
|
||||
hugeicons="ThumbsDownIcon"
|
||||
phosphor="ThumbsDownIcon"
|
||||
remixicon="RiThumbDownLine"
|
||||
/>
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleAlignment() {
|
||||
return (
|
||||
<Example title="Alignment">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>This bubble is aligned to the start.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>This bubble is aligned to the end.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
This multiline bubble is aligned to the start. The corners should
|
||||
adjust when the text wraps to show the grouped side of the
|
||||
conversation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>
|
||||
This multiline bubble is aligned to the end. It should sit on the
|
||||
opposite side with the matching corner radius for wrapped text.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const quickReplies = [
|
||||
{
|
||||
label: "I need help with my account.",
|
||||
message: "I need help with my account.",
|
||||
},
|
||||
{
|
||||
label: "I forgot my password.",
|
||||
message: "I forgot my password.",
|
||||
},
|
||||
{
|
||||
label:
|
||||
"I have another question. I'd like to talk to a human. Can you help me?",
|
||||
message: "I have another question.",
|
||||
},
|
||||
]
|
||||
|
||||
function BubbleButtonLinks() {
|
||||
return (
|
||||
<Example title="Button & Links">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent asChild>
|
||||
<a href="#">This bubble is a link.</a>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent asChild>
|
||||
<button type="button">This one is a button you can click.</button>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent asChild>
|
||||
<button type="button">
|
||||
You can also do tinted buttons. Even ones that are multilines.
|
||||
</button>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>Chat Suggestions</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble>
|
||||
<BubbleContent>How can I help you today?</BubbleContent>
|
||||
</Bubble>
|
||||
<BubbleGroup>
|
||||
{quickReplies.map((reply) => (
|
||||
<Bubble key={reply.label} variant="outline" align="end">
|
||||
<BubbleContent asChild className="border-dashed border-primary">
|
||||
<button type="button" onClick={() => toast(reply.message)}>
|
||||
{reply.label}
|
||||
</button>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
))}
|
||||
</BubbleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
998
apps/v4/registry/bases/radix/examples/button-example.tsx
Normal file
998
apps/v4/registry/bases/radix/examples/button-example.tsx
Normal file
@@ -0,0 +1,998 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ButtonExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1 2xl:grid-cols-1">
|
||||
<ButtonVariantsAndSizes />
|
||||
<ButtonIconRight />
|
||||
<ButtonIconLeft />
|
||||
<ButtonIconOnly />
|
||||
<ButtonInvalidStates />
|
||||
<ButtonExamples />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonVariantsAndSizes() {
|
||||
return (
|
||||
<Example title="Variants & Sizes">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="xs">Default</Button>
|
||||
<Button size="xs" variant="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="xs" variant="outline">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="xs" variant="ghost">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="xs" variant="destructive">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="xs" variant="link">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="sm">Default</Button>
|
||||
<Button size="sm" variant="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="sm" variant="outline">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="sm" variant="destructive">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="sm" variant="link">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button>Default</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
<Button variant="destructive">Destructive</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="lg">Default</Button>
|
||||
<Button size="lg" variant="secondary">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="lg" variant="outline">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="lg" variant="ghost">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="lg" variant="destructive">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="lg" variant="link">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonIconRight() {
|
||||
return (
|
||||
<Example title="Icon Right">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="xs">
|
||||
Default{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="xs" variant="secondary">
|
||||
Secondary{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="xs" variant="outline">
|
||||
Outline{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="xs" variant="ghost">
|
||||
Ghost{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="xs" variant="destructive">
|
||||
Destructive{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="xs" variant="link">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="sm">
|
||||
Default
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary">
|
||||
Secondary{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="sm" variant="outline">
|
||||
Outline{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost">
|
||||
Ghost{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="sm" variant="destructive">
|
||||
Destructive{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="sm" variant="link">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button>
|
||||
Default{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="secondary">
|
||||
Secondary{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
Outline{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="ghost">
|
||||
Ghost{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="destructive">
|
||||
Destructive{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="link">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="lg">
|
||||
Default{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="lg" variant="secondary">
|
||||
Secondary{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="lg" variant="outline">
|
||||
Outline{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="lg" variant="ghost">
|
||||
Ghost{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="lg" variant="destructive">
|
||||
Destructive{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="lg" variant="link">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonIconLeft() {
|
||||
return (
|
||||
<Example title="Icon Left">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Default
|
||||
</Button>
|
||||
<Button size="xs" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="xs" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="xs" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="xs" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="xs" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Default
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="sm" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="sm" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Default
|
||||
</Button>
|
||||
<Button variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Secondary
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Outline
|
||||
</Button>
|
||||
<Button variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Ghost
|
||||
</Button>
|
||||
<Button variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Destructive
|
||||
</Button>
|
||||
<Button variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="lg">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Default
|
||||
</Button>
|
||||
<Button size="lg" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="lg" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="lg" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="lg" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="lg" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftCircleIcon"
|
||||
hugeicons="CircleArrowLeft02Icon"
|
||||
tabler="IconCircleArrowLeft"
|
||||
phosphor="ArrowCircleLeftIcon"
|
||||
remixicon="RiArrowLeftCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonIconOnly() {
|
||||
return (
|
||||
<Example title="Icon Only">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-xs" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-xs" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-xs" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-xs" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-xs" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-sm" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-sm" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-sm" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-sm" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="icon-lg">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-lg" variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-lg" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-lg" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-lg" variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button size="icon-lg" variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonExamples() {
|
||||
return (
|
||||
<Example title="Examples">
|
||||
<div className="flex flex-wrap items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline">Cancel</Button>
|
||||
<Button>
|
||||
Submit{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="destructive">Delete</Button>
|
||||
<Button size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonInvalidStates() {
|
||||
return (
|
||||
<Example title="Invalid States">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="xs" aria-invalid="true">
|
||||
Default
|
||||
</Button>
|
||||
<Button size="xs" variant="secondary" aria-invalid="true">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="xs" variant="outline" aria-invalid="true">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="xs" variant="ghost" aria-invalid="true">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="xs" variant="destructive" aria-invalid="true">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="xs" variant="link" aria-invalid="true">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="sm" aria-invalid="true">
|
||||
Default
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" aria-invalid="true">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" aria-invalid="true">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" aria-invalid="true">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="sm" variant="destructive" aria-invalid="true">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="sm" variant="link" aria-invalid="true">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button aria-invalid="true">Default</Button>
|
||||
<Button variant="secondary" aria-invalid="true">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button variant="outline" aria-invalid="true">
|
||||
Outline
|
||||
</Button>
|
||||
<Button variant="ghost" aria-invalid="true">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button variant="destructive" aria-invalid="true">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button variant="link" aria-invalid="true">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="lg" aria-invalid="true">
|
||||
Default
|
||||
</Button>
|
||||
<Button size="lg" variant="secondary" aria-invalid="true">
|
||||
Secondary
|
||||
</Button>
|
||||
<Button size="lg" variant="outline" aria-invalid="true">
|
||||
Outline
|
||||
</Button>
|
||||
<Button size="lg" variant="ghost" aria-invalid="true">
|
||||
Ghost
|
||||
</Button>
|
||||
<Button size="lg" variant="destructive" aria-invalid="true">
|
||||
Destructive
|
||||
</Button>
|
||||
<Button size="lg" variant="link" aria-invalid="true">
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
737
apps/v4/registry/bases/radix/examples/button-group-example.tsx
Normal file
737
apps/v4/registry/bases/radix/examples/button-group-example.tsx
Normal file
@@ -0,0 +1,737 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
ButtonGroup,
|
||||
ButtonGroupText,
|
||||
} from "@/registry/bases/radix/ui/button-group"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Field, FieldGroup } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/registry/bases/radix/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ButtonGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ButtonGroupBasic />
|
||||
<ButtonGroupWithInput />
|
||||
<ButtonGroupWithText />
|
||||
<ButtonGroupWithDropdown />
|
||||
<ButtonGroupWithSelect />
|
||||
<ButtonGroupWithIcons />
|
||||
<ButtonGroupWithInputGroup />
|
||||
<ButtonGroupWithFields />
|
||||
<ButtonGroupWithLike />
|
||||
<ButtonGroupWithSelectAndInput />
|
||||
<ButtonGroupNested />
|
||||
<ButtonGroupPagination />
|
||||
<ButtonGroupPaginationSplit />
|
||||
<ButtonGroupNavigation />
|
||||
<ButtonGroupTextAlignment />
|
||||
<ButtonGroupVertical />
|
||||
<ButtonGroupVerticalNested />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button</Button>
|
||||
<Button variant="outline">Another Button</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button</Button>
|
||||
<Input placeholder="Type something here..." />
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Input placeholder="Type something here..." />
|
||||
<Button variant="outline">Button</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithText() {
|
||||
return (
|
||||
<Example title="With Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<ButtonGroupText>Text</ButtonGroupText>
|
||||
<Button variant="outline">Another Button</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<ButtonGroupText asChild>
|
||||
<Label htmlFor="input-text">GPU Size</Label>
|
||||
</ButtonGroupText>
|
||||
<Input
|
||||
id="input-text"
|
||||
placeholder="Type something here..."
|
||||
className="style-luma:border-border"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Update</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Disable</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Uninstall
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Follow</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-50">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="VolumeOffIcon"
|
||||
tabler="IconVolume"
|
||||
hugeicons="VolumeOffIcon"
|
||||
phosphor="SpeakerSlashIcon"
|
||||
remixicon="RiVolumeMuteLine"
|
||||
/>
|
||||
Mute Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
Mark as Read
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="AlertTriangleIcon"
|
||||
tabler="IconAlertTriangle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
Report Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserRoundXIcon"
|
||||
tabler="IconUserX"
|
||||
hugeicons="UserRemove01Icon"
|
||||
phosphor="UserMinusIcon"
|
||||
remixicon="RiUserUnfollowLine"
|
||||
/>
|
||||
Block User
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithSelect() {
|
||||
const [currency, setCurrency] = useState("$")
|
||||
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<Field>
|
||||
<Label htmlFor="amount">Amount</Label>
|
||||
<ButtonGroup>
|
||||
<Select value={currency} onValueChange={setCurrency}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start">
|
||||
<SelectGroup>
|
||||
<SelectItem value="$">$</SelectItem>
|
||||
<SelectItem value="€">€</SelectItem>
|
||||
<SelectItem value="£">£</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Input placeholder="Enter amount to send" />
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="FlipHorizontalIcon"
|
||||
tabler="IconFlipHorizontal"
|
||||
hugeicons="FlipHorizontalIcon"
|
||||
phosphor="ArrowsHorizontalIcon"
|
||||
remixicon="RiArrowLeftRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="FlipVerticalIcon"
|
||||
tabler="IconFlipVertical"
|
||||
hugeicons="FlipVerticalIcon"
|
||||
phosphor="ArrowsVerticalIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="RotateCwIcon"
|
||||
tabler="IconRotateClockwise2"
|
||||
hugeicons="Rotate01Icon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithInputGroup() {
|
||||
return (
|
||||
<Example title="With Input Group">
|
||||
<div className="flex flex-col gap-4">
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Type to search..." />
|
||||
<InputGroupAddon
|
||||
align="inline-start"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithFields() {
|
||||
return (
|
||||
<Example title="With Fields">
|
||||
<FieldGroup className="grid grid-cols-3 gap-4">
|
||||
<Field className="col-span-2">
|
||||
<Label htmlFor="width">Width</Label>
|
||||
<ButtonGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="width" />
|
||||
<InputGroupAddon className="text-muted-foreground">
|
||||
W
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon
|
||||
align="inline-end"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
px
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithLike() {
|
||||
return (
|
||||
<Example title="With Like">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="HeartIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="Notification02Icon"
|
||||
phosphor="HeartIcon"
|
||||
remixicon="RiHeartLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Like
|
||||
</Button>
|
||||
<Button variant="outline" asChild size="icon" className="w-12">
|
||||
<span>1.2K</span>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithSelectAndInput() {
|
||||
return (
|
||||
<Example title="With Select and Input">
|
||||
<ButtonGroup>
|
||||
<Select defaultValue="hours">
|
||||
<SelectTrigger id="duration">
|
||||
<SelectValue placeholder="Select duration" />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start">
|
||||
<SelectGroup>
|
||||
<SelectItem value="hours">Hours</SelectItem>
|
||||
<SelectItem value="days">Days</SelectItem>
|
||||
<SelectItem value="weeks">Weeks</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Input />
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupNested() {
|
||||
return (
|
||||
<Example title="Nested">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Send a message..." />
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="AudioLinesIcon"
|
||||
tabler="IconHeadphones"
|
||||
hugeicons="AudioWave01Icon"
|
||||
phosphor="MicrophoneIcon"
|
||||
remixicon="RiMicLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Voice Mode</TooltipContent>
|
||||
</Tooltip>
|
||||
</InputGroup>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupPagination() {
|
||||
return (
|
||||
<Example title="Pagination">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Previous
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
1
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
2
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
3
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
4
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
5
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Next
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupPaginationSplit() {
|
||||
return (
|
||||
<Example title="Pagination Split">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="sm">
|
||||
1
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
2
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
3
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
4
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
5
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupNavigation() {
|
||||
return (
|
||||
<Example title="Navigation">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup aria-label="Single navigation button">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupTextAlignment() {
|
||||
return (
|
||||
<Example title="Text Alignment">
|
||||
<Field>
|
||||
<Label id="alignment-label">Text Alignment</Label>
|
||||
<ButtonGroup aria-labelledby="alignment-label">
|
||||
<Button variant="outline" size="sm">
|
||||
Left
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Center
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Right
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Justify
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex gap-6">
|
||||
<ButtonGroup
|
||||
orientation="vertical"
|
||||
aria-label="Media controls"
|
||||
className="h-fit"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupVerticalNested() {
|
||||
return (
|
||||
<Example title="Vertical Nested">
|
||||
<ButtonGroup orientation="vertical" aria-label="Design tools palette">
|
||||
<ButtonGroup orientation="vertical">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup orientation="vertical">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FlipHorizontalIcon"
|
||||
tabler="IconFlipHorizontal"
|
||||
hugeicons="FlipHorizontalIcon"
|
||||
phosphor="ArrowsHorizontalIcon"
|
||||
remixicon="RiArrowLeftRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FlipVerticalIcon"
|
||||
tabler="IconFlipVertical"
|
||||
hugeicons="FlipVerticalIcon"
|
||||
phosphor="ArrowsVerticalIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="RotateCwIcon"
|
||||
tabler="IconRotateClockwise2"
|
||||
hugeicons="Rotate01Icon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
536
apps/v4/registry/bases/radix/examples/calendar-example.tsx
Normal file
536
apps/v4/registry/bases/radix/examples/calendar-example.tsx
Normal file
@@ -0,0 +1,536 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { addDays, format } from "date-fns"
|
||||
import { type DateRange } from "react-day-picker"
|
||||
import { es } from "react-day-picker/locale"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Calendar, CalendarDayButton } from "@/registry/bases/radix/ui/calendar"
|
||||
import { Card, CardContent, CardFooter } from "@/registry/bases/radix/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/bases/radix/ui/popover"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CalendarExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CalendarSingle />
|
||||
<CalendarMultiple />
|
||||
<CalendarWeekNumbers />
|
||||
<CalendarBookedDates />
|
||||
<CalendarRange />
|
||||
<CalendarRangeMultipleMonths />
|
||||
<CalendarWithTime />
|
||||
<CalendarWithPresets />
|
||||
<CalendarCustomDays />
|
||||
<DatePickerSimple />
|
||||
<DataPickerWithDropdowns />
|
||||
<DatePickerWithRange />
|
||||
<CalendarInCard />
|
||||
<CalendarInPopover />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar mode="single" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarInPopover() {
|
||||
return (
|
||||
<Example title="In Popover">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" className="px-2.5 font-normal">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Open Calendar
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar mode="single" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarSingle() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(
|
||||
new Date(new Date().getFullYear(), new Date().getMonth(), 12)
|
||||
)
|
||||
return (
|
||||
<Example title="Single">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
captionLayout="dropdown"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar mode="multiple" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarRange() {
|
||||
const [dateRange, setDateRange] = React.useState<DateRange | undefined>({
|
||||
from: new Date(new Date().getFullYear(), 0, 12),
|
||||
to: addDays(new Date(new Date().getFullYear(), 0, 12), 30),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example
|
||||
title="Range"
|
||||
containerClassName="lg:col-span-full 2xl:col-span-full"
|
||||
className="p-12"
|
||||
>
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
defaultMonth={dateRange?.from}
|
||||
selected={dateRange}
|
||||
onSelect={setDateRange}
|
||||
numberOfMonths={2}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarRangeMultipleMonths() {
|
||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
||||
from: new Date(new Date().getFullYear(), 3, 12),
|
||||
to: addDays(new Date(new Date().getFullYear(), 3, 12), 60),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example
|
||||
title="Range Multiple Months"
|
||||
containerClassName="lg:col-span-full 2xl:col-span-full"
|
||||
className="p-12"
|
||||
>
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
defaultMonth={range?.from}
|
||||
selected={range}
|
||||
onSelect={setRange}
|
||||
numberOfMonths={3}
|
||||
locale={es}
|
||||
fixedWeeks
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarBookedDates() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(
|
||||
new Date(new Date().getFullYear(), 1, 3)
|
||||
)
|
||||
const bookedDates = Array.from(
|
||||
{ length: 15 },
|
||||
(_, i) => new Date(new Date().getFullYear(), 1, 12 + i)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Booked Dates">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
defaultMonth={date}
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
disabled={bookedDates}
|
||||
modifiers={{
|
||||
booked: bookedDates,
|
||||
}}
|
||||
modifiersClassNames={{
|
||||
booked: "[&>button]:line-through opacity-100",
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarWithTime() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(
|
||||
new Date(new Date().getFullYear(), new Date().getMonth(), 12)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Time">
|
||||
<Card size="sm" className="mx-auto w-fit">
|
||||
<CardContent>
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
className="p-0"
|
||||
/>
|
||||
</CardContent>
|
||||
<CardFooter className="border-t bg-card">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="time-from">Start Time</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="time-from"
|
||||
type="time"
|
||||
step="1"
|
||||
defaultValue="10:30:00"
|
||||
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="Clock2Icon"
|
||||
tabler="IconClockHour2"
|
||||
hugeicons="Clock03Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="time-to">End Time</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="time-to"
|
||||
type="time"
|
||||
step="1"
|
||||
defaultValue="12:30:00"
|
||||
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="Clock2Icon"
|
||||
tabler="IconClockHour2"
|
||||
hugeicons="Clock03Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarCustomDays() {
|
||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
||||
from: new Date(new Date().getFullYear(), 11, 8),
|
||||
to: addDays(new Date(new Date().getFullYear(), 11, 8), 10),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example title="Custom Days">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="range"
|
||||
defaultMonth={range?.from}
|
||||
selected={range}
|
||||
onSelect={setRange}
|
||||
numberOfMonths={1}
|
||||
captionLayout="dropdown"
|
||||
className="[--cell-size:--spacing(10)] md:[--cell-size:--spacing(12)]"
|
||||
formatters={{
|
||||
formatMonthDropdown: (date) => {
|
||||
return date.toLocaleString("default", { month: "long" })
|
||||
},
|
||||
}}
|
||||
components={{
|
||||
DayButton: ({ children, modifiers, day, ...props }) => {
|
||||
const isWeekend =
|
||||
day.date.getDay() === 0 || day.date.getDay() === 6
|
||||
|
||||
return (
|
||||
<CalendarDayButton day={day} modifiers={modifiers} {...props}>
|
||||
{children}
|
||||
{!modifiers.outside && (
|
||||
<span>{isWeekend ? "$120" : "$100"}</span>
|
||||
)}
|
||||
</CalendarDayButton>
|
||||
)
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarWithPresets() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(
|
||||
new Date(new Date().getFullYear(), 1, 12)
|
||||
)
|
||||
const [currentMonth, setCurrentMonth] = React.useState<Date>(
|
||||
new Date(new Date().getFullYear(), new Date().getMonth(), 1)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Presets">
|
||||
<Card className="mx-auto w-fit max-w-[300px]" size="sm">
|
||||
<CardContent className="px-4">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
month={currentMonth}
|
||||
onMonthChange={setCurrentMonth}
|
||||
fixedWeeks
|
||||
className="p-0 [--cell-size:--spacing(9.5)]"
|
||||
/>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-wrap gap-2 border-t">
|
||||
{[
|
||||
{ label: "Today", value: 0 },
|
||||
{ label: "Tomorrow", value: 1 },
|
||||
{ label: "In 3 days", value: 3 },
|
||||
{ label: "In a week", value: 7 },
|
||||
{ label: "In 2 weeks", value: 14 },
|
||||
].map((preset) => (
|
||||
<Button
|
||||
key={preset.value}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
onClick={() => {
|
||||
const newDate = addDays(new Date(), preset.value)
|
||||
setDate(newDate)
|
||||
setCurrentMonth(
|
||||
new Date(newDate.getFullYear(), newDate.getMonth(), 1)
|
||||
)
|
||||
}}
|
||||
>
|
||||
{preset.label}
|
||||
</Button>
|
||||
))}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DatePickerSimple() {
|
||||
const [date, setDate] = React.useState<Date>()
|
||||
|
||||
return (
|
||||
<Example title="Date Picker Simple">
|
||||
<Field className="mx-auto w-72">
|
||||
<FieldLabel htmlFor="date-picker-simple">Date</FieldLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
id="date-picker-simple"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
{date ? format(date, "PPP") : <span>Pick a date</span>}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar mode="single" selected={date} onSelect={setDate} />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DatePickerWithRange() {
|
||||
const [date, setDate] = React.useState<DateRange | undefined>({
|
||||
from: new Date(new Date().getFullYear(), 0, 20),
|
||||
to: addDays(new Date(new Date().getFullYear(), 0, 20), 20),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example title="Date Picker Range">
|
||||
<Field className="mx-auto w-72">
|
||||
<FieldLabel htmlFor="date-picker-range">Date Picker Range</FieldLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
id="date-picker-range"
|
||||
variant="outline"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
{date?.from ? (
|
||||
date.to ? (
|
||||
<>
|
||||
{format(date.from, "LLL dd, y")} -{" "}
|
||||
{format(date.to, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(date.from, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="range"
|
||||
defaultMonth={date?.from}
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
numberOfMonths={2}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DataPickerWithDropdowns() {
|
||||
const [date, setDate] = React.useState<Date>()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Date Picker with Dropdowns">
|
||||
<Field className="mx-auto w-72">
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<FieldLabel htmlFor="date-picker-with-dropdowns-desktop">
|
||||
Date
|
||||
</FieldLabel>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
id="date-picker-with-dropdowns-desktop"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
{date ? format(date, "PPP") : <span>Pick a date</span>}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
data-icon="inline-start"
|
||||
className="ml-auto"
|
||||
/>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
captionLayout="dropdown"
|
||||
/>
|
||||
<div className="flex gap-2 border-t p-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-full"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarWeekNumbers() {
|
||||
const [date, setDate] = React.useState<Date | undefined>(
|
||||
new Date(new Date().getFullYear(), 1, 3)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Week Numbers" className="justify-center">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
mode="single"
|
||||
defaultMonth={date}
|
||||
selected={date}
|
||||
onSelect={setDate}
|
||||
showWeekNumber
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
490
apps/v4/registry/bases/radix/examples/card-example.tsx
Normal file
490
apps/v4/registry/bases/radix/examples/card-example.tsx
Normal file
@@ -0,0 +1,490 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
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 {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const spacingOptions = [
|
||||
{
|
||||
className: "[--card-spacing:--spacing(4)]",
|
||||
label: "16px",
|
||||
value: "4",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(5)]",
|
||||
label: "20px",
|
||||
value: "5",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(6)]",
|
||||
label: "24px",
|
||||
value: "6",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(8)]",
|
||||
label: "32px",
|
||||
value: "8",
|
||||
},
|
||||
]
|
||||
|
||||
export default function CardExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CardDefault />
|
||||
<CardSmall />
|
||||
<CardContentEdgeToEdge />
|
||||
<CardCustomSpacing />
|
||||
<CardHeaderWithBorder />
|
||||
<CardFooterWithBorder />
|
||||
<CardHeaderWithBorderSmall />
|
||||
<CardFooterWithBorderSmall />
|
||||
<CardWithImage />
|
||||
<CardWithImageSmall />
|
||||
<CardLogin />
|
||||
<CardMeetingNotes />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContentEdgeToEdge() {
|
||||
return (
|
||||
<Example title="Content Edge to Edge">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Terms of Service</CardTitle>
|
||||
<CardDescription>
|
||||
Review the terms before accepting the agreement.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="-mb-(--card-spacing) px-0">
|
||||
<div className="max-h-48 space-y-4 overflow-y-scroll border-t bg-muted/50 px-(--card-spacing) py-4 text-sm leading-relaxed">
|
||||
<p>
|
||||
These terms govern your use of the workspace, including access to
|
||||
shared documents, project files, and collaboration tools.
|
||||
</p>
|
||||
<p>
|
||||
You are responsible for the content you upload and for ensuring
|
||||
that your team has the appropriate permissions to view or edit it.
|
||||
</p>
|
||||
<p>
|
||||
We may update features or limits as the service evolves. When
|
||||
those changes materially affect your workflow, we will notify your
|
||||
workspace administrators.
|
||||
</p>
|
||||
<p>
|
||||
By continuing, you agree to keep your account credentials secure
|
||||
and to follow your organization's acceptable use policies.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-end gap-2">
|
||||
<Button variant="outline">Decline</Button>
|
||||
<Button>Accept</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardCustomSpacing() {
|
||||
const [spacing, setSpacing] = React.useState("4")
|
||||
const selectedSpacing = spacingOptions.find(
|
||||
(option) => option.value === spacing
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Custom Spacing">
|
||||
<div className="mx-auto grid w-full max-w-sm gap-4">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={spacing}
|
||||
onValueChange={(value) => {
|
||||
if (value) {
|
||||
setSpacing(value)
|
||||
}
|
||||
}}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="justify-center"
|
||||
>
|
||||
{spacingOptions.map((option) => (
|
||||
<ToggleGroupItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</ToggleGroupItem>
|
||||
))}
|
||||
</ToggleGroup>
|
||||
<Card className={selectedSpacing?.className}>
|
||||
<CardHeader>
|
||||
<CardTitle>Release Health</CardTitle>
|
||||
<CardDescription>
|
||||
Track readiness across launch signals.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-2 rounded-lg bg-muted/50 p-3 text-sm style-lyra:rounded-none style-sera:rounded-none">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-muted-foreground">Checks passed</span>
|
||||
<span className="font-medium">24 / 26</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-muted-foreground">Open blockers</span>
|
||||
<span className="font-medium">2</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
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="m@example.com"
|
||||
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'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
|
||||
"default" 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
|
||||
"sm" 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>
|
||||
)
|
||||
}
|
||||
99
apps/v4/registry/bases/radix/examples/carousel-example.tsx
Normal file
99
apps/v4/registry/bases/radix/examples/carousel-example.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/registry/bases/radix/ui/carousel"
|
||||
|
||||
export default function CarouselExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<CarouselBasic />
|
||||
<CarouselMultiple />
|
||||
<CarouselWithGap />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Carousel className="mx-auto max-w-xs sm:max-w-sm">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-4xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Carousel
|
||||
className="mx-auto max-w-xs sm:max-w-sm"
|
||||
opts={{
|
||||
align: "start",
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index} className="sm:basis-1/2 lg:basis-1/3">
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-3xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselWithGap() {
|
||||
return (
|
||||
<Example title="With Gap">
|
||||
<Carousel className="mx-auto max-w-xs sm:max-w-sm">
|
||||
<CarouselContent className="-ml-1">
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index} className="pl-1 md:basis-1/2">
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-2xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
594
apps/v4/registry/bases/radix/examples/chart-example.tsx
Normal file
594
apps/v4/registry/bases/radix/examples/chart-example.tsx
Normal file
@@ -0,0 +1,594 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
Label,
|
||||
Line,
|
||||
LineChart,
|
||||
Pie,
|
||||
PieChart,
|
||||
PolarAngleAxis,
|
||||
PolarGrid,
|
||||
PolarRadiusAxis,
|
||||
Radar,
|
||||
RadarChart,
|
||||
RadialBar,
|
||||
RadialBarChart,
|
||||
XAxis,
|
||||
} from "recharts"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/radix/ui/chart"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
import { useDesignSystemSearchParams } from "@/app/(create)/lib/search-params"
|
||||
|
||||
const areaChartData = [
|
||||
{ month: "January", desktop: 186 },
|
||||
{ month: "February", desktop: 305 },
|
||||
{ month: "March", desktop: 237 },
|
||||
{ month: "April", desktop: 73 },
|
||||
{ month: "May", desktop: 209 },
|
||||
{ month: "June", desktop: 214 },
|
||||
]
|
||||
|
||||
const areaChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export default function ChartExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ChartAreaExample />
|
||||
<ChartBarExample />
|
||||
<ChartLineExample />
|
||||
<ChartPieExample />
|
||||
<ChartRadialExample />
|
||||
<ChartRadarExample />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ChartAreaExample() {
|
||||
return (
|
||||
<Example title="Area Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Area Chart</CardTitle>
|
||||
<CardDescription>
|
||||
Showing total visitors for the last 6 months
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={areaChartConfig}>
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
data={areaChartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
<Area
|
||||
dataKey="desktop"
|
||||
type="natural"
|
||||
fill="var(--color-desktop)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--color-desktop)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex w-full items-start gap-2">
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
January - June 2024
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const barChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const barChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartBarExample() {
|
||||
const [params] = useDesignSystemSearchParams()
|
||||
const isRounded = !["lyra", "sera"].includes(params.style)
|
||||
|
||||
return (
|
||||
<Example title="Bar Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Bar Chart - Multiple</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={barChartConfig}>
|
||||
<BarChart accessibilityLayer data={barChartData}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="dashed" />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="desktop"
|
||||
fill="var(--color-desktop)"
|
||||
radius={isRounded ? 4 : 0}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="mobile"
|
||||
fill="var(--color-mobile)"
|
||||
radius={isRounded ? 4 : 0}
|
||||
/>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col items-start gap-2">
|
||||
<div className="flex gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const lineChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const lineChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartLineExample() {
|
||||
return (
|
||||
<Example title="Line Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Line Chart - Multiple</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={lineChartConfig}>
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
data={lineChartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
||||
<Line
|
||||
dataKey="desktop"
|
||||
type="monotone"
|
||||
stroke="var(--color-desktop)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
<Line
|
||||
dataKey="mobile"
|
||||
type="monotone"
|
||||
stroke="var(--color-mobile)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex w-full items-start gap-2">
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const pieChartData = [
|
||||
{ browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
|
||||
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
|
||||
{ browser: "firefox", visitors: 287, fill: "var(--color-firefox)" },
|
||||
{ browser: "edge", visitors: 173, fill: "var(--color-edge)" },
|
||||
{ browser: "other", visitors: 190, fill: "var(--color-other)" },
|
||||
]
|
||||
|
||||
const pieChartConfig = {
|
||||
visitors: {
|
||||
label: "Visitors",
|
||||
},
|
||||
chrome: {
|
||||
label: "Chrome",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
safari: {
|
||||
label: "Safari",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
firefox: {
|
||||
label: "Firefox",
|
||||
color: "var(--chart-3)",
|
||||
},
|
||||
edge: {
|
||||
label: "Edge",
|
||||
color: "var(--chart-4)",
|
||||
},
|
||||
other: {
|
||||
label: "Other",
|
||||
color: "var(--chart-5)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartPieExample() {
|
||||
const totalVisitors = React.useMemo(() => {
|
||||
return pieChartData.reduce((acc, curr) => acc + curr.visitors, 0)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Example title="Pie Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader className="items-center pb-0">
|
||||
<CardTitle>Pie Chart - Donut with Text</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 pb-0">
|
||||
<ChartContainer
|
||||
config={pieChartConfig}
|
||||
className="mx-auto aspect-square max-h-[250px]"
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={pieChartData}
|
||||
dataKey="visitors"
|
||||
nameKey="browser"
|
||||
innerRadius={60}
|
||||
strokeWidth={5}
|
||||
>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground text-3xl font-bold"
|
||||
>
|
||||
{totalVisitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-muted-foreground"
|
||||
>
|
||||
Visitors
|
||||
</tspan>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const radarChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const radarChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartRadarExample() {
|
||||
return (
|
||||
<Example title="Radar Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader className="items-center pb-4">
|
||||
<CardTitle>Radar Chart - Multiple</CardTitle>
|
||||
<CardDescription>
|
||||
Showing total visitors for the last 6 months
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="pb-0">
|
||||
<ChartContainer
|
||||
config={radarChartConfig}
|
||||
className="mx-auto aspect-square max-h-[250px]"
|
||||
>
|
||||
<RadarChart data={radarChartData}>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
<PolarAngleAxis dataKey="month" />
|
||||
<PolarGrid />
|
||||
<Radar
|
||||
dataKey="desktop"
|
||||
fill="var(--color-desktop)"
|
||||
fillOpacity={0.6}
|
||||
/>
|
||||
<Radar dataKey="mobile" fill="var(--color-mobile)" />
|
||||
</RadarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
January - June 2024
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const radialChartData = [
|
||||
{ browser: "safari", visitors: 1260, fill: "var(--color-safari)" },
|
||||
]
|
||||
|
||||
const radialChartConfig = {
|
||||
visitors: {
|
||||
label: "Visitors",
|
||||
},
|
||||
safari: {
|
||||
label: "Safari",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartRadialExample() {
|
||||
return (
|
||||
<Example title="Radial Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Radial Chart - Shape</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 pb-0">
|
||||
<ChartContainer
|
||||
config={radialChartConfig}
|
||||
className="mx-auto aspect-square max-h-[210px]"
|
||||
>
|
||||
<RadialBarChart
|
||||
data={radialChartData}
|
||||
endAngle={100}
|
||||
innerRadius={64}
|
||||
outerRadius={94}
|
||||
>
|
||||
<PolarGrid
|
||||
gridType="circle"
|
||||
radialLines={false}
|
||||
stroke="none"
|
||||
className="first:fill-muted last:fill-background"
|
||||
polarRadius={[86, 74]}
|
||||
/>
|
||||
<RadialBar dataKey="visitors" background />
|
||||
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground text-4xl font-bold"
|
||||
>
|
||||
{radialChartData[0].visitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-muted-foreground"
|
||||
>
|
||||
Visitors
|
||||
</tspan>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</PolarRadiusAxis>
|
||||
</RadialBarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
260
apps/v4/registry/bases/radix/examples/checkbox-example.tsx
Normal file
260
apps/v4/registry/bases/radix/examples/checkbox-example.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/registry/bases/radix/ui/table"
|
||||
|
||||
export default function CheckboxExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CheckboxBasic />
|
||||
<CheckboxWithDescription />
|
||||
<CheckboxInvalid />
|
||||
<CheckboxDisabled />
|
||||
<CheckboxWithTitle />
|
||||
<CheckboxInTable />
|
||||
<CheckboxGroup />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="terms" />
|
||||
<FieldLabel htmlFor="terms">Accept terms and conditions</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="terms-2" defaultChecked />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="terms-2">Accept terms and conditions</FieldLabel>
|
||||
<FieldDescription>
|
||||
By clicking this checkbox, you agree to the terms and conditions.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<Checkbox id="terms-3" aria-invalid />
|
||||
<FieldLabel htmlFor="terms-3">Accept terms and conditions</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="toggle" disabled />
|
||||
<FieldLabel htmlFor="toggle">Enable notifications</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxWithTitle() {
|
||||
return (
|
||||
<Example title="With Title">
|
||||
<FieldGroup>
|
||||
<FieldLabel htmlFor="toggle-2">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="toggle-2" defaultChecked />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable notifications</FieldTitle>
|
||||
<FieldDescription>
|
||||
You can enable or disable notifications at any time.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="toggle-4">
|
||||
<Field orientation="horizontal" data-disabled>
|
||||
<Checkbox id="toggle-4" disabled />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable notifications</FieldTitle>
|
||||
<FieldDescription>
|
||||
You can enable or disable notifications at any time.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: "1",
|
||||
name: "Sarah Chen",
|
||||
email: "sarah.chen@example.com",
|
||||
role: "Admin",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Marcus Rodriguez",
|
||||
email: "marcus.rodriguez@example.com",
|
||||
role: "User",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Priya Patel",
|
||||
email: "priya.patel@example.com",
|
||||
role: "User",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "David Kim",
|
||||
email: "david.kim@example.com",
|
||||
role: "Editor",
|
||||
},
|
||||
]
|
||||
|
||||
function CheckboxInTable() {
|
||||
const [selectedRows, setSelectedRows] = React.useState<Set<string>>(
|
||||
new Set(["1"])
|
||||
)
|
||||
|
||||
const selectAll = selectedRows.size === tableData.length
|
||||
|
||||
const handleSelectAll = (checked: boolean) => {
|
||||
if (checked) {
|
||||
setSelectedRows(new Set(tableData.map((row) => row.id)))
|
||||
} else {
|
||||
setSelectedRows(new Set())
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectRow = (id: string, checked: boolean) => {
|
||||
const newSelected = new Set(selectedRows)
|
||||
if (checked) {
|
||||
newSelected.add(id)
|
||||
} else {
|
||||
newSelected.delete(id)
|
||||
}
|
||||
setSelectedRows(newSelected)
|
||||
}
|
||||
|
||||
return (
|
||||
<Example title="In Table">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-8">
|
||||
<Checkbox
|
||||
id="select-all"
|
||||
checked={selectAll}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead>Role</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{tableData.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={selectedRows.has(row.id) ? "selected" : undefined}
|
||||
>
|
||||
<TableCell>
|
||||
<Checkbox
|
||||
id={`row-${row.id}`}
|
||||
checked={selectedRows.has(row.id)}
|
||||
onCheckedChange={(checked) =>
|
||||
handleSelectRow(row.id, checked === true)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">{row.name}</TableCell>
|
||||
<TableCell>{row.email}</TableCell>
|
||||
<TableCell>{row.role}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxGroup() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<Field>
|
||||
<FieldLabel>Show these items on the desktop:</FieldLabel>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-hard-disks-ljj" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-hard-disks-ljj"
|
||||
className="font-normal"
|
||||
>
|
||||
Hard disks
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-external-disks-1yg" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-external-disks-1yg"
|
||||
className="font-normal"
|
||||
>
|
||||
External disks
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-cds-dvds-fzt" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-cds-dvds-fzt"
|
||||
className="font-normal"
|
||||
>
|
||||
CDs, DVDs, and iPods
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-connected-servers-6l2" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-connected-servers-6l2"
|
||||
className="font-normal"
|
||||
>
|
||||
Connected servers
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
239
apps/v4/registry/bases/radix/examples/collapsible-example.tsx
Normal file
239
apps/v4/registry/bases/radix/examples/collapsible-example.tsx
Normal file
@@ -0,0 +1,239 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/radix/ui/collapsible"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/registry/bases/radix/ui/tabs"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CollapsibleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CollapsibleFileTree />
|
||||
<CollapsibleSettings />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
type FileTreeItem = { name: string } | { name: string; items: FileTreeItem[] }
|
||||
|
||||
function CollapsibleFileTree() {
|
||||
const fileTree: FileTreeItem[] = [
|
||||
{
|
||||
name: "components",
|
||||
items: [
|
||||
{
|
||||
name: "ui",
|
||||
items: [
|
||||
{ name: "button.tsx" },
|
||||
{ name: "card.tsx" },
|
||||
{ name: "dialog.tsx" },
|
||||
{ name: "input.tsx" },
|
||||
{ name: "select.tsx" },
|
||||
{ name: "table.tsx" },
|
||||
],
|
||||
},
|
||||
{ name: "login-form.tsx" },
|
||||
{ name: "register-form.tsx" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "lib",
|
||||
items: [{ name: "utils.ts" }, { name: "cn.ts" }, { name: "api.ts" }],
|
||||
},
|
||||
{
|
||||
name: "hooks",
|
||||
items: [
|
||||
{ name: "use-media-query.ts" },
|
||||
{ name: "use-debounce.ts" },
|
||||
{ name: "use-local-storage.ts" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "types",
|
||||
items: [{ name: "index.d.ts" }, { name: "api.d.ts" }],
|
||||
},
|
||||
{
|
||||
name: "public",
|
||||
items: [
|
||||
{ name: "favicon.ico" },
|
||||
{ name: "logo.svg" },
|
||||
{ name: "images" },
|
||||
],
|
||||
},
|
||||
{ name: "app.tsx" },
|
||||
{ name: "layout.tsx" },
|
||||
{ name: "globals.css" },
|
||||
{ name: "package.json" },
|
||||
{ name: "tsconfig.json" },
|
||||
{ name: "README.md" },
|
||||
{ name: ".gitignore" },
|
||||
]
|
||||
|
||||
const renderItem = (fileItem: FileTreeItem) => {
|
||||
if ("items" in fileItem) {
|
||||
return (
|
||||
<Collapsible key={fileItem.name}>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="group w-full justify-start transition-none hover:bg-accent hover:text-accent-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="transition-transform group-data-[state=open]:rotate-90"
|
||||
/>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
{fileItem.name}
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mt-1 ml-5 style-lyra:ml-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
{fileItem.items.map((child) => renderItem(child))}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
key={fileItem.name}
|
||||
variant="link"
|
||||
size="sm"
|
||||
className="w-full justify-start gap-2 text-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
<span>{fileItem.name}</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Example title="File Tree" className="items-center">
|
||||
<Card className="mx-auto w-full max-w-[16rem] gap-2" size="sm">
|
||||
<CardHeader>
|
||||
<Tabs defaultValue="explorer">
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="explorer">Explorer</TabsTrigger>
|
||||
<TabsTrigger value="settings">Outline</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
{fileTree.map((item) => renderItem(item))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CollapsibleSettings() {
|
||||
const [isOpen, setIsOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Settings" className="items-center">
|
||||
<Card className="mx-auto w-full max-w-xs" size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Radius</CardTitle>
|
||||
<CardDescription>
|
||||
Set the corner radius of the element.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Collapsible
|
||||
open={isOpen}
|
||||
onOpenChange={setIsOpen}
|
||||
className="flex items-start gap-2"
|
||||
>
|
||||
<FieldGroup className="grid w-full grid-cols-2 gap-2">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-x" className="sr-only">
|
||||
Radius X
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-y" className="sr-only">
|
||||
Radius Y
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<CollapsibleContent className="col-span-full grid grid-cols-subgrid gap-2">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-x" className="sr-only">
|
||||
Radius X
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-y" className="sr-only">
|
||||
Radius Y
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
</CollapsibleContent>
|
||||
</FieldGroup>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
{isOpen ? (
|
||||
<IconPlaceholder
|
||||
lucide="MinimizeIcon"
|
||||
tabler="IconMinimize"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
) : (
|
||||
<IconPlaceholder
|
||||
lucide="MaximizeIcon"
|
||||
tabler="IconMaximize"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
</Collapsible>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
1249
apps/v4/registry/bases/radix/examples/combobox-example.tsx
Normal file
1249
apps/v4/registry/bases/radix/examples/combobox-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
590
apps/v4/registry/bases/radix/examples/command-example.tsx
Normal file
590
apps/v4/registry/bases/radix/examples/command-example.tsx
Normal file
@@ -0,0 +1,590 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "@/registry/bases/radix/ui/command"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CommandExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CommandInline />
|
||||
<CommandBasic />
|
||||
<CommandWithShortcuts />
|
||||
<CommandWithGroups />
|
||||
<CommandManyItems />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandInline() {
|
||||
return (
|
||||
<Example title="Inline">
|
||||
<Card className="w-full p-0">
|
||||
<CardContent className="p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SmileIcon"
|
||||
tabler="IconMoodSmile"
|
||||
hugeicons="SmileIcon"
|
||||
phosphor="SmileyIcon"
|
||||
remixicon="RiEmotionLine"
|
||||
/>
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandBasic() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>Calendar</CommandItem>
|
||||
<CommandItem>Search Emoji</CommandItem>
|
||||
<CommandItem>Calculator</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandWithShortcuts() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandWithGroups() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Groups">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SmileIcon"
|
||||
tabler="IconMoodSmile"
|
||||
hugeicons="SmileIcon"
|
||||
phosphor="SmileyIcon"
|
||||
remixicon="RiEmotionLine"
|
||||
/>
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandManyItems() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Many Groups & Items">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Navigation">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="HomeIcon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
<span>Home</span>
|
||||
<CommandShortcut>⌘H</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="InboxIcon"
|
||||
tabler="IconInbox"
|
||||
hugeicons="InboxIcon"
|
||||
phosphor="TrayIcon"
|
||||
remixicon="RiInboxLine"
|
||||
/>
|
||||
<span>Inbox</span>
|
||||
<CommandShortcut>⌘I</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="File02Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
<span>Documents</span>
|
||||
<CommandShortcut>⌘D</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
<span>Folders</span>
|
||||
<CommandShortcut>⌘F</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Actions">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
<span>New File</span>
|
||||
<CommandShortcut>⌘N</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderPlusIcon"
|
||||
tabler="IconFolderPlus"
|
||||
hugeicons="FolderAddIcon"
|
||||
phosphor="FolderPlusIcon"
|
||||
remixicon="RiFolderAddLine"
|
||||
/>
|
||||
<span>New Folder</span>
|
||||
<CommandShortcut>⇧⌘N</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
<span>Copy</span>
|
||||
<CommandShortcut>⌘C</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
<span>Cut</span>
|
||||
<CommandShortcut>⌘X</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
<span>Paste</span>
|
||||
<CommandShortcut>⌘V</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
<span>Delete</span>
|
||||
<CommandShortcut>⌫</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="View">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="LayoutGridIcon"
|
||||
tabler="IconLayoutGrid"
|
||||
hugeicons="GridIcon"
|
||||
phosphor="GridFourIcon"
|
||||
remixicon="RiGridLine"
|
||||
/>
|
||||
<span>Grid View</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ListIcon"
|
||||
tabler="IconList"
|
||||
hugeicons="Menu05Icon"
|
||||
phosphor="ListIcon"
|
||||
remixicon="RiListUnordered"
|
||||
/>
|
||||
<span>List View</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ZoomInIcon"
|
||||
tabler="IconZoomIn"
|
||||
hugeicons="ZoomInAreaIcon"
|
||||
phosphor="MagnifyingGlassMinusIcon"
|
||||
remixicon="RiSearchEyeLine"
|
||||
/>
|
||||
<span>Zoom In</span>
|
||||
<CommandShortcut>⌘+</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ZoomOutIcon"
|
||||
tabler="IconZoomOut"
|
||||
hugeicons="ZoomOutAreaIcon"
|
||||
phosphor="MagnifyingGlassPlusIcon"
|
||||
remixicon="RiZoomInLine"
|
||||
/>
|
||||
<span>Zoom Out</span>
|
||||
<CommandShortcut>⌘-</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Account">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
<span>Notifications</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
<span>Help & Support</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Tools">
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="ImageIcon"
|
||||
tabler="IconPhoto"
|
||||
hugeicons="ImageIcon"
|
||||
phosphor="ImageIcon"
|
||||
remixicon="RiImageLine"
|
||||
/>
|
||||
<span>Image Editor</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
<span>Code Editor</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
657
apps/v4/registry/bases/radix/examples/component-example.tsx
Normal file
657
apps/v4/registry/bases/radix/examples/component-example.tsx
Normal file
@@ -0,0 +1,657 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogMedia,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/alert-dialog"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Combobox,
|
||||
ComboboxContent,
|
||||
ComboboxEmpty,
|
||||
ComboboxInput,
|
||||
ComboboxItem,
|
||||
ComboboxList,
|
||||
} from "@/registry/bases/radix/ui/combobox"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function ComponentExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CardExample />
|
||||
<FormExample />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CardExample() {
|
||||
return (
|
||||
<Example title="Card" className="items-center justify-center">
|
||||
<Card className="relative w-full max-w-sm overflow-hidden 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>Observability Plus is replacing Monitoring</CardTitle>
|
||||
<CardDescription>
|
||||
Switch to the improved way to explore your data, with natural
|
||||
language. Monitoring will no longer be available on the Pro plan in
|
||||
November, 2025
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Show Dialog
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this
|
||||
device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<Badge variant="secondary" className="ml-auto">
|
||||
Warning
|
||||
</Badge>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const frameworks = [
|
||||
"Next.js",
|
||||
"SvelteKit",
|
||||
"Nuxt.js",
|
||||
"Remix",
|
||||
"Astro",
|
||||
] as const
|
||||
|
||||
function FormExample() {
|
||||
const [notifications, setNotifications] = React.useState({
|
||||
email: true,
|
||||
sms: false,
|
||||
push: true,
|
||||
})
|
||||
const [theme, setTheme] = React.useState("light")
|
||||
|
||||
return (
|
||||
<Example title="Form">
|
||||
<Card className="w-full max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle>User Information</CardTitle>
|
||||
<CardDescription>Please fill in your details below</CardDescription>
|
||||
<CardAction>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MoreVerticalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeVerticalIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
<span className="sr-only">More options</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>File</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
New File
|
||||
<DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
New Folder
|
||||
<DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="FolderOpenIcon"
|
||||
tabler="IconFolderOpen"
|
||||
hugeicons="FolderOpenIcon"
|
||||
phosphor="FolderOpenIcon"
|
||||
remixicon="RiFolderOpenLine"
|
||||
/>
|
||||
Open Recent
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Alpha
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Beta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
More Projects
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Gamma
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Delta
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderSearchIcon"
|
||||
tabler="IconFolderSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
Browse...
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
Save
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="DownloadIcon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
Export
|
||||
<DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>View</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.email}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({
|
||||
...notifications,
|
||||
email: checked === true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="EyeIcon"
|
||||
tabler="IconEye"
|
||||
hugeicons="EyeIcon"
|
||||
phosphor="EyeIcon"
|
||||
remixicon="RiEyeLine"
|
||||
/>
|
||||
Show Sidebar
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.sms}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({
|
||||
...notifications,
|
||||
sms: checked === true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Show Status Bar
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="PaletteIcon"
|
||||
tabler="IconPalette"
|
||||
hugeicons="PaintBoardIcon"
|
||||
phosphor="PaletteIcon"
|
||||
remixicon="RiPaletteLine"
|
||||
/>
|
||||
Theme
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup
|
||||
value={theme}
|
||||
onValueChange={setTheme}
|
||||
>
|
||||
<DropdownMenuRadioItem value="light">
|
||||
<IconPlaceholder
|
||||
lucide="SunIcon"
|
||||
tabler="IconSun"
|
||||
hugeicons="SunIcon"
|
||||
phosphor="SunIcon"
|
||||
remixicon="RiSunLine"
|
||||
/>
|
||||
Light
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="dark">
|
||||
<IconPlaceholder
|
||||
lucide="MoonIcon"
|
||||
tabler="IconMoon"
|
||||
hugeicons="MoonIcon"
|
||||
phosphor="MoonIcon"
|
||||
remixicon="RiMoonLine"
|
||||
/>
|
||||
Dark
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="system">
|
||||
<IconPlaceholder
|
||||
lucide="MonitorIcon"
|
||||
tabler="IconDeviceDesktop"
|
||||
hugeicons="ComputerIcon"
|
||||
phosphor="MonitorIcon"
|
||||
remixicon="RiComputerLine"
|
||||
/>
|
||||
System
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Preferences</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="KeyboardIcon"
|
||||
tabler="IconKeyboard"
|
||||
hugeicons="KeyboardIcon"
|
||||
phosphor="KeyboardIcon"
|
||||
remixicon="RiKeyboardLine"
|
||||
/>
|
||||
Keyboard Shortcuts
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="LanguagesIcon"
|
||||
tabler="IconLanguage"
|
||||
hugeicons="LanguageCircleIcon"
|
||||
phosphor="TranslateIcon"
|
||||
remixicon="RiTranslate"
|
||||
/>
|
||||
Language
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Notifications
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>
|
||||
Notification Types
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.push}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({
|
||||
...notifications,
|
||||
push: checked === true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Push Notifications
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.email}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({
|
||||
...notifications,
|
||||
email: checked === true,
|
||||
})
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email Notifications
|
||||
</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShieldIcon"
|
||||
tabler="IconShield"
|
||||
hugeicons="ShieldIcon"
|
||||
phosphor="ShieldIcon"
|
||||
remixicon="RiShieldLine"
|
||||
/>
|
||||
Privacy & Security
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
Help & Support
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
Documentation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<FieldGroup>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-name">Name</FieldLabel>
|
||||
<Input
|
||||
id="small-form-name"
|
||||
placeholder="Enter your name"
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-role">Role</FieldLabel>
|
||||
<Select defaultValue="">
|
||||
<SelectTrigger id="small-form-role">
|
||||
<SelectValue placeholder="Select a role" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="developer">Developer</SelectItem>
|
||||
<SelectItem value="designer">Designer</SelectItem>
|
||||
<SelectItem value="manager">Manager</SelectItem>
|
||||
<SelectItem value="other">Other</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-framework">
|
||||
Framework
|
||||
</FieldLabel>
|
||||
<Combobox items={frameworks}>
|
||||
<ComboboxInput
|
||||
id="small-form-framework"
|
||||
placeholder="Select a framework"
|
||||
required
|
||||
/>
|
||||
<ComboboxContent>
|
||||
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
|
||||
<ComboboxList>
|
||||
{(item) => (
|
||||
<ComboboxItem key={item} value={item}>
|
||||
{item}
|
||||
</ComboboxItem>
|
||||
)}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
</Combobox>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-comments">Comments</FieldLabel>
|
||||
<Textarea
|
||||
id="small-form-comments"
|
||||
placeholder="Add any additional comments"
|
||||
/>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="outline" type="button">
|
||||
Cancel
|
||||
</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
635
apps/v4/registry/bases/radix/examples/context-menu-example.tsx
Normal file
635
apps/v4/registry/bases/radix/examples/context-menu-example.tsx
Normal file
@@ -0,0 +1,635 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuCheckboxItem,
|
||||
ContextMenuContent,
|
||||
ContextMenuGroup,
|
||||
ContextMenuItem,
|
||||
ContextMenuLabel,
|
||||
ContextMenuRadioGroup,
|
||||
ContextMenuRadioItem,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuShortcut,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/context-menu"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ContextMenuExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ContextMenuBasic />
|
||||
<ContextMenuWithSides />
|
||||
<ContextMenuWithIcons />
|
||||
<ContextMenuWithShortcuts />
|
||||
<ContextMenuWithSubmenu />
|
||||
<ContextMenuWithGroups />
|
||||
<ContextMenuWithCheckboxes />
|
||||
<ContextMenuWithRadio />
|
||||
<ContextMenuWithDestructive />
|
||||
<ContextMenuInDialog />
|
||||
<ContextMenuWithInset />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem disabled>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithShortcuts() {
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Back
|
||||
<ContextMenuShortcut>⌘[</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem disabled>
|
||||
Forward
|
||||
<ContextMenuShortcut>⌘]</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Reload
|
||||
<ContextMenuShortcut>⌘R</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Save
|
||||
<ContextMenuShortcut>⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Save As...
|
||||
<ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithSubmenu() {
|
||||
return (
|
||||
<Example title="With Submenu">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Copy
|
||||
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Cut
|
||||
<ContextMenuShortcut>⌘X</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
<ContextMenuItem>Name Window...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">Delete</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithGroups() {
|
||||
return (
|
||||
<Example title="With Groups, Labels & Separators">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>File</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
New File
|
||||
<ContextMenuShortcut>⌘N</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Open File
|
||||
<ContextMenuShortcut>⌘O</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Save
|
||||
<ContextMenuShortcut>⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Edit</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
Undo
|
||||
<ContextMenuShortcut>⌘Z</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Redo
|
||||
<ContextMenuShortcut>⇧⌘Z</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuItem>
|
||||
Cut
|
||||
<ContextMenuShortcut>⌘X</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Copy
|
||||
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Paste
|
||||
<ContextMenuShortcut>⌘V</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
Delete
|
||||
<ContextMenuShortcut>⌫</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithCheckboxes() {
|
||||
const [showBookmarksBar, setShowBookmarksBar] = React.useState(true)
|
||||
const [showFullUrls, setShowFullUrls] = React.useState(false)
|
||||
const [showDeveloperTools, setShowDeveloperTools] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Checkboxes">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuCheckboxItem
|
||||
checked={showBookmarksBar}
|
||||
onCheckedChange={setShowBookmarksBar}
|
||||
>
|
||||
Show Bookmarks Bar
|
||||
</ContextMenuCheckboxItem>
|
||||
<ContextMenuCheckboxItem
|
||||
checked={showFullUrls}
|
||||
onCheckedChange={setShowFullUrls}
|
||||
>
|
||||
Show Full URLs
|
||||
</ContextMenuCheckboxItem>
|
||||
<ContextMenuCheckboxItem
|
||||
checked={showDeveloperTools}
|
||||
onCheckedChange={setShowDeveloperTools}
|
||||
>
|
||||
Show Developer Tools
|
||||
</ContextMenuCheckboxItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithRadio() {
|
||||
const [user, setUser] = React.useState("pedro")
|
||||
const [theme, setTheme] = React.useState("light")
|
||||
|
||||
return (
|
||||
<Example title="With Radio Group">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>People</ContextMenuLabel>
|
||||
<ContextMenuRadioGroup value={user} onValueChange={setUser}>
|
||||
<ContextMenuRadioItem value="pedro">
|
||||
Pedro Duarte
|
||||
</ContextMenuRadioItem>
|
||||
<ContextMenuRadioItem value="colm">
|
||||
Colm Tuite
|
||||
</ContextMenuRadioItem>
|
||||
</ContextMenuRadioGroup>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Theme</ContextMenuLabel>
|
||||
<ContextMenuRadioGroup value={theme} onValueChange={setTheme}>
|
||||
<ContextMenuRadioItem value="light">Light</ContextMenuRadioItem>
|
||||
<ContextMenuRadioItem value="dark">Dark</ContextMenuRadioItem>
|
||||
<ContextMenuRadioItem value="system">System</ContextMenuRadioItem>
|
||||
</ContextMenuRadioGroup>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithDestructive() {
|
||||
return (
|
||||
<Example title="With Destructive Items">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PencilIcon"
|
||||
tabler="IconPencil"
|
||||
hugeicons="EditIcon"
|
||||
phosphor="PencilIcon"
|
||||
remixicon="RiPencilLine"
|
||||
/>
|
||||
Edit
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="ShareIcon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ArchiveIcon"
|
||||
tabler="IconArchive"
|
||||
hugeicons="Archive02Icon"
|
||||
phosphor="ArchiveIcon"
|
||||
remixicon="RiArchiveLine"
|
||||
/>
|
||||
Archive
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithSides() {
|
||||
return (
|
||||
<Example title="With Sides">
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click (top)
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent side="top">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click (right)
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent side="right">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click (bottom)
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent side="bottom">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click (left)
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent side="left">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Context Menu Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Right click on the area below to see the context menu.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger>More Options</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
<ContextMenuItem>Name Window...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithInset() {
|
||||
const [showBookmarks, setShowBookmarks] = React.useState(true)
|
||||
const [showUrls, setShowUrls] = React.useState(false)
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Inset">
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm">
|
||||
Right click here
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenuContent className="w-44">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Actions</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem inset>Paste</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel inset>Appearance</ContextMenuLabel>
|
||||
<ContextMenuCheckboxItem
|
||||
inset
|
||||
checked={showBookmarks}
|
||||
onCheckedChange={setShowBookmarks}
|
||||
>
|
||||
Bookmarks
|
||||
</ContextMenuCheckboxItem>
|
||||
<ContextMenuCheckboxItem
|
||||
inset
|
||||
checked={showUrls}
|
||||
onCheckedChange={setShowUrls}
|
||||
>
|
||||
Full URLs
|
||||
</ContextMenuCheckboxItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel inset>Theme</ContextMenuLabel>
|
||||
<ContextMenuRadioGroup value={theme} onValueChange={setTheme}>
|
||||
<ContextMenuRadioItem inset value="light">
|
||||
Light
|
||||
</ContextMenuRadioItem>
|
||||
<ContextMenuRadioItem inset value="dark">
|
||||
Dark
|
||||
</ContextMenuRadioItem>
|
||||
<ContextMenuRadioItem inset value="system">
|
||||
System
|
||||
</ContextMenuRadioItem>
|
||||
</ContextMenuRadioGroup>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger inset>More Options</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
</ContextMenuContent>
|
||||
</ContextMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
409
apps/v4/registry/bases/radix/examples/demo.tsx
Normal file
409
apps/v4/registry/bases/radix/examples/demo.tsx
Normal file
@@ -0,0 +1,409 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/alert-dialog"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { ButtonGroup } from "@/registry/bases/radix/ui/button-group"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Field, FieldGroup } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/radix/ui/radio-group"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function Demo() {
|
||||
const [sliderValue, setSliderValue] = React.useState<number[]>([500])
|
||||
const handleSliderValueChange = React.useCallback((value: number[]) => {
|
||||
setSliderValue(value)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen w-full flex-col items-center justify-center bg-muted p-4 sm:p-6 lg:p-12 dark:bg-background">
|
||||
<div className="grid max-w-3xl gap-4 sm:grid-cols-2">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Style Overview</CardTitle>
|
||||
<CardDescription className="line-clamp-2">
|
||||
Designers love packing quirky glyphs into test phrases. This is
|
||||
a preview of the typography styles.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-6 gap-3">
|
||||
{[
|
||||
"--background",
|
||||
"--foreground",
|
||||
"--primary",
|
||||
"--secondary",
|
||||
"--muted",
|
||||
"--accent",
|
||||
"--border",
|
||||
"--chart-1",
|
||||
"--chart-2",
|
||||
"--chart-3",
|
||||
"--chart-4",
|
||||
"--chart-5",
|
||||
].map((variant) => (
|
||||
<div
|
||||
key={variant}
|
||||
className="flex flex-col flex-wrap items-center gap-2"
|
||||
>
|
||||
<div
|
||||
className="relative aspect-square w-full rounded-lg bg-(--color) after:absolute after:inset-0 after:rounded-lg after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten"
|
||||
style={
|
||||
{
|
||||
"--color": `var(${variant})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
<div className="hidden max-w-14 truncate font-mono text-[0.60rem] md:block">
|
||||
{variant}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-8 place-items-center gap-4">
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingBagIcon"
|
||||
tabler="IconShoppingBag"
|
||||
hugeicons="ShoppingBag01Icon"
|
||||
phosphor="BagIcon"
|
||||
remixicon="RiShoppingBagLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="Loader2Icon"
|
||||
tabler="IconLoader"
|
||||
hugeicons="Loading03Icon"
|
||||
phosphor="SpinnerIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft02Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings01Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card className="w-full">
|
||||
<CardContent className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button>Button</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
</div>
|
||||
<Item variant="outline">
|
||||
<ItemContent>
|
||||
<ItemTitle>Two-factor authentication</ItemTitle>
|
||||
<ItemDescription className="text-pretty xl:hidden 2xl:block">
|
||||
Verify via email or phone number.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<ItemActions className="hidden md:flex">
|
||||
<Button size="sm" variant="secondary">
|
||||
Enable
|
||||
</Button>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</div>
|
||||
<Slider
|
||||
value={sliderValue}
|
||||
onValueChange={handleSliderValueChange}
|
||||
max={1000}
|
||||
min={0}
|
||||
step={10}
|
||||
className="flex-1"
|
||||
aria-label="Slider"
|
||||
/>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field className="flex-1">
|
||||
<Textarea placeholder="Message" className="resize-none" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Badge>Badge</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
</div>
|
||||
<RadioGroup
|
||||
defaultValue="apple"
|
||||
className="ml-auto flex w-fit gap-3"
|
||||
>
|
||||
<RadioGroupItem value="apple" />
|
||||
<RadioGroupItem value="banana" />
|
||||
</RadioGroup>
|
||||
<div className="flex gap-3">
|
||||
<Checkbox defaultChecked />
|
||||
<Checkbox />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<span className="hidden md:block">Alert Dialog</span>
|
||||
<span className="block md:hidden">Dialog</span>
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
Allow accessory to connect?
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to
|
||||
this device and your data?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button Group</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronUpIcon"
|
||||
tabler="IconChevronUp"
|
||||
hugeicons="ArrowUp01Icon"
|
||||
phosphor="CaretUpIcon"
|
||||
remixicon="RiArrowUpSLine"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
side="top"
|
||||
className="w-fit"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Quick Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Mute Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Mark as Read</DropdownMenuItem>
|
||||
<DropdownMenuItem>Block User</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Conversation</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Share Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Copy Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Report Conversation</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ButtonGroup>
|
||||
<Switch defaultChecked className="ml-auto" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
586
apps/v4/registry/bases/radix/examples/dialog-example.tsx
Normal file
586
apps/v4/registry/bases/radix/examples/dialog-example.tsx
Normal file
@@ -0,0 +1,586 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldSeparator,
|
||||
FieldSet,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Kbd } from "@/registry/bases/radix/ui/kbd"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/bases/radix/ui/tabs"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/registry/bases/radix/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function DialogExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DialogWithForm />
|
||||
<DialogScrollableContent />
|
||||
<DialogWithStickyFooter />
|
||||
<DialogNoCloseButton />
|
||||
<DialogChatSettings />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogWithForm() {
|
||||
return (
|
||||
<Example title="With Form" className="items-center justify-center">
|
||||
<Dialog>
|
||||
<form>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Edit Profile</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit profile</DialogTitle>
|
||||
<DialogDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done. Your profile will be updated immediately.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="name-1">Name</FieldLabel>
|
||||
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="username-1">Username</FieldLabel>
|
||||
<Input
|
||||
id="username-1"
|
||||
name="username"
|
||||
defaultValue="@peduarte"
|
||||
/>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit">Save changes</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</form>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogScrollableContent() {
|
||||
return (
|
||||
<Example title="Scrollable Content" className="items-center justify-center">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Scrollable Content</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Scrollable Content</DialogTitle>
|
||||
<DialogDescription>
|
||||
This is a dialog with scrollable content.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="no-scrollbar max-h-[70vh] overflow-y-auto style-vega:-mx-6 style-vega:px-6 style-nova:-mx-4 style-nova:px-4 style-lyra:-mx-4 style-lyra:px-4 style-maia:-mx-6 style-maia:px-6 style-mira:-mx-4 style-mira:px-4 style-luma:-mx-6 style-luma:px-6 style-rhea:-mx-6 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
||||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogWithStickyFooter() {
|
||||
return (
|
||||
<Example title="With Sticky Footer" className="items-center justify-center">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Sticky Footer</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Scrollable Content</DialogTitle>
|
||||
<DialogDescription>
|
||||
This is a dialog with scrollable content.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="no-scrollbar max-h-[70vh] overflow-y-auto style-vega:-mx-6 style-vega:px-6 style-nova:-mx-4 style-nova:px-4 style-lyra:-mx-4 style-lyra:px-4 style-maia:-mx-6 style-maia:px-6 style-mira:-mx-4 style-mira:px-4 style-luma:-mx-6 style-luma:px-6 style-rhea:-mx-6 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
||||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Close</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogNoCloseButton() {
|
||||
return (
|
||||
<Example title="No Close Button" className="items-center justify-center">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">No Close Button</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent showCloseButton={false}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>No Close Button</DialogTitle>
|
||||
<DialogDescription>
|
||||
This dialog doesn't have a close button in the top-right
|
||||
corner.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Close</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const spokenLanguages = [
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
{ label: "French", value: "fr" },
|
||||
{ label: "German", value: "de" },
|
||||
{ label: "Italian", value: "it" },
|
||||
{ label: "Portuguese", value: "pt" },
|
||||
{ label: "Russian", value: "ru" },
|
||||
{ label: "Chinese", value: "zh" },
|
||||
{ label: "Japanese", value: "ja" },
|
||||
{ label: "Korean", value: "ko" },
|
||||
{ label: "Arabic", value: "ar" },
|
||||
{ label: "Hindi", value: "hi" },
|
||||
{ label: "Bengali", value: "bn" },
|
||||
{ label: "Telugu", value: "te" },
|
||||
{ label: "Marathi", value: "mr" },
|
||||
{ label: "Kannada", value: "kn" },
|
||||
{ label: "Malayalam", value: "ml" },
|
||||
]
|
||||
|
||||
const voices = [
|
||||
{ label: "Samantha", value: "samantha" },
|
||||
{ label: "Alex", value: "alex" },
|
||||
{ label: "Fred", value: "fred" },
|
||||
{ label: "Victoria", value: "victoria" },
|
||||
{ label: "Tom", value: "tom" },
|
||||
{ label: "Karen", value: "karen" },
|
||||
{ label: "Sam", value: "sam" },
|
||||
{ label: "Daniel", value: "daniel" },
|
||||
]
|
||||
|
||||
function DialogChatSettings() {
|
||||
const [tab, setTab] = React.useState("general")
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
const [accentColor, setAccentColor] = React.useState("default")
|
||||
const [spokenLanguage, setSpokenLanguage] = React.useState("en")
|
||||
const [voice, setVoice] = React.useState("samantha")
|
||||
|
||||
return (
|
||||
<Example title="Chat Settings" className="items-center justify-center">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Chat Settings</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="min-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Chat Settings</DialogTitle>
|
||||
<DialogDescription>
|
||||
Customize your chat settings: theme, accent color, spoken
|
||||
language, voice, personality, and custom instructions.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4">
|
||||
<NativeSelect
|
||||
value={tab}
|
||||
onChange={(e) => setTab(e.target.value)}
|
||||
className="w-full md:hidden"
|
||||
>
|
||||
<NativeSelectOption value="general">General</NativeSelectOption>
|
||||
<NativeSelectOption value="notifications">
|
||||
Notifications
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="personalization">
|
||||
Personalization
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="security">Security</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<Tabs value={tab} onValueChange={setTab}>
|
||||
<TabsList className="hidden w-full md:flex">
|
||||
<TabsTrigger value="general">General</TabsTrigger>
|
||||
<TabsTrigger value="notifications">Notifications</TabsTrigger>
|
||||
<TabsTrigger value="personalization">
|
||||
Personalization
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="security">Security</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border **:data-[slot=select-trigger]:min-w-[125px] style-vega:min-h-[550px] style-vega:rounded-lg style-vega:p-6 style-nova:min-h-[460px] style-nova:rounded-lg style-nova:p-4 style-lyra:min-h-[450px] style-lyra:rounded-none style-lyra:p-4 style-maia:min-h-[550px] style-maia:rounded-xl style-maia:p-6 style-mira:min-h-[450px] style-mira:rounded-md style-mira:p-4 style-luma:min-h-[550px] style-luma:rounded-xl style-luma:p-6 style-rhea:min-h-[480px] style-rhea:rounded-2xl style-rhea:p-6">
|
||||
<TabsContent value="general">
|
||||
<FieldSet>
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="theme">Theme</FieldLabel>
|
||||
<Select value={theme} onValueChange={setTheme}>
|
||||
<SelectTrigger id="theme">
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end">
|
||||
<SelectGroup>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="accent-color">
|
||||
Accent Color
|
||||
</FieldLabel>
|
||||
<Select
|
||||
value={accentColor}
|
||||
onValueChange={setAccentColor}
|
||||
>
|
||||
<SelectTrigger id="accent-color">
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end">
|
||||
<SelectGroup>
|
||||
<SelectItem value="default">
|
||||
<div className="size-3 rounded-full bg-neutral-500 dark:bg-neutral-400" />
|
||||
Default
|
||||
</SelectItem>
|
||||
<SelectItem value="red">
|
||||
<div className="size-3 rounded-full bg-red-500 dark:bg-red-400" />
|
||||
Red
|
||||
</SelectItem>
|
||||
<SelectItem value="blue">
|
||||
<div className="size-3 rounded-full bg-blue-500 dark:bg-blue-400" />
|
||||
Blue
|
||||
</SelectItem>
|
||||
<SelectItem value="green">
|
||||
<div className="size-3 rounded-full bg-green-500 dark:bg-green-400" />
|
||||
Green
|
||||
</SelectItem>
|
||||
<SelectItem value="purple">
|
||||
<div className="size-3 rounded-full bg-purple-500 dark:bg-purple-400" />
|
||||
Purple
|
||||
</SelectItem>
|
||||
<SelectItem value="pink">
|
||||
<div className="size-3 rounded-full bg-pink-500 dark:bg-pink-400" />
|
||||
Pink
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="responsive">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="spoken-language">
|
||||
Spoken Language
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
For best results, select the language you mainly
|
||||
speak. If it's not listed, it may still be
|
||||
supported via auto-detection.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Select
|
||||
value={spokenLanguage}
|
||||
onValueChange={setSpokenLanguage}
|
||||
>
|
||||
<SelectTrigger id="spoken-language">
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end" position="item-aligned">
|
||||
<SelectGroup>
|
||||
<SelectItem value="auto">Auto</SelectItem>
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<SelectGroup>
|
||||
{spokenLanguages.map((language) => (
|
||||
<SelectItem
|
||||
key={language.value}
|
||||
value={language.value}
|
||||
>
|
||||
{language.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="voice">Voice</FieldLabel>
|
||||
<Select value={voice} onValueChange={setVoice}>
|
||||
<SelectTrigger id="voice">
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end" position="item-aligned">
|
||||
<SelectGroup>
|
||||
{voices.map((voice) => (
|
||||
<SelectItem
|
||||
key={voice.value}
|
||||
value={voice.value}
|
||||
>
|
||||
{voice.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
</TabsContent>
|
||||
<TabsContent value="notifications">
|
||||
<FieldGroup>
|
||||
<FieldSet>
|
||||
<FieldLabel>Responses</FieldLabel>
|
||||
<FieldDescription>
|
||||
Get notified when ChatGPT responds to requests that take
|
||||
time, like research or image generation.
|
||||
</FieldDescription>
|
||||
<FieldGroup data-slot="checkbox-group">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="push" defaultChecked disabled />
|
||||
<FieldLabel htmlFor="push" className="font-normal">
|
||||
Push notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
<FieldSeparator />
|
||||
<FieldSet>
|
||||
<FieldLabel>Tasks</FieldLabel>
|
||||
<FieldDescription>
|
||||
Get notified when tasks you've created have
|
||||
updates. <a href="#">Manage tasks</a>
|
||||
</FieldDescription>
|
||||
<FieldGroup data-slot="checkbox-group">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="push-tasks" />
|
||||
<FieldLabel
|
||||
htmlFor="push-tasks"
|
||||
className="font-normal"
|
||||
>
|
||||
Push notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="email-tasks" />
|
||||
<FieldLabel
|
||||
htmlFor="email-tasks"
|
||||
className="font-normal"
|
||||
>
|
||||
Email notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
<TabsContent value="personalization">
|
||||
<FieldGroup>
|
||||
<Field orientation="responsive">
|
||||
<FieldLabel htmlFor="nickname">Nickname</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="nickname"
|
||||
placeholder="Broski"
|
||||
className="@md/field-group:max-w-[200px]"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InputGroupButton size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="flex items-center gap-2">
|
||||
Used to identify you in the chat. <Kbd>N</Kbd>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field
|
||||
orientation="responsive"
|
||||
className="@md/field-group:flex-col @2xl/field-group:flex-row"
|
||||
>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="about">More about you</FieldLabel>
|
||||
<FieldDescription>
|
||||
Tell us more about yourself. This will be used to help
|
||||
us personalize your experience.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Textarea
|
||||
id="about"
|
||||
placeholder="I'm a software engineer..."
|
||||
className="min-h-[120px] @md/field-group:min-w-full @2xl/field-group:min-w-[300px]"
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<FieldLabel>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="customization">
|
||||
Enable customizations
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable customizations to make ChatGPT more
|
||||
personalized.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="customization" defaultChecked />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
<TabsContent value="security">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="2fa">
|
||||
Multi-factor authentication
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable multi-factor authentication to secure your
|
||||
account. If you do not have a two-factor
|
||||
authentication device, you can use a one-time code
|
||||
sent to your email.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="2fa" />
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Log out</FieldTitle>
|
||||
<FieldDescription>
|
||||
Log out of your account on this device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Button variant="outline" size="sm">
|
||||
Log Out
|
||||
</Button>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Log out of all devices</FieldTitle>
|
||||
<FieldDescription>
|
||||
This will log you out of all devices, including the
|
||||
current session. It may take up to 30 minutes for the
|
||||
changes to take effect.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Button variant="outline" size="sm">
|
||||
Log Out All
|
||||
</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
125
apps/v4/registry/bases/radix/examples/drawer-example.tsx
Normal file
125
apps/v4/registry/bases/radix/examples/drawer-example.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@/registry/bases/radix/ui/drawer"
|
||||
|
||||
export default function DrawerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DrawerScrollableContent />
|
||||
<DrawerWithSides />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const DRAWER_SIDES = ["top", "right", "bottom", "left"] as const
|
||||
|
||||
function DrawerWithSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{DRAWER_SIDES.map((side) => (
|
||||
<Drawer
|
||||
key={side}
|
||||
direction={
|
||||
side === "bottom" ? undefined : (side as "top" | "right" | "left")
|
||||
}
|
||||
>
|
||||
<DrawerTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="capitalize style-sera:uppercase"
|
||||
>
|
||||
{side}
|
||||
</Button>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="data-[vaul-drawer-direction=bottom]:max-h-[50vh] data-[vaul-drawer-direction=top]:max-h-[50vh]">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Move Goal</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Set your daily activity goal.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="no-scrollbar overflow-y-auto px-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed style-sera:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia
|
||||
deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerScrollableContent() {
|
||||
return (
|
||||
<Example title="Scrollable Content">
|
||||
<Drawer direction="right">
|
||||
<DrawerTrigger asChild>
|
||||
<Button variant="outline">Scrollable Content</Button>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Move Goal</DrawerTitle>
|
||||
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="no-scrollbar overflow-y-auto px-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed style-sera:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
||||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
978
apps/v4/registry/bases/radix/examples/dropdown-menu-example.tsx
Normal file
978
apps/v4/registry/bases/radix/examples/dropdown-menu-example.tsx
Normal file
@@ -0,0 +1,978 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/radix/ui/avatar"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function DropdownMenuExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DropdownMenuBasic />
|
||||
<DropdownMenuComplex />
|
||||
<DropdownMenuWithIcons />
|
||||
<DropdownMenuWithShortcuts />
|
||||
<DropdownMenuWithSubmenu />
|
||||
<DropdownMenuWithCheckboxes />
|
||||
<DropdownMenuWithCheckboxesIcons />
|
||||
<DropdownMenuWithRadio />
|
||||
<DropdownMenuWithRadioIcons />
|
||||
<DropdownMenuWithDestructive />
|
||||
<DropdownMenuWithAvatar />
|
||||
<DropdownMenuInDialog />
|
||||
<DropdownMenuWithInset />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>GitHub</DropdownMenuItem>
|
||||
<DropdownMenuItem disabled>API</DropdownMenuItem>
|
||||
<DropdownMenuItem>Support</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithShortcuts() {
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Shortcuts
|
||||
<DropdownMenuShortcut>⌘K</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithSubmenu() {
|
||||
return (
|
||||
<Example title="With Submenu">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Email</DropdownMenuItem>
|
||||
<DropdownMenuItem>Message</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>More...</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuItem>
|
||||
New Team
|
||||
<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithCheckboxes() {
|
||||
const [showStatusBar, setShowStatusBar] = React.useState(true)
|
||||
const [showActivityBar, setShowActivityBar] = React.useState(false)
|
||||
const [showPanel, setShowPanel] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Checkboxes">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Checkboxes
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="min-w-40">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={showStatusBar}
|
||||
onCheckedChange={setShowStatusBar}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Status Bar
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={showActivityBar}
|
||||
onCheckedChange={setShowActivityBar}
|
||||
disabled
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ActivityIcon"
|
||||
tabler="IconActivity"
|
||||
hugeicons="ActivityIcon"
|
||||
phosphor="ActivityIcon"
|
||||
remixicon="RiPulseLine"
|
||||
/>
|
||||
Activity Bar
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={showPanel}
|
||||
onCheckedChange={setShowPanel}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="PanelLeftIcon"
|
||||
tabler="IconLayoutSidebar"
|
||||
hugeicons="LayoutLeftIcon"
|
||||
phosphor="SidebarIcon"
|
||||
remixicon="RiSideBarLine"
|
||||
/>
|
||||
Panel
|
||||
</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithRadio() {
|
||||
const [position, setPosition] = React.useState("bottom")
|
||||
|
||||
return (
|
||||
<Example title="With Radio Group">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Radio Group
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Panel Position</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup
|
||||
value={position}
|
||||
onValueChange={setPosition}
|
||||
>
|
||||
<DropdownMenuRadioItem value="top">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUp01Icon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
Top
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="bottom">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowDownIcon"
|
||||
tabler="IconArrowDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="ArrowDownIcon"
|
||||
remixicon="RiArrowDownLine"
|
||||
/>
|
||||
Bottom
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="right" disabled>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
Right
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithCheckboxesIcons() {
|
||||
const [notifications, setNotifications] = React.useState({
|
||||
email: true,
|
||||
sms: false,
|
||||
push: true,
|
||||
})
|
||||
|
||||
return (
|
||||
<Example title="Checkboxes with Icons">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Notifications
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="min-w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Notification Preferences</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.email}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({ ...notifications, email: checked === true })
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email notifications
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.sms}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({ ...notifications, sms: checked === true })
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="MessageSquareIcon"
|
||||
tabler="IconMessage"
|
||||
hugeicons="MessageIcon"
|
||||
phosphor="ChatCircleIcon"
|
||||
remixicon="RiChat1Line"
|
||||
/>
|
||||
SMS notifications
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={notifications.push}
|
||||
onCheckedChange={(checked) =>
|
||||
setNotifications({ ...notifications, push: checked === true })
|
||||
}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Push notifications
|
||||
</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithRadioIcons() {
|
||||
const [paymentMethod, setPaymentMethod] = React.useState("card")
|
||||
|
||||
return (
|
||||
<Example title="Radio with Icons">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">Payment Method</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="min-w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Select Payment Method</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup
|
||||
value={paymentMethod}
|
||||
onValueChange={setPaymentMethod}
|
||||
>
|
||||
<DropdownMenuRadioItem value="card">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Credit Card
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="paypal">
|
||||
<IconPlaceholder
|
||||
lucide="WalletIcon"
|
||||
tabler="IconWallet"
|
||||
hugeicons="WalletIcon"
|
||||
phosphor="WalletIcon"
|
||||
remixicon="RiWalletLine"
|
||||
/>
|
||||
PayPal
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem value="bank">
|
||||
<IconPlaceholder
|
||||
lucide="Building2Icon"
|
||||
tabler="IconBuildingBank"
|
||||
hugeicons="BankIcon"
|
||||
phosphor="BankIcon"
|
||||
remixicon="RiBankLine"
|
||||
/>
|
||||
Bank Transfer
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithDestructive() {
|
||||
return (
|
||||
<Example title="With Destructive Items">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Actions
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PencilIcon"
|
||||
tabler="IconPencil"
|
||||
hugeicons="EditIcon"
|
||||
phosphor="PencilIcon"
|
||||
remixicon="RiPencilLine"
|
||||
/>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="ShareIcon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ArchiveIcon"
|
||||
tabler="IconArchive"
|
||||
hugeicons="Archive02Icon"
|
||||
phosphor="ArchiveIcon"
|
||||
remixicon="RiArchiveLine"
|
||||
/>
|
||||
Archive
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithAvatar() {
|
||||
const menuContent = (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheckIcon"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadgeIcon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
/>
|
||||
Account
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Notifications
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Avatar">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-12 justify-start px-2 md:max-w-[200px] style-sera:font-normal style-sera:tracking-normal style-sera:normal-case"
|
||||
>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="Shadcn" />
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-semibold">shadcn</span>
|
||||
<span className="truncate text-xs text-muted-foreground">
|
||||
shadcn@example.com
|
||||
</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-(--radix-dropdown-menu-trigger-width) min-w-56">
|
||||
{menuContent}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="rounded-full">
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="shadcn" />
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" side="top">
|
||||
{menuContent}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Dropdown Menu Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to see the dropdown menu.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open Menu
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>More Options</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Save Page...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Create Shortcut...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Name Window...</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Developer Tools</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithInset() {
|
||||
const [showBookmarks, setShowBookmarks] = React.useState(true)
|
||||
const [showUrls, setShowUrls] = React.useState(false)
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Inset">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-44">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem inset>Paste</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel inset>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
inset
|
||||
checked={showBookmarks}
|
||||
onCheckedChange={setShowBookmarks}
|
||||
>
|
||||
Bookmarks
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
inset
|
||||
checked={showUrls}
|
||||
onCheckedChange={setShowUrls}
|
||||
>
|
||||
Full URLs
|
||||
</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel inset>Theme</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
|
||||
<DropdownMenuRadioItem inset value="light">
|
||||
Light
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem inset value="dark">
|
||||
Dark
|
||||
</DropdownMenuRadioItem>
|
||||
<DropdownMenuRadioItem inset value="system">
|
||||
System
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger inset>More Options</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Save Page...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Create Shortcut...</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuComplex() {
|
||||
const [showSidebar, setShowSidebar] = React.useState(true)
|
||||
const [showStatusBar, setShowStatusBar] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Complex">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Complex Menu
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>View</DropdownMenuLabel>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={showSidebar}
|
||||
onCheckedChange={setShowSidebar}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="PanelLeftIcon"
|
||||
tabler="IconLayoutSidebar"
|
||||
hugeicons="LayoutLeftIcon"
|
||||
phosphor="SidebarIcon"
|
||||
remixicon="RiSideBarLine"
|
||||
/>
|
||||
Sidebar
|
||||
</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem
|
||||
checked={showStatusBar}
|
||||
onCheckedChange={setShowStatusBar}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Status Bar
|
||||
</DropdownMenuCheckboxItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="UsersIcon"
|
||||
tabler="IconUsers"
|
||||
hugeicons="UserGroupIcon"
|
||||
phosphor="UsersIcon"
|
||||
remixicon="RiTeamLine"
|
||||
/>
|
||||
Invite Users
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="MessageSquareIcon"
|
||||
tabler="IconMessage"
|
||||
hugeicons="MessageIcon"
|
||||
phosphor="ChatCircleIcon"
|
||||
remixicon="RiChat1Line"
|
||||
/>
|
||||
Message
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PlusCircleIcon"
|
||||
tabler="IconCirclePlus"
|
||||
hugeicons="AddCircleIcon"
|
||||
phosphor="PlusCircleIcon"
|
||||
remixicon="RiAddCircleLine"
|
||||
/>
|
||||
More...
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
Support
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
254
apps/v4/registry/bases/radix/examples/empty-example.tsx
Normal file
254
apps/v4/registry/bases/radix/examples/empty-example.tsx
Normal file
@@ -0,0 +1,254 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Kbd } from "@/registry/bases/radix/ui/kbd"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function EmptyExample() {
|
||||
return (
|
||||
<ExampleWrapper className="grid-cols-1!">
|
||||
<EmptyBasic />
|
||||
<EmptyWithMutedBackground />
|
||||
<EmptyWithBorder />
|
||||
<EmptyWithIcon />
|
||||
<EmptyWithMutedBackgroundAlt />
|
||||
<EmptyInCard />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild>
|
||||
<a href="#">Create project</a>
|
||||
</Button>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<Button variant="link" asChild className="text-muted-foreground">
|
||||
<a href="#">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</a>
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithMutedBackground() {
|
||||
return (
|
||||
<Example title="With Muted Background">
|
||||
<Empty className="bg-muted">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>No results found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
No results found for your search. Try adjusting your search terms.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>Try again</Button>
|
||||
<Button variant="link" asChild className="text-muted-foreground">
|
||||
<a href="#">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</a>
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithBorder() {
|
||||
return (
|
||||
<Example title="With Border">
|
||||
<Empty className="border">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>404 - Not Found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The page you're looking for doesn't exist. Try searching
|
||||
for what you need below.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<InputGroup className="w-3/4">
|
||||
<InputGroupInput placeholder="Try searching for pages..." />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>/</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<EmptyDescription>
|
||||
Need help? <a href="#">Contact support</a>
|
||||
</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<Empty className="border">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Nothing to see here</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
No posts have been created yet. Get started by{" "}
|
||||
<a href="#">creating your first post</a>.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
New Post
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithMutedBackgroundAlt() {
|
||||
return (
|
||||
<Example title="With Muted Background Alt">
|
||||
<Empty className="bg-muted/50">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>404 - Not Found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The page you're looking for doesn't exist. Try searching
|
||||
for what you need below.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<InputGroup className="w-3/4">
|
||||
<InputGroupInput placeholder="Try searching for pages..." />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>/</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<EmptyDescription>
|
||||
Need help? <a href="#">Contact support</a>
|
||||
</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild>
|
||||
<a href="#">Create project</a>
|
||||
</Button>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<Button variant="link" asChild className="text-muted-foreground">
|
||||
<a href="#">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</a>
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
969
apps/v4/registry/bases/radix/examples/field-example.tsx
Normal file
969
apps/v4/registry/bases/radix/examples/field-example.tsx
Normal file
@@ -0,0 +1,969 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { REGEXP_ONLY_DIGITS } from "input-otp"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
InputOTP,
|
||||
InputOTPGroup,
|
||||
InputOTPSeparator,
|
||||
InputOTPSlot,
|
||||
} from "@/registry/bases/radix/ui/input-otp"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOptGroup,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/radix/ui/radio-group"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
|
||||
export default function FieldExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputFields />
|
||||
<TextareaFields />
|
||||
<SelectFields />
|
||||
<CheckboxFields />
|
||||
<RadioFields />
|
||||
<SwitchFields />
|
||||
<SliderFields />
|
||||
<NativeSelectFields />
|
||||
<InputOTPFields />
|
||||
<HorizontalFields />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputFields() {
|
||||
return (
|
||||
<Example title="Input Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-basic">Basic Input</FieldLabel>
|
||||
<Input id="input-basic" placeholder="Enter text" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-with-desc">
|
||||
Input with Description
|
||||
</FieldLabel>
|
||||
<Input id="input-with-desc" placeholder="Enter your username" />
|
||||
<FieldDescription>
|
||||
Choose a unique username for your account.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-desc-first">Email Address</FieldLabel>
|
||||
<FieldDescription>
|
||||
We'll never share your email with anyone.
|
||||
</FieldDescription>
|
||||
<Input
|
||||
id="input-desc-first"
|
||||
type="email"
|
||||
placeholder="email@example.com"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-required">
|
||||
Required Field <span className="text-destructive">*</span>
|
||||
</FieldLabel>
|
||||
<Input
|
||||
id="input-required"
|
||||
placeholder="This field is required"
|
||||
required
|
||||
/>
|
||||
<FieldDescription>This field must be filled out.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-disabled">Disabled Input</FieldLabel>
|
||||
<Input id="input-disabled" placeholder="Cannot edit" disabled />
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-badge">
|
||||
Input with Badge{" "}
|
||||
<Badge variant="secondary" className="ml-auto">
|
||||
Recommended
|
||||
</Badge>
|
||||
</FieldLabel>
|
||||
<Input id="input-badge" placeholder="Enter value" />
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="input-invalid">Invalid Input</FieldLabel>
|
||||
<Input
|
||||
id="input-invalid"
|
||||
placeholder="This field has an error"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="input-disabled-field">Disabled Field</FieldLabel>
|
||||
<Input id="input-disabled-field" placeholder="Cannot edit" disabled />
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaFields() {
|
||||
return (
|
||||
<Example title="Textarea Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-basic">Basic Textarea</FieldLabel>
|
||||
<Textarea id="textarea-basic" placeholder="Enter your message" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-comments">Comments</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-comments"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[100px]"
|
||||
/>
|
||||
<FieldDescription>Maximum 500 characters allowed.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-bio">Bio</FieldLabel>
|
||||
<FieldDescription>
|
||||
Tell us about yourself in a few sentences.
|
||||
</FieldDescription>
|
||||
<Textarea
|
||||
id="textarea-bio"
|
||||
placeholder="I am a..."
|
||||
className="min-h-[120px]"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-desc-after">Message</FieldLabel>
|
||||
<Textarea id="textarea-desc-after" placeholder="Enter your message" />
|
||||
<FieldDescription>
|
||||
Enter your message so it is long enough to test the layout.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="textarea-invalid">Invalid Textarea</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-invalid"
|
||||
placeholder="This field has an error"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="textarea-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-disabled-field"
|
||||
placeholder="Cannot edit"
|
||||
disabled
|
||||
/>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectFields() {
|
||||
return (
|
||||
<Example title="Select Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-basic">Basic Select</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="select-basic">
|
||||
<SelectValue placeholder="Choose an option" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="option1">Option 1</SelectItem>
|
||||
<SelectItem value="option2">Option 2</SelectItem>
|
||||
<SelectItem value="option3">Option 3</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-country">Country</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="select-country">
|
||||
<SelectValue placeholder="Select your country" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="us">United States</SelectItem>
|
||||
<SelectItem value="uk">United Kingdom</SelectItem>
|
||||
<SelectItem value="ca">Canada</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
Select the country where you currently reside.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-timezone">Timezone</FieldLabel>
|
||||
<FieldDescription>
|
||||
Choose your local timezone for accurate scheduling.
|
||||
</FieldDescription>
|
||||
<Select>
|
||||
<SelectTrigger id="select-timezone">
|
||||
<SelectValue placeholder="Select timezone" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="utc">UTC</SelectItem>
|
||||
<SelectItem value="est">Eastern Time</SelectItem>
|
||||
<SelectItem value="pst">Pacific Time</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="select-invalid">Invalid Select</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="select-invalid" aria-invalid>
|
||||
<SelectValue placeholder="This field has an error" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="option1">Option 1</SelectItem>
|
||||
<SelectItem value="option2">Option 2</SelectItem>
|
||||
<SelectItem value="option3">Option 3</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="select-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<Select disabled>
|
||||
<SelectTrigger id="select-disabled-field">
|
||||
<SelectValue placeholder="Cannot select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="option1">Option 1</SelectItem>
|
||||
<SelectItem value="option2">Option 2</SelectItem>
|
||||
<SelectItem value="option3">Option 3</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectFields() {
|
||||
return (
|
||||
<Example title="Native Select Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-basic">
|
||||
Basic Native Select
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-basic">
|
||||
<NativeSelectOption value="">Choose an option</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-country">Country</FieldLabel>
|
||||
<NativeSelect id="native-select-country">
|
||||
<NativeSelectOption value="">
|
||||
Select your country
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
Select the country where you currently reside.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-timezone">Timezone</FieldLabel>
|
||||
<FieldDescription>
|
||||
Choose your local timezone for accurate scheduling.
|
||||
</FieldDescription>
|
||||
<NativeSelect id="native-select-timezone">
|
||||
<NativeSelectOption value="">Select timezone</NativeSelectOption>
|
||||
<NativeSelectOption value="utc">UTC</NativeSelectOption>
|
||||
<NativeSelectOption value="est">Eastern Time</NativeSelectOption>
|
||||
<NativeSelectOption value="pst">Pacific Time</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-grouped">
|
||||
Grouped Options
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-grouped">
|
||||
<NativeSelectOption value="">Select a region</NativeSelectOption>
|
||||
<NativeSelectOptGroup label="North America">
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
<NativeSelectOption value="mx">Mexico</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
<NativeSelectOptGroup label="Europe">
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="fr">France</NativeSelectOption>
|
||||
<NativeSelectOption value="de">Germany</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
Native select with grouped options using optgroup.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="native-select-invalid">
|
||||
Invalid Native Select
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-invalid" aria-invalid>
|
||||
<NativeSelectOption value="">
|
||||
This field has an error
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="native-select-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-disabled-field" disabled>
|
||||
<NativeSelectOption value="">Cannot select</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxFields() {
|
||||
return (
|
||||
<Example title="Checkbox Fields">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-basic" defaultChecked />
|
||||
<FieldLabel htmlFor="checkbox-basic">
|
||||
I agree to the terms and conditions
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="checkbox-right">
|
||||
Accept terms and conditions
|
||||
</FieldLabel>
|
||||
<Checkbox id="checkbox-right" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-with-desc" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="checkbox-with-desc">
|
||||
Subscribe to newsletter
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive weekly updates about new features and promotions.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<FieldLabel htmlFor="checkbox-with-title">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-with-title" />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable Touch ID</FieldTitle>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Preferences</FieldLegend>
|
||||
<FieldDescription>
|
||||
Select all that apply to customize your experience.
|
||||
</FieldDescription>
|
||||
<FieldGroup className="gap-3">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-dark" />
|
||||
<FieldLabel htmlFor="pref-dark">Dark mode</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-compact" />
|
||||
<FieldLabel htmlFor="pref-compact">Compact view</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-notifications" />
|
||||
<FieldLabel htmlFor="pref-notifications">
|
||||
Enable notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<Checkbox id="checkbox-invalid" aria-invalid />
|
||||
<FieldLabel htmlFor="checkbox-invalid">Invalid checkbox</FieldLabel>
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<Checkbox id="checkbox-disabled-field" disabled />
|
||||
<FieldLabel htmlFor="checkbox-disabled-field">
|
||||
Disabled checkbox
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioFields() {
|
||||
return (
|
||||
<Example title="Radio Fields">
|
||||
<FieldGroup>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Subscription Plan</FieldLegend>
|
||||
<RadioGroup defaultValue="free">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="free" id="radio-free" />
|
||||
<FieldLabel htmlFor="radio-free">Free Plan</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="pro" id="radio-pro" />
|
||||
<FieldLabel htmlFor="radio-pro">Pro Plan</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="enterprise" id="radio-enterprise" />
|
||||
<FieldLabel htmlFor="radio-enterprise">Enterprise</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Battery Level</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose your preferred battery level.
|
||||
</FieldDescription>
|
||||
<RadioGroup>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="high" id="battery-high" />
|
||||
<FieldLabel htmlFor="battery-high">High</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="battery-medium" />
|
||||
<FieldLabel htmlFor="battery-medium">Medium</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="low" id="battery-low" />
|
||||
<FieldLabel htmlFor="battery-low">Low</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<RadioGroup className="gap-6">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option1" id="radio-content-1" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="radio-content-1">Enable Touch ID</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
<RadioGroup className="gap-3">
|
||||
<FieldLabel htmlFor="radio-title-1">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="title1" id="radio-title-1" />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable Touch ID</FieldTitle>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Invalid Radio Group</FieldLegend>
|
||||
<RadioGroup>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<RadioGroupItem
|
||||
value="invalid1"
|
||||
id="radio-invalid-1"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldLabel htmlFor="radio-invalid-1">
|
||||
Invalid Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<RadioGroupItem
|
||||
value="invalid2"
|
||||
id="radio-invalid-2"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldLabel htmlFor="radio-invalid-2">
|
||||
Invalid Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Disabled Radio Group</FieldLegend>
|
||||
<RadioGroup disabled>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<RadioGroupItem
|
||||
value="disabled1"
|
||||
id="radio-disabled-1"
|
||||
disabled
|
||||
/>
|
||||
<FieldLabel htmlFor="radio-disabled-1">
|
||||
Disabled Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<RadioGroupItem
|
||||
value="disabled2"
|
||||
id="radio-disabled-2"
|
||||
disabled
|
||||
/>
|
||||
<FieldLabel htmlFor="radio-disabled-2">
|
||||
Disabled Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchFields() {
|
||||
return (
|
||||
<Example title="Switch Fields">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-airplane">Airplane Mode</FieldLabel>
|
||||
<FieldDescription>
|
||||
Turn on airplane mode to disable all connections.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-airplane" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="switch-dark">Dark Mode</FieldLabel>
|
||||
<Switch id="switch-dark" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-marketing" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-marketing">Marketing Emails</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive emails about new products, features, and more.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Privacy Settings</FieldLabel>
|
||||
<FieldDescription>Manage your privacy preferences.</FieldDescription>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-profile" defaultChecked />
|
||||
<FieldLabel htmlFor="switch-profile">
|
||||
Make profile visible to others
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-email" />
|
||||
<FieldLabel htmlFor="switch-email">
|
||||
Show email on profile
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</Field>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-invalid">Invalid Switch</FieldLabel>
|
||||
<FieldDescription>
|
||||
This switch has validation errors.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-invalid" aria-invalid />
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-disabled-field">
|
||||
Disabled Switch
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
This switch is currently disabled.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-disabled-field" disabled />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderFields() {
|
||||
const [volume, setVolume] = useState([50])
|
||||
const [brightness, setBrightness] = useState([75])
|
||||
const [temperature, setTemperature] = useState([0.3, 0.7])
|
||||
const [priceRange, setPriceRange] = useState([25, 75])
|
||||
const [colorBalance, setColorBalance] = useState([10, 20, 70])
|
||||
|
||||
return (
|
||||
<Example title="Slider Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-volume">Volume</FieldLabel>
|
||||
<Slider
|
||||
id="slider-volume"
|
||||
value={volume}
|
||||
onValueChange={setVolume}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-brightness">Screen Brightness</FieldLabel>
|
||||
<Slider
|
||||
id="slider-brightness"
|
||||
value={brightness}
|
||||
onValueChange={setBrightness}
|
||||
max={100}
|
||||
step={5}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Current brightness: {brightness[0]}%
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-quality">Video Quality</FieldLabel>
|
||||
<FieldDescription>
|
||||
Higher quality uses more bandwidth.
|
||||
</FieldDescription>
|
||||
<Slider
|
||||
id="slider-quality"
|
||||
defaultValue={[720]}
|
||||
max={1080}
|
||||
min={360}
|
||||
step={360}
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-temperature">
|
||||
Temperature Range
|
||||
</FieldLabel>
|
||||
<Slider
|
||||
id="slider-temperature"
|
||||
value={temperature}
|
||||
onValueChange={setTemperature}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Range: {temperature[0].toFixed(1)} - {temperature[1].toFixed(1)}
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-price-range">Price Range</FieldLabel>
|
||||
<Slider
|
||||
id="slider-price-range"
|
||||
value={priceRange}
|
||||
onValueChange={setPriceRange}
|
||||
max={100}
|
||||
step={5}
|
||||
/>
|
||||
<FieldDescription>
|
||||
${priceRange[0]} - ${priceRange[1]}
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-color-balance">Color Balance</FieldLabel>
|
||||
<Slider
|
||||
id="slider-color-balance"
|
||||
value={colorBalance}
|
||||
onValueChange={setColorBalance}
|
||||
max={100}
|
||||
step={10}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Red: {colorBalance[0]}%, Green: {colorBalance[1]}%, Blue:{" "}
|
||||
{colorBalance[2]}%
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="slider-invalid">Invalid Slider</FieldLabel>
|
||||
<Slider
|
||||
id="slider-invalid"
|
||||
defaultValue={[30]}
|
||||
max={100}
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This slider has validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="slider-disabled-field">
|
||||
Disabled Slider
|
||||
</FieldLabel>
|
||||
<Slider
|
||||
id="slider-disabled-field"
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
disabled
|
||||
/>
|
||||
<FieldDescription>
|
||||
This slider is currently disabled.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPFields() {
|
||||
const [value, setValue] = useState("")
|
||||
const [pinValue, setPinValue] = useState("")
|
||||
|
||||
return (
|
||||
<Example title="OTP Input Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-basic">Verification Code</FieldLabel>
|
||||
<InputOTP id="otp-basic" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-with-desc">Enter OTP</FieldLabel>
|
||||
<InputOTP
|
||||
id="otp-with-desc"
|
||||
maxLength={6}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter the 6-digit code sent to your email.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-separator">
|
||||
Two-Factor Authentication
|
||||
</FieldLabel>
|
||||
<InputOTP id="otp-separator" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter the code from your authenticator app.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-pin">PIN Code</FieldLabel>
|
||||
<InputOTP
|
||||
id="otp-pin"
|
||||
maxLength={4}
|
||||
pattern={REGEXP_ONLY_DIGITS}
|
||||
value={pinValue}
|
||||
onChange={setPinValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter your 4-digit PIN (numbers only).
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="otp-invalid">Invalid OTP</FieldLabel>
|
||||
<InputOTP id="otp-invalid" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} aria-invalid />
|
||||
<InputOTPSlot index={1} aria-invalid />
|
||||
<InputOTPSlot index={2} aria-invalid />
|
||||
<InputOTPSlot index={3} aria-invalid />
|
||||
<InputOTPSlot index={4} aria-invalid />
|
||||
<InputOTPSlot index={5} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
This OTP field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="otp-disabled-field">Disabled OTP</FieldLabel>
|
||||
<InputOTP id="otp-disabled-field" maxLength={6} disabled>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
This OTP field is currently disabled.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function HorizontalFields() {
|
||||
return (
|
||||
<Example title="Horizontal Fields">
|
||||
<FieldGroup className="**:data-[slot=field-content]:min-w-48">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-input">Username</FieldLabel>
|
||||
<FieldDescription>Enter your preferred username.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Input id="horizontal-input" placeholder="johndoe" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-textarea">Bio</FieldLabel>
|
||||
<FieldDescription>
|
||||
Write a short description about yourself.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Textarea
|
||||
id="horizontal-textarea"
|
||||
placeholder="Tell us about yourself..."
|
||||
/>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-switch">
|
||||
Email Notifications
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive email updates about your account.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="horizontal-switch" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-select">Favorite Fruit</FieldLabel>
|
||||
<FieldDescription>Choose your favorite fruit.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Select>
|
||||
<SelectTrigger id="horizontal-select">
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="orange">Orange</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-native-select">Country</FieldLabel>
|
||||
<FieldDescription>Select your country.</FieldDescription>
|
||||
</FieldContent>
|
||||
<NativeSelect id="horizontal-native-select">
|
||||
<NativeSelectOption value="">Select a country</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-slider">Volume</FieldLabel>
|
||||
<FieldDescription>Adjust the volume level.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Slider id="horizontal-slider" defaultValue={[50]} max={100} />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
98
apps/v4/registry/bases/radix/examples/hover-card-example.tsx
Normal file
98
apps/v4/registry/bases/radix/examples/hover-card-example.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from "@/registry/bases/radix/ui/hover-card"
|
||||
|
||||
export default function HoverCardExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<HoverCardSides />
|
||||
<HoverCardInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const HOVER_CARD_SIDES = ["top", "right", "bottom", "left"] as const
|
||||
|
||||
function HoverCardSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
{HOVER_CARD_SIDES.map((side) => (
|
||||
<HoverCard key={side} openDelay={100} closeDelay={100}>
|
||||
<HoverCardTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="capitalize style-sera:uppercase"
|
||||
>
|
||||
{side}
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent side={side} className="w-64">
|
||||
<div className="flex flex-col style-vega:gap-2 style-nova:gap-1.5 style-lyra:gap-1 style-maia:gap-2 style-mira:gap-1 style-luma:gap-2 style-sera:gap-2">
|
||||
<h4 className="font-medium style-sera:font-heading style-sera:font-semibold style-sera:tracking-wide">
|
||||
Hover Card
|
||||
</h4>
|
||||
<p className="style-sera:leading-relaxed">
|
||||
This hover card appears on the {side} side of the trigger.
|
||||
</p>
|
||||
</div>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function HoverCardInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Hover Card Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Hover over the button below to see the hover card.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<HoverCard openDelay={100} closeDelay={100}>
|
||||
<HoverCardTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Hover me
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent className="w-64">
|
||||
<div className="flex flex-col style-vega:gap-2 style-nova:gap-1.5 style-lyra:gap-1 style-maia:gap-2 style-mira:gap-1 style-luma:gap-2 style-sera:gap-2">
|
||||
<h4 className="font-medium style-sera:font-heading style-sera:font-semibold style-sera:tracking-wide">
|
||||
Hover Card
|
||||
</h4>
|
||||
<p className="style-sera:leading-relaxed">
|
||||
This hover card appears inside a dialog. Hover over the button
|
||||
to see it.
|
||||
</p>
|
||||
</div>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
268
apps/v4/registry/bases/radix/examples/input-example.tsx
Normal file
268
apps/v4/registry/bases/radix/examples/input-example.tsx
Normal file
@@ -0,0 +1,268 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
|
||||
export default function InputExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputBasic />
|
||||
<InputInvalid />
|
||||
<InputWithLabel />
|
||||
<InputWithDescription />
|
||||
<InputDisabled />
|
||||
<InputTypes />
|
||||
<InputWithSelect />
|
||||
<InputWithButton />
|
||||
<InputWithNativeSelect />
|
||||
<InputForm />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Input type="email" placeholder="Email" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Input type="text" placeholder="Error" aria-invalid="true" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-email">Email</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-email"
|
||||
type="email"
|
||||
placeholder="name@example.com"
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-username">Username</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-username"
|
||||
type="text"
|
||||
placeholder="Enter your username"
|
||||
/>
|
||||
<FieldDescription>
|
||||
Choose a unique username for your account.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-disabled">Email</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-disabled"
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
disabled
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputTypes() {
|
||||
return (
|
||||
<Example title="Input Types">
|
||||
<div className="flex w-full flex-col gap-6">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-password">Password</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-tel">Phone</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-tel"
|
||||
type="tel"
|
||||
placeholder="+1 (555) 123-4567"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-url">URL</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-url"
|
||||
type="url"
|
||||
placeholder="https://example.com"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-search">Search</FieldLabel>
|
||||
<Input id="input-demo-search" type="search" placeholder="Search" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-number">Number</FieldLabel>
|
||||
<Input id="input-demo-number" type="number" placeholder="123" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-date">Date</FieldLabel>
|
||||
<Input id="input-demo-date" type="date" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-time">Time</FieldLabel>
|
||||
<Input id="input-demo-time" type="time" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-file">File</FieldLabel>
|
||||
<Input id="input-demo-file" type="file" />
|
||||
</Field>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithSelect() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="text" placeholder="Enter amount" className="flex-1" />
|
||||
<Select defaultValue="usd">
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="usd">USD</SelectItem>
|
||||
<SelectItem value="eur">EUR</SelectItem>
|
||||
<SelectItem value="gbp">GBP</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithButton() {
|
||||
return (
|
||||
<Example title="With Button">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="search" placeholder="Search..." className="flex-1" />
|
||||
<Button>Search</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithNativeSelect() {
|
||||
return (
|
||||
<Example title="With Native Select">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="tel" placeholder="(555) 123-4567" className="flex-1" />
|
||||
<NativeSelect defaultValue="+1">
|
||||
<NativeSelectOption value="+1">+1</NativeSelectOption>
|
||||
<NativeSelectOption value="+44">+44</NativeSelectOption>
|
||||
<NativeSelectOption value="+46">+46</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<form className="w-full">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-name">Name</FieldLabel>
|
||||
<Input id="form-name" type="text" placeholder="John Doe" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-email">Email</FieldLabel>
|
||||
<Input
|
||||
id="form-email"
|
||||
type="email"
|
||||
placeholder="john@example.com"
|
||||
/>
|
||||
<FieldDescription>
|
||||
We'll never share your email with anyone.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-phone">Phone</FieldLabel>
|
||||
<Input
|
||||
id="form-phone"
|
||||
type="tel"
|
||||
placeholder="+1 (555) 123-4567"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-country">Country</FieldLabel>
|
||||
<Select defaultValue="us">
|
||||
<SelectTrigger id="form-country">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="us">United States</SelectItem>
|
||||
<SelectItem value="uk">United Kingdom</SelectItem>
|
||||
<SelectItem value="ca">Canada</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-address">Address</FieldLabel>
|
||||
<Input id="form-address" type="text" placeholder="123 Main St" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Button type="button" variant="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">Submit</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
887
apps/v4/registry/bases/radix/examples/input-group-example.tsx
Normal file
887
apps/v4/registry/bases/radix/examples/input-group-example.tsx
Normal file
@@ -0,0 +1,887 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
ButtonGroup,
|
||||
ButtonGroupText,
|
||||
} from "@/registry/bases/radix/ui/button-group"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
InputGroupTextarea,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Kbd, KbdGroup } from "@/registry/bases/radix/ui/kbd"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverDescription,
|
||||
PopoverHeader,
|
||||
PopoverTitle,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/bases/radix/ui/popover"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/registry/bases/radix/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function InputGroupExample() {
|
||||
const [country, setCountry] = useState("+1")
|
||||
|
||||
return (
|
||||
<ExampleWrapper className="min-w-0">
|
||||
<InputGroupBasic />
|
||||
<InputGroupWithAddons />
|
||||
<InputGroupWithButtons />
|
||||
<InputGroupWithTooltip country={country} setCountry={setCountry} />
|
||||
<InputGroupWithKbd />
|
||||
<InputGroupInCard />
|
||||
<InputGroupTextareaExamples />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-default-01">
|
||||
Default (No Input Group)
|
||||
</FieldLabel>
|
||||
<Input placeholder="Placeholder" id="input-default-01" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-02">Input Group</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-02" placeholder="Placeholder" />
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="input-disabled-03">Disabled</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-disabled-03"
|
||||
placeholder="This field is disabled"
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field data-invalid="true">
|
||||
<FieldLabel htmlFor="input-invalid-04">Invalid</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-invalid-04"
|
||||
placeholder="This field is invalid"
|
||||
aria-invalid="true"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithAddons() {
|
||||
return (
|
||||
<Example title="With Addons">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-left-05">
|
||||
Addon (inline-start)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-left-05" />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-right-07">
|
||||
Addon (inline-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-right-07" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="EyeOffIcon"
|
||||
tabler="IconEyeClosed"
|
||||
hugeicons="ViewOffIcon"
|
||||
phosphor="EyeSlashIcon"
|
||||
remixicon="RiEyeOffLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-both-09">
|
||||
Addon (inline-start and inline-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-both-09" />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="MicIcon"
|
||||
tabler="IconMicrophone"
|
||||
hugeicons="VoiceIcon"
|
||||
phosphor="MicrophoneIcon"
|
||||
remixicon="RiMicLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="RadioIcon"
|
||||
tabler="IconPlayerRecordFilled"
|
||||
hugeicons="RecordIcon"
|
||||
phosphor="RecordIcon"
|
||||
remixicon="RiRecordCircleLine"
|
||||
className="animate-pulse text-red-500"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-addon-20">Addon (block-start)</FieldLabel>
|
||||
<InputGroup className="h-auto">
|
||||
<InputGroupInput id="input-addon-20" />
|
||||
<InputGroupAddon align="block-start">
|
||||
<InputGroupText>First Name</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-addon-21">Addon (block-end)</FieldLabel>
|
||||
<InputGroup className="h-auto">
|
||||
<InputGroupInput id="input-addon-21" />
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>20/240 characters</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-both-10">Multiple Icons</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-both-10" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
/>
|
||||
<InputGroupButton
|
||||
size="icon-xs"
|
||||
onClick={() => toast("Copied to clipboard")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="RadioIcon"
|
||||
tabler="IconPlayerRecordFilled"
|
||||
hugeicons="RecordIcon"
|
||||
phosphor="RecordIcon"
|
||||
remixicon="RiRecordCircleLine"
|
||||
className="animate-pulse text-red-500"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-description-10">Description</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-description-10" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-label-10">Label</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<FieldLabel htmlFor="input-label-10">Label</FieldLabel>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="input-label-10" />
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-optional-12" aria-label="Optional" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupText>(optional)</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithButtons() {
|
||||
return (
|
||||
<Example title="With Buttons">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-button-13">Button</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-13" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton>Default</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-14" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="outline">Outline</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-15" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="secondary">Secondary</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-16" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton variant="secondary">Button</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-17" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-18" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton variant="secondary" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithTooltip({
|
||||
country,
|
||||
setCountry,
|
||||
}: {
|
||||
country: string
|
||||
setCountry: (value: string) => void
|
||||
}) {
|
||||
return (
|
||||
<Example title="With Tooltip, Dropdown, Popover">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-tooltip-20">Tooltip</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-tooltip-20" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<InputGroupButton className="rounded-full" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>This is content in a tooltip.</TooltipContent>
|
||||
</Tooltip>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-dropdown-21">Dropdown</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-dropdown-21" />
|
||||
<InputGroupAddon>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<InputGroupButton className="text-muted-foreground tabular-nums">
|
||||
{country}{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="start"
|
||||
className="min-w-16"
|
||||
sideOffset={10}
|
||||
alignOffset={-8}
|
||||
>
|
||||
<DropdownMenuItem onClick={() => setCountry("+1")}>
|
||||
+1
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setCountry("+44")}>
|
||||
+44
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setCountry("+46")}>
|
||||
+46
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-secure-19">Popover</FieldLabel>
|
||||
<InputGroup>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="secondary" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Your connection is not secure.</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
You should not enter any sensitive information on this site.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<InputGroupAddon className="pl-1 text-muted-foreground">
|
||||
https://
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="input-secure-19" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton
|
||||
size="icon-xs"
|
||||
onClick={() => toast("Added to favorites")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithKbd() {
|
||||
return (
|
||||
<Example title="With Kbd">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-kbd-22">Input Group with Kbd</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-kbd-22" />
|
||||
<InputGroupAddon>
|
||||
<Kbd>⌘K</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-kbd-23" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>⌘K</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-apps-24"
|
||||
placeholder="Search for Apps..."
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">Ask AI</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>Tab</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-type-25"
|
||||
placeholder="Type to search..."
|
||||
/>
|
||||
<InputGroupAddon align="inline-start">
|
||||
<IconPlaceholder
|
||||
lucide="SparklesIcon"
|
||||
tabler="IconServerSpark"
|
||||
hugeicons="SparklesIcon"
|
||||
phosphor="SparkleIcon"
|
||||
remixicon="RiSparklingLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<KbdGroup>
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>C</Kbd>
|
||||
</KbdGroup>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-username-26">Username</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-username-26" defaultValue="shadcn" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<div className="flex size-4 items-center justify-center rounded-full bg-green-500 dark:bg-green-800">
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
className="size-3 text-white"
|
||||
/>
|
||||
</div>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription className="text-green-700">
|
||||
This username is available.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-docs-27"
|
||||
placeholder="Search documentation..."
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">12 results</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup data-disabled="true">
|
||||
<InputGroupInput
|
||||
id="input-search-disabled-28"
|
||||
placeholder="Search documentation..."
|
||||
disabled
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">Disabled</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldGroup className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-11">First Name</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-11" placeholder="First Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-12">Last Name</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-12" placeholder="Last Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="input-group-29">
|
||||
Loading ("data-disabled="true")
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-group-29"
|
||||
disabled
|
||||
defaultValue="shadcn"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Spinner />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Card with Input Group</CardTitle>
|
||||
<CardDescription>This is a card with an input group.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="email-input">Email Address</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="email-input"
|
||||
type="email"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="website-input">Website URL</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<InputGroupText>https://</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="website-input" placeholder="example.com" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="ExternalLinkIcon"
|
||||
tabler="IconExternalLink"
|
||||
hugeicons="LinkSquare02Icon"
|
||||
phosphor="ArrowSquareOutIcon"
|
||||
remixicon="RiExternalLinkLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="feedback-textarea">
|
||||
Feedback & Comments
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="feedback-textarea"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[100px]"
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>0/500 characters</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-end gap-2">
|
||||
<Button variant="outline">Cancel</Button>
|
||||
<Button>Submit</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupTextareaExamples() {
|
||||
return (
|
||||
<Example title="Textarea">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-12">
|
||||
Default Textarea (No Input Group)
|
||||
</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-header-footer-12"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-13">
|
||||
Input Group
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-13"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid="true">
|
||||
<FieldLabel htmlFor="textarea-header-footer-14">Invalid</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-14"
|
||||
placeholder="Enter your text here..."
|
||||
aria-invalid="true"
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="textarea-header-footer-15">Disabled</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-15"
|
||||
placeholder="Enter your text here..."
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="prompt-31">Addon (block-start)</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea id="prompt-31" />
|
||||
<InputGroupAddon align="block-start">
|
||||
<InputGroupText>Ask, Search or Chat...</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-30">
|
||||
Addon (block-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-30"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>0/280 characters</InputGroupText>
|
||||
<InputGroupButton
|
||||
variant="default"
|
||||
size="icon-xs"
|
||||
className="ml-auto rounded-full"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUpIcon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
<span className="sr-only">Send</span>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-comment-31">Addon (Buttons)</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-comment-31"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[120px]"
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupButton variant="ghost" className="ml-auto" size="sm">
|
||||
Cancel
|
||||
</InputGroupButton>
|
||||
<InputGroupButton variant="default" size="sm">
|
||||
Post Comment
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-code-32">Code Editor</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-code-32"
|
||||
placeholder="console.log('Hello, world!');"
|
||||
className="min-h-[300px] py-3"
|
||||
/>
|
||||
<InputGroupAddon align="block-start" className="border-b">
|
||||
<InputGroupText className="font-mono font-medium">
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconBrandJavascript"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
script.js
|
||||
</InputGroupText>
|
||||
<InputGroupButton size="icon-xs" className="ml-auto">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCwIcon"
|
||||
tabler="IconRefresh"
|
||||
hugeicons="RefreshIcon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
<InputGroupButton size="icon-xs" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="block-end" className="border-t">
|
||||
<InputGroupText>Line 1, Column 1</InputGroupText>
|
||||
<InputGroupText className="ml-auto">JavaScript</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
292
apps/v4/registry/bases/radix/examples/input-otp-example.tsx
Normal file
292
apps/v4/registry/bases/radix/examples/input-otp-example.tsx
Normal file
@@ -0,0 +1,292 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputOTP,
|
||||
InputOTPGroup,
|
||||
InputOTPSeparator,
|
||||
InputOTPSlot,
|
||||
} from "@/registry/bases/radix/ui/input-otp"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function InputOTPExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputOTPForm />
|
||||
<InputOTPSimple />
|
||||
<InputOTPPattern />
|
||||
<InputOTPWithSeparator />
|
||||
<InputOTPAlphanumeric />
|
||||
<InputOTPDisabled />
|
||||
<InputOTPFourDigits />
|
||||
<InputOTPInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="simple">Simple</FieldLabel>
|
||||
<InputOTP id="simple" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPPattern() {
|
||||
return (
|
||||
<Example title="Digits Only">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="digits-only">Digits Only</FieldLabel>
|
||||
<InputOTP id="digits-only" maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPWithSeparator() {
|
||||
const [value, setValue] = React.useState("123456")
|
||||
|
||||
return (
|
||||
<Example title="With Separator">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="with-separator">With Separator</FieldLabel>
|
||||
<InputOTP
|
||||
id="with-separator"
|
||||
maxLength={6}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPAlphanumeric() {
|
||||
return (
|
||||
<Example title="Alphanumeric">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="alphanumeric">Alphanumeric</FieldLabel>
|
||||
<FieldDescription>Accepts both letters and numbers.</FieldDescription>
|
||||
<InputOTP
|
||||
id="alphanumeric"
|
||||
maxLength={6}
|
||||
pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="disabled">Disabled</FieldLabel>
|
||||
<InputOTP id="disabled" maxLength={6} disabled value="123456">
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPFourDigits() {
|
||||
return (
|
||||
<Example title="4 Digits">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="four-digits">4 Digits</FieldLabel>
|
||||
<FieldDescription>Common pattern for PIN codes.</FieldDescription>
|
||||
<InputOTP id="four-digits" maxLength={4} pattern={REGEXP_ONLY_DIGITS}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPInvalid() {
|
||||
const [value, setValue] = React.useState("000000")
|
||||
|
||||
return (
|
||||
<Example title="Invalid State">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="invalid">Invalid State</FieldLabel>
|
||||
<FieldDescription>
|
||||
Example showing the invalid error state.
|
||||
</FieldDescription>
|
||||
<InputOTP id="invalid" maxLength={6} value={value} onChange={setValue}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} aria-invalid />
|
||||
<InputOTPSlot index={1} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={2} aria-invalid />
|
||||
<InputOTPSlot index={3} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={4} aria-invalid />
|
||||
<InputOTPSlot index={5} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldError errors={[{ message: "Invalid code. Please try again." }]} />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<Card className="mx-auto max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle>Verify your login</CardTitle>
|
||||
<CardDescription>
|
||||
Enter the verification code we sent to your email address:{" "}
|
||||
<span className="font-medium">m@example.com</span>.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<Field>
|
||||
<div className="flex items-center justify-between">
|
||||
<FieldLabel htmlFor="otp-verification">
|
||||
Verification code
|
||||
</FieldLabel>
|
||||
<Button variant="outline" size="xs">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCwIcon"
|
||||
hugeicons="RefreshIcon"
|
||||
tabler="IconRefresh"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Resend Code
|
||||
</Button>
|
||||
</div>
|
||||
<InputOTP maxLength={6} id="otp-verification" required>
|
||||
<InputOTPGroup className="*:data-[slot=input-otp-slot]:text-xl style-vega:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-maia:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-mira:*:data-[slot=input-otp-slot]:w-11 style-luma:*:data-[slot=input-otp-slot]:h-16 style-luma:*:data-[slot=input-otp-slot]:w-12 style-sera:*:data-[slot=input-otp-slot]:h-14 style-sera:*:data-[slot=input-otp-slot]:w-10">
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup className="*:data-[slot=input-otp-slot]:text-xl style-vega:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-maia:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-mira:*:data-[slot=input-otp-slot]:w-11 style-luma:*:data-[slot=input-otp-slot]:h-16 style-luma:*:data-[slot=input-otp-slot]:w-12 style-sera:*:data-[slot=input-otp-slot]:h-14 style-sera:*:data-[slot=input-otp-slot]:w-10">
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
<a href="#">I no longer have access to this email address.</a>
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<Button type="submit" className="w-full">
|
||||
Verify
|
||||
</Button>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Having trouble signing in?{" "}
|
||||
<a
|
||||
href="#"
|
||||
className="underline underline-offset-4 transition-colors hover:text-primary"
|
||||
>
|
||||
Contact support
|
||||
</a>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
2079
apps/v4/registry/bases/radix/examples/item-example.tsx
Normal file
2079
apps/v4/registry/bases/radix/examples/item-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
194
apps/v4/registry/bases/radix/examples/kbd-example.tsx
Normal file
194
apps/v4/registry/bases/radix/examples/kbd-example.tsx
Normal file
@@ -0,0 +1,194 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Kbd, KbdGroup } from "@/registry/bases/radix/ui/kbd"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/registry/bases/radix/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function KbdExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<KbdBasic />
|
||||
<KbdModifierKeys />
|
||||
<KbdGroupExample />
|
||||
<KbdArrowKeys />
|
||||
<KbdWithIcons />
|
||||
<KbdWithIconsAndText />
|
||||
<KbdInInputGroup />
|
||||
<KbdInTooltip />
|
||||
<KbdWithSamp />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>⌘K</Kbd>
|
||||
<Kbd>Ctrl + B</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdModifierKeys() {
|
||||
return (
|
||||
<Example title="Modifier Keys">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>⌘</Kbd>
|
||||
<Kbd>C</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdGroupExample() {
|
||||
return (
|
||||
<Example title="KbdGroup">
|
||||
<KbdGroup>
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>Shift</Kbd>
|
||||
<Kbd>P</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdArrowKeys() {
|
||||
return (
|
||||
<Example title="Arrow Keys">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>↑</Kbd>
|
||||
<Kbd>↓</Kbd>
|
||||
<Kbd>←</Kbd>
|
||||
<Kbd>→</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<KbdGroup>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithIconsAndText() {
|
||||
return (
|
||||
<Example title="With Icons and Text">
|
||||
<KbdGroup>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
Left
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
Voice Enabled
|
||||
</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdInInputGroup() {
|
||||
return (
|
||||
<Example title="InputGroup">
|
||||
<InputGroup>
|
||||
<InputGroupInput />
|
||||
<InputGroupAddon>
|
||||
<Kbd>Space</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdInTooltip() {
|
||||
return (
|
||||
<Example title="Tooltip">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button size="icon-sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="pr-1.5">
|
||||
<div className="flex items-center gap-2">
|
||||
Save Changes <Kbd>S</Kbd>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithSamp() {
|
||||
return (
|
||||
<Example title="With samp">
|
||||
<Kbd>
|
||||
<samp>File</samp>
|
||||
</Kbd>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
64
apps/v4/registry/bases/radix/examples/label-example.tsx
Normal file
64
apps/v4/registry/bases/radix/examples/label-example.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Checkbox } from "@/registry/bases/radix/ui/checkbox"
|
||||
import { Field } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
|
||||
export default function LabelExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<LabelWithCheckbox />
|
||||
<LabelWithInput />
|
||||
<LabelDisabled />
|
||||
<LabelWithTextarea />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithCheckbox() {
|
||||
return (
|
||||
<Example title="With Checkbox">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="label-demo-terms" />
|
||||
<Label htmlFor="label-demo-terms">Accept terms and conditions</Label>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<Field>
|
||||
<Label htmlFor="label-demo-username">Username</Label>
|
||||
<Input id="label-demo-username" placeholder="Username" />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field data-disabled={true}>
|
||||
<Label htmlFor="label-demo-disabled">Disabled</Label>
|
||||
<Input id="label-demo-disabled" placeholder="Disabled" disabled />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithTextarea() {
|
||||
return (
|
||||
<Example title="With Textarea">
|
||||
<Field>
|
||||
<Label htmlFor="label-demo-message">Message</Label>
|
||||
<Textarea id="label-demo-message" placeholder="Message" />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
330
apps/v4/registry/bases/radix/examples/marker-example.tsx
Normal file
330
apps/v4/registry/bases/radix/examples/marker-example.tsx
Normal file
@@ -0,0 +1,330 @@
|
||||
"use client"
|
||||
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/registry/bases/radix/ui/accordion"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@/registry/bases/radix/ui/drawer"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/radix/ui/marker"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function MarkerExamples() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MarkerExample />
|
||||
<MarkerBorder />
|
||||
<MarkerSeparator />
|
||||
<MarkerAccordion />
|
||||
<MarkerDrawer />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerExample() {
|
||||
return (
|
||||
<Example title="Markers" className="gap-8">
|
||||
<Marker>
|
||||
<MarkerContent>A default marker</MarkerContent>
|
||||
</Marker>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with icon</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with a spinner</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent className="shimmer">
|
||||
Marker with shimmer effect
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerContent className="shimmer">Thinking...</MarkerContent>
|
||||
</Marker>
|
||||
<Marker asChild>
|
||||
<a href="#">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker as a link</MarkerContent>
|
||||
</a>
|
||||
</Marker>
|
||||
<Marker asChild>
|
||||
<button
|
||||
onClick={() => toast("You clicked the button")}
|
||||
className="transition-colors hover:text-foreground"
|
||||
>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ClockIcon"
|
||||
tabler="IconClock"
|
||||
hugeicons="Clock01Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent className="flex-1">
|
||||
<div>Marker as a button</div>
|
||||
</MarkerContent>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
</button>
|
||||
</Marker>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleUserIcon"
|
||||
tabler="IconUserCircle"
|
||||
hugeicons="UserCircleIcon"
|
||||
phosphor="UserCircleIcon"
|
||||
remixicon="RiUserSmileLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Rhea joined the chat</MarkerContent>
|
||||
</Marker>
|
||||
<Marker className="justify-center">
|
||||
<MarkerContent>
|
||||
<strong className="font-medium">Olivia Rose</strong> left the chat
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker className="flex-col">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with icon at the top</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerBorder() {
|
||||
return (
|
||||
<Example title="Border" className="gap-3">
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Switched to release-candidate</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Reviewed 8 related files</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Opened implementation notes</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerSeparator() {
|
||||
return (
|
||||
<Example title="Separator" className="gap-8">
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>Worked for 42s</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator" role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Compacting conversation</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator" role="status">
|
||||
<MarkerContent className="shimmer">Reading 4 files</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Conversation compacted</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>
|
||||
With a <a href="#">link to learn more</a>
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerAccordion() {
|
||||
return (
|
||||
<Example title="Accordion" containerClassName="min-h-72">
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="1">
|
||||
<AccordionTrigger>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ClockIcon"
|
||||
tabler="IconClock"
|
||||
hugeicons="Clock01Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Worked for 42s</MarkerContent>
|
||||
</Marker>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The user asked for a list of all the files in the current
|
||||
directory. The assistant responded with a list of all the files in
|
||||
the current directory.
|
||||
</p>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerDrawer() {
|
||||
return (
|
||||
<Example title="Drawer">
|
||||
<Drawer direction="right">
|
||||
<Marker variant="separator">
|
||||
<DrawerTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Explored 4 files
|
||||
</Button>
|
||||
</DrawerTrigger>
|
||||
</Marker>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>File Activity</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Files read while preparing the response.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="grid gap-3 px-4 text-sm">
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">app/chat/page.tsx</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">components/message.tsx</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">lib/ai.ts</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose asChild>
|
||||
<Button variant="outline">Close</Button>
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
807
apps/v4/registry/bases/radix/examples/menubar-example.tsx
Normal file
807
apps/v4/registry/bases/radix/examples/menubar-example.tsx
Normal file
@@ -0,0 +1,807 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
Menubar,
|
||||
MenubarCheckboxItem,
|
||||
MenubarContent,
|
||||
MenubarGroup,
|
||||
MenubarItem,
|
||||
MenubarLabel,
|
||||
MenubarMenu,
|
||||
MenubarRadioGroup,
|
||||
MenubarRadioItem,
|
||||
MenubarSeparator,
|
||||
MenubarShortcut,
|
||||
MenubarSub,
|
||||
MenubarSubContent,
|
||||
MenubarSubTrigger,
|
||||
MenubarTrigger,
|
||||
} from "@/registry/bases/radix/ui/menubar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function MenubarExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MenubarBasic />
|
||||
<MenubarWithSubmenu />
|
||||
<MenubarWithCheckboxes />
|
||||
<MenubarWithRadio />
|
||||
<MenubarWithIcons />
|
||||
<MenubarWithShortcuts />
|
||||
<MenubarFormat />
|
||||
<MenubarInsert />
|
||||
<MenubarDestructive />
|
||||
<MenubarInDialog />
|
||||
<MenubarWithInset />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
New Window <MenubarShortcut>⌘N</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem disabled>New Incognito Window</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Print... <MenubarShortcut>⌘P</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Edit</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Cut</MenubarItem>
|
||||
<MenubarItem>Copy</MenubarItem>
|
||||
<MenubarItem>Paste</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithSubmenu() {
|
||||
return (
|
||||
<Example title="With Submenu">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarSub>
|
||||
<MenubarSubTrigger>Share</MenubarSubTrigger>
|
||||
<MenubarSubContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Email link</MenubarItem>
|
||||
<MenubarItem>Messages</MenubarItem>
|
||||
<MenubarItem>Notes</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Print... <MenubarShortcut>⌘P</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Edit</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarSub>
|
||||
<MenubarSubTrigger>Find</MenubarSubTrigger>
|
||||
<MenubarSubContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Find...</MenubarItem>
|
||||
<MenubarItem>Find Next</MenubarItem>
|
||||
<MenubarItem>Find Previous</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Cut</MenubarItem>
|
||||
<MenubarItem>Copy</MenubarItem>
|
||||
<MenubarItem>Paste</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithCheckboxes() {
|
||||
return (
|
||||
<Example title="With Checkboxes">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>View</MenubarTrigger>
|
||||
<MenubarContent className="w-64">
|
||||
<MenubarGroup>
|
||||
<MenubarCheckboxItem>
|
||||
Always Show Bookmarks Bar
|
||||
</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem checked>
|
||||
Always Show Full URLs
|
||||
</MenubarCheckboxItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem inset>
|
||||
Reload <MenubarShortcut>⌘R</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem disabled inset>
|
||||
Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Format</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarCheckboxItem checked>Strikethrough</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem>Code</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem>Superscript</MenubarCheckboxItem>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithRadio() {
|
||||
const [user, setUser] = React.useState("benoit")
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Radio">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Profiles</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarRadioGroup value={user} onValueChange={setUser}>
|
||||
<MenubarRadioItem value="andy">Andy</MenubarRadioItem>
|
||||
<MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
|
||||
<MenubarRadioItem value="luis">Luis</MenubarRadioItem>
|
||||
</MenubarRadioGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem inset>Edit...</MenubarItem>
|
||||
<MenubarItem inset>Add Profile...</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Theme</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarRadioGroup value={theme} onValueChange={setTheme}>
|
||||
<MenubarRadioItem value="light">Light</MenubarRadioItem>
|
||||
<MenubarRadioItem value="dark">Dark</MenubarRadioItem>
|
||||
<MenubarRadioItem value="system">System</MenubarRadioItem>
|
||||
</MenubarRadioGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
New File <MenubarShortcut>⌘N</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
Open Folder
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
Save <MenubarShortcut>⌘S</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>More</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
Settings
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
Help
|
||||
</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
Delete
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithShortcuts() {
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
New Window <MenubarShortcut>⌘N</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Print... <MenubarShortcut>⌘P</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Edit</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Cut <MenubarShortcut>⌘X</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Copy <MenubarShortcut>⌘C</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Paste <MenubarShortcut>⌘V</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarFormat() {
|
||||
return (
|
||||
<Example title="Format">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Format</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
Bold <MenubarShortcut>⌘B</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
Italic <MenubarShortcut>⌘I</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
Underline <MenubarShortcut>⌘U</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarCheckboxItem checked>Strikethrough</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem>Code</MenubarCheckboxItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>View</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarCheckboxItem>Show Ruler</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem checked>Show Grid</MenubarCheckboxItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem inset>Zoom In</MenubarItem>
|
||||
<MenubarItem inset>Zoom Out</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarInsert() {
|
||||
return (
|
||||
<Example title="Insert">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Insert</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarSub>
|
||||
<MenubarSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="ImageIcon"
|
||||
tabler="IconPhoto"
|
||||
hugeicons="ImageIcon"
|
||||
phosphor="ImageIcon"
|
||||
remixicon="RiImageLine"
|
||||
/>
|
||||
Media
|
||||
</MenubarSubTrigger>
|
||||
<MenubarSubContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Image</MenubarItem>
|
||||
<MenubarItem>Video</MenubarItem>
|
||||
<MenubarItem>Audio</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="LinkIcon"
|
||||
tabler="IconLink"
|
||||
hugeicons="LinkIcon"
|
||||
phosphor="LinkIcon"
|
||||
remixicon="RiLinksLine"
|
||||
/>
|
||||
Link <MenubarShortcut>⌘K</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="TableIcon"
|
||||
tabler="IconTable"
|
||||
hugeicons="TableIcon"
|
||||
phosphor="TableIcon"
|
||||
remixicon="RiTableLine"
|
||||
/>
|
||||
Table
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Tools</MenubarTrigger>
|
||||
<MenubarContent className="w-44">
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
Find & Replace <MenubarShortcut>⌘F</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
Spell Check
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarDestructive() {
|
||||
return (
|
||||
<Example title="Destructive">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent className="w-40">
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
New File <MenubarShortcut>⌘N</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
Open Folder
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete File <MenubarShortcut>⌘⌫</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Account</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign out
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Menubar Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use the menubar below to see the menu options.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>File</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarSub>
|
||||
<MenubarSubTrigger>More Options</MenubarSubTrigger>
|
||||
<MenubarSubContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Save Page...</MenubarItem>
|
||||
<MenubarItem>Create Shortcut...</MenubarItem>
|
||||
<MenubarItem>Name Window...</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Developer Tools</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Edit</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>
|
||||
Undo <MenubarShortcut>⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MenubarWithInset() {
|
||||
const [showBookmarks, setShowBookmarks] = React.useState(true)
|
||||
const [showUrls, setShowUrls] = React.useState(false)
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Inset">
|
||||
<Menubar>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>View</MenubarTrigger>
|
||||
<MenubarContent className="w-44">
|
||||
<MenubarGroup>
|
||||
<MenubarLabel>Actions</MenubarLabel>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</MenubarItem>
|
||||
<MenubarItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</MenubarItem>
|
||||
<MenubarItem inset>Paste</MenubarItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarLabel inset>Appearance</MenubarLabel>
|
||||
<MenubarCheckboxItem
|
||||
inset
|
||||
checked={showBookmarks}
|
||||
onCheckedChange={setShowBookmarks}
|
||||
>
|
||||
Bookmarks
|
||||
</MenubarCheckboxItem>
|
||||
<MenubarCheckboxItem
|
||||
inset
|
||||
checked={showUrls}
|
||||
onCheckedChange={setShowUrls}
|
||||
>
|
||||
Full URLs
|
||||
</MenubarCheckboxItem>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarGroup>
|
||||
<MenubarLabel inset>Theme</MenubarLabel>
|
||||
<MenubarRadioGroup value={theme} onValueChange={setTheme}>
|
||||
<MenubarRadioItem inset value="light">
|
||||
Light
|
||||
</MenubarRadioItem>
|
||||
<MenubarRadioItem inset value="dark">
|
||||
Dark
|
||||
</MenubarRadioItem>
|
||||
<MenubarRadioItem inset value="system">
|
||||
System
|
||||
</MenubarRadioItem>
|
||||
</MenubarRadioGroup>
|
||||
</MenubarGroup>
|
||||
<MenubarSeparator />
|
||||
<MenubarSub>
|
||||
<MenubarSubTrigger inset>More Options</MenubarSubTrigger>
|
||||
<MenubarSubContent>
|
||||
<MenubarGroup>
|
||||
<MenubarItem>Save Page...</MenubarItem>
|
||||
<MenubarItem>Create Shortcut...</MenubarItem>
|
||||
</MenubarGroup>
|
||||
</MenubarSubContent>
|
||||
</MenubarSub>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
948
apps/v4/registry/bases/radix/examples/message-example.tsx
Normal file
948
apps/v4/registry/bases/radix/examples/message-example.tsx
Normal file
@@ -0,0 +1,948 @@
|
||||
import type { UIMessage } from "ai"
|
||||
|
||||
import { createChat } from "@/lib/ai"
|
||||
import { type MessagePartRenderProps } from "@/components/message-parts"
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Attachment,
|
||||
AttachmentAction,
|
||||
AttachmentActions,
|
||||
AttachmentContent,
|
||||
AttachmentDescription,
|
||||
AttachmentGroup,
|
||||
AttachmentMedia,
|
||||
AttachmentTitle,
|
||||
} from "@/registry/bases/radix/ui/attachment"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/radix/ui/avatar"
|
||||
import {
|
||||
Bubble,
|
||||
BubbleContent,
|
||||
BubbleGroup,
|
||||
BubbleReactions,
|
||||
} from "@/registry/bases/radix/ui/bubble"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/radix/ui/marker"
|
||||
import {
|
||||
Message,
|
||||
MessageAvatar,
|
||||
MessageContent,
|
||||
MessageFooter,
|
||||
MessageGroup,
|
||||
MessageHeader,
|
||||
} from "@/registry/bases/radix/ui/message"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
type MessagePartsData = {
|
||||
deployment: {
|
||||
status: "healthy" | "degraded"
|
||||
region: string
|
||||
latency: number
|
||||
}
|
||||
}
|
||||
|
||||
type MessagePartsTools = {
|
||||
getDeploymentHealth: {
|
||||
input: {
|
||||
project: string
|
||||
region: string
|
||||
}
|
||||
output: {
|
||||
status: "healthy" | "degraded"
|
||||
p95: number
|
||||
errors: number
|
||||
recommendation: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MessagePartsMessage = UIMessage<
|
||||
unknown,
|
||||
MessagePartsData,
|
||||
MessagePartsTools
|
||||
>
|
||||
|
||||
const messagePartsChat = createChat<MessagePartsMessage>()
|
||||
.user("Can you review this screenshot and check the deployment?", {
|
||||
files: [
|
||||
{
|
||||
mediaType: "image/jpeg",
|
||||
filename: "checkout-error.jpg",
|
||||
url: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=900&auto=format&fit=crop&q=80",
|
||||
},
|
||||
],
|
||||
})
|
||||
.assistant(({ writer }) => {
|
||||
writer.reasoning(
|
||||
"The user included an image and asked for deployment status, so I should inspect the screenshot context and call the deployment health tool before answering."
|
||||
)
|
||||
|
||||
const deployment = writer.tool("getDeploymentHealth", {
|
||||
title: "Checking deployment health",
|
||||
input: {
|
||||
project: "checkout",
|
||||
region: "iad1",
|
||||
},
|
||||
})
|
||||
|
||||
deployment.output({
|
||||
status: "healthy",
|
||||
p95: 186,
|
||||
errors: 2,
|
||||
recommendation: "Keep the deployment live and monitor error rate.",
|
||||
})
|
||||
|
||||
writer.data({
|
||||
type: "data-deployment",
|
||||
id: "deployment-health",
|
||||
data: {
|
||||
status: "healthy",
|
||||
region: "iad1",
|
||||
latency: 186,
|
||||
},
|
||||
})
|
||||
writer.text(
|
||||
"The deployment looks healthy. P95 latency is **186ms** with **2 recent errors**, so I would keep it live and monitor error rate for the next 15 minutes."
|
||||
)
|
||||
writer.sourceUrl({
|
||||
sourceId: "source-deployment-docs",
|
||||
title: "Deployment health checks",
|
||||
url: "https://vercel.com/docs/deployments",
|
||||
})
|
||||
writer.sourceDocument({
|
||||
sourceId: "source-runbook",
|
||||
title: "Checkout release runbook",
|
||||
filename: "checkout-release-runbook.md",
|
||||
mediaType: "text/markdown",
|
||||
})
|
||||
})
|
||||
|
||||
const messagePartsMessages = messagePartsChat.get()
|
||||
|
||||
type MessagePartsPart = MessagePartsMessage["parts"][number]
|
||||
|
||||
export default function MessageExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MessageDefault />
|
||||
<MessageWithAvatar />
|
||||
<MessageGroupExample />
|
||||
<MessageGroupChat />
|
||||
<MessageHeaderFooter />
|
||||
<MessageActions />
|
||||
<MessageAttachment />
|
||||
<MessageAttachmentGroup />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageTextPart({
|
||||
part,
|
||||
message,
|
||||
}: MessagePartRenderProps<MessagePartsPart, MessagePartsMessage>) {
|
||||
if (part.type !== "text") {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Bubble
|
||||
align={message.role === "user" ? "end" : "start"}
|
||||
variant={message.role === "user" ? "default" : "ghost"}
|
||||
>
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">{part.text}</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageDefault() {
|
||||
return (
|
||||
<Example title="Message">
|
||||
<div className="flex w-full max-w-md min-w-0 flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>Deploying to prod real quick.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>It's 4:55 PM. On a Friday.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>It's a one-line change.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<BubbleGroup>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
It's always a one-line change 😭. Make sure to run the
|
||||
tests this time.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Alright, go for it.</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageWithAvatar() {
|
||||
return (
|
||||
<Example title="Avatar">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
I checked the latest deployment and found the build failed
|
||||
during dependency installation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent className="space-y-2">
|
||||
<div>
|
||||
I checked the latest deployment and found the build failed
|
||||
during dependency installation.
|
||||
</div>
|
||||
<div>Can you share the exact error message from the logs?</div>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageGroupExample() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageGroupChat() {
|
||||
return (
|
||||
<Example title="Group Chat">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
Why is the dashboard showing zero users
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Define "zero."</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>What do you mean?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
<span className="font-medium">@eve</span> can you check?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Checking the logs...</MarkerContent>
|
||||
</Marker>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<MessageHeader>Eve</MessageHeader>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`I found the following error in the logs:
|
||||
|
||||
- Error: No users found
|
||||
- Stack trace:
|
||||
- at src/users/services/user-service.ts:123
|
||||
- at src/users/services/get-user.ts:230
|
||||
|
||||
Can you check if the users are being created?`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageHeaderFooter() {
|
||||
return (
|
||||
<Example title="Header and Footer">
|
||||
<div className="flex w-full max-w-md flex-col gap-12">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader className="justify-end">You</MessageHeader>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Can we keep this style quiet and send the update today?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Delivered</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Undo
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="start">
|
||||
<MessageContent>
|
||||
<MessageHeader>
|
||||
<span>Olivia</span>
|
||||
<span className="ml-auto font-normal">1m ago</span>
|
||||
</MessageHeader>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
I checked the logs. The retry finished and the missing invoices
|
||||
are included now.
|
||||
</BubbleContent>
|
||||
<BubbleReactions>
|
||||
<Button variant="ghost" size="xs">
|
||||
Thanks
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>From Support queue</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Copy
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader>Marina</MessageHeader>
|
||||
<Bubble variant="outline">
|
||||
<BubbleContent>
|
||||
I drafted the reply with the exact filter path and a link to the
|
||||
export history.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Draft ready</span>
|
||||
<Button variant="outline" size="xs">
|
||||
Review
|
||||
</Button>
|
||||
<Button size="xs">Send</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="start">
|
||||
<MessageContent>
|
||||
<MessageHeader>Assistant note</MessageHeader>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
Ghost messages keep long-form assistant notes aligned with the
|
||||
surrounding text instead of adding a frame.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Internal only</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Pin
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader className="justify-end">
|
||||
Automation warning
|
||||
</MessageHeader>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>
|
||||
The old export link expires in 10 minutes. Regenerate before
|
||||
sending this transcript externally.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Needs action</span>
|
||||
<Button variant="destructive" size="xs">
|
||||
Regenerate
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageAttachment() {
|
||||
return (
|
||||
<Example title="Attachment">
|
||||
<div className="flex w-full max-w-sm flex-col gap-8">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Workspace"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Here's the image. Can you add it to the PDF? Use it for the
|
||||
cover page.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Done. Here's the PDF with the image added as the cover
|
||||
page.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Attachment>
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
|
||||
<AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
title="Download"
|
||||
aria-label="Download"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>Thanks. Looks good.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageAttachmentGroup() {
|
||||
return (
|
||||
<Example title="Attachment Group">
|
||||
<div className="flex w-full max-w-sm flex-col gap-8">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<AttachmentGroup className="w-[80%]">
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Workspace"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497215728101-856f4ea42174?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Desk"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366811353-6870744d04b2?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Office"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
</AttachmentGroup>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Here are the brand photos. Can you add them to the deck?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Done. Here's the draft deck and the exported assets.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<AttachmentGroup className="w-full">
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-deck.pdf</AttachmentTitle>
|
||||
<AttachmentDescription>PDF · 3.1 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
title="Download"
|
||||
aria-label="Download brand-deck.pdf"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="PresentationIcon"
|
||||
tabler="IconPresentation"
|
||||
hugeicons="Presentation01Icon"
|
||||
phosphor="PresentationIcon"
|
||||
remixicon="RiSlideshowLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-deck.key</AttachmentTitle>
|
||||
<AttachmentDescription>Keynote · 9 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
title="Download"
|
||||
aria-label="Download brand-deck.key"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileArchiveIcon"
|
||||
tabler="IconFileZip"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileZipIcon"
|
||||
remixicon="RiFileZipLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-assets.zip</AttachmentTitle>
|
||||
<AttachmentDescription>ZIP · 4.2 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
title="Download"
|
||||
aria-label="Download brand-assets.zip"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
</AttachmentGroup>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageActions() {
|
||||
return (
|
||||
<Example title="Actions">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
What is the status of the deployment?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Copy"
|
||||
title="Copy"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Retry"
|
||||
title="Retry"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCcwIcon"
|
||||
tabler="IconRefresh"
|
||||
hugeicons="ReloadIcon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The install failure is coming from the workspace package. I can
|
||||
open the exact log line or retry the deployment.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Copy"
|
||||
title="Copy"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Like: thumbs up"
|
||||
title="Like: thumbs up"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsUpIcon"
|
||||
tabler="IconThumbUp"
|
||||
hugeicons="ThumbsUpIcon"
|
||||
phosphor="ThumbsUpIcon"
|
||||
remixicon="RiThumbUpLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Like: thumbs down"
|
||||
title="Like: thumbs down"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsDownIcon"
|
||||
tabler="IconThumbDown"
|
||||
hugeicons="ThumbsDownIcon"
|
||||
phosphor="ThumbsDownIcon"
|
||||
remixicon="RiThumbDownLine"
|
||||
/>
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Okay drop me a link. I'll check it out.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span className="font-normal text-destructive">
|
||||
Failed to send
|
||||
</span>
|
||||
<Button variant="secondary" size="xs">
|
||||
Retry
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { useChat } from "@ai-sdk/react"
|
||||
|
||||
import { createChat, getMessageText } from "@/lib/ai"
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Bubble, BubbleContent } from "@/registry/bases/radix/ui/bubble"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupTextarea,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/radix/ui/marker"
|
||||
import { Message, MessageContent } from "@/registry/bases/radix/ui/message"
|
||||
import {
|
||||
MessageScroller,
|
||||
MessageScrollerButton,
|
||||
MessageScrollerContent,
|
||||
MessageScrollerItem,
|
||||
MessageScrollerProvider,
|
||||
MessageScrollerViewport,
|
||||
} from "@/registry/bases/radix/ui/message-scroller"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function MessageScrollerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MessageScrollerDemo />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const chat = createChat()
|
||||
.user("Hello there!")
|
||||
.sleep(2000)
|
||||
.assistant("Hey, how's it going?")
|
||||
.user(
|
||||
`I'm prototyping an AI chat surface for our product docs.
|
||||
|
||||
Can you sketch a sensible component breakdown and call out anything I'd regret baking into v1?`
|
||||
)
|
||||
.sleep(2000)
|
||||
.assistant(
|
||||
`## Recommended layout
|
||||
|
||||
Treat the chat as three layers so scrolling and the composer never fight each other:
|
||||
|
||||
| Layer | Responsibility |
|
||||
| --- | --- |
|
||||
| **Shell** | Card or page frame, title, status indicator |
|
||||
| **Transcript** | \`overflow-y-auto\` message list |
|
||||
| **Composer** | Input group, send, stop |
|
||||
|
||||
### Message rendering
|
||||
|
||||
- **User messages**: right-aligned, muted background, \`max-w-[80%]\`.
|
||||
- **Assistant messages**: full width within the column; use \`whitespace-pre-wrap\` for text.
|
||||
|
||||
### Suggested component split
|
||||
|
||||
\`\`\`tsx
|
||||
<ChatCard>
|
||||
<ChatHeader status={status} />
|
||||
<ChatTranscript messages={messages} />
|
||||
<ChatComposer onSubmit={sendMessage} onStop={stop} />
|
||||
</ChatCard>
|
||||
\`\`\`
|
||||
|
||||
### v1 pitfalls to avoid
|
||||
|
||||
1. **Inlining transport logic in the UI** — keep scripted/demo transport beside your example, not inside shared components.
|
||||
2. **Fixed transcript height without \`overflow-hidden\`** — parent must clip, child must scroll, or the composer jumps.
|
||||
3. **Not giving the scroller a ref or auto-scroll flag** — long replies should stay pinned to the bottom unless the user scrolls up.
|
||||
|
||||
### Practical next step
|
||||
|
||||
Start with plain \`whitespace-pre-wrap\` text to validate spacing and scroll behavior. Once the transcript feels right, you can swap assistant text rendering to a richer renderer if you need it.
|
||||
|
||||
Want me to walk through auto-scroll vs. manual scroll-to-bottom next?`
|
||||
)
|
||||
.user(
|
||||
"What about message spacing when one reply is short and the next is really long?"
|
||||
)
|
||||
.sleep(2000)
|
||||
.assistant(
|
||||
`Good question. The scroll container should own vertical rhythm, not individual bubbles.
|
||||
|
||||
Use a consistent \`gap\` on the message list (something like \`gap-4\` or \`gap-6\`) so short and long messages sit on the same grid. For assistant replies that span many paragraphs, keep everything in one bubble rather than splitting on every line break — otherwise the transcript feels choppy when you're skimming.
|
||||
|
||||
When a long reply streams in, pin the viewport to the bottom with \`MessageScroller autoScroll\` until the user scrolls up. If they've scrolled away, show a scroll-to-bottom affordance instead of yanking them back mid-read.
|
||||
|
||||
That's usually enough for v1. Fancy diff animations or per-paragraph fade-ins can wait until you've validated that the base scroll + composer layout holds up on real devices.`
|
||||
)
|
||||
.user("Thanks, that helps.")
|
||||
.sleep(1000)
|
||||
.assistant(
|
||||
"Happy to help — send another message when you're ready to keep stepping through the demo."
|
||||
)
|
||||
|
||||
const initialMessages = chat.get(0)
|
||||
const transport = chat.transport({
|
||||
delayMs: 10,
|
||||
})
|
||||
|
||||
function MessageScrollerDemo() {
|
||||
const { messages, sendMessage, status, stop } = useChat({
|
||||
messages: initialMessages,
|
||||
transport,
|
||||
})
|
||||
const nextMessage = chat.next(messages)
|
||||
const isBusy = status === "submitted" || status === "streaming"
|
||||
|
||||
function handleFormSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
if (!nextMessage || isBusy) {
|
||||
return
|
||||
}
|
||||
|
||||
void sendMessage(nextMessage)
|
||||
}
|
||||
|
||||
return (
|
||||
<Example title="Chat" containerClassName="self-start">
|
||||
<Card className="h-140">
|
||||
<CardHeader>
|
||||
<CardTitle>How can I help you today?</CardTitle>
|
||||
<CardDescription>Status: {status}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="min-h-0 flex-1 overflow-hidden p-0">
|
||||
<MessageScrollerProvider>
|
||||
<MessageScroller>
|
||||
<MessageScrollerViewport>
|
||||
<MessageScrollerContent className="p-(--card-spacing)">
|
||||
{messages.map((message) => (
|
||||
<MessageScrollerItem
|
||||
key={message.id}
|
||||
messageId={message.id}
|
||||
scrollAnchor={message.role === "user"}
|
||||
>
|
||||
<Message
|
||||
align={message.role === "user" ? "end" : "start"}
|
||||
>
|
||||
<MessageContent>
|
||||
{message.parts.map((part, index) => {
|
||||
if (part.type !== "text") {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Bubble
|
||||
key={`${message.id}-${index}`}
|
||||
variant={
|
||||
message.role === "user" ? "default" : "muted"
|
||||
}
|
||||
>
|
||||
<BubbleContent className="whitespace-pre-wrap">
|
||||
{part.text}
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
)
|
||||
})}
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageScrollerItem>
|
||||
))}
|
||||
{status === "submitted" ? (
|
||||
<MessageScrollerItem scrollAnchor={false}>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Thinking...</MarkerContent>
|
||||
</Marker>
|
||||
</MessageScrollerItem>
|
||||
) : null}
|
||||
</MessageScrollerContent>
|
||||
</MessageScrollerViewport>
|
||||
<MessageScrollerButton />
|
||||
</MessageScroller>
|
||||
</MessageScrollerProvider>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<form onSubmit={handleFormSubmit} className="w-full" id="chat-form">
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
placeholder="Ask me anything..."
|
||||
className="h-10 min-h-10 overflow-y-auto"
|
||||
value={
|
||||
isBusy ? "" : nextMessage ? getMessageText(nextMessage) : ""
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
<InputGroupAddon align="block-end" className="p-2">
|
||||
<InputGroupButton
|
||||
variant="default"
|
||||
size="icon-sm"
|
||||
type="submit"
|
||||
disabled={!nextMessage || isBusy}
|
||||
className="ml-auto data-[hidden=true]:hidden"
|
||||
data-hidden={isBusy}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUp02Icon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
<span className="sr-only">Send</span>
|
||||
</InputGroupButton>
|
||||
<InputGroupButton
|
||||
size="icon-sm"
|
||||
type="button"
|
||||
data-hidden={!isBusy}
|
||||
className="ml-auto data-[hidden=true]:hidden"
|
||||
onClick={() => stop()}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StopCircleIcon"
|
||||
tabler="IconPlayerStop"
|
||||
hugeicons="StopCircleIcon"
|
||||
phosphor="StopCircleIcon"
|
||||
remixicon="RiStopCircleLine"
|
||||
/>
|
||||
<span className="sr-only">Stop</span>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</form>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
129
apps/v4/registry/bases/radix/examples/native-select-example.tsx
Normal file
129
apps/v4/registry/bases/radix/examples/native-select-example.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOptGroup,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
|
||||
export default function NativeSelectExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<NativeSelectBasic />
|
||||
<NativeSelectWithGroups />
|
||||
<NativeSelectSizes />
|
||||
<NativeSelectWithField />
|
||||
<NativeSelectDisabled />
|
||||
<NativeSelectInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<NativeSelect>
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
<NativeSelectOption value="grapes" disabled>
|
||||
Grapes
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="pineapple">Pineapple</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectWithGroups() {
|
||||
return (
|
||||
<Example title="With Groups">
|
||||
<NativeSelect>
|
||||
<NativeSelectOption value="">Select a food</NativeSelectOption>
|
||||
<NativeSelectOptGroup label="Fruits">
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
<NativeSelectOptGroup label="Vegetables">
|
||||
<NativeSelectOption value="carrot">Carrot</NativeSelectOption>
|
||||
<NativeSelectOption value="broccoli">Broccoli</NativeSelectOption>
|
||||
<NativeSelectOption value="spinach">Spinach</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<NativeSelect size="sm">
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<NativeSelect size="default">
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectWithField() {
|
||||
return (
|
||||
<Example title="With Field">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-country">Country</FieldLabel>
|
||||
<NativeSelect id="native-select-country">
|
||||
<NativeSelectOption value="">Select a country</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
<NativeSelectOption value="au">Australia</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>Select your country of residence.</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<NativeSelect disabled>
|
||||
<NativeSelectOption value="">Disabled</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<NativeSelect aria-invalid="true">
|
||||
<NativeSelectOption value="">Error state</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import Link from "next/link"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
NavigationMenuTrigger,
|
||||
navigationMenuTriggerStyle,
|
||||
} from "@/registry/bases/radix/ui/navigation-menu"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const components: { title: string; href: string; description: string }[] = [
|
||||
{
|
||||
title: "Alert Dialog",
|
||||
href: "/docs/primitives/alert-dialog",
|
||||
description:
|
||||
"A modal dialog that interrupts the user with important content and expects a response.",
|
||||
},
|
||||
{
|
||||
title: "Hover Card",
|
||||
href: "/docs/primitives/hover-card",
|
||||
description:
|
||||
"For sighted users to preview content available behind a link.",
|
||||
},
|
||||
{
|
||||
title: "Progress",
|
||||
href: "/docs/primitives/progress",
|
||||
description:
|
||||
"Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.",
|
||||
},
|
||||
{
|
||||
title: "Scroll-area",
|
||||
href: "/docs/primitives/scroll-area",
|
||||
description: "Visually or semantically separates content.",
|
||||
},
|
||||
{
|
||||
title: "Tabs",
|
||||
href: "/docs/primitives/tabs",
|
||||
description:
|
||||
"A set of layered sections of content—known as tab panels—that are displayed one at a time.",
|
||||
},
|
||||
{
|
||||
title: "Tooltip",
|
||||
href: "/docs/primitives/tooltip",
|
||||
description:
|
||||
"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
|
||||
},
|
||||
]
|
||||
|
||||
export default function NavigationMenuExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<NavigationMenuWithViewport />
|
||||
<NavigationMenuWithoutViewport />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuWithViewport() {
|
||||
return (
|
||||
<Example title="With Viewport">
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul className="w-96">
|
||||
<ListItem href="/docs" title="Introduction">
|
||||
Re-usable components built with Tailwind CSS.
|
||||
</ListItem>
|
||||
<ListItem href="/docs/installation" title="Installation">
|
||||
How to install dependencies and structure your app.
|
||||
</ListItem>
|
||||
<ListItem href="/docs/primitives/typography" title="Typography">
|
||||
Styles for headings, paragraphs, lists...etc
|
||||
</ListItem>
|
||||
</ul>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>Components</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul className="grid w-[400px] gap-1 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
|
||||
{components.map((component) => (
|
||||
<ListItem
|
||||
key={component.title}
|
||||
title={component.title}
|
||||
href={component.href}
|
||||
>
|
||||
{component.description}
|
||||
</ListItem>
|
||||
))}
|
||||
</ul>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={navigationMenuTriggerStyle()}
|
||||
>
|
||||
<Link href="/docs">Documentation</Link>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NavigationMenuWithoutViewport() {
|
||||
return (
|
||||
<Example title="Without Viewport">
|
||||
<NavigationMenu viewport={false}>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={navigationMenuTriggerStyle()}
|
||||
>
|
||||
<Link href="/docs">Documentation</Link>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>List</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul className="w-72">
|
||||
<li>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">
|
||||
<div className="flex flex-col">
|
||||
<div className="font-medium style-sera:font-heading style-sera:tracking-wide style-sera:uppercase">
|
||||
Components
|
||||
</div>
|
||||
<div className="text-muted-foreground style-sera:mt-0.5 style-sera:leading-relaxed">
|
||||
Browse all components in the library.
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">
|
||||
<div className="flex flex-col">
|
||||
<div className="font-medium style-sera:font-heading style-sera:tracking-wide style-sera:uppercase">
|
||||
Documentation
|
||||
</div>
|
||||
<div className="text-muted-foreground style-sera:mt-0.5 style-sera:leading-relaxed">
|
||||
Learn how to use the library.
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">
|
||||
<div className="flex flex-col">
|
||||
<div className="font-medium style-sera:font-heading style-sera:tracking-wide style-sera:uppercase">
|
||||
Blog
|
||||
</div>
|
||||
<div className="text-muted-foreground style-sera:mt-0.5 style-sera:leading-relaxed">
|
||||
Read our latest blog posts.
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
</li>
|
||||
</ul>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>Simple List</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul>
|
||||
<li>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">Components</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">Documentation</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">Blocks</Link>
|
||||
</NavigationMenuLink>
|
||||
</li>
|
||||
</ul>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>With Icon</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<ul className="grid w-[200px]">
|
||||
<li>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#" className="flex-row items-center gap-2">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
Backlog
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#" className="flex-row items-center gap-2">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
To Do
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href="#">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
Done
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
</li>
|
||||
</ul>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ListItem({
|
||||
title,
|
||||
children,
|
||||
href,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<"li"> & { href: string }) {
|
||||
return (
|
||||
<li {...props}>
|
||||
<NavigationMenuLink asChild>
|
||||
<Link href={href}>
|
||||
<div className="flex flex-col gap-1 style-vega:text-sm style-nova:text-sm style-lyra:text-xs style-maia:text-sm style-mira:text-xs style-luma:text-sm">
|
||||
<div className="leading-none font-medium style-sera:font-heading style-sera:tracking-wide style-sera:uppercase">
|
||||
{title}
|
||||
</div>
|
||||
<div className="line-clamp-2 text-muted-foreground style-sera:mt-0.5 style-sera:leading-relaxed">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</NavigationMenuLink>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
126
apps/v4/registry/bases/radix/examples/pagination-example.tsx
Normal file
126
apps/v4/registry/bases/radix/examples/pagination-example.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Field, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationEllipsis,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "@/registry/bases/radix/ui/pagination"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
|
||||
export default function PaginationExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<PaginationBasic />
|
||||
<PaginationSimple />
|
||||
<PaginationIconsOnly />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious href="#" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">1</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#" isActive>
|
||||
2
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">3</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext href="#" />
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">1</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#" isActive>
|
||||
2
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">3</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">4</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">5</PaginationLink>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationIconsOnly() {
|
||||
return (
|
||||
<Example title="With Select" containerClassName="col-span-2">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<Field orientation="horizontal" className="w-fit">
|
||||
<FieldLabel htmlFor="select-rows-per-page">Rows per page</FieldLabel>
|
||||
<Select defaultValue="25">
|
||||
<SelectTrigger className="w-20" id="select-rows-per-page">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="start">
|
||||
<SelectGroup>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
<SelectItem value="25">25</SelectItem>
|
||||
<SelectItem value="50">50</SelectItem>
|
||||
<SelectItem value="100">100</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Pagination className="mx-0 w-auto">
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious href="#" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext href="#" />
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
163
apps/v4/registry/bases/radix/examples/popover-example.tsx
Normal file
163
apps/v4/registry/bases/radix/examples/popover-example.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverDescription,
|
||||
PopoverHeader,
|
||||
PopoverTitle,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/bases/radix/ui/popover"
|
||||
|
||||
export default function PopoverExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<PopoverBasic />
|
||||
<PopoverWithForm />
|
||||
<PopoverAlignments />
|
||||
<PopoverInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline">Open Popover</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Dimensions</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
Set the dimensions for the layer.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverWithForm() {
|
||||
return (
|
||||
<Example title="With Form">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline">Open Popover</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-64" align="start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Dimensions</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
Set the dimensions for the layer.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
<FieldGroup className="gap-4">
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="width" className="w-1/2">
|
||||
Width
|
||||
</FieldLabel>
|
||||
<Input id="width" defaultValue="100%" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="height" className="w-1/2">
|
||||
Height
|
||||
</FieldLabel>
|
||||
<Input id="height" defaultValue="25px" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAlignments() {
|
||||
return (
|
||||
<Example title="Alignments">
|
||||
<div className="flex gap-6">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
Start
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start" className="w-40">
|
||||
Aligned to start
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
Center
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="center" className="w-40">
|
||||
Aligned to center
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
End
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-40">
|
||||
Aligned to end
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Popover Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to see the popover.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open Popover
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Popover in Dialog</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
This popover appears inside a dialog. Click the button to open
|
||||
it.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
142
apps/v4/registry/bases/radix/examples/progress-example.tsx
Normal file
142
apps/v4/registry/bases/radix/examples/progress-example.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Field, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { Progress } from "@/registry/bases/radix/ui/progress"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ProgressExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ProgressValues />
|
||||
<ProgressWithLabel />
|
||||
<ProgressControlled />
|
||||
<FileUploadList />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressValues() {
|
||||
return (
|
||||
<Example title="Progress Bar">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Progress value={0} />
|
||||
<Progress value={25} className="w-full" />
|
||||
<Progress value={50} />
|
||||
<Progress value={75} />
|
||||
<Progress value={100} />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="progress-upload">
|
||||
<span>Upload progress</span>
|
||||
<span className="ml-auto">66%</span>
|
||||
</FieldLabel>
|
||||
<Progress value={66} className="w-full" id="progress-upload" />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressControlled() {
|
||||
const [value, setValue] = React.useState([50])
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Progress value={value[0]} className="w-full" />
|
||||
<Slider
|
||||
value={value}
|
||||
onValueChange={setValue}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function FileUploadList() {
|
||||
const files = React.useMemo(
|
||||
() => [
|
||||
{
|
||||
id: "1",
|
||||
name: "document.pdf",
|
||||
progress: 45,
|
||||
timeRemaining: "2m 30s",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "presentation.pptx",
|
||||
progress: 78,
|
||||
timeRemaining: "45s",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "spreadsheet.xlsx",
|
||||
progress: 12,
|
||||
timeRemaining: "5m 12s",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "image.jpg",
|
||||
progress: 100,
|
||||
timeRemaining: "Complete",
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="File Upload List">
|
||||
<ItemGroup>
|
||||
{files.map((file) => (
|
||||
<Item key={file.id} size="xs" className="px-0">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
className="size-5"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="inline-block truncate">
|
||||
<ItemTitle className="inline">{file.name}</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemContent>
|
||||
<Progress value={file.progress} className="w-32" />
|
||||
</ItemContent>
|
||||
<ItemActions className="w-16 justify-end">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{file.timeRemaining}
|
||||
</span>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
))}
|
||||
</ItemGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
473
apps/v4/registry/bases/radix/examples/questionnaire-example.tsx
Normal file
473
apps/v4/registry/bases/radix/examples/questionnaire-example.tsx
Normal file
@@ -0,0 +1,473 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
Questionnaire,
|
||||
QuestionnaireActions,
|
||||
QuestionnaireChoice,
|
||||
QuestionnaireChoiceDescription,
|
||||
QuestionnaireChoices,
|
||||
QuestionnaireDescription,
|
||||
QuestionnaireError,
|
||||
QuestionnaireInput,
|
||||
QuestionnaireItem,
|
||||
QuestionnaireNext,
|
||||
QuestionnairePrevious,
|
||||
QuestionnaireProgress,
|
||||
QuestionnaireSkip,
|
||||
QuestionnaireSubmit,
|
||||
QuestionnaireTitle,
|
||||
} from "@/registry/bases/radix/ui/questionnaire"
|
||||
|
||||
const questionnaireItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "delegation" },
|
||||
{ value: "questions" },
|
||||
{ value: "both" },
|
||||
],
|
||||
name: "direction",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
choices: [
|
||||
{ value: "progress" },
|
||||
{ value: "decisions" },
|
||||
{ value: "risks" },
|
||||
],
|
||||
name: "signals",
|
||||
},
|
||||
{
|
||||
choices: [{ value: "week" }, { value: "cycle" }, { value: "later" }],
|
||||
name: "timing",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
const taskItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "inspect" },
|
||||
{ value: "implement" },
|
||||
{ value: "review" },
|
||||
],
|
||||
name: "task",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
const planItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "plus" },
|
||||
{ value: "pro" },
|
||||
{ value: "enterprise", disabled: true },
|
||||
],
|
||||
name: "plan",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
export default function QuestionnaireExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<QuestionnaireStandalone />
|
||||
<QuestionnaireCard />
|
||||
<QuestionnaireDialog />
|
||||
<QuestionnaireNoDescription />
|
||||
<QuestionnaireDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireDisabled() {
|
||||
return (
|
||||
<Example title="Disabled" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="plan"
|
||||
items={planItems}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireItem name="plan" required>
|
||||
<QuestionnaireTitle>Choose a plan</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Enterprise is not available on your account.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="plus">
|
||||
<span className="font-medium">Plus</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For individuals and small teams
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="pro">
|
||||
<span className="font-medium">Pro</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For growing businesses
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="enterprise" disabled>
|
||||
<span className="font-medium">Enterprise</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For large teams and enterprises
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireNoDescription() {
|
||||
return (
|
||||
<Example title="No description" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="task"
|
||||
items={taskItems}
|
||||
shortcuts="letters"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireProgress />
|
||||
<QuestionnaireItem name="task" required>
|
||||
<QuestionnaireTitle>
|
||||
What should the agent do next?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="inspect">
|
||||
Inspect the codebase
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="implement">
|
||||
Implement the change
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="review">
|
||||
Review the result
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireStandalone() {
|
||||
return (
|
||||
<Example title="Standalone" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
shortcuts="letters"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireProgress />
|
||||
<QuestionnaireQuestions />
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireCard() {
|
||||
return (
|
||||
<Example title="Card" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
shortcuts="numbers"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireCardQuestions />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireDialog() {
|
||||
return (
|
||||
<Example
|
||||
title="Dialog"
|
||||
className="items-center justify-center"
|
||||
containerClassName="md:col-span-2"
|
||||
>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open questionnaire</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<Questionnaire
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="sr-only">
|
||||
Plan an agent interface
|
||||
</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
Answer three questions to shape the next prototype.
|
||||
</DialogDescription>
|
||||
<QuestionnaireProgress
|
||||
className="font-semibold tracking-widest text-foreground uppercase"
|
||||
render={(props, state) => (
|
||||
<span {...props}>
|
||||
Question {state.current} of {state.total}
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</DialogHeader>
|
||||
<QuestionnaireQuestions />
|
||||
<DialogFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</DialogFooter>
|
||||
</Questionnaire>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireCardQuestions() {
|
||||
const directionTitleId = React.useId()
|
||||
const signalsTitleId = React.useId()
|
||||
const timingTitleId = React.useId()
|
||||
|
||||
return (
|
||||
<>
|
||||
<QuestionnaireItem
|
||||
aria-labelledby={directionTitleId}
|
||||
name="direction"
|
||||
required
|
||||
>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={directionTitleId} render={<CardTitle />}>
|
||||
What should we prototype next?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Choose one direction or write another answer.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="delegation">
|
||||
<span className="font-medium">Sub-agent delegation</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show when work is delegated and what comes back.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="questions">
|
||||
<span className="font-medium">Question prompts</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show choices while the agent waits for input.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="both">
|
||||
<span className="font-medium">Both together</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Explore one unified interaction pattern.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireInput
|
||||
aria-label="Another direction"
|
||||
placeholder="Type another direction…"
|
||||
/>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem
|
||||
aria-labelledby={signalsTitleId}
|
||||
name="signals"
|
||||
multiple
|
||||
>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={signalsTitleId} render={<CardTitle />}>
|
||||
What should every progress update include?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Select all that apply, or skip this question.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="progress">
|
||||
Progress
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="decisions">
|
||||
Decisions
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="risks">Risks</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem aria-labelledby={timingTitleId} name="timing" required>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={timingTitleId} render={<CardTitle />}>
|
||||
When should this be revisited?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Choose when this should be revisited.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="week">This week</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="cycle">
|
||||
Next cycle
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="later">
|
||||
Revisit later
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireQuestions() {
|
||||
return (
|
||||
<>
|
||||
<QuestionnaireItem name="direction" required>
|
||||
<QuestionnaireTitle>What should we prototype next?</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Choose one direction or write another answer.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="delegation">
|
||||
<span className="font-medium">Sub-agent delegation</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show when work is delegated and what comes back.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="questions">
|
||||
<span className="font-medium">Question prompts</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show choices while the agent waits for input.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="both">
|
||||
<span className="font-medium">Both together</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Explore one unified interaction pattern.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireInput
|
||||
aria-label="Another direction"
|
||||
placeholder="Type another direction…"
|
||||
/>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem name="signals" multiple>
|
||||
<QuestionnaireTitle>
|
||||
What should every progress update include?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Select all that apply, or skip this question.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="progress">Progress</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="decisions">Decisions</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="risks">Risks</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem name="timing" required>
|
||||
<QuestionnaireTitle>When should this be revisited?</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Choose when this should be revisited.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="week">This week</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="cycle">Next cycle</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="later">Revisit later</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireNavigation() {
|
||||
return (
|
||||
<QuestionnaireActions className="w-full">
|
||||
<QuestionnairePrevious />
|
||||
<QuestionnaireSkip />
|
||||
<QuestionnaireNext>Next</QuestionnaireNext>
|
||||
<QuestionnaireSubmit>Save answers</QuestionnaireSubmit>
|
||||
</QuestionnaireActions>
|
||||
)
|
||||
}
|
||||
|
||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
|
||||
const formData = new FormData(event.currentTarget)
|
||||
const values = {
|
||||
direction: formData.get("direction"),
|
||||
signals: formData.getAll("signals"),
|
||||
timing: formData.get("timing"),
|
||||
}
|
||||
|
||||
toast("Questionnaire submitted", {
|
||||
description: `Direction: ${values.direction ?? "None"} · Progress signals: ${values.signals.join(", ") || "None"} · Timing: ${values.timing ?? "None"}`,
|
||||
})
|
||||
}
|
||||
222
apps/v4/registry/bases/radix/examples/radio-group-example.tsx
Normal file
222
apps/v4/registry/bases/radix/examples/radio-group-example.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/radix/ui/radio-group"
|
||||
|
||||
export default function RadioGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<RadioGroupBasic />
|
||||
<RadioGroupWithDescriptions />
|
||||
<RadioGroupWithFieldSet />
|
||||
<RadioGroupGrid />
|
||||
<RadioGroupDisabled />
|
||||
<RadioGroupInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<RadioGroup defaultValue="comfortable">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="default" id="r1" />
|
||||
<FieldLabel htmlFor="r1" className="font-normal">
|
||||
Default
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="comfortable" id="r2" />
|
||||
<FieldLabel htmlFor="r2" className="font-normal">
|
||||
Comfortable
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="compact" id="r3" />
|
||||
<FieldLabel htmlFor="r3" className="font-normal">
|
||||
Compact
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupWithDescriptions() {
|
||||
return (
|
||||
<Example title="With Descriptions">
|
||||
<RadioGroup defaultValue="plus">
|
||||
<FieldLabel htmlFor="plus-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Plus</div>
|
||||
<FieldDescription>
|
||||
For individuals and small teams
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="plus" id="plus-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="pro-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Pro</div>
|
||||
<FieldDescription>For growing businesses</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="pro" id="pro-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="enterprise-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Enterprise</div>
|
||||
<FieldDescription>
|
||||
For large teams and enterprises
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="enterprise" id="enterprise-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupWithFieldSet() {
|
||||
return (
|
||||
<Example title="With FieldSet">
|
||||
<FieldSet>
|
||||
<FieldLegend>Battery Level</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose your preferred battery level.
|
||||
</FieldDescription>
|
||||
<RadioGroup defaultValue="medium">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="high" id="battery-high" />
|
||||
<FieldLabel htmlFor="battery-high" className="font-normal">
|
||||
High
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="battery-medium" />
|
||||
<FieldLabel htmlFor="battery-medium" className="font-normal">
|
||||
Medium
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="low" id="battery-low" />
|
||||
<FieldLabel htmlFor="battery-low" className="font-normal">
|
||||
Low
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupGrid() {
|
||||
return (
|
||||
<Example title="Grid Layout">
|
||||
<RadioGroup defaultValue="medium" className="grid grid-cols-2 gap-2">
|
||||
<FieldLabel htmlFor="size-small">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="small" id="size-small" />
|
||||
<div className="font-medium">Small</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-medium">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="size-medium" />
|
||||
<div className="font-medium">Medium</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-large">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="large" id="size-large" />
|
||||
<div className="font-medium">Large</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-xlarge">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="xlarge" id="size-xlarge" />
|
||||
<div className="font-medium">X-Large</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<RadioGroup defaultValue="option2" disabled>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option1" id="disabled-1" />
|
||||
<FieldLabel htmlFor="disabled-1" className="font-normal">
|
||||
Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option2" id="disabled-2" />
|
||||
<FieldLabel htmlFor="disabled-2" className="font-normal">
|
||||
Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option3" id="disabled-3" />
|
||||
<FieldLabel htmlFor="disabled-3" className="font-normal">
|
||||
Option 3
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<FieldSet>
|
||||
<FieldLegend>Notification Preferences</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose how you want to receive notifications.
|
||||
</FieldDescription>
|
||||
<RadioGroup defaultValue="email">
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="email" id="invalid-email" aria-invalid />
|
||||
<FieldLabel htmlFor="invalid-email" className="font-normal">
|
||||
Email only
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="sms" id="invalid-sms" aria-invalid />
|
||||
<FieldLabel htmlFor="invalid-sms" className="font-normal">
|
||||
SMS only
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="both" id="invalid-both" aria-invalid />
|
||||
<FieldLabel htmlFor="invalid-both" className="font-normal">
|
||||
Both Email & SMS
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
158
apps/v4/registry/bases/radix/examples/resizable-example.tsx
Normal file
158
apps/v4/registry/bases/radix/examples/resizable-example.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type { Layout } from "react-resizable-panels"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from "@/registry/bases/radix/ui/resizable"
|
||||
|
||||
export default function ResizableExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ResizableHorizontal />
|
||||
<ResizableVertical />
|
||||
<ResizableWithHandle />
|
||||
<ResizableNested />
|
||||
<ResizableControlled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border style-lyra:rounded-none style-sera:rounded-none"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Sidebar</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ResizablePanelGroup
|
||||
orientation="vertical"
|
||||
className="min-h-[200px] rounded-lg border style-lyra:rounded-none style-sera:rounded-none"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Header</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableWithHandle() {
|
||||
return (
|
||||
<Example title="With Handle">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border style-lyra:rounded-none style-sera:rounded-none"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Sidebar</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableNested() {
|
||||
return (
|
||||
<Example title="Nested">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="rounded-lg border style-lyra:rounded-none style-sera:rounded-none"
|
||||
>
|
||||
<ResizablePanel defaultSize="50%">
|
||||
<div className="flex h-[200px] items-center justify-center p-6">
|
||||
<span className="font-semibold">One</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="50%">
|
||||
<ResizablePanelGroup orientation="vertical">
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Two</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Three</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableControlled() {
|
||||
const [layout, setLayout] = React.useState<Layout>({})
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border style-lyra:rounded-none style-sera:rounded-none"
|
||||
onLayoutChange={setLayout}
|
||||
>
|
||||
<ResizablePanel defaultSize="30%" id="left" minSize="20%">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
|
||||
<span className="font-semibold">
|
||||
{Math.round(layout.left ?? 30)}%
|
||||
</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="70%" id="right" minSize="30%">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
|
||||
<span className="font-semibold">
|
||||
{Math.round(layout.right ?? 70)}%
|
||||
</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import * as React from "react"
|
||||
import Image from "next/image"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { ScrollArea, ScrollBar } from "@/registry/bases/radix/ui/scroll-area"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
const tags = Array.from({ length: 50 }).map(
|
||||
(_, i, a) => `v1.2.0-beta.${a.length - i}`
|
||||
)
|
||||
|
||||
const works = [
|
||||
{
|
||||
artist: "Ornella Binni",
|
||||
art: "https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
{
|
||||
artist: "Tom Byrom",
|
||||
art: "https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
{
|
||||
artist: "Vladimir Malyav",
|
||||
art: "https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
] as const
|
||||
|
||||
export default function ScrollAreaExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ScrollAreaVertical />
|
||||
<ScrollAreaHorizontal />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ScrollAreaVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ScrollArea className="mx-auto h-72 w-48 overflow-hidden rounded-md border style-lyra:rounded-none style-maia:rounded-2xl style-luma:rounded-2xl style-sera:rounded-none style-rhea:rounded-2xl">
|
||||
<div className="p-4">
|
||||
<h4 className="mb-4 text-sm leading-none font-medium">Tags</h4>
|
||||
{tags.map((tag) => (
|
||||
<React.Fragment key={tag}>
|
||||
<div className="text-sm">{tag}</div>
|
||||
<Separator className="my-2" />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ScrollAreaHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<ScrollArea className="mx-auto w-full max-w-96 overflow-hidden rounded-md border p-4 **:data-[slot=scroll-area-viewport]:rounded-md style-lyra:rounded-none style-lyra:**:data-[slot=scroll-area-viewport]:rounded-none style-maia:rounded-2xl style-luma:rounded-2xl style-sera:rounded-none style-sera:**:data-[slot=scroll-area-viewport]:rounded-none style-rhea:rounded-2xl">
|
||||
<div className="flex gap-4">
|
||||
{works.map((artwork) => (
|
||||
<figure key={artwork.artist} className="shrink-0">
|
||||
<div className="overflow-hidden rounded-md style-lyra:rounded-none style-sera:rounded-none">
|
||||
<Image
|
||||
src={artwork.art}
|
||||
alt={`Photo by ${artwork.artist}`}
|
||||
className="aspect-3/4 h-fit w-fit object-cover"
|
||||
width={300}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
<figcaption className="pt-2 text-xs text-muted-foreground">
|
||||
Photo by{" "}
|
||||
<span className="font-semibold text-foreground">
|
||||
{artwork.artist}
|
||||
</span>
|
||||
</figcaption>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
554
apps/v4/registry/bases/radix/examples/select-example.tsx
Normal file
554
apps/v4/registry/bases/radix/examples/select-example.tsx
Normal file
@@ -0,0 +1,554 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/radix/ui/dialog"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/radix/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SelectExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SelectBasic />
|
||||
<SelectWithIcons />
|
||||
<SelectWithGroups />
|
||||
<SelectLargeList />
|
||||
<SelectSizes />
|
||||
<SelectPlan />
|
||||
<SelectWithButton />
|
||||
<SelectItemAligned />
|
||||
<SelectWithField />
|
||||
<SelectInvalid />
|
||||
<SelectInline />
|
||||
<SelectDisabled />
|
||||
<SelectInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes" disabled>
|
||||
Grapes
|
||||
</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue
|
||||
placeholder={
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Chart Type
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="line">
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartBarIcon"
|
||||
remixicon="RiBarChartLine"
|
||||
/>
|
||||
Line
|
||||
</SelectItem>
|
||||
<SelectItem value="bar">
|
||||
<IconPlaceholder
|
||||
lucide="ChartBarIcon"
|
||||
tabler="IconChartBar"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartBarIcon"
|
||||
remixicon="RiBarChartLine"
|
||||
/>
|
||||
Bar
|
||||
</SelectItem>
|
||||
<SelectItem value="pie">
|
||||
<IconPlaceholder
|
||||
lucide="ChartPieIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
Pie
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select>
|
||||
<SelectTrigger size="default">
|
||||
<SelectValue
|
||||
placeholder={
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Chart Type
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="line">
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Line
|
||||
</SelectItem>
|
||||
<SelectItem value="bar">
|
||||
<IconPlaceholder
|
||||
lucide="ChartBarIcon"
|
||||
tabler="IconChartBar"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartBarIcon"
|
||||
remixicon="RiBarChartLine"
|
||||
/>
|
||||
Bar
|
||||
</SelectItem>
|
||||
<SelectItem value="pie">
|
||||
<IconPlaceholder
|
||||
lucide="ChartPieIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
Pie
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithGroups() {
|
||||
return (
|
||||
<Example title="With Groups & Labels">
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Fruits</SelectLabel>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<SelectGroup>
|
||||
<SelectLabel>Vegetables</SelectLabel>
|
||||
<SelectItem value="carrot">Carrot</SelectItem>
|
||||
<SelectItem value="broccoli">Broccoli</SelectItem>
|
||||
<SelectItem value="spinach">Spinach</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLargeList() {
|
||||
return (
|
||||
<Example title="Large List">
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select an item" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{Array.from({ length: 100 }).map((_, i) => (
|
||||
<SelectItem key={i} value={`item-${i}`}>
|
||||
Item {i}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue placeholder="Small size" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select>
|
||||
<SelectTrigger size="default">
|
||||
<SelectValue placeholder="Default size" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithButton() {
|
||||
return (
|
||||
<Example title="With Button">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Select>
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue placeholder="Small" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Default" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline">Submit</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItemAligned() {
|
||||
return (
|
||||
<Example title="Popper">
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent position="popper">
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes" disabled>
|
||||
Grapes
|
||||
</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithField() {
|
||||
return (
|
||||
<Example title="With Field">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-fruit">Favorite Fruit</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="select-fruit">
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes">Grapes</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
Choose your favorite fruit from the list.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select>
|
||||
<SelectTrigger aria-invalid="true">
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes">Grapes</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="select-fruit-invalid">Favorite Fruit</FieldLabel>
|
||||
<Select>
|
||||
<SelectTrigger id="select-fruit-invalid" aria-invalid>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes">Grapes</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldError errors={[{ message: "Please select a valid fruit." }]} />
|
||||
</Field>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInline() {
|
||||
return (
|
||||
<Example title="Inline with Input & NativeSelect">
|
||||
<div className="flex items-center gap-2">
|
||||
<Input placeholder="Search..." className="flex-1" />
|
||||
<Select>
|
||||
<SelectTrigger className="w-[140px]">
|
||||
<SelectValue placeholder="Filter" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="all">All</SelectItem>
|
||||
<SelectItem value="active">Active</SelectItem>
|
||||
<SelectItem value="inactive">Inactive</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<NativeSelect className="w-[140px]">
|
||||
<NativeSelectOption value="">Sort by</NativeSelectOption>
|
||||
<NativeSelectOption value="name">Name</NativeSelectOption>
|
||||
<NativeSelectOption value="date">Date</NativeSelectOption>
|
||||
<NativeSelectOption value="status">Status</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Select disabled>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Disabled" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes" disabled>
|
||||
Grapes
|
||||
</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const plans = [
|
||||
{
|
||||
name: "Starter",
|
||||
description: "Perfect for individuals getting started.",
|
||||
},
|
||||
{
|
||||
name: "Professional",
|
||||
description: "Ideal for growing teams and businesses.",
|
||||
},
|
||||
{
|
||||
name: "Enterprise",
|
||||
description: "Advanced features for large organizations.",
|
||||
},
|
||||
]
|
||||
|
||||
function SelectPlan() {
|
||||
const [plan, setPlan] = React.useState<string>(plans[0].name)
|
||||
|
||||
const selectedPlan = plans.find((p) => p.name === plan)
|
||||
|
||||
return (
|
||||
<Example title="Subscription Plan">
|
||||
<Select value={plan} onValueChange={setPlan}>
|
||||
<SelectTrigger className="h-auto! w-72">
|
||||
<SelectValue>
|
||||
{selectedPlan && <SelectPlanItem plan={selectedPlan} />}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{plans.map((plan) => (
|
||||
<SelectItem key={plan.name} value={plan.name}>
|
||||
<SelectPlanItem plan={plan} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectPlanItem({ plan }: { plan: (typeof plans)[number] }) {
|
||||
return (
|
||||
<Item size="xs" className="w-full p-0">
|
||||
<ItemContent className="gap-0 normal-case">
|
||||
<ItemTitle className="font-sans">{plan.name}</ItemTitle>
|
||||
<ItemDescription className="text-xs font-normal tracking-normal">
|
||||
{plan.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Select Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use the select below to choose a fruit.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
<SelectItem value="blueberry">Blueberry</SelectItem>
|
||||
<SelectItem value="grapes">Grapes</SelectItem>
|
||||
<SelectItem value="pineapple">Pineapple</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
100
apps/v4/registry/bases/radix/examples/separator-example.tsx
Normal file
100
apps/v4/registry/bases/radix/examples/separator-example.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Separator } from "@/registry/bases/radix/ui/separator"
|
||||
|
||||
export default function SeparatorExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SeparatorHorizontal />
|
||||
<SeparatorVertical />
|
||||
<SeparatorVerticalMenu />
|
||||
<SeparatorInList />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<div className="flex flex-col gap-4 text-sm style-lyra:text-xs/relaxed">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="leading-none font-medium">shadcn/ui</div>
|
||||
<div className="text-muted-foreground">
|
||||
The Foundation for your Design System
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div>
|
||||
A set of beautifully designed components that you can customize,
|
||||
extend, and build on.
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex h-5 items-center gap-4 text-sm style-lyra:text-xs/relaxed">
|
||||
<div>Blog</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div>Docs</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div>Source</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorVerticalMenu() {
|
||||
return (
|
||||
<Example title="Vertical Menu">
|
||||
<div className="flex items-center gap-2 text-sm md:gap-4 style-lyra:text-xs/relaxed">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Settings</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Manage preferences
|
||||
</span>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Account</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Profile & security
|
||||
</span>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Help</span>
|
||||
<span className="text-xs text-muted-foreground">Support & docs</span>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorInList() {
|
||||
return (
|
||||
<Example title="In List">
|
||||
<div className="flex flex-col gap-2 text-sm style-lyra:text-xs/relaxed">
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 1</dt>
|
||||
<dd className="text-muted-foreground">Value 1</dd>
|
||||
</dl>
|
||||
<Separator />
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 2</dt>
|
||||
<dd className="text-muted-foreground">Value 2</dd>
|
||||
</dl>
|
||||
<Separator />
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 3</dt>
|
||||
<dd className="text-muted-foreground">Value 3</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
145
apps/v4/registry/bases/radix/examples/sheet-example.tsx
Normal file
145
apps/v4/registry/bases/radix/examples/sheet-example.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/registry/bases/radix/ui/sheet"
|
||||
|
||||
export default function SheetExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SheetWithForm />
|
||||
<SheetNoCloseButton />
|
||||
<SheetWithSides />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SheetWithForm() {
|
||||
return (
|
||||
<Example title="With Form">
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline">Open</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit profile</SheetTitle>
|
||||
<SheetDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="style-vega:px-4 style-nova:px-4 style-lyra:px-4 style-maia:px-6 style-mira:px-6 style-luma:px-6 style-sera:px-8 style-rhea:px-6">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="sheet-demo-name">Name</FieldLabel>
|
||||
<Input id="sheet-demo-name" defaultValue="Pedro Duarte" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="sheet-demo-username">Username</FieldLabel>
|
||||
<Input id="sheet-demo-username" defaultValue="@peduarte" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button type="submit">Save changes</Button>
|
||||
<SheetClose asChild>
|
||||
<Button variant="outline">Close</Button>
|
||||
</SheetClose>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SheetNoCloseButton() {
|
||||
return (
|
||||
<Example title="No Close Button">
|
||||
<Sheet>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="outline">No Close Button</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent showCloseButton={false}>
|
||||
<SheetHeader>
|
||||
<SheetTitle>No Close Button</SheetTitle>
|
||||
<SheetDescription>
|
||||
This sheet doesn't have a close button in the top-right
|
||||
corner. You can only close it using the button below.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const SHEET_SIDES = ["top", "right", "bottom", "left"] as const
|
||||
|
||||
function SheetWithSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{SHEET_SIDES.map((side) => (
|
||||
<Sheet key={side}>
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="capitalize style-sera:uppercase"
|
||||
>
|
||||
{side}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent
|
||||
side={side}
|
||||
className="data-[side=bottom]:max-h-[50vh] data-[side=top]:max-h-[50vh]"
|
||||
>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit profile</SheetTitle>
|
||||
<SheetDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="no-scrollbar overflow-y-auto style-vega:px-4 style-nova:px-4 style-lyra:px-4 style-maia:px-6 style-mira:px-6 style-luma:px-6 style-sera:px-8 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed style-sera:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia
|
||||
deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button type="submit">Save changes</Button>
|
||||
<SheetClose asChild>
|
||||
<Button variant="outline">Cancel</Button>
|
||||
</SheetClose>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
286
apps/v4/registry/bases/radix/examples/sidebar-example.tsx
Normal file
286
apps/v4/registry/bases/radix/examples/sidebar-example.tsx
Normal file
@@ -0,0 +1,286 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarExample() {
|
||||
const data = {
|
||||
versions: ["1.0.1", "1.1.0-alpha", "2.0.0-beta1"],
|
||||
navMain: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Installation",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Project Structure",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Build Your Application",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Routing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Data Fetching",
|
||||
url: "#",
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Rendering",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Caching",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Styling",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Optimizing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Configuring",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Testing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Authentication",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Deploying",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Upgrading",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Examples",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "API Reference",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Components",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "File Conventions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Functions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "next.config.js Options",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "CLI",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Edge Runtime",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Architecture",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Accessibility",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Fast Refresh",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Next.js Compiler",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Supported Browsers",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Turbopack",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const [selectedVersion, setSelectedVersion] = React.useState(data.versions[0])
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar>
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Item className="p-0" size="xs">
|
||||
<ItemContent>
|
||||
<ItemTitle className="text-sm">Documentation</ItemTitle>
|
||||
<ItemDescription>v{selectedVersion}</ItemDescription>
|
||||
</ItemContent>
|
||||
<ItemActions>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
{data.versions.map((version) => (
|
||||
<DropdownMenuItem
|
||||
key={version}
|
||||
onSelect={() => setSelectedVersion(version)}
|
||||
>
|
||||
v{version}{" "}
|
||||
{version === selectedVersion && (
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
className="ml-auto"
|
||||
/>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
<form>
|
||||
<SidebarGroup className="py-0">
|
||||
<SidebarGroupContent className="relative">
|
||||
<Label htmlFor="search" className="sr-only">
|
||||
Search
|
||||
</Label>
|
||||
<SidebarInput
|
||||
id="search"
|
||||
placeholder="Search the docs..."
|
||||
className="pl-8"
|
||||
/>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
className="pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"
|
||||
/>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</form>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
{data.navMain.map((item) => (
|
||||
<SidebarGroup key={item.title}>
|
||||
<SidebarGroupLabel>{item.title}</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{item.items.map((subItem) => (
|
||||
<SidebarMenuItem key={subItem.title}>
|
||||
<SidebarMenuButton asChild isActive={subItem.isActive}>
|
||||
<a href={subItem.url}>{subItem.title}</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
))}
|
||||
</SidebarContent>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/radix/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Field } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarFloatingExample() {
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Installation",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Project Structure",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Build Your Application",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Routing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Data Fetching",
|
||||
url: "#",
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Rendering",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Caching",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Styling",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Optimizing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Configuring",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Testing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Authentication",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Deploying",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Upgrading",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Examples",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "API Reference",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Components",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "File Conventions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Functions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "next.config.js Options",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "CLI",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Edge Runtime",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Architecture",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Accessibility",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Fast Refresh",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Next.js Compiler",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Supported Browsers",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Turbopack",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider className="bg-background">
|
||||
<Sidebar variant="floating">
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton size="lg" asChild>
|
||||
<a href="#">
|
||||
<Item className="p-0" size="xs">
|
||||
<ItemContent>
|
||||
<ItemTitle className="text-sm">Documentation</ItemTitle>
|
||||
<ItemDescription>v1.0.0</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<DropdownMenu key={item.title}>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
||||
{item.title}{" "}
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
className="ml-auto"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
{item.items?.length ? (
|
||||
<DropdownMenuContent side="right" align="start">
|
||||
<DropdownMenuGroup>
|
||||
{item.items.map((subItem) => (
|
||||
<DropdownMenuItem asChild key={subItem.title}>
|
||||
<a href={subItem.url}>{subItem.title}</a>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
) : null}
|
||||
</SidebarMenuItem>
|
||||
</DropdownMenu>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<SidebarGroup className="pb-1">
|
||||
<Card size="sm" className="-mx-1">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm">
|
||||
Subscribe to our newsletter
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Opt-in to receive updates and news about the sidebar.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<Field>
|
||||
<SidebarInput type="email" placeholder="Email" />
|
||||
<Button
|
||||
className="w-full bg-sidebar-primary text-sidebar-primary-foreground"
|
||||
size="sm"
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
</Field>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</SidebarGroup>
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
461
apps/v4/registry/bases/radix/examples/sidebar-icon-example.tsx
Normal file
461
apps/v4/registry/bases/radix/examples/sidebar-icon-example.tsx
Normal file
@@ -0,0 +1,461 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/radix/ui/avatar"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/radix/ui/collapsible"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/radix/ui/item"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarIconExample() {
|
||||
const data = {
|
||||
user: {
|
||||
name: "shadcn",
|
||||
email: "m@example.com",
|
||||
avatar: "/avatars/shadcn.jpg",
|
||||
},
|
||||
teams: [
|
||||
{
|
||||
name: "Acme Inc",
|
||||
plan: "Enterprise",
|
||||
},
|
||||
{
|
||||
name: "Acme Corp.",
|
||||
plan: "Startup",
|
||||
},
|
||||
{
|
||||
name: "Evil Corp.",
|
||||
plan: "Free",
|
||||
},
|
||||
],
|
||||
navMain: [
|
||||
{
|
||||
title: "Playground",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="TerminalSquareIcon"
|
||||
tabler="IconTerminal2"
|
||||
hugeicons="ComputerTerminalIcon"
|
||||
phosphor="TerminalIcon"
|
||||
remixicon="RiTerminalBoxLine"
|
||||
/>
|
||||
),
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "History",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Starred",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Models",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="BotIcon"
|
||||
tabler="IconRobot"
|
||||
hugeicons="RoboticIcon"
|
||||
phosphor="RobotIcon"
|
||||
remixicon="RiRobotLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Genesis",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Explorer",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Quantum",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Documentation",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="BookOpen"
|
||||
tabler="IconBook"
|
||||
hugeicons="BookOpen02Icon"
|
||||
phosphor="BookOpenIcon"
|
||||
remixicon="RiBookOpenLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Introduction",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Get Started",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Tutorials",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Changelog",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Settings2Icon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings05Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "General",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Team",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Billing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Limits",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
name: "Design Engineering",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="FrameIcon"
|
||||
tabler="IconFrame"
|
||||
hugeicons="CropIcon"
|
||||
phosphor="CropIcon"
|
||||
remixicon="RiCropLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Sales & Marketing",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="PieChartIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="PieChartIcon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Travel",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="MapIcon"
|
||||
tabler="IconMap"
|
||||
hugeicons="MapsIcon"
|
||||
phosphor="MapTrifoldIcon"
|
||||
remixicon="RiMapLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const [activeTeam, setActiveTeam] = React.useState(data.teams[0])
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar collapsible="icon">
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Button size="icon-sm" asChild className="size-8">
|
||||
<span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<rect width="256" height="256" fill="none"></rect>
|
||||
<line
|
||||
x1="208"
|
||||
y1="128"
|
||||
x2="128"
|
||||
y2="208"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="32"
|
||||
></line>
|
||||
<line
|
||||
x1="192"
|
||||
y1="40"
|
||||
x2="40"
|
||||
y2="192"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="32"
|
||||
></line>
|
||||
</svg>
|
||||
</span>
|
||||
</Button>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">
|
||||
{activeTeam.name}
|
||||
</span>
|
||||
<span className="truncate text-xs">
|
||||
{activeTeam.plan}
|
||||
</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Teams</DropdownMenuLabel>
|
||||
{data.teams.map((team) => (
|
||||
<DropdownMenuItem
|
||||
key={team.name}
|
||||
onClick={() => setActiveTeam(team)}
|
||||
>
|
||||
{team.name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Platform</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<Collapsible
|
||||
key={item.title}
|
||||
asChild
|
||||
defaultOpen={item.isActive}
|
||||
className="group/collapsible"
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton tooltip={item.title} asChild>
|
||||
<CollapsibleTrigger>
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="ml-auto transition-transform duration-100 group-data-open/collapsible:rotate-90"
|
||||
/>
|
||||
</CollapsibleTrigger>
|
||||
</SidebarMenuButton>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.items?.map((subItem) => (
|
||||
<SidebarMenuSubItem key={subItem.title}>
|
||||
<SidebarMenuSubButton asChild>
|
||||
<a href={subItem.url}>{subItem.title}</a>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
||||
<SidebarGroupLabel>Projects</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.projects.map((item) => (
|
||||
<SidebarMenuItem key={item.name}>
|
||||
<SidebarMenuButton asChild>
|
||||
<a href={item.url}>
|
||||
{item.icon}
|
||||
{item.name}
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src={data.user.avatar}
|
||||
alt={data.user.name}
|
||||
/>
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">
|
||||
{data.user.name}
|
||||
</span>
|
||||
<span className="truncate text-xs">
|
||||
{data.user.email}
|
||||
</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>
|
||||
<Item size="xs">
|
||||
<ItemMedia>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src={data.user.avatar}
|
||||
alt={data.user.name}
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{data.user.name}</ItemTitle>
|
||||
<ItemDescription> {data.user.email}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</DropdownMenuLabel>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Account</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Log out</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
292
apps/v4/registry/bases/radix/examples/sidebar-inset-example.tsx
Normal file
292
apps/v4/registry/bases/radix/examples/sidebar-inset-example.tsx
Normal file
@@ -0,0 +1,292 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/radix/ui/collapsible"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuAction,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/radix/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarInsetExample() {
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Dashboard",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="Home01Icon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
),
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "Overview",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Analytics",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Analytics",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="ChartIcon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Reports",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Metrics",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Orders",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingBagIcon"
|
||||
tabler="IconShoppingBag"
|
||||
hugeicons="ShoppingBag01Icon"
|
||||
phosphor="BagIcon"
|
||||
remixicon="RiShoppingBagLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "All Orders",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Pending",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Completed",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Products",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingCartIcon"
|
||||
tabler="IconShoppingCart"
|
||||
hugeicons="ShoppingCart01Icon"
|
||||
phosphor="ShoppingCartIcon"
|
||||
remixicon="RiShoppingCartLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "All Products",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Categories",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Invoices",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Customers",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Settings2Icon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings05Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
navSecondary: [
|
||||
{
|
||||
title: "Support",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="LifeBuoy"
|
||||
tabler="IconLifebuoy"
|
||||
hugeicons="ChartRingIcon"
|
||||
phosphor="LifebuoyIcon"
|
||||
remixicon="RiLifebuoyLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Feedback",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Send"
|
||||
tabler="IconSend"
|
||||
hugeicons="SentIcon"
|
||||
phosphor="PaperPlaneTiltIcon"
|
||||
remixicon="RiSendPlaneLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar variant="inset">
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Dashboard</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<Collapsible
|
||||
key={item.title}
|
||||
asChild
|
||||
defaultOpen={item.isActive}
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
tooltip={item.title}
|
||||
isActive={item.isActive}
|
||||
>
|
||||
<a href={item.url}>
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
{item.items?.length ? (
|
||||
<>
|
||||
<CollapsibleTrigger asChild>
|
||||
<SidebarMenuAction className="data-[state=open]:rotate-90">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
<span className="sr-only">Toggle</span>
|
||||
</SidebarMenuAction>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.items.map((subItem) => (
|
||||
<SidebarMenuSubItem key={subItem.title}>
|
||||
<SidebarMenuSubButton asChild>
|
||||
<a href={subItem.url}>
|
||||
<span>{subItem.title}</span>
|
||||
</a>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</>
|
||||
) : null}
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
<SidebarGroup className="mt-auto">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{data.navSecondary.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<SidebarMenuButton asChild size="sm">
|
||||
<a href={item.url}>
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
102
apps/v4/registry/bases/radix/examples/skeleton-example.tsx
Normal file
102
apps/v4/registry/bases/radix/examples/skeleton-example.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Card, CardContent, CardHeader } from "@/registry/bases/radix/ui/card"
|
||||
import { Skeleton } from "@/registry/bases/radix/ui/skeleton"
|
||||
|
||||
export default function SkeletonExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SkeletonAvatar />
|
||||
<SkeletonCard />
|
||||
<SkeletonText />
|
||||
<SkeletonForm />
|
||||
<SkeletonTable />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonAvatar() {
|
||||
return (
|
||||
<Example title="Avatar">
|
||||
<div className="flex w-full items-center gap-4">
|
||||
<Skeleton className="size-10 shrink-0 rounded-full" />
|
||||
<div className="grid gap-2">
|
||||
<Skeleton className="h-4 w-[150px]" />
|
||||
<Skeleton className="h-4 w-[100px]" />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonCard() {
|
||||
return (
|
||||
<Example title="Card">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
<Skeleton className="h-4 w-1/2" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Skeleton className="aspect-square w-full" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonText() {
|
||||
return (
|
||||
<Example title="Text">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<div className="flex w-full flex-col gap-7">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Skeleton className="h-4 w-20" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
<Skeleton className="h-9 w-24" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonTable() {
|
||||
return (
|
||||
<Example title="Table">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
103
apps/v4/registry/bases/radix/examples/slider-example.tsx
Normal file
103
apps/v4/registry/bases/radix/examples/slider-example.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import { Slider } from "@/registry/bases/radix/ui/slider"
|
||||
|
||||
export default function SliderExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SliderBasic />
|
||||
<SliderRange />
|
||||
<SliderMultiple />
|
||||
<SliderVertical />
|
||||
<SliderControlled />
|
||||
<SliderDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Slider defaultValue={[50]} max={100} step={1} />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderRange() {
|
||||
return (
|
||||
<Example title="Range">
|
||||
<Slider defaultValue={[25, 50]} max={100} step={5} />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderMultiple() {
|
||||
return (
|
||||
<Example title="Multiple Thumbs">
|
||||
<Slider defaultValue={[10, 20, 70]} max={100} step={10} />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex items-center gap-6">
|
||||
<Slider
|
||||
defaultValue={[50]}
|
||||
max={100}
|
||||
step={1}
|
||||
orientation="vertical"
|
||||
className="h-40"
|
||||
/>
|
||||
<Slider
|
||||
defaultValue={[25]}
|
||||
max={100}
|
||||
step={1}
|
||||
orientation="vertical"
|
||||
className="h-40"
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderControlled() {
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<div className="grid w-full gap-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<Label htmlFor="slider-demo-temperature">Temperature</Label>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{value.join(", ")}
|
||||
</span>
|
||||
</div>
|
||||
<Slider
|
||||
id="slider-demo-temperature"
|
||||
value={value}
|
||||
onValueChange={setValue}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Slider defaultValue={[50]} max={100} step={1} disabled />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
50
apps/v4/registry/bases/radix/examples/sonner-example.tsx
Normal file
50
apps/v4/registry/bases/radix/examples/sonner-example.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
"use client"
|
||||
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
|
||||
export default function SonnerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SonnerBasic />
|
||||
<SonnerWithDescription />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SonnerBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center justify-center">
|
||||
<Button
|
||||
onClick={() => toast("Event has been created")}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Show Toast
|
||||
</Button>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SonnerWithDescription() {
|
||||
return (
|
||||
<Example title="With Description" className="items-center justify-center">
|
||||
<Button
|
||||
onClick={() =>
|
||||
toast("Event has been created", {
|
||||
description: "Monday, January 3rd at 6:00pm",
|
||||
})
|
||||
}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Show Toast
|
||||
</Button>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
147
apps/v4/registry/bases/radix/examples/spinner-example.tsx
Normal file
147
apps/v4/registry/bases/radix/examples/spinner-example.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Badge } from "@/registry/bases/radix/ui/badge"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/radix/ui/empty"
|
||||
import { Field, FieldLabel } from "@/registry/bases/radix/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/radix/ui/input-group"
|
||||
import { Spinner } from "@/registry/bases/radix/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SpinnerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SpinnerBasic />
|
||||
<SpinnerInButtons />
|
||||
<SpinnerInBadges />
|
||||
<SpinnerInInputGroup />
|
||||
<SpinnerInEmpty />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex items-center gap-6">
|
||||
<Spinner />
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInButtons() {
|
||||
return (
|
||||
<Example title="In Buttons">
|
||||
<div className="flex flex-wrap items-center gap-4">
|
||||
<Button>
|
||||
<Spinner data-icon="inline-start" /> Submit
|
||||
</Button>
|
||||
<Button disabled>
|
||||
<Spinner data-icon="inline-start" /> Disabled
|
||||
</Button>
|
||||
<Button variant="outline" disabled>
|
||||
<Spinner data-icon="inline-start" /> Outline
|
||||
</Button>
|
||||
<Button variant="outline" size="icon" disabled>
|
||||
<Spinner data-icon="inline-start" />
|
||||
<span className="sr-only">Loading...</span>
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInBadges() {
|
||||
return (
|
||||
<Example title="In Badges" className="items-center justify-center">
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<Badge>
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInInputGroup() {
|
||||
return (
|
||||
<Example title="In Input Group">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-spinner">Input Group</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-spinner" />
|
||||
<InputGroupAddon>
|
||||
<Spinner />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInEmpty() {
|
||||
return (
|
||||
<Example title="In Empty State" containerClassName="lg:col-span-full">
|
||||
<Empty className="min-h-[300px]">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<Spinner />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<Button asChild>
|
||||
<a href="#">Create project</a>
|
||||
</Button>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<Button variant="link" asChild className="text-muted-foreground">
|
||||
<a href="#">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</a>
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
102
apps/v4/registry/bases/radix/examples/switch-example.tsx
Normal file
102
apps/v4/registry/bases/radix/examples/switch-example.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Label } from "@/registry/bases/radix/ui/label"
|
||||
import { Switch } from "@/registry/bases/radix/ui/switch"
|
||||
|
||||
export default function SwitchExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SwitchBasic />
|
||||
<SwitchWithDescription />
|
||||
<SwitchWithLabel />
|
||||
<SwitchDisabled />
|
||||
<SwitchSizes />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-basic" />
|
||||
<FieldLabel htmlFor="switch-basic">Airplane Mode</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-bluetooth" defaultChecked />
|
||||
<Label htmlFor="switch-bluetooth">Bluetooth</Label>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<FieldLabel htmlFor="switch-focus-mode">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Share across devices</FieldTitle>
|
||||
<FieldDescription>
|
||||
Focus is shared across devices, and turns off when you leave the
|
||||
app.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-focus-mode" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<div className="flex flex-col gap-12">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-disabled-unchecked" disabled />
|
||||
<Label htmlFor="switch-disabled-unchecked">
|
||||
Disabled (Unchecked)
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-disabled-checked" defaultChecked disabled />
|
||||
<Label htmlFor="switch-disabled-checked">Disabled (Checked)</Label>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-12">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-size-sm" size="sm" />
|
||||
<Label htmlFor="switch-size-sm">Small</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-size-default" size="default" />
|
||||
<Label htmlFor="switch-size-default">Default</Label>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
478
apps/v4/registry/bases/radix/examples/table-example.tsx
Normal file
478
apps/v4/registry/bases/radix/examples/table-example.tsx
Normal file
@@ -0,0 +1,478 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/registry/bases/radix/ui/table"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const invoices = [
|
||||
{
|
||||
invoice: "INV001",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$250.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
{
|
||||
invoice: "INV002",
|
||||
paymentStatus: "Pending",
|
||||
totalAmount: "$150.00",
|
||||
paymentMethod: "PayPal",
|
||||
},
|
||||
{
|
||||
invoice: "INV003",
|
||||
paymentStatus: "Unpaid",
|
||||
totalAmount: "$350.00",
|
||||
paymentMethod: "Bank Transfer",
|
||||
},
|
||||
{
|
||||
invoice: "INV004",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$450.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
{
|
||||
invoice: "INV005",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$550.00",
|
||||
paymentMethod: "PayPal",
|
||||
},
|
||||
{
|
||||
invoice: "INV006",
|
||||
paymentStatus: "Pending",
|
||||
totalAmount: "$200.00",
|
||||
paymentMethod: "Bank Transfer",
|
||||
},
|
||||
{
|
||||
invoice: "INV007",
|
||||
paymentStatus: "Unpaid",
|
||||
totalAmount: "$300.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
]
|
||||
|
||||
export default function TableExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TableBasic />
|
||||
<TableWithFooter />
|
||||
<TableSimple />
|
||||
<TableWithBadges />
|
||||
<TableWithActions />
|
||||
<TableWithSelect />
|
||||
<TableWithInput />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TableBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Table>
|
||||
<TableCaption>A list of your recent invoices.</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Invoice</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Method</TableHead>
|
||||
<TableHead className="text-right">Amount</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{invoices.slice(0, 3).map((invoice) => (
|
||||
<TableRow key={invoice.invoice}>
|
||||
<TableCell className="font-medium">{invoice.invoice}</TableCell>
|
||||
<TableCell>{invoice.paymentStatus}</TableCell>
|
||||
<TableCell>{invoice.paymentMethod}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{invoice.totalAmount}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithFooter() {
|
||||
return (
|
||||
<Example title="With Footer">
|
||||
<Table>
|
||||
<TableCaption>A list of your recent invoices.</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Invoice</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Method</TableHead>
|
||||
<TableHead className="text-right">Amount</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{invoices.slice(0, 3).map((invoice) => (
|
||||
<TableRow key={invoice.invoice}>
|
||||
<TableCell className="font-medium">{invoice.invoice}</TableCell>
|
||||
<TableCell>{invoice.paymentStatus}</TableCell>
|
||||
<TableCell>{invoice.paymentMethod}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{invoice.totalAmount}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3}>Total</TableCell>
|
||||
<TableCell className="text-right">$2,500.00</TableCell>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead className="text-right">Role</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Sarah Chen</TableCell>
|
||||
<TableCell>sarah.chen@acme.com</TableCell>
|
||||
<TableCell className="text-right">Admin</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Marc Rodriguez</TableCell>
|
||||
<TableCell>marcus.rodriguez@acme.com</TableCell>
|
||||
<TableCell className="text-right">User</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Emily Watson</TableCell>
|
||||
<TableCell>emily.watson@acme.com</TableCell>
|
||||
<TableCell className="text-right">User</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithBadges() {
|
||||
return (
|
||||
<Example title="With Badges">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Task</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="text-right">Priority</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Design homepage</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-green-500/10 px-2 py-1 text-xs font-medium text-green-700 dark:text-green-400">
|
||||
Completed
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-blue-500/10 px-2 py-1 text-xs font-medium text-blue-700 dark:text-blue-400">
|
||||
High
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Implement API</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-yellow-500/10 px-2 py-1 text-xs font-medium text-yellow-700 dark:text-yellow-400">
|
||||
In Progress
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Medium
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Write tests</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Pending
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Low
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithActions() {
|
||||
return (
|
||||
<Example title="With Actions">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Product</TableHead>
|
||||
<TableHead>Price</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Wireless Mouse</TableCell>
|
||||
<TableCell>$29.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
|
||||
<TableCell>$129.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">USB-C Hub</TableCell>
|
||||
<TableCell>$49.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithSelect() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Task</TableHead>
|
||||
<TableHead>Assignee</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Design homepage</TableCell>
|
||||
<TableCell>
|
||||
<Select defaultValue="sarah">
|
||||
<SelectTrigger className="w-40" size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="sarah">Sarah Chen</SelectItem>
|
||||
<SelectItem value="marcus">Marc Rodriguez</SelectItem>
|
||||
<SelectItem value="emily">Emily Watson</SelectItem>
|
||||
<SelectItem value="david">David Kim</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell>In Progress</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Implement API</TableCell>
|
||||
<TableCell>
|
||||
<Select defaultValue="marcus">
|
||||
<SelectTrigger className="w-40" size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="sarah">Sarah Chen</SelectItem>
|
||||
<SelectItem value="marcus">Marc Rodriguez</SelectItem>
|
||||
<SelectItem value="emily">Emily Watson</SelectItem>
|
||||
<SelectItem value="david">David Kim</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell>Pending</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Write tests</TableCell>
|
||||
<TableCell>
|
||||
<Select defaultValue="emily">
|
||||
<SelectTrigger className="w-40" size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="sarah">Sarah Chen</SelectItem>
|
||||
<SelectItem value="marcus">Marc Rodriguez</SelectItem>
|
||||
<SelectItem value="emily">Emily Watson</SelectItem>
|
||||
<SelectItem value="david">David Kim</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell>Not Started</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Product</TableHead>
|
||||
<TableHead>Quantity</TableHead>
|
||||
<TableHead>Price</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Wireless Mouse</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="1"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$29.99</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="2"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$129.99</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">USB-C Hub</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="1"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$49.99</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
361
apps/v4/registry/bases/radix/examples/tabs-example.tsx
Normal file
361
apps/v4/registry/bases/radix/examples/tabs-example.tsx
Normal file
@@ -0,0 +1,361 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/radix/ui/dropdown-menu"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/bases/radix/ui/tabs"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function TabsExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TabsBasic />
|
||||
<TabsLine />
|
||||
<TabsVariantsComparison />
|
||||
<TabsDisabled />
|
||||
<TabsWithIcons />
|
||||
<TabsIconOnly />
|
||||
<TabsMultiple />
|
||||
<TabsWithContent />
|
||||
<TabsLineWithContent />
|
||||
<TabsLineDisabled />
|
||||
<TabsWithDropdown />
|
||||
<TabsVertical />
|
||||
<TabsWithInputAndButton />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Tabs defaultValue="home">
|
||||
<TabsList>
|
||||
<TabsTrigger value="home">Home</TabsTrigger>
|
||||
<TabsTrigger value="settings">Settings</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLine() {
|
||||
return (
|
||||
<Example title="Line">
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger value="reports">Reports</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsVariantsComparison() {
|
||||
return (
|
||||
<Example title="Variants Alignment">
|
||||
<div className="flex gap-4">
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Tabs defaultValue="home">
|
||||
<TabsList>
|
||||
<TabsTrigger value="home">Home</TabsTrigger>
|
||||
<TabsTrigger value="settings" disabled>
|
||||
Disabled
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<Tabs defaultValue="preview">
|
||||
<TabsList>
|
||||
<TabsTrigger value="preview">
|
||||
<IconPlaceholder
|
||||
lucide="AppWindowIcon"
|
||||
tabler="IconAppWindow"
|
||||
hugeicons="CursorInWindowIcon"
|
||||
phosphor="AppWindowIcon"
|
||||
remixicon="RiWindowLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Preview
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="code">
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Code
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsIconOnly() {
|
||||
return (
|
||||
<Example title="Icon Only">
|
||||
<Tabs defaultValue="home">
|
||||
<TabsList>
|
||||
<TabsTrigger value="home">
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="HomeIcon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="search">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger value="reports">Reports</TabsTrigger>
|
||||
<TabsTrigger value="settings">Settings</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithContent() {
|
||||
return (
|
||||
<Example title="With Content">
|
||||
<Tabs defaultValue="account">
|
||||
<TabsList>
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
<TabsTrigger value="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-sera:rounded-none style-sera:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent value="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent value="password">
|
||||
Update your password to keep your account secure.
|
||||
</TabsContent>
|
||||
<TabsContent value="notifications">
|
||||
Configure how you receive notifications and alerts.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLineWithContent() {
|
||||
return (
|
||||
<Example title="Line With Content">
|
||||
<Tabs defaultValue="account">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
<TabsTrigger value="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-sera:rounded-none style-sera:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent value="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent value="password">
|
||||
Update your password to keep your account secure.
|
||||
</TabsContent>
|
||||
<TabsContent value="notifications">
|
||||
Configure how you receive notifications and alerts.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLineDisabled() {
|
||||
return (
|
||||
<Example title="Line Disabled">
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger value="reports" disabled>
|
||||
Reports
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown">
|
||||
<Tabs defaultValue="overview">
|
||||
<div className="flex items-center justify-between">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger value="reports">Reports</TabsTrigger>
|
||||
</TabsList>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">More options</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
<DropdownMenuItem>Export</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Archive</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-sera:rounded-none style-sera:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent value="overview">
|
||||
View your dashboard metrics and key performance indicators.
|
||||
</TabsContent>
|
||||
<TabsContent value="analytics">
|
||||
Detailed analytics and insights about your data.
|
||||
</TabsContent>
|
||||
<TabsContent value="reports">
|
||||
Generate and view custom reports.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<Tabs defaultValue="account" orientation="vertical">
|
||||
<TabsList>
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
<TabsTrigger value="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-sera:rounded-none style-sera:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent value="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent value="password">
|
||||
Update your password to keep your account secure. Use a strong
|
||||
password with a mix of letters, numbers, and symbols.
|
||||
</TabsContent>
|
||||
<TabsContent value="notifications">
|
||||
Configure how you receive notifications and alerts. Choose which
|
||||
types of notifications you want to receive and how you want to
|
||||
receive them.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithInputAndButton() {
|
||||
return (
|
||||
<Example title="With Input and Button" containerClassName="col-span-full">
|
||||
<Tabs defaultValue="overview" className="mx-auto w-full max-w-lg">
|
||||
<div className="flex items-center gap-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Input placeholder="Search..." className="w-44" />
|
||||
<Button>Action</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-sera:rounded-none style-sera:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent value="overview">
|
||||
View your dashboard metrics and key performance indicators.
|
||||
</TabsContent>
|
||||
<TabsContent value="analytics">
|
||||
Detailed analytics and insights about your data.
|
||||
</TabsContent>
|
||||
<TabsContent value="reports">
|
||||
Generate and view custom reports.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
86
apps/v4/registry/bases/radix/examples/textarea-example.tsx
Normal file
86
apps/v4/registry/bases/radix/examples/textarea-example.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Textarea } from "@/registry/bases/radix/ui/textarea"
|
||||
|
||||
export default function TextareaExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TextareaBasic />
|
||||
<TextareaInvalid />
|
||||
<TextareaWithLabel />
|
||||
<TextareaWithDescription />
|
||||
<TextareaDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Textarea placeholder="Type your message here." />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Textarea placeholder="Type your message here." aria-invalid="true" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-message">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-message"
|
||||
placeholder="Type your message here."
|
||||
rows={6}
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-message-2">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-message-2"
|
||||
placeholder="Type your message here."
|
||||
rows={6}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Type your message and press enter to send.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-disabled">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-disabled"
|
||||
placeholder="Type your message here."
|
||||
disabled
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
344
apps/v4/registry/bases/radix/examples/toggle-example.tsx
Normal file
344
apps/v4/registry/bases/radix/examples/toggle-example.tsx
Normal file
@@ -0,0 +1,344 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Toggle } from "@/registry/bases/radix/ui/toggle"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ToggleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ToggleBasic />
|
||||
<ToggleOutline />
|
||||
<ToggleSizes />
|
||||
<ToggleWithButtonText />
|
||||
<ToggleWithButtonIcon />
|
||||
<ToggleWithButtonIconText />
|
||||
<ToggleDisabled />
|
||||
<ToggleWithIcon />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle bold" defaultPressed>
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleOutline() {
|
||||
return (
|
||||
<Example title="Outline">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle variant="outline" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Italic
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Bold
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle variant="outline" aria-label="Toggle small" size="sm">
|
||||
Small
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle default" size="default">
|
||||
Default
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle large" size="lg">
|
||||
Large
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonText() {
|
||||
return (
|
||||
<Example title="With Button Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm" size="sm">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="default" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle default" size="default">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="lg" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg" size="lg">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonIcon() {
|
||||
return (
|
||||
<Example title="With Button Icon">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm icon" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle
|
||||
variant="outline"
|
||||
aria-label="Toggle default icon"
|
||||
size="default"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon-lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg icon" size="lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonIconText() {
|
||||
return (
|
||||
<Example title="With Button Icon + Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
data-icon="inline-start"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm icon text" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="default" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
data-icon="inline-start"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle
|
||||
variant="outline"
|
||||
aria-label="Toggle default icon text"
|
||||
size="default"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="lg" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg icon text" size="lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle disabled" disabled>
|
||||
Disabled
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle disabled outline" disabled>
|
||||
Disabled
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle bookmark" defaultPressed>
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
className="group-data-[state=on]/toggle:fill-accent-foreground"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle bookmark outline">
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
className="group-data-[state=on]/toggle:fill-accent-foreground"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Bookmark
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
568
apps/v4/registry/bases/radix/examples/toggle-group-example.tsx
Normal file
568
apps/v4/registry/bases/radix/examples/toggle-group-example.tsx
Normal file
@@ -0,0 +1,568 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/radix/ui/field"
|
||||
import { Input } from "@/registry/bases/radix/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/radix/ui/select"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/radix/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ToggleGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ToggleGroupBasic />
|
||||
<ToggleGroupOutline />
|
||||
<ToggleGroupOutlineWithIcons />
|
||||
<ToggleGroupSizes />
|
||||
<ToggleGroupSpacing />
|
||||
<ToggleGroupWithIcons />
|
||||
<ToggleGroupFilter />
|
||||
<ToggleGroupDateRange />
|
||||
<ToggleGroupSort />
|
||||
<ToggleGroupWithInputAndSelect />
|
||||
<ToggleGroupVertical />
|
||||
<ToggleGroupVerticalOutline />
|
||||
<ToggleGroupVerticalOutlineWithIcons />
|
||||
<ToggleGroupVerticalWithSpacing />
|
||||
<ToggleGroupFontWeightSelector />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<ToggleGroup type="multiple" spacing={1}>
|
||||
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupOutline() {
|
||||
return (
|
||||
<Example title="Outline">
|
||||
<ToggleGroup variant="outline" type="single" defaultValue="all">
|
||||
<ToggleGroupItem value="all" aria-label="Toggle all">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="missed" aria-label="Toggle missed">
|
||||
Missed
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupOutlineWithIcons() {
|
||||
return (
|
||||
<Example title="Outline With Icons">
|
||||
<ToggleGroup variant="outline" type="multiple" size="sm">
|
||||
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
size="sm"
|
||||
defaultValue="top"
|
||||
variant="outline"
|
||||
>
|
||||
<ToggleGroupItem value="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<ToggleGroup type="single" defaultValue="top" variant="outline">
|
||||
<ToggleGroupItem value="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSpacing() {
|
||||
return (
|
||||
<Example title="With Spacing">
|
||||
<ToggleGroup type="single" size="sm" defaultValue="top" spacing={2}>
|
||||
<ToggleGroupItem value="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<ToggleGroup type="multiple" variant="outline" spacing={1} size="sm">
|
||||
<ToggleGroupItem
|
||||
value="star"
|
||||
aria-label="Toggle star"
|
||||
className="aria-pressed:*:[svg]:stroke-foregfill-foreground aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Star
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="heart"
|
||||
aria-label="Toggle heart"
|
||||
className="aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground aria-pressed:*:[svg]:stroke-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="HeartIcon"
|
||||
tabler="IconHeart"
|
||||
hugeicons="FavouriteIcon"
|
||||
phosphor="HeartIcon"
|
||||
remixicon="RiHeartLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Heart
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="bookmark"
|
||||
aria-label="Toggle bookmark"
|
||||
className="aria-pressed:bg-transparent aria-pressed:*:[svg]:fill-foreground aria-pressed:*:[svg]:stroke-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Bookmark
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupFilter() {
|
||||
return (
|
||||
<Example title="Filter">
|
||||
<ToggleGroup type="single" defaultValue="all" variant="outline" size="sm">
|
||||
<ToggleGroupItem value="all" aria-label="All">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="active" aria-label="Active">
|
||||
Active
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="completed" aria-label="Completed">
|
||||
Completed
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="archived" aria-label="Archived">
|
||||
Archived
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupDateRange() {
|
||||
return (
|
||||
<Example title="Date Range">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
defaultValue="today"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
spacing={2}
|
||||
>
|
||||
<ToggleGroupItem value="today" aria-label="Today">
|
||||
Today
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="week" aria-label="This Week">
|
||||
This Week
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="month" aria-label="This Month">
|
||||
This Month
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="year" aria-label="This Year">
|
||||
This Year
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSort() {
|
||||
return (
|
||||
<Example title="Sort">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
defaultValue="newest"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem value="newest" aria-label="Newest">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowDownIcon"
|
||||
tabler="IconArrowDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="ArrowDownIcon"
|
||||
remixicon="RiArrowDownLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Newest
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="oldest" aria-label="Oldest">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUpIcon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Oldest
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="popular" aria-label="Popular">
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="TradeUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Popular
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupWithInputAndSelect() {
|
||||
return (
|
||||
<Example title="With Input and Select">
|
||||
<div className="flex items-center gap-2">
|
||||
<Input type="search" placeholder="Search..." className="flex-1" />
|
||||
<Select defaultValue="all">
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="all">All</SelectItem>
|
||||
<SelectItem value="active">Active</SelectItem>
|
||||
<SelectItem value="archived">Archived</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<ToggleGroup type="single" defaultValue="grid" variant="outline">
|
||||
<ToggleGroupItem value="grid" aria-label="Grid view">
|
||||
Grid
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="list" aria-label="List view">
|
||||
List
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ToggleGroup type="multiple" orientation="vertical" spacing={2}>
|
||||
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalOutline() {
|
||||
return (
|
||||
<Example title="Vertical Outline">
|
||||
<ToggleGroup
|
||||
variant="outline"
|
||||
type="single"
|
||||
defaultValue="all"
|
||||
orientation="vertical"
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem value="all" aria-label="Toggle all">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="active" aria-label="Toggle active">
|
||||
Active
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="completed" aria-label="Toggle completed">
|
||||
Completed
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="archived" aria-label="Toggle archived">
|
||||
Archived
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalOutlineWithIcons() {
|
||||
return (
|
||||
<Example title="Vertical Outline With Icons">
|
||||
<ToggleGroup
|
||||
variant="outline"
|
||||
type="multiple"
|
||||
orientation="vertical"
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupFontWeightSelector() {
|
||||
const [fontWeight, setFontWeight] = React.useState("normal")
|
||||
return (
|
||||
<Example title="Font Weight Selector">
|
||||
<Field>
|
||||
<FieldLabel>Font Weight</FieldLabel>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={fontWeight}
|
||||
onValueChange={(value) => setFontWeight(value)}
|
||||
variant="outline"
|
||||
spacing={2}
|
||||
size="lg"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="light"
|
||||
aria-label="Light"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-light">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Light</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="normal"
|
||||
aria-label="Normal"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-normal">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Normal</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="medium"
|
||||
aria-label="Medium"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-medium">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Medium</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="bold"
|
||||
aria-label="Bold"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-bold">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Bold</span>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<FieldDescription>
|
||||
Use{" "}
|
||||
<code className="rounded-md bg-muted px-1 py-0.5 font-mono">
|
||||
font-{fontWeight}
|
||||
</code>{" "}
|
||||
to set the font weight.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalWithSpacing() {
|
||||
return (
|
||||
<Example title="Vertical With Spacing">
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
size="sm"
|
||||
defaultValue="top"
|
||||
orientation="vertical"
|
||||
spacing={2}
|
||||
>
|
||||
<ToggleGroupItem value="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
195
apps/v4/registry/bases/radix/examples/tooltip-example.tsx
Normal file
195
apps/v4/registry/bases/radix/examples/tooltip-example.tsx
Normal file
@@ -0,0 +1,195 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/radix/components/example"
|
||||
import { Button } from "@/registry/bases/radix/ui/button"
|
||||
import { Kbd } from "@/registry/bases/radix/ui/kbd"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/registry/bases/radix/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function TooltipExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TooltipBasic />
|
||||
<TooltipSides />
|
||||
<TooltipWithIcon />
|
||||
<TooltipLongContent />
|
||||
<TooltipDisabled />
|
||||
<TooltipWithKeyboard />
|
||||
<TooltipOnLink />
|
||||
<TooltipFormatted />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Show Tooltip
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Add to library</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["top", "right", "bottom", "left"] as const).map((side) => (
|
||||
<Tooltip key={side}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-fit capitalize style-sera:uppercase"
|
||||
>
|
||||
{side}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side={side}>
|
||||
<p>Add to library</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
<span className="sr-only">Info</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Additional information</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipLongContent() {
|
||||
return (
|
||||
<Example title="Long Content">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Show Tooltip
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
To learn more about how this works, check out the docs. If you have
|
||||
any questions, please reach out to us.
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-block w-fit">
|
||||
<Button variant="outline" disabled>
|
||||
Disabled
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>This feature is currently unavailable</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipWithKeyboard() {
|
||||
return (
|
||||
<Example title="With Keyboard Shortcut">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Save Changes <Kbd>S</Kbd>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipOnLink() {
|
||||
return (
|
||||
<Example title="On Link">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href="#"
|
||||
className="w-fit text-sm text-primary underline-offset-4 hover:underline"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Click to read the documentation</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipFormatted() {
|
||||
return (
|
||||
<Example title="Formatted Content">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Status
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-semibold">Active</p>
|
||||
<p className="text-xs opacity-80">Last updated 2 hours ago</p>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user