Merge branch 'dev' of https://github.com/selemondev/shadcn-vue into dev
This commit is contained in:
commit
4b686b85d5
35
apps/www/.vitepress/theme/components/CodeSandbox.vue
Normal file
35
apps/www/.vitepress/theme/components/CodeSandbox.vue
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { makeCodeSandboxParams } from '../utils/codeeditor'
|
||||
import Tooltip from './Tooltip.vue'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
import { type Style } from '@/lib/registry/styles'
|
||||
|
||||
const props = defineProps<{
|
||||
name: string
|
||||
code: string
|
||||
style: Style
|
||||
}>()
|
||||
|
||||
const sources = ref<Record<string, string>>({})
|
||||
|
||||
onMounted(() => {
|
||||
sources.value['App.vue'] = props.code
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank">
|
||||
<input type="hidden" name="query" value="file=src/App.vue">
|
||||
<input type="hidden" name="environment" value="server">
|
||||
<input type="hidden" name="hidedevtools" value="1">
|
||||
<input type="hidden" name="parameters" :value="makeCodeSandboxParams(name, style, sources)">
|
||||
|
||||
<Tooltip :content="`Open ${name} in CodeSandbox`">
|
||||
<Button :variant="'ghost'" :size="'icon'" type="submit">
|
||||
<Icon icon="ph-codesandbox-logo" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</form>
|
||||
</template>
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import StyleSwitcher from './StyleSwitcher.vue'
|
||||
import ComponentLoader from './ComponentLoader.vue'
|
||||
import Stackblitz from './Stackblitz.vue'
|
||||
import CodeSandbox from './CodeSandbox.vue'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
|
@ -39,6 +41,11 @@ const { style } = useConfigStore()
|
|||
<TabsContent value="preview" class="relative rounded-md border">
|
||||
<div class="flex items-center justify-between p-4">
|
||||
<StyleSwitcher />
|
||||
|
||||
<div class="flex items-center gap-x-1">
|
||||
<Stackblitz :key="style" :style="style" :name="name" :code="decodeURIComponent(sfcTsCode ?? '')" />
|
||||
<CodeSandbox :key="style" :style="style" :name="name" :code="decodeURIComponent(sfcTsCode ?? '')" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="cn('preview flex min-h-[350px] w-full justify-center p-6 lg:p-10', {
|
||||
|
|
|
|||
34
apps/www/.vitepress/theme/components/Stackblitz.vue
Normal file
34
apps/www/.vitepress/theme/components/Stackblitz.vue
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { makeStackblitzParams } from '../utils/codeeditor'
|
||||
import Tooltip from './Tooltip.vue'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
import { type Style } from '@/lib/registry/styles'
|
||||
|
||||
const props = defineProps<{
|
||||
name: string
|
||||
code: string
|
||||
style: Style
|
||||
}>()
|
||||
|
||||
const sources = ref<Record<string, string>>({})
|
||||
|
||||
onMounted(() => {
|
||||
sources.value['App.vue'] = props.code
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
makeStackblitzParams(props.name, props.style, sources.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Tooltip :content="`Open ${name} in Stackblitz`">
|
||||
<Button :variant="'ghost'" :size="'icon'" @click="handleClick">
|
||||
<Icon icon="simple-icons:stackblitz" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
26
apps/www/.vitepress/theme/components/Tooltip.vue
Normal file
26
apps/www/.vitepress/theme/components/Tooltip.vue
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/lib/registry/default/ui/tooltip'
|
||||
|
||||
defineProps<{
|
||||
content: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<slot />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{{ content }}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</template>
|
||||
|
|
@ -119,26 +119,29 @@ watch(() => $route.path, (n) => {
|
|||
</div>
|
||||
</Button>
|
||||
|
||||
<div
|
||||
v-for="link in links"
|
||||
:key="link.name"
|
||||
class="flex items-center space-x-1"
|
||||
>
|
||||
<a :href="link.href" target="_blank" class="text-foreground">
|
||||
<component :is="link.icon" class="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-1">
|
||||
<Button
|
||||
v-for="link in links"
|
||||
:key="link.name"
|
||||
as="a"
|
||||
:href="link.href" target="_blank"
|
||||
:variant="'ghost'" :size="'icon'"
|
||||
>
|
||||
<component :is="link.icon" class="w-[20px] h-[20px]" />
|
||||
</Button>
|
||||
|
||||
<button
|
||||
class="flex items-center justify-center"
|
||||
aria-label="Toggle dark mode"
|
||||
@click="toggleDark()"
|
||||
>
|
||||
<component
|
||||
:is="isDark ? RadixIconsSun : RadixIconsMoon"
|
||||
class="w-5 h-5 text-foreground"
|
||||
/>
|
||||
</button>
|
||||
<Button
|
||||
class="flex items-center justify-center"
|
||||
aria-label="Toggle dark mode"
|
||||
:variant="'ghost'"
|
||||
:size="'icon'" @click="toggleDark()"
|
||||
>
|
||||
<component
|
||||
:is="isDark ? RadixIconsSun : RadixIconsMoon"
|
||||
class="w-[20px] h-[20px] text-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
|||
212
apps/www/.vitepress/theme/utils/codeeditor.ts
Normal file
212
apps/www/.vitepress/theme/utils/codeeditor.ts
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
import { getParameters } from 'codesandbox/lib/api/define'
|
||||
import sdk from '@stackblitz/sdk'
|
||||
import { dependencies as deps } from '../../../package.json'
|
||||
import { Index as demoIndex } from '../../../../www/__registry__'
|
||||
import tailwindConfigRaw from '../../../tailwind.config?raw'
|
||||
import cssRaw from '../../../../../packages/cli/test/fixtures/nuxt/assets/css/tailwind.css?raw'
|
||||
import { type Style } from '@/lib/registry/styles'
|
||||
|
||||
export function makeCodeSandboxParams(componentName: string, style: Style, sources: Record<string, string>) {
|
||||
let files = {}
|
||||
files = constructFiles(componentName, style, sources)
|
||||
return getParameters({ files, template: 'node' })
|
||||
}
|
||||
|
||||
export function makeStackblitzParams(componentName: string, style: Style, sources: Record<string, string>) {
|
||||
const files: Record<string, string> = {}
|
||||
Object.entries(constructFiles(componentName, style, sources)).forEach(([k, v]) => (files[`${k}`] = typeof v.content === 'object' ? JSON.stringify(v.content, null, 2) : v.content))
|
||||
return sdk.openProject({
|
||||
title: `${componentName} - Radix Vue`,
|
||||
files,
|
||||
template: 'node',
|
||||
}, {
|
||||
newWindow: true,
|
||||
openFile: ['src/App.vue'],
|
||||
})
|
||||
}
|
||||
|
||||
const viteConfig = {
|
||||
'vite.config.js': {
|
||||
content: `import path from "path"
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})`,
|
||||
isBinary: false,
|
||||
},
|
||||
'index.html': {
|
||||
content: `<!DOCTYPE html>
|
||||
<html class="dark" lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
isBinary: false,
|
||||
},
|
||||
}
|
||||
|
||||
function constructFiles(componentName: string, style: Style, sources: Record<string, string>) {
|
||||
const componentsJson = {
|
||||
style,
|
||||
tailwind: {
|
||||
config: 'tailwind.config.js',
|
||||
css: 'src/assets/index.css',
|
||||
baseColor: 'zinc',
|
||||
cssVariables: true,
|
||||
},
|
||||
aliases: {
|
||||
utils: '@/utils',
|
||||
components: '@/components',
|
||||
},
|
||||
}
|
||||
|
||||
const iconPackage = style === 'default' ? 'lucide-vue-next' : '@radix-icons/vue'
|
||||
const dependencies = {
|
||||
'vue': 'latest',
|
||||
'radix-vue': deps['radix-vue'],
|
||||
'@radix-ui/colors': 'latest',
|
||||
'clsx': 'latest',
|
||||
'class-variance-authority': 'latest',
|
||||
'tailwind-merge': 'latest',
|
||||
'tailwindcss-animate': 'latest',
|
||||
[iconPackage]: 'latest',
|
||||
'shadcn-vue': 'latest',
|
||||
'typescript': 'latest',
|
||||
}
|
||||
|
||||
const devDependencies = {
|
||||
'vite': 'latest',
|
||||
'@vitejs/plugin-vue': 'latest',
|
||||
'vue-tsc': 'latest',
|
||||
'tailwindcss': 'latest',
|
||||
'postcss': 'latest',
|
||||
'autoprefixer': 'latest',
|
||||
}
|
||||
|
||||
const transformImportPath = (code: string) => {
|
||||
let parsed = code
|
||||
parsed = parsed.replaceAll(`@/lib/registry/${style}`, '@/components')
|
||||
parsed = parsed.replaceAll('@/lib/utils', '@/utils')
|
||||
return parsed
|
||||
}
|
||||
|
||||
const componentFiles = Object.keys(sources).filter(key => key.endsWith('.vue') && key !== 'index.vue')
|
||||
const components: Record<string, any> = {}
|
||||
componentFiles.forEach((i) => {
|
||||
components[`src/${i}`] = {
|
||||
isBinary: false,
|
||||
content: transformImportPath(sources[i]),
|
||||
}
|
||||
})
|
||||
|
||||
// @ts-expect-error componentName migth not exist in Index
|
||||
const registryDependencies = demoIndex[style][componentName as any]?.registryDependencies?.filter(i => i !== 'utils')
|
||||
|
||||
const files = {
|
||||
'package.json': {
|
||||
content: {
|
||||
name: `shadcn-vue-${componentName.toLowerCase().replace(/ /g, '-')}`,
|
||||
scripts: { start: `shadcn-vue add ${registryDependencies.join(' ')} -y && vite` },
|
||||
dependencies,
|
||||
devDependencies,
|
||||
},
|
||||
isBinary: false,
|
||||
},
|
||||
'components.json': {
|
||||
content: componentsJson,
|
||||
isBinary: false,
|
||||
},
|
||||
...viteConfig,
|
||||
'tailwind.config.js': {
|
||||
content: tailwindConfigRaw,
|
||||
isBinary: false,
|
||||
},
|
||||
'postcss.config.js': {
|
||||
content: `module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
}
|
||||
}`,
|
||||
isBinary: false,
|
||||
},
|
||||
'tsconfig.json': {
|
||||
content: `{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
isBinary: false,
|
||||
},
|
||||
'src/utils.ts': {
|
||||
isBinary: false,
|
||||
content: `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))
|
||||
}`,
|
||||
},
|
||||
'src/assets/index.css': {
|
||||
content: cssRaw,
|
||||
isBinary: false,
|
||||
},
|
||||
'src/main.ts': {
|
||||
content: `import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import './assets/global.css';
|
||||
import './assets/index.css';
|
||||
|
||||
createApp(App).mount('#app')`,
|
||||
isBinary: false,
|
||||
},
|
||||
'src/App.vue': {
|
||||
isBinary: false,
|
||||
content: sources['index.vue'],
|
||||
},
|
||||
...components,
|
||||
'src/assets/global.css': {
|
||||
content: `body {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding-top: 120px;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: hsl(var(--background));
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
color: hsl(var(--foreground));
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-feature-settings: "rlig" 1, "calt" 1;
|
||||
}
|
||||
|
||||
#app {
|
||||
@apply w-full flex items-center justify-center px-12;
|
||||
}`,
|
||||
isBinary: false,
|
||||
},
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
|
@ -576,27 +576,7 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyTable.vue'],
|
||||
},
|
||||
ActivityGoal: {
|
||||
name: 'ActivityGoal',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'card', 'themes', 'config'],
|
||||
component: () => import('../src/lib/registry/default/example/ActivityGoal.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/ActivityGoal.vue'],
|
||||
},
|
||||
DataTable: {
|
||||
name: 'DataTable',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'checkbox', 'dropdown-menu', 'input', 'table', 'card', 'utils'],
|
||||
component: () => import('../src/lib/registry/default/example/DataTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/DataTable.vue'],
|
||||
},
|
||||
Metric: {
|
||||
name: 'Metric',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['card', 'config'],
|
||||
component: () => import('../src/lib/registry/default/example/Metric.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/Metric.vue'],
|
||||
},
|
||||
|
||||
},
|
||||
'new-york': {
|
||||
AccordionDemo: {
|
||||
|
|
@ -1173,26 +1153,5 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyTable.vue'],
|
||||
},
|
||||
ActivityGoal: {
|
||||
name: 'ActivityGoal',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'card', 'themes', 'config'],
|
||||
component: () => import('../src/lib/registry/new-york/example/ActivityGoal.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/ActivityGoal.vue'],
|
||||
},
|
||||
DataTable: {
|
||||
name: 'DataTable',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'checkbox', 'dropdown-menu', 'input', 'table', 'card', 'utils'],
|
||||
component: () => import('../src/lib/registry/new-york/example/DataTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/DataTable.vue'],
|
||||
},
|
||||
Metric: {
|
||||
name: 'Metric',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['card', 'config'],
|
||||
component: () => import('../src/lib/registry/new-york/example/Metric.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/Metric.vue'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"@formkit/auto-animate": "^0.8.0",
|
||||
"@morev/vue-transitions": "^2.3.6",
|
||||
"@radix-icons/vue": "^1.0.0",
|
||||
"@stackblitz/sdk": "^1.9.0",
|
||||
"@tanstack/vue-table": "^8.10.3",
|
||||
"@unovis/ts": "^1.2.1",
|
||||
"@unovis/vue": "1.3.0-alpha.3",
|
||||
|
|
@ -22,8 +23,10 @@
|
|||
"@vueuse/core": "^10.4.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"codesandbox": "^2.2.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"lucide-vue-next": "^0.276.0",
|
||||
"radix-vue": "^0.4.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"v-calendar": "^3.1.0",
|
||||
"vee-validate": "4.11.7",
|
||||
|
|
@ -44,7 +47,6 @@
|
|||
"@vue/compiler-dom": "^3.3.4",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"lodash.template": "^4.5.0",
|
||||
"radix-vue": "^0.4.1",
|
||||
"rimraf": "^5.0.1",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ import { computed, nextTick, onMounted, ref } from 'vue'
|
|||
import { buttonVariants } from '../button'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps< {
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue?: string | number | Date | Partial<{
|
||||
start: Date
|
||||
end: Date
|
||||
|
|
@ -41,7 +45,6 @@ function handleNav(direction: 'prev' | 'next') {
|
|||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
if (modelValue.value instanceof Date && calendarRef.value)
|
||||
calendarRef.value.focusDate(modelValue.value)
|
||||
|
|
@ -59,7 +62,16 @@ onMounted(async () => {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<DatePicker ref="datePicker" v-model="modelValue" :model-modifiers="modelModifiers" class="calendar" trim-weeks :transition="'none'" :columns="columns" />
|
||||
<DatePicker
|
||||
ref="datePicker"
|
||||
v-model="modelValue"
|
||||
v-bind="$attrs"
|
||||
:model-modifiers="modelModifiers"
|
||||
class="calendar"
|
||||
trim-weeks
|
||||
:transition="'none'"
|
||||
:columns="columns"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ import { computed, nextTick, onMounted, ref } from 'vue'
|
|||
import { buttonVariants } from '../button'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps< {
|
||||
modelValue?: string | number | Date | Partial<{
|
||||
start: Date
|
||||
|
|
@ -41,7 +45,6 @@ function handleNav(direction: 'prev' | 'next') {
|
|||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
if (modelValue.value instanceof Date && calendarRef.value)
|
||||
calendarRef.value.focusDate(modelValue.value)
|
||||
|
|
@ -59,7 +62,16 @@ onMounted(async () => {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<DatePicker ref="datePicker" v-model="modelValue" :model-modifiers="modelModifiers" class="calendar" trim-weeks :transition="'none'" :columns="columns" />
|
||||
<DatePicker
|
||||
ref="datePicker"
|
||||
v-bind="$attrs"
|
||||
v-model="modelValue"
|
||||
:model-modifiers="modelModifiers"
|
||||
class="calendar"
|
||||
trim-weeks
|
||||
:transition="'none'"
|
||||
:columns="columns"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ export const styles = [
|
|||
},
|
||||
] as const
|
||||
|
||||
export type Style = (typeof styles)[number]
|
||||
export type Style = typeof styles[number]['name']
|
||||
|
|
|
|||
|
|
@ -9,7 +9,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 '../button'\nimport { cn } from '@/lib/utils'\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 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 ref=\"datePicker\" v-model=\"modelValue\" :model-modifiers=\"modelModifiers\" class=\"calendar\" trim-weeks :transition=\"'none'\" :columns=\"columns\" />\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 '../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"
|
||||
},
|
||||
{
|
||||
"name": "index.ts",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,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 '../button'\nimport { cn } from '@/lib/utils'\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 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 ref=\"datePicker\" v-model=\"modelValue\" :model-modifiers=\"modelModifiers\" class=\"calendar\" trim-weeks :transition=\"'none'\" :columns=\"columns\" />\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 { ChevronLeft, ChevronRight } from 'lucide-vue-next'\nimport { computed, nextTick, onMounted, ref } from 'vue'\nimport { buttonVariants } from '../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-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",
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import { computed } from 'vue'
|
|||
import { useSessionStorage } from '@vueuse/core'
|
||||
import { useData } from 'vitepress'
|
||||
import { type Theme, themes } from './../lib/registry/themes'
|
||||
import { styles } from '@/lib/registry/styles'
|
||||
import { type Style, styles } from '@/lib/registry/styles'
|
||||
|
||||
interface Config {
|
||||
theme: Theme['name']
|
||||
radius: number
|
||||
style: string
|
||||
style: Style
|
||||
}
|
||||
|
||||
export const RADII = [0, 0.25, 0.5, 0.75, 1]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "shadcn-vue",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.8.0",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "shadcn-vue",
|
||||
"type": "module",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.1",
|
||||
"description": "Add components to your apps.",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
@ -49,6 +49,7 @@
|
|||
"@babel/core": "^7.22.17",
|
||||
"@babel/parser": "^7.22.16",
|
||||
"@babel/plugin-transform-typescript": "^7.22.15",
|
||||
"@vue/compiler-sfc": "^3.3.6",
|
||||
"chalk": "5.3.0",
|
||||
"commander": "^11.0.0",
|
||||
"cosmiconfig": "^8.3.6",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
rawConfigSchema,
|
||||
resolveConfigPaths,
|
||||
} from '../utils/get-config'
|
||||
import { transformCJSToESM } from '../utils/transformers/transform-cjs-to-esm'
|
||||
|
||||
const PROJECT_DEPENDENCIES = {
|
||||
base: [
|
||||
|
|
@ -110,6 +111,7 @@ export async function promptForConfig(
|
|||
{ title: 'Vite', value: 'vite' },
|
||||
{ title: 'Nuxt', value: 'nuxt' },
|
||||
{ title: 'Laravel', value: 'laravel' },
|
||||
{ title: 'Astro', value: 'astro' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -136,7 +138,7 @@ export async function promptForConfig(
|
|||
type: 'text',
|
||||
name: 'tailwindCss',
|
||||
message: `Where is your ${highlight('Tailwind CSS')} file?`,
|
||||
initial: (prev, values) => defaultConfig?.tailwind.css ?? TAILWIND_CSS_PATH[values.framework as 'vite' | 'nuxt' | 'laravel'],
|
||||
initial: (prev, values) => defaultConfig?.tailwind.css ?? TAILWIND_CSS_PATH[values.framework as 'vite' | 'nuxt' | 'laravel' | 'astro'],
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
|
|
@ -151,8 +153,14 @@ export async function promptForConfig(
|
|||
{
|
||||
type: 'text',
|
||||
name: 'tailwindConfig',
|
||||
message: `Where is your ${highlight('tailwind.config.js')} located?`,
|
||||
initial: defaultConfig?.tailwind.config ?? DEFAULT_TAILWIND_CONFIG,
|
||||
message: `Where is your ${highlight('tailwind.config')} located?`,
|
||||
initial: (prev, values) => {
|
||||
if (defaultConfig?.tailwind.config)
|
||||
return defaultConfig?.tailwind.config
|
||||
if (values.framework === 'astro')
|
||||
return 'tailwind.config.mjs'
|
||||
else return DEFAULT_TAILWIND_CONFIG
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
|
|
@ -235,9 +243,12 @@ export async function runInit(cwd: string, config: Config) {
|
|||
// Write tailwind config.
|
||||
await fs.writeFile(
|
||||
config.resolvedPaths.tailwindConfig,
|
||||
config.tailwind.cssVariables
|
||||
? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework })
|
||||
: template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework }),
|
||||
transformCJSToESM(
|
||||
config.resolvedPaths.tailwindConfig,
|
||||
config.tailwind.cssVariables
|
||||
? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework })
|
||||
: template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework }),
|
||||
),
|
||||
'utf8',
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const TAILWIND_CSS_PATH = {
|
|||
nuxt: 'assets/css/tailwind.css',
|
||||
vite: 'src/assets/index.css',
|
||||
laravel: 'resources/css/app.css',
|
||||
astro: 'src/styles/globals.css',
|
||||
}
|
||||
|
||||
// TODO: Figure out if we want to support all cosmiconfig formats.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ export function cn(...inputs: ClassValue[]) {
|
|||
}
|
||||
`
|
||||
|
||||
export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */
|
||||
export const TAILWIND_CONFIG = `const animate = require("tailwindcss-animate")
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
|
|
@ -41,10 +43,12 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [animate],
|
||||
}`
|
||||
|
||||
export const TAILWIND_CONFIG_WITH_VARIABLES = `/** @type {import('tailwindcss').Config} */
|
||||
export const TAILWIND_CONFIG_WITH_VARIABLES = `const animate = require("tailwindcss-animate")
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
<% if (framework === 'vite') { %>
|
||||
|
|
@ -61,6 +65,10 @@ module.exports = {
|
|||
"./resources/views/**/*.blade.php",
|
||||
"./resources/js/**/*.{<%- extension %>,<%- extension %>x,vue}",
|
||||
],
|
||||
<% } else if (framework === 'astro') { %>
|
||||
content: [
|
||||
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
|
||||
],
|
||||
<% } %>
|
||||
theme: {
|
||||
container: {
|
||||
|
|
@ -127,5 +135,5 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [animate],
|
||||
}`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
export function transformCJSToESM(filename: string, code: string) {
|
||||
if (filename.endsWith('.mjs')) {
|
||||
return code
|
||||
.replace(/const\s([\w\d_]+)\s*=\s*require\((.*)\);?/g, 'import $1 from $2')
|
||||
.replace(/module\.exports = /g, 'export default ')
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { SyntaxKind } from 'ts-morph'
|
||||
import type * as z from 'zod'
|
||||
import MagicString from 'magic-string'
|
||||
import { parse, walk } from '@vue/compiler-sfc'
|
||||
import { SyntaxKind } from 'ts-morph'
|
||||
import type { registryBaseColorSchema } from '@/src/utils/registry/schema'
|
||||
import type { Transformer } from '@/src/utils/transformers'
|
||||
|
||||
|
|
@ -9,22 +11,32 @@ export const transformCssVars: Transformer = async ({
|
|||
baseColor,
|
||||
}) => {
|
||||
// No transform if using css variables.
|
||||
if (config.tailwind?.cssVariables || !baseColor?.inlineColors)
|
||||
if (config.tailwind?.cssVariables || !baseColor?.inlineColors || sourceFile.getFilePath().endsWith('ts'))
|
||||
return sourceFile
|
||||
|
||||
const parsed = parse(sourceFile.getText())
|
||||
const template = parsed.descriptor.template
|
||||
|
||||
if (!template)
|
||||
return sourceFile
|
||||
|
||||
sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral).forEach((node) => {
|
||||
if (template.loc.start.offset >= node.getPos())
|
||||
return sourceFile
|
||||
|
||||
const value = node.getText()
|
||||
|
||||
if (value.includes('cn(')) {
|
||||
const splitted = value.split('\'').map(i => applyColorMapping(i, baseColor.inlineColors))
|
||||
node.replaceWithText(`${splitted.join('\'')}`)
|
||||
const hasClosingDoubleQuote = value.match(/"/g)?.length === 2
|
||||
if (value.search('\'') === -1 && hasClosingDoubleQuote) {
|
||||
const mapped = applyColorMapping(value.replace(/"/g, ''), baseColor.inlineColors)
|
||||
node.replaceWithText(`"${mapped}"`)
|
||||
}
|
||||
else if (value) {
|
||||
const valueWithColorMapping = applyColorMapping(
|
||||
value.replace(/"/g, ''),
|
||||
baseColor.inlineColors,
|
||||
)
|
||||
node.replaceWithText(`"${valueWithColorMapping.trim()}"`)
|
||||
else {
|
||||
const s = new MagicString(value)
|
||||
s.replace(/'(.*?)'/g, (substring) => {
|
||||
return `'${applyColorMapping(substring.replace(/\'/g, ''), baseColor.inlineColors)}'`
|
||||
})
|
||||
node.replaceWithText(s.toString())
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -103,6 +115,6 @@ export function applyColorMapping(
|
|||
if (!lightMode.includes(className))
|
||||
lightMode.push(className)
|
||||
}
|
||||
|
||||
return `${lightMode.join(' ')} ${darkMode.join(' ').trim()}`
|
||||
const combined = `${lightMode.join(' ').replace(/\'/g, '')} ${darkMode.join(' ').trim()}`.trim()
|
||||
return `${combined}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,68 +5,64 @@
|
|||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 222.2 84% 4.9%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border:240 5.9% 90%;
|
||||
--input:240 5.9% 90%;
|
||||
--ring:240 5.9% 10%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
--background:240 10% 3.9%;
|
||||
--foreground:0 0% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--card:240 10% 3.9%;
|
||||
--card-foreground:0 0% 98%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
--popover:240 10% 3.9%;
|
||||
--popover-foreground:0 0% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
--primary:0 0% 98%;
|
||||
--primary-foreground:240 5.9% 10%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--secondary:240 3.7% 15.9%;
|
||||
--secondary-foreground:0 0% 98%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--muted:240 3.7% 15.9%;
|
||||
--muted-foreground:240 5% 64.9%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
--accent:240 3.7% 15.9%;
|
||||
--accent-foreground:0 0% 98%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
--destructive:0 62.8% 30.6%;
|
||||
--destructive-foreground:0 0% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
--border:240 3.7% 15.9%;
|
||||
--input:240 3.7% 15.9%;
|
||||
--ring:240 4.9% 83.9%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`handle tailwind config template correctly 1`] = `
|
||||
"import animate from \\"tailwindcss-animate\\"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: [\\"class\\"],
|
||||
content: [
|
||||
'./pages/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./components/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./app/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./src/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: \\"2rem\\",
|
||||
screens: {
|
||||
\\"2xl\\": \\"1400px\\",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
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],
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`handle tailwind config template correctly 2`] = `
|
||||
"import animate from \\"tailwindcss-animate\\"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: [\\"class\\"],
|
||||
<% if (framework === 'vite') { %>
|
||||
content: [
|
||||
'./pages/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./components/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./app/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
'./src/**/*.{<%- extension %>,<%- extension %>x,vue}',
|
||||
],
|
||||
<% } else if (framework === 'laravel') { %>
|
||||
content: [
|
||||
\\"./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php\\",
|
||||
\\"./storage/framework/views/*.php\\",
|
||||
\\"./resources/views/**/*.blade.php\\",
|
||||
\\"./resources/js/**/*.{<%- extension %>,<%- extension %>x,vue}\\",
|
||||
],
|
||||
<% } else if (framework === 'astro') { %>
|
||||
content: [
|
||||
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
|
||||
],
|
||||
<% } %>
|
||||
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],
|
||||
}"
|
||||
`;
|
||||
|
|
@ -17,6 +17,6 @@ exports[`transform css vars 2`] = `
|
|||
exports[`transform css vars 3`] = `
|
||||
"<script setup lang=\\"ts\\"></script>
|
||||
<template>
|
||||
<div :class=\\"cn( 'bg-white hover:bg-stone-100 dark:bg-stone-950 dark:hover:bg-stone-800', true && 'text-stone-50 sm:focus:text-stone-900 dark:text-stone-900 dark:sm:focus:text-stone-50')\\" >foo</div>
|
||||
<div :class=\\"cn('bg-white hover:bg-stone-100 dark:bg-stone-950 dark:hover:bg-stone-800', true && 'text-stone-50 sm:focus:text-stone-900 dark:text-stone-900 dark:sm:focus:text-stone-50')\\">foo</div>
|
||||
</template>\\""
|
||||
`;
|
||||
|
|
|
|||
8
packages/cli/test/utils/transform-cjs-to-esm.test.ts
Normal file
8
packages/cli/test/utils/transform-cjs-to-esm.test.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { expect, test } from 'vitest'
|
||||
import { TAILWIND_CONFIG, TAILWIND_CONFIG_WITH_VARIABLES } from '../../src/utils/templates'
|
||||
import { transformCJSToESM } from '../../src/utils/transformers/transform-cjs-to-esm'
|
||||
|
||||
test('handle tailwind config template correctly', () => {
|
||||
expect(transformCJSToESM('.mjs', TAILWIND_CONFIG)).toMatchSnapshot()
|
||||
expect(transformCJSToESM('.mjs', TAILWIND_CONFIG_WITH_VARIABLES)).toMatchSnapshot()
|
||||
})
|
||||
1552
pnpm-lock.yaml
1552
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user