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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user