Skip to content

fix(vue): make theme reactive #3971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
505c1e5
fix(vue): make theme reactive
HugoRCD Apr 24, 2025
713e943
remove log
HugoRCD Apr 24, 2025
8284d05
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD Apr 24, 2025
776aef6
improve code reusability
HugoRCD Apr 25, 2025
1a119e6
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD Apr 25, 2025
88ff542
fix(templates): add missing `border-bg` / `divide-bg` utilities
benjamincanac Apr 25, 2025
996573f
Merge branch 'v3' into fix/3952
HugoRCD Apr 25, 2025
9f7f591
feat(useOverlay): add `closeAll` method (#3984)
genu Apr 25, 2025
6366118
fix(module): support `nuxt-nightly` (#3996)
danielroe Apr 28, 2025
c0347f6
fix(defineShortcuts): bring back `meta` to `ctrl` convert on non maco…
benjamincanac Apr 28, 2025
eb76077
fix(module): define default shades for named tailwindcss colors
benjamincanac Apr 28, 2025
4d17989
chore(deps): update all non-major dependencies (v3) (#4002)
renovate[bot] Apr 28, 2025
0f2d2e5
fix(InputMenu/Select/SelectMenu): add `min-w-fit` to content slot (#4…
hanneskuettner Apr 28, 2025
e8d493a
docs(form-field/switch): fix typo (#4015)
HtmAl Apr 29, 2025
4104cd9
Revert "fix(InputMenu/Select/SelectMenu): add `min-w-fit` to content …
benjamincanac Apr 29, 2025
67bcb49
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD Apr 29, 2025
b507f69
Merge branch 'v3' into fix/3952
HugoRCD Apr 29, 2025
adf11f4
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD Apr 29, 2025
7c4329d
Merge branch 'v3' into fix/3952
HugoRCD May 2, 2025
0c1417b
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD May 5, 2025
322a6f4
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD May 7, 2025
266e870
Merge remote-tracking branch 'origin/v3' into fix/3952
HugoRCD May 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/plugins/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }))
}
Expand Down
34 changes: 2 additions & 32 deletions src/runtime/plugins/colors.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,13 @@
import { computed } from 'vue'
import colors from 'tailwindcss/colors'
import type { UseHeadInput } from '@unhead/vue/types'
import { defineNuxtPlugin, useAppConfig, useNuxtApp, useHead } from '#imports'

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});`
}
import { generateColorStyles } from '../utils/colors'

export default defineNuxtPlugin(() => {
const appConfig = useAppConfig()
const nuxtApp = useNuxtApp()

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 ')}
}
}`
})
const root = computed(() => generateColorStyles(appConfig.ui.colors))

// Head
const headData: UseHeadInput = {
Expand Down
34 changes: 34 additions & 0 deletions src/runtime/utils/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import colors from 'tailwindcss/colors'

export const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const

export 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 ''
}

export 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 ')}`
}

export function generateColor(key: string, shade: number) {
return `--ui-${key}: var(--ui-color-${key}-${shade});`
}

export function generateColorStyles(colors: Record<string, string>) {
const { neutral, ...rest } = colors

return `@layer base {
:root {
${Object.entries(colors).map(([key, value]: [string, string]) => generateShades(key, value)).join('\n ')}
}
:root, .light {
${Object.keys(rest).map(key => generateColor(key, 500)).join('\n ')}
}
.dark {
${Object.keys(rest).map(key => generateColor(key, 400)).join('\n ')}
}
}`
}
5 changes: 4 additions & 1 deletion src/runtime/vue/composables/useAppConfig.ts
Original file line number Diff line number Diff line change
@@ -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
35 changes: 35 additions & 0 deletions src/runtime/vue/plugins/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { computed, watchEffect } from 'vue'
import { useHead } from '@unhead/vue'
import type { Plugin } from 'vue'
import { useAppConfig } from '../composables/useAppConfig'
import { generateColorStyles } from '../../utils/colors'

export default {
install(app) {
app.runWithContext(() => {
const appConfig = useAppConfig()

const root = computed(() => generateColorStyles(appConfig.ui.colors))

useHead({
style: [{
innerHTML: root,
tagPriority: -2,
id: 'nuxt-ui-colors'
}]
})

if (typeof document !== 'undefined') {
watchEffect(() => {
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