diff --git a/ai.js b/ai.js index a985350..30b103b 100644 --- a/ai.js +++ b/ai.js @@ -195,12 +195,39 @@ document.addEventListener('DOMContentLoaded', () => { const settingsModalCloseBtn = document.getElementById('settings-modal-close-btn'); const apiKeyInput = document.getElementById('api-key-input'); const settingsSaveBtn = document.getElementById('settings-save-btn'); + const showLineNumbersCheckbox = document.getElementById('show-line-numbers'); + const editorFontSizeSlider = document.getElementById('editor-font-size-slider'); + const previewFontSizeSlider = document.getElementById('preview-font-size-slider'); + const editorFontSizeVal = document.getElementById('editor-font-size-val'); + const previewFontSizeVal = document.getElementById('preview-font-size-val'); settingsBtn.addEventListener('click', () => { apiKeyInput.value = localStorage.getItem('gemini-api-key') || ''; + showLineNumbersCheckbox.checked = localStorage.getItem('show-line-numbers') === 'true'; + + const editorSize = localStorage.getItem('editor-font-size') || '16'; + const previewSize = localStorage.getItem('preview-font-size') || '16'; + + editorFontSizeSlider.value = editorSize; + editorFontSizeVal.textContent = `${editorSize}px`; + previewFontSizeSlider.value = previewSize; + previewFontSizeVal.textContent = `${previewSize}px`; + settingsModalOverlay.classList.remove('hidden'); }); + editorFontSizeSlider.addEventListener('input', (e) => { + const size = e.target.value; + editorFontSizeVal.textContent = `${size}px`; + document.documentElement.style.setProperty('--editor-font-size', `${size}px`); + }); + + previewFontSizeSlider.addEventListener('input', (e) => { + const size = e.target.value; + previewFontSizeVal.textContent = `${size}px`; + document.documentElement.style.setProperty('--preview-font-size', `${size}px`); + }); + settingsModalCloseBtn.addEventListener('click', () => { settingsModalOverlay.classList.add('hidden'); }); @@ -208,8 +235,24 @@ document.addEventListener('DOMContentLoaded', () => { settingsSaveBtn.addEventListener('click', () => { apiKey = apiKeyInput.value.trim(); localStorage.setItem('gemini-api-key', apiKey); + + const showLineNumbers = showLineNumbersCheckbox.checked; + localStorage.setItem('show-line-numbers', showLineNumbers); + + localStorage.setItem('editor-font-size', editorFontSizeSlider.value); + localStorage.setItem('preview-font-size', previewFontSizeSlider.value); + + // Dispatch event to notify editor.js + window.dispatchEvent(new CustomEvent('settings-updated', { + detail: { + showLineNumbers, + editorFontSize: editorFontSizeSlider.value, + previewFontSize: previewFontSizeSlider.value + } + })); + settingsModalOverlay.classList.add('hidden'); - if (window.toast) window.toast('API key saved', 'success'); + if (window.toast) window.toast('Settings saved', 'success'); }); aiNewChatBtn.addEventListener('click', () => { diff --git a/dashboard.js b/dashboard.js index 1808fa5..fe11ed5 100644 --- a/dashboard.js +++ b/dashboard.js @@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => { const modalConfirmBtn = document.getElementById('modal-confirm-btn'); const themeToggle = document.getElementById('theme-toggle'); const docCountBadge = document.getElementById('doc-count-badge'); + const dropOverlay = document.getElementById('drop-overlay'); let files = []; let modalResolve = null; @@ -38,6 +39,34 @@ document.addEventListener('DOMContentLoaded', () => { files = await RazenFS.getAllFiles(); }; + window.toast = (message, type = 'info') => { + const container = document.getElementById('toast-container'); + if (!container) return; + + const toast = document.createElement('div'); + toast.className = `toast toast-${type}`; + + let icon = 'info-circle'; + if (type === 'success') icon = 'check-circle'; + if (type === 'error') icon = 'exclamation-circle'; + if (type === 'warning') icon = 'exclamation-triangle'; + + toast.innerHTML = ` + + ${message} + `; + + container.appendChild(toast); + + const dismiss = () => { + toast.classList.add('fade-out'); + setTimeout(() => toast.remove(), 300); + }; + + toast.onclick = dismiss; + setTimeout(dismiss, 3000); + }; + const updateDocCount = () => { if (!docCountBadge) return; const n = files.length; @@ -160,6 +189,63 @@ document.addEventListener('DOMContentLoaded', () => { } }; + const handleFileImport = (file) => { + if (!file.name.endsWith('.md') && !file.name.endsWith('.txt')) { + toast('Only .md and .txt files are supported', 'error'); + return; + } + + const reader = new FileReader(); + reader.onload = async (e) => { + const content = e.target.result; + const name = file.name.replace(/\.(md|txt)$/, ''); + const newId = `file_${Date.now()}`; + const newFile = { + id: newId, + name: name, + content: content + }; + await RazenFS.saveFile(newFile); + files.push(newFile); + renderDocuments(); + toast('File imported', 'success'); + }; + reader.readAsText(file); + }; + + // Drag and Drop + const handleDragOver = (e) => { + e.preventDefault(); + e.stopPropagation(); + dropOverlay.classList.remove('hidden'); + }; + + const handleDragLeave = (e) => { + e.preventDefault(); + e.stopPropagation(); + if (e.relatedTarget === null || !dropOverlay.contains(e.relatedTarget)) { + dropOverlay.classList.add('hidden'); + } + }; + + const handleDrop = (e) => { + e.preventDefault(); + e.stopPropagation(); + dropOverlay.classList.add('hidden'); + + const file = e.dataTransfer.files[0]; + if (file) { + handleFileImport(file); + } + }; + + if (documentsGrid) { + documentsGrid.addEventListener('dragenter', handleDragOver); + dropOverlay.addEventListener('dragover', (e) => e.preventDefault()); + dropOverlay.addEventListener('dragleave', handleDragLeave); + dropOverlay.addEventListener('drop', handleDrop); + } + const handleDownloadFile = (id) => { const file = files.find(f => f.id === id); if (!file) return; diff --git a/editor.html b/editor.html index c04db2c..59478e4 100644 --- a/editor.html +++ b/editor.html @@ -58,6 +58,10 @@