fix(vue): make theme reactive

This commit is contained in:
HugoRCD
2025-04-24 16:09:16 +02:00
parent c63a6dd133
commit 505c1e502a
3 changed files with 74 additions and 1 deletions

View File

@@ -16,6 +16,7 @@ export default function PluginsPlugin(options: NuxtUIOptions) {
const plugins = globSync(['**/*', '!*.d.ts'], { cwd: join(runtimeDir, 'plugins'), absolute: true })
plugins.unshift(resolvePathSync('../runtime/vue/plugins/head', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
plugins.push(resolvePathSync('../runtime/vue/plugins/colors', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
if (options.colorMode) {
plugins.push(resolvePathSync('../runtime/vue/plugins/color-mode', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
}

View File

@@ -1,3 +1,6 @@
import { reactive } from 'vue'
import appConfig from '#build/app.config'
export const useAppConfig = () => appConfig
const _appConfig = reactive(appConfig)
export const useAppConfig = () => _appConfig

View File

@@ -0,0 +1,69 @@
import { computed, watch, watchEffect } from 'vue'
import colors from 'tailwindcss/colors'
import { useHead } from '@unhead/vue'
import type { Plugin } from 'vue'
import { useAppConfig } from '../composables/useAppConfig'
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const
function getColor(color: keyof typeof colors, shade: typeof shades[number]): string {
if (color in colors && typeof colors[color] === 'object' && shade in colors[color]) {
return colors[color][shade] as string
}
return ''
}
function generateShades(key: string, value: string) {
return `${shades.map(shade => `--ui-color-${key}-${shade}: var(--color-${value === 'neutral' ? 'old-neutral' : value}-${shade}, ${getColor(value as keyof typeof colors, shade)});`).join('\n ')}`
}
function generateColor(key: string, shade: number) {
return `--ui-${key}: var(--ui-color-${key}-${shade});`
}
export default {
install(app) {
app.runWithContext(() => {
const appConfig = useAppConfig()
const root = computed(() => {
const { neutral, ...colors } = appConfig.ui.colors
return `@layer base {
:root {
${Object.entries(appConfig.ui.colors).map(([key, value]: [string, string]) => generateShades(key, value)).join('\n ')}
}
:root, .light {
${Object.keys(colors).map(key => generateColor(key, 500)).join('\n ')}
}
.dark {
${Object.keys(colors).map(key => generateColor(key, 400)).join('\n ')}
}
}`
})
useHead({
style: [{
innerHTML: root,
tagPriority: -2,
id: 'nuxt-ui-colors'
}]
})
if (typeof document !== 'undefined') {
watchEffect(() => {
console.log('Colors changed, updating style:', JSON.stringify(appConfig.ui.colors))
let styleEl = document.querySelector('#nuxt-ui-colors-vue') as HTMLStyleElement
if (!styleEl) {
styleEl = document.createElement('style')
styleEl.id = 'nuxt-ui-colors-vue'
document.head.appendChild(styleEl)
}
styleEl.innerHTML = root.value
})
}
})
}
} satisfies Plugin