docs: add combobox, datepicker, radio-group, select, switch and textarea form and some other exmaples
This commit is contained in:
parent
5868374679
commit
fd0087b89b
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -34,4 +34,10 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
|||
</div>
|
||||
</RadioGroup>
|
||||
</template>
|
||||
```
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Form
|
||||
|
||||
<ComponentPreview name="RadioGroupForm" />
|
||||
|
|
|
|||
|
|
@ -45,4 +45,10 @@ import {
|
|||
</SelectContent>
|
||||
</Select>
|
||||
</template>
|
||||
```
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Form
|
||||
|
||||
<ComponentPreview name="SelectForm" />
|
||||
|
|
|
|||
|
|
@ -47,4 +47,10 @@ import { Switch } from '@/components/ui/switch'
|
|||
<template>
|
||||
<Switch />
|
||||
</template>
|
||||
```
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Form
|
||||
|
||||
<ComponentPreview name="SwitchForm" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
112
apps/www/src/lib/registry/default/example/ComboboxForm.vue
Normal file
112
apps/www/src/lib/registry/default/example/ComboboxForm.vue
Normal 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>
|
||||
118
apps/www/src/lib/registry/default/example/ComboboxPopover.vue
Normal file
118
apps/www/src/lib/registry/default/example/ComboboxPopover.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
76
apps/www/src/lib/registry/default/example/RadioGroupForm.vue
Normal file
76
apps/www/src/lib/registry/default/example/RadioGroupForm.vue
Normal 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>
|
||||
79
apps/www/src/lib/registry/default/example/SelectForm.vue
Normal file
79
apps/www/src/lib/registry/default/example/SelectForm.vue
Normal 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>
|
||||
85
apps/www/src/lib/registry/default/example/SwitchForm.vue
Normal file
85
apps/www/src/lib/registry/default/example/SwitchForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
59
apps/www/src/lib/registry/default/example/TextareaForm.vue
Normal file
59
apps/www/src/lib/registry/default/example/TextareaForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
115
apps/www/src/lib/registry/new-york/example/ComboboxForm.vue
Normal file
115
apps/www/src/lib/registry/new-york/example/ComboboxForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
79
apps/www/src/lib/registry/new-york/example/SelectForm.vue
Normal file
79
apps/www/src/lib/registry/new-york/example/SelectForm.vue
Normal 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>
|
||||
85
apps/www/src/lib/registry/new-york/example/SwitchForm.vue
Normal file
85
apps/www/src/lib/registry/new-york/example/SwitchForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
59
apps/www/src/lib/registry/new-york/example/TextareaForm.vue
Normal file
59
apps/www/src/lib/registry/new-york/example/TextareaForm.vue
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue
Block a user