diff --git a/package.json b/package.json index e4f8fba6fe..bfb9de4e44 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,12 @@ "style": "./dist/runtime/index.css", "import": "./dist/module.mjs" }, + "./sources": { + "style": "./dist/runtime/sources.css" + }, + "./theme": { + "style": "./dist/runtime/theme.css" + }, "./unplugin": { "types": "./dist/unplugin.d.mts", "import": "./dist/unplugin.mjs" @@ -88,7 +94,9 @@ } }, "imports": { - "#build/ui.css": "./.nuxt/ui.css" + "#build/ui.css": "./.nuxt/ui.css", + "#build/ui-sources.css": "./.nuxt/ui-sources.css", + "#build/ui-theme.css": "./.nuxt/ui-theme.css" }, "bin": { "nuxt-ui": "./cli/index.mjs" diff --git a/src/runtime/sources.css b/src/runtime/sources.css new file mode 100644 index 0000000000..58ff993d92 --- /dev/null +++ b/src/runtime/sources.css @@ -0,0 +1,2 @@ +@import '#build/ui-sources.css'; +@source './components'; diff --git a/src/runtime/theme.css b/src/runtime/theme.css new file mode 100644 index 0000000000..ce8f3747f4 --- /dev/null +++ b/src/runtime/theme.css @@ -0,0 +1,54 @@ +@import '#build/ui-theme.css'; +@import './keyframes.css'; + +@variant light (&:where(.light, .light *)); +@variant dark (&:where(.dark, .dark *)); + +@layer theme { + :root, :host { + --ui-header-height: --spacing(16); + } + + :root, :host, .light { + --ui-text-dimmed: var(--ui-color-neutral-400); + --ui-text-muted: var(--ui-color-neutral-500); + --ui-text-toned: var(--ui-color-neutral-600); + --ui-text: var(--ui-color-neutral-700); + --ui-text-highlighted: var(--ui-color-neutral-900); + --ui-text-inverted: white; + + --ui-bg: white; + --ui-bg-muted: var(--ui-color-neutral-50); + --ui-bg-elevated: var(--ui-color-neutral-100); + --ui-bg-accented: var(--ui-color-neutral-200); + --ui-bg-inverted: var(--ui-color-neutral-900); + + --ui-border: var(--ui-color-neutral-200); + --ui-border-muted: var(--ui-color-neutral-200); + --ui-border-accented: var(--ui-color-neutral-300); + --ui-border-inverted: var(--ui-color-neutral-900); + + --ui-radius: 0.25rem; + --ui-container: 80rem; + } + + .dark { + --ui-text-dimmed: var(--ui-color-neutral-500); + --ui-text-muted: var(--ui-color-neutral-400); + --ui-text-toned: var(--ui-color-neutral-300); + --ui-text: var(--ui-color-neutral-200); + --ui-text-highlighted: white; + --ui-text-inverted: var(--ui-color-neutral-900); + + --ui-bg: var(--ui-color-neutral-900); + --ui-bg-muted: var(--ui-color-neutral-800); + --ui-bg-elevated: var(--ui-color-neutral-800); + --ui-bg-accented: var(--ui-color-neutral-700); + --ui-bg-inverted: white; + + --ui-border: var(--ui-color-neutral-800); + --ui-border-muted: var(--ui-color-neutral-700); + --ui-border-accented: var(--ui-color-neutral-700); + --ui-border-inverted: white; + } +} diff --git a/src/templates.ts b/src/templates.ts index 15ddecbb02..159e39a484 100644 --- a/src/templates.ts +++ b/src/templates.ts @@ -187,6 +187,96 @@ export function getTemplates(options: ModuleOptions, uiConfig: Record { + return await generateSources() + } + }) + + // Separate template for theme styles (can be used with CSS cascade layers) + templates.push({ + filename: 'ui-theme.css', + write: true, + getContents: async () => { + const prefix = options.theme?.prefix ? `${options.theme.prefix}:` : '' + + return `@layer base { + body { + @apply ${prefix}antialiased ${prefix}text-default ${prefix}bg-default ${prefix}scheme-light ${prefix}dark:scheme-dark; + } +} + +@theme static { + --color-old-neutral-50: ${colors.neutral[50]}; + --color-old-neutral-100: ${colors.neutral[100]}; + --color-old-neutral-200: ${colors.neutral[200]}; + --color-old-neutral-300: ${colors.neutral[300]}; + --color-old-neutral-400: ${colors.neutral[400]}; + --color-old-neutral-500: ${colors.neutral[500]}; + --color-old-neutral-600: ${colors.neutral[600]}; + --color-old-neutral-700: ${colors.neutral[700]}; + --color-old-neutral-800: ${colors.neutral[800]}; + --color-old-neutral-900: ${colors.neutral[900]}; + --color-old-neutral-950: ${colors.neutral[950]}; +} + +@theme default inline { + ${[...(options.theme?.colors || []).filter(color => !colors[color as keyof typeof colors]), 'neutral'].map(color => [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950].map(shade => `--color-${color}-${shade}: var(--ui-color-${color}-${shade});`).join('\n\t')).join('\n\t')} + ${options.theme?.colors?.map(color => `--color-${color}: var(--ui-${color});`).join('\n\t')} + --radius-xs: calc(var(--ui-radius) * 0.5); + --radius-sm: var(--ui-radius); + --radius-md: calc(var(--ui-radius) * 1.5); + --radius-lg: calc(var(--ui-radius) * 2); + --radius-xl: calc(var(--ui-radius) * 3); + --radius-2xl: calc(var(--ui-radius) * 4); + --radius-3xl: calc(var(--ui-radius) * 6); + --text-color-dimmed: var(--ui-text-dimmed); + --text-color-muted: var(--ui-text-muted); + --text-color-toned: var(--ui-text-toned); + --text-color-default: var(--ui-text); + --text-color-highlighted: var(--ui-text-highlighted); + --text-color-inverted: var(--ui-text-inverted); + --background-color-default: var(--ui-bg); + --background-color-muted: var(--ui-bg-muted); + --background-color-elevated: var(--ui-bg-elevated); + --background-color-accented: var(--ui-bg-accented); + --background-color-inverted: var(--ui-bg-inverted); + --background-color-border: var(--ui-border); + --border-color-default: var(--ui-border); + --border-color-muted: var(--ui-border-muted); + --border-color-accented: var(--ui-border-accented); + --border-color-inverted: var(--ui-border-inverted); + --border-color-bg: var(--ui-bg); + --ring-color-default: var(--ui-border); + --ring-color-muted: var(--ui-border-muted); + --ring-color-accented: var(--ui-border-accented); + --ring-color-inverted: var(--ui-border-inverted); + --ring-color-bg: var(--ui-bg); + --ring-offset-color-default: var(--ui-border); + --ring-offset-color-muted: var(--ui-border-muted); + --ring-offset-color-accented: var(--ui-border-accented); + --ring-offset-color-inverted: var(--ui-border-inverted); + --ring-offset-color-bg: var(--ui-bg); + --divide-color-default: var(--ui-border); + --divide-color-muted: var(--ui-border-muted); + --divide-color-accented: var(--ui-border-accented); + --divide-color-inverted: var(--ui-border-inverted); + --divide-color-bg: var(--ui-bg); + --outline-color-default: var(--ui-border); + --outline-color-inverted: var(--ui-border-inverted); + --stroke-default: var(--ui-border); + --stroke-inverted: var(--ui-border-inverted); + --fill-default: var(--ui-border); + --fill-inverted: var(--ui-border-inverted); +} +` + } + }) + + // Combined template for backwards compatibility templates.push({ filename: 'ui.css', write: true,