Replace thread loading spinner with skeleton pattern#14906
Conversation
* Add ChatLoadingSkeleton component with skeleton message bubbles Co-Authored-By: Claude <noreply@anthropic.com> * Remove unused avatarReserve property and add #if DEBUG guard to preview * Use adaptive maxWidth for skeleton bones to handle narrow containers * Use VRadius.pill instead of hardcoded radius for avatar circle --------- Co-authored-by: Claude <noreply@anthropic.com>
* Replace loading spinners with ChatLoadingSkeleton in chat area Co-Authored-By: Claude <noreply@anthropic.com> * Update stale docstring on DaemonLoadingChatSkeleton * Add accessibility labels for VoiceOver on skeleton loading states --------- Co-authored-by: Claude <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6339738044
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| } | ||
| } | ||
| } | ||
| .accessibilityHidden(true) |
There was a problem hiding this comment.
Remove unconditional accessibility hiding from skeleton
ChatLoadingSkeleton applies .accessibilityHidden(true) at its root, which removes the view from the accessibility tree in every context. In this patch, both ChatView loading states rely on wrapping this skeleton with explicit labels ("Loading chat history" / "Getting ready"), so VoiceOver users can end up with no announced loading status after the spinner/text was removed. Keep the skeleton hidden only in contexts that are truly decorative (for example, the daemon overlay) and allow labeled loading states to remain accessible.
Useful? React with 👍 / 👎.
The skeleton itself should not unconditionally hide from VoiceOver. Each usage site already controls accessibility appropriately: - DaemonLoadingOverlay hides the ZStack (decorative) - ChatView loading states use accessibilityElement + accessibilityLabel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
- User message: right-aligned bubble with two short text lines, matching real ChatBubble user styling (fill, padding, corner radius) - Assistant message: left-aligned with 28pt avatar placeholder and six varying-width text lines, using the same overlay/offset pattern as real ChatBubble (avatar at -(28+sm), content padded .leading 36pt) - Spacing uses VSpacing.md between messages (matching LazyVStack) - Constrained to chatColumnMaxWidth for proper centering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Start from top of chat area instead of vertically centered - Use real assistant avatar (AvatarAppearanceManager) instead of skeleton bone for the avatar circle - Add subtle bubble background to assistant message block - Add Spacer at bottom of skeleton to push content to top Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use darker bone fill (surfaceBorder 0.7) instead of default 0.5 - Use surfaceBorder as shimmer highlight instead of bright surface color - Widen user message bones (280/200pt) for more realistic proportions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User skeleton bubble now spans the same width as the assistant block (680pt) instead of shrink-wrapping around short bones. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
surfaceBorder is Moss._100 in light mode — same as background, making bones invisible. Switch to textMuted (Stone._600 light / Moss._500 dark) which contrasts well against the background in both color schemes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User messages are typically shorter than assistant responses. The skeleton now reflects this with a 65% width bubble. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Real ChatBubble uses Color.clear for assistant messages and the skeleton doesn't need bubble chrome — just bare bones matching the layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User messages have a visible bubble in both dark and light modes (Moss._950 / Moss._200). Skeleton now uses the real userBubble color with proper padding and corner radius matching ChatBubble. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Replace the spinning loading indicators in the chat area with content-aware skeleton placeholders that mimic the chat message layout, providing better perceived-performance UX when threads are loading.
Changes
ChatLoadingSkeletoncomponent with alternating assistant/user skeleton message bubbles usingVSkeletonBone+ shimmer animationProgressView()spinner in ChatView (history loading state) withChatLoadingSkeleton()VLoadingIndicatorinDaemonLoadingChatSkeletonwithChatLoadingSkeleton()VLoadingIndicator+ "Getting ready..." inChatBootstrapLoadingViewwithChatLoadingSkeleton()maxWidthsizing so skeletons scale with narrow containersMilestone PRs (merged into feature branch)
Project issue
Closes #14888
Test plan
Generated with Claude Code