// API Base URL const API_BASE = '/claude/api'; // State let currentFile = null; let isEditing = false; let fileTree = []; // DOM Elements const loginScreen = document.getElementById('login-screen'); const mainApp = document.getElementById('main-app'); const loginForm = document.getElementById('login-form'); const loginError = document.getElementById('login-error'); const logoutBtn = document.getElementById('logout-btn'); const searchInput = document.getElementById('search-input'); const fileTreeEl = document.getElementById('file-tree'); const recentFilesEl = document.getElementById('recent-files'); const contentView = document.getElementById('content-view'); const contentEditor = document.getElementById('content-editor'); const breadcrumb = document.getElementById('breadcrumb'); const editBtn = document.getElementById('edit-btn'); const saveBtn = document.getElementById('save-btn'); const cancelBtn = document.getElementById('cancel-btn'); // Initialize document.addEventListener('DOMContentLoaded', () => { checkAuth(); setupEventListeners(); }); function setupEventListeners() { // Login form const loginForm = document.getElementById('login-form'); if (loginForm) { loginForm.addEventListener('submit', handleLogin); } // Logout const logoutBtn = document.getElementById('logout-btn'); if (logoutBtn) { logoutBtn.addEventListener('click', handleLogout); } // Search const searchInput = document.getElementById('search-input'); if (searchInput) { let searchTimeout; searchInput.addEventListener('input', (e) => { clearTimeout(searchTimeout); searchTimeout = setTimeout(() => handleSearch(e.target.value), 300); }); } // Edit/Save/Cancel buttons const editBtn = document.getElementById('edit-btn'); const saveBtn = document.getElementById('save-btn'); const cancelBtn = document.getElementById('cancel-btn'); if (editBtn) { editBtn.addEventListener('click', startEditing); } if (saveBtn) { saveBtn.addEventListener('click', saveFile); } if (cancelBtn) { cancelBtn.addEventListener('click', stopEditing); } } // Auth functions async function checkAuth() { try { const res = await fetch(`${API_BASE}/auth/status`); const data = await res.json(); if (data.authenticated) { // Redirect to landing page if authenticated window.location.href = '/claude/'; } else { showLogin(); } } catch (error) { console.error('Auth check failed:', error); showLogin(); } } async function handleLogin(e) { e.preventDefault(); const username = document.getElementById('username').value; const password = document.getElementById('password').value; try { const res = await fetch(`${API_BASE}/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await res.json(); if (data.success) { // Redirect to landing page after successful login window.location.href = '/claude/'; } else { loginError.textContent = data.error || 'Login failed'; } } catch (error) { loginError.textContent = 'Network error. Please try again.'; } } async function handleLogout() { try { await fetch(`${API_BASE}/logout`, { method: 'POST' }); showLogin(); } catch (error) { console.error('Logout failed:', error); } } function showLogin() { loginScreen.style.display = 'flex'; mainApp.style.display = 'none'; } function showApp() { loginScreen.style.display = 'none'; mainApp.style.display = 'flex'; loadFileTree(); loadRecentFiles(); } // File functions async function loadFileTree() { try { const res = await fetch(`${API_BASE}/files`); const data = await res.json(); fileTree = data.tree; renderFileTree(fileTree, fileTreeEl); } catch (error) { console.error('Failed to load file tree:', error); } } function renderFileTree(tree, container, level = 0) { container.innerHTML = ''; tree.forEach(item => { const div = document.createElement('div'); div.className = 'tree-item ' + item.type; div.style.paddingLeft = (level * 1 + 0.75) + 'rem'; const icon = document.createElement('span'); icon.className = 'tree-icon'; icon.textContent = item.type === 'folder' ? '📁' : '📄'; div.appendChild(icon); const name = document.createElement('span'); name.textContent = item.name; div.appendChild(name); if (item.type === 'folder' && item.children) { const children = document.createElement('div'); children.className = 'tree-children'; children.style.display = 'none'; div.addEventListener('click', () => { children.style.display = children.style.display === 'none' ? 'block' : 'none'; icon.textContent = children.style.display === 'none' ? '📁' : '📂'; }); renderFileTree(item.children, children, level + 1); div.appendChild(children); } else if (item.type === 'file') { div.addEventListener('click', () => loadFile(item.path)); } container.appendChild(div); }); } async function loadRecentFiles() { try { const res = await fetch(`${API_BASE}/recent?limit=10`); const data = await res.json(); recentFilesEl.innerHTML = ''; data.files.forEach(file => { const li = document.createElement('li'); li.textContent = file.name; li.title = file.path; li.addEventListener('click', () => loadFile(file.path)); recentFilesEl.appendChild(li); }); } catch (error) { console.error('Failed to load recent files:', error); } } async function loadFile(filePath) { try { const res = await fetch(`${API_BASE}/file/${encodeURIComponent(filePath)}`); const data = await res.json(); if (data.error) { console.error('Error loading file:', data.error); return; } currentFile = data; breadcrumb.textContent = data.path; contentView.innerHTML = data.html; contentEditor.value = data.content; editBtn.style.display = 'inline-block'; stopEditing(); } catch (error) { console.error('Failed to load file:', error); } } async function handleSearch(query) { if (!query.trim()) { return; } try { const res = await fetch(`${API_BASE}/search?q=${encodeURIComponent(query)}`); const data = await res.json(); // Show search results in file tree fileTreeEl.innerHTML = ''; if (data.results.length === 0) { fileTreeEl.innerHTML = '