diff --git a/apps/web/src/components/__tests__/chat-interface.test.tsx b/apps/web/src/components/__tests__/chat-interface.test.tsx index 2d66ff3d..5ac2b2a7 100644 --- a/apps/web/src/components/__tests__/chat-interface.test.tsx +++ b/apps/web/src/components/__tests__/chat-interface.test.tsx @@ -231,6 +231,7 @@ function makeDefaultState() { chatId: null, isResuming: false, resumedContent: '', + resetChatError: vi.fn(), } } diff --git a/apps/web/src/components/ai-elements/conversation.tsx b/apps/web/src/components/ai-elements/conversation.tsx index 58c7289e..76e9b4ab 100644 --- a/apps/web/src/components/ai-elements/conversation.tsx +++ b/apps/web/src/components/ai-elements/conversation.tsx @@ -83,6 +83,7 @@ export const Conversation = ({ className, children, showScrollButton = false, .. ref={scrollRef} className="absolute inset-0 overflow-y-auto" role="log" + aria-label="Chat messages" > {children} {/* Anchor element for scroll-to-bottom */} @@ -92,10 +93,11 @@ export const Conversation = ({ className, children, showScrollButton = false, .. {showScrollButton && !isAtBottom && ( )} diff --git a/apps/web/src/components/app-loading-placeholder.tsx b/apps/web/src/components/app-loading-placeholder.tsx new file mode 100644 index 00000000..934d6545 --- /dev/null +++ b/apps/web/src/components/app-loading-placeholder.tsx @@ -0,0 +1,44 @@ +import { cn } from "@/lib/utils"; + +type AppLoadingPlaceholderProps = { + /** Announced to screen readers */ + message?: string; + className?: string; + /** Matches authenticated shell: sidebar stub + main pane */ + variant?: "app-shell" | "simple"; +}; + +/** + * Accessible loading placeholder for route-level and auth-gated suspense states. + */ +export function AppLoadingPlaceholder({ + message = "Loading", + className, + variant = "simple", +}: AppLoadingPlaceholderProps) { + if (variant === "app-shell") { + return ( +
+ {message} +