1"use client";
2
3import {
4 AuthPreviewOperateScope,
5 type PreviewAnnotationPayload,
6 type ScopedThreadRef,
7} from "@t3tools/contracts";
8
9import type { ComposerImageAttachment } from "~/composerDraftStore";
10import { usePreviewAvailable } from "~/browser/previewRuntime";
11import { useEnvironmentScope } from "~/state/session";
12
13import { PreviewPanelShell, type PreviewPanelMode } from "./PreviewPanelShell";
14import { PreviewView } from "./PreviewView";
15
16interface Props {
17 mode: PreviewPanelMode;
18 threadRef: ScopedThreadRef;
19 tabId?: string | null;
20 configuredUrls?: ReadonlyArray<string> | undefined;
21 visible: boolean;
22 onSendAnnotation?: (
23 annotation: PreviewAnnotationPayload,
24 image: ComposerImageAttachment | null,
25 ) => void;
26}
27
28export function PreviewPanel({
29 mode,
30 threadRef,
31 tabId,
32 configuredUrls,
33 visible,
34 onSendAnnotation,
35}: Props) {
36 const available = usePreviewAvailable(threadRef.environmentId);
37 const canOperatePreview = useEnvironmentScope(threadRef.environmentId, AuthPreviewOperateScope);
38 if (!canOperatePreview || !available) {
39 return (
40 <PreviewPanelShell mode={mode}>
41 <div className="flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-8 text-center">
42 <p className="max-w-sm text-sm text-muted-foreground">
43 {canOperatePreview
44 ? "Preview is only available in The Knife desktop app."
45 : "Pair this client again with preview access to control browser previews."}
46 </p>
47 </div>
48 </PreviewPanelShell>
49 );
50 }
51
52 return (
53 <PreviewPanelShell mode={mode}>
54 <PreviewView
55 threadRef={threadRef}
56 {...(tabId !== undefined ? { tabId } : {})}
57 configuredUrls={configuredUrls}
58 visible={visible}
59 {...(onSendAnnotation ? { onSendAnnotation } : {})}
60 />
61 </PreviewPanelShell>
62 );
63}