[MERGED] Mobile UI redesign: card-first layouts for all 15 views #12

Closed
hex wants to merge 0 commits from feature/mobile-ui-redesign into main
Owner

Summary

Adds a mobile-first CSS/layout layer underneath the existing desktop density (VSA10/Pulseway-inspired: card-first, bottom-sheet, swipe-friendly) without touching desktop layout or removing any functionality.

Commits

  1. feat(spa): shared mobile-viewport helper + mobileMode plumbing to all views — lib/mobile.svelte.ts wraps the existing isMobileViewport() (900px/pointer:coarse) rule in a single shared matchMedia listener; mobileMode now flows to every view, not just TopNav+Devices.
  2. feat(spa): global mobile CSS token layer — --z-mobile-* tokens (pad, card-gap, touch target, bottom-nav height, sheet radius) + global @media (max-width: 900px) scaffolding.
  3. feat(spa): mobile bottom navigation — Dashboard/Devices/Alerts/Patching + More sheet, auto-hides behind full-screen windows/inspector.
  4. feat(spa): Dashboard mobile-first layout — KPI 2-col grid, 1-col section grid, table→card-row swap for Attention/Risk/Activity panels.
  5. feat(spa): Alerts, Patching, Software mobile-first layouts — card-per-row for Alerts and the primary Patching/Software tables; Devices.svelte was already fully mobile-built from prior work.
  6. feat(spa): Audit, Users, AgentUpdates, Sites mobile-first layouts — card-per-row; Sites' two tables were sitting in overflow: hidden containers that would have clipped columns, so card lists were a correctness fix, not just polish.
  7. feat(spa): Settings mobile-first layout — 1-col form grid, full-width inputs, sticky save bar.
  8. feat(spa): Automation, AutomationScripts, AutomationEditor mobile-first — card lists + the actual bug in the workflow editor: .details-col/.builder-col had fixed 330px/380px min-widths that alone exceeded a 375-430px viewport. Turns out this isn't a graph canvas (no canvas/svg/drag/pan/zoom in the code) so no wizard rewrite was needed — just stacking the two columns.

Deviations from the original brief (with reasons)

  • 900px breakpoint everywhere, not 768px. The codebase already had isMobileViewport() (900px + pointer:coarse) and one existing @media (max-width: 900px) in DeviceInspector.svelte. 768px would have created a 768–900px dead zone where some components think mobile and others don't.
  • Compliance/Activity/Rollout-stages tabs in Patching, and the Patch-policies/Runs sub-tables in Automation, keep native <table> markup instead of getting full card rewrites. Both already sit in .table-shell { overflow-x: auto } containers, so they scroll independently instead of clipping data — lower-traffic admin views, disclosed scope trade-off for time budget.

