Online Memory Palace Learning Tool

Memory Palace Learning Tool

Create a new Memory Palace or load an existing one to start learning.


OR

No items in this room yet.

`; elements.roomContainer.appendChild(roomDiv); }); } function renderItemsInRoom(roomId, items) { const container = document.getElementById(`items-for-room-${roomId}`); if (!container) return; const roomData = allPalaceData.rooms.find(r => r.id === roomId); if (roomData) roomData.items = items; if (items.length === 0) { container.innerHTML = `

No items in this room yet.

`; return; } container.innerHTML = items.map(item => `

${item.location}

${item.information}

`).join(''); } function openModal(modal) { modal.classList.remove('hidden'); setTimeout(() => { modal.querySelector('.modal-overlay')?.classList.remove('opacity-0'); modal.querySelector('.modal-container')?.classList.remove('scale-95'); }, 10); } function closeModal(modal) { modal.querySelector('.modal-overlay')?.classList.add('opacity-0'); modal.querySelector('.modal-container')?.classList.add('scale-95'); setTimeout(() => { modal.classList.add('hidden'); }, 300); } async function handleAddRoom(e) { e.preventDefault(); const roomName = elements.roomNameInput.value.trim(); if (!roomName || !currentPalaceId) return; try { const roomsCol = collection(db, 'artifacts', appId, 'public', 'data', 'memory-palaces', currentPalaceId, 'rooms'); await addDoc(roomsCol, { name: roomName, createdAt: serverTimestamp() }); elements.roomForm.reset(); closeModal(elements.roomModal); } catch (error) { console.error("Error adding room:", error); showMessage("Failed to add room.", "error"); } } async function handleAddItem(e) { e.preventDefault(); const roomId = elements.itemRoomIdInput.value; const location = elements.itemLocationInput.value.trim(); const information = elements.itemToMemorizeInput.value.trim(); if (!roomId || !location || !information) return; try { const itemsCol = collection(db, 'artifacts', appId, 'public', 'data', 'memory-palaces', currentPalaceId, 'rooms', roomId, 'items'); await addDoc(itemsCol, { location, information, createdAt: serverTimestamp() }); elements.itemForm.reset(); closeModal(elements.itemModal); } catch (error) { console.error("Error adding item:", error); showMessage("Failed to add item.", "error"); } } function downloadPdf() { if (!allPalaceData.info) { showMessage("No palace data to export.", "error"); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFont('helvetica', 'bold'); doc.setFontSize(18); doc.text(allPalaceData.info.name, doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' }); doc.setFont('helvetica', 'normal'); doc.setFontSize(12); doc.text(allPalaceData.info.description, doc.internal.pageSize.getWidth() / 2, 28, { align: 'center' }); doc.setFontSize(10); doc.setTextColor(150); doc.text(`Palace ID: ${currentPalaceId}`, doc.internal.pageSize.getWidth() / 2, 35, { align: 'center' }); let startY = 45; allPalaceData.rooms.forEach(room => { if (startY > 260) { doc.addPage(); startY = 20; } const tableBody = room.items.map(item => [item.location, item.information]); doc.autoTable({ startY: startY, head: [[room.name]], body: [], theme: 'striped', headStyles: { fillColor: [79, 70, 229], fontSize: 14 }, }); doc.autoTable({ startY: doc.autoTable.previous.finalY, head: [['Location in Room', 'Information to Memorize']], body: tableBody, theme: 'grid', }); startY = doc.autoTable.previous.finalY + 15; }); doc.save(`${allPalaceData.info.name.replace(/\s+/g, '-')}-memory-palace.pdf`); } // --- Firebase Initialization and Auth --- async function initializeFirebase() { try { const app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); onAuthStateChanged(auth, (user) => { userId = user ? user.uid : null; }); if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (error) { console.error("Firebase initialization failed:", error); showMessage("Could not connect to the service.", "error"); } } // --- Event Listeners --- elements.btnCreatePalace.addEventListener('click', createPalace); elements.btnJoinPalace.addEventListener('click', () => { const id = elements.joinPalaceIdInput.value.trim(); if (id) loadPalace(id); else showMessage("Please enter a Palace ID.", "error"); }); elements.btnCopyId.addEventListener('click', () => { navigator.clipboard.writeText(currentPalaceId).then(() => showMessage("Palace ID copied!", "success")); }); elements.btnDownloadPdf.addEventListener('click', downloadPdf); elements.btnAddRoomOpen.addEventListener('click', () => openModal(elements.roomModal)); elements.roomForm.addEventListener('submit', handleAddRoom); elements.itemForm.addEventListener('submit', handleAddItem); document.body.addEventListener('click', (e) => { if (e.target.classList.contains('btn-add-item-open')) { const roomId = e.target.dataset.roomId; elements.itemRoomIdInput.value = roomId; openModal(elements.itemModal); } if (e.target.classList.contains('btn-modal-close') || e.target.closest('.btn-modal-close')) { closeModal(e.target.closest('.modal-overlay')); } }); // --- Start the app --- initializeFirebase();
Scroll to Top