diff --git a/apps/web/src/components/chat/ComposerActivityStatus.tsx b/apps/web/src/components/chat/ComposerActivityStatus.tsx index 49d4bece350d..3d6f5b763b95 100644 --- a/apps/web/src/components/chat/ComposerActivityStatus.tsx +++ b/apps/web/src/components/chat/ComposerActivityStatus.tsx @@ -6,7 +6,7 @@ export function ComposerActivityRow({ phase }: { readonly phase: ThreadSyncPhase return ( - + ; + return ; } if (status === "failed") { return ; diff --git a/apps/web/src/components/chat/MessagesTimeline.test.tsx b/apps/web/src/components/chat/MessagesTimeline.test.tsx index 83a6719a6c10..7cb64023d0e4 100644 --- a/apps/web/src/components/chat/MessagesTimeline.test.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.test.tsx @@ -1203,7 +1203,7 @@ describe("MessagesTimeline", () => { expect(markup).not.toContain('aria-label="Hidden work includes a failure"'); }); - it("shows the animated one-line label for a live tool group", () => { + it("shows the one-line label for a live tool group", () => { const turnId = TurnId.make("turn-live"); const markup = renderToStaticMarkup( { expect(markup).toContain("Working for"); expect(markup).toContain("Running pnpm"); - expect(markup).toContain("live-activity-focus"); }); it("scopes a live row failure to the tool named by the row", () => { @@ -1358,7 +1357,6 @@ describe("MessagesTimeline", () => { expect(markup).toContain("Running pnpm"); expect(markup).toContain("lucide-terminal"); - expect(markup).toContain("live-activity-focus"); expect(markup).not.toContain("Ran pnpm"); expect(markup).not.toContain("Thinking"); expect(markup).not.toContain('data-timeline-row-kind="thinking"'); diff --git a/apps/web/src/components/chat/MessagesTimeline.tsx b/apps/web/src/components/chat/MessagesTimeline.tsx index 50dd76e99af2..035a37689873 100644 --- a/apps/web/src/components/chat/MessagesTimeline.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.tsx @@ -1614,17 +1614,9 @@ function WorkingTimelineRow({ row }: { row: Extract {isPreparingWorktree ? ( - <> - Setting up worktree… - Setting up worktree… - + "Setting up worktree…" ) : isCompacting ? ( - <> - - - - - + ) : row.createdAt ? ( <> Working for @@ -1878,19 +1870,6 @@ function ExpandedWorkGroupEntries({ const workEntryKey = (entry: TimelineWorkEntry) => entry.id; -function ActivityShimmerOverlay({ children }: { children: ReactNode }) { - return ( - - - {children} - - - ); -} - const failedToolIconClassName = "text-tool-error-icon/40"; /** Image icons and the gradient computer-use mark cannot take a currentColor @@ -1914,7 +1893,7 @@ function LiveActivityRow({ failed?: boolean; }) { return ( -
+
- - -
); } @@ -1941,14 +1911,12 @@ function LiveActivityContent({ toolIcon, failed = false, announceFailure = false, - highlighted = false, }: { label: string; iconName: WorkEntryIconName | undefined; toolIcon?: ToolActivityIcon | undefined; failed?: boolean; announceFailure?: boolean; - highlighted?: boolean; }) { const showTrailingFailureMark = failed && iconName !== undefined && !toolIconAcceptsTint(iconName, toolIcon); @@ -1958,14 +1926,14 @@ function LiveActivityContent({ className={cn( "flex min-h-6 min-w-0 items-center gap-1.5 py-0.5", iconName ? "px-0.5" : "px-1", - highlighted ? "text-foreground" : "text-secondary-label", + "text-secondary-label", )} > {iconName ? ( ) : null} {label} {showTrailingFailureMark ? ( - + ) : null} ); @@ -2002,24 +1967,12 @@ function LiveWorkEntryTimelineRow({ row }: { row: Extract ctx.onToggleWorkGroup(row.groupId, row.id)} > - {row.active ? ( - - ) : ( -
- -
- )} + ); } diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 63dc9e21c094..54bb5b70d5fa 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -425,80 +425,6 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil } } -@keyframes live-activity-focus { - 0% { - transform: translateX(0); - } - 100% { - transform: translateX(100%); - } -} - -@keyframes live-activity-focus-counter { - 0% { - transform: translateX(0); - } - 100% { - transform: translateX(-100%); - } -} - -@utility live-activity-focus { - --live-activity-focus-width: 4.5rem; - - right: auto; - left: calc(-1 * var(--live-activity-focus-width)); - width: calc(100% + var(--live-activity-focus-width) + var(--live-activity-focus-width)); - -webkit-mask-image: linear-gradient( - to right, - transparent 0, - rgb(0 0 0 / 12%) 0.675rem, - rgb(0 0 0 / 55%) 1.575rem, - black 2.25rem, - rgb(0 0 0 / 55%) 2.925rem, - rgb(0 0 0 / 12%) 3.825rem, - transparent var(--live-activity-focus-width), - transparent 100% - ); - -webkit-mask-repeat: no-repeat; - mask-image: linear-gradient( - to right, - transparent 0, - rgb(0 0 0 / 12%) 0.675rem, - rgb(0 0 0 / 55%) 1.575rem, - black 2.25rem, - rgb(0 0 0 / 55%) 2.925rem, - rgb(0 0 0 / 12%) 3.825rem, - transparent var(--live-activity-focus-width), - transparent 100% - ); - mask-repeat: no-repeat; - animation: live-activity-focus 2.2s linear infinite; - will-change: transform; - - @media (prefers-reduced-motion: reduce) { - animation: none; - opacity: 0; - will-change: auto; - } -} - -@utility live-activity-focus-counter { - width: 100%; - animation: live-activity-focus-counter 2.2s linear infinite; - will-change: transform; - - @media (prefers-reduced-motion: reduce) { - animation: none; - will-change: auto; - } -} - -@utility live-activity-focus-aligned { - width: calc(100% - var(--live-activity-focus-width) - var(--live-activity-focus-width)); - margin-left: var(--live-activity-focus-width); -} - @property --assistant-citation-highlight-opacity { syntax: ""; inherits: true; @@ -1906,24 +1832,6 @@ code { color: var(--code-foreground) !important; } -@keyframes ultrathink-rainbow { - 0% { - background-position: 0% 50%; - } - 100% { - background-position: 200% 50%; - } -} - -@keyframes ultrathink-chroma-shift { - 0% { - filter: hue-rotate(0deg) saturate(1.2); - } - 100% { - filter: hue-rotate(360deg) saturate(1.2); - } -} - .ultrathink-frame { --ultrathink-spectrum: linear-gradient( 120deg, @@ -1946,6 +1854,7 @@ code { padding: 2px; background-image: var(--ultrathink-spectrum); background-size: 220% 220%; + background-position: 0% 50%; pointer-events: none; filter: saturate(0.82) brightness(0.92); -webkit-mask: @@ -1956,7 +1865,6 @@ code { linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude; - animation: ultrathink-rainbow 10s linear infinite; } .ultrathink-frame > * { @@ -1964,7 +1872,7 @@ code { } .ultrathink-chroma { - animation: ultrathink-chroma-shift 10s linear infinite; + filter: saturate(1.2); } @keyframes preview-loading-progress { diff --git a/docs/user/composer.md b/docs/user/composer.md index 2e98a21f7198..f158eb8f185e 100644 --- a/docs/user/composer.md +++ b/docs/user/composer.md @@ -174,6 +174,8 @@ On web and desktop, loading and syncing statuses fill the available banner width stash tab. Task progress appears above the composer, while the timeline's working timer shows only elapsed time. +Loading, syncing, and server-update icons are static. Live tool labels do not shimmer. + On web and desktop, additional notices peek out above the attached banner. Hover over the peek to reveal them, or focus **Show other notices** with `Tab` and press `Enter` or `Space`. Press `Escape` to close the stack and return focus to that control. On a touchscreen, tap the peek to