3 Commits

Author SHA1 Message Date
d0dd45c03a refactor(theme): Plan 2.5 P3 — dark mode class on <html> (AD-2.5-D1 + Fix 6)
Per RFC-WS-PRIMEVUE-PLAN-2-5 §4 AD-2.5-D1 and §5.6 Fix 6. Single class
on <html> drives both PrimeVue darkModeSelector and Tailwind v4
@custom-variant dark — one toggle, two ecosystems react.

Audit findings (pre-change):
- applyDomAttributes was writing BOTH data-theme="dark" AND .dark on
  documentElement. The historic data-theme write is the design-doc §4
  mechanism that AD-2.5-D1 supersedes; the .dark toggle was already
  correct (and is already paired with PrimeVue darkModeSelector: '.dark'
  in plugins/primevue/index.ts:31, verified in P1).
- tailwind.css had NO @custom-variant dark directive — Tailwind v4
  default is `prefers-color-scheme` (OS-controlled), so utility
  `dark:` variants would have ignored the topbar toggle entirely.
- One stray .dark subtree wrapper in AppTopbar.stories.ts:56
  (DarkTheme story) — deliberate Storybook isolation per its comment,
  but in violation of AD-2.5-D1's single-source-of-truth rule.

Changes:
- useShellUiStore.applyDomAttributes(): removed data-theme write,
  kept .dark class toggle on document.documentElement, kept
  data-density (P6 wires density-toggle UI; density is an
  orthogonal axis and unaffected). File-header comment updated to
  cite AD-2.5-D1 + reference the Tailwind & PrimeVue mirror sites.
- assets/styles/tailwind.css: added
  `@custom-variant dark (&:where(.dark, .dark *))` so utility
  `dark:` classes resolve via the same .dark trigger.
- components-v2/layout/AppTopbar.stories.ts: stripped class="dark"
  from the DarkTheme story's render wrapper. Story comment updated
  to flag that visual confirmation now comes via parity-batch
  Playwright (after Plan 2.5 closes), not Storybook autodocs. A
  proper documentElement-mutating decorator is a backlog item.
- stores/__tests__/useShellUiStore.spec.ts: updated the existing
  applyDomAttributes assertion to drop the data-theme expectation
  (the write is gone); added a new `describe('applyDomAttributes
  — dark mode (AD-2.5-D1)', …)` block with 2 specs (class toggle
  reactive, no data-theme attribute written).

Re-grep verification — all three return 0 hits:
- stray .dark in v2 (excluding `dark:` utility prefixes)
- data-theme setAttribute calls in stores/
- [data-theme=…] CSS selectors anywhere

Suite delta: 573 → 575 (+2). vue-tsc clean. Scoped ESLint clean.

Note: darkModeSelector: '.dark' was already set in
plugins/primevue/index.ts:31 (verified in P1 audit) — the config
dimension of AD-2.5-D1 was satisfied before this commit; P3 closes
the store-side, Tailwind-side, and stray-class dimensions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 09:31:30 +02:00
41af180168 feat(theme): Plan 2.5 P2 — Inter typography (AD-2.5-T1)
Per RFC-WS-PRIMEVUE-PLAN-2-5 §4 AD-2.5-T1. Establishes Inter as the
canonical Crewli body font via @fontsource/inter (local package, no
Google Fonts CDN).

Audit findings (pre-change):
- No @fontsource/public-sans package was installed.
- No <link> tag in index.html loaded Public Sans.
- Only one Public Sans reference existed in source: the vendored
  Vuexy SCSS variable $font-family-custom at
  src/@core/scss/template/libs/vuetify/_variables.scss, which drives
  Vuetify's $body-font-family on legacy surfaces during F4.
- No src/main.css exists; the Tailwind v4 entry lives at
  src/assets/styles/tailwind.css with no @theme block yet.

Changes:
- @fontsource/inter@^5.2.8 added to dependencies; weights
  400/500/600/700 imported at main.ts ahead of tailwind.css.
- src/assets/styles/tailwind.css: new @theme block declaring
  --font-sans Inter-first, plus :root --crewli-font-family and
  html/body font-family applying that variable cascade-wide.
- src/@core/scss/template/libs/vuetify/_variables.scss:
  $font-family-custom switched from the historical body font to
  Inter (vendored edit, narrowly scoped, F6 removes @core/ entirely).
- tests/unit/styles/typography.spec.ts: 3-spec regression lock
  (Tailwind direct stacks, Vuexy SCSS variable, zero historical
  references in either file). File-content inspection — jsdom does
  not cascade from imported stylesheets, so getComputedStyle would
  always pass.

Suite delta: 570 → 573 (+3; the prompt's template was +2 but the
audit revealed two distinct font-config files, so each gets its own
assertion per the prompt's "cover all sites" rule). vue-tsc clean.
Scoped ESLint clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 08:36:11 +02:00
90d5c1678c feat(tailwind): install Tailwind v4 alongside Vuetify (parallel mode)
Three additions wire Tailwind v4 into the SPA without disturbing the
existing Vuetify pipeline:

- apps/app/src/assets/styles/tailwind.css — Tailwind v4 CSS-first entry.
  Uses @import "tailwindcss"; @plugin "tailwindcss-primeui"; and
  @source pointing at apps/app/src/ to scan template content.

- apps/app/vite.config.ts — adds the @tailwindcss/vite plugin between
  vue() and vuetify(). After vue() so it sees compiled template
  content; before vuetify() so Vuetify's SCSS pipeline runs unimpeded.

- apps/app/src/main.ts — imports tailwind.css before the Vuetify/Vuexy
  SCSS so utility classes are available alongside Vuetify's cascade.

optimizeDeps.exclude remains ['vuetify'] (no PrimeVue addition) — HMR
behaves correctly in dev with the current config; revisit if needed.

Verification:
- pnpm typecheck — clean.
- pnpm build — succeeds in 13.97s; CSS emitted per-route as expected.
- pnpm test — 402 tests pass unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 01:02:05 +02:00