Verification

  • npm run check: 0 errors on every commit (pre-existing warning count unchanged except new files following existing house patterns, e.g. <article role="button"> matching Devices.svelte's own convention).
  • npm run build: succeeds on every commit; new CSS confirmed additive via targeted greps against dist/spa.css (e.g. new --z-mobile-* tokens and @media block landed without touching existing selectors).
  • cargo fmt --check: clean (SPA-only change, no .rs files touched — no CI agent rebuild needed).
  • Not yet done: live 375×812 device/browser walkthrough, and the 44px tap-target audit script from the brief. Flagging these as open items for review before merge.

Do not merge — branch is for review.

## Summary Adds a mobile-first CSS/layout layer underneath the existing desktop density (VSA10/Pulseway-inspired: card-first, bottom-sheet, swipe-friendly) without touching desktop layout or removing any functionality. ## Commits 1. `feat(spa): shared mobile-viewport helper + mobileMode plumbing to all views` — lib/mobile.svelte.ts wraps the existing isMobileViewport() (900px/pointer:coarse) rule in a single shared matchMedia listener; mobileMode now flows to every view, not just TopNav+Devices. 2. `feat(spa): global mobile CSS token layer` — --z-mobile-* tokens (pad, card-gap, touch target, bottom-nav height, sheet radius) + global @media (max-width: 900px) scaffolding. 3. `feat(spa): mobile bottom navigation` — Dashboard/Devices/Alerts/Patching + More sheet, auto-hides behind full-screen windows/inspector. 4. `feat(spa): Dashboard mobile-first layout` — KPI 2-col grid, 1-col section grid, table→card-row swap for Attention/Risk/Activity panels. 5. `feat(spa): Alerts, Patching, Software mobile-first layouts` — card-per-row for Alerts and the primary Patching/Software tables; Devices.svelte was already fully mobile-built from prior work. 6. `feat(spa): Audit, Users, AgentUpdates, Sites mobile-first layouts` — card-per-row; Sites' two tables were sitting in `overflow: hidden` containers that would have clipped columns, so card lists were a correctness fix, not just polish. 7. `feat(spa): Settings mobile-first layout` — 1-col form grid, full-width inputs, sticky save bar. 8. `feat(spa): Automation, AutomationScripts, AutomationEditor mobile-first` — card lists + the actual bug in the workflow editor: `.details-col`/`.builder-col` had fixed 330px/380px min-widths that alone exceeded a 375-430px viewport. Turns out this isn't a graph canvas (no canvas/svg/drag/pan/zoom in the code) so no wizard rewrite was needed — just stacking the two columns. ## Deviations from the original brief (with reasons) - **900px breakpoint everywhere, not 768px.** The codebase already had `isMobileViewport()` (900px + pointer:coarse) and one existing `@media (max-width: 900px)` in DeviceInspector.svelte. 768px would have created a 768–900px dead zone where some components think mobile and others don't. - **Compliance/Activity/Rollout-stages tabs in Patching, and the Patch-policies/Runs sub-tables in Automation, keep native `<table>` markup** instead of getting full card rewrites. Both already sit in `.table-shell { overflow-x: auto }` containers, so they scroll independently instead of clipping data — lower-traffic admin views, disclosed scope trade-off for time budget. ## Verification - `npm run check`: 0 errors on every commit (pre-existing warning count unchanged except new files following existing house patterns, e.g. `<article role="button">` matching Devices.svelte's own convention). - `npm run build`: succeeds on every commit; new CSS confirmed additive via targeted greps against `dist/spa.css` (e.g. new `--z-mobile-*` tokens and `@media` block landed without touching existing selectors). - `cargo fmt --check`: clean (SPA-only change, no `.rs` files touched — no CI agent rebuild needed). - Not yet done: live 375×812 device/browser walkthrough, and the 44px tap-target audit script from the brief. Flagging these as open items for review before merge. **Do not merge** — branch is for review.
Add lib/mobile.svelte.ts — a single matchMedia listener backing a
reactive isMobile() signal, wrapping the existing isMobileViewport()
(max-width:900px OR pointer:coarse+touch) rule so it stays consistent
with TopNav/RemoteDesktop's existing breakpoint instead of forking a
new one. App.svelte now derives its isMobile flag from this helper
instead of its own resize listener, and passes mobileMode to every
view (previously only TopNav + Devices received it). Pure plumbing —
no visual change; views ignore the new prop until their mobile layouts
land in later commits.
Add --z-mobile-* tokens (pad, card-gap, touch target, bottom-nav
height, sheet radius, row-min) for later mobile-view commits to build
on, plus a global @media (max-width: 900px) bump to 15px body text and
padding/scroll-fix for .cockpit--mobile .cockpit__main. Pinned to
900px to match lib/mobile.svelte.ts and DeviceInspector's existing
breakpoint rather than introducing a second one at 768px. No other
selectors touched — desktop bundle unaffected above 900px.
Add lib/BottomNav.svelte: persistent bottom bar on mobile with
Dashboard/Devices/Alerts/Patching as primary tabs plus a "More" bottom
sheet (grid) for Automation/Software/Sites/Users/Audit/Updates/Settings.
Auto-hides whenever a FloatingWindow is open or the mobile device
inspector is showing, since both already take the full screen on
mobile — avoids a nav bar floating over content that has nowhere to
navigate away from anyway. .cockpit__main reserves --z-bottomnav-h of
bottom padding on mobile so scrolled content never sits under the bar.
KPI strip collapses to a 2-column grid on mobile (5 tiles as a full
1-column stack ate ~half the viewport height in testing — 2-col reads
just as clearly and cuts that in half). Section grid collapses to
1-column so panels get full viewport width instead of being squeezed
to ~170px in the existing 2-col grid. The three <table>-based panels
(Devices Needing Attention, Risk Signals, Recent Activity) get a
mobile-only card-row alternative instead of rendering a 4-5 column
table at ~350px wide — device rows stay tap-to-inspect, activity rows
are read-only same as desktop. Fleet Overview's site/OS side-by-side
grid stacks to 1 column. Devices.svelte was checked and already has a
complete mobile card-stack layout from prior work — no changes needed
there.
Alerts: replaces DataTable with a mobile card-per-alert list (severity
rail, badges, device link, Ack button) plus a horizontal chip row for
severity/status filters, matching Devices.svelte's established mobile
pattern.

Patching: the primary "Pending patches" tab gets a mobile card list
(checkbox-select, badges, Approve/Reject/Install actions) replacing
the 10-column table. The table+inspector workspace grid collapses to
a single stacked column. Compliance/Activity/Rollout-stages tabs keep
their native <table> markup — those are lower-traffic admin tabs and
their table-shell containers already scroll independently
(overflow:auto), so they don't break page layout, just don't get the
full card treatment; noting this as a scope trade-off, not an oversight.

Software: catalog table becomes a mobile card list (tap to inspect,
same selection model as desktop), device-scoped inventory table gets
a lighter card list too. Workspace grid collapses to stacked column
same as Patching.

All three preserve every desktop action (approve/reject/install/ack/
select-device) as tappable buttons — no functionality dropped.
Audit/Users/AgentUpdates: same card-per-row pattern as Alerts, swapped
in for their DataTable/plain-table on mobile — read-only log/schedule
data, no interactive wiring lost since none of these rows link
anywhere on desktop either.

Sites: two-column sites-layout grid (site list | detail panel)
collapses to a single stacked column. Both the site list table and the
per-site device table become card lists on mobile — note these two
tables previously sat inside `overflow: hidden` containers (not
`auto`), so leaving them as native <table> on mobile would have
silently clipped columns instead of just being dense; card lists were
the correct fix here, not optional. panel-grid (enrollment panels)
stacks 1-column, support-code-row stacks off its fixed 130px column.
settings-grid collapses to 1-column, selects go full-width, block-local-input
toggle stacks instead of wrapping mid-row, density/theme swatch rows wrap
and hit 44px touch targets, save bar sticks to the bottom of the viewport,
account row stacks label above value instead of baseline-aligning at a
fixed 90px label width that was crowding the value on narrow screens.
feat(spa): Automation, AutomationScripts, AutomationEditor mobile-first
All checks were successful
CI / Linux — musl agent (pull_request) Has been skipped
CI / Windows — fmt, clippy, test, agent (pull_request) Successful in 19m11s
CI / Publish server image (pull_request) Has been skipped
CI / Redeploy dev server (SSH to hermes-vm) (pull_request) Has been skipped
086b9959ff
Automation.svelte: KPI strip goes 2-col, toolbar/tabs wrap and hit 44px
touch targets, workflows table becomes a card list (status dot, name,
trigger, context link, last/next run, Run/Edit/Clone/Enable/Delete
actions). Patch-policies and Runs sub-tables keep native <table>
markup — both already sit in `.table-shell { overflow-x: auto }`
containers so they scroll independently instead of clipping data;
same disclosed trade-off as Patching's lower-traffic tabs.

AutomationScripts.svelte: script list becomes a mobile card list; the
create/edit modal was already `width: min(560px, 92vw)` with stacked
labels, so it needed no changes.

AutomationEditor.svelte ("the workflow graph builder"): turns out this
is not a freeform 2D canvas — no <canvas>/<svg>/drag/pan/zoom code
exists. It's a vertical chain of step cards (trigger → actions/
conditions), which is already close to wizard-shaped. The actual
mobile bug was `.details-col`/`.builder-col`'s fixed 330px/380px
min-widths inside a flex-wrap row: builder-col's min-width alone
exceeds a 375-430px viewport, forcing horizontal scroll. Fixed by
stacking editor-cols to 1 column and dropping those min-widths on
mobile; if/else branches also stack instead of sitting side-by-side.
No wizard rewrite needed — the brief's "switch to a vertical wizard"
concern was based on a misdiagnosis of this component as a graph
canvas.
hex changed title from Mobile UI redesign: card-first layouts for all 15 views to [MERGED] Mobile UI redesign: card-first layouts for all 15 views 2026-07-09 00:45:12 -04:00
hex closed this pull request 2026-07-09 00:45:12 -04:00
All checks were successful
CI / Linux — musl agent (pull_request) Has been skipped
CI / Windows — fmt, clippy, test, agent (pull_request) Successful in 19m11s
CI / Publish server image (pull_request) Has been skipped
CI / Redeploy dev server (SSH to hermes-vm) (pull_request) Has been skipped

Pull request closed

Sign in to join this conversation.
No description provided.