feat(plant-overview): live debounced search + bigger search bar

The search bar required Enter to fire, which felt clunky on a shop
floor where managers expect cards to filter as they type. Switched
to a 200ms-debounced live search — fast enough to feel instant on
keystrokes, slow enough to skip the network call when someone is
mid-word.

Search bar visual weight bumped:
  - Width 260px → 380px (320px on iPad, full width on phones)
  - Height 48px → 52px
  - Font-size base → md, weight medium
  - Search icon nudged 14px → 16px from the edge with a 1.05rem size
  - Placeholder uses the lighter $fp-ink-faint so the input feels
    inviting rather than already-filled

Behaviour:
  - Type → cards filter after 200ms of no input
  - Enter → fires immediately (skips debounce) for power users
  - Escape → clears the search (new shortcut)
  - Clear button → unchanged

Bumped shopfloor to 19.0.14.0.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-18 23:53:12 -04:00
parent 9b3b674197
commit 4065c6891b
3 changed files with 32 additions and 7 deletions

View File

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

View File

@@ -74,18 +74,33 @@ export class PlantOverview extends Component {
} }
// ----- Search ------------------------------------------------------------ // ----- Search ------------------------------------------------------------
//
// Live search with a 200ms debounce. The user types, the cards update
// as they go — no "press Enter" leap of faith. Debounce keeps us off
// the network on every keystroke when someone types fast.
onSearchInput(ev) { onSearchInput(ev) {
this.state.searchTerm = ev.target.value; this.state.searchTerm = ev.target.value;
this._debouncedSearch();
}
_debouncedSearch() {
if (this._searchTimer) clearTimeout(this._searchTimer);
this._searchTimer = setTimeout(() => this.loadData(), 200);
} }
onSearchKey(ev) { onSearchKey(ev) {
// Enter still works — fires immediately, skipping the debounce.
if (ev.key === "Enter") { if (ev.key === "Enter") {
if (this._searchTimer) clearTimeout(this._searchTimer);
this.loadData(); this.loadData();
} else if (ev.key === "Escape") {
this.onSearchClear();
} }
} }
onSearchClear() { onSearchClear() {
if (this._searchTimer) clearTimeout(this._searchTimer);
this.state.searchTerm = ""; this.state.searchTerm = "";
this.loadData(); this.loadData();
} }

View File

@@ -65,26 +65,36 @@
align-items: center; align-items: center;
.o_fp_po_search_icon { .o_fp_po_search_icon {
position: absolute; left: 14px; position: absolute; left: 16px;
color: $fp-ink-mute; pointer-events: none; color: $fp-ink-mute; pointer-events: none;
font-size: 1.05rem;
} }
.o_fp_po_search_input { .o_fp_po_search_input {
padding: 0 $fp-space-4 0 $fp-space-7; // Bumped from 260px → 380px and slightly taller padding so the
min-height: $fp-touch-min; // search bar carries proper visual weight on the toolbar. Live
// search (200ms debounce) makes the input feel like the
// primary affordance on the page, not an afterthought.
padding: 0 $fp-space-5 0 $fp-space-8;
min-height: 52px;
border: 1px solid #{$fp-border}; border: 1px solid #{$fp-border};
border-radius: $fp-radius-md; border-radius: $fp-radius-md;
background-color: $fp-card; background-color: $fp-card;
color: $fp-ink; color: $fp-ink;
box-shadow: $fp-elev-1; box-shadow: $fp-elev-1;
width: 260px; width: 380px;
font-size: $fp-text-base; font-size: $fp-text-md;
font-weight: $fp-weight-medium;
transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease; transition: box-shadow $fp-dur $fp-ease, border-color $fp-dur $fp-ease;
&::placeholder { color: $fp-ink-faint; font-weight: $fp-weight-medium; }
&:focus { &:focus {
@include fp-focus-ring; @include fp-focus-ring;
border-color: $fp-accent; border-color: $fp-accent;
} }
@media (max-width: 600px) { width: 100%; } // Tablet — keep it generously sized but cap so the toolbar
// doesn't blow past the viewport.
@media (max-width: 1180px) { width: 320px; min-height: 48px; }
@media (max-width: 900px) { width: 100%; }
} }
.o_fp_po_search_clear { .o_fp_po_search_clear {
position: absolute; right: 6px; position: absolute; right: 6px;