comparison hg-web/src/index.html @ 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 2301aeb7503b
children 71ad34a8bc9a
comparison
equal deleted inserted replaced
133:902e29c38d66 135:ffb764d2fcc5
32 <p>No files found in this directory</p> 32 <p>No files found in this directory</p>
33 </div> 33 </div>
34 </main> 34 </main>
35 35
36 <script src="/markdown_to_html.js"></script> 36 <script src="/markdown_to_html.js"></script>
37 <script> 37 <script src="/index.js"></script>
38 const API_BASE = '/api/repo';
39
40 // Get current path from URL
41 function getCurrentPath() {
42 const params = new URLSearchParams(window.location.search);
43 return params.get('path') || '';
44 }
45
46 // Update URL without reloading
47 function updateURL(path) {
48 const url = path ? `?path=${encodeURIComponent(path)}` : '/';
49 window.history.pushState({path}, '', url);
50 }
51
52 // Render breadcrumb
53 function renderBreadcrumb(path) {
54 const breadcrumb = document.getElementById('breadcrumb');
55 if (!path) {
56 breadcrumb.innerHTML = '<a href="/">Root</a>';
57 return;
58 }
59
60 const parts = path.split('/').filter(p => p);
61 let currentPath = '';
62 let html = '<a href="/">Root</a>';
63
64 parts.forEach((part, index) => {
65 currentPath += (currentPath ? '/' : '') + part;
66 html += ` <span>/</span> `;
67 if (index === parts.length - 1) {
68 html += `<span>${part}</span>`;
69 } else {
70 html += `<a href="?path=${encodeURIComponent(currentPath)}">${part}</a>`;
71 }
72 });
73
74 breadcrumb.innerHTML = html;
75 }
76
77 // Render file list
78 function renderFiles(files) {
79 const fileList = document.getElementById('fileList');
80 const emptyState = document.getElementById('emptyState');
81
82 if (!files || files.length === 0) {
83 fileList.style.display = 'none';
84 emptyState.style.display = 'block';
85 return;
86 }
87
88 emptyState.style.display = 'none';
89 fileList.style.display = 'block';
90
91 // Sort: directories first, then files, alphabetically
92 files.sort((a, b) => {
93 if (a.type !== b.type) {
94 return a.type === 'directory' ? -1 : 1;
95 }
96 return a.name.localeCompare(b.name);
97 });
98
99 let html = '';
100 files.forEach(file => {
101 const icon = file.type === 'directory' ? '📁' : '📄';
102 const className = file.type;
103 const href = file.type === 'directory'
104 ? `?path=${encodeURIComponent(file.path)}`
105 : `/api/repo/file?path=${encodeURIComponent(file.path)}`;
106 const target = file.type === 'directory' ? '' : 'target="_blank"';
107
108 html += `
109 <div class="file-item ${className}">
110 <span class="icon">${icon}</span>
111 <span class="name">
112 <a href="${href}" ${target}>${file.name}</a>
113 </span>
114 </div>
115 `;
116 });
117
118 fileList.innerHTML = html;
119 }
120
121 // Load and render README
122 async function loadReadme(path) {
123 const readmeSection = document.getElementById('readmeSection');
124 const readmeContent = document.getElementById('readmeContent');
125
126 try {
127 const readmePath = path ? `${path}/README.md` : 'README.md';
128 const response = await fetch(`/api/repo/readme?path=${encodeURIComponent(readmePath)}`);
129
130 if (response.ok) {
131 const markdown = await response.text();
132 readmeSection.style.display = 'block';
133 renderMarkdown(readmeContent, markdown);
134 } else {
135 readmeSection.style.display = 'none';
136 }
137 } catch (error) {
138 readmeSection.style.display = 'none';
139 }
140 }
141
142 // Load directory contents
143 async function loadDirectory(path) {
144 try {
145 const url = path ? `${API_BASE}/list?path=${encodeURIComponent(path)}` : `${API_BASE}/list`;
146 const response = await fetch(url);
147 const data = await response.json();
148
149 if (data.error) {
150 throw new Error(data.error);
151 }
152
153 renderBreadcrumb(path);
154 renderFiles(data.files);
155 loadReadme(path);
156 } catch (error) {
157 console.error('Error loading directory:', error);
158 document.getElementById('fileList').innerHTML = `
159 <div class="error-message">Error loading directory: ${error.message}</div>
160 `;
161 }
162 }
163
164 // Handle browser back/forward
165 window.addEventListener('popstate', (event) => {
166 const path = event.state?.path || '';
167 loadDirectory(path);
168 });
169
170 // Initial load
171 const currentPath = getCurrentPath();
172 loadDirectory(currentPath);
173 </script>
174 </body> 38 </body>
175 </html> 39 </html>