This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/ROADMAP-UI.md
Jeffrey Smith abf71162b1
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
CI/CD / test-frontend (pull_request) Has been cancelled
Feat v0.6.12 extension css isolation
Prefix enforcement prevents extension CSS from leaking into the kernel
or sibling extensions. All 12 in-tree packages migrated to .ext-{slug}-*
naming convention.

- Add data-ext attribute to extension mount container
- Add CSS linter (scripts/lint-package-css.sh) enforcing .ext-{slug} prefix
- Add kernel CSS contract doc (docs/EXTENSION-CSS.md)
- Migrate 12 packages: chat, dashboard, editor, git-board, hello-dashboard,
  icd-test-runner, notes, schedules, sdk-test-runner, tasks,
  team-activity-log, workflow-demo (CSS + JS in lockstep)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 11:54:51 +00:00

155 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Armature — v0.6.x UI Hardening Roadmap
> **Goal**: Fix all viewport scaling, banner integration, and styling inconsistencies
> so Claude Code can run a meaningful automated usability survey against a
> stable, uniform UI.
---
## Problem Inventory
### P1 — Viewport & Scaling (blocks everything)
| # | Issue | Where | Impact |
|---|-------|-------|--------|
| 1 | **Dual layout systems**`base.html` template has its own banner→surface→footer column; `app-shell.js` Preact shell has a separate `sw-shell``sw-shell__body``sw-shell__surface` column. They never coordinate. | `server/pages/templates/base.html``src/js/sw/shell/app-shell.js` | Every surface inherits an ambiguous viewport ancestor. |
| 2 | **Transform-based scaling is broken**`transform: scale()` on `#surfaceInner` doesn't reflow layout. Breaks `getBoundingClientRect` (menu.js already carries a scale-correction hack at line 20), scroll containment, pointer events, and the inverse-width/height hack (`100/s%`) doesn't account for banners consuming viewport space. | `base.html:56-67`, `appearance.js:41-53`, `menu.js:20-33` | Menus, tooltips, dropdowns all mis-positioned at any non-100% scale. Click targets wrong. |
| 3 | **Banner height desync**`base.html` hardcodes `--banner-h: 28px` and renders banners in-flow. `app-shell.js` ShellBanner measures `offsetHeight` into `--banner-top-height` / `--banner-bottom-height` and uses `position: fixed` + body padding. Two independent banner systems. | `base.html:31,72-75,103-107``app-shell.js:25-42`, `sw-shell.css:22-37,63-69` | With banners enabled, content overflows by the banner height or gets double-inset depending on which code path is active. |
| 4 | **`100vh` on mobile** — `.sw-shell`, `.chat-app`, `.chat-loading`, `.login-shell` use `100vh` which doesn't subtract mobile browser chrome (address bar, toolbar). | `sw-shell.css:9`, `chat/css/main.css:15,25`, `sw-login.css:7` | Content overflows on iOS Safari, Android Chrome. |
| 5 | **Chat uses `100vh` not `100%`**`.chat-app { height: 100vh }` ignores parent container (which already excludes banners/footer). Notes correctly uses `height: 100%`. Every extension surface that copies chat's pattern will inherit the bug. | `packages/chat/css/main.css:15` | Chat surface overflows behind banners. |
### P2 — CSS Architecture
| # | Issue | Where | Impact |
|---|-------|-------|--------|
| 6 | **Class name collisions**`.settings-section` defined in both `modals.css:41-43` and `surfaces.css:75-83` with different padding, margin, and border-bottom rules. `.sw-dropdown` in `primitives.css:443` (styled `<select>`) vs `sw-primitives.css:262` (custom dropdown component). `.sw-tabs` in `primitives.css:459` vs `sw-primitives.css:234`. | Kernel CSS | Styles randomly win depending on load order. Bug reports differ by surface. |
| 7 | **Old/new primitive duplication** — Two button systems (`.btn-primary`/`.btn-small` in `primitives.css` vs `.sw-btn--primary`/`.sw-btn--sm` in `sw-primitives.css`). Two toast systems (`.toast` vs `.sw-toast`). Two dropdown, two tabs implementations. | `primitives.css``sw-primitives.css` | No single source of truth for any component. Extension authors can't know which to use. |
| 8 | **Extension CSS bleeds globally** — Extension `main.css` loaded via `<link>` at document level, no scoping. Any class name can override kernel or sibling extension styles. | `base.html:26-28`, `extension-surface.css` | Package CSS fights with kernel. Two packages with `.sidebar` both lose. |
| 9 | **No intermediate breakpoint** — Only `768px` mobile breakpoint. No tablet (7681024px). Secondary workspace pane hardcoded `480px`. Admin nav hardcoded `200px`. | `layout.css:263`, `surfaces.css:305` | Cramped layout on iPad/small laptops. |
### P3 — Visual Consistency
| # | Issue | Where | Impact |
|---|-------|-------|--------|
| 10 | **Mixed unit systems**`px`, `rem`, `em` used interchangeably with no rationale. Some font-sizes in `px` (primitives), others in `rem` (sw-primitives), others in `em` (user-picker). | All CSS files | Zoom/scale behaves differently per element. |
| 11 | **Google Fonts CDN dependency**`@import url(...)` in `variables.css:5` blocks rendering if CDN is slow; breaks entirely on air-gapped deployments. | `variables.css:5` | FOUT or blank page on slow networks. No offline support. |
| 12 | **No spacing scale** — Padding/margins are ad-hoc values (10px, 12px, 14px, 16px, 20px, 24px, 28px…). No design-token spacing scale. | All CSS | Inconsistent visual rhythm across surfaces. |
| 13 | **Hardcoded fallback colors in component CSS**`sw-shell.css`, `sw-primitives.css` have inline fallbacks like `var(--accent, #b38a4e)` — a gold color from a previous theme that doesn't match the current blue `#6c9fff`. | `sw-shell.css`, `sw-primitives.css` | Wrong colors flash briefly if variables load late. |
---
## Roadmap
### v0.6.9 — Session Lifetime Config ✅
Shipped. Admin-configurable TTLs, "keep me logged in" checkbox, idle timeout,
config-driven `generateTokens()`, 7 new tests. See CHANGELOG.md for details.
### v0.6.10 — Viewport Foundation ✅
Shipped. Single layout model: `body → shell → surface`. CSS `zoom` replaces
`transform: scale()`. `100dvh` fallbacks everywhere. Extension surfaces use
`100%` instead of `100vh`. Dead shell layout code deprecated. See CHANGELOG.md.
### v0.6.11 — CSS Deduplication ✅
Shipped. Old primitive system retired. One class per concept. See CHANGELOG.md.
| Step | Description |
|------|-------------|
| Audit collision inventory | Script that finds all duplicate class selectors across kernel CSS files. Produce a machine-readable collision report (JSON). |
| Migrate `.settings-section` | Remove `modals.css:41-43` definition. The `surfaces.css` definition is authoritative. Modals that used the old styles get explicit overrides scoped to `.modal .settings-section`. |
| Retire `primitives.css` old components | `.btn-primary`, `.btn-small`, `.btn-danger`, `.btn-full` → migrate all usages to `.sw-btn--*`. `.toast-container` / `.toast` → migrate to `.sw-toast-container` / `.sw-toast`. Old `.popup-menu` → migrate to `.sw-menu`. Old `.sw-dropdown` (styled select in primitives.css) → rename to `.sw-native-select` or delete if unused. Old `.sw-tabs` / `.sw-tab-btn` in primitives.css → delete (sw-primitives.css version is authoritative). |
| Mark deprecated classes | Any remaining old classes get a `/* DEPRECATED v0.6.11 — use .sw-btn--* */` comment and a 1-version grace period for package authors. |
| Package CSS audit | Scan all `packages/*/css/main.css` for references to deprecated kernel classes. Fix in-tree packages. |
### v0.6.12 — Extension CSS Isolation ✅
Shipped. Prefix enforcement via linter. All 12 in-tree packages migrated.
See CHANGELOG.md.
| Step | Description |
|------|-------------|
| Scoping strategy | Prefix enforcement (option B). `@scope` support still patchy; prefix works everywhere, trivially lintable. |
| Linter | `scripts/lint-package-css.sh` — validates first class selector in every rule starts with `.ext-{slug}`. Exempts `:root`, `@keyframes`, `@font-face`, `@media`, `.sw-*` kernel classes, `.cm-*` CodeMirror classes. |
| Kernel CSS contract | `docs/EXTENSION-CSS.md` — stable public classes (`.sw-btn--*`, `.sw-input`, `.sw-field`, `.sw-dialog`, `.sw-toast`, `.sw-menu`, `.sw-tabs`, etc.) and all CSS variables. Everything else internal. |
| Migrate in-tree packages | `data-ext="{{.Surface}}"` on extension mount. All 12 packages prefixed to `.ext-{slug}-*`. CSS + JS updated in lockstep. |
### v0.6.13 — Responsive & Spacing
Fill the gaps between mobile and desktop.
| Step | Description |
|------|-------------|
| Tablet breakpoint | Add `@media (min-width: 769px) and (max-width: 1024px)` rules. Secondary workspace pane: `360px` (from `480px`). Admin nav collapses to icon-only at this breakpoint. Settings nav: `180px`. |
| Spacing scale | Define spacing tokens in `variables.css`: `--space-1: 4px` through `--space-8: 64px` (4px base, doubling). Migrate hardcoded padding/margin values to tokens. Priority: surfaces that users see on every session (sidebar, topbar, admin content areas). |
| Font-size scale | Define `--text-xs: 0.75rem` through `--text-xl: 1.25rem` (5 stops). Migrate all font-size declarations. Remove `em`-based sizes (user-picker) and bare `px` sizes. |
| Secondary pane responsive | `workspace-secondary.open` width uses `clamp(320px, 35vw, 560px)` instead of fixed `480px`. |
### v0.6.14 — Visual Polish
Systematic cleanup of stale values and rendering artifacts.
| Step | Description |
|------|-------------|
| Purge stale fallback colors | Remove all `var(--foo, #hexvalue)` fallbacks that reference old gold theme colors (`#b38a4e` and variants). If a CSS variable is undefined at this point, that's a bug — don't mask it with a wrong fallback. |
| Self-host fonts | Bundle DM Sans and JetBrains Mono woff2 files in `src/fonts/`. Replace Google Fonts `@import` with local `@font-face` declarations. Zero external font dependencies. |
| Light theme audit | Walk every surface in light mode. Fix any remaining hardcoded dark-mode colors, contrast issues, or invisible borders. Document any surface-specific light-mode overrides. |
| Consistent border-radius | Surfaces currently mix `6px`, `8px`, `10px`, `var(--radius)`, `var(--radius-lg)`. Audit and reduce to 3 values: `--radius-sm: 4px`, `--radius: 8px`, `--radius-lg: 12px`. |
### v0.6.15 — Usability Survey Gate
Make the UI machine-auditable so Claude Code can run an automated survey.
| Step | Description |
|------|-------------|
| UI inventory manifest | `scripts/generate-ui-inventory.sh` — walks kernel CSS + package CSS, extracts every rendered class, groups by surface, outputs `ui-inventory.json`. Fields: `{surface, component, classes, file, line, responsive_breakpoints, spacing_tokens_used, font_size_tokens_used}`. |
| Contrast checker | Script that parses `variables.css` light/dark token pairs and checks WCAG AA contrast ratios for all `text-*` on `bg-*` combinations. Outputs pass/fail report. |
| Component coverage matrix | Markdown table: each kernel primitive (button, input, dropdown, dialog, toast, menu, tabs, avatar, spinner, tooltip, drawer, banner) × each surface that uses it. Identifies surfaces still using deprecated old-style components. |
| Touch target audit | Script that finds all `<button>`, `[role=button]`, clickable elements across templates and JS, checks for `min-width/min-height ≥ 44px` on mobile breakpoint. |
| Claude Code survey prompt | `docs/USABILITY-SURVEY.md` — structured prompt template that Claude Code can execute against the codebase. Sections: viewport correctness, banner integration, responsive behavior, styling consistency, accessibility basics (contrast, touch targets, focus indicators), component uniformity. Each section has pass/fail criteria and file paths to inspect. |
| Survey dry-run | Run the survey. Fix anything it catches. Tag `v0.6.15` only after clean survey. |
---
## Sequencing Rationale
```
v0.6.9 Session Lifetime Config ✅ SHIPPED
v0.6.10 Viewport Foundation ✅ SHIPPED
v0.6.11 CSS Deduplication ✅ SHIPPED
v0.6.12 Extension CSS Isolation ✅ SHIPPED
v0.6.13 Responsive & Spacing ← Spacing tokens need stable class names to attach to
v0.6.14 Visual Polish ← Final visual pass after structure is locked
v0.6.15 Usability Survey Gate ← Machine-audit the finished product
```
Each version is independently shippable and testable. No version depends on
anything after it.
---
## What "Usability Survey by Code" Means
The v0.6.15 deliverables give Claude Code (or any automated tool) three things:
1. **A structured inventory** (`ui-inventory.json`) of every component, on every
surface, with its CSS file and line number.
2. **Automated checks** (contrast, touch targets, token usage) that produce
machine-readable pass/fail reports.
3. **A survey prompt** (`USABILITY-SURVEY.md`) with explicit criteria and file
paths, so Claude Code can `cat` the relevant files, run the scripts, and
produce a scored report without human guidance.
The survey is not a substitute for real user testing — it's a structural
quality gate that catches the class of bugs (overflow, contrast, misalignment,
inconsistent styling) that have historically slipped through.