Skip to content

fix(ui): restore nav-section/topbar class names after v2026.3.13-1 sync — paired call-site update missed #2501

@alexey-pelykh

Description

@alexey-pelykh

Problem

Multiple visible UI regressions on the Control UI shell from the v2026.3.13-1 sync (04a7853f0f). Two confirmed symptoms with the same root cause:

Symptom 1 — Sidebar nav group headers render as raw text +/ (instead of styled chevrons), with no group spacing/colors/borders. The Chat, Control, Agent, Settings group headers display the literal +/ characters from app-render.ts:270 as fallback content because the corresponding CSS classes are undefined.

Symptom 2 — Topbar overlap: page title (Overview) overlaps the brand block (REMOTECLAW / Gateway Dashboard) because the flex containers that previously positioned them are unstyled.

Root cause

Sync 04a7853f0f (v2026.3.13-1, 751 commits) brought in upstream's ui/src/styles/layout.css wholesale, which had renamed several class families as part of upstream's dashboard-v2 refactor. The fork's ui/src/ui/app-render.ts was NOT touched by the same sync (it's heavily fork-diverged: 2 rebrand commits + 6 gut commits + 1 prior-sync-regression remediation), so it still references the OLD class names.

The result: render code emits classes that no CSS rule defines → unstyled fallback rendering.

Affected class renames (extracted from git show 04a7853f0f -- ui/src/styles/layout.css):

Render code uses (fork) Upstream CSS now has
.nav-group .nav-section
.nav-group__items .nav-section__items
.nav-group--collapsed .nav-section--collapsed
.nav-label .nav-section__label
.nav-label--static (removed entirely)
.nav-label__text .nav-section__label-text
.nav-label__chevron .nav-section__chevron (now expects an SVG child, not text)
.topbar-left (removed; layout reorganized)
.brand-text (removed)
.brand-sub (removed)
.topbar-status .theme-toggle .topbar-status .theme-orb__trigger
.topbar-status .theme-icon .topbar-search family

app-render.ts lines using these classes:

  • 213<header class="topbar"> (still defined)
  • 214<div class="topbar-left"> ❌ undefined
  • 227<div class="brand"> (still defined)
  • 231<div class="brand-text"> ❌ undefined
  • 232-233<div class="brand-title">REMOTECLAW</div><div class="brand-sub">Gateway Dashboard</div> (.brand-sub undefined)
  • 256<div class="nav-group ..."> ❌ undefined
  • 258<button class="nav-label"> ❌ undefined
  • 269<span class="nav-label__text"> ❌ undefined
  • 270<span class="nav-label__chevron">${isGroupCollapsed ? "+" : "−"}</span> ❌ undefined (renders as raw text)
  • 272<div class="nav-group__items"> ❌ undefined
  • 278<div class="nav-group nav-group--links"> ❌ undefined
  • 279<div class="nav-label nav-label--static"> ❌ undefined

Pattern class

This is the second instance of the regression class documented in HQ #57 (gateway-disconnect post-mortem) and HQ #59 (fork-sync risk model). The variant table has been generalized in the personal-config fork-sync skill from "type-definition-only sync without paired class-implementation update" to "definition-site sync without paired call-site update" — covering CSS-class/template-string drift as well as type/class drift.

Notably: the existing build pipeline (pnpm tsgo, pnpm lint, pnpm test) does NOT catch CSS class drift. TypeScript doesn't validate template-string class names; oxlint/stylelint as currently configured don't cross-reference template strings against CSS files. A CSS class consistency lint is the highest-leverage prevention for this variant (see follow-up issue for the lint rule).

Fix options

# Approach Effort Trade-off
1 Restore old CSS rules in a new fork-owned file ui/src/styles/nav-groups.css (recovered from the 04a7853f0f deletion); add @import to ui/src/styles.css. Same for the deleted .topbar-left/.brand-text/.brand-sub rules. ~30 min Stays on legacy class names; future syncs to layout.css won't conflict with the fork-owned restoration file; but fork visually diverges from upstream design choices
2 Migrate render code to upstream class names: update ui/src/ui/app-render.ts to use .nav-section* and the new topbar structure. Replace text +/ chevron with an SVG icon (look at upstream's ${icons.chevronDown} reference at upstream app-render.ts:1317 to find the icon source). Accept upstream's visual restyle (uppercase nav labels, tighter padding, etc.). 1-2 h Aligned with upstream design; future syncs land cleanly; permanently resolves this regression class for these components

Recommend option 2 — option 1 just delays the same conflict to the next time upstream restyles these components. Option 2 future-proofs by making fork's render code track upstream's class vocabulary.

Acceptance criteria

  • Sidebar nav groups render with proper spacing and chevron icons (no raw +/ characters visible)
  • Topbar shows REMOTECLAW + Gateway Dashboard brand block on the left, page title centered, status pills on the right — no overlapping text
  • Theme toggle works (uses correct class .theme-orb__trigger if migrating)
  • pnpm check (tsgo + lint + format) passes
  • pnpm test passes
  • Visual smoke check: load /overview, /chat, /agents and verify layout sanity in light + dark themes

Commit message

fix(ui): restore nav-section/topbar class names after v2026.3.13-1 sync — paired call-site update missed

or

refactor(ui): migrate app-render.ts to upstream nav-section + topbar class vocabulary — resolve sync drift

References

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions