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:
Muhammad Mahmoud 2024-05-07 07:44:15 +03:00 committed by GitHub
parent 3dd2fbda95
commit 631ffb81d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 435 additions and 556 deletions

View File

@ -39,13 +39,12 @@
"@oxc-parser/wasm": "^0.1.0"
},
"devDependencies": {
"@nuxt/devtools": "latest",
"@nuxt/eslint-config": "^0.3.6",
"@nuxt/module-builder": "^0.5.5",
"@nuxt/eslint-config": "^0.3.10",
"@nuxt/module-builder": "^0.6.0",
"@nuxt/schema": "^3.11.2",
"@nuxt/test-utils": "^3.12.0",
"@types/node": "^20.12.7",
"@nuxt/test-utils": "^3.12.1",
"@types/node": "^20.12.8",
"nuxt": "^3.11.2",
"vitest": "^0.33.0"
"vitest": "^1.6.0"
}
}

View File

@ -0,0 +1 @@
shamefully-hoist=true

View File

@ -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>
<template>
<div>
<UiButton :variant="'destructive'">
hi
</UiButton>
Nuxt module playground!
<main class="flex flex-col min-h-dvh">
<header class="border-b py-1 ">
<div class="container flex justify-between items-center ">
<h1 class="font-medium">
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>
</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>

View 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;
}
}

View File

@ -1,4 +1,5 @@
{
"$schema": "https://shadcn-vue.com/schema.json",
"style": "default",
"typescript": true,
"tailwind": {

View File

@ -1,23 +1,26 @@
<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'
interface Props {
variant?: NonNullable<Parameters<typeof buttonVariants>[0]>['variant']
size?: NonNullable<Parameters<typeof buttonVariants>[0]>['size']
as?: string
interface Props extends PrimitiveProps {
variant?: ButtonVariants['variant']
size?: ButtonVariants['size']
class?: HTMLAttributes['class']
}
withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<Props>(), {
as: 'button',
})
</script>
<template>
<component
:is="as"
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
<Primitive
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
>
<slot />
</component>
</Primitive>
</template>

View File

@ -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 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: {
variant: {
@ -19,6 +19,7 @@ export const buttonVariants = cva(
},
size: {
default: 'h-10 px-4 py-2',
xs: 'h-7 rounded px-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10',
@ -30,3 +31,5 @@ export const buttonVariants = cva(
},
},
)
export type ButtonVariants = VariantProps<typeof buttonVariants>

View File

@ -1,5 +1,5 @@
export default defineNuxtConfig({
modules: ['../src/module'],
modules: ['@nuxtjs/tailwindcss', '../src/module'],
shadcn: {
prefix: 'Ui',
},

View File

@ -8,17 +8,17 @@
"generate": "nuxi generate"
},
"dependencies": {
"@nuxtjs/tailwindcss": "^6.10.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"clsx": "^2.1.1",
"embla-carousel": "8.0.0-rc19",
"embla-carousel-vue": "8.0.0-rc19",
"lucide-vue-next": "^0.276.0",
"radix-vue": "^1.4.8",
"tailwind-merge": "^2.0.0",
"radix-vue": "^1.7.2",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@nuxtjs/tailwindcss": "^6.12.0",
"nuxt": "latest"
}
}

View File

@ -3,6 +3,8 @@ const animate = require('tailwindcss-animate')
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ['class'],
safelist: ['dark'],
prefix: '',
theme: {
container: {
@ -49,6 +51,7 @@ module.exports = {
},
},
borderRadius: {
xl: 'calc(var(--radius) + 4px)',
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)',
@ -62,10 +65,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',
},
},
},

View File

@ -1,7 +1,8 @@
import { readFileSync, readdirSync } from 'node:fs'
import { join } from 'node:path'
import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit'
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
// Module options TypeScript interface definition
@ -29,15 +30,36 @@ export default defineNuxtModule<ModuleOptions>({
async setup({ prefix, componentDir }, nuxt) {
const COMPONENT_DIR_PATH = componentDir!
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 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) => {
dirs.unshift({
path: resolve(COMPONENT_DIR_PATH),
path: componentsPath,
extensions: [],
})
})
// Manually scan `componentsDir` for components and register them for auto imports
try {
readdirSync(resolve(COMPONENT_DIR_PATH))
.forEach(async (dir) => {

File diff suppressed because it is too large Load Diff