authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-11 19:34:57-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-11 19:34:57-03:00
log0eaa18c12936dffde078b277be91cbafa5758cb9
tree511bfbd1ce14e686933d15114f704bc1449ad054
parentb3ed07fb39fb795b9d2c74644e4b0a7f12392ad5
signature Signed by PGP key B5690EEEBB952194

feat(web): show recording status on floating previews (#11312)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

1 files changed, 28 insertions(+), 3 deletions(-)

apps/web/src/components/preview/ThreadPreviewMiniPlayer.tsx+28-3
......@@ -12,6 +12,10 @@ import {
1212} from "react";
1313
1414import { BrowserSurfaceSlot } from "~/browser/BrowserSurfaceSlot";
15import {
16 findActiveBrowserRecordingRuntimeTabId,
17 useActiveBrowserRecordingTabIds,
18} from "~/browser/browserRecording";
1519import { useBrowserSurfaceStore } from "~/browser/browserSurfaceStore";
1620import type { BrowserViewportResizeDirection } from "~/browser/browserViewportLayout";
1721import { previewRuntimeTabId } from "~/browser/previewRuntimeTabId";
......@@ -151,6 +155,10 @@ function BrowserMiniPlayer({
151155 const previewState = useThreadPreviewState(threadRef);
152156 const snapshot = previewState.sessions[tabId] ?? null;
153157 const runtimeTabId = previewRuntimeTabId(threadRef, previewState.serverEpoch, tabId);
158 const recordingTabIds = useActiveBrowserRecordingTabIds();
159 const recording =
160 recordingTabIds.has(runtimeTabId) ||
161 findActiveBrowserRecordingRuntimeTabId(threadRef, tabId) !== null;
154162 const desktopOverlay = previewState.desktopByTabId[tabId] ?? null;
155163 const fittedSourceContent = useBrowserSurfaceStore(
156164 (state) => state.byTabId[runtimeTabId]?.fittedSourceContent ?? null,
......@@ -189,6 +197,7 @@ function BrowserMiniPlayer({
189197 sourceSize={sourceSize}
190198 composerOverlayElement={composerOverlayElement}
191199 label="Floating browser preview"
200 recording={recording}
192201 onOpenInPanel={openInPanel}
193202 pillActions={
194203 <Tooltip>
......@@ -314,6 +323,7 @@ function MiniPlayerShell({
314323 label,
315324 onOpenInPanel,
316325 pillActions,
326 recording = false,
317327 cornerRadius = frameCornerRadius,
318328 children,
319329}: {
......@@ -324,6 +334,7 @@ function MiniPlayerShell({
324334 readonly label: string;
325335 readonly onOpenInPanel: () => void;
326336 readonly pillActions?: ReactNode;
337 readonly recording?: boolean;
327338 /** The clip radius for a given frame; the pill stays inside the curve. */
328339 readonly cornerRadius?: (frame: PreviewMiniPlayerSize) => number;
329340 readonly children: (frame: PreviewMiniPlayerFrame) => ReactNode;
......@@ -443,9 +454,18 @@ function MiniPlayerShell({
443454 style={{ right: pillInset, top: pillInset }}
444455 >
445456 <div
446 aria-hidden="true"
447 className="absolute right-0 top-0 size-2 rounded-full bg-foreground/25 shadow-sm ring-1 ring-background/70 transition-opacity group-hover:opacity-0 group-focus-within:opacity-0"
448 />
457 role={recording ? "status" : undefined}
458 aria-label={recording ? "Recording preview" : undefined}
459 aria-hidden={!recording}
460 className="absolute right-0 top-0 size-2 transition-opacity group-hover:opacity-0 group-focus-within:opacity-0"
461 >
462 <span
463 className={cn(
464 "block size-2 rounded-full shadow-sm ring-1 ring-background/70",
465 recording ? "bg-red-500 motion-safe:animate-status-pulse" : "bg-foreground/25",
466 )}
467 />
468 </div>
449469 <div
450470 className="pointer-events-none absolute right-0 top-0 flex h-8 cursor-grab items-center gap-0.5 rounded-lg border border-border/80 bg-popover/92 p-0.5 opacity-0 shadow-lg/20 backdrop-blur-xl transition-opacity group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100 active:cursor-grabbing"
451471 onPointerDown={(event) => beginGesture(event, null)}
......@@ -453,6 +473,11 @@ function MiniPlayerShell({
453473 onPointerUp={endGesture}
454474 onPointerCancel={endGesture}
455475 >
476 {recording ? (
477 <span aria-hidden className="flex size-6 shrink-0 items-center justify-center">
478 <span className="size-2 rounded-full bg-red-500 motion-safe:animate-status-pulse" />
479 </span>
480 ) : null}
456481 <Tooltip>
457482 <TooltipTrigger
458483 render={