mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-27 06:34:12 +00:00
feat(command): add command component
This commit is contained in:
@@ -11,7 +11,7 @@ import { ThemeProvider } from "@/components/theme-provider"
|
||||
const fontSans = FontSans({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-sans",
|
||||
display: 'swap',
|
||||
display: "swap",
|
||||
})
|
||||
|
||||
interface RootLayoutProps {
|
||||
|
||||
115
apps/www/components/command-menu.tsx
Normal file
115
apps/www/components/command-menu.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { DialogProps } from "@radix-ui/react-alert-dialog"
|
||||
import { allDocs } from "contentlayer/generated"
|
||||
import { Circle, File, Laptop, Moon, SunMedium } from "lucide-react"
|
||||
import { useTheme } from "next-themes"
|
||||
|
||||
import { docsConfig } from "@/config/docs"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
} from "@/components/ui/command"
|
||||
|
||||
export function CommandMenu({ ...props }: DialogProps) {
|
||||
const router = useRouter()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const { setTheme } = useTheme()
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
if (e.key === "k" && e.metaKey) {
|
||||
setOpen((open) => !open)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", down)
|
||||
return () => document.removeEventListener("keydown", down)
|
||||
}, [])
|
||||
|
||||
const runCommand = React.useCallback((command: () => unknown) => {
|
||||
setOpen(false)
|
||||
command()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"relative h-9 w-full justify-start text-sm text-slate-500 dark:text-slate-400 sm:pr-12 md:w-40 lg:w-64"
|
||||
)}
|
||||
onClick={() => setOpen(true)}
|
||||
{...props}
|
||||
>
|
||||
<span className="hidden lg:inline-flex">Search documentation...</span>
|
||||
<span className="inline-flex lg:hidden">Search...</span>
|
||||
<kbd className="pointer-events-none absolute top-2 right-1.5 hidden h-5 select-none items-center gap-1 rounded border border-slate-100 bg-slate-100 px-1.5 font-mono text-[10px] font-medium text-slate-600 opacity-100 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 sm:flex">
|
||||
<span className="text-xs">⌘</span>K
|
||||
</kbd>
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Links">
|
||||
{docsConfig.mainNav
|
||||
.filter((navitem) => !navitem.external)
|
||||
.map((navItem) => (
|
||||
<CommandItem
|
||||
key={navItem.href}
|
||||
onSelect={() => {
|
||||
runCommand(() => router.push(navItem.href as string))
|
||||
}}
|
||||
>
|
||||
<File className="mr-2 h-4 w-4" />
|
||||
{navItem.title}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
<CommandGroup heading="Components">
|
||||
{allDocs
|
||||
.filter((doc) => doc.component)
|
||||
.map((doc) => (
|
||||
<CommandItem
|
||||
key={doc._id}
|
||||
onSelect={() => {
|
||||
runCommand(() => router.push(doc.slug))
|
||||
}}
|
||||
>
|
||||
<div className="mr-2 flex h-4 w-4 items-center justify-center">
|
||||
<Circle className="h-3 w-3" />
|
||||
</div>
|
||||
{doc.title}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Theme">
|
||||
<CommandItem onSelect={() => runCommand(() => setTheme("light"))}>
|
||||
<SunMedium className="mr-2 h-4 w-4" />
|
||||
Light
|
||||
</CommandItem>
|
||||
<CommandItem onSelect={() => runCommand(() => setTheme("dark"))}>
|
||||
<Moon className="mr-2 h-4 w-4" />
|
||||
Dark
|
||||
</CommandItem>
|
||||
<CommandItem onSelect={() => runCommand(() => setTheme("system"))}>
|
||||
<Laptop className="mr-2 h-4 w-4" />
|
||||
System
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
interface ComponentExampleProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
extractClassname?: boolean
|
||||
extractedClassNames?: string
|
||||
align?: "center" | "start" | "end"
|
||||
}
|
||||
|
||||
export function ComponentExample({
|
||||
@@ -16,6 +17,7 @@ export function ComponentExample({
|
||||
className,
|
||||
extractClassname,
|
||||
extractedClassNames,
|
||||
align = "center",
|
||||
...props
|
||||
}: ComponentExampleProps) {
|
||||
const [Example, Code, ...Children] = React.Children.toArray(
|
||||
@@ -55,7 +57,13 @@ export function ComponentExample({
|
||||
)}
|
||||
</div>
|
||||
<TabsContent value="preview" className="p-0">
|
||||
<div className="flex min-h-[350px] items-center justify-center p-10">
|
||||
<div
|
||||
className={cn("flex min-h-[350px] justify-center p-10", {
|
||||
"items-center": align === "center",
|
||||
"items-start": align === "start",
|
||||
"items-end": align === "end",
|
||||
})}
|
||||
>
|
||||
{Example}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
90
apps/www/components/examples/command/combobox.tsx
Normal file
90
apps/www/components/examples/command/combobox.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Check, ChevronsUpDown } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
|
||||
const frameworks = [
|
||||
{
|
||||
value: "next.js",
|
||||
label: "Next.js",
|
||||
},
|
||||
{
|
||||
value: "sveltekit",
|
||||
label: "SvelteKit",
|
||||
},
|
||||
{
|
||||
value: "nuxt.js",
|
||||
label: "Nuxt.js",
|
||||
},
|
||||
{
|
||||
value: "remix",
|
||||
label: "Remix",
|
||||
},
|
||||
{
|
||||
value: "astro",
|
||||
label: "Astro",
|
||||
},
|
||||
]
|
||||
|
||||
export function CommandCombobox() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const [value, setValue] = React.useState("")
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="w-[200px] justify-between"
|
||||
>
|
||||
{value
|
||||
? frameworks.find((framework) => framework.value === value)?.label
|
||||
: "Select framework..."}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{frameworks.map((framework) => (
|
||||
<CommandItem
|
||||
key={framework.value}
|
||||
onSelect={(currentValue) => {
|
||||
setValue(currentValue === value ? "" : currentValue)
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
value === framework.value ? "opacity-100" : "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{framework.label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
64
apps/www/components/examples/command/demo.tsx
Normal file
64
apps/www/components/examples/command/demo.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Calculator,
|
||||
Calendar,
|
||||
CreditCard,
|
||||
Settings,
|
||||
Smile,
|
||||
User,
|
||||
} from "lucide-react"
|
||||
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "@/components/ui/command"
|
||||
|
||||
export function CommandDemo() {
|
||||
return (
|
||||
<Command className="rounded-lg border border-slate-100 shadow-md dark:border-slate-800">
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>
|
||||
<Calendar className="mr-2 h-4 w-4" />
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Smile className="mr-2 h-4 w-4" />
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Calculator className="mr-2 h-4 w-4" />
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<CreditCard className="mr-2 h-4 w-4" />
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
)
|
||||
}
|
||||
86
apps/www/components/examples/command/dialog.tsx
Normal file
86
apps/www/components/examples/command/dialog.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
Calculator,
|
||||
Calendar,
|
||||
CreditCard,
|
||||
Settings,
|
||||
Smile,
|
||||
User,
|
||||
} from "lucide-react"
|
||||
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "@/components/ui/command"
|
||||
|
||||
export function CommandDialogDemo() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
if (e.key === "j" && e.metaKey) {
|
||||
setOpen((open) => !open)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", down)
|
||||
return () => document.removeEventListener("keydown", down)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">
|
||||
Press{" "}
|
||||
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-slate-100 bg-slate-100 px-1.5 font-mono text-[10px] font-medium text-slate-600 opacity-100 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400">
|
||||
<span className="text-xs">⌘</span>J
|
||||
</kbd>
|
||||
</p>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>
|
||||
<Calendar className="mr-2 h-4 w-4" />
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Smile className="mr-2 h-4 w-4" />
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Calculator className="mr-2 h-4 w-4" />
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<CreditCard className="mr-2 h-4 w-4" />
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem>
|
||||
<Settings className="mr-2 h-4 w-4" />
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
110
apps/www/components/examples/command/dropdown-menu.tsx
Normal file
110
apps/www/components/examples/command/dropdown-menu.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Calendar, MoreHorizontal, Pen, Tags, Trash, User } from "lucide-react"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
|
||||
const labels = [
|
||||
"feature",
|
||||
"bug",
|
||||
"enhancement",
|
||||
"documentation",
|
||||
"design",
|
||||
"question",
|
||||
"maintenance",
|
||||
]
|
||||
|
||||
export function CommandDropdownMenu() {
|
||||
const [label, setLabel] = React.useState("feature")
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-start justify-between rounded-md border border-slate-200 py-3 px-4 dark:border-slate-700 sm:flex-row sm:items-center">
|
||||
<p className="text-sm font-medium leading-none">
|
||||
<span className="mr-2 rounded-lg bg-slate-900 px-2 py-1 text-xs text-slate-50 dark:bg-slate-800 dark:text-slate-100">
|
||||
{label}
|
||||
</span>
|
||||
<span className="text-slate-500">Create a new project</span>
|
||||
</p>
|
||||
<DropdownMenu open={open} onOpenChange={setOpen}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<MoreHorizontal />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-[200px]">
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<User className="mr-2 h-4 w-4" />
|
||||
Assign to...
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Calendar className="mr-2 h-4 w-4" />
|
||||
Set due date...
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<Tags className="mr-2 h-4 w-4" />
|
||||
Apply label
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent className="p-0">
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder="Filter label..."
|
||||
autoFocus={true}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty>No label found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{labels.map((label) => (
|
||||
<CommandItem
|
||||
key={label}
|
||||
onSelect={(value) => {
|
||||
setLabel(value)
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem className="text-red-600">
|
||||
<Trash className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
124
apps/www/components/examples/command/popover.tsx
Normal file
124
apps/www/components/examples/command/popover.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
ArrowUpCircle,
|
||||
CheckCircle2,
|
||||
Circle,
|
||||
HelpCircle,
|
||||
LucideIcon,
|
||||
XCircle,
|
||||
} from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
|
||||
type Status = {
|
||||
value: string
|
||||
label: string
|
||||
icon: LucideIcon
|
||||
}
|
||||
|
||||
const statuses: Status[] = [
|
||||
{
|
||||
value: "backlog",
|
||||
label: "Backlog",
|
||||
icon: HelpCircle,
|
||||
},
|
||||
{
|
||||
value: "todo",
|
||||
label: "Todo",
|
||||
icon: Circle,
|
||||
},
|
||||
{
|
||||
value: "in progress",
|
||||
label: "In Progress",
|
||||
icon: ArrowUpCircle,
|
||||
},
|
||||
{
|
||||
value: "done",
|
||||
label: "Done",
|
||||
icon: CheckCircle2,
|
||||
},
|
||||
{
|
||||
value: "canceled",
|
||||
label: "Canceled",
|
||||
icon: XCircle,
|
||||
},
|
||||
]
|
||||
|
||||
export function CommandPopover() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const [selectedStatus, setSelectedStatus] = React.useState<Status | null>(
|
||||
null
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-4">
|
||||
<p className="text-sm text-slate-500 dark:text-slate-400">Status</p>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-[120px] justify-start"
|
||||
>
|
||||
{selectedStatus ? (
|
||||
<>
|
||||
<selectedStatus.icon className="mr-2 h-4 w-4 shrink-0" />
|
||||
{selectedStatus.label}
|
||||
</>
|
||||
) : (
|
||||
<>+ Set status</>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" side="right" align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder="Change status..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{statuses.map((status) => (
|
||||
<CommandItem
|
||||
key={status.value}
|
||||
onSelect={(value) => {
|
||||
setSelectedStatus(
|
||||
statuses.find((priority) => priority.value === value) ||
|
||||
null
|
||||
)
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<status.icon
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
status.value === selectedStatus?.value
|
||||
? "opacity-100"
|
||||
: "opacity-40"
|
||||
)}
|
||||
/>
|
||||
<span>{status.label}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -14,6 +14,11 @@ import { CheckboxDemo } from "@/components/examples/checkbox/demo"
|
||||
import { CheckboxDisabled } from "@/components/examples/checkbox/disabled"
|
||||
import { CheckboxWithText } from "@/components/examples/checkbox/with-text"
|
||||
import { CollapsibleDemo } from "@/components/examples/collapsible/demo"
|
||||
import { CommandCombobox } from "@/components/examples/command/combobox"
|
||||
import { CommandDemo } from "@/components/examples/command/demo"
|
||||
import { CommandDialogDemo } from "@/components/examples/command/dialog"
|
||||
import { CommandDropdownMenu } from "@/components/examples/command/dropdown-menu"
|
||||
import { CommandPopover } from "@/components/examples/command/popover"
|
||||
import { ContextMenuDemo } from "@/components/examples/context-menu/demo"
|
||||
import { DialogDemo } from "@/components/examples/dialog/demo"
|
||||
import { DropdownMenuCheckboxes } from "@/components/examples/dropdown-menu/checkboxes"
|
||||
@@ -81,6 +86,11 @@ export const examples = {
|
||||
CheckboxDisabled,
|
||||
CheckboxWithText,
|
||||
CollapsibleDemo,
|
||||
CommandDemo,
|
||||
CommandDialogDemo,
|
||||
CommandCombobox,
|
||||
CommandPopover,
|
||||
CommandDropdownMenu,
|
||||
ContextMenuDemo,
|
||||
DialogDemo,
|
||||
DropdownMenuCheckboxes,
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Input } from "@/components/ui/input"
|
||||
|
||||
interface DocsSearchProps extends React.HTMLAttributes<HTMLFormElement> {}
|
||||
|
||||
export function DocsSearch({ className, ...props }: DocsSearchProps) {
|
||||
function onSubmit(event: React.SyntheticEvent) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
className={cn("relative w-full", className)}
|
||||
{...props}
|
||||
>
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search documentation..."
|
||||
className="h-9 sm:pr-12 md:w-40 lg:w-64"
|
||||
disabled
|
||||
/>
|
||||
<kbd className="pointer-events-none absolute top-2 right-1.5 hidden h-5 select-none items-center gap-1 rounded border border-slate-100 bg-slate-100 px-1.5 font-mono text-[10px] font-medium text-slate-600 opacity-100 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 sm:flex">
|
||||
<span className="text-xs">⌘</span>K
|
||||
</kbd>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -16,7 +16,7 @@ export function DocsSidebarNav({ items }: DocsSidebarNavProps) {
|
||||
return items.length ? (
|
||||
<div className="w-full">
|
||||
{items.map((item, index) => (
|
||||
<div key={index} className={cn("pb-8")}>
|
||||
<div key={index} className={cn("pb-6")}>
|
||||
<h4 className="mb-1 rounded-md px-2 py-1 text-sm font-semibold">
|
||||
{item.title}
|
||||
</h4>
|
||||
@@ -46,7 +46,7 @@ export function DocsSidebarNavItems({
|
||||
key={index}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
"flex w-full items-center rounded-md p-2 hover:underline",
|
||||
"group flex w-full items-center rounded-md py-1.5 px-2 hover:bg-slate-50 dark:hover:bg-slate-800",
|
||||
item.disabled && "cursor-not-allowed opacity-60",
|
||||
{
|
||||
"bg-slate-100 dark:bg-slate-800": pathname === item.href,
|
||||
@@ -56,6 +56,11 @@ export function DocsSidebarNavItems({
|
||||
rel={item.external ? "noreferrer" : ""}
|
||||
>
|
||||
{item.title}
|
||||
{item.label && (
|
||||
<span className="ml-2 rounded-md bg-teal-100 px-1.5 py-0.5 text-xs no-underline group-hover:no-underline dark:text-slate-900">
|
||||
{item.label}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
) : (
|
||||
<span
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import Link from "next/link"
|
||||
|
||||
import { docsConfig } from "@/config/docs"
|
||||
import { siteConfig } from "@/config/site"
|
||||
import { CommandMenu } from "@/components/command-menu"
|
||||
import { Icons } from "@/components/icons"
|
||||
import { MainNav } from "@/components/main-nav"
|
||||
import { MobileNav } from "@/components/mobile-nav"
|
||||
import { ModeToggle } from "@/components/mode-toggle"
|
||||
import { DocsSearch } from "@/components/search"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
export function SiteHeader() {
|
||||
@@ -15,9 +14,9 @@ export function SiteHeader() {
|
||||
<div className="container flex h-16 items-center">
|
||||
<MainNav />
|
||||
<MobileNav />
|
||||
<div className="flex flex-1 items-center justify-end space-x-4">
|
||||
<div className="hidden flex-1 sm:grow-0 md:flex">
|
||||
<DocsSearch />
|
||||
<div className="flex flex-1 items-center justify-between space-x-2 sm:space-x-4 md:justify-end">
|
||||
<div className="w-full flex-1 md:w-auto md:flex-none">
|
||||
<CommandMenu />
|
||||
</div>
|
||||
<nav className="flex items-center space-x-1">
|
||||
<Link
|
||||
|
||||
158
apps/www/components/ui/command.tsx
Normal file
158
apps/www/components/ui/command.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive, useCommandState } from "cmdk"
|
||||
import { ChevronsUpDown, Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-lg bg-white dark:bg-slate-800",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-2xl [&_[dialog-overlay]]:bg-red-100">
|
||||
<Command className="[&_[cmdk-group]]:px-2 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-slate-500 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-input]]:h-12 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-group]_+[cmdk-group]]:pt-0">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
className="flex items-center border-b border-b-slate-100 px-4 dark:border-b-slate-700"
|
||||
cmdk-input-wrapper=""
|
||||
>
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-slate-400 disabled:cursor-not-allowed disabled:opacity-50 dark:text-slate-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden py-3 px-2 text-slate-700 dark:text-slate-400 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:text-sm [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-slate-900 [&_[cmdk-group-heading]]:dark:text-slate-300",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-slate-100 dark:bg-slate-700", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-md py-1.5 px-2 text-sm font-medium outline-none aria-selected:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-slate-700",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-slate-500",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
@@ -29,7 +29,7 @@ const DialogOverlay = React.forwardRef<
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-opacity animate-in fade-in",
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -47,7 +47,7 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed z-50 grid w-full scale-100 gap-4 bg-white p-6 opacity-100 animate-in fade-in-90 slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0",
|
||||
"fixed z-50 grid w-full gap-4 rounded-b-lg bg-white p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
|
||||
"dark:bg-slate-900",
|
||||
className
|
||||
)}
|
||||
|
||||
@@ -19,7 +19,7 @@ const PopoverContent = React.forwardRef<
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border border-slate-100 bg-white p-4 shadow-md outline-none animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 dark:border-slate-800 dark:bg-slate-800",
|
||||
"z-50 w-72 rounded-md border border-slate-100 bg-white p-4 shadow-md outline-none animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 dark:border-slate-800 dark:bg-slate-800",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -18,6 +18,7 @@ export const docsConfig: DocsConfig = {
|
||||
{
|
||||
title: "Figma",
|
||||
href: "/figma",
|
||||
label: "New",
|
||||
},
|
||||
{
|
||||
title: "GitHub",
|
||||
@@ -57,6 +58,7 @@ export const docsConfig: DocsConfig = {
|
||||
{
|
||||
title: "Figma",
|
||||
href: "/figma",
|
||||
label: "New",
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
@@ -99,6 +101,12 @@ export const docsConfig: DocsConfig = {
|
||||
href: "/docs/primitives/collapsible",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Command",
|
||||
href: "/docs/primitives/command",
|
||||
label: "Beta",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Context Menu",
|
||||
href: "/docs/primitives/context-menu",
|
||||
@@ -192,6 +200,7 @@ export const docsConfig: DocsConfig = {
|
||||
{
|
||||
title: "Toggle",
|
||||
href: "/docs/primitives/toggle",
|
||||
label: "New",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Accordion
|
||||
description: A vertically stacked set of interactive headings that each reveal an associated section of content.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/accordion
|
||||
api: https://www.radix-ui.com/docs/primitives/components/accordion#api-reference
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Alert Dialog
|
||||
description: A modal dialog that interrupts the user with important content and expects a response.
|
||||
featured: true
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/alert-dialog
|
||||
api: https://www.radix-ui.com/docs/primitives/components/alert-dialog#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Aspect Ratio
|
||||
description: Displays content within a desired ratio.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/aspect-ratio
|
||||
api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Avatar
|
||||
description: An image element with a fallback for representing the user.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/avatar
|
||||
api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Button
|
||||
description: Displays a button or a component that looks like a button.
|
||||
featured: true
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentExample src="/components/examples/button/demo.tsx">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Checkbox
|
||||
description: A control that allows the user to toggle between checked and not checked.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/checkbox
|
||||
api: https://www.radix-ui.com/docs/primitives/components/checkbox#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Collapsible
|
||||
description: An interactive component which expands/collapses a panel.
|
||||
component: true
|
||||
featured: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/collapsible
|
||||
|
||||
121
apps/www/content/docs/primitives/command.mdx
Normal file
121
apps/www/content/docs/primitives/command.mdx
Normal file
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: Command
|
||||
description: Fast, composable, unstyled command menu for React.
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentExample src="/components/examples/command/demo.tsx" align="start">
|
||||
<CommandDemo />
|
||||
</ComponentExample>
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install the `cmdk` package:
|
||||
|
||||
```bash
|
||||
npm install cmdk
|
||||
```
|
||||
|
||||
2. The `<Command />` component depends on the `<Dialog />` component. Follow the [Dialog installation instructions](//docs/primitives/dialog#installation).
|
||||
|
||||
3. Copy and paste the following code into your project.
|
||||
|
||||
<ComponentSource src="/components/ui/command.tsx" />
|
||||
|
||||
<Callout>
|
||||
This is the `<Command />` primitive. You can place it in a file at
|
||||
`components/ui/command.tsx`.
|
||||
</Callout>
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import {
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "@/components/ui/command"
|
||||
```
|
||||
|
||||
```tsx
|
||||
<CommandDialog triggerKey="j">
|
||||
<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>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>Profile</CommandItem>
|
||||
<CommandItem>Billing</CommandItem>
|
||||
<CommandItem>Settings</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Dialog
|
||||
|
||||
<ComponentExample src="/components/examples/command/dialog.tsx">
|
||||
<CommandDialogDemo />
|
||||
</ComponentExample>
|
||||
|
||||
To show the command menu in a dialog, use the `<CommandDialog />` component.
|
||||
|
||||
```tsx
|
||||
export function CommandMenu() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
if (e.key === "k" && e.metaKey) {
|
||||
setOpen((open) => !open)
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", down)
|
||||
return () => document.removeEventListener("keydown", down)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<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>
|
||||
</CommandDialog>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Combobox
|
||||
|
||||
<ComponentExample src="/components/examples/command/combobox.tsx">
|
||||
<CommandCombobox />
|
||||
</ComponentExample>
|
||||
|
||||
### Popover
|
||||
|
||||
<ComponentExample src="/components/examples/command/popover.tsx">
|
||||
<CommandPopover />
|
||||
</ComponentExample>
|
||||
|
||||
### Dropdown menu
|
||||
|
||||
<ComponentExample src="/components/examples/command/dropdown-menu.tsx">
|
||||
<CommandDropdownMenu />
|
||||
</ComponentExample>
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Dialog
|
||||
description: A modal dialog that interrupts the user with important content and expects a response.
|
||||
featured: true
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/dialog
|
||||
api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Dropdown Menu
|
||||
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
|
||||
featured: true
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/dropdown-menu
|
||||
api: https://www.radix-ui.com/docs/primitives/components/dropdown-menu#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Hover Card
|
||||
description: For sighted users to preview content available behind a link.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/hover-card
|
||||
api: https://www.radix-ui.com/docs/primitives/components/hover-card#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Input
|
||||
description: Displays a form input field or a component that looks like an input field.
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentExample
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Label
|
||||
description: Renders an accessible label associated with controls.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/label
|
||||
api: https://www.radix-ui.com/docs/primitives/components/label#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Menubar
|
||||
description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/menubar
|
||||
api: https://www.radix-ui.com/docs/primitives/components/menubar#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Navigation Menu
|
||||
description: A collection of links for navigating websites.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/navigation-menu
|
||||
api: https://www.radix-ui.com/docs/primitives/components/navigation-menu#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Popover
|
||||
description: Displays rich content in a portal, triggered by a button.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/popover
|
||||
api: https://www.radix-ui.com/docs/primitives/components/popover#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Progress
|
||||
description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/progress
|
||||
api: https://www.radix-ui.com/docs/primitives/components/progress#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Radio Group
|
||||
description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/radio-group
|
||||
api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Scroll-area
|
||||
description: Visually or semantically separates content.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/scroll-area
|
||||
api: https://www.radix-ui.com/docs/primitives/components/scroll-area#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Select
|
||||
description: Displays a list of options for the user to pick from—triggered by a button.
|
||||
component: true
|
||||
featured: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/select
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Separator
|
||||
description: Visually or semantically separates content.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/separator
|
||||
api: https://www.radix-ui.com/docs/primitives/components/separator#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Slider
|
||||
description: An input where the user selects a value from within a given range.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/slider
|
||||
api: https://www.radix-ui.com/docs/primitives/components/slider#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Tabs
|
||||
description: A set of layered sections of content—known as tab panels—that are displayed one at a time.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/tabs
|
||||
api: https://www.radix-ui.com/docs/primitives/components/tabs#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Textarea
|
||||
description: Displays a form textarea or a component that looks like a textarea.
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentExample src="/components/examples/textarea/demo.tsx">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Toggle
|
||||
description: A two-state button that can be either on or off.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/toggle
|
||||
api: https://www.radix-ui.com/docs/primitives/components/toggle#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Tooltip
|
||||
description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
|
||||
component: true
|
||||
radix:
|
||||
link: https://www.radix-ui.com/docs/primitives/components/tooltip
|
||||
api: https://www.radix-ui.com/docs/primitives/components/tooltip#api-reference
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
title: Typography
|
||||
description: Styles for headings, paragraphs, lists...etc
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentExample
|
||||
|
||||
@@ -65,6 +65,11 @@ export const Doc = defineDocumentType(() => ({
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
component: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computedFields,
|
||||
}))
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"@vercel/og": "^0.0.21",
|
||||
"class-variance-authority": "^0.4.0",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^0.1.21",
|
||||
"contentlayer": "^0.3.0",
|
||||
"logsnag": "^0.1.6",
|
||||
"lucide-react": "0.105.0-alpha.4",
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface NavItem {
|
||||
disabled?: boolean
|
||||
external?: boolean
|
||||
icon?: keyof typeof Icons
|
||||
label?: string
|
||||
}
|
||||
|
||||
export interface NavItemWithChildren extends NavItem {
|
||||
|
||||
140
pnpm-lock.yaml
generated
140
pnpm-lock.yaml
generated
@@ -90,6 +90,7 @@ importers:
|
||||
'@vercel/og': ^0.0.21
|
||||
class-variance-authority: ^0.4.0
|
||||
clsx: ^1.2.1
|
||||
cmdk: ^0.1.21
|
||||
contentlayer: ^0.3.0
|
||||
esbuild: ^0.17.3
|
||||
eslint: 7.32.0
|
||||
@@ -151,6 +152,7 @@ importers:
|
||||
'@vercel/og': 0.0.21
|
||||
class-variance-authority: 0.4.0_typescript@4.9.4
|
||||
clsx: 1.2.1
|
||||
cmdk: 0.1.21_ib3m5ricvtkl2cll7qpr2f6lvq
|
||||
contentlayer: 0.3.0_esbuild@0.17.3
|
||||
logsnag: 0.1.6
|
||||
lucide-react: 0.105.0-alpha.4_react@18.2.0
|
||||
@@ -1798,6 +1800,33 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-dialog/1.0.0_ib3m5ricvtkl2cll7qpr2f6lvq:
|
||||
resolution: {integrity: sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/primitive': 1.0.0
|
||||
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-context': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-dismissable-layer': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-focus-guards': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-focus-scope': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-id': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-portal': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-presence': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-primitive': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-slot': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0
|
||||
aria-hidden: 1.2.2_kzbn2opkn2327fwg5yzwzya5o4
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-remove-scroll: 2.5.4_kzbn2opkn2327fwg5yzwzya5o4
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-dialog/1.0.2_ib3m5ricvtkl2cll7qpr2f6lvq:
|
||||
resolution: {integrity: sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA==}
|
||||
peerDependencies:
|
||||
@@ -1834,6 +1863,22 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-dismissable-layer/1.0.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/primitive': 1.0.0
|
||||
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-primitive': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-use-escape-keydown': 1.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-dismissable-layer/1.0.2_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg==}
|
||||
peerDependencies:
|
||||
@@ -1879,6 +1924,20 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-focus-scope/1.0.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
|
||||
'@radix-ui/react-primitive': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
'@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-focus-scope/1.0.1_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ==}
|
||||
peerDependencies:
|
||||
@@ -2120,6 +2179,18 @@ packages:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-portal/1.0.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/react-primitive': 1.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-portal/1.0.1_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig==}
|
||||
peerDependencies:
|
||||
@@ -2145,6 +2216,18 @@ packages:
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-primitive/1.0.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/react-slot': 1.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-primitive/1.0.1_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==}
|
||||
peerDependencies:
|
||||
@@ -2319,6 +2402,16 @@ packages:
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-slot/1.0.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-slot/1.0.1_react@18.2.0:
|
||||
resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==}
|
||||
peerDependencies:
|
||||
@@ -2442,6 +2535,16 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-use-escape-keydown/1.0.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.6
|
||||
'@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-use-escape-keydown/1.0.2_react@18.2.0:
|
||||
resolution: {integrity: sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==}
|
||||
peerDependencies:
|
||||
@@ -3224,6 +3327,20 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/cmdk/0.1.21_ib3m5ricvtkl2cll7qpr2f6lvq:
|
||||
resolution: {integrity: sha512-O5oiYmoBdcoqmax4RMOsnJHrseaXlnkzfCSWgNdyBxneTaSCmUByBF5MliJbsveoHJsjkyL2uNUs2kTBBMmIaw==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
dependencies:
|
||||
'@radix-ui/react-dialog': 1.0.0_ib3m5ricvtkl2cll7qpr2f6lvq
|
||||
command-score: 0.1.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/color-convert/1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
dependencies:
|
||||
@@ -3259,6 +3376,10 @@ packages:
|
||||
/comma-separated-tokens/2.0.3:
|
||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
||||
|
||||
/command-score/0.1.2:
|
||||
resolution: {integrity: sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w==}
|
||||
dev: false
|
||||
|
||||
/comment-json/4.2.3:
|
||||
resolution: {integrity: sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -6425,6 +6546,25 @@ packages:
|
||||
tslib: 2.4.1
|
||||
dev: false
|
||||
|
||||
/react-remove-scroll/2.5.4_kzbn2opkn2327fwg5yzwzya5o4:
|
||||
resolution: {integrity: sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/react': 18.0.26
|
||||
react: 18.2.0
|
||||
react-remove-scroll-bar: 2.3.4_kzbn2opkn2327fwg5yzwzya5o4
|
||||
react-style-singleton: 2.2.1_kzbn2opkn2327fwg5yzwzya5o4
|
||||
tslib: 2.4.1
|
||||
use-callback-ref: 1.3.0_kzbn2opkn2327fwg5yzwzya5o4
|
||||
use-sidecar: 1.1.2_kzbn2opkn2327fwg5yzwzya5o4
|
||||
dev: false
|
||||
|
||||
/react-remove-scroll/2.5.5_kzbn2opkn2327fwg5yzwzya5o4:
|
||||
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
Reference in New Issue
Block a user