docs: add combobox, datepicker, radio-group, select, switch and textarea form and some other exmaples

This commit is contained in:
Sadegh Barati 2023-10-03 02:51:04 +03:30
parent 5868374679
commit fd0087b89b
32 changed files with 1585 additions and 42 deletions

View File

@ -86,4 +86,20 @@ const value = ref({})
</template>
```
## Examples
### Combobox
<ComponentPreview name="ComboboxDemo" />
### Popover
<ComponentPreview name="ComboboxPopover" />
### Dropdown menu
<ComponentPreview name="ComboboxDropdownMenu" />
### Form
<ComponentPreview name="ComboboxForm" />

View File

@ -56,14 +56,18 @@ const date = ref<Date>()
## Examples
### Date Range Picker
<ComponentPreview name="DatePickerWithRange" />
### Date Picker
<ComponentPreview name="DatePickerDemo" />
### Date Range Picker
<ComponentPreview name="DatePickerWithRange" />
### With Presets
<ComponentPreview name="DatePickerWithPresets" />
### Form
<ComponentPreview name="DatePickerForm" />

View File

@ -34,4 +34,10 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
</div>
</RadioGroup>
</template>
```
```
## Examples
### Form
<ComponentPreview name="RadioGroupForm" />

View File

@ -45,4 +45,10 @@ import {
</SelectContent>
</Select>
</template>
```
```
## Examples
### Form
<ComponentPreview name="SelectForm" />

View File

@ -47,4 +47,10 @@ import { Switch } from '@/components/ui/switch'
<template>
<Switch />
</template>
```
```
## Examples
### Form
<ComponentPreview name="SwitchForm" />

View File

@ -45,4 +45,30 @@ import { Textarea } from '@/components/ui/textarea'
<template>
<Textarea />
</template>
```
```
## Examples
### Default
<ComponentPreview name="TextareaDemo" />
### Disabled
<ComponentPreview name="TextareaDisabled" />
### With Label
<ComponentPreview name="TextareaWithLabel" className="[&_div.grid]:w-full" />
### With Text
<ComponentPreview name="TextareaWithText" />
### With Button
<ComponentPreview name="TextareaWithButton" />
### Form
<ComponentPreview name="TextareaForm" />

View File

@ -77,7 +77,7 @@ async function onSubmit(values: any) {
</p>
</div>
<Separator />
<Form :validation-schema="accountFormSchema" class="space-y-8" @submit="onSubmit">
<Form v-slot="{ setValues }" :validation-schema="accountFormSchema" class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="name">
<FormItem>
<FormLabel>Name</FormLabel>
@ -119,7 +119,7 @@ async function onSubmit(values: any) {
</FormItem>
</FormField>
<FormField v-slot="{ value, componentField }" name="language">
<FormField v-slot="{ value }" name="language">
<FormItem>
<FormLabel>Language</FormLabel>
@ -141,19 +141,23 @@ async function onSubmit(values: any) {
</FormControl>
</PopoverTrigger>
<PopoverContent class="w-[200px] p-0">
<Command v-bind="componentField">
<Command>
<CommandInput placeholder="Search language..." />
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="language in languages" :key="language.value" :value="language.value" @select="() => {
v-for="language in languages" :key="language.value" :value="language.label"
@select="() => {
setValues({
language: language.value,
})
open = false
}"
>
<Check
:class="cn(
'mr-2 h-4 w-4',
value === language.label ? 'opacity-100' : 'opacity-0',
value === language.value ? 'opacity-100' : 'opacity-0',
)"
/>
{{ language.label }}

View File

@ -3,18 +3,12 @@ import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { ChevronDownIcon } from '@radix-icons/vue'
import { cn } from '@/lib/utils'
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/default/ui/form'
import { Separator } from '@/lib/registry/new-york/ui/separator'
import { RadioGroup, RadioGroupItem } from '@/lib/registry/default/ui/radio-group'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/new-york/ui/select'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Button, buttonVariants } from '@/lib/registry/new-york/ui/button'
const appearanceFormSchema = toTypedSchema(z.object({
theme: z.enum(['light', 'dark'], {
@ -50,30 +44,30 @@ const onSubmit = handleSubmit((values) => {
</div>
<Separator />
<form class="space-y-8" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="font">
<FormField v-slot="{ field }" name="font">
<FormItem>
<FormLabel>Email</FormLabel>
<div class="relative w-[200px]">
<FormControl>
<Select v-bind="componentField">
<SelectTrigger>
<SelectValue placeholder="Select a font" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="inter">
Inter
</SelectItem>
<SelectItem value="manrope">
Manrope
</SelectItem>
<SelectItem value="system">
System
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<select
:class="cn(
buttonVariants({ variant: 'outline' }),
'w-[200px] appearance-none bg-transparent font-normal',
)"
v-bind="field"
>
<option value="inter">
Inter
</option>
<option value="manrope">
Manrope
</option>
<option value="system">
System
</option>
</select>
</FormControl>
<ChevronDownIcon class="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
</div>
<FormDescription>
Set the font you want to use in the dashboard.

View File

@ -0,0 +1,108 @@
<script setup lang="ts">
import { ref } from 'vue'
import { Calendar, MoreHorizontal, Tags, Trash, User } from 'lucide-vue-next'
import { Button } from '@/lib/registry/default/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/lib/registry/default/ui/command'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from '@/lib/registry/default/ui/dropdown-menu'
const labels = [
'feature',
'bug',
'enhancement',
'documentation',
'design',
'question',
'maintenance',
]
const labelRef = ref('feature')
const open = ref(false)
</script>
<template>
<div class="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
<p class="text-sm font-medium leading-none">
<span class="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
{{ labelRef }}
</span>
<span class="text-muted-foreground">Create a new project</span>
</p>
<DropdownMenu :open="open">
<DropdownMenuTrigger as-child>
<Button variant="ghost" size="sm">
<MoreHorizontal />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-[200px]">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuGroup>
<DropdownMenuItem>
<User class="mr-2 h-4 w-4" />
Assign to...
</DropdownMenuItem>
<DropdownMenuItem>
<Calendar class="mr-2 h-4 w-4" />
Set due date...
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Tags class="mr-2 h-4 w-4" />
Apply label
</DropdownMenuSubTrigger>
<DropdownMenuSubContent class="p-0">
<Command>
<CommandInput
placeholder="Filter label..."
auto-focus
/>
<CommandList>
<CommandEmpty>No label found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="label in labels"
:key="label"
:value="label"
@select="(value) => {
labelRef = value as string
open = false
}"
>
{{ label }}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem class="text-red-600">
<Trash class="mr-2 h-4 w-4" />
Delete
<DropdownMenuShortcut></DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</template>

View File

@ -0,0 +1,112 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Check, ChevronsUpDown } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from '@/lib/registry/default/ui/command'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/default/ui/popover'
const languages = [
{ label: 'English', value: 'en' },
{ label: 'French', value: 'fr' },
{ label: 'German', value: 'de' },
{ label: 'Spanish', value: 'es' },
{ label: 'Portuguese', value: 'pt' },
{ label: 'Russian', value: 'ru' },
{ label: 'Japanese', value: 'ja' },
{ label: 'Korean', value: 'ko' },
{ label: 'Chinese', value: 'zh' },
]
const formSchema = toTypedSchema(z.object({
language: z.string({
required_error: 'Please select a language.',
}),
}))
const { handleSubmit, setValues } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-6" @submit="onSubmit">
<FormField v-slot="{ value }" name="language">
<FormItem class="flex flex-col">
<FormLabel>Language</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline"
role="combobox"
:class="cn('w-[200px] justify-between', !value && 'text-muted-foreground')"
>
{{ value ? languages.find(
(language) => language.value === value,
)?.label : 'Select language...' }}
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent class="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search language..." />
<CommandEmpty>Nothing found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="language in languages"
:key="language.value"
:value="language.label"
@select="() => {
setValues({
language: language.value,
})
}"
>
<Check
:class="cn('mr-2 h-4 w-4', language.value === value ? 'opacity-100' : 'opacity-0')"
/>
{{ language.label }}
</CommandItem>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
<FormDescription>
This is the language that will be used in the dashboard.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,118 @@
<script setup lang="ts">
import { h, ref } from 'vue'
import {
ArrowUpCircle,
CheckCircle2,
Circle,
HelpCircle,
XCircle,
} from 'lucide-vue-next'
import type { Icon } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/lib/registry/default/ui/command'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/default/ui/popover'
interface Status {
value: string
label: string
icon: Icon
}
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,
},
]
const open = ref(false)
const value = ref<typeof statuses[number]>()
const selectedStatus = ref<Status | null>(null)
</script>
<template>
<div class="flex items-center space-x-4">
<p class="text-sm text-muted-foreground">
Status
</p>
<Popover :open="open">
<PopoverTrigger as-child>
<Button
variant="outline"
size="sm"
class="w-[150px] justify-start"
>
<template v-if="selectedStatus">
<component :is="h(selectedStatus?.icon)" class="mr-2 h-4 w-4 shrink-0" />
{{ selectedStatus?.label }}
</template>
<template v-else>
+ Set status
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="p-0" side="right" align="start">
<Command>
<CommandInput placeholder="Change status..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="status in statuses"
:key="status.value"
:value="status.value"
@select="(value) => {
selectedStatus = statuses.find((priority) => priority.value === value) || null
open = false
}"
>
<component
:is="h(status.icon)"
:key="status.value"
:class="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>
</template>

View File

@ -0,0 +1,73 @@
<script setup lang="ts">
import { addDays, format } from 'date-fns'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { ref } from 'vue'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/default/ui/button'
import { Calendar } from '@/lib/registry/default/ui/calendar'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/default/ui/popover'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/default/ui/select'
const date = ref<Date>()
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!date && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="date">
{{ format(date, "PPP") }}
</template>
<template v-else>
<span>Pick a date</span>
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="flex w-auto flex-col space-y-2 p-2">
<Select
@update:model-value="(value) => {
date = addDays(new Date(), parseInt(value))
}"
>
<SelectTrigger>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="0">
Today
</SelectItem>
<SelectItem value="1">
Tomorrow
</SelectItem>
<SelectItem value="3">
In 3 days
</SelectItem>
<SelectItem value="7">
In a week
</SelectItem>
</SelectContent>
</Select>
<div class="rounded-md border">
<Calendar v-model="date" mode="single" />
</div>
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,76 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { RadioGroup, RadioGroupItem } from '@/lib/registry/default/ui/radio-group'
const formSchema = toTypedSchema(z.object({
type: z.enum(['all', 'mentions', 'none'], {
required_error: 'You need to select a notification type.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form className="w-2/3 space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="type">
<FormItem class="space-y-3">
<FormLabel>Notify me about...</FormLabel>
<FormControl>
<RadioGroup
class="flex flex-col space-y-1"
v-bind="componentField"
>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="all" />
</FormControl>
<FormLabel class="font-normal">
All new messages
</FormLabel>
</FormItem>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="mentions" />
</FormControl>
<FormLabel class="font-normal">
Direct messages and mentions
</FormLabel>
</FormItem>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="none" />
</FormControl>
<FormLabel class="font-normal">
Nothing
</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,79 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/default/ui/select'
const formSchema = toTypedSchema(z.object({
email: z
.string({
required_error: 'Please select an email to display.',
})
.email(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form className="w-2/3 space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="email">
<FormItem>
<FormLabel>Email</FormLabel>
<Select v-bind="componentField">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select a verified email to display" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectGroup>
<SelectItem value="m@example.com">
m@example.com
</SelectItem>
<SelectItem value="m@google.com">
m@google.com
</SelectItem>
<SelectItem value="m@support.com">
m@support.com
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
You can manage email addresses in your
<a href="/examples/forms">email settings</a>.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,85 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
} from '@/lib/registry/default/ui/form'
import { Switch } from '@/lib/registry/default/ui/switch'
const formSchema = toTypedSchema(z.object({
marketing_emails: z.boolean().default(false).optional(),
security_emails: z.boolean(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
security_emails: true,
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="w-full space-y-6" @submit="onSubmit">
<div>
<h3 class="mb-4 text-lg font-medium">
Email Notifications
</h3>
<div class="space-y-4">
<FormField v-slot="{ value, handleChange }" name="marketing_emails">
<FormItem class="flex flex-row items-center justify-between rounded-lg border p-4">
<div class="space-y-0.5">
<FormLabel class="text-base">
Marketing emails
</FormLabel>
<FormDescription>
Receive emails about new products, features, and more.
</FormDescription>
</div>
<FormControl>
<Switch
:checked="value"
@update:checked="handleChange"
/>
</FormControl>
</FormItem>
</FormField>
<FormField v-slot="{ value, handleChange }" name="security_emails">
<FormItem class="flex flex-row items-center justify-between rounded-lg border p-4">
<div class="space-y-0.5">
<FormLabel class="text-base">
Security emails
</FormLabel>
<FormDescription>
Receive emails about your account security.
</FormDescription>
</div>
<FormControl>
<Switch
:checked="value"
disabled
aria-readonly
@update:checked="handleChange"
/>
</FormControl>
</FormItem>
</FormField>
</div>
</div>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,7 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/default/ui/textarea'
</script>
<template>
<Textarea placeholder="Type your message here." disabled />
</template>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/default/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/default/ui/form'
import { Textarea } from '@/lib/registry/default/ui/textarea'
const formSchema = toTypedSchema(z.object({
bio: z
.string()
.min(10, {
message: 'Bio must be at least 10 characters.',
})
.max(160, {
message: 'Bio must not be longer than 30 characters.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="w-full space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="bio">
<FormItem>
<FormLabel>Bio</FormLabel>
<FormControl>
<Textarea
placeholder="Tell us a little bit about yourself"
class="resize-none"
v-bind="componentField"
/>
</FormControl>
<FormDescription>
You can <span>@mention</span> other users and organizations.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/default/ui/textarea'
import { Button } from '@/lib/registry/default/ui/button'
</script>
<template>
<div class="grid w-full gap-2">
<Textarea placeholder="Type your message here." />
<Button>Send message</Button>
</div>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/default/ui/textarea'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<div class="grid w-full gap-1.5">
<Label for="message">Your message</Label>
<Textarea id="message" placeholder="Type your message here." />
</div>
</template>

View File

@ -0,0 +1,14 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/default/ui/textarea'
import { Label } from '@/lib/registry/default/ui/label'
</script>
<template>
<div class="grid w-full gap-1.5">
<Label for="message-2">Your message</Label>
<Textarea id="message-2" placeholder="Type your message here." />
<p className="text-sm text-muted-foreground">
Your message will be copied to the support team.
</p>
</div>
</template>

View File

@ -0,0 +1,104 @@
<script setup lang="ts">
import { ref } from 'vue'
import { DotsHorizontalIcon } from '@radix-icons/vue'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/lib/registry/new-york/ui/command'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from '@/lib/registry/new-york/ui/dropdown-menu'
const labels = [
'feature',
'bug',
'enhancement',
'documentation',
'design',
'question',
'maintenance',
]
const labelRef = ref('feature')
const open = ref(false)
</script>
<template>
<div class="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
<p class="text-sm font-medium leading-none">
<span class="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
{{ labelRef }}
</span>
<span class="text-muted-foreground">Create a new project</span>
</p>
<DropdownMenu :open="open">
<DropdownMenuTrigger as-child>
<Button variant="ghost" size="sm">
<DotsHorizontalIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-[200px]">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuGroup>
<DropdownMenuItem>
Assign to...
</DropdownMenuItem>
<DropdownMenuItem>
Set due date...
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuSub>
<DropdownMenuSubTrigger>
Apply label
</DropdownMenuSubTrigger>
<DropdownMenuSubContent class="p-0">
<Command>
<CommandInput
placeholder="Filter label..."
auto-focus
/>
<CommandList>
<CommandEmpty>No label found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="label in labels"
:key="label"
:value="label"
@select="(value) => {
labelRef = value as string
open = false
}"
>
{{ label }}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem class="text-red-600">
Delete
<DropdownMenuShortcut></DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</template>

View File

@ -0,0 +1,115 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { CaretSortIcon, CheckIcon } from '@radix-icons/vue'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from '@/lib/registry/new-york/ui/command'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/new-york/ui/popover'
const languages = [
{ label: 'English', value: 'en' },
{ label: 'French', value: 'fr' },
{ label: 'German', value: 'de' },
{ label: 'Spanish', value: 'es' },
{ label: 'Portuguese', value: 'pt' },
{ label: 'Russian', value: 'ru' },
{ label: 'Japanese', value: 'ja' },
{ label: 'Korean', value: 'ko' },
{ label: 'Chinese', value: 'zh' },
] as const
const formSchema = toTypedSchema(z.object({
language: z.string({
required_error: 'Please select a language.',
}),
}))
const { handleSubmit, setValues } = useForm({
validationSchema: formSchema,
initialValues: {
language: '',
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="space-y-6" @submit="onSubmit">
<FormField v-slot="{ value }" name="language">
<FormItem class="flex flex-col">
<FormLabel>Language</FormLabel>
<Popover>
<PopoverTrigger as-child>
<FormControl>
<Button
variant="outline"
role="combobox"
:class="cn('w-[200px] justify-between', !value && 'text-muted-foreground')"
>
{{ value ? languages.find(
(language) => language.value === value,
)?.label : 'Select language...' }}
<CaretSortIcon class="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent class="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search language..." />
<CommandEmpty>Nothing found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="language in languages"
:key="language.value"
:value="language.label"
@select="() => {
setValues({
language: language.value,
})
}"
>
{{ language.label }}
<CheckIcon
:class="cn('ml-auto h-4 w-4', language.value === value ? 'opacity-100' : 'opacity-0')"
/>
</CommandItem>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
<FormDescription>
This is the language that will be used in the dashboard.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,94 @@
<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/lib/registry/new-york/ui/command'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/new-york/ui/popover'
interface Status {
value: string
label: string
}
const statuses: Status[] = [
{
value: 'backlog',
label: 'Backlog',
},
{
value: 'todo',
label: 'Todo',
},
{
value: 'in progress',
label: 'In Progress',
},
{
value: 'done',
label: 'Done',
},
{
value: 'canceled',
label: 'Canceled',
},
]
const open = ref(false)
const selectedStatus = ref<Status | null>(null)
</script>
<template>
<div class="flex items-center space-x-4">
<p class="text-sm text-muted-foreground">
Status
</p>
<Popover :open="open">
<PopoverTrigger as-child>
<Button
variant="outline"
size="sm"
class="w-[150px] justify-start"
>
<template v-if="selectedStatus">
{{ selectedStatus?.label }}
</template>
<template v-else>
+ Set status
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="p-0" side="right" align="start">
<Command>
<CommandInput placeholder="Change status..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="status in statuses"
:key="status.value"
:value="status"
@select="(value) => {
selectedStatus = statuses.find((priority) => priority.value === value) || null
open = false
}"
>
{{ status.label }}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</div>
</template>

View File

@ -0,0 +1,73 @@
<script setup lang="ts">
import { addDays, format } from 'date-fns'
import { Calendar as CalendarIcon } from 'lucide-vue-next'
import { ref } from 'vue'
import { cn } from '@/lib/utils'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/lib/registry/new-york/ui/popover'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/new-york/ui/select'
const date = ref<Date>()
</script>
<template>
<Popover>
<PopoverTrigger as-child>
<Button
variant="outline"
:class="cn(
'w-[280px] justify-start text-left font-normal',
!date && 'text-muted-foreground',
)"
>
<CalendarIcon class="mr-2 h-4 w-4" />
<template v-if="date">
{{ format(date, "PPP") }}
</template>
<template v-else>
<span>Pick a date</span>
</template>
</Button>
</PopoverTrigger>
<PopoverContent class="flex w-auto flex-col space-y-2 p-2">
<Select
@update:model-value="(value) => {
date = addDays(new Date(), parseInt(value))
}"
>
<SelectTrigger>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="0">
Today
</SelectItem>
<SelectItem value="1">
Tomorrow
</SelectItem>
<SelectItem value="3">
In 3 days
</SelectItem>
<SelectItem value="7">
In a week
</SelectItem>
</SelectContent>
</Select>
<div class="rounded-md border">
<Calendar v-model="date" mode="single" />
</div>
</PopoverContent>
</Popover>
</template>

View File

@ -0,0 +1,76 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import { RadioGroup, RadioGroupItem } from '@/lib/registry/new-york/ui/radio-group'
const formSchema = toTypedSchema(z.object({
type: z.enum(['all', 'mentions', 'none'], {
required_error: 'You need to select a notification type.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form className="w-2/3 space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="type">
<FormItem class="space-y-3">
<FormLabel>Notify me about...</FormLabel>
<FormControl>
<RadioGroup
class="flex flex-col space-y-1"
v-bind="componentField"
>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="all" />
</FormControl>
<FormLabel class="font-normal">
All new messages
</FormLabel>
</FormItem>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="mentions" />
</FormControl>
<FormLabel class="font-normal">
Direct messages and mentions
</FormLabel>
</FormItem>
<FormItem class="flex items-center gap-x-3 space-y-0">
<FormControl>
<RadioGroupItem value="none" />
</FormControl>
<FormLabel class="font-normal">
Nothing
</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,79 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/new-york/ui/select'
const formSchema = toTypedSchema(z.object({
email: z
.string({
required_error: 'Please select an email to display.',
})
.email(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form className="w-2/3 space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="email">
<FormItem>
<FormLabel>Email</FormLabel>
<Select v-bind="componentField">
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select a verified email to display" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectGroup>
<SelectItem value="m@example.com">
m@example.com
</SelectItem>
<SelectItem value="m@google.com">
m@google.com
</SelectItem>
<SelectItem value="m@support.com">
m@support.com
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<FormDescription>
You can manage email addresses in your
<a href="/examples/forms">email settings</a>.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,85 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
} from '@/lib/registry/new-york/ui/form'
import { Switch } from '@/lib/registry/new-york/ui/switch'
const formSchema = toTypedSchema(z.object({
marketing_emails: z.boolean().default(false).optional(),
security_emails: z.boolean(),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
initialValues: {
security_emails: true,
},
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="w-full space-y-6" @submit="onSubmit">
<div>
<h3 class="mb-4 text-lg font-medium">
Email Notifications
</h3>
<div class="space-y-4">
<FormField v-slot="{ value, handleChange }" name="marketing_emails">
<FormItem class="flex flex-row items-center justify-between rounded-lg border p-4">
<div class="space-y-0.5">
<FormLabel class="text-base">
Marketing emails
</FormLabel>
<FormDescription>
Receive emails about new products, features, and more.
</FormDescription>
</div>
<FormControl>
<Switch
:checked="value"
@update:checked="handleChange"
/>
</FormControl>
</FormItem>
</FormField>
<FormField v-slot="{ value, handleChange }" name="security_emails">
<FormItem class="flex flex-row items-center justify-between rounded-lg border p-4">
<div class="space-y-0.5">
<FormLabel class="text-base">
Security emails
</FormLabel>
<FormDescription>
Receive emails about your account security.
</FormDescription>
</div>
<FormControl>
<Switch
:checked="value"
disabled
aria-readonly
@update:checked="handleChange"
/>
</FormControl>
</FormItem>
</FormField>
</div>
</div>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,7 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
</script>
<template>
<Textarea placeholder="Type your message here." disabled />
</template>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod'
import { Button } from '@/lib/registry/new-york/ui/button'
import {
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/lib/registry/new-york/ui/form'
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
const formSchema = toTypedSchema(z.object({
bio: z
.string()
.min(10, {
message: 'Bio must be at least 10 characters.',
})
.max(160, {
message: 'Bio must not be longer than 30 characters.',
}),
}))
const { handleSubmit } = useForm({
validationSchema: formSchema,
})
const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values)
})
</script>
<template>
<form class="w-full space-y-6" @submit="onSubmit">
<FormField v-slot="{ componentField }" name="bio">
<FormItem>
<FormLabel>Bio</FormLabel>
<FormControl>
<Textarea
placeholder="Tell us a little bit about yourself"
class="resize-none"
v-bind="componentField"
/>
</FormControl>
<FormDescription>
You can <span>@mention</span> other users and organizations.
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
<Button type="submit">
Submit
</Button>
</form>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
import { Button } from '@/lib/registry/new-york/ui/button'
</script>
<template>
<div class="grid w-full gap-2">
<Textarea placeholder="Type your message here." />
<Button>Send message</Button>
</div>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
import { Label } from '@/lib/registry/new-york/ui/label'
</script>
<template>
<div class="grid w-full gap-1.5">
<Label for="message">Your message</Label>
<Textarea id="message" placeholder="Type your message here." />
</div>
</template>

View File

@ -0,0 +1,14 @@
<script setup lang="ts">
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
import { Label } from '@/lib/registry/new-york/ui/label'
</script>
<template>
<div class="grid w-full gap-1.5">
<Label for="message-2">Your message</Label>
<Textarea id="message-2" placeholder="Type your message here." />
<p className="text-sm text-muted-foreground">
Your message will be copied to the support team.
</p>
</div>
</template>