style(shopfloor): phone + iPad responsive across all 5 pages

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) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-18 18:16:35 -04:00
parent d29857078a
commit ae03e32b5d
3 changed files with 184 additions and 9 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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; }
}