diff --git a/CLAUDE.md b/CLAUDE.md index 17f9f32b..bee454de 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,16 +29,39 @@ For custom OWL dashboards / client actions use the same approach: $fp-border: var(--fp-border-color, #d8dadd); ``` - Reference those tokens everywhere (never `var(--bs-border-color)` directly) -- Override the custom properties for dark mode at the bottom of the tokens file: - ```scss - :root[data-bs-theme="dark"], body.o_dark_mode, .o_dark_mode { - --fp-card-bg: #22262d; - --fp-border-color: #343942; - } - ``` - Three-layer contrast: **page** (grayest) → **container/column** (mid) → **card** (brightest). That's what makes cards pop. - Reference implementation: `fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss`. +## Dark Mode — Branch on `$o-webclient-color-scheme` at SCSS Compile Time +Odoo 19 does NOT flip dark mode via a runtime DOM class. It compiles TWO asset bundles: +- `web.assets_backend` — compiled with `$o-webclient-color-scheme: bright` +- `web.assets_web_dark` — compiled with `$o-webclient-color-scheme: dark` (dark variant primary variables loaded first) + +Your SCSS file is compiled into BOTH bundles. To make the dark bundle have different colors, **branch at compile time** using the SCSS variable Odoo sets: + +```scss +$o-webclient-color-scheme: bright !default; + +$_my-page-hex: #f3f4f6; +$_my-card-hex: #ffffff; + +@if $o-webclient-color-scheme == dark { + $_my-page-hex: #1a1d21 !global; + $_my-card-hex: #22262d !global; +} + +$my-page: var(--my-page-bg, $_my-page-hex); +$my-card: var(--my-card-bg, $_my-card-hex); +``` + +**Do NOT use** `.o_dark_mode` class selectors, `[data-bs-theme="dark"]`, or `@media (prefers-color-scheme: dark)` — none of those fire reliably in Odoo 19. The user toggles dark mode via the user profile, which sets a `color_scheme` cookie and reloads the page; Odoo then serves the dark bundle. Your SCSS `@if` handles the rest at compile time. + +Verify by inspecting the attachments — you should see two files with different URLs for the two bundles: +```python +env['ir.qweb']._get_asset_bundle('web.assets_backend').css() # light +env['ir.qweb']._get_asset_bundle('web.assets_web_dark').css() # dark +``` + ## Asset Bundle Cache Busting Odoo content-hashes the compiled bundle URL (`/web/assets//...`). When CSS changes but the hash doesn't update, the browser serves the old bundle. Fixes in order of escalation: 1. Bump the module `version` in `__manifest__.py` diff --git a/fusion_plating/fusion_plating_shopfloor/__manifest__.py b/fusion_plating/fusion_plating_shopfloor/__manifest__.py index b007ec94..5632be3e 100644 --- a/fusion_plating/fusion_plating_shopfloor/__manifest__.py +++ b/fusion_plating/fusion_plating_shopfloor/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating — Shop Floor', - 'version': '19.0.4.0.0', + 'version': '19.0.5.0.0', 'category': 'Manufacturing/Plating', 'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer, ' 'first-piece inspection gates.', diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss index d7899f58..ad408037 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/_fp_shopfloor_tokens.scss @@ -31,40 +31,60 @@ $fp-radius-lg : 20px; $fp-radius-xl : 28px; $fp-radius-pill: 999px; -// ---------- Surfaces — tied to Odoo's Bootstrap tokens ----------------------- +// ---------- Surfaces — COMPILE-TIME branch on Odoo's dark scheme ------------- // -// Odoo 19's dark mode is NOT a runtime class toggle — it's a separate -// compiled CSS bundle where --bs-body-bg, --bs-card-bg, --bs-tertiary-bg, -// --bs-border-color are baked in with dark values. So if we chain our -// tokens through those Bootstrap variables, they auto-invert when Odoo -// swaps the bundle; no .o_dark_mode override needed. +// Odoo 19 compiles TWO asset bundles: web.assets_backend (light) and +// web.assets_web_dark (dark). The two bundles differ only in the value +// of the SCSS variable $o-webclient-color-scheme — `bright` for light, +// `dark` for dark (defined in primary_variables.scss / +// primary_variables.dark.scss in web_enterprise). // -// Fallback order: -// 1. --fp-* (custom override, e.g. shop-branded skin) -// 2. --bs-* (Odoo/Bootstrap semantic token — inverts on dark) -// 3. explicit hex (absolute fallback if vars are missing) -$fp-page : var(--fp-page-bg, - var(--bs-tertiary-bg, #f3f4f6)); -$fp-card : var(--fp-card-bg, - var(--bs-card-bg, - var(--o-view-background-color, #ffffff))); -$fp-card-soft : var(--fp-card-soft-bg, - var(--bs-secondary-bg, #f1f3f5)); -$fp-border : var(--fp-border-color, - var(--bs-border-color, #d8dadd)); -$fp-border-strong : var(--fp-border-strong, - var(--bs-border-color-translucent, #b6babf)); +// Odoo does NOT redefine --bs-body-bg / --bs-card-bg as CSS custom +// properties at runtime. It bakes the chosen palette into the bundle +// at compile time via Bootstrap SCSS variables. So our tokens must do +// the same: branch on $o-webclient-color-scheme at compile time and +// emit the right hex values into each bundle. -// ---------- Text tiers — same chain pattern ---------------------------------- -$fp-ink : var(--fp-ink, var(--bs-body-color, #1f2937)); -$fp-ink-soft : var(--fp-ink-soft, var(--bs-secondary-color, #4b5563)); -$fp-ink-mute : var(--fp-ink-mute, var(--bs-tertiary-color, #6b7280)); -$fp-ink-faint : var(--fp-ink-faint, - color-mix(in srgb, var(--bs-body-color, #000) 40%, transparent)); +$o-webclient-color-scheme: bright !default; -// Action colour — Odoo's primary. Explicit hex fallback to Odoo's -// default brand purple so .btn-primary doesn't render transparent. -$fp-accent : var(--o-action, #714B67); +// Default (light / bright) palette +$_fp-page-hex : #f3f4f6; +$_fp-card-hex : #ffffff; +$_fp-card-soft-hex : #f1f3f5; +$_fp-border-hex : #d8dadd; +$_fp-border-strong-hex : #b6babf; +$_fp-ink-hex : #1f2937; +$_fp-ink-soft-hex : #4b5563; +$_fp-ink-mute-hex : #6b7280; +$_fp-ink-faint-hex : #9ca3af; + +// Dark palette — engaged when the dark bundle is compiled +@if $o-webclient-color-scheme == dark { + $_fp-page-hex : #1a1d21 !global; + $_fp-card-hex : #22262d !global; + $_fp-card-soft-hex : #1c2027 !global; + $_fp-border-hex : #343942 !global; + $_fp-border-strong-hex : #4a505a !global; + $_fp-ink-hex : #e5e7eb !global; + $_fp-ink-soft-hex : #c8ccd2 !global; + $_fp-ink-mute-hex : #8a909a !global; + $_fp-ink-faint-hex : #5a606b !global; +} + +// Public tokens — CSS custom property fallback chain remains so a +// deployment can still override via --fp-* without touching SCSS. +$fp-page : var(--fp-page-bg, $_fp-page-hex); +$fp-card : var(--fp-card-bg, $_fp-card-hex); +$fp-card-soft : var(--fp-card-soft-bg, $_fp-card-soft-hex); +$fp-border : var(--fp-border-color, $_fp-border-hex); +$fp-border-strong : var(--fp-border-strong, $_fp-border-strong-hex); +$fp-ink : var(--fp-ink, $_fp-ink-hex); +$fp-ink-soft : var(--fp-ink-soft, $_fp-ink-soft-hex); +$fp-ink-mute : var(--fp-ink-mute, $_fp-ink-mute-hex); +$fp-ink-faint : var(--fp-ink-faint, $_fp-ink-faint-hex); + +// Action colour — Odoo's primary. Same in both bundles (brand purple). +$fp-accent : var(--o-action, #714B67); // ---------- Elevation — explicit rgba shadows -------------------------------- // Explicit rgba values (not color-mix) so they render identically across