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>
This commit is contained in:
@@ -3,8 +3,14 @@ import { ref } from 'vue'
|
||||
|
||||
// v2 shell UI state ONLY (RFC-WS-GUI-REDESIGN AD-G4). No tenant/org
|
||||
// state — that stays in useAuthStore/useOrganisationStore. Owns the
|
||||
// writes to <html data-theme>/<html data-density>/.dark (composes with
|
||||
// Aura darkModeSelector '.dark'); v2 bypasses Vuexy useSkins.ts.
|
||||
// writes to <html data-density>/.dark; v2 bypasses Vuexy useSkins.ts.
|
||||
//
|
||||
// AD-2.5-D1 (RFC-WS-PRIMEVUE-PLAN-2-5 §4): dark mode is the single
|
||||
// class `.dark` on document.documentElement. Tailwind v4's
|
||||
// @custom-variant dark (in assets/styles/tailwind.css) and PrimeVue's
|
||||
// darkModeSelector (in plugins/primevue/index.ts:31) both react to
|
||||
// that class — one toggle, both ecosystems. The historic
|
||||
// <html data-theme="..."> mechanism is superseded and removed.
|
||||
|
||||
export type ShellTheme = 'light' | 'dark'
|
||||
export type ShellDensity = 'comfortable' | 'compact'
|
||||
@@ -41,9 +47,18 @@ export const useShellUiStore = defineStore('shellUi', () => {
|
||||
function applyDomAttributes(): void {
|
||||
const el = document.documentElement
|
||||
|
||||
el.setAttribute('data-theme', theme.value)
|
||||
// AD-2.5-D1: dark mode is `.dark` on <html>. PrimeVue
|
||||
// darkModeSelector and Tailwind v4 @custom-variant dark both
|
||||
// resolve to this class — see file header.
|
||||
if (theme.value === 'dark')
|
||||
el.classList.add('dark')
|
||||
else
|
||||
el.classList.remove('dark')
|
||||
|
||||
// Density continues to use data-attribute (orthogonal axis to
|
||||
// colour scheme; coexists with the .dark class on the same root).
|
||||
// Density toggle UI lands in P6 Fix 10.
|
||||
el.setAttribute('data-density', density.value)
|
||||
el.classList.toggle('dark', theme.value === 'dark')
|
||||
}
|
||||
|
||||
function openDrawer(component: string, props: Record<string, unknown> = {}): void {
|
||||
|
||||
Reference in New Issue
Block a user