feat: wire up Tailwind v4 and shadcn-vue token mapping alongside PrimeVue
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
8751c150cd
commit
106c214b16
10 changed files with 965 additions and 22 deletions
26
packages/library/components.json
Normal file
26
packages/library/components.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"$schema": "https://shadcn-vue.com/schema.json",
|
||||
"style": "reka-nova",
|
||||
"font": "geist-sans",
|
||||
"typescript": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/assets/css/tailwind.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"rtl": false,
|
||||
"pointer": false,
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"composables": "@/composables"
|
||||
},
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle",
|
||||
"registries": {}
|
||||
}
|
||||
|
|
@ -38,5 +38,16 @@
|
|||
"@vitest/coverage-v8": "^2.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"vite-plugin-dts": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lucide/vue": "^1.24.0",
|
||||
"@tailwindcss/vite": "^4.3.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"reka-ui": "^2.10.1",
|
||||
"shadcn-vue": "^2.7.4",
|
||||
"tailwind-merge": "^3.6.0",
|
||||
"tailwindcss": "^4.3.2",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
174
packages/library/src/assets/css/tailwind.css
Normal file
174
packages/library/src/assets/css/tailwind.css
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/* ============================================================
|
||||
tailwind.css
|
||||
Toggle themes by setting data-theme on <html>:
|
||||
<html data-theme="hades">
|
||||
<html data-theme="apollo">
|
||||
============================================================ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600&family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500&display=swap');
|
||||
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@import "shadcn-vue/tailwind.css";
|
||||
|
||||
@theme inline {
|
||||
--font-sans: var(--font-sans);
|
||||
--font-serif: var(--font-serif);
|
||||
--font-mono: var(--font-mono);
|
||||
--color-background: var(--surface-0);
|
||||
--color-foreground: var(--text-body);
|
||||
--color-card: var(--surface-1);
|
||||
--color-card-foreground: var(--text-body);
|
||||
--color-popover: var(--surface-2);
|
||||
--color-popover-foreground: var(--text-body);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-fg);
|
||||
--color-secondary: var(--neutral);
|
||||
--color-secondary-foreground: var(--neutral-fg);
|
||||
--color-muted: var(--surface-2);
|
||||
--color-muted-foreground: var(--text-muted);
|
||||
--color-accent: var(--surface-3);
|
||||
--color-accent-foreground: var(--text-high);
|
||||
--color-destructive: var(--danger);
|
||||
--color-destructive-foreground: var(--danger-fg);
|
||||
--color-info: var(--info);
|
||||
--color-info-foreground: var(--info-fg);
|
||||
--color-success: var(--success);
|
||||
--color-success-foreground: var(--success-fg);
|
||||
--color-warning: var(--warn);
|
||||
--color-warning-foreground: var(--warn-fg);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--border);
|
||||
--color-ring: var(--primary);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.3125rem;
|
||||
}
|
||||
|
||||
/* ── HADES ───────────────────────────────────────────────── */
|
||||
[data-theme='hades'] {
|
||||
--surface-0: #18160f;
|
||||
--surface-1: #28241a;
|
||||
--surface-2: #2e2a1e;
|
||||
--surface-3: #322e22;
|
||||
--track: #32302a;
|
||||
|
||||
--border: #4a4538;
|
||||
--border-hi: #5a5040;
|
||||
--border-lo: #38342a;
|
||||
|
||||
--primary: #d4b278;
|
||||
--primary-fg: #0e0c08;
|
||||
|
||||
--warn: #e08840;
|
||||
--warn-subtle: #281808;
|
||||
--warn-border: #4a2c10;
|
||||
--warn-fg: #fff8e8;
|
||||
|
||||
--danger: #7a1a1a;
|
||||
--danger-subtle: #200808;
|
||||
--danger-border: #3a1010;
|
||||
--danger-fg: #fff8e8;
|
||||
|
||||
--info: #88aec8;
|
||||
--info-subtle: #101e2c;
|
||||
--info-border: #1e3850;
|
||||
--info-fg: #0a1828;
|
||||
|
||||
--neutral: #7a6e60;
|
||||
--neutral-fg: #fff8e8;
|
||||
|
||||
--success: #6aaa7a;
|
||||
--success-subtle: #0e2214;
|
||||
--success-border: #1e4228;
|
||||
--success-fg: #fff8e8;
|
||||
|
||||
--text-high: #f4f0e8;
|
||||
--text-body: #d0c8b8;
|
||||
--text-muted: #908878;
|
||||
--text-dim: #807868;
|
||||
--text-label: #c0b8a8;
|
||||
|
||||
--focus-ring: 0 0 0 3px rgba(212, 178, 120, 0.65);
|
||||
|
||||
--font-serif: 'Cinzel', Georgia, serif;
|
||||
--font-sans: 'IBM Plex Sans', system-ui, sans-serif;
|
||||
--font-mono: 'IBM Plex Mono', monospace;
|
||||
}
|
||||
|
||||
/* ── APOLLO ──────────────────────────────────────────────── */
|
||||
[data-theme='apollo'] {
|
||||
--surface-0: #faf7f2;
|
||||
--surface-1: #f4f0e8;
|
||||
--surface-2: #eee9df;
|
||||
--surface-3: #e4ddd0;
|
||||
--track: #e4ddd0;
|
||||
|
||||
--border: #bab2a0;
|
||||
--border-hi: #c0b8a8;
|
||||
--border-lo: #ccc4b4;
|
||||
|
||||
--primary: #b8860b;
|
||||
--primary-fg: #fff8e8;
|
||||
|
||||
--warn: #9a6020;
|
||||
--warn-subtle: #fdf3e0;
|
||||
--warn-border: #e8d0a0;
|
||||
--warn-fg: #fff8e8;
|
||||
|
||||
--danger: #7a1a1a;
|
||||
--danger-subtle: #faeaea;
|
||||
--danger-border: #c8a0a0;
|
||||
--danger-fg: #fff8e8;
|
||||
|
||||
--info: #3a5a8a;
|
||||
--info-subtle: #e8eef8;
|
||||
--info-border: #b0c4e0;
|
||||
--info-fg: #fff8e8;
|
||||
|
||||
--neutral: #8a8070;
|
||||
--neutral-fg: #fff8e8;
|
||||
|
||||
--success: #5a7a40;
|
||||
--success-subtle: #eef4e8;
|
||||
--success-border: #c0d4a8;
|
||||
--success-fg: #fff8e8;
|
||||
|
||||
--text-high: #1a1610;
|
||||
--text-body: #3a3020;
|
||||
--text-muted: #5a5040;
|
||||
--text-dim: #8a8070;
|
||||
--text-label: #5a5040;
|
||||
|
||||
--focus-ring: 0 0 0 3px rgba(184, 134, 11, 0.65);
|
||||
|
||||
--font-serif: 'Cinzel', Georgia, serif;
|
||||
--font-sans: 'IBM Plex Sans', system-ui, sans-serif;
|
||||
--font-mono: 'IBM Plex Mono', monospace;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 14px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
min-height: 100vh;
|
||||
}
|
||||
:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: var(--focus-ring);
|
||||
}
|
||||
}
|
||||
7
packages/library/src/lib/utils.ts
Normal file
7
packages/library/src/lib/utils.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import type { ClassValue } from "clsx"
|
||||
import { clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
28
packages/library/tests/tailwind-tokens.spec.ts
Normal file
28
packages/library/tests/tailwind-tokens.spec.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { describe, it, expect } from 'vitest'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
const cssPath = resolve(process.cwd(), 'src/assets/css/tailwind.css')
|
||||
|
||||
describe('tailwind token mapping', () => {
|
||||
const css = readFileSync(cssPath, 'utf-8')
|
||||
|
||||
it('maps --color-primary onto the existing --primary token', () => {
|
||||
expect(css).toMatch(/--color-primary:\s*var\(--primary\)/)
|
||||
})
|
||||
|
||||
it('maps --color-destructive onto the existing --danger token', () => {
|
||||
expect(css).toMatch(/--color-destructive:\s*var\(--danger\)/)
|
||||
})
|
||||
|
||||
it('defines the extra info/success/warning color slots', () => {
|
||||
expect(css).toMatch(/--color-info:\s*var\(--info\)/)
|
||||
expect(css).toMatch(/--color-success:\s*var\(--success\)/)
|
||||
expect(css).toMatch(/--color-warning:\s*var\(--warn\)/)
|
||||
})
|
||||
|
||||
it('keeps both Hades and Apollo theme selectors', () => {
|
||||
expect(css).toContain("[data-theme='hades']")
|
||||
expect(css).toContain("[data-theme='apollo']")
|
||||
})
|
||||
})
|
||||
|
|
@ -2,12 +2,14 @@ import { fileURLToPath } from 'node:url'
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import dts from 'vite-plugin-dts'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), dts({ tsconfigPath: './tsconfig.json', include: ['src/**/*'] })],
|
||||
plugins: [vue(), tailwindcss(), dts({ tsconfigPath: './tsconfig.json', include: ['src/**/*'] })],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export default defineConfig({
|
|||
resolve: {
|
||||
alias: {
|
||||
'~': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@nychthemeron/library": "workspace:*",
|
||||
"@tailwindcss/vite": "^4.3.2",
|
||||
"primevue": "^4.5.0",
|
||||
"vue": "^3.5.32"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { fileURLToPath } from 'node:url'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
plugins: [vue(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
|
|
|
|||
Loading…
Reference in a new issue