diff --git a/index.html b/index.html index 29d4d0f..ccfd1bf 100644 --- a/index.html +++ b/index.html @@ -205,14 +205,45 @@ position: relative; } + /* ── Editor title bar ── */ + .editor-title-bar { + display: flex; + align-items: center; + padding: 0 14px; + height: 44px; + border-bottom: 1px solid var(--border); + flex-shrink: 0; + gap: 10px; + } + #note-title-display { + flex: 1; + font-size: 15px; + font-weight: 700; + color: var(--fg); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: text; + opacity: 0.75; + } + #note-title-display:hover { opacity: 1; } + #note-title-input { + flex: 1; + font-size: 15px; + font-weight: 700; + font-family: 'Roboto Mono', monospace; + border: none; + outline: none; + background: transparent; + color: var(--fg); + display: none; + } + /* floating share + dark toggle */ .float-actions { - position: absolute; - top: 10px; - right: 12px; display: flex; gap: 6px; - z-index: 10; + flex-shrink: 0; } .float-btn { padding: 5px 12px; @@ -226,28 +257,14 @@ color: #000; } .float-btn:hover { background: var(--accent-hover); } - .float-icon-btn { - background: none; - border: 1px solid var(--border); - border-radius: 4px; - padding: 4px 8px; - cursor: pointer; - font-size: 15px; - color: var(--fg); - } - .float-icon-btn:hover { background: var(--sidebar-hover); } - /* save flash */ .save-flash { - position: absolute; - top: 12px; - left: 50%; - transform: translateX(-50%); font-size: 11px; color: var(--muted); opacity: 0; transition: opacity 0.4s; pointer-events: none; + white-space: nowrap; } .save-flash.show { opacity: 1; } @@ -415,10 +432,13 @@
-
+
+ Untitled + ✓ saved - - +
+ +
@@ -499,16 +519,63 @@ let autoSaveTimer = null, syncTimer = null, flashTimer = null; const $ = id => document.getElementById(id); - const notepad = $('notepad'); - const mdView = $('md-view'); - const canvasWrap = $('canvas-wrap'); - const canvas = $('drawing-canvas'); - const drawCtrls = $('draw-controls'); - const sidebar = $('sidebar'); - const notesList = $('notes-list'); - const saveFlash = $('save-flash'); - const wordCount = $('word-count'); - const syncStatus = $('sync-status'); + const notepad = $('notepad'); + const mdView = $('md-view'); + const canvasWrap = $('canvas-wrap'); + const canvas = $('drawing-canvas'); + const drawCtrls = $('draw-controls'); + const sidebar = $('sidebar'); + const notesList = $('notes-list'); + const saveFlash = $('save-flash'); + const wordCount = $('word-count'); + const syncStatus = $('sync-status'); + const titleDisplay = $('note-title-display'); + const titleInput = $('note-title-input'); + + // ── Title display & rename ──────────────────────────────────────────────── + function setTitleDisplay(title) { + titleDisplay.textContent = title || 'Untitled'; + } + + titleDisplay.addEventListener('click', () => { + titleDisplay.style.display = 'none'; + titleInput.style.display = ''; + titleInput.value = notes[currentId]?.title || ''; + titleInput.focus(); + titleInput.select(); + }); + + titleInput.addEventListener('blur', commitTitleInput); + titleInput.addEventListener('keydown', e => { + if (e.key === 'Enter') titleInput.blur(); + if (e.key === 'Escape') { renderTitle(); titleInput.style.display = 'none'; titleDisplay.style.display = ''; } + }); + + function commitTitleInput() { + if (!notes[currentId]) return; + notes[currentId].title = titleInput.value.trim(); + notes[currentId].updatedAt = Date.now(); + persist(); + renderTitle(); + renderList(); + titleInput.style.display = 'none'; + titleDisplay.style.display = ''; + scheduleSync(); + } + + function renderTitle() { + setTitleDisplay(notes[currentId]?.title || ''); + } + + function autoTitleFromContent() { + const n = notes[currentId]; + if (!n) return; + const firstLine = notepad.value.split('\n')[0].trim(); + n.title = firstLine; + n.updatedAt = Date.now(); + renderTitle(); + renderList(); + } // ── Persist ────────────────────────────────────────────────────────────── function persist() { localStorage.setItem('noted_notes', JSON.stringify(notes)); } @@ -622,6 +689,7 @@ $('text-color').value = n.textColor || '#000000'; updateWordCount(); renderMd(); + renderTitle(); undoStack = []; redoStack = []; if (ctx) { ctx.clearRect(0, 0, canvas.width, canvas.height); @@ -664,7 +732,7 @@ clearTimeout(autoSaveTimer); autoSaveTimer = setTimeout(() => saveNote(), 3000); } - notepad.addEventListener('input', () => { updateWordCount(); renderMd(); scheduleAutoSave(); }); + notepad.addEventListener('input', () => { updateWordCount(); renderMd(); autoTitleFromContent(); scheduleAutoSave(); }); // ── Markdown ────────────────────────────────────────────────────────────── function renderMd() { if (isMd) mdView.innerHTML = marked.parse(notepad.value || ''); }