Add queued-message controls and shared squircle styling - #95
Add queued-message controls and shared squircle styling#95sambitcreate wants to merge 6 commits into
Conversation
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Incremental review of the squircle commit (21fbf5e2), the delta since the previously pushed head (47787cff).
- Shaped the composer shell with a broader native squircle: added the
--radius-composer: 40pxsemantic token andcorner-shape: squircleon.composer-shell, and dropped therounded-2xlutility from the shell div so the CSS class owns the radius. - Added an Electron E2E test asserting the squircle shape, that it survives draft growth and a resize to a 900px window, and that the workspace-access popover (anchored inside the shell, opening above its top edge) remains visible and hit-testable with overflow left visible.
- Fixed a provider-transport race in the navigation-isolation E2E test: it now polls until the mock server has actually received the next generation request before asserting its conversation history.
Notes from verification: corner-shape support is asserted against the real Electron runtime via CSS.supports plus computed-style checks, and the packaged app pins Electron ^43, so the unsupported-runtime fallback (plain 40px radius) is effectively unreachable in production. The resize assertion is geometrically sound at the 900px breakpoint (the 72px-per-side dock gutter pushes the 52rem column below its cap), and the window-resize idiom mirrors the existing chat-shell-interactions.spec.ts patterns. No other markup references the removed rounded-2xl on the shell, and no contract test depended on it.
DeepSeek Flash | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Queued chat follow-ups: composer can now enqueue drafts while a response runs (
onQueuerouting with aListPlusaffordance), with per-chat document-local queues, FIFO drain, edit/delete/reorder/steer controls, and pause/resume. - Delivery serialization:
ChatMessageQueue.claim/settlewith a main-process persistence barrier (chats:waitUntilIdle) and post-barrier route/readiness re-checks; uncertain append outcomes (isAppendReconciliationRequired) are never replayed. - Race hardening: editing blocks dispatch, steer moves + resumes + stops through the barrier, chat deletion discards queues via
removeDeletedChatFromCache, and chat-scopedcontextKeyprevents cross-chat delivery; queues are window-local by design. - Auto-hide workspace bar: new default-on
autoHideComposerContextappearance preference collapses the composer context strip (ComposerContextBar) after the first persisted user message, withinert/aria-hidden, 180 ms grid-rows collapse, reduced-motion override, and legacy settings compatibility. - Tests: new unit suites (
chat-message-queue.test.ts, expanded deletion-cache/appearance/composer contract tests) and six Electron e2e scenarios plus mock-LMStudio hold/release completion fixtures.
The delivery state machine holds up under adversarial interleavings I traced: pause/stop landing between claim and send (deferral only occurs before any send; single-flight sendingId claim prevents double claims), navigation and unmount mid-delivery (isCurrent reads a live ref that is nulled on unmount before the post-barrier guard), chat deletion while a delivery waits (discard clears sendingId, main releases turn admission before the store delete), and steer/stop vs. drain concurrency (steer requires isGenerating, claims require !isGenerating — disjoint). Generation-start rejections surface through the stream onError handler in both the accepted-with-error and not-accepted paths, so the queue pauses rather than draining into unanswered turns. I also verified in headless Chromium that applying inert blurs the focused element only at the frame boundary — after React layout effects run — so the focus handoff guard in composer-context-bar.tsx fires correctly, and confirmed the drop-index semantics of drag reordering are uniform with the keyboard path. Queue, deletion-cache, and appearance unit suites pass locally (31 tests).
DeepSeek Flash | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes (delta since the prior pullfrog review of 47787cf):
- Squircle composer shell:
rounded-2xlwas removed from.composer-shellin favor of a new--radius-composer: 40pxtoken plus nativecorner-shape: squircleinstyles.css, withoverflowkept visible so composer menus stay unclipped. - Squircle e2e: new Electron scenario asserts
corner-shapesupport and computed styles (radius 40px,overflow: visible, noclip-path, shadow retained), verifies the shape survives window resizing and draft growth, and hit-tests the workspace-access popover above the shell. - Navigation e2e race fix: the "switching chats retains the queue" scenario now polls for the specific provider request before inspecting its conversation history, closing the window between durable append and the async mock-server request.
The squircle change is purely presentational with a well-targeted test: the geometry of an n=4 squircle keeps the cut crescent tight to the corner, so the 10px-padded content row is not clipped, and the test's overflow/clip-path/hit-test assertions would catch a regression if menus or access controls were affected. The radius token follows the existing --radius-* convention in the same block, corner-shape degrades gracefully to the plain 40px border-radius on engines that lack it, and the CSS.supports gate in the test makes CI enforce the minimum Electron version. The CI race fix is correct and matches the papercuts note. Squircle e2e assertions match the shipped styles exactly.
DeepSeek Flash | 𝕏
There was a problem hiding this comment.
ℹ️ No critical issues — one styling consequence of the unified action rule is worth a look before merge.
Reviewed changes — Incremental review of the button-unification commit (4189124a), the delta since the prior pullfrog review (21fbf5e2).
- Unified action geometry: added the
:root :is(button, [role="button"], [data-slot="button"], .squircle-control)rule plus the--radius-button: 16pxtoken, and removed the pill/roundedradiusprop from the sharedButton, updating callers in the model picker, open-in-editor picker, scheduled-task editor/view, and subagent views. - Switched the minimized-assistant artwork mask from a circular crop to the shared
.squircle-controlsilhouette (assistant-bubble.tsx). - Added
docs/design-guide.md, folded the rule intoAGENTS.mdand the element specimen (composer radius 20→40px, new focus tokens, mirrored action rule), and re-scopedbutton-appearance-contract.test.tsto assert the unified rule shape, token, doc/specimen consistency, and removal of theradiusprop. - Added the
expectSquircleButtonsE2E fixture asserting every visible action computescorner-shape: squirclewith a 16px radius, wired into onboarding, chat/queue flows, and the Settings traversal in both themes.
The unification itself is cleanly scoped and well-tested: --radius-button is a real theme token generating rounded-button, no radius="..." callers remain, :not() exclusions match the actual selection controls (Radix roles; no native radio/checkbox inputs exist), and the E2E sweep plus contract tests lock the geometry across the swept surfaces. One consequence of the rule's specificity on the segmented editor picker is flagged inline.
ℹ️ Nitpicks
assistant-bubble.tsx:39— the outer button'srounded-fullis now inert: the new global rule (0,2,0) overrides the utility, so the bubble renders the 16px squircle fromstyles.css. Drop the class so the markup reflects the rendered silhouette (the inner.squircle-controlmask already matches it).
DeepSeek Flash | 𝕏
There was a problem hiding this comment.
ℹ️ No critical issues — the joined-action fix is sound and the prior thread's concern is fully addressed; one nitpick about a test assertion that can't do what its comment claims.
Reviewed changes — Incremental review of ea003d56 ("Preserve joined action seams in shared squircle controls"), the delta since the prior pullfrog review of 4189124a.
- Added the
.squircle-action-groupchild rules inrenderer/styles.css(square internal seams, end caps matching the shared 16px squircle) and folded the action rule's role-exclusion clauses into:where(...)so those group-child overrides win by specificity. - Converted the segmented "Open workspace in editor" pill to the shared squircle silhouette: the container is now
.squircle-control.squircle-action-groupwith visible overflow, and the dead per-cornerrounded-l-pill/rounded-r-pillutilities were dropped from both halves (separator span retained). - Removed the inert
rounded-fullfrom the assistant bubble's outer button so the markup matches the rendered 16px squircle (prior nitpick). - Documented the joined-action pattern in
docs/design-guide.md, mirrored the rules plus a demo group indocs/chatgpt-ui-element-specimen.html, and recorded the styling constraint in.papercuts/troubleshooting.md. - Extended Electron coverage with a joined-editor-actions scenario (hover-fill presence, square seam radii, keyboard focus outlines, dropdown open/Escape focus return, screenshot) and a group-aware branch in the
expectSquircleButtonssweep.
The seam mechanics check out: the group rules outrank the shared action rule after the :where() fold, :first-child/:last-child correctly target the two halves around the separator span, and the fixture's group branch mirrors the CSS exactly (logical radius getters resolve to the same physical corners in LTR). The prior review's inline finding is resolved by removing the per-corner utilities rather than by clipping, which is the cleaner of the two suggested routes.
DeepSeek Flash | 𝕏

