| ... | @@ -44,6 +44,8 @@ interface Props { | ... | @@ -44,6 +44,8 @@ interface Props { |
| 44 | readonly bottomInset: number; | 44 | readonly bottomInset: number; |
| 45 | } | 45 | } |
| 46 | | 46 | |
| | 47 | const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12; |
| | 48 | |
| 47 | // Invisible grab zones straddling each edge; the cursor is the only affordance. | 49 | // Invisible grab zones straddling each edge; the cursor is the only affordance. |
| 48 | const RESIZE_HANDLES: ReadonlyArray<{ | 50 | const RESIZE_HANDLES: ReadonlyArray<{ |
| 49 | readonly direction: BrowserViewportResizeDirection; | 51 | readonly direction: BrowserViewportResizeDirection; |
| ... | @@ -59,6 +61,10 @@ const RESIZE_HANDLES: ReadonlyArray<{ | ... | @@ -59,6 +61,10 @@ const RESIZE_HANDLES: ReadonlyArray<{ |
| 59 | { direction: "southeast", className: "-bottom-2 -right-2 size-4 cursor-nwse-resize" }, | 61 | { direction: "southeast", className: "-bottom-2 -right-2 size-4 cursor-nwse-resize" }, |
| 60 | ]; | 62 | ]; |
| 61 | | 63 | |
| | 64 | /** |
| | 65 | * Floats the thread's browser surface over chat. Native clipping and the DOM |
| | 66 | * frame use the same radius so their separately composited edges stay aligned. |
| | 67 | */ |
| 62 | export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props) { | 68 | export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props) { |
| 63 | const containerRef = useRef<HTMLDivElement | null>(null); | 69 | const containerRef = useRef<HTMLDivElement | null>(null); |
| 64 | const gestureRef = useRef<PointerGesture | null>(null); | 70 | const gestureRef = useRef<PointerGesture | null>(null); |
| ... | @@ -193,7 +199,13 @@ export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props | ... | @@ -193,7 +199,13 @@ export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props |
| 193 | aria-label="Floating browser preview" | 199 | aria-label="Floating browser preview" |
| 194 | data-preview-mini-player={tabId} | 200 | data-preview-mini-player={tabId} |
| 195 | className="pointer-events-none absolute select-none" | 201 | className="pointer-events-none absolute select-none" |
| 196 | style={{ left: frame.x, top: frame.y, width: frame.width, height: frame.height }} | 202 | style={{ |
| | 203 | left: frame.x, |
| | 204 | top: frame.y, |
| | 205 | width: frame.width, |
| | 206 | height: frame.height, |
| | 207 | borderRadius: PREVIEW_MINI_PLAYER_CORNER_RADIUS, |
| | 208 | }} |
| 197 | > | 209 | > |
| 198 | <div className="group pointer-events-auto absolute right-2 top-2 z-[49] size-3"> | 210 | <div className="group pointer-events-auto absolute right-2 top-2 z-[49] size-3"> |
| 199 | <div | 211 | <div |
| ... | @@ -267,19 +279,19 @@ export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props | ... | @@ -267,19 +279,19 @@ export function ThreadPreviewMiniPlayer({ threadRef, tabId, bottomInset }: Props |
| 267 | </div> | 279 | </div> |
| 268 | </div> | 280 | </div> |
| 269 | | 281 | |
| 270 | <div className="absolute inset-0 z-[47] rounded-xl bg-muted shadow-2xl/35" /> | 282 | <div className="absolute inset-0 z-[47] rounded-[inherit] bg-muted shadow-2xl/35" /> |
| 271 | <BrowserSurfaceSlot | 283 | <BrowserSurfaceSlot |
| 272 | tabId={runtimeTabId} | 284 | tabId={runtimeTabId} |
| 273 | visible={Boolean(desktopOverlay?.hasWebContents)} | 285 | visible={Boolean(desktopOverlay?.hasWebContents)} |
| 274 | cornerRadius={12} | 286 | cornerRadius={PREVIEW_MINI_PLAYER_CORNER_RADIUS} |
| 275 | zIndex={PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX} | 287 | zIndex={PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX} |
| 276 | fitSourceContent | 288 | fitSourceContent |
| 277 | layoutVersion={`${frame.x}:${frame.y}`} | 289 | layoutVersion={`${frame.x}:${frame.y}`} |
| 278 | className="absolute inset-0" | 290 | className="absolute inset-0" |
| 279 | /> | 291 | /> |
| 280 | <div className="pointer-events-none absolute inset-0 z-[49] rounded-xl ring-1 ring-inset ring-border/80" /> | 292 | <div className="pointer-events-none absolute inset-0 z-[49] rounded-[inherit] ring-1 ring-inset ring-border/80" /> |
| 281 | {!desktopOverlay?.hasWebContents ? ( | 293 | {!desktopOverlay?.hasWebContents ? ( |
| 282 | <div className="pointer-events-none absolute inset-0 z-[49] flex items-center justify-center rounded-xl bg-muted text-xs text-muted-foreground"> | 294 | <div className="pointer-events-none absolute inset-0 z-[49] flex items-center justify-center rounded-[inherit] bg-muted text-xs text-muted-foreground"> |
| 283 | Reconnecting preview… | 295 | Reconnecting preview… |
| 284 | </div> | 296 | </div> |
| 285 | ) : null} | 297 | ) : null} |