Skip to content
File

Blob: src/client/pages/BlobPage.tsx

typescript149 lines
1import { Breadcrumbs } from "@/client/components/Breadcrumbs";
2import { CodeViewer } from "@/client/components/CodeViewer";
3import { MarkdownContent } from "@/client/components/MarkdownContent";
4import { RepoNav } from "@/client/components/RepoNav";
5import { BlobActionsIsland } from "@/client/islands/blob-actions";
6import { IslandHost } from "@/client/server/IslandHost";
7 
8type BreadcrumbItem = {
9 name: string;
10 href: string | null;
11};
12 
13export type BlobPageProps = {
14 owner: string;
15 repo: string;
16 refEnc: string;
17 fileName: string;
18 codeLang?: string | null;
19 lineCount?: number;
20 sizeStr?: string;
21 viewRawHref: string;
22 rawHref: string;
23 tooLarge?: boolean;
24 isImage?: boolean;
25 isPdf?: boolean;
26 mediaSrc?: string;
27 isMarkdown?: boolean;
28 markdownRaw?: string;
29 mdOwner?: string;
30 mdRepo?: string;
31 mdRef?: string;
32 mdBase?: string;
33 isBinary?: boolean;
34 codeText?: string;
35 breadcrumbs?: BreadcrumbItem[];
36 parentHref?: string | null;
37};
38 
39export function BlobPage(props: BlobPageProps) {
40 const {
41 owner,
42 repo,
43 refEnc,
44 fileName,
45 codeLang,
46 lineCount,
47 sizeStr,
48 viewRawHref,
49 rawHref,
50 tooLarge,
51 isImage,
52 isPdf,
53 mediaSrc,
54 isMarkdown,
55 markdownRaw,
56 mdOwner,
57 mdRepo,
58 mdRef,
59 mdBase,
60 isBinary,
61 codeText,
62 breadcrumbs,
63 parentHref,
64 } = props;
65 
66 const showCopy = !isMarkdown && !isImage && !isPdf && !isBinary && !tooLarge;
67 
68 return (
69 <div>
70 <RepoNav owner={owner} repo={repo} refEnc={refEnc} currentTab="browse" />
71 <span className="mb-1 inline-block text-xs font-semibold uppercase tracking-wider text-accent-500 dark:text-accent-400">
72 File
73 </span>
74 <h2 className="font-display tracking-tight">Blob: {fileName}</h2>
75 <Breadcrumbs items={breadcrumbs} parentHref={parentHref} />
76 <div className="blob-container mt-4 rounded-2xl border border-zinc-200 bg-zinc-50 dark:border-zinc-800/60 dark:bg-zinc-900/50">
77 <div className="flex items-center justify-between border-b border-zinc-200 px-3 py-2 dark:border-zinc-800/60">
78 <div className="flex items-center gap-2 text-xs text-zinc-600 dark:text-zinc-400">
79 {codeLang ? (
80 <span className="inline-flex items-center rounded-lg border border-zinc-300 bg-zinc-50 px-2 py-0.5 dark:border-zinc-700 dark:bg-zinc-800/50">
81 {codeLang}
82 </span>
83 ) : null}
84 {isMarkdown ? (
85 <span className="inline-flex items-center rounded-lg border border-zinc-300 bg-zinc-50 px-2 py-0.5 dark:border-zinc-700 dark:bg-zinc-800/50">
86 Markdown
87 </span>
88 ) : null}
89 {isMarkdown || codeLang ? (
90 lineCount ? (
91 <span className="text-zinc-500 dark:text-zinc-400">
92 {lineCount} line{lineCount === 1 ? "" : "s"}
93 </span>
94 ) : null
95 ) : sizeStr ? (
96 <span className="text-zinc-500 dark:text-zinc-400">{sizeStr}</span>
97 ) : null}
98 </div>
99 <IslandHost
100 name="blob-actions"
101 props={{ viewRawHref, rawHref, showCopy, isImage, isPdf }}
102 className="flex items-center gap-2"
103 >
104 <BlobActionsIsland
105 viewRawHref={viewRawHref}
106 rawHref={rawHref}
107 showCopy={showCopy}
108 isImage={isImage}
109 isPdf={isPdf}
110 />
111 </IslandHost>
112 </div>
113 <div className={`${isMarkdown ? "p-5" : isBinary || tooLarge ? "p-3" : "p-1"}`}>
114 {tooLarge ? (
115 <div className="text-zinc-500 dark:text-zinc-400">File too large to preview.</div>
116 ) : null}
117 {!tooLarge && isImage && mediaSrc ? (
118 <div className="flex items-center justify-center">
119 <img src={mediaSrc} alt={fileName} className="max-w-full rounded-md" loading="lazy" />
120 </div>
121 ) : null}
122 {!tooLarge && isPdf && mediaSrc ? (
123 <div className="w-full" style={{ height: "75vh" }}>
124 <iframe
125 src={mediaSrc}
126 className="h-full w-full rounded-md"
127 title={fileName}
128 loading="lazy"
129 ></iframe>
130 </div>
131 ) : null}
132 {!tooLarge && isMarkdown && markdownRaw && mdOwner && mdRepo && mdRef ? (
133 <MarkdownContent
134 markdown={markdownRaw}
135 context={{ owner: mdOwner, repo: mdRepo, ref: mdRef, baseDir: mdBase || "" }}
136 />
137 ) : null}
138 {!tooLarge && isBinary && !isImage && !isPdf ? (
139 <div className="text-zinc-500 dark:text-zinc-400">Binary file.</div>
140 ) : null}
141 {!tooLarge && !isBinary && !isMarkdown && codeText !== undefined ? (
142 <CodeViewer code={codeText} language={codeLang || null} />
143 ) : null}
144 </div>
145 </div>
146 </div>
147 );
148}