/* ELYSIA MARKDOWN STUDIO v1.0 - Documents Module Document management and sidebar */ import Utils from "./utils.js"; import DB from "./db.js"; const Documents = { currentFilter: "all", searchQuery: "", init() { this.setupEventListeners(); this.loadDocuments(); }, setupEventListeners() { // Open/close sidebar document.getElementById("btn-documents").addEventListener("click", () => { this.toggleSidebar(); }); document.getElementById("btn-close-sidebar").addEventListener("click", () => { this.toggleSidebar(); }); // Filter tabs document.querySelectorAll(".filter-tab").forEach(tab => { tab.addEventListener("click", () => { const filter = tab.getAttribute("data-filter"); this.setFilter(filter); }); }); // Search document.getElementById("search-docs").addEventListener( "input", Utils.debounce(e => { this.searchQuery = e.target.value; this.loadDocuments(); }, 300) ); }, toggleSidebar() { const sidebar = document.getElementById("sidebar-docs"); const main = document.querySelector(".main-container"); sidebar.classList.toggle("collapsed"); main.classList.toggle("sidebar-open"); if (!sidebar.classList.contains("collapsed")) { this.loadDocuments(); } }, setFilter(filter) { this.currentFilter = filter; // Update active tab document.querySelectorAll(".filter-tab").forEach(tab => { tab.classList.toggle("active", tab.getAttribute("data-filter") === filter); }); this.loadDocuments(); }, async loadDocuments() { const container = document.getElementById("documents-list"); try { let docs; if (this.searchQuery) { docs = await DB.searchDocuments(this.searchQuery); } else { docs = await DB.getAllDocuments(this.currentFilter); } if (docs.length === 0) { container.innerHTML = `

📄 No documents found

Create your first document!

`; return; } container.innerHTML = docs .map( doc => `
${doc.favorite ? "⭐ " : ""}${Utils.truncate(doc.title, 40)}
${doc.wordCount || 0} words • ${Utils.formatDate(doc.updatedAt)}
` ) .join(""); // Add click handlers container.querySelectorAll(".doc-item").forEach(item => { item.addEventListener("click", () => { const id = item.getAttribute("data-id"); window.app?.loadDocument(id); }); // Right-click context menu item.addEventListener("contextmenu", e => { e.preventDefault(); this.showContextMenu(e, item.getAttribute("data-id")); }); }); } catch (err) { console.error("Failed to load documents:", err); Utils.toast.error("Failed to load documents"); } }, showContextMenu(e, docId) { // Remove any existing context menu const existingMenu = document.querySelector(".context-menu"); if (existingMenu) existingMenu.remove(); // Create context menu const menu = document.createElement("div"); menu.className = "context-menu"; menu.innerHTML = `
Toggle Favorite
✏️ Rename
🗑️ Delete
`; // Position menu with boundary checks document.body.appendChild(menu); // Get menu dimensions const menuRect = menu.getBoundingClientRect(); const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; // Calculate position let left = e.pageX; let top = e.pageY; // Prevent horizontal overflow if (left + menuRect.width > viewportWidth) { left = viewportWidth - menuRect.width - 10; } // Prevent vertical overflow if (top + menuRect.height > viewportHeight) { top = viewportHeight - menuRect.height - 10; } menu.style.left = `${left}px`; menu.style.top = `${top}px`; // Handle clicks menu.querySelectorAll(".context-menu-item").forEach(item => { item.addEventListener("click", async () => { const action = item.getAttribute("data-action"); switch (action) { case "favorite": await this.toggleFavorite(docId); break; case "rename": await this.renameDocument(docId); break; case "delete": const confirmDelete = confirm("Are you sure you want to delete this document?"); if (confirmDelete) { await this.deleteDocument(docId); } break; } menu.remove(); }); }); // Close menu on outside click const closeMenu = event => { if (!menu.contains(event.target)) { menu.remove(); document.removeEventListener("click", closeMenu); } }; setTimeout(() => { document.addEventListener("click", closeMenu); }, 10); }, async renameDocument(docId) { const doc = await DB.getDocument(docId); if (!doc) return; const newTitle = prompt("Enter new title:", doc.title); if (newTitle && newTitle !== doc.title) { await DB.updateDocument(docId, { title: newTitle }); Utils.toast.success("Document renamed!"); this.loadDocuments(); // Update editor if this is current doc if (window.app?.currentDocId === docId) { document.getElementById("doc-title").value = newTitle; } } }, async toggleFavorite(docId) { const isFavorite = await DB.toggleFavorite(docId); Utils.toast.success(isFavorite ? "Added to favorites" : "Removed from favorites"); this.loadDocuments(); }, async deleteDocument(docId) { await DB.deleteDocument(docId); // If deleting current doc, clear editor if (window.app?.currentDocId === docId) { window.app.newDocument(); } this.loadDocuments(); }, // Update current doc item highlight updateActiveDoc(docId) { document.querySelectorAll(".doc-item").forEach(item => { item.classList.toggle("active", item.getAttribute("data-id") === docId); }); } }; export default Documents;