From ae03e32b5de356337725c4c99841d71dd28f7e30 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 18 Apr 2026 18:16:35 -0400 Subject: [PATCH] style(shopfloor): phone + iPad responsive across all 5 pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shop-floor workers and managers use phones and iPads on the line. The existing layouts only stacked at 1100px / 1280px, which left everything cramped on a 375px iPhone or 390px Android. Pass through all 5 shop-floor screens with disciplined breakpoints and touch-first sizing. Breakpoint ladder (consistent across files): 1400px : manager WO row: worker/tank pickers drop to their own rows 1280px : manager grid 3 → 2 columns, Team spans both 1100px : tablet dashboard 2 → 1 column 900px : manager grid → 1 column; tablet + manager padding shrinks 768px : plant overview columns stack; first-piece & bake kanbans already handled natively by Odoo 600px : PHONE — all columns stack, everything full-width, every button min-height 44px (Apple HIG touch target), font shrinks for denser phone screens Manager Desk (manager_dashboard.scss): - Header stacks into two full-width rows on phone, action buttons flex-grow to share the row - 3 column grid stacks earlier (900px instead of 800px) so iPad portrait gets a clean single-column view - WO rows: assign/tank pickers go full-width on their own rows at 1400px, then the whole row stacks to 1 column at 600px - Cards min 56px tap zone - Team avatars keep their layout but cap gap on phone Tablet Station (fusion_plating_shopfloor.scss): - Header: picker/scan button stack full-width on phone - KPI strip auto-fit by default, forced 2×3 grid on phone so 6 tiles stay visible without scrolling past a wall of tall cards - Queue rows: Start/Finish buttons drop to their own row on phone, each flexing to 50% width → easy one-thumb tap - Bake/Gate/Hold rows: full stack on phone, action buttons flex-grow - Bath tile grid: 2-up on phone (not auto-fit) - Active WO banner stacks, Open-WO button full-width - Station picker and scan input go full-width Plant Overview (plant_overview.scss): - Columns stack at 768px (already there) + 600px padding shrink, search input full-width, header wraps sensibly - Cards get min-height 64px for touch Touch-device hover suppression: @media (hover: none) — hover highlights were sticking after tap on phones/iPads. Block them for .o_fp_queue_row, .o_fp_tile, .o_fp_tablet_card, .o_fp_mgr_card, .o_fp_team_card, .o_fp_po_card. Asset cache cleared so phones pick up the new SCSS on next load. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/scss/fusion_plating_shopfloor.scss | 105 +++++++++++++++++- .../static/src/scss/manager_dashboard.scss | 64 ++++++++++- .../static/src/scss/plant_overview.scss | 24 ++++ 3 files changed, 184 insertions(+), 9 deletions(-) diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss index 3a70f981..ab778885 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/fusion_plating_shopfloor.scss @@ -29,6 +29,21 @@ } +// ----------------------------------------------------------------------------- +// Global touch tweaks — apply to every shop-floor page +// ----------------------------------------------------------------------------- +@media (hover: none) { + // Hover highlights stick on tap — disable them on touch devices. + .o_fp_tablet .o_fp_queue_row:hover, + .o_fp_tablet .o_fp_tile:hover, + .o_fp_tablet .o_fp_tablet_card:hover { + background-color: inherit !important; + border-color: var(--bs-border-color) !important; + box-shadow: none !important; + } +} + + // ----------------------------------------------------------------------------- // Tablet root container — large touch targets, generous whitespace // ----------------------------------------------------------------------------- @@ -42,6 +57,11 @@ flex-direction: column; gap: 14px; + // iPad portrait / small tablet + @media (max-width: 900px) { padding: 14px 12px; gap: 10px; } + // Phone + @media (max-width: 600px) { padding: 10px 8px; gap: 8px; font-size: 0.95rem; } + // ---------- Header ------------------------------------------------------- .o_fp_tablet_header { display: flex; @@ -49,10 +69,23 @@ align-items: center; gap: 16px; flex-wrap: wrap; + + @media (max-width: 600px) { + flex-direction: column; + align-items: stretch; + gap: 8px; + + .o_fp_tablet_header_actions { + width: 100%; + flex-wrap: wrap; + > * { flex: 1; min-width: 0; } + } + } } .o_fp_tablet_title { font-size: 1.5rem; font-weight: 600; + @media (max-width: 600px) { font-size: 1.15rem; } } .o_fp_tablet_subtitle { font-size: 0.95rem; @@ -77,9 +110,15 @@ .o_fp_station_picker { min-width: 240px; max-width: 320px; + min-height: 38px; + @media (max-width: 600px) { + min-width: 0; + max-width: 100%; + } } .o_fp_scan_toggle { white-space: nowrap; + min-height: 44px; } // ---------- Scan drawer -------------------------------------------------- @@ -108,6 +147,11 @@ display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; + @media (max-width: 600px) { + // 2 columns on phone so 6 tiles wrap to 3 rows instead of 6 stacked + grid-template-columns: repeat(2, 1fr); + gap: 6px; + } } .o_fp_kpi { position: relative; @@ -119,6 +163,12 @@ flex-direction: column; gap: 2px; transition: border-color 120ms ease, box-shadow 120ms ease; + @media (max-width: 600px) { + padding: 8px 10px; + .o_fp_kpi_value { font-size: 1.4rem !important; } + .o_fp_kpi_label { font-size: 0.72rem !important; } + > .fa { font-size: 1rem !important; top: 8px; right: 8px; } + } > .fa { position: absolute; @@ -151,6 +201,13 @@ border: 1px solid color-mix(in srgb, var(--bs-success) 40%, var(--bs-border-color)); background-color: color-mix(in srgb, var(--bs-success) 7%, var(--o-view-background-color, var(--bs-body-bg))); border-radius: 10px; + @media (max-width: 600px) { + flex-direction: column; + align-items: stretch; + gap: 8px; + padding: 10px 12px; + > .btn { width: 100%; min-height: 44px; } + } } .o_fp_active_wo_left { display: flex; @@ -176,14 +233,14 @@ display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 14px; - } - @media (max-width: 1100px) { - .o_fp_tablet_dashboard { grid-template-columns: 1fr; } + @media (max-width: 1100px) { grid-template-columns: 1fr; } + @media (max-width: 600px) { gap: 8px; } } .o_fp_right_col { display: flex; flex-direction: column; gap: 14px; + @media (max-width: 600px) { gap: 8px; } } // ---------- Panel (reusable card) --------------------------------------- @@ -192,6 +249,10 @@ border: 1px solid var(--bs-border-color); border-radius: 12px; padding: 14px 16px; + @media (max-width: 600px) { + padding: 10px 12px; + border-radius: 10px; + } } .o_fp_panel_head { display: flex; @@ -234,9 +295,22 @@ border: 1px solid var(--bs-border-color); border-radius: 8px; transition: background-color 120ms ease, border-color 120ms ease; - &:hover { - background-color: color-mix(in srgb, var(--o-action) 7%, var(--o-view-background-color, var(--bs-body-bg))); - border-color: color-mix(in srgb, var(--o-action) 40%, var(--bs-border-color)); + min-height: 56px; // comfortable tap zone + @media (hover: hover) { + &:hover { + background-color: color-mix(in srgb, var(--o-action) 7%, var(--o-view-background-color, var(--bs-body-bg))); + border-color: color-mix(in srgb, var(--o-action) 40%, var(--bs-border-color)); + } + } + @media (max-width: 600px) { + grid-template-columns: 32px 1fr; + // Action buttons drop to their own row + .o_fp_queue_actions { + grid-column: 1 / -1; + justify-content: flex-end; + margin-top: 4px; + > .btn { flex: 1; } + } } } .o_fp_queue_body { cursor: pointer; } @@ -244,6 +318,7 @@ display: flex; gap: 6px; align-items: center; + .btn { min-height: 44px; } // touch-friendly } .o_fp_queue_label { font-weight: 600; } .o_fp_queue_desc { font-size: 0.88rem; color: var(--bs-secondary-color); } @@ -265,6 +340,10 @@ display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; + @media (max-width: 600px) { + grid-template-columns: 1fr 1fr; + gap: 6px; + } } .o_fp_tile { border: 1px solid var(--bs-border-color); @@ -320,6 +399,20 @@ padding: 8px 10px; border: 1px solid var(--bs-border-color); border-radius: 8px; + min-height: 56px; + + @media (max-width: 600px) { + grid-template-columns: 1fr; + gap: 6px; + .o_fp_bake_time, .o_fp_bake_actions { + justify-self: stretch; + } + .o_fp_bake_actions { + display: flex; + gap: 6px; + .btn { flex: 1; min-height: 44px; } + } + } &[data-state="awaiting_bake"], &[data-state="pending"] { border-left: 4px solid var(--bs-warning); diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/manager_dashboard.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/manager_dashboard.scss index 7f3a2e08..5d366ff2 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/manager_dashboard.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/manager_dashboard.scss @@ -8,6 +8,15 @@ // .o_fp_panel, .o_fp_empty, .o_fp_tablet_message from the tablet SCSS. // ============================================================================= +// Touch device — stop hover states from sticking on tap +@media (hover: none) { + .o_fp_manager .o_fp_mgr_card:hover, + .o_fp_manager .o_fp_team_card:hover { + background-color: inherit !important; + border-color: var(--bs-border-color) !important; + } +} + .o_fp_manager { background-color: var(--o-view-background-color, var(--bs-body-bg)); color: var(--bs-body-color); @@ -17,18 +26,42 @@ flex-direction: column; gap: 14px; + // iPad portrait & small tablet + @media (max-width: 900px) { + padding: 14px 12px; + gap: 10px; + } + // Phone + @media (max-width: 600px) { + padding: 10px 8px; + gap: 8px; + } + .o_fp_manager_header { display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; + + @media (max-width: 600px) { + gap: 8px; + // Stack title and actions on phone + flex-direction: column; + align-items: stretch; + + .o_fp_manager_head_actions { + width: 100%; + > .btn { flex: 1; } + } + } } .o_fp_manager_title { font-size: 1.5rem; font-weight: 600; display: inline-flex; align-items: center; + @media (max-width: 600px) { font-size: 1.15rem; } } // Small breathing dot that pulses while a poll is in flight. @@ -63,14 +96,19 @@ grid-template-columns: minmax(0, 1.2fr) minmax(0, 1.2fr) minmax(0, 0.8fr); gap: 14px; } + // iPad landscape @media (max-width: 1280px) { .o_fp_manager_grid { grid-template-columns: 1fr 1fr; } .o_fp_panel_team { grid-column: span 2; } } - @media (max-width: 800px) { - .o_fp_manager_grid { grid-template-columns: 1fr; } + // iPad portrait / phone landscape + @media (max-width: 900px) { + .o_fp_manager_grid { + grid-template-columns: 1fr; + gap: 10px; + } .o_fp_panel_team { grid-column: auto; } } @@ -113,6 +151,12 @@ padding: 10px 14px; cursor: pointer; gap: 10px; + min-height: 56px; // comfortable touch zone + + @media (max-width: 600px) { + flex-wrap: wrap; + padding: 10px 12px; + } } .o_fp_mgr_card_title { font-weight: 600; @@ -152,8 +196,21 @@ @media (max-width: 1400px) { .o_fp_mgr_wo_row { grid-template-columns: 1fr auto auto; + // Worker picker takes its own row + .o_fp_mgr_picker:nth-of-type(1) { grid-column: 1 / -1; } + // Tank picker also takes its own row + .o_fp_mgr_picker:nth-of-type(2) { grid-column: 1 / -1; } + } + } + // Phone — everything stacks full-width + @media (max-width: 600px) { + .o_fp_mgr_wo_row { + grid-template-columns: 1fr; + padding: 10px 0; + gap: 6px; - .o_fp_mgr_picker:nth-of-type(2) { grid-column: span 3; } + .o_fp_mgr_picker { max-width: 100% !important; width: 100%; } + .btn { min-height: 44px; } } } .o_fp_mgr_wo_info { @@ -165,6 +222,7 @@ .o_fp_mgr_picker { min-width: 120px; max-width: 180px; + min-height: 38px; // readable tap target } // Team grid diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_overview.scss b/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_overview.scss index 6d3d1ca7..33597635 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_overview.scss +++ b/fusion_plating/fusion_plating_shopfloor/static/src/scss/plant_overview.scss @@ -422,6 +422,7 @@ flex-direction: column; align-items: stretch; padding: 12px; + gap: 10px; } .o_fp_po_column { @@ -437,5 +438,28 @@ .o_fp_po_header { padding: 12px; + flex-wrap: wrap; + gap: 8px; } } + +// Phone — further tighten + touch-first cards +@media (max-width: 600px) { + .o_fp_po_columns { padding: 8px; gap: 8px; } + .o_fp_po_col_body { padding: 6px; } + .o_fp_po_card { + padding: 10px 12px; + min-height: 64px; // comfortable tap zone + } + .o_fp_po_search_input { width: 100% !important; } + .o_fp_po_header { + flex-direction: column; + align-items: stretch; + > * { width: 100%; } + } +} + +// Touch devices: disable hover-only highlights (they stick on tap) +@media (hover: none) { + .o_fp_po_card:hover { background: inherit !important; } +}