> **Status: COMPLETED** — All 5 phases executed on 2026-04-09. # UI Consistency Fix — Design Spec **Date:** 2026-04-09 **Goal:** Bring the cameleer3-server UI to consistent design system usage — eliminate CSS duplication, hardcoded colors, inline styles, and native HTML where DS components exist. **Source:** `UI-CONSISTENCY-AUDIT.md` (same repo, same date) --- ## Approach: Fix by Category Extract shared patterns first (unblocks everything), then sweep all files per issue type. Phases are independent after Phase 1 and can run in parallel. ## Phase 1: Extract Shared CSS Modules ### 1a. Table Section Pattern Create `ui/src/styles/table-section.module.css` containing: - `.tableSection`, `.tableHeader`, `.tableTitle`, `.tableMeta`, `.tableRight` Update these 5 files to import from shared module instead of local definitions: - `pages/DashboardTab/DashboardTab.module.css` - `pages/Admin/AuditLogPage.module.css` - `pages/Admin/ClickHouseAdminPage.module.css` - `pages/Routes/RoutesMetrics.module.css` - `pages/Routes/RouteDetail.module.css` ### 1b. Log Panel Pattern Create `ui/src/styles/log-panel.module.css` containing: - `.logCard`, `.logHeader`, `.logToolbar`, `.logSearchWrap`, `.logSearchInput`, `.logSearchClear`, `.logClearFilters`, `.logEmpty`, `.sortBtn`, `.refreshBtn`, `.headerActions` Update `AgentHealth.module.css` and `AgentInstance.module.css` to import shared. ### 1c. Rate Color Classes Create `ui/src/styles/rate-colors.module.css`: - `.rateGood`, `.rateWarn`, `.rateBad`, `.rateNeutral` Update DashboardTab, RouteDetail, RoutesMetrics. ### 1d. Tap Modal Dedup Remove duplicate tap modal CSS from `RouteDetail.module.css` — it already uses the `TapConfigModal` component which has its own CSS module. ### 1e. Refresh Indicator Dedup Move `.refreshIndicator`, `.refreshDot`, `.refreshText`, `@keyframes pulse` to shared module. Update DashboardTab and RoutesMetrics. ### 1f. Other Small Dedup - `.chartCard` — shared between AgentInstance and RouteDetail - `.section` — shared between AppConfigDetailPage and OidcConfigPage - `.metaGrid/.metaLabel/.metaValue` — shared between AboutMeDialog and UserManagement ## Phase 2: Fix Hardcoded Colors in CSS For each CSS module file: - Replace naked hex values with design system variables - Strip hex fallbacks from `var(--token, #hex)` -> `var(--token)` - Fix undefined variable names: - `--accent` -> `--amber` - `--bg-base` -> `--bg-body` - `--surface` -> `--bg-surface` - `--bg-surface-raised` -> `--bg-raised` - For tint colors without DS tokens (e.g., `#FDF2F0` error background), check if DS provides equivalents. If not, define them as local CSS custom properties at the component level using `color-mix()` from DS base colors. Files to fix (priority order): 1. `ExecutionDiagram/ExecutionDiagram.module.css` (~57 violations) 2. `ProcessDiagram/ProcessDiagram.module.css` (~20 violations) 3. `Dashboard/Dashboard.module.css` (4 violations including naked `#5db866`) 4. `DashboardTab/DashboardTab.module.css` (rgba shadow) 5. `RoutesMetrics/RoutesMetrics.module.css` (rgba shadow) 6. `AppsTab/AppsTab.module.css` (`--accent` + rgba) 7. `AgentHealth/AgentHealth.module.css` (`#fff`) 8. `LoginPage.module.css`, `ContentTabs.module.css`, `EnvironmentSelector.module.css` (undefined vars) ## Phase 3: Fix Hardcoded Colors in TSX Create `ui/src/utils/theme-colors.ts`: ```ts // Reads CSS custom properties from the document root at call time. // Use for SVG attributes where var() isn't supported in JS string contexts. export function cssVar(name: string): string { return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); } ``` Then replace all hex literals in ProcessDiagram components: - `DiagramNode.tsx` (~20 values) - `CompoundNode.tsx` (~8 values) - `DiagramEdge.tsx` (~3 values) - `ConfigBadge.tsx` (~3 values) - `ErrorSection.tsx` (~2 values) - `NodeToolbar.tsx` (~2 values) - `Minimap.tsx` (~3 values) - `ProcessDiagram.tsx` (~2 values) Note: SVG `fill` and `stroke` attributes DO support `var()` in modern browsers. Where the color is a static attribute (not computed in JS), use `fill="var(--success)"` directly. Only use `cssVar()` where the value must be a JS string (e.g., in computed color logic). Also fix TSX color references in: - `pages/Dashboard/Dashboard.tsx` (hardcoded `#3D7C47`) - `components/LayoutShell.tsx` (inline `color: 'var(--error)'` -> CSS class) Leave data-visualization computed `hsl()` values (Treemap, PunchcardHeatmap, DiagramNode heatmap) — these are intentional gradients. ## Phase 4: Eliminate Inline Styles ### 4a. Create Missing CSS Modules - `pages/Admin/AdminLayout.module.css` — extract the single inline layout style - `pages/Admin/DatabaseAdminPage.module.css` — extract all inline layout/typography - `auth/OidcCallback.module.css` — extract full-page layout ### 4b. Extract Shared Components - Create `components/PageLoader.tsx` — replaces the 3 copy-pasted `` + flex + padding patterns in router.tsx, RuntimePage, DashboardPage ### 4c. Move Static Inline Styles to CSS Modules Priority files (most violations): - `AppsTab.tsx` — fixed-width inputs -> size classes, visually-hidden pattern, table cell layouts - `LayoutShell.tsx` — StarredList styles - `EnvironmentsPage.tsx` — save/cancel button rows, raw `` -> DS `Select` 2. `ExecutionDiagram/tabs/LogTab.tsx` — raw table -> DS `LogViewer` 3. `AppsTab.tsx` sub-tab bars -> DS `SegmentedTabs` or `Tabs` 4. `AppConfigDetailPage.tsx` — `` -> DS `Toggle`, `