Replaces the 'Open questions' section with 'Resolved decisions' and propagates the four decisions into the relevant phases: - Hard cut: no config.ui.layout flag. Phase 6 now includes the removal of .nav-header, side-menu.css and the #tab1..#tab4 block with a git grep verification step. - Macros: Control row binds to config.macros.slice(0, 8); Settings -> Macros owns the master list and reordering. - Pin to Control: deferred, status strip stays at State / V&F / Spindle / Job for this iteration. - Feed/spindle override: bottom drawer triggered by the Spindle KPI tile, reusing override_feed / override_speed. Goals (s.1) and Phase 6 testing checklist updated to match.
14 KiB
UX Redesign — Implementation Plan
Reference mock: docs/mocks/v09_full_ux.html
Target hardware: 10.8" portable monitor, 1920×1080, capacitive touch, Chrome fullscreen.
1. Goals
The redesign keeps every existing feature but reorganizes the page into a single-screen control surface for finger-touch use:
- A slim 96 px header replaces the 140 px nav-header. Only logo + ONEFINITY wordmark + tab bar + system pill + READY badge + octagonal STOP.
- 4 top-level sections accessed via underline-ribbon tabs in the header:
- Control — jog pad, DRO table, status strip, macro row.
- Program — Auto run controls, file actions, G-code listing, 3D viewer.
- Console — MDI, Messages, Indicators (sub-tabs).
- Settings — paged settings (replaces the Pure left rail).
- Touch targets ≥ 64 px (jog tiles 72 px, axis action icons 72 px, macro buttons 84 px).
- All action chip-soup (WiFi/Camera/Rotary/IP/Version) collapses into one "All systems · view" pill that opens a popover. Burger menu removed (Settings tab supersedes it).
- V09 jog/macro palette: flat soft slate (#3f4b63), no drop shadow; yellow (#fde047) accent for active states (step seg, tab underline, macro number badge).
- Spindle override / feed override sliders live in a bottom-edge drawer triggered by tapping the Spindle KPI tile (no permanent screen real estate).
- Hard cut: no
config.ui.layoutflag; the new shell replaces the old in a single release.
2. Scope of code change
The build is Pug + Stylus + Browserify Vue (Vue 1.x). index.pug defines the chrome; src/pug/templates/*.pug defines each view; src/js/*.js mirrors them as Vue components routed by currentView from the URL hash.
Files we will touch:
src/pug/index.pug— replace#layout / #menu / #main / .nav-headerwith the new header + tab bar + body. Drop the burger and the side-menu include.src/pug/templates/control-view.pug— restructure into the new Control panel (jog grid + DRO table + status strip + macro row). MDI/Messages/Indicators move out.- New
src/pug/templates/program-view.pug— Auto sub-panel content (action bar, file bar, gcode-viewer, path-viewer). - New
src/pug/templates/console-view.pug— MDI / Messages / Indicators sub-tabs hosting existingconsole.pugandindicators.pugpartials. src/js/app.js— extendparse_hashso#program,#console,#settingsresolve; expose tab state for the header to highlight.src/js/control-view.js— keep jog/DRO logic, drop the Auto/MDI/Messages/Indicators internaltabstate and template hooks.- New
src/js/program-view.js,src/js/console-view.js— extracted Vue components. src/stylus/style.styl— add.app-shell,.head,.tabs-host,.ktab, panel styles, V09 jog tokens. Keep legacy classes alive until templates fully migrated.src/static/css/side-menu.css— stop including inindex.pug.- Settings: keep
settings-view.pug,admin-general-view.pug,admin-network-view.pug,motor-view.pug,tool-view.pug,io-view.pug, etc., and surface them through a left-rail navigator inside the Settings panel rather than the sidebar. - Settings → Macros owns the full macro list (1…N). Control's macro row is a slice of the first 8; reordering happens in Settings.
3. Routing model
We keep the existing URL hash routing because everything in src/js/app.js#parse_hash and the deep-linked menu items (#motor:0, #admin-network, etc.) depend on it.
| URL hash | Top tab | Notes |
|---|---|---|
#control |
Control | Default |
#program / #program:auto |
Program | Auto sub-view (only sub-view for now) |
#console / #console:mdi |
Console | MDI default, also :messages and :indicators |
#settings |
Settings | Settings home (Display & Units) |
#admin-general, #admin-network, #motor:N, #tool, #io, #help, #cheat-sheet |
Settings | Existing routes remain, surfaced in the Settings left rail |
The header tab bar maps URL prefix → active tab. A tiny helper topTabFromHash(hash) lives in app.js and is reused by the header template.
4. Step-by-step
Phase 1 — Mock parity (1–2 days)
- Add
docs/mocks/v09_full_ux.html(done) so anyone can preview the target. - Move the V09 palette into Stylus tokens at the top of
style.styl:$jog-bg = #3f4b63 $jog-hover = #4a5777 $jog-dir = #5b6885 $jog-ghost = #8c97ad $accent = #fde047 $accent-ink = #0f172a - Build the header in
index.pug:.app-shell header.head .brand-blk .brand-logo .brand-name ONEFINITY nav.tabs-host(role="tablist") a.ktab(:class="{active: topTab === 'control'}", href="#control") .fa.fa-gamepad | Control a.ktab(:class="{active: topTab === 'program'}", href="#program") … a.ktab(:class="{active: topTab === 'console'}", href="#console") … a.ktab(:class="{active: topTab === 'settings'}", href="#settings") … button.sys-btn(@click="toggle_sys_popover") … span.state-badge(:class="state_class") estop(@click="estop") - Style the header tabs as underline ribbon (V02): transparent fills, slate-gray text, dark text + 5 px yellow underline on active. CSS already proven in the mock.
- Move the rotary toggle and pi-temp warning into the system pill popover.
Phase 2 — Control panel (2 days)
- Rewrite the outer markup of
control-view.pugto a CSS grid:Drop the.control-grid → 720px jog-card | 1fr right-col(dro-card + status-strip)<table>-based outer layout (axes table stays — it's a real data table). - Replace the legacy
<button>elements in the jog table with.jbtnmarkup that pulls colors from$jog-*tokens. Keep the@click="jog_fn(...)"bindings unchanged. - Build the new
.step-segwith the existingjog_incrmodel. The four buttons stay wired tojog_incr = 'fine' | 'small' | 'medium' | 'large'. - Build
.dro-cardfrom the existingtable.axesmarkup. Each row gets the new 7-column grid; axis cells just need.dro-axis,.dro-pos,.dro-secclasses. - Move the four KPI tiles (
State / Velocity-Feed / Spindle / Job) into.status-strip. Existingstate.v,state.feed,state.s,state.linebindings are unchanged. - Move
.macros-divinto a.macro-row8-column grid. The row binds toconfig.macros.slice(0, 8); macros 9…N are editable and runnable only from Settings → Macros (no drawer in Control). Reordering in Settings changes which macros appear in the visible 8. - Drop the legacy
.tabs / #tab1 …block fromcontrol-view.pugentirely.
Phase 3 — Program panel (1.5 days)
- New file
src/pug/templates/program-view.pugwith.program-cardand the action / file bars. - Move the Auto bar (RUN, STOP, UPLOAD FOLDER, UPLOAD FILE, DOWNLOAD FILE, DELETE) and the file-select strip (Create Folder, Delete Folder, folder picker, file picker, sort) out of
control-view.puginto here. Use the V09 button styles (.action-btn,.action-btn.run,.action-btn.danger,.file-btn,.file-select). - Embed
path-viewerandgcode-viewerin.program-body { 1fr 600px }. Both Vue components render unchanged. - New
src/js/program-view.jsexporting the same data model the existingAutotab uses (gcode_files,state.selected,start_pause, etc.). The fastest path: move the relevant computed/methods into a mixingcode-program-mixin.jsconsumed by both old and new components during the migration. - Wire
<component :is="currentView + '-view'">inindex.pugto pick upprogram-view.
Phase 4 — Console panel (1 day)
- New
src/pug/templates/console-view.pugwith the inner.ptab-bar(MDI / Messages / Indicators) anddata-subpanels. - The MDI panel reuses the existing
<input v-model="mdi" @keyup.enter="submit_mdi">plus the on-screen keypad (G0/G1/G2/G3/G28/G92/M3/M5 + axis letters + CLEAR/SEND). - The Messages panel pulls from the existing
popupMessagesarray + a newmessages_logstate we will accumulate fromapp.js'serrorandpopupMessageschannels (no protocol change). - The Indicators panel mounts the existing
<indicators :state="state" :template="template">component. - Sub-tab state is local Vue state (
activeSub: 'mdi' | 'messages' | 'indicators') plus URL fragment after:so deep links keep working.
Phase 5 — Settings panel (1 day)
- New
src/pug/templates/settings-view.pugwith a left rail and a content slot. - The left rail is data-driven from a list of existing settings views: General, Network, Motion (settings-view), Spindle (tool-view), Safety (admin-general subset), Camera, Macros (settings-view subset), I/O, Motors, Help, About.
- The content slot uses
<component :is="settingsSub + '-view'">so each existing pug template renders unchanged (admin-general-view.pug,admin-network-view.pug,motor-view.pug,tool-view.pug,io-view.pug,settings-view.pug,help-view.pug,cheat-sheet-view.pug). - Existing routes (
#admin-network,#motor:0, …) resolve to Settings + the matching left-rail item. We lose nothing. - Decommission the side menu in
index.pugand stop includingside-menu.css.
Phase 6 — Polish & rollout (0.5 days)
- Pulse-dot animation for the READY badge (CSS keyframes already in the mock).
- System pill popover content: WiFi state + button, Camera state + retry, Rotary toggle, IP address, firmware version, "Open Settings".
- Disabled states: jog buttons + macro buttons honor
is_readylike before; gray them out instead of hiding. - Decimal-places setting from the existing
display_unitsplumbing — wire to a newprecisionconfig the DRO reads. - Build the Spindle override drawer: clicking the
.stat-cardfor Spindle toggles.override-drawer.openanchored to the bottom edge of the body. The drawer hosts the two existing<input type="range">controls forfeed_overrideandspeed_overrideplusResetbuttons. Bind to the existingoverride_feed/override_speedmethods. - Hard cut cleanup: delete the legacy
.nav-header, side-menu markup, and the inline.tabs / #tab1…#tab4block fromcontrol-view.pug. Removesrc/static/css/side-menu.cssfromindex.pugincludes. Sweepstyle.stylfor orphan rules (.nav-header,.brand,.menu-link,.pure-menu*overrides,.tabs > inputselectors) and delete them in the same commit so we don't ship dead CSS.
5. Migration risks & mitigations
| Risk | Mitigation |
|---|---|
Existing deep links from PDFs / forum posts (#admin-network) break |
Keep the same hashes; only their visual shell changes. parse_hash resolves them. |
| Vue 1.x doesn't support modern slot syntax we used in the mock | The mock is plain HTML for visual review; production code uses the existing Vue 1 patterns. No new Vue features required. |
| Touch monitor with HDMI vs USB-C may report different DPI | The new layout is fluid inside 1920 × 1080 only when fullscreen Chrome. Provide a CSS @media (max-width: 1820px) fallback that scales the macro row to 4 columns and stacks the right column under the jog. |
| Existing customers rely on muscle memory of the side menu | Settings tab opens directly to the same left-rail navigator. First-launch toast: "Side menu moved to Settings." |
path-viewer / gcode-viewer are heavy three.js components |
They live in the Program tab now; we lazy-mount with v-if="currentView === 'program'" so Control stays light. |
MDI input could lose focus when the inner .ptab is switched |
Keep the input mounted, just hide non-active subs with display:none. |
6. Testing checklist
- Chrome on the 10.8" 1920 × 1080 monitor, fullscreen — every panel fits without scrolling at 100 %.
- Chrome at 1366 × 768 — fallback layout works (Control collapses jog above DRO).
- Touch hit-tests: every interactive target ≥ 48 px on its shortest side, primary jog tiles ≥ 72 px.
- Existing flows still work end-to-end: home all axes, run a small program, MDI a
G0 X10, switch to Imperial, upload a folder, delete a file. - Hash routing: hand-type
#motor:1and confirm Settings tab activates with Motor 1 selected. - Spindle override drawer: tap Spindle KPI tile, sliders move feed/speed override,
Resetreturns both to 100 %, tile tap closes drawer. - Macro row shows macros 1–8 only; reordering in Settings → Macros changes which 8 appear on Control.
- Pulse-dot animation respects
prefers-reduced-motion. - Hard-cut cleanup verified:
git grepfinds no references to the old.nav-header,side-menu.css, or the#tab1…#tab4selectors after the rename.
7. Estimated effort
About 6–7 working days for one developer:
- Mock parity & header — 1.5 days
- Control panel (incl. macro slice + DRO grid) — 2 days
- Program panel — 1.5 days
- Console panel — 1 day
- Settings shell — 1 day
- Override drawer, polish, hard-cut cleanup, regression tests — 0.5–1 day
8. Resolved decisions
- Rollout: hard cut. No
config.ui.layoutfeature flag, no parallel legacy shell. The newindex.pugtree replaces the old one in a single release; the old.nav-header, side menu, and embedded.tabsblock are deleted (not gated). One pre-release internal QA pass on real hardware before tagging. - Macros above 8: Settings owns the master list; Control surfaces the first 8 (configurable). The Control macro row reads from
config.macros[0..7]; everything beyond index 7 is editable / runnable only from Settings → Macros. Users can reorder which macros land in the visible 8 there. - "Pin to Control" indicator slot: defer. Not in this redesign. Tracked as a follow-up; current status strip stays fixed at State / Velocity·Feed / Spindle / Job.
- Feed & spindle override: drawer triggered by the Spindle KPI tile. The Spindle card in the status strip becomes tappable. Tap opens a bottom-edge drawer (≈ 220 px tall) containing the two existing range inputs (
feed_override,speed_override) at touch-friendly size withReset to 100 %buttons. Closes by tapping the tile again or the drawer chevron. No protocol change; reuses the existingoverride_feed/override_speedhandlers.