feat(module): auto inject lib/utils & refresh the playground (#528)
* chore: add dev:nuxt script * chore(module): add `.npmrc` to playground * chore: bump 'nuxtjs/tailwindcss' and add it to modules * chore: add schema to components.json * chore: bump playground deps * fix: add missing tailwind.css by the cli * chore: bump tailwind config * chore(playground): bump Button component * chore: add comments * refactor: simplify components registration * chore(module): bump deps * chore(module): remove `oxc-parser` * chore: dedupe * feat(module): auto generate `lib/utils` * feat(module): refresh playground style and dark mode * chore: revert components registration and link the comment * chore: readd oxc-parser * chore: bump vitest
This commit is contained in:
parent
3dd2fbda95
commit
631ffb81d5
|
|
@ -39,13 +39,12 @@
|
||||||
"@oxc-parser/wasm": "^0.1.0"
|
"@oxc-parser/wasm": "^0.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/devtools": "latest",
|
"@nuxt/eslint-config": "^0.3.10",
|
||||||
"@nuxt/eslint-config": "^0.3.6",
|
"@nuxt/module-builder": "^0.6.0",
|
||||||
"@nuxt/module-builder": "^0.5.5",
|
|
||||||
"@nuxt/schema": "^3.11.2",
|
"@nuxt/schema": "^3.11.2",
|
||||||
"@nuxt/test-utils": "^3.12.0",
|
"@nuxt/test-utils": "^3.12.1",
|
||||||
"@types/node": "^20.12.7",
|
"@types/node": "^20.12.8",
|
||||||
"nuxt": "^3.11.2",
|
"nuxt": "^3.11.2",
|
||||||
"vitest": "^0.33.0"
|
"vitest": "^1.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
packages/module/playground/.npmrc
Normal file
1
packages/module/playground/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
shamefully-hoist=true
|
||||||
|
|
@ -1,11 +1,38 @@
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
|
import { MoonIcon, SunIcon } from '@radix-icons/vue'
|
||||||
|
|
||||||
|
const isDark = ref(true)
|
||||||
|
useHead({ htmlAttrs: { class: () => isDark.value ? 'dark' : '' } })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<main class="flex flex-col min-h-dvh">
|
||||||
<UiButton :variant="'destructive'">
|
<header class="border-b py-1 ">
|
||||||
hi
|
<div class="container flex justify-between items-center ">
|
||||||
</UiButton>
|
<h1 class="font-medium">
|
||||||
Nuxt module playground!
|
shadcn-vue Playground
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<ClientOnly>
|
||||||
|
<button
|
||||||
|
class="p-2 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors rounded-md"
|
||||||
|
aria-label="Toggle dark mode"
|
||||||
|
@click="isDark = !isDark"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="isDark ? SunIcon : MoonIcon"
|
||||||
|
class="size-5"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</ClientOnly>
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Try your components here -->
|
||||||
|
<section class="container grow my-4 p-4 rounded-md border grid place-content-center">
|
||||||
|
<UiButton variant="destructive">
|
||||||
|
Hi
|
||||||
|
</UiButton>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
78
packages/module/playground/assets/css/tailwind.css
Normal file
78
packages/module/playground/assets/css/tailwind.css
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@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%;
|
||||||
|
|
||||||
|
--card: 0 0% 100%;
|
||||||
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--border: 214.3 31.8% 91.4%;
|
||||||
|
--input: 214.3 31.8% 91.4%;
|
||||||
|
|
||||||
|
--primary: 222.2 47.4% 11.2%;
|
||||||
|
--primary-foreground: 210 40% 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%;
|
||||||
|
|
||||||
|
--destructive: 0 84.2% 60.2%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 222.2 84% 4.9%;
|
||||||
|
--foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--muted: 217.2 32.6% 17.5%;
|
||||||
|
--muted-foreground: 215 20.2% 65.1%;
|
||||||
|
|
||||||
|
--popover: 222.2 84% 4.9%;
|
||||||
|
--popover-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--card: 222.2 84% 4.9%;
|
||||||
|
--card-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--border: 217.2 32.6% 17.5%;
|
||||||
|
--input: 217.2 32.6% 17.5%;
|
||||||
|
|
||||||
|
--primary: 210 40% 98%;
|
||||||
|
--primary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--secondary: 217.2 32.6% 17.5%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--accent: 217.2 32.6% 17.5%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--destructive: 0 62.8% 30.6%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--ring: 212.7 26.8% 83.9%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"$schema": "https://shadcn-vue.com/schema.json",
|
||||||
"style": "default",
|
"style": "default",
|
||||||
"typescript": true,
|
"typescript": true,
|
||||||
"tailwind": {
|
"tailwind": {
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { buttonVariants } from '.'
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { Primitive, type PrimitiveProps } from 'radix-vue'
|
||||||
|
import { type ButtonVariants, buttonVariants } from '.'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
interface Props {
|
interface Props extends PrimitiveProps {
|
||||||
variant?: NonNullable<Parameters<typeof buttonVariants>[0]>['variant']
|
variant?: ButtonVariants['variant']
|
||||||
size?: NonNullable<Parameters<typeof buttonVariants>[0]>['size']
|
size?: ButtonVariants['size']
|
||||||
as?: string
|
class?: HTMLAttributes['class']
|
||||||
}
|
}
|
||||||
|
|
||||||
withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
as: 'button',
|
as: 'button',
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<component
|
<Primitive
|
||||||
:is="as"
|
:as="as"
|
||||||
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
|
:as-child="asChild"
|
||||||
|
:class="cn(buttonVariants({ variant, size }), props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</component>
|
</Primitive>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { cva } from 'class-variance-authority'
|
import { type VariantProps, cva } from 'class-variance-authority'
|
||||||
|
|
||||||
export { default as Button } from './Button.vue'
|
export { default as Button } from './Button.vue'
|
||||||
|
|
||||||
export const buttonVariants = cva(
|
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',
|
'inline-flex items-center justify-center whitespace-nowrap 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: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
|
|
@ -19,6 +19,7 @@ export const buttonVariants = cva(
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'h-10 px-4 py-2',
|
default: 'h-10 px-4 py-2',
|
||||||
|
xs: 'h-7 rounded px-2',
|
||||||
sm: 'h-9 rounded-md px-3',
|
sm: 'h-9 rounded-md px-3',
|
||||||
lg: 'h-11 rounded-md px-8',
|
lg: 'h-11 rounded-md px-8',
|
||||||
icon: 'h-10 w-10',
|
icon: 'h-10 w-10',
|
||||||
|
|
@ -30,3 +31,5 @@ export const buttonVariants = cva(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export type ButtonVariants = VariantProps<typeof buttonVariants>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
modules: ['../src/module'],
|
modules: ['@nuxtjs/tailwindcss', '../src/module'],
|
||||||
shadcn: {
|
shadcn: {
|
||||||
prefix: 'Ui',
|
prefix: 'Ui',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,17 @@
|
||||||
"generate": "nuxi generate"
|
"generate": "nuxi generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/tailwindcss": "^6.10.1",
|
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.1.1",
|
||||||
"embla-carousel": "8.0.0-rc19",
|
"embla-carousel": "8.0.0-rc19",
|
||||||
"embla-carousel-vue": "8.0.0-rc19",
|
"embla-carousel-vue": "8.0.0-rc19",
|
||||||
"lucide-vue-next": "^0.276.0",
|
"lucide-vue-next": "^0.276.0",
|
||||||
"radix-vue": "^1.4.8",
|
"radix-vue": "^1.7.2",
|
||||||
"tailwind-merge": "^2.0.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7"
|
"tailwindcss-animate": "^1.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@nuxtjs/tailwindcss": "^6.12.0",
|
||||||
"nuxt": "latest"
|
"nuxt": "latest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ const animate = require('tailwindcss-animate')
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: ['class'],
|
darkMode: ['class'],
|
||||||
|
safelist: ['dark'],
|
||||||
|
prefix: '',
|
||||||
|
|
||||||
theme: {
|
theme: {
|
||||||
container: {
|
container: {
|
||||||
|
|
@ -49,6 +51,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
|
xl: 'calc(var(--radius) + 4px)',
|
||||||
lg: 'var(--radius)',
|
lg: 'var(--radius)',
|
||||||
md: 'calc(var(--radius) - 2px)',
|
md: 'calc(var(--radius) - 2px)',
|
||||||
sm: 'calc(var(--radius) - 4px)',
|
sm: 'calc(var(--radius) - 4px)',
|
||||||
|
|
@ -62,10 +65,20 @@ module.exports = {
|
||||||
from: { height: 'var(--radix-accordion-content-height)' },
|
from: { height: 'var(--radix-accordion-content-height)' },
|
||||||
to: { height: 0 },
|
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: {
|
animation: {
|
||||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||||
'accordion-up': 'accordion-up 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,8 @@
|
||||||
import { readFileSync, readdirSync } from 'node:fs'
|
import { readFileSync, readdirSync } from 'node:fs'
|
||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit'
|
|
||||||
import { parseSync } from '@oxc-parser/wasm'
|
import { parseSync } from '@oxc-parser/wasm'
|
||||||
|
import { addComponent, addTemplate, createResolver, defineNuxtModule, findPath, useLogger } from '@nuxt/kit'
|
||||||
|
import { UTILS } from '../../cli/src/utils/templates'
|
||||||
|
|
||||||
// TODO: add test to make sure all registry is being parse correctly
|
// TODO: add test to make sure all registry is being parse correctly
|
||||||
// Module options TypeScript interface definition
|
// Module options TypeScript interface definition
|
||||||
|
|
@ -29,15 +30,36 @@ export default defineNuxtModule<ModuleOptions>({
|
||||||
async setup({ prefix, componentDir }, nuxt) {
|
async setup({ prefix, componentDir }, nuxt) {
|
||||||
const COMPONENT_DIR_PATH = componentDir!
|
const COMPONENT_DIR_PATH = componentDir!
|
||||||
const ROOT_DIR_PATH = nuxt.options.rootDir
|
const ROOT_DIR_PATH = nuxt.options.rootDir
|
||||||
|
const UTILS_ALIAS = '@/lib/utils' // Use the same path from the cli for backward compatibility
|
||||||
const { resolve, resolvePath } = createResolver(ROOT_DIR_PATH)
|
const { resolve, resolvePath } = createResolver(ROOT_DIR_PATH)
|
||||||
|
const logger = useLogger('shadcn-nuxt')
|
||||||
|
|
||||||
|
// `lib/utils`
|
||||||
|
const utilsTemplate = addTemplate({
|
||||||
|
filename: 'shadcn-nuxt/utils.ts',
|
||||||
|
getContents: () => UTILS,
|
||||||
|
write: true,
|
||||||
|
})
|
||||||
|
nuxt.options.alias = { [UTILS_ALIAS]: utilsTemplate.dst, ...nuxt.options.alias } // We add our alias to the top to avoid conflicts with nuxt built in `@` alias
|
||||||
|
|
||||||
|
// Recommend to remove the root `lib/utils` if exists
|
||||||
|
const isRootUtilsExists = await findPath('./lib/utils.ts', { cwd: ROOT_DIR_PATH })
|
||||||
|
if (isRootUtilsExists)
|
||||||
|
logger.warn('[shadcn-nuxt] `lib/utils.ts` is auto generated by the module and can be safely removed.')
|
||||||
|
|
||||||
|
// Components Auto Imports
|
||||||
|
const componentsPath = resolve(COMPONENT_DIR_PATH)
|
||||||
|
|
||||||
|
// Tell Nuxt to not scan `componentsDir` for auto imports as we will do it manually
|
||||||
|
// See https://github.com/radix-vue/shadcn-vue/pull/528#discussion_r1590206268
|
||||||
nuxt.hook('components:dirs', (dirs) => {
|
nuxt.hook('components:dirs', (dirs) => {
|
||||||
dirs.unshift({
|
dirs.unshift({
|
||||||
path: resolve(COMPONENT_DIR_PATH),
|
path: componentsPath,
|
||||||
extensions: [],
|
extensions: [],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Manually scan `componentsDir` for components and register them for auto imports
|
||||||
try {
|
try {
|
||||||
readdirSync(resolve(COMPONENT_DIR_PATH))
|
readdirSync(resolve(COMPONENT_DIR_PATH))
|
||||||
.forEach(async (dir) => {
|
.forEach(async (dir) => {
|
||||||
|
|
|
||||||
780
pnpm-lock.yaml
780
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user