comparison hg-web/src/index.js @ 135:ffb764d2fcc5

[HgWeb] Updated hg web so it works
author June Park <parkjune1995@gmail.com>
date Fri, 09 Jan 2026 11:17:20 -0800
parents
children
comparison
equal deleted inserted replaced
133:902e29c38d66 135:ffb764d2fcc5
1 const API_BASE = '/api/repo';
2
3 function getCurrentPath() {
4 const params = new URLSearchParams(window.location.search);
5 return params.get('path') || '';
6 }
7
8 function renderBreadcrumb(path) {
9 const breadcrumb = document.getElementById('breadcrumb');
10 if (!path) {
11 breadcrumb.innerHTML = '<a href="/">Root</a>';
12 return;
13 }
14
15 const parts = path.split('/').filter(p => p);
16 let currentPath = '';
17 let html = '<a href="/">Root</a>';
18
19 parts.forEach((part, index) => {
20 currentPath += (currentPath ? '/' : '') + part;
21 html += ` <span>/</span> `;
22 if (index === parts.length - 1) {
23 html += `<span>${part}</span>`;
24 } else {
25 html += `<a href="?path=${encodeURIComponent(currentPath)}">${part}</a>`;
26 }
27 });
28
29 breadcrumb.innerHTML = html;
30 }
31
32 function renderFiles(files, directories) {
33 if (!files || files.length === 0) {
34 fileList.style.display = 'none';
35 emptyState.style.display = 'block';
36 return;
37 }
38
39 emptyState.style.display = 'none';
40 fileList.style.display = 'block';
41
42 let html = '';
43 directories.forEach(file => {
44 const icon = '📁';
45 const className = file.type;
46 const href = `?path=${encodeURIComponent(file.abspath)}`;
47 const target = '';
48
49 html += `
50 <div class="file-item ${className}">
51 <span class="icon">${icon}</span>
52 <span class="name">
53 <a href="${href}" ${target}>${file.basename}</a>
54 </span>
55 </div>
56 `;
57 });
58 files.forEach(file => {
59 const icon = '📄';
60 const className = file.type;
61 const href = `/api/repo/file?path=${encodeURIComponent(file.abspath)}`;
62 const target = 'target="_blank"';
63
64 html += `
65 <div class="file-item ${className}">
66 <span class="icon">${icon}</span>
67 <span class="name">
68 <a href="${href}" ${target}>${file.basename}</a>
69 </span>
70 </div>
71 `;
72 });
73
74 fileList.innerHTML = html;
75 }
76
77 async function loadReadme(path) {
78 const readmeSection = document.getElementById('readmeSection');
79 const readmeContent = document.getElementById('readmeContent');
80
81 try {
82 const readmePath = path ? `${path}/README.md` : 'README.md';
83 const response = await fetch(`/api/repo/readme?path=${encodeURIComponent(readmePath)}`);
84
85 if (response.ok) {
86 const markdown = await response.text();
87 readmeSection.style.display = 'block';
88 renderMarkdown(readmeContent, markdown);
89 } else {
90 readmeSection.style.display = 'none';
91 }
92 } catch (error) {
93 readmeSection.style.display = 'none';
94 }
95 }
96
97 async function loadDirectory(path) {
98 try {
99 const url = path ? `${API_BASE}/list?path=${encodeURIComponent(path)}` : `${API_BASE}/list`;
100 const response = await fetch(url);
101 const data = await response.json();
102
103 if (data.error) {
104 throw new Error(data.error);
105 }
106
107 const { files, directories } = data;
108
109 renderBreadcrumb(path);
110 renderFiles(files, directories);
111 loadReadme(path);
112 } catch (error) {
113 console.error('Error loading directory:', error);
114 document.getElementById('fileList').innerHTML = `
115 <div class="error-message">Error loading directory: ${error.message}</div>
116 `;
117 }
118 }
119
120 window.addEventListener('popstate', (event) => {
121 const path = event.state?.path || '';
122 loadDirectory(path);
123 });
124
125 const currentPath = getCurrentPath();
126 loadDirectory(currentPath);