diff --git a/fusion_plating/fusion_plating_shopfloor/__manifest__.py b/fusion_plating/fusion_plating_shopfloor/__manifest__.py index 5a15b971..0a3c7b4e 100644 --- a/fusion_plating/fusion_plating_shopfloor/__manifest__.py +++ b/fusion_plating/fusion_plating_shopfloor/__manifest__.py @@ -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.', 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 8c4fac2e..2466f13d 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 @@ -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,"); + 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; } } diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml index 7ed7286e..b8f8d9b2 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml +++ b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml @@ -36,6 +36,7 @@