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