The desktop composer now accepts follow-ups while Aiden is responding. Queued rows above the composer show attachment previews, direct Steer and delete actions, and a three-dot control that opens a separate editor without replacing the current draft. Dragging, Alt+Arrow keys, and editor controls can reorder messages.
Steer stops the current response, waits for terminal persistence, then sends the selected message next through the normal append/generation path. Stop and errors pause the queue; uncertain append outcomes are never replayed. Editing blocks dispatch, deleting a chat discards its queue, and queued drafts stay scoped to their chat across navigation. Queues live in the current window, drain only while that chat is open and ready, and do not survive closing/reloading the window; the UI explains this.
Appearance now has Auto-hide workspace bar, enabled by default. After the first user message is saved, the workspace/Local strip slides down and collapses while queued messages remain visible. Hidden controls are inert, reduced motion removes the transition, and turning the setting off restores the strip. Legacy appearance settings remain compatible and the preference survives relaunch.
The composer and app actions now share native squircle geometry without a package dependency. The composer uses a broader 40px semantic radius; shared and existing custom action buttons use 16px across onboarding, chat, navigation, dialogs, Settings, and the compact dictation window. Existing theme, shadows, keyboard focus, disabled states, and overflow menus remain intact. Selection controls retain their native affordances. Removed the shared button's separate capsule-radius option and updated its callers. Joined editor actions share the outer squircle with square internal seams, so hover fills meet cleanly and keyboard focus stays visible.
Added
docs/design-guide.mddescribing reusable components, shape tokens, state behavior, and verification. The interactive element specimen and project UI instructions point to the same rules.Updated the existing Workspace Agent onboarding tile. Inspected iOS and Android send consumers: no Remote API, shared transcript/activity, or native behavior changes are required.
Validation:
The app-wide styling revision additionally passes 26 focused button, composer, assistant, and interface contract tests; full renderer and E2E TypeScript checks; lint; and the renderer production build.
Pullfrog follow-up: added a joined-action regression covering hover fills, square seam radii, keyboard focus and dropdown dismissal; removed the obsolete circle class from the assistant button.