fix(tablet): tighten layout for iPad + custom dropdown chevron

Operators run the Tablet Station on iPads (mostly landscape, sometimes
portrait). The previous design pushed the dashboard panels below the
fold on a 1024×768 viewport — meant a swipe before they could see
their queue. Tightens spacing across the page without changing the
visual language.

What changed (all behind @media (max-width: 1180px)):
- Page padding 24/32 → 16/20, gap between sections 24 → 16
- Hero title 32 → 24px, subtitle margin-top halved
- KPI strip switches from auto-fit to fixed 6-column grid so all six
  KPIs stay on a single row instead of wrapping at iPad widths;
  per-tile padding 20 → 12/16, value font 44 → 24px, label 14 → 12px
- Active WO banner padding 20 → 12/16
- Dashboard breakpoint to single-column lowered 1100 → 760px so
  iPad portrait still gets two columns of panels
- Panel padding 20 → 16, panel-head padding-bottom 12 → 8
- Empty state padding 32/16 → 16/12 (the "All caught up" tile no
  longer eats 140px per panel)
- Queue rows min-height 64 → 52, bake/gate rows 64 → 48

Station picker dropdown:
- Native chevron suppressed via appearance: none and replaced with
  an inlined SVG arrow positioned with explicit right-edge inset.
  Stroke uses currentColor so it follows light/dark mode.
- Right padding bumped from $fp-space-4 → $fp-space-7 to give the
  arrow breathing room — previously hugged the rounded corner.

Station dropdown labels:
- Append "(CODE)" after the name. The shop's five stations
  (Bake Oven Tablet / Inspection Kiosk / Plating Room Tablet 1 /
  Receiving Mobile / Shipping Desktop) all live in the same facility
  with no work_center, so without the code suffix the dropdown
  options looked similar at a glance.

Bumped fusion_plating_shopfloor → 19.0.10.0.0. Asset bundle
regenerated as bc28f73.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-18 21:26:42 -04:00
parent 76c898aadf
commit c1d26f3168
3 changed files with 95 additions and 10 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Shop Floor',
'version': '19.0.9.0.0',
'version': '19.0.10.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer, '
'first-piece inspection gates.',

View File

