Skip to content

v1.8.0 — Mode + palette themes, accessibility, tablet layout

Choose a tag to compare

@samuelloranger samuelloranger released this 28 Jul 11:03
· 11 commits to main since this release

🎨 Theme mode + palette, split apart

The theme picker was one flat list of 23 entries. It's now a Light / Dark / System toggle plus an 11-item palette dropdown, in both the header pill and the Customize dialog.

  • System mode composes with any palette. Previously "System" meant Amber and nothing else — now System + Nord, System + Forest, and every other pairing works, resolving before first paint so there's still no flash.
  • Decorative motion (the idle logo float, the breathing state messages) is now opt-in and off by default, under Customize → Decorative motion. Functional motion — the reconnecting pulse, live-activity dots — is untouched.

♿ Accessibility

A full pass against WCAG 2.2 AA, verified in-browser across all 22 themes.

  • Focus is visible again. The integration form set outline: none on every input with no replacement, so keyboard users lost their place mid-task. One ring now covers the app, coloured from the active theme's ink so it clears 3:1 everywhere.
  • Live state is announced. Labby streams everything over SSE and previously said none of it out loud. Stream connection and monitor counts are live regions; all 15 widgets announce their error state.
  • Status isn't colour-only. Up/warning/down was a 9px dot and nothing else; it now carries text for screen readers. Download and playback bars expose real progress values.
  • Contrast holds on every theme. --ok, --warn, --down and --idle were declared once and never re-tuned, so the eleven light palettes rendered status text between 1.71:1 and 2.99:1. All 176 token/theme pairs now clear AA, with 4.75:1 as the floor. A test parses app.css and does the WCAG maths, so it can't silently regress.
  • Native <dialog> semantics for modals: real focus containment, Escape to close, focus returned to whatever opened it.
  • The dashboard has an <h1>.

📱 Responsive

  • A tablet tier. The board jumped from three columns straight to one at 1080px, so iPad portrait and half-screen windows got a single stretched column. The ladder is now 1 / 2 / 3 / 4 columns.
  • Phones no longer scroll sideways. Compact density forced two columns into a 342px card and each row burst its track, making the page 8px wider than the viewport.
  • Tap targets measured on a real 390px viewport: the buttons already passed, but the service-name links were 19px tall and the "View all" links 16px. Both now clear the 24px minimum.

🔒 Security

  • GET/POST/PUT /api/integrations no longer return stored secrets to the browser. Blank secret fields on update preserve the stored value instead of wiping it.
  • POST /api/backup writes atomically to config/backups/ and returns only the path — never the backup body, which contains credentials in plaintext.

🐛 Fixes

  • Custom CSS cancel now discards the draft. Preview was mutating the saved config on every keystroke, so Cancel had nothing left to restore.
  • Header health chips were monitor-only while claiming to cover everything. Relabeled to "Monitored sites", and the row hides when no monitor is configured instead of showing a misleading 0/0/0.
  • Docker widget counted exited containers as "Running" when configured with show: all.
  • Reorder buttons on Manage Services are reachable by keyboard on desktop again — they were hidden in favour of mouse-only drag.

⚡ Under the hood

  • Response compression (hono/compress, no new dependency). JavaScript goes out at 61KB instead of 273KB, CSS at 12KB instead of 67KB. SSE is correctly excluded.
  • Measured performance on a throttled mid-range phone: LCP 2.0s, CLS 0. Three proposed optimizations — transform: scaleX for progress bars, content-visibility on cards, preloading the webfont — were each benchmarked and rejected, because every one measured as noise or slower. The reasoning is recorded in the code so it doesn't get "fixed" later.
  • prefers-reduced-motion was killing every transition, including the colour changes that acknowledge a click. It now removes movement and keeps feedback.
  • 218 tests, up from 207.

Image

ghcr.io/samuelloranger/labby:1.8.0 (also tagged 1.8, 1, latest) — multi-arch linux/amd64 + arm64.

Full changelog: v1.7.1...v1.8.0