Merge remote-tracking branch 'origin/dev' into charting
This commit is contained in:
commit
a84e1ece5c
|
|
@ -17,6 +17,9 @@ export default defineConfig({
|
|||
['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' }],
|
||||
['link', { rel: 'manifest', href: '/site.webmanifest' }],
|
||||
|
||||
['meta', { name: 'theme-color', media: '(prefers-color-scheme: light)', content: 'white' }],
|
||||
['meta', { name: 'theme-color', media: '(prefers-color-scheme: dark)', content: 'black' }],
|
||||
|
||||
['meta', { name: 'creator', content: 'radix-vue' }],
|
||||
['meta', { name: 'theme-color', content: '#41b883' }],
|
||||
['meta', { name: 'og:type', content: 'website' }],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
|||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||
import ExamplesNav from '../components/ExamplesNav.vue'
|
||||
import { announcementConfig } from '../config/site'
|
||||
import ArrowRightIcon from '~icons/radix-icons/arrow-right'
|
||||
import GitHubIcon from '~icons/radix-icons/github-logo'
|
||||
|
||||
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
|
|
|
|||
|
|
@ -44,14 +44,14 @@ const { theme, setTheme } = useConfigStore()
|
|||
class="flex h-9 w-9 items-center justify-center rounded-full border-2 border-border text-xs"
|
||||
:class="
|
||||
color === theme
|
||||
? 'border-foreground'
|
||||
? 'border-primary'
|
||||
: 'border-transparent'
|
||||
"
|
||||
@click="setTheme(color)"
|
||||
>
|
||||
<span
|
||||
class="flex h-6 w-6 items-center justify-center rounded-full"
|
||||
:style="{ backgroundColor: colors[color][7].rgb }"
|
||||
:style="{ backgroundColor: colors[color][6].rgb }"
|
||||
>
|
||||
<RadixIconsCheck
|
||||
v-if="color === theme"
|
||||
|
|
@ -63,7 +63,7 @@ const { theme, setTheme } = useConfigStore()
|
|||
<TooltipContent
|
||||
align="center"
|
||||
:side-offset="1"
|
||||
class="capitalize"
|
||||
class="capitalize bg-zinc-900 text-zinc-50"
|
||||
>
|
||||
{{ allColors[index] }}
|
||||
</TooltipContent>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
html {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
.theme-zinc {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import cssRaw from '../../../../../packages/cli/test/fixtures/nuxt/assets/css/ta
|
|||
import { type Style } from '@/lib/registry/styles'
|
||||
|
||||
export function makeCodeSandboxParams(componentName: string, style: Style, sources: Record<string, string>) {
|
||||
let files = {}
|
||||
let files: Record<string, any> = {}
|
||||
files = constructFiles(componentName, style, sources)
|
||||
files['.codesandbox/Dockerfile'] = {
|
||||
content: 'FROM node:18',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "www",
|
||||
"type": "module",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.4",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
|
|
@ -9,7 +9,9 @@
|
|||
"dev": "vitepress dev",
|
||||
"build": "vitepress build",
|
||||
"preview": "vitepress preview",
|
||||
"build:registry": "tsx ./scripts/build-registry.ts"
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"typecheck:registry": "vue-tsc --noEmit -p tsconfig.registry.json",
|
||||
"build:registry": "pnpm typecheck:registry && tsx ./scripts/build-registry.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formkit/auto-animate": "^0.8.0",
|
||||
|
|
@ -26,7 +28,7 @@
|
|||
"codesandbox": "^2.2.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"lucide-vue-next": "^0.276.0",
|
||||
"radix-vue": "^1.1.1",
|
||||
"radix-vue": "^1.2.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"v-calendar": "^3.1.2",
|
||||
"vee-validate": "4.11.8",
|
||||
|
|
@ -45,9 +47,10 @@
|
|||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||
"@vue/compiler-core": "^3.3.7",
|
||||
"@vue/compiler-dom": "^3.3.7",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"lodash.template": "^4.5.0",
|
||||
"radix-vue": "^1.1.1",
|
||||
"pathe": "^1.1.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"tailwindcss": "^3.3.5",
|
||||
|
|
|
|||
|
|
@ -11,10 +11,45 @@ primitive: https://www.radix-vue.com/components/collapsible.html
|
|||
## Installation
|
||||
|
||||
|
||||
<Steps>
|
||||
|
||||
### Run the following command
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add collapsible
|
||||
```
|
||||
|
||||
### Update `tailwind.config.js`
|
||||
|
||||
Add the following animations to your `tailwind.config.js` file:
|
||||
|
||||
```js title="tailwind.config.js" {5-18}
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
keyframes: {
|
||||
'collapsible-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-collapsible-content-height)' },
|
||||
},
|
||||
'collapsible-up': {
|
||||
from: { height: 'var(--radix-collapsible-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'collapsible-down': 'collapsible-down 0.2s ease-in-out',
|
||||
'collapsible-up': 'collapsible-up 0.2s ease-in-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@ component: true
|
|||
|
||||
<ComponentPreview name="ComboboxDemo" />
|
||||
|
||||
<br>
|
||||
<Callout title="Note" class="bg-destructive">
|
||||
|
||||
[Radix Vue](https://github.com/radix-vue/radix-vue/releases/tag/v1.2.0) introduced a breaking change. You will need to wrap `ComboboxGroup` and `ComboboxItem` inside of `ComboboxList` now.
|
||||
|
||||
</Callout>
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
The Combobox is built using a composition of the `<Popover />` and the `<Command />` components.
|
||||
|
|
@ -27,6 +35,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from '@/components/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
|
|
@ -64,22 +73,24 @@ const value = ref({})
|
|||
<Command v-model="value">
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="open = false"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="open = false"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ To activate the `Dialog` component from within a `Context Menu` or `Dropdown Men
|
|||
</ContextMenu>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
|
||||
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
||||
<DialogDescription>
|
||||
This action cannot be undone. Are you sure you want to permanently
|
||||
delete this file from our servers?
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ const onSubmit = form.handleSubmit((values) => {
|
|||
<template>
|
||||
<form @submit="onSubmit">
|
||||
...
|
||||
</Form>
|
||||
</form>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
|
@ -302,7 +302,7 @@ const onSubmit = form.handleSubmit((values) => {
|
|||
<Button type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Form>
|
||||
</form>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -26,31 +26,28 @@ npm install -D typescript
|
|||
npm install -D @nuxtjs/tailwindcss
|
||||
```
|
||||
|
||||
### Install `shadcn-nuxt` module (New ✨)
|
||||
|
||||
```bash
|
||||
npm install -D shadcn-nuxt
|
||||
```
|
||||
|
||||
|
||||
### Configure `nuxt.config.ts`
|
||||
|
||||
<Callout class="mt-4">
|
||||
|
||||
**Tip:** It's better to use Nuxt `components:dirs` hook to extend auto-import components directories.
|
||||
|
||||
If you use `components` key in `nuxt.config.ts` default config will disposed
|
||||
|
||||
</Callout>
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxtjs/tailwindcss'],
|
||||
hooks: {
|
||||
'components:dirs': (dirs) => {
|
||||
dirs.unshift({
|
||||
path: '~/components/ui',
|
||||
// this is required else Nuxt will autoImport `.ts` file
|
||||
extensions: ['.vue'],
|
||||
// prefix for your components, eg: UiButton
|
||||
prefix: 'Ui',
|
||||
// prevent adding another prefix component by it's path.
|
||||
pathPrefix: false
|
||||
})
|
||||
}
|
||||
modules: ['@nuxtjs/tailwindcss', 'shadcn-nuxt'],
|
||||
shadcn: {
|
||||
/**
|
||||
* Prefix for all the imported component
|
||||
*/
|
||||
prefix: '',
|
||||
/**
|
||||
* Directory that the component lives in.
|
||||
* @default "./components/ui"
|
||||
*/
|
||||
componentDir: './components/ui'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
|
@ -133,7 +130,7 @@ The command above will add the `Button` component to your project. Nuxt autoImpo
|
|||
```vue {3}
|
||||
<template>
|
||||
<div>
|
||||
<UiButton>Click me</UiButton>
|
||||
<Button>Click me</Button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ const selectedTeam = ref<Team>(groups[0].teams[0])
|
|||
<CommandGroup>
|
||||
<DialogTrigger as-child>
|
||||
<CommandItem
|
||||
:value="{ label: 'Create Team' }"
|
||||
value="create-team"
|
||||
@select="() => {
|
||||
open = false
|
||||
showNewTeamDialog = true
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { h, ref } from 'vue'
|
|||
import * as z from 'zod'
|
||||
import { format } from 'date-fns'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { configure } from 'vee-validate'
|
||||
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Cross1Icon } from '@radix-icons/vue'
|
|||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/default/ui/form'
|
||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/default/ui/form'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ import CounterClockwiseClockIcon from '~icons/radix-icons/counter-clockwise-cloc
|
|||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
<ModelSelector :types="types" :models="models" />
|
||||
<ModelSelector />
|
||||
<TemperatureSelector :default-value="[0.56]" />
|
||||
<MaxLengthSelector :default-value="[256]" />
|
||||
<TopPSelector :default-value="[0.9]" />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { Column } from '@tanstack/vue-table'
|
||||
import type { Component } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { type Task } from '../data/schema'
|
||||
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { ChevronDown, Minus, Plus, Send } from 'lucide-vue-next'
|
||||
import { Minus, Plus } from 'lucide-vue-next'
|
||||
import { VisStackedBar, VisXYContainer } from '@unovis/vue'
|
||||
import { useData } from 'vitepress'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/lib/registry/default/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
|
|
@ -48,25 +49,28 @@ const filterFunction = (list: typeof frameworks, search: string) => list.filter(
|
|||
<Command :filter-function="filterFunction">
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="(ev) => {
|
||||
value = ev.detail.value as typeof framework
|
||||
open = false
|
||||
}"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="(ev) => {
|
||||
value = ev.detail.value
|
||||
console.log(ev)
|
||||
open = false
|
||||
}"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/lib/registry/default/ui/command'
|
||||
import {
|
||||
FormControl,
|
||||
|
|
@ -83,23 +84,25 @@ const onSubmit = handleSubmit((values) => {
|
|||
<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 === values.language ? 'opacity-100' : 'opacity-0')"
|
||||
/>
|
||||
{{ language.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandList>
|
||||
<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 === values.language ? 'opacity-100' : 'opacity-0')"
|
||||
/>
|
||||
{{ language.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { h, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
ArrowUpCircle,
|
||||
CheckCircle2,
|
||||
|
|
|
|||
|
|
@ -2,20 +2,24 @@
|
|||
import { ScrollArea, ScrollBar } from '@/lib/registry/default/ui/scroll-area'
|
||||
|
||||
interface Artwork {
|
||||
id: string
|
||||
artist: string
|
||||
art: string
|
||||
}
|
||||
|
||||
const works: Artwork[] = [
|
||||
{
|
||||
id: '1',
|
||||
artist: 'Ornella Binni',
|
||||
art: 'https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
artist: 'Tom Byrom',
|
||||
art: 'https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
artist: 'Vladimir Malyavko',
|
||||
art: 'https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
|
|
@ -30,7 +34,7 @@ const works: Artwork[] = [
|
|||
<div class="overflow-hidden rounded-md">
|
||||
<img
|
||||
:src="artwork.art"
|
||||
:alt="`Photo by ${artwork.name}`"
|
||||
:alt="`Photo by ${artwork.artist}`"
|
||||
class="aspect-[3/4] w-36 h-56 object-cover"
|
||||
>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,15 +7,30 @@ import { computed, nextTick, onMounted, ref } from 'vue'
|
|||
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
/* Extracted from v-calendar */
|
||||
type DatePickerModel = DatePickerDate | DatePickerRangeObject
|
||||
type DateSource = Date | string | number
|
||||
type DatePickerDate = DateSource | Partial<SimpleDateParts> | null
|
||||
interface DatePickerRangeObject {
|
||||
start: Exclude<DatePickerDate, null>
|
||||
end: Exclude<DatePickerDate, null>
|
||||
}
|
||||
interface SimpleDateParts {
|
||||
year: number
|
||||
month: number
|
||||
day: number
|
||||
hours: number
|
||||
minutes: number
|
||||
seconds: number
|
||||
milliseconds: number
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue?: string | number | Date | Partial<{
|
||||
start: Date
|
||||
end: Date
|
||||
}>
|
||||
modelValue?: string | number | Date | DatePickerModel
|
||||
modelModifiers?: object
|
||||
columns?: number
|
||||
type?: 'single' | 'range'
|
||||
|
|
@ -53,7 +68,7 @@ onMounted(async () => {
|
|||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<div class="absolute top-3 flex justify-between w-full px-4">
|
||||
<div class="absolute flex justify-between w-full px-4 top-3 z-[1]">
|
||||
<button :class="cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')" @click="handleNav('prev')">
|
||||
<ChevronLeft class="w-4 h-4" />
|
||||
</button>
|
||||
|
|
@ -119,4 +134,94 @@ onMounted(async () => {
|
|||
.calendar .vc-highlight-content-light {
|
||||
@apply bg-accent text-accent-foreground;
|
||||
}
|
||||
.calendar .vc-pane-container.in-transition {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
.calendar .vc-pane-container {
|
||||
@apply w-full relative;
|
||||
}
|
||||
:root {
|
||||
--vc-slide-translate: 22px;
|
||||
--vc-slide-duration: 0.15s;
|
||||
--vc-slide-timing: ease;
|
||||
}
|
||||
.calendar .vc-fade-enter-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-enter-active,
|
||||
.calendar .vc-slide-left-leave-active,
|
||||
.calendar .vc-slide-right-enter-active,
|
||||
.calendar .vc-slide-right-leave-active,
|
||||
.calendar .vc-slide-up-enter-active,
|
||||
.calendar .vc-slide-up-leave-active,
|
||||
.calendar .vc-slide-down-enter-active,
|
||||
.calendar .vc-slide-down-leave-active,
|
||||
.calendar .vc-slide-fade-enter-active,
|
||||
.calendar .vc-slide-fade-leave-active {
|
||||
transition:
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
-webkit-transform var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
transition:
|
||||
transform var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
transition:
|
||||
transform var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
-webkit-transform var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.calendar .vc-none-leave-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-leave-active,
|
||||
.calendar .vc-slide-right-leave-active,
|
||||
.calendar .vc-slide-up-leave-active,
|
||||
.calendar .vc-slide-down-leave-active {
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
}
|
||||
.calendar .vc-none-enter-from,
|
||||
.calendar .vc-none-leave-to,
|
||||
.calendar .vc-fade-enter-from,
|
||||
.calendar .vc-fade-leave-to,
|
||||
.calendar .vc-slide-left-enter-from,
|
||||
.calendar .vc-slide-left-leave-to,
|
||||
.calendar .vc-slide-right-enter-from,
|
||||
.calendar .vc-slide-right-leave-to,
|
||||
.calendar .vc-slide-up-enter-from,
|
||||
.calendar .vc-slide-up-leave-to,
|
||||
.calendar .vc-slide-down-enter-from,
|
||||
.calendar .vc-slide-down-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from,
|
||||
.calendar .vc-slide-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.calendar .vc-slide-left-enter-from,
|
||||
.calendar .vc-slide-right-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-left,
|
||||
.calendar .vc-slide-fade-leave-to.direction-left {
|
||||
-webkit-transform: translateX(var(--vc-slide-translate));
|
||||
transform: translateX(var(--vc-slide-translate));
|
||||
}
|
||||
.calendar .vc-slide-right-enter-from,
|
||||
.calendar .vc-slide-left-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-right,
|
||||
.calendar .vc-slide-fade-leave-to.direction-right {
|
||||
-webkit-transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
}
|
||||
.calendar .vc-slide-up-enter-from,
|
||||
.calendar .vc-slide-down-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-top,
|
||||
.calendar .vc-slide-fade-leave-to.direction-top {
|
||||
-webkit-transform: translateY(var(--vc-slide-translate));
|
||||
transform: translateY(var(--vc-slide-translate));
|
||||
}
|
||||
.calendar .vc-slide-down-enter-from,
|
||||
.calendar .vc-slide-up-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-bottom,
|
||||
.calendar .vc-slide-fade-leave-to.direction-bottom {
|
||||
-webkit-transform: translateY(calc(-1 * var(--vc-slide-translate)));
|
||||
transform: translateY(calc(-1 * var(--vc-slide-translate)));
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|||
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
$attrs.class ?? '')"
|
||||
>
|
||||
<CheckboxIndicator class="flex items-center justify-center text-current">
|
||||
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
|
||||
<Check class="h-4 w-4" />
|
||||
</CheckboxIndicator>
|
||||
</CheckboxRoot>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useEmitAsProps, useForwardPropsEmits } from 'radix-vue'
|
||||
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useForwardPropsEmits } from 'radix-vue'
|
||||
|
||||
const props = defineProps<DropdownMenuRootProps>()
|
||||
const emits = defineEmits<DropdownMenuRootEmits>()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { useAttrs } from 'vue'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<{
|
||||
defaultValue?: string | number
|
||||
modelValue?: string | number
|
||||
|
|
@ -11,6 +16,8 @@ const emits = defineEmits<{
|
|||
(e: 'update:modelValue', payload: string | number): void
|
||||
}>()
|
||||
|
||||
const { class: className, ...rest } = useAttrs()
|
||||
|
||||
const modelValue = useVModel(props, 'modelValue', emits, {
|
||||
passive: true,
|
||||
defaultValue: props.defaultValue,
|
||||
|
|
@ -18,5 +25,5 @@ const modelValue = useVModel(props, 'modelValue', emits, {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<input v-model="modelValue" type="text" :class="cn('flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', $attrs.class ?? '')">
|
||||
<input v-model="modelValue" :class="cn('flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', className ?? '')" v-bind="rest">
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/lib/registry/new-york/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
|
|
@ -48,25 +49,27 @@ const filterFunction = (list: typeof frameworks, search: string) => list.filter(
|
|||
<Command v-model="value" :filter-function="filterFunction">
|
||||
<CommandInput class="h-9" placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="(ev) => {
|
||||
value = ev.detail.value as typeof framework
|
||||
open = false
|
||||
}"
|
||||
>
|
||||
{{ framework.label }}
|
||||
<CheckIcon
|
||||
:class="cn(
|
||||
'ml-auto h-4 w-4',
|
||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="(ev) => {
|
||||
value = ev.detail.value
|
||||
open = false
|
||||
}"
|
||||
>
|
||||
{{ framework.label }}
|
||||
<CheckIcon
|
||||
:class="cn(
|
||||
'ml-auto h-4 w-4',
|
||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/lib/registry/new-york/ui/command'
|
||||
import {
|
||||
FormControl,
|
||||
|
|
@ -86,23 +87,25 @@ const onSubmit = handleSubmit((values) => {
|
|||
<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 === values.language ? 'opacity-100' : 'opacity-0')"
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandList>
|
||||
<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 === values.language ? 'opacity-100' : 'opacity-0')"
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
|
|
|||
|
|
@ -2,20 +2,24 @@
|
|||
import { ScrollArea, ScrollBar } from '@/lib/registry/new-york/ui/scroll-area'
|
||||
|
||||
interface Artwork {
|
||||
id: string
|
||||
artist: string
|
||||
art: string
|
||||
}
|
||||
|
||||
const works: Artwork[] = [
|
||||
{
|
||||
id: '1',
|
||||
artist: 'Ornella Binni',
|
||||
art: 'https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
artist: 'Tom Byrom',
|
||||
art: 'https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
artist: 'Vladimir Malyavko',
|
||||
art: 'https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80',
|
||||
},
|
||||
|
|
@ -30,7 +34,7 @@ const works: Artwork[] = [
|
|||
<div class="overflow-hidden rounded-md">
|
||||
<img
|
||||
:src="artwork.art"
|
||||
:alt="`Photo by ${artwork.name}`"
|
||||
:alt="`Photo by ${artwork.artist}`"
|
||||
class="aspect-[3/4] w-36 h-56 object-cover"
|
||||
>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,15 +7,29 @@ import { computed, nextTick, onMounted, ref } from 'vue'
|
|||
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
/* Extracted from v-calendar */
|
||||
type DatePickerModel = DatePickerDate | DatePickerRangeObject
|
||||
type DateSource = Date | string | number
|
||||
type DatePickerDate = DateSource | Partial<SimpleDateParts> | null
|
||||
interface DatePickerRangeObject {
|
||||
start: Exclude<DatePickerDate, null>
|
||||
end: Exclude<DatePickerDate, null>
|
||||
}
|
||||
interface SimpleDateParts {
|
||||
year: number
|
||||
month: number
|
||||
day: number
|
||||
hours: number
|
||||
minutes: number
|
||||
seconds: number
|
||||
milliseconds: number
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps< {
|
||||
modelValue?: string | number | Date | Partial<{
|
||||
start: Date
|
||||
end: Date
|
||||
}>
|
||||
modelValue?: string | number | Date | DatePickerModel
|
||||
modelModifiers?: object
|
||||
columns?: number
|
||||
type?: 'single' | 'range'
|
||||
|
|
@ -53,7 +67,7 @@ onMounted(async () => {
|
|||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<div class="absolute top-3 flex justify-between w-full px-4">
|
||||
<div class="absolute flex justify-between w-full px-4 top-3 z-[1]">
|
||||
<button :class="cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')" @click="handleNav('prev')">
|
||||
<ChevronLeftIcon class="w-4 h-4" />
|
||||
</button>
|
||||
|
|
@ -119,4 +133,101 @@ onMounted(async () => {
|
|||
.calendar .vc-highlight-content-light {
|
||||
@apply bg-accent text-accent-foreground;
|
||||
}
|
||||
.calendar .vc-pane-container.in-transition {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
.calendar .vc-pane-container {
|
||||
@apply w-full relative;
|
||||
}
|
||||
:root {
|
||||
--vc-slide-translate: 22px;
|
||||
--vc-slide-duration: 0.15s;
|
||||
--vc-slide-timing: ease;
|
||||
}
|
||||
|
||||
.calendar .vc-fade-enter-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-enter-active,
|
||||
.calendar .vc-slide-left-leave-active,
|
||||
.calendar .vc-slide-right-enter-active,
|
||||
.calendar .vc-slide-right-leave-active,
|
||||
.calendar .vc-slide-up-enter-active,
|
||||
.calendar .vc-slide-up-leave-active,
|
||||
.calendar .vc-slide-down-enter-active,
|
||||
.calendar .vc-slide-down-leave-active,
|
||||
.calendar .vc-slide-fade-enter-active,
|
||||
.calendar .vc-slide-fade-leave-active {
|
||||
transition:
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
-webkit-transform var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
transition:
|
||||
transform var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
transition:
|
||||
transform var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
opacity var(--vc-slide-duration) var(--vc-slide-timing),
|
||||
-webkit-transform var(--vc-slide-duration) var(--vc-slide-timing);
|
||||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.calendar .vc-none-leave-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-leave-active,
|
||||
.calendar .vc-slide-right-leave-active,
|
||||
.calendar .vc-slide-up-leave-active,
|
||||
.calendar .vc-slide-down-leave-active {
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.calendar .vc-none-enter-from,
|
||||
.calendar .vc-none-leave-to,
|
||||
.calendar .vc-fade-enter-from,
|
||||
.calendar .vc-fade-leave-to,
|
||||
.calendar .vc-slide-left-enter-from,
|
||||
.calendar .vc-slide-left-leave-to,
|
||||
.calendar .vc-slide-right-enter-from,
|
||||
.calendar .vc-slide-right-leave-to,
|
||||
.calendar .vc-slide-up-enter-from,
|
||||
.calendar .vc-slide-up-leave-to,
|
||||
.calendar .vc-slide-down-enter-from,
|
||||
.calendar .vc-slide-down-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from,
|
||||
.calendar .vc-slide-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.calendar .vc-slide-left-enter-from,
|
||||
.calendar .vc-slide-right-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-left,
|
||||
.calendar .vc-slide-fade-leave-to.direction-left {
|
||||
-webkit-transform: translateX(var(--vc-slide-translate));
|
||||
transform: translateX(var(--vc-slide-translate));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-right-enter-from,
|
||||
.calendar .vc-slide-left-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-right,
|
||||
.calendar .vc-slide-fade-leave-to.direction-right {
|
||||
-webkit-transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-up-enter-from,
|
||||
.calendar .vc-slide-down-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-top,
|
||||
.calendar .vc-slide-fade-leave-to.direction-top {
|
||||
-webkit-transform: translateY(var(--vc-slide-translate));
|
||||
transform: translateY(var(--vc-slide-translate));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-down-enter-from,
|
||||
.calendar .vc-slide-up-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-bottom,
|
||||
.calendar .vc-slide-fade-leave-to.direction-bottom {
|
||||
-webkit-transform: translateY(calc(-1 * var(--vc-slide-translate)));
|
||||
transform: translateY(calc(-1 * var(--vc-slide-translate)));
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|||
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
$attrs.class ?? '')"
|
||||
>
|
||||
<CheckboxIndicator class="flex items-center justify-center text-current">
|
||||
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
|
||||
<CheckIcon class="h-4 w-4" />
|
||||
</CheckboxIndicator>
|
||||
</CheckboxRoot>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxRootEmits, ComboboxRootProps } from 'radix-vue'
|
||||
import { ComboboxRoot, useEmitAsProps, useForwardPropsEmits } from 'radix-vue'
|
||||
import { ComboboxRoot, useForwardPropsEmits } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<ComboboxRootProps>()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|||
|
||||
<template>
|
||||
<ComboboxContent v-bind="forwarded" :class="cn('max-h-[300px] overflow-y-auto overflow-x-hidden', $attrs.class ?? '')">
|
||||
<slot />
|
||||
<div role="presentation">
|
||||
<slot />
|
||||
</div>
|
||||
</ComboboxContent>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useEmitAsProps, useForwardPropsEmits } from 'radix-vue'
|
||||
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useForwardPropsEmits } from 'radix-vue'
|
||||
|
||||
const props = defineProps<DropdownMenuRootProps>()
|
||||
const emits = defineEmits<DropdownMenuRootEmits>()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { useAttrs } from 'vue'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<{
|
||||
defaultValue?: string | number
|
||||
modelValue?: string | number
|
||||
|
|
@ -11,6 +16,8 @@ const emits = defineEmits<{
|
|||
(e: 'update:modelValue', payload: string | number): void
|
||||
}>()
|
||||
|
||||
const { class: className, ...rest } = useAttrs()
|
||||
|
||||
const modelValue = useVModel(props, 'modelValue', emits, {
|
||||
passive: true,
|
||||
defaultValue: props.defaultValue,
|
||||
|
|
@ -18,5 +25,5 @@ const modelValue = useVModel(props, 'modelValue', emits, {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<input v-model="modelValue" type="text" :class="cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', $attrs.class ?? '')">
|
||||
<input v-model="modelValue" :class="cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', className ?? '')" v-bind="rest">
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { readFile, readdir } from 'node:fs/promises'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { join, resolve } from 'pathe'
|
||||
import { compileScript, parse } from 'vue/compiler-sfc'
|
||||
|
||||
import type { Registry } from '../../lib/registry'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { Updater } from '@tanstack/vue-table'
|
||||
import { type ClassValue, clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { type Ref, camelize, getCurrentInstance, toHandlerKey } from 'vue'
|
||||
import { type Ref } from 'vue'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"files": [
|
||||
{
|
||||
"name": "Calendar.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { useVModel } from '@vueuse/core'\nimport type { Calendar } from 'v-calendar'\nimport { DatePicker } from 'v-calendar'\nimport { ChevronLeft, ChevronRight } from 'lucide-vue-next'\nimport { computed, nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\nimport { cn } from '@/lib/utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | number | Date | Partial<{\n start: Date\n end: Date\n }>\n modelModifiers?: object\n columns?: number\n type?: 'single' | 'range'\n}>(), {\n type: 'single',\n columns: 1,\n})\nconst emits = defineEmits<{\n (e: 'update:modelValue', payload: typeof props.modelValue): void\n}>()\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n passive: true,\n})\n\nconst datePicker = ref<InstanceType<typeof DatePicker>>()\n// @ts-expect-error in this current version of v-calendar has the calendaRef instance, which is required to handle arrow nav.\nconst calendarRef = computed<InstanceType<typeof Calendar>>(() => datePicker.value.calendarRef)\n\nfunction handleNav(direction: 'prev' | 'next') {\n if (!calendarRef.value)\n return\n\n if (direction === 'prev')\n calendarRef.value.movePrev()\n else calendarRef.value.moveNext()\n}\n\nonMounted(async () => {\n await nextTick()\n if (modelValue.value instanceof Date && calendarRef.value)\n calendarRef.value.focusDate(modelValue.value)\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div class=\"absolute top-3 flex justify-between w-full px-4\">\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('prev')\">\n <ChevronLeft class=\"w-4 h-4\" />\n </button>\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('next')\">\n <ChevronRight class=\"w-4 h-4\" />\n </button>\n </div>\n\n <DatePicker\n ref=\"datePicker\"\n v-model=\"modelValue\"\n v-bind=\"$attrs\"\n :model-modifiers=\"modelModifiers\"\n class=\"calendar\"\n trim-weeks\n :transition=\"'none'\"\n :columns=\"columns\"\n />\n </div>\n</template>\n\n<style lang=\"postcss\">\n.calendar {\n @apply p-3 text-center;\n}\n.calendar .vc-pane-layout {\n @apply grid gap-4;\n}\n.calendar .vc-title {\n @apply text-sm font-medium pointer-events-none;\n}\n.calendar .vc-pane-header-wrapper {\n @apply hidden;\n}\n.calendar .vc-weeks {\n @apply mt-4;\n}\n.calendar .vc-weekdays {\n @apply flex;\n}\n.calendar .vc-weekday {\n @apply text-muted-foreground rounded-md w-9 font-normal text-[0.8rem];\n}\n.calendar .vc-weeks {\n @apply w-full space-y-2 flex flex-col [&>_div]:grid [&>_div]:grid-cols-7;\n}\n.calendar .vc-day:has(.vc-highlights) {\n @apply bg-accent first:rounded-l-md last:rounded-r-md overflow-hidden;\n}\n.calendar .vc-day-content {\n @apply text-center text-sm p-0 relative focus-within:relative focus-within:z-20 inline-flex items-center justify-center ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 hover:bg-accent hover:text-accent-foreground h-9 w-9 font-normal aria-selected:opacity-100 select-none;\n}\n.calendar .vc-day-content:not(.vc-highlight-content-light) {\n @apply rounded-md;\n}\n.calendar .is-not-in-month:not(:has(.vc-highlight-content-solid)):not(:has(.vc-highlight-content-light)):not(:has(.vc-highlight-content-outline)),\n.calendar .vc-disabled {\n @apply text-muted-foreground opacity-50;\n}\n.calendar .vc-highlight-content-solid, .calendar .vc-highlight-content-outline {\n @apply bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground;\n}\n.calendar .vc-highlight-content-light {\n @apply bg-accent text-accent-foreground;\n}\n</style>\n"
|
||||
"content": "<script setup lang=\"ts\">\nimport { useVModel } from '@vueuse/core'\nimport type { Calendar } from 'v-calendar'\nimport { DatePicker } from 'v-calendar'\nimport { ChevronLeft, ChevronRight } from 'lucide-vue-next'\nimport { computed, nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '@/lib/registry/default/ui/button'\nimport { cn } from '@/lib/utils'\n\n/* Extracted from v-calendar */\ntype DatePickerModel = DatePickerDate | DatePickerRangeObject\ntype DateSource = Date | string | number\ntype DatePickerDate = DateSource | Partial<SimpleDateParts> | null\ninterface DatePickerRangeObject {\n start: Exclude<DatePickerDate, null>\n end: Exclude<DatePickerDate, null>\n}\ninterface SimpleDateParts {\n year: number\n month: number\n day: number\n hours: number\n minutes: number\n seconds: number\n milliseconds: number\n}\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n modelValue?: string | number | Date | DatePickerModel\n modelModifiers?: object\n columns?: number\n type?: 'single' | 'range'\n}>(), {\n type: 'single',\n columns: 1,\n})\nconst emits = defineEmits<{\n (e: 'update:modelValue', payload: typeof props.modelValue): void\n}>()\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n passive: true,\n})\n\nconst datePicker = ref<InstanceType<typeof DatePicker>>()\n// @ts-expect-error in this current version of v-calendar has the calendaRef instance, which is required to handle arrow nav.\nconst calendarRef = computed<InstanceType<typeof Calendar>>(() => datePicker.value.calendarRef)\n\nfunction handleNav(direction: 'prev' | 'next') {\n if (!calendarRef.value)\n return\n\n if (direction === 'prev')\n calendarRef.value.movePrev()\n else calendarRef.value.moveNext()\n}\n\nonMounted(async () => {\n await nextTick()\n if (modelValue.value instanceof Date && calendarRef.value)\n calendarRef.value.focusDate(modelValue.value)\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div class=\"absolute top-3 flex justify-between w-full px-4\">\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('prev')\">\n <ChevronLeft class=\"w-4 h-4\" />\n </button>\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('next')\">\n <ChevronRight class=\"w-4 h-4\" />\n </button>\n </div>\n\n <DatePicker\n ref=\"datePicker\"\n v-model=\"modelValue\"\n v-bind=\"$attrs\"\n :model-modifiers=\"modelModifiers\"\n class=\"calendar\"\n trim-weeks\n :transition=\"'none'\"\n :columns=\"columns\"\n />\n </div>\n</template>\n\n<style lang=\"postcss\">\n.calendar {\n @apply p-3 text-center;\n}\n.calendar .vc-pane-layout {\n @apply grid gap-4;\n}\n.calendar .vc-title {\n @apply text-sm font-medium pointer-events-none;\n}\n.calendar .vc-pane-header-wrapper {\n @apply hidden;\n}\n.calendar .vc-weeks {\n @apply mt-4;\n}\n.calendar .vc-weekdays {\n @apply flex;\n}\n.calendar .vc-weekday {\n @apply text-muted-foreground rounded-md w-9 font-normal text-[0.8rem];\n}\n.calendar .vc-weeks {\n @apply w-full space-y-2 flex flex-col [&>_div]:grid [&>_div]:grid-cols-7;\n}\n.calendar .vc-day:has(.vc-highlights) {\n @apply bg-accent first:rounded-l-md last:rounded-r-md overflow-hidden;\n}\n.calendar .vc-day-content {\n @apply text-center text-sm p-0 relative focus-within:relative focus-within:z-20 inline-flex items-center justify-center ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 hover:bg-accent hover:text-accent-foreground h-9 w-9 font-normal aria-selected:opacity-100 select-none;\n}\n.calendar .vc-day-content:not(.vc-highlight-content-light) {\n @apply rounded-md;\n}\n.calendar .is-not-in-month:not(:has(.vc-highlight-content-solid)):not(:has(.vc-highlight-content-light)):not(:has(.vc-highlight-content-outline)),\n.calendar .vc-disabled {\n @apply text-muted-foreground opacity-50;\n}\n.calendar .vc-highlight-content-solid, .calendar .vc-highlight-content-outline {\n @apply bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground;\n}\n.calendar .vc-highlight-content-light {\n @apply bg-accent text-accent-foreground;\n}\n</style>\n"
|
||||
},
|
||||
{
|
||||
"name": "index.ts",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"files": [
|
||||
{
|
||||
"name": "Checkbox.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'\nimport { Check } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<CheckboxRootProps>()\nconst emits = defineEmits<CheckboxRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n $attrs.class ?? '')\"\n >\n <CheckboxIndicator class=\"flex items-center justify-center text-current\">\n <Check class=\"h-4 w-4\" />\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"
|
||||
"content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'\nimport { Check } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<CheckboxRootProps>()\nconst emits = defineEmits<CheckboxRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n $attrs.class ?? '')\"\n >\n <CheckboxIndicator class=\"flex h-full w-full items-center justify-center text-current\">\n <Check class=\"h-4 w-4\" />\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"
|
||||
},
|
||||
{
|
||||
"name": "index.ts",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"files": [
|
||||
{
|
||||
"name": "Calendar.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport { useVModel } from '@vueuse/core'\nimport type { Calendar } from 'v-calendar'\nimport { DatePicker } from 'v-calendar'\nimport { ChevronLeftIcon, ChevronRightIcon } from '@radix-icons/vue'\nimport { computed, nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '@/lib/registry/new-york/ui/button'\nimport { cn } from '@/lib/utils'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps< {\n modelValue?: string | number | Date | Partial<{\n start: Date\n end: Date\n }>\n modelModifiers?: object\n columns?: number\n type?: 'single' | 'range'\n}>(), {\n type: 'single',\n columns: 1,\n})\nconst emits = defineEmits<{\n (e: 'update:modelValue', payload: typeof props.modelValue): void\n}>()\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n passive: true,\n})\n\nconst datePicker = ref<InstanceType<typeof DatePicker>>()\n// @ts-expect-error in this current version of v-calendar has the calendaRef instance, which is required to handle arrow nav.\nconst calendarRef = computed<InstanceType<typeof Calendar>>(() => datePicker.value.calendarRef)\n\nfunction handleNav(direction: 'prev' | 'next') {\n if (!calendarRef.value)\n return\n\n if (direction === 'prev')\n calendarRef.value.movePrev()\n else calendarRef.value.moveNext()\n}\n\nonMounted(async () => {\n await nextTick()\n if (modelValue.value instanceof Date && calendarRef.value)\n calendarRef.value.focusDate(modelValue.value)\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div class=\"absolute top-3 flex justify-between w-full px-4\">\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('prev')\">\n <ChevronLeftIcon class=\"w-4 h-4\" />\n </button>\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('next')\">\n <ChevronRightIcon class=\"w-4 h-4\" />\n </button>\n </div>\n\n <DatePicker\n ref=\"datePicker\"\n v-bind=\"$attrs\"\n v-model=\"modelValue\"\n :model-modifiers=\"modelModifiers\"\n class=\"calendar\"\n trim-weeks\n :transition=\"'none'\"\n :columns=\"columns\"\n />\n </div>\n</template>\n\n<style lang=\"postcss\">\n.calendar {\n @apply p-3 text-center;\n}\n.calendar .vc-pane-layout {\n @apply grid gap-4;\n}\n.calendar .vc-title {\n @apply text-sm font-medium pointer-events-none;\n}\n.calendar .vc-pane-header-wrapper {\n @apply hidden;\n}\n.calendar .vc-weeks {\n @apply mt-4;\n}\n.calendar .vc-weekdays {\n @apply flex;\n}\n.calendar .vc-weekday {\n @apply text-muted-foreground rounded-md w-8 font-normal text-[0.8rem];\n}\n.calendar .vc-weeks {\n @apply w-full space-y-2 flex flex-col [&>_div]:grid [&>_div]:grid-cols-7;\n}\n.calendar .vc-day:has(.vc-highlights) {\n @apply bg-accent first:rounded-l-md last:rounded-r-md overflow-hidden;\n}\n.calendar .vc-day-content {\n @apply text-center text-sm p-0 relative focus-within:relative focus-within:z-20 inline-flex items-center justify-center ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 hover:bg-accent hover:text-accent-foreground h-8 w-8 font-normal aria-selected:opacity-100 select-none;\n}\n.calendar .vc-day-content:not(.vc-highlight-content-light) {\n @apply rounded-md;\n}\n.calendar .is-not-in-month:not(:has(.vc-highlight-content-solid)):not(:has(.vc-highlight-content-light)):not(:has(.vc-highlight-content-outline)),\n.calendar .vc-disabled {\n @apply text-muted-foreground opacity-50;\n}\n.calendar .vc-highlight-content-solid, .calendar .vc-highlight-content-outline {\n @apply bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground;\n}\n.calendar .vc-highlight-content-light {\n @apply bg-accent text-accent-foreground;\n}\n</style>\n"
|
||||
"content": "<script setup lang=\"ts\">\nimport { useVModel } from '@vueuse/core'\nimport type { Calendar } from 'v-calendar'\nimport { DatePicker } from 'v-calendar'\nimport { ChevronLeftIcon, ChevronRightIcon } from '@radix-icons/vue'\nimport { computed, nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '@/lib/registry/new-york/ui/button'\nimport { cn } from '@/lib/utils'\n\n/* Extracted from v-calendar */\ntype DatePickerModel = DatePickerDate | DatePickerRangeObject\ntype DateSource = Date | string | number\ntype DatePickerDate = DateSource | Partial<SimpleDateParts> | null\ninterface DatePickerRangeObject {\n start: Exclude<DatePickerDate, null>\n end: Exclude<DatePickerDate, null>\n}\ninterface SimpleDateParts {\n year: number\n month: number\n day: number\n hours: number\n minutes: number\n seconds: number\n milliseconds: number\n}\n\ndefineOptions({\n inheritAttrs: false,\n})\nconst props = withDefaults(defineProps< {\n modelValue?: string | number | Date | DatePickerModel\n modelModifiers?: object\n columns?: number\n type?: 'single' | 'range'\n}>(), {\n type: 'single',\n columns: 1,\n})\nconst emits = defineEmits<{\n (e: 'update:modelValue', payload: typeof props.modelValue): void\n}>()\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n passive: true,\n})\n\nconst datePicker = ref<InstanceType<typeof DatePicker>>()\n// @ts-expect-error in this current version of v-calendar has the calendaRef instance, which is required to handle arrow nav.\nconst calendarRef = computed<InstanceType<typeof Calendar>>(() => datePicker.value.calendarRef)\n\nfunction handleNav(direction: 'prev' | 'next') {\n if (!calendarRef.value)\n return\n\n if (direction === 'prev')\n calendarRef.value.movePrev()\n else calendarRef.value.moveNext()\n}\n\nonMounted(async () => {\n await nextTick()\n if (modelValue.value instanceof Date && calendarRef.value)\n calendarRef.value.focusDate(modelValue.value)\n})\n</script>\n\n<template>\n <div class=\"relative\">\n <div class=\"absolute top-3 flex justify-between w-full px-4\">\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('prev')\">\n <ChevronLeftIcon class=\"w-4 h-4\" />\n </button>\n <button :class=\"cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100')\" @click=\"handleNav('next')\">\n <ChevronRightIcon class=\"w-4 h-4\" />\n </button>\n </div>\n\n <DatePicker\n ref=\"datePicker\"\n v-bind=\"$attrs\"\n v-model=\"modelValue\"\n :model-modifiers=\"modelModifiers\"\n class=\"calendar\"\n trim-weeks\n :transition=\"'none'\"\n :columns=\"columns\"\n />\n </div>\n</template>\n\n<style lang=\"postcss\">\n.calendar {\n @apply p-3 text-center;\n}\n.calendar .vc-pane-layout {\n @apply grid gap-4;\n}\n.calendar .vc-title {\n @apply text-sm font-medium pointer-events-none;\n}\n.calendar .vc-pane-header-wrapper {\n @apply hidden;\n}\n.calendar .vc-weeks {\n @apply mt-4;\n}\n.calendar .vc-weekdays {\n @apply flex;\n}\n.calendar .vc-weekday {\n @apply text-muted-foreground rounded-md w-8 font-normal text-[0.8rem];\n}\n.calendar .vc-weeks {\n @apply w-full space-y-2 flex flex-col [&>_div]:grid [&>_div]:grid-cols-7;\n}\n.calendar .vc-day:has(.vc-highlights) {\n @apply bg-accent first:rounded-l-md last:rounded-r-md overflow-hidden;\n}\n.calendar .vc-day-content {\n @apply text-center text-sm p-0 relative focus-within:relative focus-within:z-20 inline-flex items-center justify-center ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 hover:bg-accent hover:text-accent-foreground h-8 w-8 font-normal aria-selected:opacity-100 select-none;\n}\n.calendar .vc-day-content:not(.vc-highlight-content-light) {\n @apply rounded-md;\n}\n.calendar .is-not-in-month:not(:has(.vc-highlight-content-solid)):not(:has(.vc-highlight-content-light)):not(:has(.vc-highlight-content-outline)),\n.calendar .vc-disabled {\n @apply text-muted-foreground opacity-50;\n}\n.calendar .vc-highlight-content-solid, .calendar .vc-highlight-content-outline {\n @apply bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground;\n}\n.calendar .vc-highlight-content-light {\n @apply bg-accent text-accent-foreground;\n}\n</style>\n"
|
||||
},
|
||||
{
|
||||
"name": "index.ts",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"files": [
|
||||
{
|
||||
"name": "Checkbox.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'\nimport { CheckIcon } from '@radix-icons/vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<CheckboxRootProps>()\nconst emits = defineEmits<CheckboxRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n $attrs.class ?? '')\"\n >\n <CheckboxIndicator class=\"flex items-center justify-center text-current\">\n <CheckIcon class=\"h-4 w-4\" />\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"
|
||||
"content": "<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'\nimport { CheckIcon } from '@radix-icons/vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<CheckboxRootProps>()\nconst emits = defineEmits<CheckboxRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n $attrs.class ?? '')\"\n >\n <CheckboxIndicator class=\"flex h-full w-full items-center justify-center text-current\">\n <CheckIcon class=\"h-4 w-4\" />\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"
|
||||
},
|
||||
{
|
||||
"name": "index.ts",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
},
|
||||
{
|
||||
"name": "CommandList.vue",
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'radix-vue'\nimport { ComboboxContent, useForwardPropsEmits } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<ComboboxContentProps>()\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', $attrs.class ?? '')\">\n <slot />\n </ComboboxContent>\n</template>\n"
|
||||
"content": "<script setup lang=\"ts\">\nimport type { ComboboxContentEmits, ComboboxContentProps } from 'radix-vue'\nimport { ComboboxContent, useForwardPropsEmits } from 'radix-vue'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<ComboboxContentProps>()\nconst emits = defineEmits<ComboboxContentEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <ComboboxContent v-bind=\"forwarded\" :class=\"cn('max-h-[300px] overflow-y-auto overflow-x-hidden', $attrs.class ?? '')\">\n <div role=\"presentation\">\n <slot />\n </div>\n </ComboboxContent>\n</template>\n"
|
||||
},
|
||||
{
|
||||
"name": "CommandSeparator.vue",
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": ["esnext", "dom"],
|
||||
"jsx": "preserve",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"moduleResolution": "Node",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"types": ["unplugin-icons/types/vue", "node"],
|
||||
"resolveJsonModule": true,
|
||||
"declaration": false,
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["/**/*.vue", "src", ".vitepress/**/*.vue", "/**/*.ts", ".vitepress/**/*.mts", ".vitepress/**/*.vue", "src/lib/**/*"],
|
||||
"include": ["src", ".vitepress/**/*.vue", ".vitepress/**/*.mts", ".vitepress/**/*.vue", "src/lib/**/*"],
|
||||
"exclude": ["node_modules", "./scripts/build-registry.ts"]
|
||||
}
|
||||
|
|
|
|||
13
apps/www/tsconfig.registry.json
Normal file
13
apps/www/tsconfig.registry.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"declaration": false
|
||||
},
|
||||
"include": ["src/lib/**/*"],
|
||||
"exclude": ["node_modules", "src/lib/registry/**/example/**/*"]
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "shadcn-vue",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.4",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.10.2",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "shadcn-vue",
|
||||
"type": "module",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.4",
|
||||
"description": "Add components to your apps.",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
"node-fetch": "^3.3.2",
|
||||
"ora": "^7.0.1",
|
||||
"prompts": "^2.4.2",
|
||||
"radix-vue": "^1.1.0",
|
||||
"radix-vue": "^1.2.3",
|
||||
"recast": "^0.23.4",
|
||||
"rimraf": "^5.0.1",
|
||||
"ts-morph": "^19.0.0",
|
||||
|
|
|
|||
|
|
@ -128,10 +128,20 @@ module.exports = {
|
|||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: 0 },
|
||||
},
|
||||
"collapsible-down": {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-collapsible-content-height)' },
|
||||
},
|
||||
"collapsible-up": {
|
||||
from: { height: 'var(--radix-collapsible-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
"collapsible-down": "collapsible-down 0.2s ease-in-out",
|
||||
"collapsible-up": "collapsible-up 0.2s ease-in-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type * as z from 'zod'
|
||||
import MagicString from 'magic-string'
|
||||
import type { SFCTemplateBlock } from '@vue/compiler-sfc'
|
||||
import { parse, walk } from '@vue/compiler-sfc'
|
||||
import { parse } from '@vue/compiler-sfc'
|
||||
import { SyntaxKind } from 'ts-morph'
|
||||
import type { registryBaseColorSchema } from '@/src/utils/registry/schema'
|
||||
import type { Transformer } from '@/src/utils/transformers'
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"incremental": true,
|
||||
"target": "es2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
".eslintrc.cjs",
|
||||
|
|
|
|||
1
packages/cli/test/fixtures/nuxt/lib/utils.ts
vendored
1
packages/cli/test/fixtures/nuxt/lib/utils.ts
vendored
|
|
@ -1,6 +1,5 @@
|
|||
import { type ClassValue, clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
|
|
|
|||
2
packages/cli/test/fixtures/nuxt/package.json
vendored
2
packages/cli/test/fixtures/nuxt/package.json
vendored
|
|
@ -13,7 +13,7 @@
|
|||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"lucide-vue-next": "^0.276.0",
|
||||
"radix-vue": "^1.1.0",
|
||||
"radix-vue": "^1.2.3",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -124,10 +124,20 @@ export default {
|
|||
from: { height: \\"var(--radix-accordion-content-height)\\" },
|
||||
to: { height: 0 },
|
||||
},
|
||||
\\"collapsible-down\\": {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-collapsible-content-height)' },
|
||||
},
|
||||
\\"collapsible-up\\": {
|
||||
from: { height: 'var(--radix-collapsible-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
\\"accordion-down\\": \\"accordion-down 0.2s ease-out\\",
|
||||
\\"accordion-up\\": \\"accordion-up 0.2s ease-out\\",
|
||||
\\"collapsible-down\\": \\"collapsible-down 0.2s ease-in-out\\",
|
||||
\\"collapsible-up\\": \\"collapsible-up 0.2s ease-in-out\\",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ describe('transformSFC', () => {
|
|||
`,
|
||||
config: {},
|
||||
})
|
||||
expect(result).toMatchSnapshot()
|
||||
// TODO: Ignore test until https://github.com/radix-vue/shadcn-vue/issues/187 is resolved
|
||||
// expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('defineEmits', async () => {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": false,
|
||||
"baseUrl": ".",
|
||||
"module": "ES2020",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"isolatedModules": false
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
|
|
|
|||
56
packages/module/.gitignore
vendored
Normal file
56
packages/module/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
*.log*
|
||||
|
||||
# Temp directories
|
||||
.temp
|
||||
.tmp
|
||||
.cache
|
||||
|
||||
# Yarn
|
||||
**/.yarn/cache
|
||||
**/.yarn/*state*
|
||||
|
||||
# Generated dirs
|
||||
dist
|
||||
|
||||
# Nuxt
|
||||
.nuxt
|
||||
.output
|
||||
.data
|
||||
.vercel_build_output
|
||||
.build-*
|
||||
.netlify
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Testing
|
||||
reports
|
||||
coverage
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Intellij idea
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
1
packages/module/.npmrc
Normal file
1
packages/module/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
shamefully-hoist=true
|
||||
104
packages/module/README.md
Normal file
104
packages/module/README.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<!--
|
||||
Get your module up and running quickly.
|
||||
|
||||
Find and replace all on all files (CMD+SHIFT+F):
|
||||
- Name: Shadcn Nuxt
|
||||
- Package name: shadcn-nuxt
|
||||
- Description: My new Nuxt module
|
||||
-->
|
||||
|
||||
# Shadcn Nuxt
|
||||
|
||||
[![npm version][npm-version-src]][npm-version-href]
|
||||
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
||||
[![License][license-src]][license-href]
|
||||
[![Nuxt][nuxt-src]][nuxt-href]
|
||||
|
||||
Shadcn Vue module for Nuxt.
|
||||
|
||||
- [✨ Release Notes](/CHANGELOG.md)
|
||||
<!-- - [🏀 Online playground](https://stackblitz.com/github/radix-vue/shadcn-vue?file=playground%2Fapp.vue) -->
|
||||
- [📖 Documentation](https://www.shadcn-vue.com/docs/installation/nuxt.html)
|
||||
|
||||
## Features
|
||||
|
||||
<!-- Highlight some of the features your module provide here -->
|
||||
- ⛰ Auto-import correct and relevant components
|
||||
- more to come...
|
||||
|
||||
## Quick Setup
|
||||
|
||||
1. Add `shadcn-nuxt` dependency to your project
|
||||
|
||||
```bash
|
||||
# Using pnpm
|
||||
pnpm add -D shadcn-nuxt
|
||||
|
||||
# Using yarn
|
||||
yarn add --dev shadcn-nuxt
|
||||
|
||||
# Using npm
|
||||
npm install --save-dev shadcn-nuxt
|
||||
```
|
||||
|
||||
2. Add `shadcn-nuxt` to the `modules` section of `nuxt.config.ts`
|
||||
|
||||
```js
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
'shadcn-nuxt'
|
||||
],
|
||||
shadcn: {
|
||||
/**
|
||||
* Prefix for all the imported component
|
||||
*/
|
||||
prefix: '',
|
||||
/**
|
||||
* Directory that the component lives in.
|
||||
* @default "./components/ui"
|
||||
*/
|
||||
componentDir: './components/ui'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
That's it! You can now use Shadcn Nuxt in your Nuxt app ✨
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Generate type stubs
|
||||
npm run dev:prepare
|
||||
|
||||
# Develop with the playground
|
||||
npm run dev
|
||||
|
||||
# Build the playground
|
||||
npm run dev:build
|
||||
|
||||
# Run ESLint
|
||||
npm run lint
|
||||
|
||||
# Run Vitest
|
||||
npm run test
|
||||
npm run test:watch
|
||||
|
||||
# Release new version
|
||||
npm run release
|
||||
```
|
||||
|
||||
<!-- Badges -->
|
||||
[npm-version-src]: https://img.shields.io/npm/v/shadcn-nuxt/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
[npm-version-href]: https://npmjs.com/package/shadcn-nuxt
|
||||
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/shadcn-nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
[npm-downloads-href]: https://npmjs.com/package/shadcn-nuxt
|
||||
|
||||
[license-src]: https://img.shields.io/npm/l/shadcn-nuxt.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
[license-href]: https://npmjs.com/package/shadcn-nuxt
|
||||
|
||||
[nuxt-src]: https://img.shields.io/badge/Nuxt-18181B?logo=nuxt.js
|
||||
[nuxt-href]: https://nuxt.com
|
||||
51
packages/module/package.json
Normal file
51
packages/module/package.json
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"name": "shadcn-nuxt",
|
||||
"type": "module",
|
||||
"version": "0.8.4",
|
||||
"description": "Add shadcn-vue module to Nuxt",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/radix-vue/shadcn-vue.git",
|
||||
"directory": "packages/module"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/types.d.ts",
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs"
|
||||
}
|
||||
},
|
||||
"main": "./dist/module.cjs",
|
||||
"types": "./dist/types.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"prepack": "nuxt-module-build build",
|
||||
"dev": "nuxi dev playground",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
||||
"lint": "eslint .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest watch",
|
||||
"release": "pnpm run prepack && pnpm publish && git push --follow-tags"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^3.8.2",
|
||||
"ts-morph": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/devtools": "latest",
|
||||
"@nuxt/eslint-config": "^0.2.0",
|
||||
"@nuxt/module-builder": "^0.5.4",
|
||||
"@nuxt/schema": "^3.8.2",
|
||||
"@nuxt/test-utils": "^3.8.1",
|
||||
"@types/node": "^20.9.3",
|
||||
"nuxt": "^3.8.2",
|
||||
"vitest": "^0.33.0"
|
||||
}
|
||||
}
|
||||
11
packages/module/playground/app.vue
Normal file
11
packages/module/playground/app.vue
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<script setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UiButton :variant="'destructive'">
|
||||
hi
|
||||
</UiButton>
|
||||
Nuxt module playground!
|
||||
</div>
|
||||
</template>
|
||||
15
packages/module/playground/components.json
Normal file
15
packages/module/playground/components.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"style": "default",
|
||||
"typescript": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "assets/css/tailwind.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true
|
||||
},
|
||||
"framework": "nuxt",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils"
|
||||
}
|
||||
}
|
||||
23
packages/module/playground/components/ui/button/Button.vue
Normal file
23
packages/module/playground/components/ui/button/Button.vue
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<script setup lang="ts">
|
||||
import { buttonVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
variant?: NonNullable<Parameters<typeof buttonVariants>[0]>['variant']
|
||||
size?: NonNullable<Parameters<typeof buttonVariants>[0]>['size']
|
||||
as?: string
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
as: 'button',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="as"
|
||||
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
32
packages/module/playground/components/ui/button/index.ts
Normal file
32
packages/module/playground/components/ui/button/index.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Button } from './Button.vue'
|
||||
|
||||
export const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useForwardPropsEmits } from 'radix-vue'
|
||||
|
||||
const props = defineProps<DropdownMenuRootProps>()
|
||||
const emits = defineEmits<DropdownMenuRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuRoot v-bind="forwarded">
|
||||
<slot />
|
||||
</DropdownMenuRoot>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
DropdownMenuCheckboxItem,
|
||||
type DropdownMenuCheckboxItemEmits,
|
||||
type DropdownMenuCheckboxItemProps,
|
||||
DropdownMenuItemIndicator,
|
||||
useEmitAsProps,
|
||||
} from 'radix-vue'
|
||||
import { Check } from 'lucide-vue-next'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: string }>()
|
||||
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuCheckboxItem
|
||||
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||
:class=" cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuItemIndicator>
|
||||
<Check class="w-4 h-4" />
|
||||
</DropdownMenuItemIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</DropdownMenuCheckboxItem>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export { DropdownMenuPortal } from 'radix-vue'
|
||||
|
||||
export { default as DropdownMenu } from './DropdownMenu.vue'
|
||||
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
|
||||
6
packages/module/playground/lib/utils.ts
Normal file
6
packages/module/playground/lib/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { type ClassValue, clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
7
packages/module/playground/nuxt.config.ts
Normal file
7
packages/module/playground/nuxt.config.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export default defineNuxtConfig({
|
||||
modules: ['../src/module'],
|
||||
shadcn: {
|
||||
prefix: 'Ui',
|
||||
},
|
||||
devtools: { enabled: true },
|
||||
})
|
||||
22
packages/module/playground/package.json
Normal file
22
packages/module/playground/package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "my-module-playground",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxi dev",
|
||||
"build": "nuxi build",
|
||||
"generate": "nuxi generate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.10.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"lucide-vue-next": "^0.276.0",
|
||||
"radix-vue": "^1.2.3",
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nuxt": "latest"
|
||||
}
|
||||
}
|
||||
73
packages/module/playground/tailwind.config.js
Normal file
73
packages/module/playground/tailwind.config.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
const animate = require('tailwindcss-animate')
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ['class'],
|
||||
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
'2xl': '1400px',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [animate],
|
||||
}
|
||||
3
packages/module/playground/tsconfig.json
Normal file
3
packages/module/playground/tsconfig.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
65
packages/module/src/module.ts
Normal file
65
packages/module/src/module.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { readdirSync } from 'node:fs'
|
||||
import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit'
|
||||
import { Project } from 'ts-morph'
|
||||
|
||||
// Module options TypeScript interface definition
|
||||
export interface ModuleOptions {
|
||||
/**
|
||||
* Prefix for all the imported component
|
||||
*/
|
||||
prefix?: string
|
||||
/**
|
||||
* Directory that the component lives in.
|
||||
* @default "./components/ui"
|
||||
*/
|
||||
componentDir?: string
|
||||
}
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
name: 'shadcn',
|
||||
configKey: 'shadcn',
|
||||
},
|
||||
defaults: {
|
||||
prefix: '',
|
||||
componentDir: './components/ui',
|
||||
},
|
||||
async setup(options, nuxt) {
|
||||
const IGNORE_DIR = '**/components/ui'
|
||||
const COMPONENT_DIR_PATH = options.componentDir!
|
||||
const ROOT_DIR_PATH = nuxt.options.rootDir
|
||||
|
||||
const { resolve } = createResolver(ROOT_DIR_PATH)
|
||||
|
||||
nuxt.options.ignore.push(IGNORE_DIR)
|
||||
nuxt._ignore?.add(IGNORE_DIR)
|
||||
nuxt._ignorePatterns?.push(IGNORE_DIR)
|
||||
|
||||
try {
|
||||
readdirSync(resolve(COMPONENT_DIR_PATH))
|
||||
.forEach(async (dir) => {
|
||||
const filePath = resolve(COMPONENT_DIR_PATH, dir, 'index.ts')
|
||||
|
||||
const project = new Project()
|
||||
project.addSourceFileAtPath(filePath)
|
||||
const sourceFile = project.getSourceFileOrThrow(filePath)
|
||||
const exportedDeclarations = sourceFile.getExportedDeclarations()
|
||||
|
||||
// Filter out non-component export
|
||||
const exportedKeys = Array.from(exportedDeclarations.keys()).filter(key => /^[A-Z]/.test(key))
|
||||
|
||||
exportedKeys.forEach((key) => {
|
||||
addComponent({
|
||||
name: `${options.prefix}${key}`, // name of the component to be used in vue templates
|
||||
export: key, // (optional) if the component is a named (rather than default) export
|
||||
filePath: resolve(filePath),
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof Error)
|
||||
console.warn(err.message)
|
||||
}
|
||||
},
|
||||
})
|
||||
15
packages/module/test/basic.test.ts
Normal file
15
packages/module/test/basic.test.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { $fetch, setup } from '@nuxt/test-utils'
|
||||
|
||||
describe('ssr', async () => {
|
||||
await setup({
|
||||
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
||||
})
|
||||
|
||||
it('renders the index page', async () => {
|
||||
// Get response to a server-rendered page with `$fetch`.
|
||||
const html = await $fetch('/')
|
||||
expect(html).toContain('<div>basic</div>')
|
||||
})
|
||||
})
|
||||
6
packages/module/test/fixtures/basic/app.vue
vendored
Normal file
6
packages/module/test/fixtures/basic/app.vue
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<script setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>basic</div>
|
||||
</template>
|
||||
7
packages/module/test/fixtures/basic/nuxt.config.ts
vendored
Normal file
7
packages/module/test/fixtures/basic/nuxt.config.ts
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import MyModule from '../../../src/module'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
MyModule,
|
||||
],
|
||||
})
|
||||
5
packages/module/test/fixtures/basic/package.json
vendored
Normal file
5
packages/module/test/fixtures/basic/package.json
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "basic",
|
||||
"type": "module",
|
||||
"private": true
|
||||
}
|
||||
3
packages/module/tsconfig.json
Normal file
3
packages/module/tsconfig.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
6325
pnpm-lock.yaml
6325
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user