diff --git a/README.md b/README.md index c156c1b..747c076 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ The Vite dev server auto-detects DDEV/Docker environments for proper HMR configu │ └── views/ # Blade templates (128 files) │ └── woocommerce/ # Full WooCommerce template overrides ├── languages/ # Translations (text domain: %theme_name%) -├── theme.json # WordPress design tokens (generated by Vite) +├── theme.json # Base settings; the build adds the design tokens ├── vite.config.js # Build configuration └── routes.php # Theme routes (optional) ``` @@ -61,6 +61,26 @@ The Vite dev server auto-detects DDEV/Docker environments for proper HMR configu - **Accessibility**: Semantic HTML, ARIA labels, keyboard navigation - **i18n**: Fully translatable (French included) +## Design tokens + +The design lives in the `@theme static` block of `resources/assets/css/app.css`: +colours, type scale, fonts and radii, with concrete values. `npm run build` +writes them into the `theme.json` the editor reads +(`public/build/theme//assets/theme.json`), so the page and the editor +always offer the same palette and sizes. + +- Change a token in `app.css`, not in `theme.json`: the root `theme.json` is + only the base (layout, editor settings), and a slug defined there wins over + `@theme`. +- To keep a value out of Tailwind, define that slug in `theme.json`, or turn a + whole family off in `vite.config.js` (`disableTailwindColors`, + `disableTailwindFontSizes`, `disableTailwindFonts`, + `disableTailwindBorderRadius`). +- Spacing and layout widths are not generated: set them in `theme.json`. + +See [Theme.json and Vite Build Integration](https://pollora.dev/theming/theme-structure/) +for the details. + ## Configuration All theme behavior is driven by config files in `config/`: diff --git a/bin/tests/e2e/editor.spec.ts b/bin/tests/e2e/editor.spec.ts index 5c2d034..a437a2a 100644 --- a/bin/tests/e2e/editor.spec.ts +++ b/bin/tests/e2e/editor.spec.ts @@ -15,18 +15,15 @@ async function canvasColor(admin: { createNewPost: () => Promise }, editor ); } -test("the theme's palette reaches the editor canvas", async ({ admin, editor }) => { - expect(await canvasColor(admin, editor, 'red-500'), 'a scale colour of theme.json').not.toBe(''); +test("the theme's palette reaches the editor canvas, and Tailwind's scale does not", async ({ admin, editor }) => { + expect(await canvasColor(admin, editor, 'surface'), 'a colour of the theme').not.toBe(''); + // The palette once held Tailwind's whole default scale, some 290 colours, offered to authors. + expect(await canvasColor(admin, editor, 'red-500'), 'a colour of the Tailwind scale').toBe(''); }); test('the semantic colours of the palette have a value', async ({ admin, editor }) => { - // Known defect: theme.json declares primary as var(--wp--preset--color--primary, #1f2937), - // a variable defined as itself, which CSS discards as a cycle. The same holds for accent, - // foreground, muted, subtle, surface, surface-alt, outline, ring and primary-hover: a block - // coloured "Primary" gets a transparent background, in the editor and on the page. - // This passes, and is reported as such, once the palette resolves. - test.fail(true, 'theme.json semantic colours reference themselves'); - + // theme.json once declared primary as var(--wp--preset--color--primary, #1f2937), a variable + // defined as itself, which CSS discards as a cycle: a block coloured "Primary" was transparent. expect(await canvasColor(admin, editor, 'primary')).not.toBe(''); }); diff --git a/resources/assets/css/app.css b/resources/assets/css/app.css index 597a9f7..6904cd0 100644 --- a/resources/assets/css/app.css +++ b/resources/assets/css/app.css @@ -1,4 +1,4 @@ -@import "tailwindcss" theme(static); +@import "tailwindcss"; @plugin "@tailwindcss/typography"; @source "../../views"; @@ -22,23 +22,23 @@ display: none !important; } -@theme { +@theme static { /* Primary action color — buttons, links, active states */ - --color-primary: var(--wp--preset--color--primary, #1f2937); - --color-primary-hover: var(--wp--preset--color--primary-hover, #111827); + --color-primary: #1f2937; + --color-primary-hover: #111827; /* Secondary color — accents, badges, highlights */ - --color-secondary: var(--wp--preset--color--secondary, #92400e); - --color-accent: var(--wp--preset--color--accent, #fbbf24); + --color-secondary: #92400e; + --color-accent: #fbbf24; /* Text hierarchy */ - --color-foreground: var(--wp--preset--color--foreground, #1f2937); - --color-muted: var(--wp--preset--color--muted, #6b7280); - --color-subtle: var(--wp--preset--color--subtle, #9ca3af); + --color-foreground: #1f2937; + --color-muted: #6b7280; + --color-subtle: #9ca3af; /* Surfaces */ - --color-surface: var(--wp--preset--color--surface, #f9fafb); - --color-surface-alt: var(--wp--preset--color--surface-alt, #f3f4f6); + --color-surface: #f9fafb; + --color-surface-alt: #f3f4f6; /* Borders */ - --color-outline: var(--wp--preset--color--outline, #e5e7eb); - --color-ring: var(--wp--preset--color--ring, #6b7280); + --color-outline: #e5e7eb; + --color-ring: #6b7280; /* Feedback states */ --color-success: #16a34a; --color-success-light: #f0fdf4; @@ -48,6 +48,25 @@ --color-warning-light: #fffbeb; --color-info: #2563eb; --color-info-light: #eff6ff; + /* Typography — the font and the type scale offered in the editor */ + --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --text-xs: 0.75rem; + --text-sm: 0.875rem; + --text-base: 1rem; + --text-lg: 1.125rem; + --text-xl: 1.25rem; + --text-2xl: 1.5rem; + --text-3xl: 1.875rem; + --text-4xl: 2.25rem; + --text-5xl: 3rem; + /* Corner radii */ + --radius-xs: 0.125rem; + --radius-sm: 0.25rem; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; /* Animations */ --animate-fade-in-down: fade-in-down 0.3s ease-out; --animate-fade-out-up: fade-out-up 0.2s ease-in forwards; @@ -62,6 +81,29 @@ to { opacity: 0; transform: translateX(-50%) translateY(-0.5rem); } } +/* + * The build copies the @theme colours above into the theme.json palette. They are + * `static`, so each one reaches it even when no utility uses it, and concrete: a + * preset defined through its own variable is a cycle, and CSS drops it. The + * utilities then read the WordPress presets, so a palette edited in the Site + * Editor still reaches the theme. + */ +@layer base { + :root { + --color-primary: var(--wp--preset--color--primary, #1f2937); + --color-primary-hover: var(--wp--preset--color--primary-hover, #111827); + --color-secondary: var(--wp--preset--color--secondary, #92400e); + --color-accent: var(--wp--preset--color--accent, #fbbf24); + --color-foreground: var(--wp--preset--color--foreground, #1f2937); + --color-muted: var(--wp--preset--color--muted, #6b7280); + --color-subtle: var(--wp--preset--color--subtle, #9ca3af); + --color-surface: var(--wp--preset--color--surface, #f9fafb); + --color-surface-alt: var(--wp--preset--color--surface-alt, #f3f4f6); + --color-outline: var(--wp--preset--color--outline, #e5e7eb); + --color-ring: var(--wp--preset--color--ring, #6b7280); + } +} + /* * Override WordPress core rule `a:where(:not(.wp-element-button))` which forces * underline on all links regardless of Tailwind utilities. diff --git a/resources/assets/css/frontend/components/privacy-text.css b/resources/assets/css/frontend/components/privacy-text.css index 4698b26..1b5dd61 100644 --- a/resources/assets/css/frontend/components/privacy-text.css +++ b/resources/assets/css/frontend/components/privacy-text.css @@ -1,3 +1,3 @@ .woocommerce-privacy-policy-text { - @apply text-sm text-gray-500 mt-5; + @apply text-sm text-muted mt-5; } \ No newline at end of file diff --git a/resources/assets/css/frontend/components/wpgb.css b/resources/assets/css/frontend/components/wpgb.css index 5d118ab..fb92a14 100644 --- a/resources/assets/css/frontend/components/wpgb.css +++ b/resources/assets/css/frontend/components/wpgb.css @@ -1,7 +1,7 @@ .product-grid-controls .wpgb-facet .wpgb-result-count, .product-grid-controls .wpgb-facet .wpgb-facet-title, .product-facets .wpgb-facet .wpgb-facet-title { - @apply block text-sm font-medium text-gray-900; + @apply block text-sm font-medium text-foreground; } .product-facets .wpgb-facet { @@ -12,7 +12,7 @@ .product-facets .wpgb-facet .wpgb-rating-label, .product-facets .wpgb-facet .wpgb-checkbox-label, .product-facets .wpgb-facet .wpgb-range-facet .wpgb-range-values { - @apply ml-3 text-sm text-gray-600; + @apply ml-3 text-sm text-muted; } .product-grid-controls .wpgb-facet.sort-product { @@ -34,7 +34,7 @@ .product-grid-controls .wpgb-facet select.wpgb-select:not([multiple]) { - @apply pt-0.5 pb-0.5 h-auto text-sm font-medium text-gray-900; + @apply pt-0.5 pb-0.5 h-auto text-sm font-medium text-foreground; min-height: 35px; line-height: 1; } \ No newline at end of file diff --git a/resources/views/woocommerce/global/rating-stars.blade.php b/resources/views/woocommerce/global/rating-stars.blade.php index e0c65ff..fa248e3 100644 --- a/resources/views/woocommerce/global/rating-stars.blade.php +++ b/resources/views/woocommerce/global/rating-stars.blade.php @@ -7,11 +7,11 @@
@for($i=1;$i<=5;$i++) @if ($rating >= $i) -