Files
Extrudex/design/01-filament-inventory-list.md

344 lines
18 KiB
Markdown
Raw Permalink Normal View History

2026-04-25 18:51:05 +00:00
# Filament Inventory List — Screen Specification
> **Screen ID:** FIL-001
> **Source of Truth:** [Material Design 3](https://m3.material.io/)
> **Tone:** Modern Industrial/Maker
> **Theme:** Dark Mode, High-Contrast
> **Last Updated:** 2026-04-20
---
## 1. Objective
Provide a single, scannable view of all filament spools in inventory. Users (shop operators) must be able to:
- Rapidly assess stock levels at a glance (which spools are low/critical).
- Search by material type, brand, color, or internal tracking ID.
- Filter by status (Available, In Use, Low Stock, Depleted).
- Navigate to spool detail or initiate the Smart Intake workflow.
This is the **primary landing screen** for both the kiosk and the mobile PWA.
---
## 2. Screen Inventory
| Element | MD3 Component | Notes |
|---------|--------------|-------|
| Top App Bar | `md-top-app-bar` (medium) | Title + search toggle + intake FAB |
| Search Bar | `md-search-bar` | Expandable on tap; collapses to icon on kiosk |
| Filter Chips | `md-chip-set` (filter) | Status filters: All / Available / In Use / Low / Depleted |
| Inventory List | `md-list` (3-line) | Spool cards as list items |
| Low-Stock Badge | `md-badge` | Tonal badge on list items |
| Extended FAB | `md-fab` (extended) | "Smart Intake" CTA |
| Navigation Rail | `md-navigation-rail` | Kiosk only — Inventory / Printers / Jobs / Settings |
| Bottom Navigation | `md-navigation-bar` | Mobile only — same destinations |
| Empty State | Illustration + `md-text-button` | When no spools match filter |
---
## 3. Layout Specification
### Title
**"Filament Inventory"** — displayed in the Top App Bar headline slot.
### Sections
#### A. Top App Bar (56dp mobile / 64dp kiosk)
- **Leading:** Menu icon (kiosk) / Back arrow (mobile, if deep-linked)
- **Title:** "Filament Inventory"
- **Trailing actions:** Search icon (toggles search bar), Overflow menu (Sort by, Export)
#### B. Search Bar (0dp collapsed → 56dp expanded)
- Triggered by search icon tap or pull-down gesture on mobile
- Placeholder: "Search spools, brands, colors…"
- Auto-focus on expand; dismiss on back/clear
- Real-time filtering as user types
#### C. Filter Chip Row (52dp height, horizontal scroll)
- Chips: `All` | `Available` | `In Use` | `Low Stock` | `Depleted`
- Default selection: `All`
- Multi-select disabled — single filter active at a time
- Chip styling: Tonal variants per status color
- Available: `green` tonal
- In Use: `blue` tonal (primary)
- Low Stock: `yellow` tonal (warning)
- Depleted: `red` tonal (error)
#### D. Inventory List (flex, scrollable)
- Each item is a **3-line list item** with leading/trailing elements:
```
┌──────────────────────────────────────────────────┐
│ [Color Swatch] PLA Basic - Matte Black │
│ Bambu Lab • Slot A3 • 842g left │
│ ▓▓▓▓▓▓▓▓▓▓░░ 67% [Low] badge │
├──────────────────────────────────────────────────┤
│ [Color Swatch] PETG Basic - Transparent │
│ Polymaker • Shelf B2 • 210g left │
│ ▓▓▓░░░░░░░░░ 21% [Critical] ⚠ │
└──────────────────────────────────────────────────┘
```
- **Leading:** Circular color swatch (40dp) — matches filament color
- **Line 1:** Material name (MaterialBase + Finish + Modifier) — `titleMedium`, `onSurface`
- **Line 2:** Brand • Location • Remaining weight — `bodyMedium`, `onSurfaceVariant`
- **Line 3:** Linear progress indicator + percentage text — `labelSmall`, `onSurfaceVariant`
- **Trailing:** Status badge (tonal chip) + chevron icon
- **Divider:** Full-width between items
**Sort order (default):** Low stock first, then alphabetical by material name.
#### E. Extended FAB (Bottom-end, mobile; Bottom-end, kiosk)
- Label: **"Smart Intake"** + `qr_code_scanner` icon
- Container: `primaryContainer` color
- On tap → navigates to Smart Intake Scan State
#### F. Navigation (Screen-level)
- **Kiosk:** Navigation Rail on leading edge (80dp wide)
- Destinations: Inventory (active), Printers, Jobs, Settings
- **Mobile:** Bottom Navigation Bar (80dp height)
- Same destinations
### Primary CTA
**Smart Intake** (Extended FAB) — always visible, anchored bottom-end.
### Secondary Actions
- Tap list item → Spool Detail View
- Overflow → Sort options (Name A-Z, Name Z-A, Weight Low→High, Weight High→Low, Recently Used)
- Overflow → Export inventory (CSV)
### Key Components
- Search bar with real-time filtering
- Filter chip set (single-select)
- 3-line list items with progress indicators
- Color swatch leading element
- Status tonal badges
- Extended FAB
### States
| State | Visual |
|-------|--------|
| **Loading** | `md-circular-progress` centered, list skeleton (shimmer) |
| **Empty (no spools)** | Spool icon illustration + "No spools in inventory" + "Add your first spool" text button |
| **Empty (no filter matches)** | "No spools match your filter" + Clear filter chip button |
| **Error** | Error illustration + "Couldn't load inventory" + Retry button |
| **Low Stock item** | Yellow tonal badge "Low" + progress bar < 25% yellow |
| **Critical item** | Red tonal badge "Critical" + progress bar < 10% red + pulsing dot |
| **Depleted item** | Red tonal badge "Depleted" + progress bar 0% + strikethrough title |
---
## 4. UX Rationale
1. **Progress bars beat numbers alone.** A visual progress indicator communicates remaining spool life faster than parsing "210g / 1000g" — critical in a busy workshop where decisions are made in seconds.
2. **Low stock first (default sort).** Operators need to see what's running out before what's plentiful. This prevents the "surprise empty spool" problem mid-print.
3. **Color swatches as leading elements.** Filament identification is primarily visual — operators scan for color before reading text. The swatch leverages pre-attentive processing.
4. **Single-select filters over multi-select.** Workshop operators don't construct complex queries. They want one quick filter tap. Multi-select adds cognitive load for minimal practical benefit.
5. **Smart Intake FAB, not a menu item.** Intake is the most frequent action (new spools arrive regularly). It deserves the highest-affordance control on screen — a FAB is unmissable.
6. **Search collapses by default.** On kiosk, screen space is precious. The search icon expands the bar only when needed, preserving vertical list space.
7. **Empty states with action.** An empty inventory list should immediately offer the path forward — "Add your first spool" links directly to Smart Intake.
---
## 5. Visual Direction
### Typography (MD3 Type Scale)
| Role | Token | Size | Weight | Line Height |
|------|-------|------|--------|-------------|
| App Bar Title | `titleLarge` | 22sp | 400 | 28sp |
| List Item Line 1 | `titleMedium` | 16sp | 500 | 24sp |
| List Item Line 2 | `bodyMedium` | 14sp | 400 | 20sp |
| List Item Line 3 | `labelSmall` | 11sp | 500 | 16sp |
| Filter Chip Text | `labelLarge` | 14sp | 500 | 20sp |
| FAB Label | `labelLarge` | 14sp | 500 | 20sp |
| Empty State Title | `headlineSmall` | 24sp | 400 | 32sp |
| Empty State Body | `bodyMedium` | 14sp | 400 | 20sp |
### Spacing (MD3 8dp grid)
| Element | Spacing |
|---------|---------|
| App Bar internal padding | 16dp horizontal, 12dp vertical |
| Filter chip row padding | 16dp horizontal, 8dp vertical |
| Chip gap | 8dp |
| List item padding | 16dp horizontal, 12dp vertical (top/bottom of 3-line) |
| List item internal gap | 16dp (leading to content), 16dp (content to trailing) |
| FAB margin | 16dp from edges |
| Content area padding | 0dp (list is edge-to-edge with dividers) |
### Color (MD3 Dark Theme — "Industrial Maker")
Based on a **blue-grey** primary seed for the industrial feel, with **teal** as secondary (maker accent).
| Role | Token | Value (Dark) | Usage |
|------|-------|-------------|-------|
| Background | `surface` | `#1C1B1F` | Screen background |
| On Background | `onSurface` | `#E6E1E5` | Primary text |
| Surface Variant | `surfaceContainer` | `#211F26` | App bar, list items |
| On Surface Variant | `onSurfaceVariant` | `#CAC4D0` | Secondary text, chip outlines |
| Primary | `primary` | `#A8CEDA` | FAB container, active states |
| On Primary | `onPrimary` | `#00303E` | FAB label text |
| Primary Container | `primaryContainer` | `#004D63` | FAB container (tonal), active chip fill |
| On Primary Container | `onPrimaryContainer` | `#A8CEDA` | Active chip text |
| Secondary | `secondary` | `#B1CCC7` | Navigation rail active icon |
| Tertiary | `tertiary` | `#EFB8C8` | Accent (not used here) |
| Error | `error` | `#F2B8B5` | Depleted badge, critical states |
| Error Container | `errorContainer` | `#8C1D18` | Critical badge background |
| On Error Container | `onErrorContainer` | `#F2B8B5` | Critical badge text |
| **Custom: Warning** | — | `#FFD580` | Low stock indicator |
| **Custom: Warning Container** | — | `#5D4200` | Low stock badge background |
| **Custom: Success** | — | `#8BD0A0` | Available badge text |
| **Custom: Success Container** | — | `#00522E` | Available badge background |
| Outline | `outline` | `#938F99` | Dividers, chip outlines |
| Outline Variant | `outlineVariant` | `#49454F` | Subtle borders |
### Color Swatches
Spool color swatches use the actual filament color as a circular filled element (40dp diameter) with a 2dp `outlineVariant` border for visibility on dark backgrounds. For transparent/clear filaments, use a diagonal hatch pattern fill.
---
## 6. Responsiveness
### Kiosk (800×480, Raspberry Pi 5 Touchscreen)
```
┌──────┬──────────────────────────────────────────────┐
│ NAV │ Filament Inventory [🔍] [⋮] │
│ RAIL │──────────────────────────────────────────────│
│ │ [All] [Available] [In Use] [Low] [Depleted] │
│ 📦 │──────────────────────────────────────────────│
│ 🖨️ │ ● PLA Basic - Matte Black │
│ 📋 │ Bambu Lab • Slot A3 • 842g │
│ ⚙️ │ ▓▓▓▓▓▓▓▓▓▓░░ 67% [Low] │
│ │──────────────────────────────────────────────│
│ │ ● PETG Basic - Transparent │
│ │ Polymaker • Shelf B2 • 210g │
│ │ ▓▓▓░░░░░░░░░ 21% [Critical] │
│ │──────────────────────────────────────────────│
│ │ ● ABS Basic - White │
│ │ eSUN • Slot B1 • 950g │
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓ 95% [Available] │
│ │ [+ Smart │
│ │ Intake] ↗ │
└──────┴──────────────────────────────────────────────┘
```
- **Navigation Rail:** 80dp wide, pinned left
- **List area:** 720dp × 420dp usable
- **Visible items:** ~4-5 spools without scrolling
- **Touch targets:** All interactive elements ≥ 48dp (exceeds 44dp minimum for workshop glove use)
- **FAB:** Bottom-right, 16dp margin from rail and screen edge
### Mobile PWA (375×812, e.g., iPhone 14)
```
┌──────────────────────────────────┐
│ Filament Inventory [🔍] [⋮] │
│──────────────────────────────────│
│ [All] [Avail] [In Use] [Low] [×]│
│──────────────────────────────────│
│ ● PLA Basic - Matte Black │
│ Bambu Lab • Slot A3 • 842g │
│ ▓▓▓▓▓▓▓▓▓▓░░ 67% [Low] │
│──────────────────────────────────│
│ ● PETG Basic - Transparent │
│ Polymaker • Shelf B2 • 210g │
│ ▓▓▓░░░░░░░░░ 21% [Critical] │
│──────────────────────────────────│
│ ● ABS Basic - White │
│ eSUN • Slot B1 • 950g │
│ ▓▓▓▓▓▓▓▓▓▓▓▓ 95% [Avail] │
│──────────────────────────────────│
│ │
│ [+ Smart Intake] ↗ │
│──────────────────────────────────│
│ 📦 🖨️ 📋 ⚙️ │
│ Inventory Printers Jobs Settings │
└──────────────────────────────────┘
```
- **Bottom Navigation:** 80dp, pinned bottom
- **List area:** 375dp × ~600dp usable
- **Visible items:** ~5-6 spools without scrolling
- **FAB:** Floating above bottom nav, right-aligned
- **Filter chips:** Horizontally scrollable when more than screen width
### Key Adaptations
| Property | Kiosk (800×480) | Mobile (375×812) |
|----------|-----------------|-------------------|
| Navigation | Rail (left) | Bottom bar |
| Search | Collapsed icon by default | Same, but swipe-down gesture also expands |
| List item density | Comfortable (3-line, 72dp) | Same density |
| FAB position | Bottom-right, above list | Bottom-right, above nav bar |
| Filter chips | All visible at once | Horizontally scrollable |
| Sort access | Overflow menu | Overflow menu |
---
## 7. Developer Handoff Notes
### Angular Material Components
| UI Element | Angular Material Component | Notes |
|-----------|--------------------------|-------|
| Top App Bar | `<mat-toolbar>` | Use `@angular/material/toolbar`. Medium emphasis variant. |
| Search | Custom wrapper + `<input matInput>` | No native mat-search-bar in Angular Material; implement custom expandable search with `@ViewChild` animation. |
| Filter Chips | `<mat-chip-listbox>` | Use `mat-chip-option` with `selected` binding. Single-select: deselect others on select. |
| List Items | `<mat-list>` + `<mat-list-item>` | 3-line variant with `matListItemTitle`, `matListItemLine`, `matListItemMeta`. |
| Progress Bar | `<mat-progress-bar>` | Use `mode="determinate"` with `[value]` binding. Custom color classes for warning/error thresholds. |
| Badge | `<mat-badge>` | Overlay on list items. Use `matBadgeColor` for status colors. |
| Extended FAB | `<button mat-fab extended>` | Use `@angular/material/button`. `extended` attribute for label. |
| Nav Rail | `<mat-sidenav>` styled as rail | No native nav-rail in Angular Material yet; implement as styled sidenav with icon buttons. |
| Bottom Nav | `<mat-bottom-nav>` or custom | Use `<nav mat-tab-nav-bar>` positioned at bottom as a workaround. |
| Empty State | Custom component | Illustration (SVG) + `<button mat-button>`. |
| Loading | `<mat-spinner>` | Use `mode="indeterminate"` centered in list area. |
### Interaction Notes
1. **Search expansion:** Animate height from 0→56dp with `@angular/animations` (`expandCollapse` trigger, 200ms ease-out).
2. **Filter chip selection:** Single-select logic in component — on chip click, set `selectedChip = chip.value`, deselect all others.
3. **List item tap → navigation:** Use `routerLink="/spools/:id"` on each `mat-list-item`.
4. **FAB → Smart Intake:** Navigates to `/intake/scan`.
5. **Progress bar color:** Dynamically set based on percentage:
- ≥ 25%: `primary` (teal-blue)
- 10-24%: Custom `warn-yellow` class
- < 10%: `warn` (red)
6. **Skeleton loading:** Use `@angular/material` skeleton pattern or custom shimmer CSS animation on list items during initial load.
7. **Pull-to-refresh (mobile):** Implement with Angular CDK `@cdk/drag-drop` or a custom gesture handler to refresh inventory data.
8. **Infinite scroll / pagination:** Load 20 spools initially, load more on scroll-to-bottom.
### Accessibility
| Requirement | Implementation |
|-------------|---------------|
| Screen reader | Each list item: `aria-label="PLA Basic Matte Black, Bambu Lab, Slot A3, 842 grams remaining, 67 percent, Low stock"` |
| Color swatch | `aria-label="Color: Matte Black"` + `role="img"` |
| Progress bar | `aria-valuenow`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-label="Remaining filament: 67 percent"` |
| Filter chips | `role="listbox"`, each chip `role="option"` + `aria-selected` |
| Search | `role="search"`, `aria-label="Search filament inventory"` |
| FAB | `aria-label="Smart Intake: scan new spool"` |
| Keyboard nav | Tab through list items, Enter to select. Escape to dismiss search. |
| Focus management | On search expand, auto-focus input. On search collapse, return focus to search icon. |
| Motion reduction | Respect `prefers-reduced-motion` — disable shimmer, use opacity fade for loading. |
| Contrast | All text meets WCAG AA (4.5:1) against dark surface. Verified: `onSurface` (#E6E1E5) on `surface` (#1C1B1F) = 11.2:1 ✓ |
### SignalR Integration
- Subscribe to `SpoolUpdated` hub event on screen init.
- On event: update the corresponding list item in-place (no full refresh).
- On `SpoolAdded`: insert at sorted position with highlight animation (300ms `primaryContainer` background flash).
- On `SpoolDepleted`: move to Depleted filter group, show toast notification.
### Performance Notes
- Use `TrackByFunction` on `*ngFor` to prevent full list re-render on updates.
- Virtual scrolling via `<cdk-virtual-scroll-viewport>` if inventory exceeds 100 spools.
- Debounce search input at 300ms.