feat(useMood): options darkClass et persist pour le pattern dark/light
- darkClass: bascule une classe unique sur <html> selon isDark
(variants dark: UnoCSS/Tailwind — besoin GrateWizard)
- setMood(id, { persist: false }): application éphémère (embed, prefers-color-scheme)
- initMood ne persiste plus le défaut, seulement un choix déjà stocké
- README: section GrateWizard + avertissement distribution (extends relatif
hors repo = build Docker/CI cassé, à trancher avant merge)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,12 @@ Fournit le **mécanisme** commun, jamais les couleurs (chaque projet garde son i
|
|||||||
Supporte les 2 patterns existants sans réécrire le CSS d'un projet :
|
Supporte les 2 patterns existants sans réécrire le CSS d'un projet :
|
||||||
- **classes `.mood-<id>`** + variables `--mood-*` définies en CSS (style libreDecision) ;
|
- **classes `.mood-<id>`** + variables `--mood-*` définies en CSS (style libreDecision) ;
|
||||||
- **variables CSS injectées en JS** via `MoodDef.vars` (style librodrome `--color-*`) ;
|
- **variables CSS injectées en JS** via `MoodDef.vars` (style librodrome `--color-*`) ;
|
||||||
- option `lightDarkClasses` pour basculer aussi `.palette-light/.palette-dark`.
|
- option `lightDarkClasses` pour basculer aussi `.palette-light/.palette-dark` ;
|
||||||
|
- option `darkClass: 'dark'` pour basculer une classe unique selon `isDark`
|
||||||
|
(variants `dark:` UnoCSS/Tailwind — style GrateWizard) ;
|
||||||
|
- `setMood(id, { persist: false })` pour une application éphémère
|
||||||
|
(thème imposé en mode embed, suivi de `prefers-color-scheme`) ;
|
||||||
|
- `initMood()` ne persiste que si un choix était déjà stocké.
|
||||||
|
|
||||||
## Adoption (à faire AVEC vérif visuelle mobile + desktop — zéro régression)
|
## Adoption (à faire AVEC vérif visuelle mobile + desktop — zéro régression)
|
||||||
|
|
||||||
@@ -40,8 +45,23 @@ export const useLibreMood = () => useMood(moods, { storageKey: 'libredecision_mo
|
|||||||
### librodrome (via l'option vars — le CSS `--color-*` reste inchangé)
|
### librodrome (via l'option vars — le CSS `--color-*` reste inchangé)
|
||||||
Convertir `stores/palette.ts` pour déléguer l'application DOM à `useMood`, en passant les triplets HSL dans `vars` (`--color-primary`, etc.) et `lightDarkClasses: true`. Le store peut rester pour l'API publique, mais l'application au DOM passe par le mécanisme partagé. Vérifier les 4 saisons + light/dark.
|
Convertir `stores/palette.ts` pour déléguer l'application DOM à `useMood`, en passant les triplets HSL dans `vars` (`--color-primary`, etc.) et `lightDarkClasses: true`. Le store peut rester pour l'API publique, mais l'application au DOM passe par le mécanisme partagé. Vérifier les 4 saisons + light/dark.
|
||||||
|
|
||||||
### GrateWizard / SejeteralO
|
### GrateWizard (dark/light seulement, contraintes embed)
|
||||||
Adopter après les deux premiers, même principe. SejeteralO (pas d'UnoCSS, vue-router 5) en dernier, prudemment.
|
Deux moods `light`/`dark` avec `darkClass: 'dark'` (variants UnoCSS) et
|
||||||
|
`syncColorMode: false`. `useDarkMode` reste l'API publique et garde sa logique
|
||||||
|
de décision : thème imposé par `?theme=` en embed (`setMood(id, { persist: false })`
|
||||||
|
— ne jamais écraser la préférence standalone, même origine), migration du
|
||||||
|
stockage legacy `'true'/'false'` → `'dark'/'light'`, suivi de
|
||||||
|
`prefers-color-scheme` tant qu'aucun choix explicite n'est stocké.
|
||||||
|
Vérifier : toggle + persistance standalone, embed `?theme=light` non persisté, sceau.
|
||||||
|
|
||||||
|
### SejeteralO
|
||||||
|
Adopter en dernier (pas d'UnoCSS, vue-router 5), prudemment.
|
||||||
|
|
||||||
|
## ⚠️ Distribution — à régler AVANT tout merge/push des adoptions
|
||||||
|
Les `extends` relatifs (`../yvv-nuxt-base`) pointent HORS des repos consommateurs :
|
||||||
|
les builds Docker (`COPY . .`) et la CI échoueront. Options à trancher :
|
||||||
|
repo distant + dépendance git, `git subtree` vendoré par projet, ou contexte
|
||||||
|
Docker élargi. En dev local, rien à faire.
|
||||||
|
|
||||||
## Principe
|
## Principe
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ export interface UseMoodOptions {
|
|||||||
syncColorMode?: boolean
|
syncColorMode?: boolean
|
||||||
/** bascule aussi les classes .palette-light / .palette-dark (style librodrome) (défaut: false) */
|
/** bascule aussi les classes .palette-light / .palette-dark (style librodrome) (défaut: false) */
|
||||||
lightDarkClasses?: boolean
|
lightDarkClasses?: boolean
|
||||||
|
/**
|
||||||
|
* Classe unique à basculer sur <html> selon mood.isDark (ex. 'dark' pour
|
||||||
|
* les variants dark: d'UnoCSS/Tailwind — style GrateWizard). Défaut: aucune.
|
||||||
|
*/
|
||||||
|
darkClass?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetMoodOptions {
|
||||||
|
/** écrit le choix en localStorage (défaut: true). false = application
|
||||||
|
* éphémère (ex. thème imposé en mode embed, suivi de prefers-color-scheme) */
|
||||||
|
persist?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentMood: Ref<string> = ref('')
|
const currentMood: Ref<string> = ref('')
|
||||||
@@ -51,9 +62,10 @@ export function useMood(moods: MoodDef[], options: UseMoodOptions = {}) {
|
|||||||
defaultId = moods[0]?.id ?? '',
|
defaultId = moods[0]?.id ?? '',
|
||||||
syncColorMode = true,
|
syncColorMode = true,
|
||||||
lightDarkClasses = false,
|
lightDarkClasses = false,
|
||||||
|
darkClass,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
function applyMood(moodId: string) {
|
function applyMood(moodId: string, { persist = true }: SetMoodOptions = {}) {
|
||||||
if (import.meta.server) return
|
if (import.meta.server) return
|
||||||
const mood = moods.find(m => m.id === moodId)
|
const mood = moods.find(m => m.id === moodId)
|
||||||
if (!mood) return
|
if (!mood) return
|
||||||
@@ -71,6 +83,11 @@ export function useMood(moods: MoodDef[], options: UseMoodOptions = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// classe dark unique (compat variants dark: UnoCSS/Tailwind)
|
||||||
|
if (darkClass) {
|
||||||
|
html.classList.toggle(darkClass, mood.isDark)
|
||||||
|
}
|
||||||
|
|
||||||
// classes palette-light / palette-dark (compat style librodrome)
|
// classes palette-light / palette-dark (compat style librodrome)
|
||||||
if (lightDarkClasses) {
|
if (lightDarkClasses) {
|
||||||
html.classList.toggle('palette-light', !mood.isDark)
|
html.classList.toggle('palette-light', !mood.isDark)
|
||||||
@@ -89,19 +106,21 @@ export function useMood(moods: MoodDef[], options: UseMoodOptions = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem(storageKey, moodId)
|
if (persist) localStorage.setItem(storageKey, moodId)
|
||||||
currentMood.value = moodId
|
currentMood.value = moodId
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMood(moodId: string) {
|
function setMood(moodId: string, options: SetMoodOptions = {}) {
|
||||||
applyMood(moodId)
|
applyMood(moodId, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
function initMood() {
|
function initMood() {
|
||||||
if (import.meta.server) return
|
if (import.meta.server) return
|
||||||
const saved = localStorage.getItem(storageKey)
|
const saved = localStorage.getItem(storageKey)
|
||||||
const moodId = saved && moods.some(m => m.id === saved) ? saved : defaultId
|
const moodId = saved && moods.some(m => m.id === saved) ? saved : defaultId
|
||||||
applyMood(moodId)
|
// ne persiste que ce qui était déjà stocké : appliquer le défaut
|
||||||
|
// ne doit pas verrouiller un choix que l'utilisateur n'a pas fait
|
||||||
|
applyMood(moodId, { persist: saved != null })
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user