--- phase: 01-foundation plan: 04 subsystem: frontend tags: [spa, javascript, css, device-crud, gap-closure, ui] # Dependency graph requires: - phase: 01-03 provides: "Docker deploy to lightsync.groll.cloud with backend API including POST/DELETE /api/devices" provides: - "Add-device form in DEVICES panel (name, strip_type select, led_count, ip, port, submit)" - "POST /api/devices form submit handler with form reset on success" - "DELETE /api/devices/{id} remove button on each device row" - "apiPost() and apiDelete() helper functions in app.js" - "removeDevice() function exposed globally via window.removeDevice for onclick" - "CSS --accent: #00ffff as canonical variable; --text-accent and --border-bright as aliases" - "Panel IDs: devices-panel, animations-panel, timeline-panel, transport-panel" affects: [] # Tech tracking tech-stack: added: [] patterns: - "module-scoped async helpers (apiPost/apiDelete) for fetch wrappers with error propagation" - "window export pattern for onclick-accessible functions in ES modules (window.removeDevice)" - "CSS single-source-of-truth variable pattern: --accent as canonical, aliases via var()" key-files: created: - .planning/phases/01-foundation/01-04-SUMMARY.md modified: - lightsync/frontend/index.html - lightsync/frontend/app.js - lightsync/frontend/style.css key-decisions: - "Panel IDs added in Task 1 (alongside form), not deferred to Task 2 — single HTML touch reduces diff noise" - "window.removeDevice export required because app.js uses type=module which scopes functions away from global onclick" - "--accent added as new root variable; existing --border-bright and --text-accent become aliases — no refactor of usage sites needed" requirements-completed: - DEV-03 - UI-02 # Metrics duration: ~2min completed: 2026-04-05 --- # Phase 01 Plan 04: Device CRUD UI and CSS Variable Fix Summary **Gap-closure plan: added device add/remove form to DEVICES panel and fixed CSS variable naming — closes DEV-03 (device list with UI interaction) and UI-02 (CSS contract alignment)** ## Performance - **Duration:** ~2 min - **Started:** 2026-04-05T20:11:51Z - **Completed:** 2026-04-05T20:13:30Z - **Tasks:** 2 (both auto) - **Files modified:** 3 (index.html, app.js, style.css) ## Accomplishments ### Task 1: Device CRUD UI - Added `
` to the DEVICES panel in `index.html`, with inputs for name (text), strip_type (select: sk6812/ws2801/generic), led_count (number), ip (text), port (number, default 21324), and a submit button "+ ADD DEVICE" - Added `apiPost(path, data)` and `apiDelete(path)` async fetch helpers to `app.js` (positioned after WS_URL const, before LightSyncClient) - Updated `loadDevices()` device row template to include a `.device-remove` button with `onclick="removeDevice(d.id)"` alongside a `.device-row-info` wrapper for the name/metadata - Added `removeDevice(id)` function that calls `apiDelete(/api/devices/{id})` then refreshes the list; exported as `window.removeDevice` for ES module compatibility with inline onclick handlers - Added form submit handler that calls `apiPost("/api/devices", data)`, resets form (restoring port default to 21324), then refreshes the device list - Added panel IDs to all four panels: `id="devices-panel"`, `id="animations-panel"`, `id="timeline-panel"`, `id="transport-panel"` ### Task 2: CSS Variable Naming Fix - Added `--accent: #00ffff` as canonical variable in `:root` - Changed `--border-bright` and `--text-accent` to be aliases: `var(--accent)` instead of hardcoded `#00ffff` - Added `.device-form` CSS rule: flex-column, 4px gap, border-top separator from device list - Added `.device-remove` rule: borderless button, dim text, hover turns red (`#ff3333`) - Updated `.device-row` to `display: flex; align-items: center; justify-content: space-between` to accommodate remove button alongside info - Added `.device-row-info` flex-column wrapper for name + metadata within each row ## Task Commits 1. **Task 1: Device CRUD UI** — `ccc40c8` (feat) 2. **Task 2: CSS variable fix + device form styles** — `2ff35f9` (feat) ## Files Created/Modified - `lightsync/frontend/index.html` — added form, panel IDs, timeline/transport panel wrappers - `lightsync/frontend/app.js` — added apiPost, apiDelete, removeDevice, form submit handler, updated device row template - `lightsync/frontend/style.css` — added --accent canonical variable, aliases, device form and remove button styles ## Decisions Made - **Panel IDs added in Task 1**: The HTML file was already being modified for the form, so panel IDs were added in the same edit pass to minimize diff noise. Task 2 only touched CSS. - **window.removeDevice export**: ES modules scope all declarations — `onclick="removeDevice(...)"` in dynamically rendered HTML requires the function to be on the global `window` object. - **No refactor of --text-accent usage sites**: `--border-bright` and `--text-accent` are now aliases of `--accent`. No existing CSS rules using these variables needed to change — the alias pattern lets the semantics remain meaningful (text-accent vs border-bright) while sharing a single source color value. ## Deviations from Plan None — plan executed exactly as written. Panel IDs were added in Task 1 edit rather than Task 2 (minor sequencing optimization, not a behavioral change). ## Requirements Closed | Requirement | Status | Evidence | |-------------|--------|----------| | DEV-03 | CLOSED | Add-device form in DEVICES panel; POST/DELETE wired; device rows have remove buttons | | UI-02 | CLOSED | `--accent: #00ffff` canonical variable present; `--text-accent` and `--border-bright` are aliases; all four panel IDs present | ## Verification Results 1. `grep "add-device-form" lightsync/frontend/index.html` — MATCH 2. `grep "apiPost\|apiDelete\|removeDevice" lightsync/frontend/app.js` — 4 matches (function defs + window export + apiPost call in form handler) 3. `grep "\-\-accent.*#00ffff" lightsync/frontend/style.css` — MATCH 4. `grep "devices-panel\|animations-panel\|timeline-panel\|transport-panel" lightsync/frontend/index.html` — 4 matches ## Known Stubs None — all gap-closure work is fully wired. The form submits to a live API endpoint. Device removal calls a live DELETE endpoint. ## Self-Check Files modified: - lightsync/frontend/index.html — FOUND - lightsync/frontend/app.js — FOUND - lightsync/frontend/style.css — FOUND Commits: - ccc40c8 — Task 1 (feat(01-04)) - 2ff35f9 — Task 2 (feat(01-04)) ## Self-Check: PASSED --- *Phase: 01-foundation* *Completed: 2026-04-05*