annotate hg-web/src/components/directory-browser.tsx @ 198:008ca7780c8a

S3 upload got it to work.
author MrJuneJune <me@mrjunejune.com>
date Sat, 14 Feb 2026 16:18:14 -0800
parents 9f4429c49733
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
193
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 import React, { useState, useEffect, useRef, useCallback } from 'react';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2 import createMarkdownModule from 'markdown_converter/markdown_to_html_wasm/markdown_to_html_bin.js';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 import hljs from 'third_party/highlight/highlight.min.js';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5 // --- ICONS (served as static files) ---
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 const ICONS = {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7 folder: "/icons/folder.png",
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 file: "/icons/file.svg",
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 close: "/icons/close.png"
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 const API_BASE = '/api/repo';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 // File extensions that should be displayed as code
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 const CODE_EXTENSIONS = new Set([
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 'js', 'jsx', 'ts', 'tsx', 'py', 'rb', 'java', 'c', 'cpp', 'h', 'hpp',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 'cs', 'go', 'rs', 'swift', 'kt', 'scala', 'php', 'pl', 'sh', 'bash',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 'zsh', 'fish', 'ps1', 'bat', 'cmd', 'html', 'htm', 'css', 'scss',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19 'sass', 'less', 'json', 'xml', 'yaml', 'yml', 'toml', 'ini', 'cfg',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 'conf', 'md', 'markdown', 'txt', 'log', 'sql', 'graphql', 'vue',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 'svelte', 'astro', 'prisma', 'dockerfile', 'makefile', 'cmake',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 'gradle', 'pom', 'lock', 'gitignore', 'env', 'example', 'sample'
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 ]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 // Prefetch cache
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 const prefetchCache = new Map<string, Promise<any>>();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 function isCodeFile(filename: string): boolean {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 const ext = filename.split('.').pop()?.toLowerCase() || '';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 const basename = filename.toLowerCase();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 return CODE_EXTENSIONS.has(ext) ||
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32 CODE_EXTENSIONS.has(basename) ||
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 basename === 'dockerfile' ||
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 basename === 'makefile' ||
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 basename.startsWith('.');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 function isMarkdownFile(filename: string): boolean {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 const ext = filename.split('.').pop()?.toLowerCase() || '';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 return ext === 'md' || ext === 'markdown';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 function prefetchDirectory(path: string): void {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 const cacheKey = `dir:${path}`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 if (prefetchCache.has(cacheKey)) return;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 const url = path
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 ? `${API_BASE}/list?path=${encodeURIComponent(path)}`
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 : `${API_BASE}/list`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 prefetchCache.set(cacheKey, fetch(url).then(r => r.json()).catch(() => null));
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 function prefetchFile(path: string): void {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 const cacheKey = `file:${path}`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 if (prefetchCache.has(cacheKey)) return;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 prefetchCache.set(cacheKey,
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 fetch(`${API_BASE}/file?path=${encodeURIComponent(path)}`)
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 .then(r => r.ok ? r.text() : null)
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 .catch(() => null)
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 async function getCachedFile(path: string): Promise<string | null> {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66 const cacheKey = `file:${path}`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 if (prefetchCache.has(cacheKey)) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 return prefetchCache.get(cacheKey);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 prefetchFile(path);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71 return prefetchCache.get(cacheKey)!;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75 * Component: Breadcrumb
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
76 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
77 function Breadcrumb({ currentPath, onNavigate }: { currentPath: string; onNavigate: (path: string) => void }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 if (!currentPath) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80 <nav className="breadcrumb">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
81 <span className="nav-item active">root</span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
82 </nav>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
83 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
84 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
85
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
86 const parts = currentPath.split('/').filter(p => p);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
87 const crumbs = parts.map((part, index) => ({
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
88 name: part,
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
89 fullPath: parts.slice(0, index + 1).join('/')
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
90 }));
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
91
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
92 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
93 <nav className="breadcrumb">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
94 <a
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
95 href="#"
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
96 onClick={(e) => { e.preventDefault(); onNavigate(''); }}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
97 title="Go to Root"
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
98 >
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
99 root
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
100 </a>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
101 {crumbs.map((crumb, index) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
102 const isLast = index === crumbs.length - 1;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
103 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
104 <React.Fragment key={crumb.fullPath}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
105 <span className="separator">/</span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
106 {isLast ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
107 <span className="nav-item active">{crumb.name}</span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
108 ) : (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
109 <a
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
110 href="#"
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
111 onClick={(e) => { e.preventDefault(); onNavigate(crumb.fullPath); }}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
112 >
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
113 {crumb.name}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
114 </a>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
115 )}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
116 </React.Fragment>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
117 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
118 })}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
119 </nav>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
120 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
121 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
122
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
123 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
124 * Component: FileViewer
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
125 * Shows file content inline with syntax highlighting
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
126 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
127 function FileViewer({ filePath, onClose }: { filePath: string; onClose: () => void }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
128 const [content, setContent] = useState<string | null>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
129 const [loading, setLoading] = useState(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
130 const codeRef = useRef<HTMLElement>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
131
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
132 const filename = filePath.split('/').pop() || filePath;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
133
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
134 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
135 setLoading(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
136 getCachedFile(filePath).then((text) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
137 setContent(text);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
138 setLoading(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
139 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
140 }, [filePath]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
141
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
142 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
143 if (content && codeRef.current) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
144 hljs.highlightElement(codeRef.current);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
145 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
146 }, [content]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
147
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
148 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
149 const handleKeyDown = (e: KeyboardEvent) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
150 if (e.key === 'Escape') onClose();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
151 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
152 window.addEventListener('keydown', handleKeyDown);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
153 return () => window.removeEventListener('keydown', handleKeyDown);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
154 }, [onClose]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
155
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
156 const getLanguage = () => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
157 const ext = filename.split('.').pop()?.toLowerCase() || '';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
158 const langMap: Record<string, string> = {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
159 js: 'javascript', jsx: 'javascript', ts: 'typescript', tsx: 'typescript',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
160 py: 'python', rb: 'ruby', rs: 'rust', go: 'go', java: 'java',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
161 c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp', cs: 'csharp',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
162 sh: 'bash', bash: 'bash', zsh: 'bash', fish: 'bash',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
163 json: 'json', yaml: 'yaml', yml: 'yaml', toml: 'toml',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
164 html: 'html', htm: 'html', css: 'css', scss: 'scss', sass: 'scss',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
165 sql: 'sql', md: 'markdown', markdown: 'markdown', xml: 'xml',
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
166 dockerfile: 'dockerfile', makefile: 'makefile'
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
167 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
168 return langMap[ext] || 'plaintext';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
169 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
170
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
171 const addLineNumbers = (text: string) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
172 const lines = text.split('\n');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
173 return lines.map((_, i) => i + 1).join('\n');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
174 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
175
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
176 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
177 <div className="file-viewer-overlay" onClick={onClose}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
178 <div className="file-viewer" onClick={(e) => e.stopPropagation()}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
179 <div className="file-viewer-header">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
180 <span className="file-viewer-title">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
181 <img src={ICONS.file} alt="" style={{ width: 16, height: 16 }} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
182 {filename}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
183 </span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
184 <button className="file-viewer-close" onClick={onClose} title="Close (Esc)">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
185 <img className="icon-invert" src={ICONS.close} alt="Close" />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
186 </button>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
187 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
188 <div className="file-viewer-content">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
189 {loading ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
190 <div className="file-viewer-loading">Loading...</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
191 ) : content ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
192 <pre style={{ display: 'flex' }}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
193 <span className="file-viewer-line-numbers">{addLineNumbers(content)}</span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
194 <code ref={codeRef} className={`language-${getLanguage()}`}>{content}</code>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
195 </pre>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
196 ) : (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
197 <div className="file-viewer-loading">Unable to load file</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
198 )}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
199 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
200 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
201 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
202 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
203 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
204
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
205 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
206 * Component: MarkdownViewerModal
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
207 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
208 function MarkdownViewerModal({ filePath, onClose }: { filePath: string; onClose: () => void }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
209 const [content, setContent] = useState<string | null>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
210 const [loading, setLoading] = useState(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
211 const contentRef = useRef<HTMLDivElement>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
212 const moduleRef = useRef<any>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
213 const [wasmReady, setWasmReady] = useState(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
214
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
215 const filename = filePath.split('/').pop() || filePath;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
216
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
217 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
218 createMarkdownModule().then((Module: any) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
219 moduleRef.current = Module;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
220 setWasmReady(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
221 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
222 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
223
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
224 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
225 setLoading(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
226 getCachedFile(filePath).then((text) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
227 setContent(text);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
228 setLoading(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
229 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
230 }, [filePath]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
231
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
232 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
233 if (!content || !wasmReady || !contentRef.current || !moduleRef.current) return;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
234
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
235 const Module = moduleRef.current;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
236 const markdownToHtmlPtr = Module.cwrap('markdown_to_html', 'number', ['string']);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
237 const markdownFree = Module.cwrap('markdown_free', null, ['number']);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
238
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
239 const ptr = markdownToHtmlPtr(content);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
240 const html = Module.UTF8ToString(ptr);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
241 markdownFree(ptr);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
242 contentRef.current.innerHTML = html;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
243 }, [content, wasmReady]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
244
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
245 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
246 const handleKeyDown = (e: KeyboardEvent) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
247 if (e.key === 'Escape') onClose();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
248 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
249 window.addEventListener('keydown', handleKeyDown);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
250 return () => window.removeEventListener('keydown', handleKeyDown);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
251 }, [onClose]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
252
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
253 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
254 <div className="file-viewer-overlay" onClick={onClose}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
255 <div className="file-viewer" onClick={(e) => e.stopPropagation()}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
256 <div className="file-viewer-header">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
257 <span className="file-viewer-title">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
258 <img src={ICONS.file} alt="" style={{ width: 16, height: 16 }} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
259 {filename}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
260 </span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
261 <button className="file-viewer-close" onClick={onClose} title="Close (Esc)">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
262 <img className="icon-invert" src={ICONS.close} alt="Close" />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
263 </button>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
264 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
265 <div className="file-viewer-content">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
266 {loading || !wasmReady ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
267 <div className="file-viewer-loading">Loading...</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
268 ) : content ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
269 <div className="readme-content" ref={contentRef} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
270 ) : (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
271 <div className="file-viewer-loading">Unable to load file</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
272 )}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
273 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
274 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
275 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
276 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
277 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
278
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
279 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
280 * Component: FileList
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
281 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
282 function FileList({ directories, files, onNavigate, onOpenFile }: {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
283 directories: any[];
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
284 files: any[];
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
285 onNavigate: (path: string) => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
286 onOpenFile: (path: string) => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
287 }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
288 const isEmpty = directories.length === 0 && files.length === 0;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
289
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
290 if (isEmpty) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
291 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
292 <div className="file-list-container">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
293 <div className="empty-state">This directory is empty.</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
294 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
295 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
296 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
297
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
298 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
299 <div className="file-list-container">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
300 <div className="file-header">Files</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
301 <div id="fileListBody">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
302 {directories.map((dir) => (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
303 <FileRow
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
304 key={dir.abspath}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
305 item={dir}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
306 iconUrl={ICONS.folder}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
307 isDir={true}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
308 onNavigate={onNavigate}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
309 onOpenFile={onOpenFile}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
310 />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
311 ))}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
312 {files.map((file) => (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
313 <FileRow
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
314 key={file.abspath}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
315 item={file}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
316 iconUrl={ICONS.file}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
317 isDir={false}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
318 onNavigate={onNavigate}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
319 onOpenFile={onOpenFile}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
320 />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
321 ))}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
322 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
323 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
324 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
325 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
326
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
327 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
328 * Component: FileRow
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
329 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
330 function FileRow({ item, iconUrl, isDir, onNavigate, onOpenFile }: {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
331 item: { abspath: string; basename: string };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
332 iconUrl: string;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
333 isDir: boolean;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
334 onNavigate: (path: string) => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
335 onOpenFile: (path: string) => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
336 }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
337 const handleClick = (e: React.MouseEvent) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
338 e.preventDefault();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
339 if (isDir) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
340 onNavigate(item.abspath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
341 } else if (isCodeFile(item.basename)) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
342 onOpenFile(item.abspath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
343 } else {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
344 window.open(`/api/repo/file?path=${encodeURIComponent(item.abspath)}`, '_blank');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
345 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
346 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
347
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
348 const handleMouseEnter = () => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
349 if (isDir) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
350 prefetchDirectory(item.abspath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
351 } else if (isCodeFile(item.basename)) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
352 prefetchFile(item.abspath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
353 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
354 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
355
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
356 const href = isDir
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
357 ? `#`
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
358 : `/api/repo/file?path=${encodeURIComponent(item.abspath)}`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
359
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
360 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
361 <div className="file-row" onMouseEnter={handleMouseEnter}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
362 <span className="icon">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
363 <img className="icon-invert" src={iconUrl} alt={isDir ? "Directory" : "File"} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
364 </span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
365 <span className="name">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
366 <a href={href} onClick={handleClick}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
367 {item.basename}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
368 </a>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
369 </span>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
370 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
371 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
372 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
373
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
374 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
375 * Component: ReadmeViewer
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
376 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
377 function ReadmeViewer({ content }: { content: string | null }) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
378 const contentRef = useRef<HTMLDivElement>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
379 const moduleRef = useRef<any>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
380 const [wasmReady, setWasmReady] = useState(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
381
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
382 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
383 createMarkdownModule().then((Module: any) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
384 moduleRef.current = Module;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
385 setWasmReady(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
386 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
387 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
388
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
389 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
390 if (!content || !wasmReady || !contentRef.current || !moduleRef.current) return;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
391
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
392 const Module = moduleRef.current;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
393 const markdownToHtmlPtr = Module.cwrap('markdown_to_html', 'number', ['string']);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
394 const markdownFree = Module.cwrap('markdown_free', null, ['number']);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
395
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
396 const ptr = markdownToHtmlPtr(content);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
397 const html = Module.UTF8ToString(ptr);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
398 markdownFree(ptr);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
399 contentRef.current.innerHTML = html;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
400 }, [content, wasmReady]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
401
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
402 if (!content) return null;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
403
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
404 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
405 <div className="readme-section">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
406 <div className="readme-header">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
407 <img className="icon-invert" src={ICONS.file} width="16" alt="" style={{ opacity: 0.5 }} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
408 README.md
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
409 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
410 <div className="readme-content" ref={contentRef}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
411 {!wasmReady && 'Loading...'}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
412 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
413 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
414 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
415 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
416
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
417 /**
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
418 * Directory Browser Component (no header/footer - for embedding in app)
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
419 */
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
420 interface DirectoryBrowserProps {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
421 initialPath?: string;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
422 onPathChange?: (path: string) => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
423 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
424
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
425 function DirectoryBrowser({ initialPath = '', onPathChange }: DirectoryBrowserProps) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
426 const [currentPath, setCurrentPath] = useState(initialPath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
427 const [content, setContent] = useState<{ files: any[]; directories: any[] }>({ files: [], directories: [] });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
428 const [readme, setReadme] = useState<string | null>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
429 const [error, setError] = useState<string | null>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
430 const [loading, setLoading] = useState(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
431 const [viewingFile, setViewingFile] = useState<string | null>(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
432
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
433 // Sync with initialPath prop
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
434 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
435 setCurrentPath(initialPath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
436 }, [initialPath]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
437
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
438 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
439 fetchDirectory(currentPath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
440 fetchReadme(currentPath);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
441 }, [currentPath]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
442
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
443 const navigate = useCallback((path: string) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
444 setCurrentPath(path);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
445 onPathChange?.(path);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
446 }, [onPathChange]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
447
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
448 const fetchDirectory = async (path: string) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
449 setLoading(true);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
450 setError(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
451 try {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
452 const cacheKey = `dir:${path}`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
453 let data;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
454 if (prefetchCache.has(cacheKey)) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
455 data = await prefetchCache.get(cacheKey);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
456 prefetchCache.delete(cacheKey);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
457 } else {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
458 const url = path
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
459 ? `${API_BASE}/list?path=${encodeURIComponent(path)}`
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
460 : `${API_BASE}/list`;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
461 const response = await fetch(url);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
462 if (response.ok) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
463 data = await response.json();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
464 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
465 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
466
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
467 if (data?.error) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
468 throw new Error(data.error);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
469 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
470
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
471 setContent({
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
472 files: data?.files || [],
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
473 directories: data?.directories || []
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
474 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
475 } catch (err: any) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
476 console.error('Error loading directory:', err);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
477 setError(err.message);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
478 } finally {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
479 setLoading(false);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
480 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
481 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
482
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
483 const fetchReadme = async (path: string) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
484 setReadme(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
485 const readmePath = path ? `${path}/README.md` : 'README.md';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
486 try {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
487 const response = await fetch(`${API_BASE}/file?path=${encodeURIComponent(readmePath)}`);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
488 if (response.ok) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
489 const text = await response.text();
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
490 setReadme(text);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
491 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
492 } catch (err) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
493 // Readme is optional
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
494 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
495 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
496
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
497 const handleOpenFile = useCallback((path: string) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
498 setViewingFile(path);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
499 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
500
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
501 const handleCloseFile = useCallback(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
502 setViewingFile(null);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
503 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
504
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
505 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
506 <>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
507 <Breadcrumb currentPath={currentPath} onNavigate={navigate} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
508
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
509 {error && <div className="error-message">Error: {error}</div>}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
510
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
511 {loading ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
512 <div className="file-list-container">
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
513 <div className="loading-state">Loading files...</div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
514 </div>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
515 ) : (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
516 <>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
517 <FileList
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
518 directories={content.directories}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
519 files={content.files}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
520 onNavigate={navigate}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
521 onOpenFile={handleOpenFile}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
522 />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
523 <ReadmeViewer content={readme} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
524 </>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
525 )}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
526
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
527 {/* File Viewer Modal */}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
528 {viewingFile && (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
529 isMarkdownFile(viewingFile) ? (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
530 <MarkdownViewerModal filePath={viewingFile} onClose={handleCloseFile} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
531 ) : (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
532 <FileViewer filePath={viewingFile} onClose={handleCloseFile} />
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
533 )
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
534 )}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
535 </>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
536 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
537 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
538
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
539 export { DirectoryBrowser };