1import { File, type FileOptions, Virtualizer } from "@pierre/diffs/react";
2
3import { DiffWorkerPoolProvider } from "~/components/DiffWorkerPoolProvider";
4import { useClientSettings } from "~/hooks/useSettings";
5import { useTheme } from "~/hooks/useTheme";
6import { resolveDiffThemeName } from "~/lib/diffRendering";
7import { PREFERRED_HIGHLIGHTER } from "~/lib/syntaxHighlighting";
8
9import { FILE_LINK_REVEAL_UNSAFE_CSS } from "./fileSurfaceChrome";
10
11/**
12 * Highlighted source for files that cannot be edited: captured attachments,
13 * host files outside the workspace and truncated reads. Same surface theme,
14 * word-wrap preference and virtualization as the editable workspace file.
15 */
16export default function ReadOnlySourcePreview(props: {
17 readonly name: string;
18 readonly text: string;
19 readonly cacheKey?: string;
20 readonly onPostRender?: FileOptions<unknown, undefined>["onPostRender"];
21}) {
22 const { resolvedTheme } = useTheme();
23 const wordWrap = useClientSettings((settings) => settings.wordWrap);
24 return (
25 <DiffWorkerPoolProvider>
26 <Virtualizer
27 key={`${props.name}:${resolvedTheme}:${props.text.length}`}
28 className="file-preview-virtualizer min-h-0 flex-1 overflow-auto"
29 config={{ overscrollSize: 600, intersectionObserverMargin: 1200 }}
30 >
31 <File
32 file={{
33 name: props.name,
34 contents: props.text,
35 ...(props.cacheKey ? { cacheKey: props.cacheKey } : {}),
36 }}
37 options={{
38 disableFileHeader: true,
39 overflow: wordWrap ? "wrap" : "scroll",
40 theme: resolveDiffThemeName(resolvedTheme),
41 preferredHighlighter: PREFERRED_HIGHLIGHTER,
42 themeType: resolvedTheme,
43 unsafeCSS: FILE_LINK_REVEAL_UNSAFE_CSS,
44 ...(props.onPostRender ? { onPostRender: props.onPostRender } : {}),
45 }}
46 className="min-h-full"
47 />
48 </Virtualizer>
49 </DiffWorkerPoolProvider>
50 );
51}