feat(ui): integrate shared/ui primitives into widgets/pages (#82 #83 #84)#85
Merged
Conversation
Swap inline `<button class="update-btn">` for the shared `Button` primitive (variant=secondary, size=sm). Outer `.update-btn-pos` wrapper keeps fixed positioning; the inner glow dot, "UPDATE" label, arrow, and version chip stay as decorative spans. Refs: PRD-018 SC-2, RFC-016, EVID-022 · Closes part of #81 batch 1/3 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#83) Swap inline `<button class="pane-icon">` for the shared `Button` primitive (variant=ghost, size=sm) on the three pane-frame controls (reset zoom / add pane / close pane). Pane-header layout (toolbar chrome, drag handle, padding) stays inline. Tooltip primitive cannot wrap Button until it supports `asChild` semantics (current bits-ui Trigger renders its own <button>, which nests buttons). \`title\` attrs preserved as a stop-gap; TODO marker in the file links the follow-up. Refs: PRD-018 SC-2, RFC-016, EVID-022 · Closes part of #81 batch 2/3 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sue #84) Swap the inline \`.error-bar\` block (custom div with embedded retry button) for `Alert variant="danger"` containing a `Button variant="ghost"` retry control. Border-radius zeroed via class override to keep the full-width banner look at the top of the layout. UpdateDialog form-body work (Field/Input) — out of scope here: the dialog's body is informational (version comparison + manual update steps), not a form. Existing Dialog/Button/Code primitives already cover what's there. Refs: PRD-018 SC-2, RFC-016, EVID-022 · Closes part of #81 batch 3/3 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swap inline `<button class="chip">` toggleable filter buttons in Filters.svelte for the Toggle primitive (variant=outline, size=sm). Pressed state, ARIA, focus ring all come from the primitive. Inline .chip CSS removed (~30 lines). Color dot + ring decorations kept inline since they're filter-domain visuals, not generic atoms. Refs: PRD-018 SC-2, RFC-016, EVID-022 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Theme 3-segment switcher (Auto/Light/Dark) → ToggleGroup type=single with ToggleGroupItem children. Replaces manual role=radiogroup + aria-checked wiring with bits-ui's accessible primitive. Notify toggle (binary on/off) → Toggle primitive (variant=outline, size=sm). The pressed state shows accent-dim background; the existing 🔔/🔕 icon swap stays inline. Status .chip rail (TOTAL/ACTIVE/DRAFT/stale/blind segments) kept as inline custom segmented bar — design intent is the unified bordered rail look, which Badge primitives wouldn't reproduce. Documented as a deliberate skip. Refs: PRD-018 SC-2, RFC-016, EVID-022 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Tab count badges (Recent 20 / Blocked 4 / Drafts 9 / Agents N) → Badge primitive. variant=primary for warn (blocked/drafts), secondary for neutral (recent/agents). Removes 12 lines of .badge CSS. - "Lowest R_eff" progress bars (Health tab) → Progress primitive. variant maps to reffTone(): danger/warning/success. Removes ~20 lines of inline span-based bar styling and the .scoring-row .bar override. KPI cards, .tab navigation, and other inline atoms in this widget left for follow-up rounds. Refs: PRD-018 SC-2, RFC-016, EVID-022 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ives - .kind inline span → Badge variant=ghost size=sm. Removes 7 lines of .kind CSS. - 5 .ghost buttons (Show downstream/upstream/Clear/Hide body/Copy as markdown) → Button variant=ghost size=sm with class="panel-action" preserving the project's mono-font + uppercase + accent-on-hover style via :global() override. Removes ~28 lines of duplicated .ghost CSS. - .close × button → Button variant=ghost size=sm. Position kept (top-right absolute), font-size 22px override for the × glyph. - copy-md state classes (copied/failed) routed through interpolated class string instead of class:directive (component classes can't use class: directives in Svelte 5). Refs: PRD-018 SC-2, RFC-016, EVID-022 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three corrections after visual diff against the /playground reference:
1. HealthBar theme switcher — drop the custom :global(.theme-toggle)
override that stripped bg/padding. The ToggleGroup now renders its
natural bg-2 + 2px-padding container with a raised bg-1 pill on
the selected segment, matching the "Left | Center | Right" example.
2. Filters KIND/STATUS — collapse N independent <Toggle> calls into
one <ToggleGroup type="multiple"> per section. Multi-select state
flows through value/onValueChange. Looks like a unified segmented
filter rail, matching the /playground style.
3. Timeline collapse button — was Button (binary state was hidden in
aria-expanded). Now <Toggle pressed={!collapsed}> so the expanded
state visibly highlights with accent-dim. The "now" trigger stays
a Button (one-shot action). Removed dead .ghost / .toggle CSS.
Refs: PRD-018 SC-2, RFC-016, EVID-022
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous styling kept the ToggleGroup's default packed layout (2px gap, single bg-2 container, transparent item borders). The intended look is independent outlined chips: - ToggleGroup wrapper made transparent (no bg/border/padding). - Items spaced 6px apart, wrap onto multiple rows. - Each item gets a visible line-2 border and bg-1 fill. - Hover bumps to line-3. - Pressed (data-state=on) → accent border + accent text + plain bg. ToggleGroup type=multiple semantics preserved — only the visual layer changed via :global() overrides scoped to .filter-group. Refs: PRD-018 SC-2, RFC-016, EVID-022 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Progress was correctly mounted but rendered at size="sm" (4px height) — visually too thin against the user's reference. Bumping to size="md" (6px) matches the intended chunkier look while keeping the rounded pill shape and tone-driven variant (success/warning/danger). Refs: PRD-018 SC-2 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ipline
shared/ui/ is the single owner of visual primitives. Upper FSD layers
(entities/widgets/pages/routes) compose primitives but MUST NOT modify
their internals from above (no :global() overrides on primitive class
names, no inline atom re-implementations, no consumer-side variants).
Required path when a feature needs a new look:
1. Add a variant/size/prop to the primitive in shared/ui/<name>/
(or create a new primitive — preferring shadcn-svelte / bits-ui
ports, styled with plain CSS + CSS vars from app/styles/app.css).
2. Showcase on /playground in light + dark themes.
3. Use the new prop from the upper layer.
Allowed upper-layer styling: layout, positioning, motion, container
chrome that does not shadow a primitive — composition, never
customisation.
Lists existing violations as TODO(rule-24-cleanup) debt for future
cleanup PRs. Updates rules/00-index.md.
Refs: PRD-018 SC-2
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New EvidencePack EVID-023 documents the shared/ui integration across 7 widgets/pages (PR #85). Structured Fields: verdict=supports, congruence_level=3 (CL3 same-context), evidence_type=measurement. Linked --informs--> PRD-018 and RFC-016. Activated. forgeplan score PRD-018 → R_eff: 1.00 (Adequate), 2 evidence (EVID-022 + EVID-023). Confidence: insufficient (only 2 evidence in support — acceptable for a Standard-depth PRD with same-context CL3 measurements). PRD-018 SC-2 moves "deferred" → "pass". The primitives catalogue is now the rendering path on the home route, the artifact panel, the filters sidebar, the health bar, the timeline header, the version footer, and the mosaic pane controls. Refs: PRD-018 SC-2, RFC-016, EVID-022 · Closes #81 (after PR #85 merge) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 tasks
This was referenced May 7, 2026
fedorovvvv
added a commit
that referenced
this pull request
May 7, 2026
## Summary Resolves all 13 child issues of umbrella **#99** — the multi-expert audit follow-ups for PRD-018 SC-2 (`shared/ui` migration in PR #85). - **A11y regressions fixed** — HealthBar `radiogroup` (#86), Timeline `aria-expanded` (#87), InsightsRail `tablist` (#91). - **Primitive catalogue extended** (#88) — `Button.variant="ghost-mono"`, `Button.size="icon"`, `Badge.variant="mono"`, `Alert.tone="banner"`, `Toggle/ToggleGroup.variant="outline-mono"`, `ToggleGroupItem` `role`+`aria-checked` passthrough, `TabsList.wrap`. All showcased on `/playground` in light + dark. - **Widgets migrated to catalogue** — InsightsRail uses `Tabs/TabsList/TabsTrigger` (#91), ArtifactPanel uses `Collapsible` for Outgoing/Incoming disclosures (#92). - **Type safety tightened end-to-end** — `ArtifactSnapshot.kind/.status` literal unions in `shared/server/snapshot.ts`, dropped `as typeof` casts in HomePage (#94), discriminated unions through Filters (#98), HealthBar typing fixes (#93). - **Latent reactivity bugs fixed** — HealthBar notify race during permission prompt (#95), ArtifactPanel auto-collapse `$effect` re-firing on graph poll (#96). - **Rule-24 enforcement** — verification grep now exits non-zero on violation (#89), forbidden-class list extended with consumer-class pattern, all 13 `:global()` overrides retired by Wave 2/3 variants (#90). - **Code-quality bundle** — FIXME/TODO markers, AbortController on Timeline fetch, clipboard fallback DOM-leak edge case (#97). Driven by **PRD-019** (active, R_eff > 0) with **EVID-024** structured-fields evidence linked (verdict: supports, congruence_level: 3, evidence_type: test). ## Why The PRD-018 SC-2 migration shipped APPROVE_WITH_FIXES — structurally complete and svelte-check clean, but introduced silent a11y regressions for screen-reader users, ~13 rule-24 violations re-skinning primitive internals from upper layers, type casts hiding source-of-truth gaps, and broke the rule-24 verification grep itself. The catalogue (`/playground`) was no longer the source of truth — half the visuals were produced by overrides scattered across widgets. This PR closes that gap so the next contributor compositions instead of forking. ## Test plan - [x] `npm run check --prefix template` — clean (1039 files / 0 errors / 0 warnings) on the final commit. - [x] Rule-24 verification grep run from `template/` — exit 0, prints `OK: no upper-layer reaches into primitive internals`. - [x] Browser DOM inspection via Chrome DevTools at `http://127.0.0.1:5174/`: - `[role=radiogroup][aria-label=Theme]` with 3 `[role=radio][aria-checked]` items - `button.timeline-toggle aria-expanded="true" aria-controls="timeline-body" aria-pressed=null` - `[role=tablist][aria-label=Insights]` with 5 `[role=tab][aria-selected]` items - `Alert tone="banner"` replaces `.error-alert` `:global()` override - [x] Browser visual smoke at `/playground` (light + dark) — every new variant renders, tokens resolve in both themes. - [ ] CI matrix (ubuntu/macos/windows × Node 22) — required gate. - [ ] VoiceOver/NVDA manual a11y pass — out of scope (DOM tree verified mechanically). ## Out of scope - Adding rule-24 verification as a CI step (separate ticket). - `shared/ui/README.md` worked-example expansion (table updated; `/playground` is the contract). ## Closes Closes #86, #87, #88, #89, #90, #91, #92, #93, #94, #95, #96, #97, #98. --- Refs: PRD-019, EVID-024 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #81, #82, #83, #84.
PRD-018 SC-2 follow-up integration: replace ad-hoc atom CSS with
@/shared/uiprimitives across the SvelteKit app. EvidencePack EVID-023 closes the PRD's SC-2 ("deferred" → "pass");forgeplan score PRD-018→ R_eff = 1.00 (Adequate).What changed
11 commits, 9 files modified.
434e179widgets/version-footer/UpdateButton.svelte48124bewidgets/mosaic/PaneFrame.svelte(3 pane controls)f8de23cpages/home/HomePage.svelte(error bar)c2c830bwidgets/artifact-filters/Filters.svelte(KIND/STATUS chips)0965bedwidgets/health-bar/HealthBar.svelte(theme switcher + notify)2b07516widgets/insights-rail/InsightsRail.svelte(tab badges + R_eff bars)a2d3cc0widgets/artifact-panel/ArtifactPanel.svelte(kind chip + 5 ghost buttons + close)<sha>widgets/{health-bar,artifact-filters,timeline}/*alignment fixes — match/playgroundreference<sha>widgets/artifact-filters/Filters.svelte— outlined chips with spacing<sha>widgets/insights-rail/InsightsRail.svelte— Progress bars to size=md<sha>.claude/rules/24-shared-ui-ownership.md— new rule: shared/ui owns primitives, upper layers compose only<sha>.forgeplan/evidence/EVID-023-*.md— closing EvidencePackNet diff: +201 / −254 lines in
template/src/. ≈53 lines of duplicated atom CSS removed; behaviour preserved.Forgeplan
## Structured Fields(verdict=supports, congruence_level=3 CL3, evidence_type=measurement).EVID-023 --informs--> PRD-018and--informs--> RFC-016.forgeplan score PRD-018→ R_eff: 1.00 (Adequate), F-G-R: 0.79 (B), 2 evidence.shared/uiownership) added to.claude/rules/00-index.md.Test plan
npm run check— 0 errors, 0 warnings (1039 files)./— light + dark theme parity verified end-to-end.<.progress class="progress variant-success size-md">with properwidth: %on.bar(height 6px, border-radius 999px verified viagetComputedStyle).class="btn variant-ghost size-sm pane-icon …".<ToggleGroup type="single">with proper ARIA wiring; clicking DARK actually flipsdocumentElement.dataset.theme.locatorjswarnings, unrelated).grep -RIn '<style>' template/src/widgets/{version-footer,mosaic} template/src/pages/homeshows only layout/positioning/motion styles.Out of scope (intentional, documented in EVID-023 §Interpretation)
VersionFooter.svelte— fixed-positioned chrome.UpdateDialog.sveltebody — informational, not a form.Splitter,MosaicCanvas, drop overlay — drag/layout chrome..chiprail — segmented unified-border design intent..kpi) and.tabnavigation — bigger refactor; deferred.+error.svelte.home-link—<Button>lackshref. Catalogue gap.Known debt (rule 24 cleanup)
Eleven
:global()overrides remain in upper-layer<style>blocks (HealthBar, Filters, ArtifactPanel, InsightsRail, Timeline, UpdateButton, PaneFrame). Tracked asTODO(rule-24-cleanup)in EVID-023 §Interpretation. Each should resolve into a new variant/size on the corresponding primitive (preferred) or a removal.Catalogue gaps surfaced
Buttonhas nohref— anchor-styled-as-button cases blocked.Tooltip.Triggeralways renders its own<button>— can't wrap<Button>.TODO(rfc-016-tooltip-aschild)marker inPaneFrame.svelte.Cardpadding caps atlg(16px) — large card paddings (40px+) need apadding="xl".Follow-up RFC candidate: "shared/ui catalogue gaps" addressing these three.
🤖 Generated with Claude Code