diff --git a/apps/desktop/src/backend/DesktopBackendPool.ts b/apps/desktop/src/backend/DesktopBackendPool.ts index 258f8731fa1e7..45d7c78c2fb0a 100644 --- a/apps/desktop/src/backend/DesktopBackendPool.ts +++ b/apps/desktop/src/backend/DesktopBackendPool.ts @@ -238,8 +238,8 @@ export const layer = Layer.effect( { reason }, ); yield* electronDialog.showErrorBox( - "WSL backend is still unavailable", - `${reason}\n\nT3 Code will use the Windows backend for this launch and retry WSL the next time the app starts.`, + "WSL environment is still unavailable", + `${reason}\n\nT3 Code will use the Windows environment for this launch and retry WSL the next time the app starts.`, ); yield* appSettings.applyWslWindowsFallbackInMemory; return true; @@ -249,8 +249,8 @@ export const layer = Layer.effect( reason, }); yield* electronDialog.showErrorBox( - "WSL backend couldn't start", - `${reason}\n\nFalling back to the Windows backend so T3 Code can open. Re-enable the WSL backend from Settings > Connections once the WSL distro is fixed.`, + "WSL environment couldn't start", + `${reason}\n\nFalling back to the Windows environment so T3 Code can open. Re-enable the WSL environment from Settings > Connections once the WSL distro is fixed.`, ); // Fully disable the WSL backend — both flags, matching the "Switch to // Windows" recovery path — so the manager's next restart re-resolves the diff --git a/apps/desktop/src/wsl/DesktopWslEnvironment.ts b/apps/desktop/src/wsl/DesktopWslEnvironment.ts index c6c274d8500b9..c66354d66fc11 100644 --- a/apps/desktop/src/wsl/DesktopWslEnvironment.ts +++ b/apps/desktop/src/wsl/DesktopWslEnvironment.ts @@ -123,11 +123,11 @@ export const formatWslShellTransportFailureReason = ( ): string | null => { switch (failure) { case "timeout": - return "WSL backend preflight timed out while probing for Node.js. WSL may be slow to start; retry, or check that the distro is healthy."; + return "WSL environment preflight timed out while probing for Node.js. WSL may be slow to start; retry, or check that the distro is healthy."; case "spawn": - return "WSL backend preflight could not start wsl.exe to probe for Node.js. Check that WSL is installed and the distro is accessible."; + return "WSL environment preflight could not start wsl.exe to probe for Node.js. Check that WSL is installed and the distro is accessible."; case "process": - return "WSL backend preflight lost communication with wsl.exe while probing for Node.js. Retry, or check that the distro is healthy."; + return "WSL environment preflight lost communication with wsl.exe while probing for Node.js. Retry, or check that the distro is healthy."; case null: return null; } @@ -542,7 +542,7 @@ const ensureNodePtyImpl = ( ok: false, reason: nodeOnlyReason ?? - "The bundled WSL backend binary (node-pty) could not be loaded in this distro. This usually means an unsupported CPU architecture or incompatible system libraries (glibc). Use a glibc-based x64/arm64 WSL distro such as Ubuntu; if you already are, please report this with your distro and the output of `uname -m`.", + "The bundled WSL environment binary (node-pty) could not be loaded in this distro. This usually means an unsupported CPU architecture or incompatible system libraries (glibc). Use a glibc-based x64/arm64 WSL distro such as Ubuntu; if you already are, please report this with your distro and the output of `uname -m`.", fatal: true, } as const; } diff --git a/apps/web/src/browser/BrowserDeviceToolbar.tsx b/apps/web/src/browser/BrowserDeviceToolbar.tsx index f20ab0b37109e..27c686a3708b2 100644 --- a/apps/web/src/browser/BrowserDeviceToolbar.tsx +++ b/apps/web/src/browser/BrowserDeviceToolbar.tsx @@ -172,7 +172,7 @@ export function BrowserDeviceToolbar({ return (
{width >= 560 ? ( - + Dimensions ) : null} @@ -327,7 +327,7 @@ export function BrowserDeviceToolbar({ size="icon-xs" type="button" aria-label="Close device toolbar" - className="sticky right-0 ml-auto bg-background/95" + className="sticky end-0 ms-auto bg-background/95" disabled={pending} onClick={() => { apply({ _tag: "fill" }, null); diff --git a/apps/web/src/browser/BrowserViewportResizeHandles.tsx b/apps/web/src/browser/BrowserViewportResizeHandles.tsx index 08e69c359a158..69c6281890368 100644 --- a/apps/web/src/browser/BrowserViewportResizeHandles.tsx +++ b/apps/web/src/browser/BrowserViewportResizeHandles.tsx @@ -32,7 +32,7 @@ type HandleKind = "horizontal" | "vertical" | "corner"; const EDGE_BUTTON_CLASS = "group absolute z-20 touch-none border-0 bg-transparent p-0 outline-none before:absolute before:-inset-1 before:content-[''] focus-visible:bg-foreground/[0.04]"; const EDGE_GRIP_CLASS = - "pointer-events-none absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center text-muted-foreground/55 transition-colors duration-150 group-hover:text-foreground/85 group-focus-visible:text-foreground group-active:text-foreground"; + "pointer-events-none absolute start-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center text-muted-foreground transition-colors duration-150 group-hover:text-foreground/85 group-focus-visible:text-foreground group-active:text-foreground"; function ResizeHandle(props: { readonly direction: BrowserViewportResizeDirection; @@ -89,8 +89,8 @@ function ResizeHandle(props: { className={cn("relative block size-3", mirrorCorner && "-scale-x-100")} aria-hidden="true" > - - + + )} diff --git a/apps/web/src/browser/HostedBrowserWebview.tsx b/apps/web/src/browser/HostedBrowserWebview.tsx index a72da49c6fa37..9bf870fe03620 100644 --- a/apps/web/src/browser/HostedBrowserWebview.tsx +++ b/apps/web/src/browser/HostedBrowserWebview.tsx @@ -243,7 +243,7 @@ export function HostedBrowserWebview(props: { /> {activeDrag ? (
@@ -167,7 +167,7 @@ export function AppSidebarLayout({ children }: { children: ReactNode }) { collapsible="offcanvas" data-app-sidebar="" data-sidebar-version={useSidebarV2Theme ? "v2" : "v1"} - className="border-r border-sidebar-border bg-sidebar text-sidebar-foreground" + className="border-e border-sidebar-border bg-sidebar text-sidebar-foreground" resizable={{ maxWidth: sidebarMaximumWidth, minWidth: THREAD_SIDEBAR_MIN_WIDTH, diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx index e703427d4b632..4ccc22572d515 100644 --- a/apps/web/src/components/BranchToolbar.tsx +++ b/apps/web/src/components/BranchToolbar.tsx @@ -125,7 +125,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ if (isLocked) { return ( - + {triggerContent} ); @@ -135,7 +135,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ } - className="min-w-0 max-w-[48%] flex-1 justify-start text-muted-foreground/70 hover:text-foreground/80 md:hidden" + className="min-w-0 max-w-[48%] flex-1 justify-start text-muted-foreground hover:text-foreground/80 md:hidden" > {triggerContent} @@ -345,7 +345,7 @@ export const BranchToolbar = memo(function BranchToolbar({ )}
{itemValue} - {badge && {badge}} + {badge && {badge}}
); @@ -710,7 +710,7 @@ export function BranchToolbarBranchSelector({ aria-label={branchPrTooltip} onClick={(event) => openPrLink(event, branchPrStatus.url)} className={cn( - "inline-flex shrink-0 items-center gap-0.5 rounded px-1 py-0.5 text-[11px] font-medium tabular-nums transition-colors hover:bg-muted/60", + "inline-flex shrink-0 items-center gap-0.5 rounded px-1 py-0.5 text-2xs font-medium tabular-nums transition-colors hover:bg-muted/60", branchPrStatus.colorClass, )} /> @@ -731,7 +731,7 @@ export function BranchToolbarBranchSelector({ > } - className="min-w-0 max-w-full text-muted-foreground/70 hover:text-foreground/80" + className="min-w-0 max-w-full text-muted-foreground hover:text-foreground/80" disabled={isInitialBranchesLoadPending || isBranchActionPending} > @@ -745,12 +745,12 @@ export function BranchToolbarBranchSelector({
- No refs found. + + {branchQuery.trim().length > 0 ? ( + + No refs match “{branchQuery.trim()}”. + + + ) : ( + "No refs in this repository yet. Type a name to create one." + )} +
diff --git a/apps/web/src/components/BranchToolbarEnvModeSelector.tsx b/apps/web/src/components/BranchToolbarEnvModeSelector.tsx index e915c27312cda..63f5a4e5cb994 100644 --- a/apps/web/src/components/BranchToolbarEnvModeSelector.tsx +++ b/apps/web/src/components/BranchToolbarEnvModeSelector.tsx @@ -50,7 +50,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe if (envLocked) { return ( - + {activeWorktreePath ? ( <> diff --git a/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx b/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx index dbc742bea5a7b..8d4443976a677 100644 --- a/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx +++ b/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx @@ -43,7 +43,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir if (envLocked || onEnvironmentChange === undefined) { return ( - + {activeEnvironment?.isPrimary ? ( ) : ( diff --git a/apps/web/src/components/ChatMarkdown.tsx b/apps/web/src/components/ChatMarkdown.tsx index fac3bf7d24559..4ab68e5b740fb 100644 --- a/apps/web/src/components/ChatMarkdown.tsx +++ b/apps/web/src/components/ChatMarkdown.tsx @@ -481,7 +481,7 @@ function MarkdownDetails({ data-markdown-details-open={isOpen ? "true" : "false"} >
{displayPath} diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index ab1256cddb34f..3cec6d723a8c3 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -1112,7 +1112,7 @@ type LocalThreadErrorEntry = { }; function chatActionErrorMessage(error: unknown): string { - return error instanceof Error ? error.message : "An error occurred."; + return error instanceof Error ? error.message : "That didn't go through. Try again."; } function ChatViewContent(props: ChatViewProps) { @@ -1627,7 +1627,7 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Could not reconnect environment", + title: "Couldn't reconnect environment", description: error instanceof Error ? error.message : "Failed to reconnect.", }), ); @@ -2017,6 +2017,21 @@ function ChatViewContent(props: ChatViewProps) { activeThread?.session ?? null, localDispatchStartedAt, ); + // Responses stream in with no announcement of their own: sighted users see the + // pulsing dots, screen-reader users get silence. Keep the message terse — the + // reply itself is read from the timeline, this only marks the boundaries. + const [turnAnnouncement, setTurnAnnouncement] = useState(""); + const wasWorkingRef = useRef(false); + useEffect(() => { + if (isWorking === wasWorkingRef.current) return; + wasWorkingRef.current = isWorking; + setTurnAnnouncement(isWorking ? "Assistant is responding" : "Response complete"); + }, [isWorking]); + useEffect(() => { + // A new thread starts from silence rather than inheriting the last one. + wasWorkingRef.current = false; + setTurnAnnouncement(""); + }, [activeThread?.id]); useEffect(() => { attachmentPreviewHandoffByMessageIdRef.current = attachmentPreviewHandoffByMessageId; }, [attachmentPreviewHandoffByMessageId]); @@ -2915,7 +2930,7 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Could not delete action", + title: "Couldn't delete action", description: error instanceof Error ? error.message : "An unexpected error occurred.", }), ); @@ -3269,7 +3284,7 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to copy path", + title: "Couldn't copy path", description: "Clipboard API unavailable.", }), ); @@ -3288,8 +3303,11 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to copy path", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't copy path", + description: + error instanceof Error + ? error.message + : "Copying the path didn't go through. Try again.", }), ); }, @@ -3899,8 +3917,11 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to un-settle thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't un-settle thread", + description: + error instanceof Error + ? error.message + : "Un-settling the thread didn't go through. Try again.", }), ); } @@ -3927,8 +3948,11 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to wake thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't wake thread", + description: + error instanceof Error + ? error.message + : "Waking the thread didn't go through. Try again.", }), ); } @@ -4000,7 +4024,7 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to switch checkout", + title: "Couldn't switch checkout", description: chatActionErrorMessage(squashAtomCommandFailure(checkoutResult)), }), ); @@ -5305,11 +5329,11 @@ function ChatViewContent(props: ChatViewProps) { toastManager.add( stackedThreadToast({ type: "error", - title: "Could not start implementation thread", + title: "Couldn't start implementation thread", description: error instanceof Error ? error.message - : "An error occurred while creating the new thread.", + : "Creating the thread didn't go through. Try again.", }), ); } @@ -5620,18 +5644,19 @@ function ChatViewContent(props: ChatViewProps) { data-chat-header className={cn( "bg-background transition-[padding-left] duration-200 ease-linear motion-reduce:transition-none", + // .workspace-topbar now carries the shared safe-area inset; only the + // trailing override for native window controls stays here. isElectron ? cn( - "workspace-topbar drag-region relative px-3 sm:px-5", + "workspace-topbar drag-region relative", reserveTitleBarControlInset && !inlineRightPanelOwnsTitleBar && - "wco:pr-[var(--workspace-native-controls-inset)]", + "wco:pe-[var(--workspace-native-controls-inset)]", ) - : "workspace-topbar pl-[calc(env(safe-area-inset-left)+0.75rem)] pr-[calc(env(safe-area-inset-right)+0.75rem)] sm:pl-[calc(env(safe-area-inset-left)+1.25rem)] sm:pr-[calc(env(safe-area-inset-right)+1.25rem)]", + : "workspace-topbar", COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS, )} > - {!rightPanelOpen ? panelLayoutControls : null} + {/* Rendered last so keyboard and screen-reader users reach the project + and thread title before the panel controls. The controls are + absolutely positioned, so their visual position is unchanged. */} + {!rightPanelOpen ? panelLayoutControls : null} setThreadError(activeThread.id, null)} /> + {/* Mounted empty so the region is already in the accessibility tree when + its first message lands; late-inserted live regions are not read. */} +
+ {turnAnnouncement} +
{/* Main content area with optional plan sidebar */}
{/* Chat column */} @@ -5712,7 +5746,7 @@ function ChatViewContent(props: ChatViewProps) { {/* scroll to end pill — shown when user has scrolled away from the live edge */} {showScrollToBottom && (
+ + ) : ( + "No refs to compare against yet. Create a branch to pick a base." + )} + {!activeThread ? ( -
+
Select a thread to inspect turn diffs.
) : !isGitRepo ? ( -
+
Turn diffs are unavailable because this project is not a git repository.
) : selectedTurnId !== null && orderedTurnDiffSummaries.length === 0 ? ( -
+
No completed turns yet.
) : ( <>
{isSelectedPatchTruncated && ( -

+

This diff was truncated because it exceeded the preview limit. The changes shown are incomplete.

)} {selectedPatchError && !renderablePatch && (
-

{selectedPatchError}

+

{selectedPatchError}

)} {!renderablePatch ? ( @@ -835,14 +850,14 @@ export default function DiffPanel({ ) : ( -
+

{hasNoNetChanges ? "No net changes in this selection." @@ -866,7 +881,9 @@ export default function DiffPanel({

-

{renderablePatch.reason}

+

{renderablePatch.reason}

@@ -70,7 +71,7 @@ export function DiffPanelLoadingState(props: { label: string }) {
       >
         
- +
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx index 11716e935ae75..ffcc6b1bfbede 100644 --- a/apps/web/src/components/GitActionsControl.tsx +++ b/apps/web/src/components/GitActionsControl.tsx @@ -496,7 +496,11 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { if (result._tag === "Failure") { if (!isAtomCommandInterrupted(result)) { const error = squashAtomCommandFailure(result); - setPublishError(error instanceof Error ? error.message : "An error occurred."); + setPublishError( + error instanceof Error + ? error.message + : "Publishing the repository didn't go through. Try again.", + ); } return; } @@ -565,7 +569,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { onClick={isClickable ? () => setPublishWizardStep(index) : undefined} disabled={!isClickable} className={cn( - "grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] gap-x-2 rounded-lg border px-3 py-2 text-left", + "grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] gap-x-2 rounded-lg border px-3 py-2 text-start", index === publishWizardStep ? "border-primary bg-primary/10 ring-1 ring-primary/25 dark:border-transparent" : isComplete @@ -587,7 +591,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { > {isComplete ? : null} - + Step {index + 1} @@ -627,7 +631,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { return (
{ event.preventDefault(); event.stopPropagation(); @@ -667,7 +671,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { key={option.value} value={option.value} className={cn( - "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-3 text-left outline-none transition-[background-color,border-color,box-shadow]", + "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-3 text-start outline-none transition-[background-color,border-color,box-shadow]", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", isSelected ? "border-primary bg-background shadow-sm ring-2 ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" @@ -693,7 +697,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { Repository
- + {publishHost}/ @@ -712,7 +716,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { }} placeholder={publishPathPlaceholder} disabled={publishRepositoryAction.isPending} - className="w-full bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground/60 focus:outline-none" + className="w-full bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground focus:outline-none" />
@@ -753,7 +757,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { key={option.value} value={option.value} className={cn( - "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2.5 text-left outline-none transition-[background-color,border-color,box-shadow]", + "relative flex cursor-pointer items-center gap-3 rounded-lg border px-3 py-2.5 text-start outline-none transition-[background-color,border-color,box-shadow]", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background", isSelected ? "border-primary bg-background shadow-sm ring-2 ring-primary/35 dark:border-transparent dark:bg-primary/10 dark:shadow-none dark:ring-1 dark:ring-primary/30" @@ -852,7 +856,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { className="flex items-center gap-2 rounded-md border border-input bg-muted/40 px-3 py-2 text-xs text-muted-foreground dark:border-transparent dark:bg-white/[0.035]" > - Publishing repository to {publishProviderLabel}... + Publishing repository to {publishProviderLabel}…
) : null} {publishError && !publishRepositoryAction.isPending ? ( @@ -951,7 +955,7 @@ function PublishRepositoryDialog(props: PublishRepositoryDialogProps) { {publishRepositoryAction.isPending ? ( <> - Publishing... + Publishing… ) : ( "Publish" @@ -1234,8 +1238,11 @@ export default function GitActionsControl({ toastManager.add( stackedThreadToast({ type: "error", - title: "Unable to open pull request link", - description: err instanceof Error ? err.message : "An error occurred.", + title: "Couldn't open pull request link", + description: + err instanceof Error + ? err.message + : "Opening the pull request link didn't go through. Try again.", ...(threadToastData !== undefined ? { data: threadToastData } : {}), }), ); @@ -1302,8 +1309,8 @@ export default function GitActionsControl({ progressToastId ?? toastManager.add({ type: "loading", - title: progressStages[0] ?? "Running git action...", - description: "Waiting for Git...", + title: progressStages[0] ?? "Running git action…", + description: "Waiting for Git…", timeout: 0, data: scopedToastData, }); @@ -1312,19 +1319,19 @@ export default function GitActionsControl({ toastId: resolvedProgressToastId, toastData: scopedToastData, actionId, - title: progressStages[0] ?? "Running git action...", + title: progressStages[0] ?? "Running git action…", phaseStartedAtMs: null, hookStartedAtMs: null, hookName: null, lastOutputLine: null, - currentPhaseLabel: progressStages[0] ?? "Running git action...", + currentPhaseLabel: progressStages[0] ?? "Running git action…", }; if (progressToastId) { toastManager.update(progressToastId, { type: "loading", - title: progressStages[0] ?? "Running git action...", - description: "Waiting for Git...", + title: progressStages[0] ?? "Running git action…", + description: "Waiting for Git…", timeout: 0, data: scopedToastData, }); @@ -1359,7 +1366,7 @@ export default function GitActionsControl({ progress.lastOutputLine = null; break; case "hook_started": - progress.title = `Running ${event.hookName}...`; + progress.title = `Running ${event.hookName}…`; progress.hookName = event.hookName; progress.hookStartedAtMs = now; progress.lastOutputLine = null; @@ -1368,7 +1375,7 @@ export default function GitActionsControl({ progress.lastOutputLine = event.text; break; case "hook_finished": - progress.title = progress.currentPhaseLabel ?? "Committing..."; + progress.title = progress.currentPhaseLabel ?? "Committing…"; progress.hookName = null; progress.hookStartedAtMs = null; progress.lastOutputLine = null; @@ -1407,8 +1414,11 @@ export default function GitActionsControl({ resolvedProgressToastId, stackedThreadToast({ type: "error", - title: "Action failed", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't finish the Git action", + description: + error instanceof Error + ? error.message + : "The Git action didn't go through. Try again.", ...(scopedToastData !== undefined ? { data: scopedToastData } : {}), }), ); @@ -1534,7 +1544,7 @@ export default function GitActionsControl({ if (quickAction.kind === "run_pull") { const toastId = toastManager.add({ type: "loading", - title: "Pulling...", + title: "Pulling…", timeout: 0, data: threadToastData, }); @@ -1550,8 +1560,9 @@ export default function GitActionsControl({ toastId, stackedThreadToast({ type: "error", - title: "Pull failed", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't pull", + description: + error instanceof Error ? error.message : "Pulling didn't go through. Try again.", ...(threadToastData !== undefined ? { data: threadToastData } : {}), }), ); @@ -1638,8 +1649,11 @@ export default function GitActionsControl({ toastManager.add( stackedThreadToast({ type: "error", - title: "Unable to open file", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't open file", + description: + error instanceof Error + ? error.message + : "Opening the file didn't go through. Try again.", ...(threadToastData !== undefined ? { data: threadToastData } : {}), }), ); @@ -1669,8 +1683,11 @@ export default function GitActionsControl({ toastManager.add( stackedThreadToast({ type: "error", - title: "Git initialization failed", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't initialize Git", + description: + error instanceof Error + ? error.message + : "Initializing the repository didn't go through. Try again.", ...(threadToastData !== undefined ? { data: threadToastData } : {}), }), ); @@ -1678,8 +1695,8 @@ export default function GitActionsControl({ }} > - - {initAction.isPending ? "Initializing..." : "Initialize Git"} + + {initAction.isPending ? "Initializing…" : "Initialize Git"} ) : ( @@ -1701,7 +1718,7 @@ export default function GitActionsControl({ quickAction={quickAction} SourceControlIcon={SourceControlIcon} /> - + {quickAction.label} @@ -1717,7 +1734,7 @@ export default function GitActionsControl({ onClick={runQuickAction} > - + {quickAction.label} @@ -1788,7 +1805,7 @@ export default function GitActionsControl({ }} > - Publish repository... + Publish repository… ) : null} {gitStatusForActions?.refName === null && ( @@ -1839,7 +1856,7 @@ export default function GitActionsControl({ {gitStatusForActions?.refName ?? "(detached HEAD)"} {isDefaultRef && ( - Warning: default refName + Warning: default refName )}
@@ -1905,7 +1922,7 @@ export default function GitActionsControl({ )} @@ -268,8 +271,8 @@ const PlanSidebar = memo(function PlanSidebar({ {/* Empty state */} {!activePlan && !planMarkdown ? (
-

No active plan yet.

-

+

No active plan yet.

+

Plans will appear here when generated.

diff --git a/apps/web/src/components/ProjectFavicon.tsx b/apps/web/src/components/ProjectFavicon.tsx index bc3e8ee832ff1..1fef658d52b24 100644 --- a/apps/web/src/components/ProjectFavicon.tsx +++ b/apps/web/src/components/ProjectFavicon.tsx @@ -40,7 +40,9 @@ function ProjectFaviconFallback({ readonly className?: string | undefined; readonly icon: ComponentType<{ className?: string }>; }) { - return ; + return ( + + ); } function ProjectFaviconImage({ diff --git a/apps/web/src/components/ProjectScriptsControl.tsx b/apps/web/src/components/ProjectScriptsControl.tsx index 79e43f4c042d5..3228775dd2a58 100644 --- a/apps/web/src/components/ProjectScriptsControl.tsx +++ b/apps/web/src/components/ProjectScriptsControl.tsx @@ -342,7 +342,7 @@ export default function ProjectScriptsControl({ } > - + {primaryScript.name} @@ -381,7 +381,7 @@ export default function ProjectScriptsControl({ type="button" variant="ghost" size="icon-xs" - className="absolute right-0 top-1/2 size-6 -translate-y-1/2 opacity-0 pointer-events-none transition-opacity group-hover:opacity-100 group-hover:pointer-events-auto group-focus-visible:opacity-100 group-focus-visible:pointer-events-auto" + className="absolute end-0 top-1/2 size-6 -translate-y-1/2 opacity-0 pointer-events-none transition-opacity group-hover:opacity-100 group-hover:pointer-events-auto group-focus-visible:opacity-100 group-focus-visible:pointer-events-auto" aria-label={`Edit ${script.name}`} onPointerDown={(event) => { event.preventDefault(); @@ -411,7 +411,7 @@ export default function ProjectScriptsControl({ }> - + Add action @@ -432,7 +432,7 @@ export default function ProjectScriptsControl({ } > - + Add action @@ -582,7 +582,7 @@ export default function ProjectScriptsControl({ @@ -166,7 +166,7 @@ function RightPanelEmptyState(props: { const disabledCard = ( ) : !isThreadRunning ? ( appSettingsConfirmThreadArchive ? ( -
+
+
) : null} @@ -1022,7 +1041,7 @@ const SidebarProjectThreadList = memo(function SidebarProjectThreadList( render={showMoreButtonRender} data-thread-selection-safe size="sm" - className="h-8 w-full translate-x-0 justify-start px-2 text-left text-xs text-sidebar-muted-foreground/75 hover:bg-sidebar-row-hover hover:text-sidebar-foreground" + className="h-8 w-full translate-x-0 justify-start px-2 text-start text-xs text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground" onClick={() => { expandThreadListForProject(projectKey); }} @@ -1040,7 +1059,7 @@ const SidebarProjectThreadList = memo(function SidebarProjectThreadList( render={showLessButtonRender} data-thread-selection-safe size="sm" - className="h-8 w-full translate-x-0 justify-start px-2 text-left text-xs text-sidebar-muted-foreground/75 hover:bg-sidebar-row-hover hover:text-sidebar-foreground" + className="h-8 w-full translate-x-0 justify-start px-2 text-start text-xs text-sidebar-muted-foreground hover:bg-sidebar-row-hover hover:text-sidebar-foreground" onClick={() => { collapseThreadListForProject(projectKey); }} @@ -1137,8 +1156,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to copy thread ID", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't copy thread ID", + description: + error instanceof Error ? error.message : "Copying didn't go through. Try again.", }), ); }, @@ -1157,8 +1177,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to copy path", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't copy path", + description: + error instanceof Error ? error.message : "Copying didn't go through. Try again.", }), ); }, @@ -1514,17 +1535,19 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: `Failed to remove "${member.title}"`, + title: `Couldn't remove "${member.title}"`, description: error instanceof Error ? error.message - : "Unknown error removing project.", + : "Removing the project didn't go through. Try again.", }), ); } })().catch((error) => { const message = - error instanceof Error ? error.message : "Unknown error removing project."; + error instanceof Error + ? error.message + : "Removing the project didn't go through. Try again."; console.error("Failed to remove project", { projectId: member.id, environmentId: member.environmentId, @@ -1533,7 +1556,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: `Failed to remove "${member.title}"`, + title: `Couldn't remove "${member.title}"`, description: message, }), ); @@ -1559,7 +1582,10 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec const result = await removeProject(member); if (result._tag === "Failure" && !isAtomCommandInterrupted(result)) { const error = squashAtomCommandFailure(result); - const message = error instanceof Error ? error.message : "Unknown error removing project."; + const message = + error instanceof Error + ? error.message + : "Removing the project didn't go through. Try again."; console.error("Failed to remove project", { projectId: member.id, environmentId: member.environmentId, @@ -1568,7 +1594,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: `Failed to remove "${member.title}"`, + title: `Couldn't remove "${member.title}"`, description: message, }), ); @@ -1655,7 +1681,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec const clicked = await api.contextMenu.show( [ buildTargetedItem("rename", "Rename"), - buildTargetedItem("grouping", "Group into..."), + buildTargetedItem("grouping", "Group into…"), buildTargetedItem("copy-path", "Copy Path"), buildTargetedItem("delete", "Remove", { destructive: true, @@ -1803,8 +1829,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Thread archived, but navigation failed", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Thread archived, but couldn't open the next one", + description: + error instanceof Error ? error.message : "Pick another thread from the sidebar.", }), ); } @@ -1815,8 +1842,11 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to archive threads", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't archive threads", + description: + error instanceof Error + ? error.message + : "Archiving didn't go through. Try again.", }), ); } @@ -1849,8 +1879,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to delete threads", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't delete threads", + description: + error instanceof Error ? error.message : "Deleting didn't go through. Try again.", }), ); } @@ -1886,8 +1917,11 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Could not create thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't create thread", + description: + error instanceof Error + ? error.message + : "Creating the thread didn't go through. Try again.", }), ); } @@ -1928,8 +1962,11 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Could not choose environment", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't open the environment picker", + description: + error instanceof Error + ? error.message + : "Opening the picker didn't go through. Try again.", }), ); return; @@ -1958,8 +1995,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to archive thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't archive thread", + description: + error instanceof Error ? error.message : "Archiving didn't go through. Try again.", }), ); } @@ -2014,8 +2052,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to rename thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't rename thread", + description: + error instanceof Error ? error.message : "Renaming didn't go through. Try again.", }), ); } @@ -2062,8 +2101,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to rename project", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't rename project", + description: + error instanceof Error ? error.message : "Renaming didn't go through. Try again.", }), ); } @@ -2142,8 +2182,11 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Could not create thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't create thread", + description: + error instanceof Error + ? error.message + : "Creating the thread didn't go through. Try again.", }), ); } @@ -2195,8 +2238,9 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to delete thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't delete thread", + description: + error instanceof Error ? error.message : "Deleting didn't go through. Try again.", }), ); } @@ -2220,7 +2264,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec } > @@ -2247,13 +2291,13 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec }`} /> - + {projectStatus.label} ) : ( @@ -2264,7 +2308,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec {project.displayName} {project.groupedProjectCount > 1 ? ( - + {project.groupedProjectCount} projects ) : null} @@ -2283,7 +2327,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec ? "Local sandbox project" : "Remote project" } - className="pointer-events-none absolute top-1 right-1.5 inline-flex size-5 items-center justify-center rounded-md text-muted-foreground/60 transition-opacity duration-150 max-sm:right-7 group-hover/project-header:opacity-0 group-focus-within/project-header:opacity-0 max-sm:group-hover/project-header:opacity-100 max-sm:group-focus-within/project-header:opacity-100" + className="pointer-events-none absolute top-1 end-1.5 inline-flex size-5 items-center justify-center rounded-md text-muted-foreground transition-opacity duration-150 max-sm:end-7 group-hover/project-header:opacity-0 group-focus-within/project-header:opacity-0 max-sm:group-hover/project-header:opacity-100 max-sm:group-focus-within/project-header:opacity-100" /> } > @@ -2303,7 +2347,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec +
@@ -449,38 +453,37 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { ? { label: "Working", icon: "working" as const, - className: - "animate-sidebar-working-text text-sky-600 motion-reduce:animate-none dark:text-sky-400", + className: "animate-sidebar-working-text text-info-foreground motion-reduce:animate-none", } : status === "approval" ? { label: "Approval", icon: null, - className: "text-amber-700 dark:text-amber-300", + className: "text-warning-foreground", } : status === "input" ? { label: "Input", icon: null, - className: "text-indigo-600 dark:text-indigo-300", + className: "text-pending-foreground", } : status === "failed" ? { label: "Failed", icon: null, - className: "text-red-700 dark:text-red-300", + className: "text-destructive-foreground", } : isWoke ? { label: "Woke", icon: "woke" as const, - className: "text-amber-700 dark:text-amber-300", + className: "text-warning-foreground", } : isUnread ? { label: "Done", icon: "done" as const, - className: "text-emerald-700 dark:text-emerald-300", + className: "text-success-foreground", } : null; @@ -552,14 +555,24 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { }, [onContextMenu, threadRef], ); - const handleKeyDown = useCallback( - (event: ReactKeyboardEvent) => { - if (event.target !== event.currentTarget) return; - if (event.key !== "Enter" && event.key !== " ") return; - event.preventDefault(); - onThreadActivate(threadRef); - }, - [onThreadActivate, threadRef], + const handleActivate = useCallback(() => { + onThreadActivate(threadRef); + }, [onThreadActivate, threadRef]); + /** + * The row itself cannot be `role="button"`: it contains its own buttons (PR + * link, settle, snooze), and a button role forces its children to be + * presentational, so assistive tech flattens them away. Instead the row stays + * a plain container for mouse interaction and this overlay carries the row's + * own operability. `pointer-events-none` keeps every mouse path byte-identical + * to before — the overlay is reachable by Tab and Enter/Space only. + */ + const activateOverlay = ( + @@ -815,7 +826,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { type="button" aria-label="Un-settle thread" onClick={handleUnsettleClick} - className="absolute inset-y-0 right-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover/v2-row:opacity-100" + className="absolute inset-y-0 end-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover/v2-row:opacity-100" > @@ -824,7 +835,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { type="button" aria-label="Settle thread" onClick={handleSettleClick} - className="absolute inset-y-0 right-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover/v2-row:opacity-100" + className="absolute inset-y-0 end-0 inline-flex cursor-pointer items-center gap-1 rounded-md bg-transparent px-2 text-xs text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover/v2-row:opacity-100" > @@ -849,18 +860,16 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { } > -
+ {activateOverlay} +
@@ -879,10 +888,10 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { ) : ( )} - + @@ -917,7 +926,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { {props.settlementSupported || showSnoozeButton ? ( @@ -944,7 +953,7 @@ const SidebarV2Row = memo(function SidebarV2Row(props: {
{title}
-
+
{thread.branch ? ( {thread.branch} ) : ( @@ -953,16 +962,16 @@ const SidebarV2Row = memo(function SidebarV2Row(props: { {prBadge} {diff ? ( - +{diff.insertions}{" "} - −{diff.deletions} + +{diff.insertions}{" "} + −{diff.deletions} ) : null} {isRemote ? ( - + ) : null} @@ -1030,8 +1039,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to copy path", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't copy path", + description: + error instanceof Error + ? error.message + : "Copying the path didn't go through. Try again.", }), ); }, @@ -1279,8 +1291,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: `Failed to remove "${project.title}"`, - description: error instanceof Error ? error.message : "An error occurred.", + title: `Couldn't remove "${project.title}"`, + description: + error instanceof Error + ? error.message + : "Removing the project didn't go through. Try again.", }), ); } @@ -1321,8 +1336,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to rename project", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't rename project", + description: + error instanceof Error + ? error.message + : "Renaming the project didn't go through. Try again.", }), ); } @@ -1621,8 +1639,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to rename thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't rename thread", + description: + error instanceof Error + ? error.message + : "Renaming the thread didn't go through. Try again.", }), ); } @@ -1703,8 +1724,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to settle thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't settle thread", + description: + error instanceof Error + ? error.message + : "Settling the thread didn't go through. Try again.", }), ); } @@ -1731,8 +1755,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to un-settle thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't un-settle thread", + description: + error instanceof Error + ? error.message + : "Un-settling the thread didn't go through. Try again.", }), ); } @@ -1749,8 +1776,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to wake thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't wake thread", + description: + error instanceof Error + ? error.message + : "Waking the thread didn't go through. Try again.", }), ); } @@ -1782,8 +1812,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to snooze thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't snooze thread", + description: + error instanceof Error + ? error.message + : "Snoozing the thread didn't go through. Try again.", }), ); } @@ -1933,8 +1966,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to delete threads", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't delete threads", + description: + error instanceof Error + ? error.message + : "Deleting the threads didn't go through. Try again.", }), ); } @@ -2047,8 +2083,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Could not create thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't create thread", + description: + error instanceof Error + ? error.message + : "Creating the thread didn't go through. Try again.", }), ); } @@ -2087,8 +2126,11 @@ export default function SidebarV2() { toastManager.add( stackedThreadToast({ type: "error", - title: "Failed to delete thread", - description: error instanceof Error ? error.message : "An error occurred.", + title: "Couldn't delete thread", + description: + error instanceof Error + ? error.message + : "Deleting the thread didn't go through. Try again.", }), ); return; @@ -2229,10 +2271,10 @@ export default function SidebarV2() { /> } > - -
Search
+ +
Search
{commandPaletteShortcutLabel ? ( - + {commandPaletteShortcutLabel} ) : null} @@ -2252,9 +2294,9 @@ export default function SidebarV2() { /> } > - +
) : null} - + {/* The stable scrollbar gutter already reserves 6px on the end side, so + the end padding is trimmed to keep rows optically centered in the rail. */} + - + {snoozedShelfExpanded ? "Snoozed" : `Snoozed (${snoozedThreads.length})`} - + @@ -2493,16 +2537,16 @@ export default function SidebarV2() { onClick={toggleSettledShelf} aria-expanded={settledShelfExpanded} data-testid="sidebar-v2-settled-shelf-toggle" - className="mb-1 mt-3 flex w-full cursor-pointer items-center gap-2 px-2.5 text-left" + className="mb-1 mt-3 flex w-full cursor-pointer items-center gap-2 px-2 text-start" > - + {settledShelfExpanded ? "Settled" : `Settled (${settledThreads.length})`} @@ -2520,26 +2564,32 @@ export default function SidebarV2() { ) : null} {activeThreads.length + snoozedThreads.length + settledThreads.length === 0 ? ( -
+
{projects.length === 0 ? ( <> No projects yet

{member.workspaceRoot}

-
+
-
+
@@ -158,7 +158,7 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: { /> ) : compactPreviewVisible ? (
-

+

{scopeSummary.map((scope, index) => ( {index > 0 ? : null} @@ -175,21 +175,21 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: { key={file.path} type="button" title={file.path} - className="inline-flex max-w-48 items-center gap-1 rounded-md border border-border/70 bg-background/45 px-1.5 py-1 font-mono text-[10px] text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" + className="inline-flex max-w-48 items-center gap-1 rounded-md border border-border/70 bg-background/45 px-1.5 py-1 font-mono text-2xs text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" onClick={() => onOpenTurnDiff(turnId, file.path)} > {changedFileName(file.path)} ))} ) : ( -

+
{image.name}
)} @@ -2514,7 +2516,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) @@ -2532,7 +2534,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) ) : ( - + )} -
+
{annotation.comment.trim() ? (

{annotation.comment.trim()} @@ -84,13 +84,13 @@ export function ComposerPreviewAnnotationCards({ {elementLabels.slice(0, 2).map(({ id, label }) => ( {label} ))} {elementLabels.length > 2 ? ( - + +{elementLabels.length - 2} ) : null} @@ -131,7 +131,7 @@ export function ComposerPreviewAnnotationCards({ diff --git a/apps/web/src/components/chat/ExpandedImageDialog.tsx b/apps/web/src/components/chat/ExpandedImageDialog.tsx index fd14c68b0c4d7..132dc7ee13810 100644 --- a/apps/web/src/components/chat/ExpandedImageDialog.tsx +++ b/apps/web/src/components/chat/ExpandedImageDialog.tsx @@ -64,7 +64,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ type="button" size="icon" variant="ghost" - className="absolute left-2 top-1/2 z-20 -translate-y-1/2 text-white/90 hover:bg-white/10 hover:text-white sm:left-6" + className="absolute start-2 top-1/2 z-20 -translate-y-1/2 text-white/90 hover:bg-white/10 hover:text-white sm:start-6" aria-label="Previous image" onClick={() => navigateImage(-1)} > @@ -76,7 +76,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ type="button" size="icon-xs" variant="ghost" - className="absolute right-2 top-2" + className="absolute end-2 top-2" onClick={onClose} aria-label="Close image preview" > @@ -85,10 +85,10 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ {item.name} -

+

{item.name} {preview.images.length > 1 ? ` (${index + 1}/${preview.images.length})` : ""}

@@ -98,7 +98,7 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({ type="button" size="icon" variant="ghost" - className="absolute right-2 top-1/2 z-20 -translate-y-1/2 text-white/90 hover:bg-white/10 hover:text-white sm:right-6" + className="absolute end-2 top-1/2 z-20 -translate-y-1/2 text-white/90 hover:bg-white/10 hover:text-white sm:end-6" aria-label="Next image" onClick={() => navigateImage(1)} > diff --git a/apps/web/src/components/chat/MessageCopyButton.tsx b/apps/web/src/components/chat/MessageCopyButton.tsx index e6a6a491bb331..625967d31592b 100644 --- a/apps/web/src/components/chat/MessageCopyButton.tsx +++ b/apps/web/src/components/chat/MessageCopyButton.tsx @@ -32,7 +32,7 @@ const onCopyError = (ref: React.RefObject, error: Erro anchor: ref.current, }, timeout: ANCHORED_TOAST_TIMEOUT_MS, - title: "Failed to copy", + title: "Couldn't copy", description: error.message, }); } diff --git a/apps/web/src/components/chat/MessagesTimeline.tsx b/apps/web/src/components/chat/MessagesTimeline.tsx index a429b54deaf10..ab2b4d3d3d347 100644 --- a/apps/web/src/components/chat/MessagesTimeline.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.tsx @@ -473,7 +473,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ } return (
-

+

Send a message to start the conversation.

@@ -694,7 +694,7 @@ function TimelineMinimap({ return (