From 5c4a26b65feb1266b7e77f8a667296dda6a3ec4d Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Tue, 2 Jun 2026 01:24:25 -0400 Subject: [PATCH] fix(fusion_plating_shopfloor): dark-mode text/background readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operators saw dark-on-dark (invisible) text in the workspace + "Cannot Finish Step" dialog in Odoo dark mode. Root cause: var(--text-secondary, #xxx) — a made-up variable that doesn't exist in Odoo, so it always fell back to the hardcoded dark hex (invisible on dark). Used 33× across job_workspace.scss + 5 component stylesheets. Replaced with the real dark-aware var(--bs-secondary-color). Also fixed paired backgrounds that would hide the now-theme-flipped text: - finish-block action note → var(--bs-tertiary-bg) (was #f3f4f6). - Tinted status banners (finish-block step, overtime timer, receiving status) → color-mix over var(--bs-body-bg) + var(--bs-body-color). Odoo's bootstrap lacks the BS5.3 -bg-subtle/-text-emphasis vars (verified against _root.scss), so color-mix is the dark-aware path. Solid accent pills/dots (white text) and the color-coded plant-card chips (light-bg + dark-text, readable in both) intentionally left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) --- fusion_plating/CLAUDE.md | 10 +++ .../static/src/scss/components/_gate_viz.scss | 2 +- .../src/scss/components/_hold_composer.scss | 2 +- .../src/scss/components/_kanban_card.scss | 8 +-- .../static/src/scss/components/_pin_pad.scss | 6 +- .../src/scss/components/_signature_pad.scss | 4 +- .../static/src/scss/job_workspace.scss | 61 ++++++++++--------- 7 files changed, 53 insertions(+), 40 deletions(-) diff --git a/fusion_plating/CLAUDE.md b/fusion_plating/CLAUDE.md index 679ef1be..86ec855d 100644 --- a/fusion_plating/CLAUDE.md +++ b/fusion_plating/CLAUDE.md @@ -1854,3 +1854,13 @@ A 50-part job can have parts at several stages at once (10 Masking, 20 Plating, 6. **Move-based scrap (`transfer_type='scrap'`) does NOT touch `job.qty_scrapped`.** At close, `button_mark_done` calls `_fp_scrapped_via_moves()` and folds it into `qty_scrapped`, then auto-fills `qty_done = qty − qty_scrapped` (was: blindly `= job.qty`, which over-counted when parts were scrapped). The reconciliation gate is still the safety net. **Verification:** the plating modules can't be installed on the local Community dev DB (missing enterprise deps — same reason `fusion_plating` shows `installed=0` in `modsdev`/`fusion-dev`). Static checks done: pyflakes (Python), lxml parse (XML), `node --check` as `.mjs` (JS — `node --check` on a `.js` errors with "Cannot use import statement outside a module"; copy to `/tmp/x.mjs` first). Dynamic tests + browser check require an installed env (entech / odoo-trial). + +--- + +## Dark-mode SCSS gotchas — shop-floor dialogs/components (fixed 2026-06-02) + +Operators reported invisible (dark-on-dark) text in the workspace + "Cannot Finish Step" dialog under Odoo dark mode. Root causes + the rules: + +1. **`var(--text-secondary, #333)` is a MADE-UP variable — it does not exist in Odoo, so it ALWAYS falls back to the hardcoded dark hex → invisible on dark backgrounds.** It was used 33× across `job_workspace.scss` + 5 component stylesheets. The real, dark-aware secondary-text variable is **`var(--bs-secondary-color)`** (CLAUDE.md rule 9 lists it). Never use `--text-secondary` / `--text-primary` / `--card-bg` etc. — those aren't Odoo vars. +2. **Odoo's bootstrap does NOT define the Bootstrap 5.3 `--bs-{color}-bg-subtle` / `--bs-{color}-text-emphasis` family.** Verified by grepping `web/static/lib/bootstrap/scss/_root.scss`: `--bs-tertiary-bg` and `--bs-secondary-color` exist; `--bs-warning-bg-subtle`, `--bs-danger-bg-subtle`, `--bs-warning-text-emphasis` are MISSING. So `var(--bs-warning-bg-subtle, #fef3c7)` just yields the bright hex fallback — useless for dark mode. **For tinted status banners (warning/danger/info), use `color-mix` over the live theme bg instead:** `background-color: color-mix(in srgb, #f59e0b 14%, var(--bs-body-bg)); color: var(--bs-body-color);` — pale in light mode, dark-tinted in dark mode, readable in both, graceful-degrades to no-bg on ancient browsers. (`color-mix` works in `background-color` per the rule-8 note; keep it out of shorthands.) Solid accent elements (selected pills, priority dots) with `color: white` are fine as-is in both modes. +3. **Confirmed-present, dark-aware Odoo vars to reach for:** `--bs-body-color` (primary text), `--bs-secondary-color` (muted text), `--bs-body-bg` / `--bs-tertiary-bg` (surfaces), `--bs-border-color`. The deliberate color-coded plant-card status chips (`_plant_card.scss` `.kind-*` / `.tag-*`) are light-bg + dark-text (readable in both modes, just bright on a dark card) — intentionally left as a color-coded set. diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_gate_viz.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_gate_viz.scss index 04d15ce4..d46c81cc 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_gate_viz.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_gate_viz.scss @@ -26,5 +26,5 @@ $_gate-text-hex: #b06600; .o_fp_gate_icon { color: $_gate-border-hex; margin-top: 0.15rem; } .o_fp_gate_body { flex: 1; } .o_fp_gate_title { font-weight: 600; color: $_gate-text-hex; font-size: 0.85rem; } -.o_fp_gate_reason { color: var(--text-secondary, #666); font-size: 0.78rem; margin-top: 0.1rem; } +.o_fp_gate_reason { color: var(--bs-secondary-color, #666); font-size: 0.78rem; margin-top: 0.1rem; } .o_fp_gate_jump { flex-shrink: 0; } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_hold_composer.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_hold_composer.scss index 9160efcf..61780728 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_hold_composer.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_hold_composer.scss @@ -17,5 +17,5 @@ .o_fp_hc_row label { font-size: 0.8rem; font-weight: 600; - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kanban_card.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kanban_card.scss index 47dbae69..5f8396a8 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kanban_card.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_kanban_card.scss @@ -34,18 +34,18 @@ $_kc-hover-hex: #f5f5f7; } .o_fp_kcard_h2 { - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); font-size: 0.75rem; margin-top: 0.15rem; } .o_fp_kcard_qty { display: flex; justify-content: space-between; - font-size: 0.7rem; color: var(--text-secondary, #777); + font-size: 0.7rem; color: var(--bs-secondary-color, #777); margin-top: 0.3rem; } -.o_fp_kcard_due { color: var(--text-secondary, #999); } +.o_fp_kcard_due { color: var(--bs-secondary-color, #999); } .o_fp_kcard_bar { height: 4px; background: rgba(0,0,0,0.08); @@ -74,7 +74,7 @@ $_kc-hover-hex: #f5f5f7; } .o_fp_kcard_wc { - color: var(--text-secondary, #999); + color: var(--bs-secondary-color, #999); font-size: 0.7rem; } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_pin_pad.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_pin_pad.scss index 8c3acc78..9cbcf663 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_pin_pad.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_pin_pad.scss @@ -38,7 +38,7 @@ $_pin-dot-fill-hex: #1d1d1f; } .o_fp_pin_title { font-size: 1.1rem; font-weight: 600; } -.o_fp_pin_subtitle { font-size: 0.85rem; color: var(--text-secondary, #666); text-align: center; } +.o_fp_pin_subtitle { font-size: 0.85rem; color: var(--bs-secondary-color, #666); text-align: center; } .o_fp_pin_dots { display: flex; @@ -83,8 +83,8 @@ $_pin-dot-fill-hex: #1d1d1f; &:disabled { opacity: 0.5; cursor: wait; } } -.o_fp_pin_key_clear { font-size: 0.95rem; color: var(--text-secondary, #666); } -.o_fp_pin_key_cancel { font-size: 0.95rem; color: var(--text-secondary, #666); } +.o_fp_pin_key_clear { font-size: 0.95rem; color: var(--bs-secondary-color, #666); } +.o_fp_pin_key_cancel { font-size: 0.95rem; color: var(--bs-secondary-color, #666); } @keyframes o_fp_pin_shake_kf { 0%, 100% { transform: translateX(0); } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_signature_pad.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_signature_pad.scss index 909929d1..30d7318f 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_signature_pad.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/components/_signature_pad.scss @@ -21,7 +21,7 @@ $_sig-canvas-border-hex: #d8dadd; .o_fp_sig_ctx { font-size: 0.85rem; - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); } .o_fp_sig_canvas { @@ -36,6 +36,6 @@ $_sig-canvas-border-hex: #d8dadd; .o_fp_sig_hint { font-size: 0.75rem; - color: var(--text-secondary, #999); + color: var(--bs-secondary-color, #999); text-align: center; } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/job_workspace.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/job_workspace.scss index 7fcad9a5..26dc6749 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/job_workspace.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/job_workspace.scss @@ -29,7 +29,7 @@ $_ws-text-hex: #1d1d1f; .o_fp_ws_loading { margin: auto; text-align: center; - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); > div { margin-top: 0.6rem; } } @@ -87,8 +87,8 @@ $_ws-text-hex: #1d1d1f; } .o_fp_ws_wo { font-weight: 700; font-size: 1.3rem; letter-spacing: 0.01em; } -.o_fp_ws_dot { color: var(--text-secondary, #999); } -.o_fp_ws_cust, .o_fp_ws_part { color: var(--text-secondary, #555); font-size: 0.95rem; } +.o_fp_ws_dot { color: var(--bs-secondary-color, #999); } +.o_fp_ws_cust, .o_fp_ws_part { color: var(--bs-secondary-color, #555); font-size: 0.95rem; } .o_fp_ws_pill { background: linear-gradient(135deg, $_ws-card-hex 0%, $_ws-page-hex 100%); @@ -97,7 +97,7 @@ $_ws-text-hex: #1d1d1f; border-radius: 6px; font-size: 0.9rem; font-weight: 500; - color: var(--text-secondary, #555); + color: var(--bs-secondary-color, #555); box-shadow: 0 1px 2px rgba(0,0,0,0.04); } @@ -152,7 +152,7 @@ $_ws-text-hex: #1d1d1f; .o_fp_ws_bar_label { font-size: 0.8rem; font-weight: 500; - color: var(--text-secondary, #888); + color: var(--bs-secondary-color, #888); margin-top: 0.35rem; text-align: center; } @@ -237,7 +237,7 @@ $_ws-text-hex: #1d1d1f; .o_fp_ws_empty { text-align: center; padding: 2rem 1rem; - color: var(--text-secondary, #999); + color: var(--bs-secondary-color, #999); > div { margin-top: 0.5rem; } } @@ -270,9 +270,9 @@ $_ws-text-hex: #1d1d1f; } .o_fp_ws_step_icon { width: 18px; text-align: center; font-weight: 700; } -.o_fp_ws_step_num { color: var(--text-secondary, #999); font-size: 0.78rem; min-width: 50px; } +.o_fp_ws_step_num { color: var(--bs-secondary-color, #999); font-size: 0.78rem; min-width: 50px; } .o_fp_ws_step_name { font-weight: 600; } -.o_fp_ws_step_meta { color: var(--text-secondary, #999); font-size: 0.78rem; margin-left: auto; } +.o_fp_ws_step_meta { color: var(--bs-secondary-color, #999); font-size: 0.78rem; margin-left: auto; } .o_fp_ws_step_badge { background: #0071e3; @@ -295,12 +295,12 @@ $_ws-text-hex: #1d1d1f; } .o_fp_ws_step_chips { display: flex; gap: 0.3rem; flex-wrap: wrap; } -.o_fp_ws_step_instr { font-size: 0.78rem; color: var(--text-secondary, #555); font-style: italic; } +.o_fp_ws_step_instr { font-size: 0.78rem; color: var(--bs-secondary-color, #555); font-style: italic; } .o_fp_ws_step_actions { display: flex; gap: 0.35rem; flex-wrap: wrap; } .o_fp_ws_step_excluded { font-size: 0.78rem; - color: var(--text-secondary, #888); + color: var(--bs-secondary-color, #888); font-style: italic; } @@ -331,7 +331,7 @@ $_ws-text-hex: #1d1d1f; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--text-secondary, #777); + color: var(--bs-secondary-color, #777); margin-bottom: 0.35rem; } } @@ -362,14 +362,14 @@ $_ws-text-hex: #1d1d1f; display: flex; gap: 0.4rem; font-size: 0.72rem; - color: var(--text-secondary, #777); + color: var(--bs-secondary-color, #777); } .o_fp_ws_note .author { font-weight: 600; } -.o_fp_ws_note .body { color: var(--text-secondary, #555); margin-top: 0.15rem; } +.o_fp_ws_note .body { color: var(--bs-secondary-color, #555); margin-top: 0.15rem; } .o_fp_ws_empty_small { - color: var(--text-secondary, #999); + color: var(--bs-secondary-color, #999); font-size: 0.75rem; font-style: italic; } @@ -417,7 +417,7 @@ $_ws-text-hex: #1d1d1f; align-items: center; gap: 0.4rem; font-size: 0.85rem; - color: var(--text-secondary, #777); + color: var(--bs-secondary-color, #777); } .o_fp_ws_ship_fields { @@ -488,8 +488,8 @@ $_ws-text-hex: #1d1d1f; .o_fp_ws_rcv_status { padding: 0.2rem 0.6rem; border-radius: 4px; - background: #fef3c7; - color: #78350f; + background-color: color-mix(in srgb, #f59e0b 18%, var(--bs-body-bg)); + color: var(--bs-body-color); font-weight: 600; font-size: 0.85rem; text-transform: uppercase; @@ -507,7 +507,7 @@ $_ws-text-hex: #1d1d1f; label { font-weight: 600; - color: var(--text-secondary, #555); + color: var(--bs-secondary-color, #555); font-size: 0.9rem; } } @@ -529,7 +529,7 @@ $_ws-text-hex: #1d1d1f; font-size: 0.8rem; font-weight: 700; text-transform: uppercase; - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); margin-bottom: 0.5rem; letter-spacing: 0.05em; } @@ -598,7 +598,7 @@ $_ws-text-hex: #1d1d1f; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); margin-bottom: 0.5rem; display: flex; align-items: center; @@ -644,7 +644,7 @@ $_ws-text-hex: #1d1d1f; } .o_fp_ws_rcv_damage_photos { - color: var(--text-secondary, #666); + color: var(--bs-secondary-color, #666); font-size: 0.85rem; } @@ -680,7 +680,7 @@ $_ws-text-hex: #1d1d1f; } .o_fp_dmg_field { display: flex; flex-direction: column; gap: 0.4rem; } -.o_fp_dmg_label { font-weight: 600; color: var(--text-secondary, #555); } +.o_fp_dmg_label { font-weight: 600; color: var(--bs-secondary-color, #555); } .o_fp_dmg_req { color: #dc2626; } .o_fp_dmg_pills { @@ -784,8 +784,8 @@ $_ws-text-hex: #1d1d1f; } .o_fp_ws_step_timer_over { - background: #fee2e2; - color: #7f1d1d; + background-color: color-mix(in srgb, #ef4444 16%, var(--bs-body-bg)); + color: var(--bs-body-color); animation: o_fp_ws_timer_pulse 1.5s ease-in-out infinite; } @@ -808,15 +808,18 @@ $_ws-text-hex: #1d1d1f; .o_fp_finish_block_step { font-size: 1.1rem; - color: #b45309; - background: #fef3c7; + color: var(--bs-body-color); + // Amber wash over the live theme bg — pale in light mode, dark-amber + // in dark mode (the -bg-subtle/-text-emphasis BS vars aren't defined + // in Odoo's bootstrap, so color-mix is the dark-aware path). + background-color: color-mix(in srgb, #f59e0b 14%, var(--bs-body-bg)); padding: 0.7rem 1rem; border-radius: 6px; border-left: 4px solid #f59e0b; } .o_fp_finish_block_msg { - color: var(--text-secondary, #333); + color: var(--bs-secondary-color, #333); } .o_fp_finish_block_list { @@ -831,9 +834,9 @@ $_ws-text-hex: #1d1d1f; } .o_fp_finish_block_action_note { - color: var(--text-secondary, #555); + color: var(--bs-secondary-color, #555); font-style: italic; padding: 0.6rem 0.8rem; - background: #f3f4f6; + background: var(--bs-tertiary-bg, #f3f4f6); border-radius: 4px; }