From 3ca0f7a71999b6394bc52610f8877d2e705af3af Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 25 Apr 2026 05:26:42 -0400 Subject: [PATCH] fix(jobs): theme tokens + dark-mode support across remaining OWL SCSS files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 4 client-action SCSS files I shipped in Phase 6 ignored the project's documented design system (CLAUDE.md "Card Styling" + "Dark Mode" rules) and used hardcoded hex / var(--bs-*) for surfaces. Result: dark mode rendered white-text-on-white-card. Companion to "changes" (22573e7) which already landed _fp_jobs_tokens.scss + the job_plant_overview.scss refactor. This commit finishes the job: - Refactored job_process_tree.scss, job_manager_dashboard.scss and job_tablet.scss to reference the $fp-* tokens — zero hardcoded hex on theme-sensitive surfaces. Three-layer contrast applied per CLAUDE.md (page → container → card). - Process tree keeps the intentional Steelhead-style dark-slate card fill in BOTH bundles (deliberate visual choice, not a theme bug); page / header / connectors / empty state are now token- driven so they look right against light or dark page surfaces. - Manifest assets list reordered so _fp_jobs_tokens.scss compiles first in web.assets_backend (CLAUDE.md rule: SCSS variables in earlier files are visible to later files in the same bundle). This is what makes the compile-time $o-webclient-color-scheme branch in the partial actually take effect for the four consumer files. Verified on entech: light bundle (web.assets_backend) and dark bundle (web.assets_web_dark) both compile without SCSS errors and emit distinct surface hexes (light: #f3f4f6 page / #ffffff card; dark: #1a1d21 page / #22262d card). Manifest 19.0.3.0.0 → 19.0.3.1.0. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../fusion_plating_jobs/__manifest__.py | 8 +- .../src/scss/job_manager_dashboard.scss | 173 +++++----- .../static/src/scss/job_process_tree.scss | 156 ++++----- .../static/src/scss/job_tablet.scss | 312 ++++++++++-------- 4 files changed, 367 insertions(+), 282 deletions(-) diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index 285ade58..654ae07b 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.3.0.0', + 'version': '19.0.3.1.0', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'author': 'Nexa Systems Inc.', @@ -57,6 +57,12 @@ full design rationale and §6.2 of the implementation plan for task list. ], 'assets': { 'web.assets_backend': [ + # Tokens MUST be first — Odoo concatenates bundle files in + # order, and SCSS variables defined in earlier files are + # visible to later files in the same bundle. The token + # partial branches on $o-webclient-color-scheme so the dark + # bundle (web.assets_web_dark) gets a distinct palette. + 'fusion_plating_jobs/static/src/scss/_fp_jobs_tokens.scss', 'fusion_plating_jobs/static/src/scss/job_process_tree.scss', 'fusion_plating_jobs/static/src/scss/job_plant_overview.scss', 'fusion_plating_jobs/static/src/scss/job_manager_dashboard.scss', diff --git a/fusion_plating/fusion_plating_jobs/static/src/scss/job_manager_dashboard.scss b/fusion_plating/fusion_plating_jobs/static/src/scss/job_manager_dashboard.scss index 93aece4e..b09f2f9c 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/scss/job_manager_dashboard.scss +++ b/fusion_plating/fusion_plating_jobs/static/src/scss/job_manager_dashboard.scss @@ -3,21 +3,28 @@ // Copyright 2026 Nexa Systems Inc. · License OPL-1 // // Class prefix: .o_fp_jmd_* (Job Manager Dashboard) -// Self-contained — no shopfloor token partial dependency. +// +// Theme-aware: every surface, border and text colour resolves through +// the design tokens defined in _fp_jobs_tokens.scss. +// +// Three-layer contrast: +// page = $fp-page (grayest) +// header / filter bar wrapper = $fp-card-soft (mid) +// rows = $fp-card (brightest) // ============================================================================= .o_fp_job_manager_dashboard { height: 100%; overflow: auto; -webkit-overflow-scrolling: touch; - padding: 16px 24px; + padding: $fp-space-4 $fp-space-6; display: flex; flex-direction: column; - gap: 12px; - background-color: var(--o-action, #f7f7f8); - color: var(--bs-body-color, #1a1d21); + gap: $fp-space-3; + background-color: $fp-page; + color: $fp-ink; - @media (max-width: 600px) { padding: 12px; gap: 12px; } + @media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-3; } // ------------------------------------------------------------------------- @@ -27,71 +34,77 @@ display: flex; align-items: center; justify-content: space-between; - gap: 16px; + gap: $fp-space-4; flex-wrap: wrap; - padding: 12px 16px; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + padding: $fp-space-3 $fp-space-4; + background-color: $fp-card; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + box-shadow: $fp-elev-1; } .o_fp_jmd_header_left { display: flex; align-items: baseline; - gap: 12px; + gap: $fp-space-3; } .o_fp_jmd_title { - font-size: 1.1rem; - font-weight: 700; + font-size: $fp-text-md; + font-weight: $fp-weight-bold; margin: 0; + color: $fp-ink; } // ------------------------------------------------------------------------- - // Filter pill bar + // Filter pill bar — sits on the page; the bar itself is transparent // ------------------------------------------------------------------------- .o_fp_jmd_filter_bar { display: flex; flex-wrap: wrap; - gap: 8px; - padding: 8px 4px; + gap: $fp-space-2; + padding: $fp-space-2 4px; } .o_fp_jmd_pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; - border: 1px solid #d8dadd; - background-color: var(--bs-body-bg, #ffffff); - color: inherit; - border-radius: 999px; + border: 1px solid #{$fp-border}; + background-color: $fp-card; + color: $fp-ink; + border-radius: $fp-radius-pill; font-size: 0.8rem; cursor: pointer; - transition: background-color 0.15s ease, - border-color 0.15s ease, - color 0.15s ease; + transition: background-color $fp-dur-fast $fp-ease, + border-color $fp-dur-fast $fp-ease, + color $fp-dur-fast $fp-ease; - &:hover { - background-color: #f1f3f5; - border-color: #c5c8cc; + @include fp-hover-only { + &:hover { + background-color: $fp-card-soft; + border-color: $fp-border-strong; + } } &.o_fp_jmd_pill_active { - background-color: #0d6efd; - border-color: #0d6efd; + background-color: $fp-accent; + border-color: $fp-accent; color: #ffffff; - font-weight: 600; + font-weight: $fp-weight-semibold; } } .o_fp_jmd_pill_count { - background-color: rgba(0, 0, 0, 0.08); - border-radius: 999px; + background-color: color-mix(in srgb, #{$fp-ink} 8%, transparent); + color: $fp-ink-soft; + border-radius: $fp-radius-pill; padding: 0 7px; font-size: 0.7rem; - font-weight: 700; + font-weight: $fp-weight-bold; min-width: 1.5em; text-align: center; } .o_fp_jmd_pill_active .o_fp_jmd_pill_count { background-color: rgba(255, 255, 255, 0.25); + color: #ffffff; } @@ -100,9 +113,11 @@ // ------------------------------------------------------------------------- .o_fp_jmd_empty, .o_fp_jmd_loading { - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card; + color: $fp-ink-mute; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + box-shadow: $fp-elev-1; } @@ -112,34 +127,39 @@ .o_fp_jmd_rows { display: flex; flex-direction: column; - gap: 8px; + gap: $fp-space-2; } .o_fp_jmd_row { display: flex; align-items: stretch; gap: 0; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; cursor: pointer; overflow: hidden; - transition: transform 0.1s ease, box-shadow 0.15s ease, - border-color 0.15s ease; + box-shadow: $fp-elev-1; + transition: transform $fp-dur-fast $fp-ease, + box-shadow $fp-dur $fp-ease, + border-color $fp-dur $fp-ease; - &:hover { - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); - border-color: #c5c8cc; + @include fp-hover-only { + &:hover { + transform: translateY(-1px); + box-shadow: $fp-elev-2; + border-color: $fp-border-strong; + } } } .o_fp_jmd_priority_bar { flex: 0 0 6px; - background-color: #6c757d; // normal default + background-color: $fp-state-low; // normal default } - .o_fp_jmd_priority_rush .o_fp_jmd_priority_bar { background-color: #dc3545; } - .o_fp_jmd_priority_high .o_fp_jmd_priority_bar { background-color: #fd7e14; } - .o_fp_jmd_priority_normal .o_fp_jmd_priority_bar { background-color: #0d6efd; } - .o_fp_jmd_priority_low .o_fp_jmd_priority_bar { background-color: #adb5bd; } + .o_fp_jmd_priority_rush .o_fp_jmd_priority_bar { background-color: $fp-state-rush; } + .o_fp_jmd_priority_high .o_fp_jmd_priority_bar { background-color: $fp-state-high; } + .o_fp_jmd_priority_normal .o_fp_jmd_priority_bar { background-color: $fp-state-progress; } + .o_fp_jmd_priority_low .o_fp_jmd_priority_bar { background-color: $fp-ink-faint; } .o_fp_jmd_row_body { flex: 1 1 auto; @@ -153,19 +173,20 @@ flex: 0 0 auto; align-self: center; padding: 0 14px; - opacity: 0.4; + color: $fp-ink-faint; } .o_fp_jmd_row_top { display: flex; align-items: center; justify-content: space-between; - gap: 12px; + gap: $fp-space-3; flex-wrap: wrap; } .o_fp_jmd_row_id { font-size: 0.95rem; flex: 1 1 auto; min-width: 0; + color: $fp-ink; } .o_fp_jmd_row_chips { display: inline-flex; @@ -174,14 +195,14 @@ } .o_fp_jmd_row_meta { font-size: 0.75rem; - opacity: 0.85; + color: $fp-ink-mute; display: flex; flex-wrap: wrap; gap: 2px 4px; } .o_fp_jmd_overdue { - color: #dc3545; - font-weight: 600; + color: $fp-state-cancel; + font-weight: $fp-weight-semibold; } @@ -192,19 +213,19 @@ display: inline-flex; align-items: center; padding: 2px 8px; - border-radius: 999px; + border-radius: $fp-radius-pill; font-size: 0.65rem; - font-weight: 700; + font-weight: $fp-weight-bold; line-height: 1.4; text-transform: uppercase; letter-spacing: 0.02em; - &.o_fp_jmd_state_badge_draft { background-color: #e9ecef; color: #6c757d; } - &.o_fp_jmd_state_badge_confirmed { background-color: rgba(13, 110, 253, 0.18); color: #084298; } - &.o_fp_jmd_state_badge_in_progress { background-color: rgba(13, 110, 253, 0.28); color: #084298; } - &.o_fp_jmd_state_badge_on_hold { background-color: rgba(253, 126, 20, 0.20); color: #97480d; } - &.o_fp_jmd_state_badge_done { background-color: rgba(25, 135, 84, 0.20); color: #0f5132; } - &.o_fp_jmd_state_badge_cancelled { background-color: rgba(220, 53, 69, 0.18); color: #842029; } + &.o_fp_jmd_state_badge_draft { background-color: $fp-state-pending-bg; color: $fp-state-pending-text; } + &.o_fp_jmd_state_badge_confirmed { background-color: color-mix(in srgb, #{$fp-state-progress} 18%, transparent); color: $fp-state-progress-text; } + &.o_fp_jmd_state_badge_in_progress { background-color: color-mix(in srgb, #{$fp-state-progress} 28%, transparent); color: $fp-state-progress-text; } + &.o_fp_jmd_state_badge_on_hold { background-color: color-mix(in srgb, #{$fp-state-paused} 20%, transparent); color: $fp-state-paused-text; } + &.o_fp_jmd_state_badge_done { background-color: color-mix(in srgb, #{$fp-state-done} 20%, transparent); color: $fp-state-done-text; } + &.o_fp_jmd_state_badge_cancelled { background-color: color-mix(in srgb, #{$fp-state-cancel} 18%, transparent); color: $fp-state-cancel-text; } } @@ -215,15 +236,16 @@ display: inline-flex; align-items: center; padding: 2px 8px; - border-radius: 999px; + border-radius: $fp-radius-pill; font-size: 0.65rem; - font-weight: 700; + font-weight: $fp-weight-bold; line-height: 1.4; text-transform: uppercase; letter-spacing: 0.02em; + color: #ffffff; - &.o_fp_jmd_chip_rush { background-color: #dc3545; color: #fff; } - &.o_fp_jmd_chip_high { background-color: #fd7e14; color: #fff; } + &.o_fp_jmd_chip_rush { background-color: $fp-state-rush; } + &.o_fp_jmd_chip_high { background-color: $fp-state-high; } } @@ -238,23 +260,24 @@ .o_fp_jmd_bar_track { flex: 1 1 auto; height: 8px; - background-color: #e9ecef; - border-radius: 999px; + background-color: color-mix(in srgb, #{$fp-ink} 8%, transparent); + border-radius: $fp-radius-pill; overflow: hidden; } .o_fp_jmd_bar_fill { height: 100%; - border-radius: 999px; - transition: width 0.3s ease; + border-radius: $fp-radius-pill; + transition: width $fp-dur-slow $fp-ease; - &.o_fp_jmd_bar_early { background-color: #ffc107; } - &.o_fp_jmd_bar_mid { background-color: #0d6efd; } - &.o_fp_jmd_bar_done { background-color: #198754; } + &.o_fp_jmd_bar_early { background-color: $fp-state-ready; } + &.o_fp_jmd_bar_mid { background-color: $fp-state-progress; } + &.o_fp_jmd_bar_done { background-color: $fp-state-done; } } .o_fp_jmd_bar_label { flex: 0 0 auto; white-space: nowrap; font-variant-numeric: tabular-nums; + color: $fp-ink-soft; } } diff --git a/fusion_plating/fusion_plating_jobs/static/src/scss/job_process_tree.scss b/fusion_plating/fusion_plating_jobs/static/src/scss/job_process_tree.scss index c007e696..3dd16085 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/scss/job_process_tree.scss +++ b/fusion_plating/fusion_plating_jobs/static/src/scss/job_process_tree.scss @@ -2,27 +2,16 @@ // Fusion Plating — Job Process Tree (horizontal hierarchical, v1, 2026-04) // Copyright 2026 Nexa Systems Inc. · License OPL-1 // -// Parallel of fusion_plating_shopfloor's process_tree.scss, rebound to -// fp.job. Self-contained — does NOT pull in the shopfloor token partial, -// so this module stays free of the shopfloor dependency. -// // Class prefix: .o_fp_jpt_* (Job Process Tree) // -// Hierarchical bracket tree: +// Theme-aware: page, header and connector colours resolve through the +// design tokens defined in _fp_jobs_tokens.scss (compile-time branch +// on $o-webclient-color-scheme). The node CARDS keep an intentional +// Steelhead-style dark-slate fill in BOTH themes — this is a design +// choice, not a theme bug: dark cards on light or dark page give the +// same visual hierarchy as the Steelhead reference UI. // -// [Recipe]──┬──[Sub-Process]──┬──[Operation] -// │ └──[Operation] -// ├──[Operation] -// └──[Operation] -// -// Each .o_fp_jpt_node is `display: flex` with: -// - the card on the left -// - .o_fp_jpt_children on the right (column of recursed children) -// Connectors are drawn entirely from CSS pseudo-elements: -// - vertical bus column on each child via ::after -// - horizontal stub from bus column to card via ::before -// - first/last children trim the vertical line so it stops at the card -// centre. +// Hierarchical bracket tree layout — see body comments below. // ============================================================================= @@ -42,7 +31,6 @@ $jpt-card-h : 44px; // nominal card height (centre stays at h/2) $jpt-row-gap : 12px; // vertical gap between sibling children $jpt-indent : 36px; // horizontal gap from parent → children $jpt-stub : 28px; // horizontal connector segment length -$jpt-line-color : #6b7280; // connector colour $jpt-line-width : 2px; @@ -50,28 +38,30 @@ $jpt-line-width : 2px; height: 100%; overflow: auto; // both axes — wide trees scroll horizontally -webkit-overflow-scrolling: touch; - padding: 16px 24px; + padding: $fp-space-4 $fp-space-6; display: flex; flex-direction: column; - gap: 12px; - background-color: var(--o-action, #f7f7f8); - color: var(--bs-body-color, #1a1d21); + gap: $fp-space-3; + background-color: $fp-page; + color: $fp-ink; - @media (max-width: 600px) { padding: 12px; gap: 12px; } + @media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-3; } // ------------------------------------------------------------------------- - // Header (compact strip) + // Header (compact strip — sits on the page as a card) // ------------------------------------------------------------------------- .o_fp_jpt_header { display: flex; align-items: center; - gap: 12px; + gap: $fp-space-3; flex-wrap: wrap; - padding: 12px 16px; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + padding: $fp-space-3 $fp-space-4; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + box-shadow: $fp-elev-1; position: sticky; top: 0; z-index: 5; @@ -80,35 +70,41 @@ $jpt-line-width : 2px; display: inline-flex; align-items: center; padding: 6px 12px; - border-radius: 999px; - background-color: var(--bs-tertiary-bg, #f1f3f5); - color: var(--bs-body-color, #1a1d21); - font-weight: 500; - font-size: 0.875rem; - border: 1px solid #d8dadd; + border-radius: $fp-radius-pill; + background-color: $fp-card-soft; + color: $fp-ink; + font-weight: $fp-weight-medium; + font-size: $fp-text-sm; + border: 1px solid #{$fp-border}; cursor: pointer; - transition: background-color 0.15s ease, - border-color 0.15s ease, - color 0.15s ease; - &:hover { - background-color: #e9ecef; - border-color: #c5c8cc; + transition: background-color $fp-dur-fast $fp-ease, + border-color $fp-dur-fast $fp-ease, + color $fp-dur-fast $fp-ease; + @include fp-hover-only { + &:hover { + background-color: color-mix(in srgb, #{$fp-ink} 7%, $fp-card-soft); + border-color: $fp-border-strong; + } } } .o_fp_jpt_title_block { flex: 1 1 auto; min-width: 0; } .o_fp_jpt_title { - font-size: 1rem; - font-weight: 700; + font-size: $fp-text-base; + font-weight: $fp-weight-bold; margin: 0; + color: $fp-ink; display: inline-flex; align-items: center; gap: 4px; - .o_fp_jpt_job_name { font-weight: 600; opacity: 0.8; } + .o_fp_jpt_job_name { + font-weight: $fp-weight-semibold; + color: $fp-ink-soft; + } } .o_fp_jpt_subtitle { margin-top: 2px; - font-size: 0.75rem; - opacity: 0.7; + font-size: $fp-text-xs; + color: $fp-ink-mute; display: flex; flex-wrap: wrap; align-items: center; gap: 2px; - .fa { margin-right: 2px; opacity: 0.7; } + .fa { margin-right: 2px; color: $fp-ink-faint; } } @@ -117,14 +113,15 @@ $jpt-line-width : 2px; // ------------------------------------------------------------------------- .o_fp_jpt_empty { text-align: center; - padding: 40px 24px; - opacity: 0.7; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; - font-size: 0.875rem; + padding: $fp-space-8 $fp-space-6; + background-color: $fp-card; + color: $fp-ink-mute; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + box-shadow: $fp-elev-1; + font-size: $fp-text-sm; max-width: 520px; - > .fa { font-size: 1.75rem; margin-bottom: 8px; opacity: 0.6; } + > .fa { font-size: 1.75rem; margin-bottom: 8px; color: $fp-ink-faint; } } @@ -132,7 +129,7 @@ $jpt-line-width : 2px; // Tree canvas — horizontally scrollable // ------------------------------------------------------------------------- .o_fp_jpt_canvas { - padding: 12px 0; + padding: $fp-space-3 0; min-width: max-content; // let cards push the canvas wider for scroll } @@ -148,7 +145,11 @@ $jpt-line-width : 2px; // ------------------------------------------------------------------------- - // Card (Steelhead-style: dark fill, rounded) + // Card (Steelhead-style: dark fill, rounded — intentional in both themes) + // + // The dark slate is a deliberate visual choice (Steelhead parity). + // The contrasting page surface is themed via $fp-page above, so the + // overall composition still feels right in light + dark mode. // ------------------------------------------------------------------------- .o_fp_jpt_card { display: inline-flex; @@ -157,37 +158,39 @@ $jpt-line-width : 2px; min-width: 220px; max-width: 340px; min-height: $jpt-card-h; - padding: 8px 12px; - background-color: #2b2f36; // dark slate + padding: $fp-space-2 $fp-space-3; + background-color: #2b2f36; // dark slate (Steelhead parity) color: #f1f3f5; border-radius: 6px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); - font-size: 0.875rem; + box-shadow: $fp-elev-1; + font-size: $fp-text-sm; line-height: 1.25; flex: 0 0 auto; position: relative; z-index: 1; // sit above connector lines - transition: transform 0.1s ease, - box-shadow 0.15s ease, - background-color 0.15s ease; + transition: transform $fp-dur-fast $fp-ease, + box-shadow $fp-dur $fp-ease, + background-color $fp-dur-fast $fp-ease; &.o_fp_jpt_clickable { cursor: pointer; - &:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18); - background-color: #353a42; + @include fp-hover-only { + &:hover { + transform: translateY(-1px); + box-shadow: $fp-elev-2; + background-color: #353a42; + } } } // ---- Card type tints (subtle) ------------------------------------- &.o_fp_jpt_type_recipe { background-color: #1f2329; - font-weight: 700; + font-weight: $fp-weight-bold; } &.o_fp_jpt_type_sub_process { background-color: #262a31; - font-weight: 600; + font-weight: $fp-weight-semibold; } &.o_fp_jpt_type_step { background-color: #353a42; @@ -269,14 +272,17 @@ $jpt-line-width : 2px; display: inline-flex; align-items: center; padding: 1px 7px; - border-radius: 999px; + border-radius: $fp-radius-pill; font-size: 0.65rem; - font-weight: 700; + font-weight: $fp-weight-bold; line-height: 1.4; white-space: nowrap; text-transform: uppercase; letter-spacing: 0.02em; + // Cards are dark-slate filled in BOTH themes, so badge palette + // is tuned for that dark surface — light text on translucent + // tints. NOT theme-sensitive (both bundles render the same way). &.o_fp_jpt_state_badge_pending { background-color: rgba(255,255,255,.12); color: #c8ccd2; } &.o_fp_jpt_state_badge_ready { background-color: rgba(255, 193, 7, .25); color: #ffd866; } &.o_fp_jpt_state_badge_in_progress { background-color: rgba(13, 110, 253, .25); color: #6ea8fe; } @@ -308,7 +314,7 @@ $jpt-line-width : 2px; top: calc(#{$jpt-card-h} / 2); // parent-card vertical centre width: $jpt-indent; height: $jpt-line-width; - background-color: $jpt-line-color; + background-color: $fp-border-strong; z-index: 0; } } @@ -336,7 +342,7 @@ $jpt-line-width : 2px; top: calc(#{$jpt-card-h} / 2); // align with card vertical centre width: $jpt-stub; height: $jpt-line-width; - background-color: $jpt-line-color; + background-color: $fp-border-strong; z-index: 0; } @@ -348,7 +354,7 @@ $jpt-line-width : 2px; top: calc(-#{$jpt-row-gap} / 2); // bridge gap to sibling above bottom: calc(-#{$jpt-row-gap} / 2); // bridge gap to sibling below width: $jpt-line-width; - background-color: $jpt-line-color; + background-color: $fp-border-strong; z-index: 0; } diff --git a/fusion_plating/fusion_plating_jobs/static/src/scss/job_tablet.scss b/fusion_plating/fusion_plating_jobs/static/src/scss/job_tablet.scss index 10ed6c86..66209ffd 100644 --- a/fusion_plating/fusion_plating_jobs/static/src/scss/job_tablet.scss +++ b/fusion_plating/fusion_plating_jobs/static/src/scss/job_tablet.scss @@ -3,7 +3,15 @@ // Copyright 2026 Nexa Systems Inc. · License OPL-1 // // Class prefix: .o_fp_jt_* (Job Tablet) -// Self-contained — no shopfloor token partial dependency. +// +// Theme-aware: every surface, border and text colour resolves through +// the design tokens defined in _fp_jobs_tokens.scss. +// +// Three-layer contrast: +// page = $fp-page (grayest) +// mode panels (header / body / job-header / step-header) = $fp-card-soft (mid) +// cards / step rows / table rows = $fp-card (brightest) +// // Touch-first: min 60px tap targets, 16-20pt text, high contrast. // ============================================================================= @@ -11,12 +19,12 @@ height: 100%; display: flex; flex-direction: column; - padding: 16px 24px; - gap: 16px; - background-color: var(--o-action, #f7f7f8); - color: var(--bs-body-color, #1a1d21); + padding: $fp-space-4 $fp-space-6; + gap: $fp-space-4; + background-color: $fp-page; + color: $fp-ink; overflow: hidden; - font-size: 1rem; + font-size: $fp-text-base; @media (max-width: 800px) { padding: 10px; gap: 10px; } @@ -28,71 +36,77 @@ display: flex; align-items: center; justify-content: space-between; - gap: 12px; - padding: 12px 16px; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + gap: $fp-space-3; + padding: $fp-space-3 $fp-space-4; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + box-shadow: $fp-elev-1; } .o_fp_jt_header_left { display: flex; align-items: center; - gap: 12px; + gap: $fp-space-3; flex: 1 1 auto; min-width: 0; } .o_fp_jt_title { font-size: 1.4rem; - font-weight: 700; + font-weight: $fp-weight-bold; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + color: $fp-ink; } .o_fp_jt_back_btn { min-width: 60px; min-height: 60px; - border: 1px solid #d8dadd; - border-radius: 8px; - background-color: var(--bs-tertiary-bg, #f1f3f5); + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-sm; + background-color: $fp-card-soft; + color: $fp-ink; font-size: 1.4rem; cursor: pointer; flex: 0 0 auto; - &:hover { background-color: #e2e6ea; } - &:active { background-color: #d8dadd; } + &:hover { background-color: color-mix(in srgb, #{$fp-ink} 7%, $fp-card-soft); } + &:active { background-color: color-mix(in srgb, #{$fp-ink} 12%, $fp-card-soft); } } .o_fp_jt_header_right { display: flex; align-items: center; - gap: 8px; + gap: $fp-space-2; } .o_fp_jt_refresh_btn { min-width: 60px; min-height: 60px; - border: 1px solid #d8dadd; - border-radius: 8px; - background-color: var(--bs-tertiary-bg, #f1f3f5); + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-sm; + background-color: $fp-card-soft; + color: $fp-ink; font-size: 1.3rem; cursor: pointer; - &:hover { background-color: #e2e6ea; } + &:hover { background-color: color-mix(in srgb, #{$fp-ink} 7%, $fp-card-soft); } &:disabled { opacity: 0.5; cursor: not-allowed; } } // ------------------------------------------------------------------------ - // Body container + // Body container — holds whichever mode is active // ------------------------------------------------------------------------ .o_fp_jt_body { flex: 1 1 auto; overflow-y: auto; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card-soft; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; padding: 20px; - @media (max-width: 800px) { padding: 12px; } + @media (max-width: 800px) { padding: $fp-space-3; } } @@ -107,7 +121,7 @@ justify-content: center; text-align: center; padding: 60px 20px; - color: var(--bs-secondary-color, #6c757d); + color: $fp-ink-mute; font-size: 1.2rem; } @@ -118,38 +132,44 @@ .o_fp_jt_job_grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 16px; + gap: $fp-space-4; } .o_fp_jt_job_card { - background-color: var(--bs-body-bg, #ffffff); - border: 2px solid #d8dadd; + background-color: $fp-card; + color: $fp-ink; + border: 2px solid #{$fp-border}; border-radius: 12px; - padding: 16px; + padding: $fp-space-4; display: flex; flex-direction: column; gap: 10px; cursor: pointer; min-height: 180px; - transition: transform 0.1s ease, box-shadow 0.15s ease, border-color 0.15s ease; + box-shadow: $fp-elev-1; + transition: transform $fp-dur-fast $fp-ease, + box-shadow $fp-dur $fp-ease, + border-color $fp-dur $fp-ease; - &:hover { - transform: translateY(-2px); - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.10); - border-color: #0d6efd; + @include fp-hover-only { + &:hover { + transform: translateY(-2px); + box-shadow: $fp-elev-2; + border-color: $fp-accent; + } } &:active { transform: translateY(0); - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.10); + box-shadow: $fp-elev-1; } // Priority emphasis &.o_fp_jt_card_rush { - border-color: #dc3545; + border-color: $fp-state-rush; box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.30); } &.o_fp_jt_card_high { - border-color: #fd7e14; + border-color: $fp-state-high; box-shadow: 0 0 0 1px rgba(253, 126, 20, 0.25); } } @@ -158,17 +178,18 @@ display: flex; align-items: flex-start; justify-content: space-between; - gap: 8px; + gap: $fp-space-2; } .o_fp_jt_job_card_name { font-size: 1.25rem; - font-weight: 700; + font-weight: $fp-weight-bold; word-break: break-word; + color: $fp-ink; } .o_fp_jt_job_card_partner { - font-size: 1rem; - color: var(--bs-secondary-color, #6c757d); - font-weight: 500; + font-size: $fp-text-base; + color: $fp-ink-mute; + font-weight: $fp-weight-medium; } .o_fp_jt_job_card_meta { display: flex; @@ -178,19 +199,19 @@ font-size: 0.9rem; } .o_fp_jt_meta_item { - color: var(--bs-secondary-color, #6c757d); + color: $fp-ink-mute; } .o_fp_jt_job_card_progress { display: flex; align-items: center; - gap: 8px; + gap: $fp-space-2; margin-top: auto; } .o_fp_jt_job_card_current { font-size: 0.95rem; padding-top: 6px; - border-top: 1px solid #f1f3f5; - color: #084298; + border-top: 1px solid #{$fp-border}; + color: $fp-state-progress-text; } @@ -200,19 +221,19 @@ .o_fp_jt_progress_bar { flex: 1 1 auto; height: 12px; - background-color: #e9ecef; - border-radius: 999px; + background-color: color-mix(in srgb, #{$fp-ink} 8%, transparent); + border-radius: $fp-radius-pill; overflow: hidden; } .o_fp_jt_progress_fill { height: 100%; - background-color: #198754; - transition: width 0.3s ease; + background-color: $fp-state-done; + transition: width $fp-dur-slow $fp-ease; } .o_fp_jt_progress_label { font-size: 0.85rem; - font-weight: 600; - color: var(--bs-secondary-color, #6c757d); + font-weight: $fp-weight-semibold; + color: $fp-ink-mute; white-space: nowrap; } @@ -221,46 +242,53 @@ // JOB DETAIL MODE // ======================================================================== .o_fp_jt_job_header { - background-color: var(--bs-tertiary-bg, #f1f3f5); - border: 1px solid #d8dadd; - border-radius: 8px; - padding: 16px; - margin-bottom: 16px; + // Body wraps this section; this header sits inside the body's + // $fp-card-soft surface and uses $fp-card so it pops as the + // brightest layer in the body region. + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; + padding: $fp-space-4; + margin-bottom: $fp-space-4; + box-shadow: $fp-elev-1; } .o_fp_jt_job_header_row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - gap: 12px; + gap: $fp-space-3; margin-bottom: 14px; } .o_fp_jt_job_header_label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--bs-secondary-color, #6c757d); - font-weight: 600; + color: $fp-ink-mute; + font-weight: $fp-weight-semibold; } .o_fp_jt_job_header_value { font-size: 1.1rem; - font-weight: 600; + font-weight: $fp-weight-semibold; margin-top: 2px; + color: $fp-ink; } .o_fp_jt_job_header_progress { display: flex; align-items: center; - gap: 12px; + gap: $fp-space-3; } .o_fp_jt_section_title { font-size: 1.15rem; - font-weight: 700; - margin: 0 0 12px 0; + font-weight: $fp-weight-bold; + margin: 0 0 $fp-space-3 0; + color: $fp-ink; } .o_fp_jt_step_list { display: flex; flex-direction: column; - gap: 8px; + gap: $fp-space-2; } .o_fp_jt_step_row { @@ -268,20 +296,28 @@ align-items: center; gap: 14px; padding: 14px 16px; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; cursor: pointer; min-height: 72px; - transition: background-color 0.1s ease, border-color 0.15s ease, transform 0.1s ease; + box-shadow: $fp-elev-1; + transition: background-color $fp-dur-fast $fp-ease, + border-color $fp-dur $fp-ease, + box-shadow $fp-dur $fp-ease, + transform $fp-dur-fast $fp-ease; - &:hover { - border-color: #0d6efd; - background-color: #f8fafc; - transform: translateX(2px); + @include fp-hover-only { + &:hover { + border-color: $fp-accent; + background-color: color-mix(in srgb, #{$fp-accent} 4%, $fp-card); + box-shadow: $fp-elev-2; + transform: translateX(2px); + } } &:active { - background-color: #e9ecef; + background-color: color-mix(in srgb, #{$fp-ink} 6%, $fp-card); } } .o_fp_jt_step_seq { @@ -289,12 +325,12 @@ width: 36px; height: 36px; border-radius: 50%; - background-color: var(--bs-tertiary-bg, #f1f3f5); - color: var(--bs-secondary-color, #6c757d); + background-color: $fp-card-soft; + color: $fp-ink-mute; display: flex; align-items: center; justify-content: center; - font-weight: 700; + font-weight: $fp-weight-bold; font-size: 0.95rem; } .o_fp_jt_step_main { @@ -303,19 +339,20 @@ } .o_fp_jt_step_name { font-size: 1.1rem; - font-weight: 600; + font-weight: $fp-weight-semibold; word-break: break-word; + color: $fp-ink; } .o_fp_jt_step_meta { margin-top: 4px; font-size: 0.85rem; - color: var(--bs-secondary-color, #6c757d); + color: $fp-ink-mute; display: flex; flex-wrap: wrap; gap: 4px 6px; } .o_fp_jt_step_chevron { - color: var(--bs-secondary-color, #6c757d); + color: $fp-ink-mute; font-size: 1.1rem; } @@ -324,31 +361,34 @@ // STEP DETAIL MODE // ======================================================================== .o_fp_jt_step_header { - background-color: var(--bs-tertiary-bg, #f1f3f5); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; padding: 20px; margin-bottom: 20px; + box-shadow: $fp-elev-1; } .o_fp_jt_step_header_top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; - margin-bottom: 16px; + margin-bottom: $fp-space-4; } .o_fp_jt_step_header_seq { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; - color: var(--bs-secondary-color, #6c757d); - font-weight: 600; + color: $fp-ink-mute; + font-weight: $fp-weight-semibold; } .o_fp_jt_step_header_name { font-size: 1.6rem; - font-weight: 700; + font-weight: $fp-weight-bold; margin: 4px 0 0 0; word-break: break-word; + color: $fp-ink; } .o_fp_jt_step_header_grid { display: grid; @@ -359,26 +399,27 @@ font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--bs-secondary-color, #6c757d); - font-weight: 600; + color: $fp-ink-mute; + font-weight: $fp-weight-semibold; } .o_fp_jt_step_header_value { font-size: 1.1rem; - font-weight: 600; + font-weight: $fp-weight-semibold; margin-top: 2px; + color: $fp-ink; } .o_fp_jt_step_instructions { - margin-top: 16px; - padding-top: 16px; - border-top: 1px solid #d8dadd; + margin-top: $fp-space-4; + padding-top: $fp-space-4; + border-top: 1px solid #{$fp-border}; h3 { font-size: 1rem; - font-weight: 700; - margin: 0 0 8px 0; + font-weight: $fp-weight-bold; + margin: 0 0 $fp-space-2 0; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--bs-secondary-color, #6c757d); + color: $fp-ink-mute; } } @@ -388,7 +429,7 @@ // ------------------------------------------------------------------------ .o_fp_jt_action_buttons { display: flex; - gap: 12px; + gap: $fp-space-3; margin-bottom: 20px; flex-wrap: wrap; } @@ -400,13 +441,15 @@ border: none; border-radius: 12px; font-size: 1.5rem; - font-weight: 700; + font-weight: $fp-weight-bold; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #ffffff; - transition: filter 0.1s ease, transform 0.1s ease, box-shadow 0.15s ease; + transition: filter $fp-dur-fast $fp-ease, + transform $fp-dur-fast $fp-ease, + box-shadow $fp-dur $fp-ease; &:hover { filter: brightness(0.92); } &:active { transform: translateY(1px); } @@ -416,6 +459,8 @@ filter: none !important; } } + // Start / Finish buttons are CTAs — they keep semantic green / blue + // in both themes for consistent recognition on the shop floor. .o_fp_jt_btn_start { background-color: #198754; box-shadow: 0 4px 12px rgba(25, 135, 84, 0.30); @@ -428,10 +473,10 @@ .o_fp_jt_no_actions { flex: 1 1 100%; padding: 18px; - background-color: #fff3cd; - border: 1px solid #ffe69c; - border-radius: 8px; - color: #664d03; + background-color: color-mix(in srgb, #{$fp-state-ready} 18%, $fp-card); + border: 1px solid color-mix(in srgb, #{$fp-state-ready} 50%, #{$fp-border}); + border-radius: $fp-radius-md; + color: $fp-state-ready-text; font-size: 1rem; display: flex; align-items: center; @@ -448,33 +493,36 @@ width: 100%; border-collapse: separate; border-spacing: 0; - background-color: var(--bs-body-bg, #ffffff); - border: 1px solid #d8dadd; - border-radius: 8px; + background-color: $fp-card; + color: $fp-ink; + border: 1px solid #{$fp-border}; + border-radius: $fp-radius-md; overflow: hidden; + box-shadow: $fp-elev-1; th { - background-color: var(--bs-tertiary-bg, #f1f3f5); + background-color: $fp-card-soft; padding: 10px 14px; text-align: left; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; - color: var(--bs-secondary-color, #6c757d); - font-weight: 600; - border-bottom: 1px solid #d8dadd; + color: $fp-ink-mute; + font-weight: $fp-weight-semibold; + border-bottom: 1px solid #{$fp-border}; } td { padding: 10px 14px; font-size: 0.95rem; - border-bottom: 1px solid #f1f3f5; + color: $fp-ink; + border-bottom: 1px solid #{$fp-border}; } tr:last-child td { border-bottom: none; } } .o_fp_jt_running { - color: #0d6efd; + color: $fp-state-progress-text; font-style: italic; - font-weight: 600; + font-weight: $fp-weight-semibold; } @@ -485,8 +533,8 @@ .o_fp_jt_state_badge_xl { display: inline-flex; align-items: center; - border-radius: 999px; - font-weight: 700; + border-radius: $fp-radius-pill; + font-weight: $fp-weight-bold; line-height: 1.4; white-space: nowrap; text-transform: uppercase; @@ -502,16 +550,17 @@ } // Color variants — match plant_overview palette - .o_fp_jt_badge_pending { background-color: #e9ecef; color: #6c757d; } - .o_fp_jt_badge_ready { background-color: rgba(13, 110, 253, 0.18); color: #084298; } + .o_fp_jt_badge_pending { background-color: $fp-state-pending-bg; color: $fp-state-pending-text; } + .o_fp_jt_badge_ready { background-color: color-mix(in srgb, #{$fp-state-progress} 18%, transparent); color: $fp-state-progress-text; } .o_fp_jt_badge_progress { - background-color: rgba(253, 126, 20, 0.20); color: #97480d; + background-color: color-mix(in srgb, #{$fp-state-paused} 20%, transparent); + color: $fp-state-paused-text; animation: o_fp_jt_pulse 2s ease-in-out infinite; } - .o_fp_jt_badge_paused { background-color: rgba(255, 193, 7, 0.22); color: #b58105; } - .o_fp_jt_badge_done { background-color: rgba(25, 135, 84, 0.22); color: #0f5132; } - .o_fp_jt_badge_skipped { background-color: #e9ecef; color: #6c757d; } - .o_fp_jt_badge_cancelled { background-color: rgba(220, 53, 69, 0.18); color: #842029; } + .o_fp_jt_badge_paused { background-color: color-mix(in srgb, #{$fp-state-ready} 22%, transparent); color: $fp-state-ready-text; } + .o_fp_jt_badge_done { background-color: color-mix(in srgb, #{$fp-state-done} 22%, transparent); color: $fp-state-done-text; } + .o_fp_jt_badge_skipped { background-color: $fp-state-pending-bg; color: $fp-state-pending-text; } + .o_fp_jt_badge_cancelled { background-color: color-mix(in srgb, #{$fp-state-cancel} 18%, transparent); color: $fp-state-cancel-text; } // ======================================================================== @@ -521,16 +570,17 @@ display: inline-flex; align-items: center; padding: 3px 10px; - border-radius: 999px; + border-radius: $fp-radius-pill; font-size: 0.75rem; - font-weight: 700; + font-weight: $fp-weight-bold; line-height: 1.4; text-transform: uppercase; letter-spacing: 0.03em; + color: #ffffff; - &.o_fp_jt_chip_rush { background-color: #dc3545; color: #fff; } - &.o_fp_jt_chip_high { background-color: #fd7e14; color: #fff; } - &.o_fp_jt_chip_low { background-color: #6c757d; color: #fff; } + &.o_fp_jt_chip_rush { background-color: $fp-state-rush; } + &.o_fp_jt_chip_high { background-color: $fp-state-high; } + &.o_fp_jt_chip_low { background-color: $fp-state-low; } } }