feat(react-ui): AgentInterface welcome-glow rework, DotMatrixLoader, and blue default accent - #787
Conversation
Polish navigation and conversation spacing, add category-aware empty states and a reusable dot-matrix loader, and restore branded accent defaults. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Self Note test this out, why the function type changes needed
There was a problem hiding this comment.
Resolved my own note after testing. The type change is a consequence of the new onSelect?(starter) prop: the parent now needs the whole starter object (not just the prompt string), so it closes over each item — onClick={() => handleClick(item)} — and the child's internal onClick becomes a plain () => void thunk that no longer passes prompt back. ConversationStarterItemProps is not exported, so no consumer impact. Tested both variants in Storybook: short and long starters send starter.prompt through processMessage (long variant correctly sends the prompt, not the displayText), and the isRunning guard holds. The onSelect override path has no story exercising it — noted as a showcase gap.
There was a problem hiding this comment.
Update: with the export removed (8215f424), onSelect became unreachable, so the whole cluster is reverted — prop, starter-object handler, and the item onClick type change. ConversationStarter.tsx is now a 3-line diff vs main (just the long-variant separators); the function-type question is moot.
| style.setAttribute("data-openui-theme", id); | ||
| style.textContent = `${styleSelector}, .${portalClassName} { ${cssVarsString} }`; | ||
| style.textContent = `${styleSelector}, .${portalClassName} { ${cssVarsString} | ||
| --openui-agent-sidebar-shadow-color: ${sidebarShadowColor}; }`; |
There was a problem hiding this comment.
cant do this, variable should be introduced through theme Provider
There was a problem hiding this comment.
Resolved — this injection was removed entirely; ThemeProvider.tsx is now byte-identical to main. The sidebar shadow is a local SCSS variable on $sunk-deep instead.
There was a problem hiding this comment.
selfNote:- review this, standard are not getting followed here.
There was a problem hiding this comment.
@pr3khar review this file. I think this is also moving away from the standard
| gap: cssUtils.$space-2xl; | ||
| background-color: cssUtils.$highlight-subtle; | ||
| box-shadow: inset -10px 0 18px -18px | ||
| var(--openui-agent-sidebar-shadow-color, cssUtils.$sunk-deep); |
There was a problem hiding this comment.
new variable got introduced here this is not the right approach
There was a problem hiding this comment.
Addressed in 10901b8 + the merge: the ThemeProvider-injected --openui-agent-sidebar-shadow-color is fully gone (ThemeProvider.tsx now has zero diff vs main) and sidebar.scss uses a local SCSS variable on an existing token: $sidebar-shadow: inset -10px 0 18px -18px cssUtils.$sunk-deep;.
Improve sidebar and workspace feedback, standardize loader behavior, and remove the superseded message-loading component. Co-authored-by: Cursor <cursoragent@cursor.com>
Lockfile resolved to main's wholesale: this branch changes no manifests, so its lockfile diff was regeneration noise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nPH2Rn2XGXETgx5Yu5seX
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nPH2Rn2XGXETgx5Yu5seX
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nPH2Rn2XGXETgx5Yu5seX
CI (pnpm 9) resolves the react-ui prettier script to prettier@3.5.3 while a pnpm 10 install resolves 3.9.4, and the two disagree on these files; 3.5.3 is the gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nPH2Rn2XGXETgx5Yu5seX
With the component not exported (8215f42), nothing can pass onSelect — the prop, the starter-object handler, and the item onClick type change all served only that path. Handler wiring returns to main's shape; the long-variant separators and hover styling stay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nPH2Rn2XGXETgx5Yu5seX
Summary
This PR reworks the AgentInterface welcome experience, adds a branded loading indicator, and flips the default theme accent from neutral (black/white) to blue. It introduces two new components —
DotMatrixLoader(a public, reusable rAF-driven loader) andWelcomeGlow/WelcomeGlowProvider(an opt-in, CSS-only entrance glow around the welcome composer) — then wires them through the existing AgentInterface surfaces (Thread loader, artifact browser/view loading states, WelcomeScreen). Alongside the components, the default accent identity is rebranded to blue in both the JS theme generator and the static CSS fallback, and a batch of coordinated SCSS changes re-aligns the welcome screen (centered → left, ~748px column), narrows the content column (880 → 768px), flattens sidebar nav, restyles long conversation starters, and repositions the thread-list row-action button. The change is almost entirely additive at the API level; the two behavior-level shifts are the blue accent (a token mutation) and the removal of date-grouping in the thread list. All changes live underpackages/react-ui; noexamples/files change.What changed
New components
DotMatrixLoader(components/DotMatrixLoader/) — a 4×4 (16-dot)role=statusloader. Animation is arequestAnimationFrameloop mutating each dot's inlineopacityper frame (two comet trails on hand-authored OUTER_RING/INNER_RING coordinates,REVOLUTION_MS = 1400, exponential opacity falloff). Variantsdefault(36px) /compact(24px) plus asizeoverride; SCSS holds only static geometry/color. Cleanup is correct (cancelAnimationFrameon unmount). Promoted to the public API (index.ts).WelcomeGlow+WelcomeGlowProvider(components/AgentInterface/WelcomeGlow.tsx,welcomeGlow.scss) — a context (defaultfalse) gating an optional one-shot entrance/composer glow. When disabled, renders a bare<>{children}</>(no wrapper DOM, zero cost); when enabled it wraps children with two decorativearia-hiddenblobs. All motion is pure CSS@keyframes, theme-token driven, and reduced-motion-guarded. Exposed asAgentInterface.WelcomeGlow.AgentInterface UX
glowAnimation?: boolean(defaultfalse). Both render branches wrap in<WelcomeGlowProvider>and add--animated; the props branch also wraps<DesktopWelcomeComposer/>in<WelcomeGlow>. The rest of the large diff is JSX re-nesting — default-off, so existing consumers render identically.<DotMatrixLoader variant="compact" />instead of the old three-dotMessageLoading.ScrollArea's defaultuserMessageSelectoralso widened to match.openui-shell-thread-message-user.groupThreads()recency bucketing (Today / Yesterday / Previous 7/30 Days / This Year / Older) is deleted and replaced with a single static "Threads" header + flatthreads.map(...). Thread order now depends entirely onuseThreadList.onSelect?(starter)prop overriding the default send. Long variant gains hairline separators; default colors dim to secondary and brighten on hover.Loading…text replaced with<DotMatrixLoader />. No-results message becomesNo results found for "<query>"; empty illustration uses the category's own artifact-type icon.Theming
defaultTheme.tsflipsbrandSwatch "neutral" → "blue"(light + dark), sobrandSolid=blue-600and feedstextBrand,interactiveAccent*,borderAccent*, and the accent-text contrast picker. Mirrored inopenui-defaults.scssfor raw-CSS-var consumers.DEFAULT_ACCENT_SOLID(indigo) — new; the explicitbrandSwatch:"neutral"branch now returns this indigo instead of pure black/white.chatUserResponseBgswitched tooverlayBaseso user bubbles stay neutral under the new blue brand.--openui-agent-sidebar-shadow-colortoken drives a sidebar right-edge inset shadow.Cleanup / structural SCSS
Card/card.scss— removedpadding/border-radius/border-color/background-color(keepsbox-shadow: none); defers surface styling to the base Card.assistantMessage.scss/thread.scss— removed the center-align gutter; messages + loading row sit flush.How to review / showcase
Storybook runs at
http://localhost:6006; story IDs followcomponents-agentinterface--<id>. Only theWithWelcomestory changed (adds aglowAnimationtoggle); every other change is observed through existing stories.--with-welcome. Glow OFF already shows the rework (hero left-aligned, 748px). ToggleglowAnimation = truein Controls + remount: staggered entrance + two blue glow blobs behind the composer.--default. Threads under one "Threads" header; blue send button/focus/accents; faint sidebar inset shadow; hover a row → kebab fades in; user bubble neutral gray.--with-workspace, click "Create a revenue dashboard" (~400ms) for the 24px loader.--artifact-browser. Click a category → 36px loader; type a no-match query →No results found for "<query>".--long-starters. Separators between rows; secondary→primary color on hover.origin/main, and exercise dark mode.Risks & notes
DotMatrixLoaderhas noprefers-reduced-motionhandling. The rAF loop runs unconditionally while mounted and is the default per-turn thread loader, with no opt-out (unlikeWelcomeGlow, which is SCSS-guarded). Gate the loop onmatchMedia('(prefers-reduced-motion: reduce)')with a static fallback.ThemeProvidertheme silently shifts its whole accent identity to blue. Confirm this rebrand is intended/approved.Card/card.scsssurface stripping. Cards look correct only if the base react-ui Card supplies matching defaults; verify againstcomponents-card--card-story(not touched by this PR).useThreadList. Confirm the store pre-sorts newest-first.ConversationStarter.tsxandDotMatrixLoader.tsxfailprettier --check(runformat:fix).WelcomeGlowno-ops to a bare fragment when disabled;DotMatrixLoadera11y is good (role=status, glow blobsaria-hidden); all public-API changes are additive.