@@ -3,7 +3,7 @@ import { type FormEvent, useEffect, useLayoutEffect, useRef, useState } from "re
33import {
44 CircleAlertIcon ,
55 ExternalLinkIcon ,
6- GlobeIcon ,
6+ EllipsisIcon ,
77 LoaderCircleIcon ,
88 RefreshCwIcon ,
99 XIcon ,
@@ -16,6 +16,7 @@ import { usePreviewStateStore } from "~/previewStateStore";
1616
1717import { Button } from "./ui/button" ;
1818import { Input } from "./ui/input" ;
19+ import { Menu , MenuItem , MenuPopup , MenuTrigger } from "./ui/menu" ;
1920
2021const CLOSED_PREVIEW_STATE : DesktopPreviewState = {
2122 status : "closed" ,
@@ -244,46 +245,59 @@ export function PreviewPanel({ threadId, projectId, projectName, onClose }: Prev
244245
245246 return (
246247 < div className = "flex h-full min-w-0 flex-col bg-background" >
247- < div className = "flex items-center gap-2 border-b border-border px-3 py-3" >
248- < div className = "flex min-w-0 flex-1 items-center gap-2" >
249- < GlobeIcon className = "size-4 shrink-0 text-muted-foreground/70" />
250- < div className = "min-w-0" >
251- < p className = "truncate text-sm font-medium text-foreground" > Preview</ p >
252- < p className = "truncate text-xs text-muted-foreground/70" > { projectName } </ p >
253- </ div >
254- </ div >
255- < Button
256- type = "button"
257- size = "icon-xs"
258- variant = "ghost"
259- aria-label = "Reload preview"
260- onClick = { ( ) => {
261- setInputError ( null ) ;
262- void previewBridge ?. reload ( ) ;
263- } }
264- disabled = { ! showEmbeddedSurface }
265- >
266- < RefreshCwIcon className = "size-3.5" />
267- </ Button >
268- < Button
269- type = "button"
270- size = "icon-xs"
271- variant = "ghost"
272- aria-label = "Open preview externally"
273- onClick = { onOpenExternal }
274- disabled = { ! previewState . url && storedUrl . trim ( ) . length === 0 }
248+ < div className = "flex items-center justify-between gap-2 border-b border-border/60 px-3 py-2" >
249+ < p
250+ className = "truncate text-[11px] font-medium uppercase tracking-[0.18em] text-muted-foreground/75"
251+ title = { projectName }
275252 >
276- < ExternalLinkIcon className = "size-3.5" />
277- </ Button >
278- < Button
279- type = "button"
280- size = "icon-xs"
281- variant = "ghost"
282- aria-label = "Close preview"
283- onClick = { onClosePreview }
284- >
285- < XIcon className = "size-3.5" />
286- </ Button >
253+ Preview
254+ </ p >
255+ < div className = "flex items-center gap-1" >
256+ < Menu >
257+ < MenuTrigger
258+ render = {
259+ < Button
260+ type = "button"
261+ size = "icon-xs"
262+ variant = "ghost"
263+ className = "text-muted-foreground/55 hover:text-foreground"
264+ aria-label = "Preview actions"
265+ />
266+ }
267+ >
268+ < EllipsisIcon aria-hidden = "true" className = "size-3.5" />
269+ </ MenuTrigger >
270+ < MenuPopup align = "end" >
271+ < MenuItem
272+ onClick = { ( ) => {
273+ setInputError ( null ) ;
274+ void previewBridge ?. reload ( ) ;
275+ } }
276+ disabled = { ! showEmbeddedSurface }
277+ >
278+ < RefreshCwIcon aria-hidden = "true" className = "size-4" />
279+ Reload
280+ </ MenuItem >
281+ < MenuItem
282+ onClick = { onOpenExternal }
283+ disabled = { ! previewState . url && storedUrl . trim ( ) . length === 0 }
284+ >
285+ < ExternalLinkIcon aria-hidden = "true" className = "size-4" />
286+ Open in browser
287+ </ MenuItem >
288+ </ MenuPopup >
289+ </ Menu >
290+ < Button
291+ type = "button"
292+ size = "icon-xs"
293+ variant = "ghost"
294+ className = "text-muted-foreground/55 hover:text-foreground"
295+ aria-label = "Close preview"
296+ onClick = { onClosePreview }
297+ >
298+ < XIcon className = "size-3.5" />
299+ </ Button >
300+ </ div >
287301 </ div >
288302
289303 < form className = "border-b border-border px-3 py-3" onSubmit = { onSubmit } >
0 commit comments