@@ -34,10 +34,14 @@
padding: $fp-space-6 $fp-space-7;
display: flex;
flex-direction: column;
gap: $fp-space-6;
gap: $fp-space-5;
@media (max-width: 900px) { padding: $fp-space-4; gap: $fp-space-4; }
@media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-4; }
// Tablet sweet spot — iPad landscape (1024) and portrait (768).
// The goal is to fit Hero + KPIs + Active WO + the first row of
// panels in a single 768-tall viewport.
@media (max-width: 1180px) { padding: $fp-space-4 $fp-space-5; gap: $fp-space-4; }
@media (max-width: 900px) { padding: $fp-space-4; gap: $fp-space-3; }
@media (max-width: 600px) { padding: $fp-space-3; gap: $fp-space-3; }
// -------------------------------------------------------------------------
@@ -62,12 +66,18 @@
margin: 0;
color: $fp-ink;
display: flex; align-items: center; gap: $fp-space-3;
// Smaller hero on tablet — saves ~16px of vertical space without
// losing the page identity.
@media (max-width: 1180px) { font-size: $fp-text-xl; gap: $fp-space-2; }
}
.o_fp_tablet_subtitle {
margin-top: $fp-space-2;
font-size: $fp-text-sm;
color: $fp-ink-mute;
display: flex; flex-wrap: wrap; gap: $fp-space-3; align-items: center;
@media (max-width: 1180px) { margin-top: $fp-space-1; }
}
.o_fp_tablet_chip {
display: inline-flex;
@@ -93,7 +103,10 @@
.o_fp_station_picker {
min-width: 240px;
min-height: $fp-touch-min;
padding: $fp-space-2 $fp-space-4;
// Reserve room on the right so the custom chevron has breathing
// space between itself and the rounded corner — the native arrow
// hugs the edge in Odoo's frame, which looked cramped on iPad.
padding: $fp-space-2 $fp-space-7 $fp-space-2 $fp-space-4;
border: 1px solid #{$fp-border};
border-radius: $fp-radius-md;
background-color: $fp-card;
@@ -103,6 +116,20 @@
cursor: pointer;
transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease;
// Suppress the browser's native chevron and paint our own. The
// SVG is inlined (data URL) so it renders crisply at any DPI and
// doesn't trigger an extra HTTP request. Stroke uses currentColor
// so it follows light/dark mode automatically.
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><polyline points='1 1.5 6 6.5 11 1.5'/></svg>");
background-repeat: no-repeat;
// Inset from the right edge so the chevron sits inside the
// padded zone, not flush with the border radius.
background-position: right $fp-space-4 center;
background-size: 12px 8px;
&:focus { @include fp-focus-ring; border-color: $fp-accent; }
@media (max-width: 600px) { min-width: 0; width: 100%; }
}
@@ -205,6 +232,16 @@
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: $fp-space-4;
// iPad landscape (1024) — six 130px tiles + gaps fit on one row.
// Keeps the KPI strip a single line so the dashboard can stay above
// the fold.
@media (max-width: 1180px) {
grid-template-columns: repeat(6, minmax(0, 1fr));
gap: $fp-space-3;
}
@media (max-width: 820px) {
grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 600px) {
grid-template-columns: repeat(2, 1fr);
gap: $fp-space-3;
@@ -220,6 +257,15 @@
display: flex; flex-direction: column; gap: $fp-space-2;
transition: transform $fp-dur $fp-ease, box-shadow $fp-dur $fp-ease;
@media (max-width: 1180px) {
padding: $fp-space-3 $fp-space-4;
gap: $fp-space-1;
.o_fp_kpi_value { font-size: $fp-text-xl; }
.o_fp_kpi_label { font-size: $fp-text-xs; }
// Pull the status dot in so it doesn't crowd small tiles
&::after { top: $fp-space-3; right: $fp-space-3; width: 8px; height: 8px; }
}
@include fp-hover-only {
&:hover {
transform: translateY(-2px);
@@ -286,6 +332,7 @@
box-shadow: $fp-elev-1;
color: $fp-ink;
@media (max-width: 1180px) { padding: $fp-space-3 $fp-space-4; }
@media (max-width: 600px) {
flex-direction: column; align-items: stretch;
> .btn { width: 100%; min-height: $fp-touch-min; }
@@ -327,12 +374,17 @@
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
gap: $fp-space-5;
@media (max-width: 1100px) { grid-template-columns: 1fr; }
@media (max-width: 600px) { gap: $fp-space-3; }
// Keep the two-column layout down to iPad portrait (768) so the
// queue and the bath/bake panels stay side-by-side instead of
// stacking. Below that the single-column layout still kicks in.
@media (max-width: 1180px) { gap: $fp-space-3; }
@media (max-width: 760px) { grid-template-columns: 1fr; }
@media (max-width: 600px) { gap: $fp-space-3; }
}
.o_fp_right_col {
display: flex; flex-direction: column; gap: $fp-space-5;
@media (max-width: 600px) { gap: $fp-space-3; }
display: flex; flex-direction: column; gap: $fp-space-4;
@media (max-width: 1180px) { gap: $fp-space-3; }
@media (max-width: 600px) { gap: $fp-space-3; }
}
@@ -345,7 +397,8 @@
border-radius: $fp-radius-lg;
box-shadow: $fp-elev-1;
padding: $fp-space-5;
@media (max-width: 600px) { padding: $fp-space-4; }
@media (max-width: 1180px) { padding: $fp-space-4; }
@media (max-width: 600px) { padding: $fp-space-4; }
}
.o_fp_panel_head {
display: flex;
@@ -355,6 +408,14 @@
padding-bottom: $fp-space-3;
border-bottom: 1px solid #{$fp-border};
@media (max-width: 1180px) {
margin-bottom: $fp-space-3;
padding-bottom: $fp-space-2;
h3 { font-size: $fp-text-base;
> .fa { width: 28px; height: 28px; font-size: 0.85rem; }
}
}
h3 {
font-size: $fp-text-lg;
font-weight: $fp-weight-bold;
@@ -402,6 +463,15 @@
opacity: 0.5;
margin-bottom: $fp-space-3;
}
// On tablet, the "All caught up" state was eating ~140px of
// vertical space per panel. Halve it so the dashboard stays
// dense even when one or two panels are empty.
@media (max-width: 1180px) {
padding: $fp-space-4 $fp-space-3;
font-size: $fp-text-sm;
i.fa { font-size: 1.75rem; margin-bottom: $fp-space-2; }
}
}
@@ -422,6 +492,12 @@
border-radius: $fp-radius-md;
background-color: $fp-card;
min-height: 64px;
@media (max-width: 1180px) {
grid-template-columns: 36px 1fr auto;
padding: $fp-space-2 $fp-space-3;
min-height: 52px;
}
transition: background-color $fp-dur $fp-ease,
border-color $fp-dur $fp-ease,
box-shadow $fp-dur $fp-ease,
@@ -463,6 +539,8 @@
font-size: 0.72rem;
letter-spacing: 0.04em;
@media (max-width: 1180px) { width: 32px; height: 32px; }
&[data-priority="high"] { @include fp-pill(--bs-danger); }
&[data-priority="med"] { @include fp-pill(--bs-warning); }
&[data-priority="low"] { background-color: $fp-card-soft; color: $fp-ink-mute; }
@@ -561,6 +639,12 @@
border-radius: $fp-radius-md;
background-color: $fp-card;
min-height: 64px;
@media (max-width: 1180px) {
padding: $fp-space-2 $fp-space-3;
min-height: 48px;
gap: $fp-space-2;
}
transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease;
@include fp-hover-only { &:hover { box-shadow: $fp-elev-2; } }

View File

@@ -36,6 +36,7 @@
<option t-att-value="s.id"
t-att-selected="state.stationId === s.id">
<t t-esc="s.name"/>
<t t-if="s.code"> (<t t-esc="s.code"/>)</t>
<t t-if="s.work_center"> · <t t-esc="s.work_center"/></t>
</option>
</t>