Update templates/index.html
Browse files- templates/index.html +63 -14
templates/index.html
CHANGED
@@ -75,13 +75,16 @@
|
|
75 |
#download-btn { width: 100%; background-color: var(--primary-color); color: var(--background-primary); display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 1rem; font-weight: 600; border-radius: 8px; padding: 12px; }
|
76 |
#download-btn:hover { background-color: var(--accent-color); color: var(--background-primary); }
|
77 |
#download-btn i { font-size: 1.1rem; }
|
|
|
78 |
</style>
|
79 |
</head>
|
80 |
<body>
|
81 |
<div class="container">
|
82 |
<div class="sidebar left-sidebar">
|
83 |
<div class="sidebar-header"><i class="fa-solid fa-folder-tree"></i><h2>Project Files</h2></div>
|
84 |
-
<div id="file-tree" class="sidebar-content"
|
|
|
|
|
85 |
<div class="sidebar-footer"><button id="download-btn"><i class="fa-solid fa-download"></i><span>Download Project</span></button></div>
|
86 |
</div>
|
87 |
<div class="main-content">
|
@@ -139,6 +142,9 @@
|
|
139 |
const fetchApi = async (url, options) => {
|
140 |
try {
|
141 |
const response = await fetch(url, options);
|
|
|
|
|
|
|
142 |
const data = await response.json();
|
143 |
if (data.error) {
|
144 |
handleApiError(data.error);
|
@@ -147,6 +153,7 @@
|
|
147 |
return data;
|
148 |
} catch (error) {
|
149 |
handleApiError('Failed to connect to the backend. Please ensure it is running.');
|
|
|
150 |
return null;
|
151 |
}
|
152 |
};
|
@@ -154,17 +161,23 @@
|
|
154 |
const uploadProject = async (formData) => {
|
155 |
ui.uploadBox.style.display = 'none';
|
156 |
ui.progressIndicator.style.display = 'block';
|
157 |
-
const data = await fetchApi('/upload', {
|
|
|
|
|
|
|
|
|
158 |
ui.progressIndicator.style.display = 'none';
|
159 |
if (data) {
|
160 |
ui.uploadSection.style.display = 'none';
|
161 |
ui.chatSection.style.display = 'flex';
|
162 |
updateFileTree(data.file_tree);
|
163 |
ui.chatWindow.innerHTML = '';
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
|
|
|
|
168 |
} else {
|
169 |
ui.uploadBox.style.display = 'block';
|
170 |
}
|
@@ -173,14 +186,17 @@
|
|
173 |
const sendMessage = async () => {
|
174 |
const message = ui.messageInput.value.trim();
|
175 |
if (!message) return;
|
|
|
176 |
appendMessage('user', message);
|
177 |
ui.messageInput.value = '';
|
178 |
ui.messageInput.style.height = 'auto';
|
|
|
179 |
const data = await fetchApi('/chat', {
|
180 |
method: 'POST',
|
181 |
headers: { 'Content-Type': 'application/json' },
|
182 |
body: JSON.stringify({ message })
|
183 |
});
|
|
|
184 |
if (data && data.reply) {
|
185 |
appendMessage('assistant', data.reply);
|
186 |
updateFileTree();
|
@@ -197,9 +213,13 @@
|
|
197 |
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
198 |
html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
|
199 |
const trimmedCode = code.trim();
|
200 |
-
const highlighted = hljs.highlight(trimmedCode, {
|
|
|
|
|
|
|
201 |
return `<pre><code class="hljs ${lang}">${highlighted}</code></pre>`;
|
202 |
});
|
|
|
203 |
messageElement.innerHTML = html.replace(/\n/g, '<br>');
|
204 |
ui.chatWindow.appendChild(messageElement);
|
205 |
ui.chatWindow.scrollTop = ui.chatWindow.scrollHeight;
|
@@ -207,9 +227,11 @@
|
|
207 |
|
208 |
const updateFileTree = async () => {
|
209 |
const data = await fetchApi('/file_tree');
|
210 |
-
|
|
|
|
|
211 |
const activeFilePath = document.querySelector('#file-tree .active')?.dataset.path;
|
212 |
-
|
213 |
data.file_tree.forEach(path => {
|
214 |
const fileElement = document.createElement('div');
|
215 |
fileElement.textContent = path;
|
@@ -222,6 +244,11 @@
|
|
222 |
if (path === activeFilePath) fileElement.classList.add('active');
|
223 |
ui.fileTree.appendChild(fileElement);
|
224 |
});
|
|
|
|
|
|
|
|
|
|
|
225 |
}
|
226 |
};
|
227 |
|
@@ -231,21 +258,43 @@
|
|
231 |
ui.fileContentDisplay.textContent = data.content;
|
232 |
hljs.highlightElement(ui.fileContentDisplay);
|
233 |
} else {
|
234 |
-
ui.fileContentDisplay.textContent = 'Could not load file content.';
|
235 |
}
|
236 |
};
|
237 |
|
|
|
238 |
ui.projectZipInput.addEventListener('change', () => {
|
239 |
if (ui.projectZipInput.files.length > 0) {
|
240 |
ui.fileNameDisplay.textContent = `Selected: ${ui.projectZipInput.files[0].name}`;
|
241 |
ui.uploadButton.click();
|
242 |
}
|
243 |
});
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
245 |
ui.sendBtn.addEventListener('click', sendMessage);
|
246 |
-
|
247 |
-
ui.
|
248 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
});
|
250 |
</script>
|
251 |
</body>
|
|
|
75 |
#download-btn { width: 100%; background-color: var(--primary-color); color: var(--background-primary); display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 1rem; font-weight: 600; border-radius: 8px; padding: 12px; }
|
76 |
#download-btn:hover { background-color: var(--accent-color); color: var(--background-primary); }
|
77 |
#download-btn i { font-size: 1.1rem; }
|
78 |
+
.empty-state { color: var(--text-secondary); padding: 20px; text-align: center; }
|
79 |
</style>
|
80 |
</head>
|
81 |
<body>
|
82 |
<div class="container">
|
83 |
<div class="sidebar left-sidebar">
|
84 |
<div class="sidebar-header"><i class="fa-solid fa-folder-tree"></i><h2>Project Files</h2></div>
|
85 |
+
<div id="file-tree" class="sidebar-content">
|
86 |
+
<div class="empty-state">No project files. Upload a project first.</div>
|
87 |
+
</div>
|
88 |
<div class="sidebar-footer"><button id="download-btn"><i class="fa-solid fa-download"></i><span>Download Project</span></button></div>
|
89 |
</div>
|
90 |
<div class="main-content">
|
|
|
142 |
const fetchApi = async (url, options) => {
|
143 |
try {
|
144 |
const response = await fetch(url, options);
|
145 |
+
if (!response.ok) {
|
146 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
147 |
+
}
|
148 |
const data = await response.json();
|
149 |
if (data.error) {
|
150 |
handleApiError(data.error);
|
|
|
153 |
return data;
|
154 |
} catch (error) {
|
155 |
handleApiError('Failed to connect to the backend. Please ensure it is running.');
|
156 |
+
console.error('API Error:', error);
|
157 |
return null;
|
158 |
}
|
159 |
};
|
|
|
161 |
const uploadProject = async (formData) => {
|
162 |
ui.uploadBox.style.display = 'none';
|
163 |
ui.progressIndicator.style.display = 'block';
|
164 |
+
const data = await fetchApi('/upload', {
|
165 |
+
method: 'POST',
|
166 |
+
body: formData
|
167 |
+
});
|
168 |
+
|
169 |
ui.progressIndicator.style.display = 'none';
|
170 |
if (data) {
|
171 |
ui.uploadSection.style.display = 'none';
|
172 |
ui.chatSection.style.display = 'flex';
|
173 |
updateFileTree(data.file_tree);
|
174 |
ui.chatWindow.innerHTML = '';
|
175 |
+
|
176 |
+
if (data.chat_history && data.chat_history.length > 0) {
|
177 |
+
data.chat_history.forEach(msg => {
|
178 |
+
appendMessage(msg.role === 'user' ? 'user' : 'assistant', msg.content);
|
179 |
+
});
|
180 |
+
}
|
181 |
} else {
|
182 |
ui.uploadBox.style.display = 'block';
|
183 |
}
|
|
|
186 |
const sendMessage = async () => {
|
187 |
const message = ui.messageInput.value.trim();
|
188 |
if (!message) return;
|
189 |
+
|
190 |
appendMessage('user', message);
|
191 |
ui.messageInput.value = '';
|
192 |
ui.messageInput.style.height = 'auto';
|
193 |
+
|
194 |
const data = await fetchApi('/chat', {
|
195 |
method: 'POST',
|
196 |
headers: { 'Content-Type': 'application/json' },
|
197 |
body: JSON.stringify({ message })
|
198 |
});
|
199 |
+
|
200 |
if (data && data.reply) {
|
201 |
appendMessage('assistant', data.reply);
|
202 |
updateFileTree();
|
|
|
213 |
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
214 |
html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
|
215 |
const trimmedCode = code.trim();
|
216 |
+
const highlighted = hljs.highlight(trimmedCode, {
|
217 |
+
language: lang || 'plaintext',
|
218 |
+
ignoreIllegals: true
|
219 |
+
}).value;
|
220 |
return `<pre><code class="hljs ${lang}">${highlighted}</code></pre>`;
|
221 |
});
|
222 |
+
|
223 |
messageElement.innerHTML = html.replace(/\n/g, '<br>');
|
224 |
ui.chatWindow.appendChild(messageElement);
|
225 |
ui.chatWindow.scrollTop = ui.chatWindow.scrollHeight;
|
|
|
227 |
|
228 |
const updateFileTree = async () => {
|
229 |
const data = await fetchApi('/file_tree');
|
230 |
+
ui.fileTree.innerHTML = '';
|
231 |
+
|
232 |
+
if (data && data.file_tree && data.file_tree.length > 0) {
|
233 |
const activeFilePath = document.querySelector('#file-tree .active')?.dataset.path;
|
234 |
+
|
235 |
data.file_tree.forEach(path => {
|
236 |
const fileElement = document.createElement('div');
|
237 |
fileElement.textContent = path;
|
|
|
244 |
if (path === activeFilePath) fileElement.classList.add('active');
|
245 |
ui.fileTree.appendChild(fileElement);
|
246 |
});
|
247 |
+
} else {
|
248 |
+
const emptyMessage = document.createElement('div');
|
249 |
+
emptyMessage.textContent = 'No project files. Upload a project first.';
|
250 |
+
emptyMessage.classList.add('empty-state');
|
251 |
+
ui.fileTree.appendChild(emptyMessage);
|
252 |
}
|
253 |
};
|
254 |
|
|
|
258 |
ui.fileContentDisplay.textContent = data.content;
|
259 |
hljs.highlightElement(ui.fileContentDisplay);
|
260 |
} else {
|
261 |
+
ui.fileContentDisplay.textContent = data?.error || 'Could not load file content.';
|
262 |
}
|
263 |
};
|
264 |
|
265 |
+
// Event listeners
|
266 |
ui.projectZipInput.addEventListener('change', () => {
|
267 |
if (ui.projectZipInput.files.length > 0) {
|
268 |
ui.fileNameDisplay.textContent = `Selected: ${ui.projectZipInput.files[0].name}`;
|
269 |
ui.uploadButton.click();
|
270 |
}
|
271 |
});
|
272 |
+
|
273 |
+
ui.uploadForm.addEventListener('submit', (e) => {
|
274 |
+
e.preventDefault();
|
275 |
+
uploadProject(new FormData(ui.uploadForm));
|
276 |
+
});
|
277 |
+
|
278 |
ui.sendBtn.addEventListener('click', sendMessage);
|
279 |
+
|
280 |
+
ui.messageInput.addEventListener('keypress', (e) => {
|
281 |
+
if (e.key === 'Enter' && !e.shiftKey) {
|
282 |
+
e.preventDefault();
|
283 |
+
sendMessage();
|
284 |
+
}
|
285 |
+
});
|
286 |
+
|
287 |
+
ui.downloadBtn.addEventListener('click', () => {
|
288 |
+
window.location.href = '/download';
|
289 |
+
});
|
290 |
+
|
291 |
+
ui.messageInput.addEventListener('input', function() {
|
292 |
+
this.style.height = 'auto';
|
293 |
+
this.style.height = (this.scrollHeight) + 'px';
|
294 |
+
});
|
295 |
+
|
296 |
+
// Initialize the application
|
297 |
+
updateFileTree();
|
298 |
});
|
299 |
</script>
|
300 |
</body>
|