Changeset 0.22.7 (#149)

This commit is contained in:
2026-03-04 10:44:42 +00:00
parent d8e0664fa3
commit 389e47b0f9
62 changed files with 6820 additions and 1476 deletions

View File

@@ -744,15 +744,157 @@ function _showSaveToNoteModal(opts) {
// ── Notes Listeners (extracted from initListeners) ──
function _registerNotesPanel() {
const el = document.getElementById('sidePanelNotes');
if (!el) return;
const body = document.getElementById('sidePanelBody');
if (!body || typeof PanelRegistry === 'undefined') return;
// ── Create the panel element dynamically ──
const el = document.createElement('div');
el.className = 'side-panel-page';
el.id = 'sidePanelNotes';
el.style.display = 'none';
el.innerHTML = `
<!-- List view -->
<div id="notesListView">
<div class="notes-toolbar">
<button id="notesNewBtn" class="btn-small" title="New note">+ New</button>
<button id="notesTodayBtn" class="btn-small" title="Open daily note">📅 Today</button>
<button id="notesGraphBtn" class="btn-small" title="Note graph">🕸 Graph</button>
<button id="notesSelectModeBtn" class="btn-small" title="Select mode">☑ Select</button>
</div>
<div class="notes-search-row">
<input type="text" id="notesSearchInput" class="notes-search-input" placeholder="Search notes…" autocomplete="off">
</div>
<div class="notes-filter-row">
<select id="notesFolderFilter" class="notes-filter-select"><option value="">All folders</option></select>
<select id="notesSortSelect" class="notes-filter-select">
<option value="updated_desc">Last updated</option>
<option value="created_desc">Created</option>
<option value="alpha">Alphabetical</option>
</select>
</div>
<div id="notesList" class="notes-list"></div>
<div id="notesSelectionBar" class="notes-selection-bar" style="display:none;">
<label class="notes-select-all"><input type="checkbox" id="notesSelectAll"> All</label>
<span id="notesSelectedCount">0</span> selected
<button id="notesDeleteSelectedBtn" class="btn-small btn-danger">Delete</button>
<button id="notesCancelSelectBtn" class="btn-small">Cancel</button>
</div>
</div>
<!-- Editor view -->
<div id="notesEditorView" style="display:none;">
<div class="notes-editor-header">
<button id="notesBackBtn" class="btn-small" title="Back to list">← Back</button>
<div style="flex:1"></div>
<button id="noteEditBtn" class="btn-small" style="display:none;">Edit</button>
<button id="notePreviewBtn" class="btn-small" style="display:none;">Preview</button>
<button id="noteCancelEditBtn" class="btn-small" style="display:none;">Cancel</button>
<button id="noteDeleteBtn" class="btn-small btn-danger" style="display:none;">Delete</button>
<button id="noteSaveBtn" class="btn-small btn-primary">Save</button>
</div>
<!-- Edit mode -->
<div id="noteEditMode" class="notes-editor">
<input type="text" id="noteEditorTitle" class="notes-title-input" placeholder="Note title">
<div class="notes-meta-row">
<input type="text" id="noteEditorFolder" class="notes-folder-input" placeholder="Folder (e.g. work/project)">
<input type="text" id="noteEditorTags" class="notes-tags-input" placeholder="Tags (comma-separated)">
</div>
<div id="noteEditorContentContainer" class="notes-content-container">
<textarea id="noteEditorContent" rows="12" class="notes-content-input" placeholder="Write your note in markdown…"></textarea>
</div>
</div>
<!-- Read mode -->
<div id="noteReadMode" style="display:none;">
<div class="notes-read-view">
<h3 id="noteReadTitle" class="note-read-title"></h3>
<div id="noteReadMeta" class="note-read-meta"></div>
<div id="noteReadContent" class="note-read-content msg-content"></div>
<button id="noteDeleteBtn2" class="btn-small btn-danger" style="display:none;margin-top:8px;">Delete</button>
</div>
</div>
<!-- Backlinks -->
<div id="noteBacklinks" class="note-backlinks" style="display:none;">
<div class="note-backlinks-header" onclick="toggleBacklinks()">
Backlinks <span id="noteBacklinksCount" class="badge">0</span>
</div>
<div id="noteBacklinksList" class="note-backlinks-list"></div>
</div>
</div>
<!-- Graph view -->
<div id="notesGraphView" style="display:none;"></div>`;
body.appendChild(el);
// ── Wire listeners ──
// Sidebar trigger (lives outside this panel)
document.getElementById('notesBtn')?.addEventListener('click', openNotes);
// Toolbar buttons
el.querySelector('#notesNewBtn').addEventListener('click', () => openNoteEditor(null));
el.querySelector('#notesGraphBtn').addEventListener('click', () => {
if (typeof openNoteGraph === 'function') openNoteGraph();
});
el.querySelector('#notesTodayBtn').addEventListener('click', openDailyNote);
el.querySelector('#notesSelectModeBtn').addEventListener('click', () => {
if (_notesSelectMode) _exitSelectMode();
else _enterSelectMode();
});
// Editor header buttons
el.querySelector('#notesBackBtn').addEventListener('click', () => { showNotesList(); loadNotesList(); loadNoteFolders(); });
el.querySelector('#noteSaveBtn').addEventListener('click', saveNote);
el.querySelector('#noteDeleteBtn').addEventListener('click', deleteNote);
el.querySelector('#noteDeleteBtn2').addEventListener('click', deleteNote);
el.querySelector('#noteEditBtn').addEventListener('click', _showNoteEditMode);
el.querySelector('#notePreviewBtn').addEventListener('click', _showNotePreview);
el.querySelector('#noteCancelEditBtn').addEventListener('click', () => {
if (_currentNote) { _populateEditFields(_currentNote); _showNoteReadMode(); }
else showNotesList();
});
// Filters
el.querySelector('#notesFolderFilter').addEventListener('change', (e) => {
document.getElementById('notesSearchInput').value = '';
_exitSelectMode();
loadNotesList(e.target.value);
});
el.querySelector('#notesSortSelect').addEventListener('change', (e) => {
_notesSort = e.target.value;
_exitSelectMode();
loadNotesList();
});
// Multi-select controls
el.querySelector('#notesSelectAll').addEventListener('change', (e) => {
_toggleSelectAll(e.target.checked);
});
el.querySelector('#notesDeleteSelectedBtn').addEventListener('click', _bulkDeleteSelected);
el.querySelector('#notesCancelSelectBtn').addEventListener('click', _exitSelectMode);
// Search with debounce
let _notesSearchTimer;
el.querySelector('#notesSearchInput').addEventListener('input', (e) => {
clearTimeout(_notesSearchTimer);
const q = e.target.value.trim();
_notesSearchTimer = setTimeout(() => {
_exitSelectMode();
if (q.length >= 2) {
document.getElementById('notesFolderFilter').value = '';
loadNotesList(null, q);
} else if (q.length === 0) {
loadNotesList();
}
}, 300);
});
// ── Register with PanelRegistry ──
PanelRegistry.register('notes', {
element: el,
label: 'Notes',
onOpen() {
// Loading is handled by openNotes() which calls loadNotesList
},
onClose() {
_destroyNoteEditor();
},
saveState() {
const listView = document.getElementById('notesListView');
const editorView = document.getElementById('notesEditorView');
@@ -775,56 +917,8 @@ function _registerNotesPanel() {
});
}
/** @deprecated — listeners are now wired in _registerNotesPanel() */
function _initNotesListeners() {
document.getElementById('notesBtn')?.addEventListener('click', openNotes);
document.getElementById('notesNewBtn')?.addEventListener('click', () => openNoteEditor(null));
document.getElementById('notesGraphBtn')?.addEventListener('click', () => {
if (typeof openNoteGraph === 'function') openNoteGraph();
});
document.getElementById('notesTodayBtn')?.addEventListener('click', openDailyNote);
document.getElementById('notesSelectModeBtn')?.addEventListener('click', () => {
if (_notesSelectMode) _exitSelectMode();
else _enterSelectMode();
});
document.getElementById('notesBackBtn')?.addEventListener('click', () => { showNotesList(); loadNotesList(); loadNoteFolders(); });
document.getElementById('noteSaveBtn')?.addEventListener('click', saveNote);
document.getElementById('noteDeleteBtn')?.addEventListener('click', deleteNote);
document.getElementById('noteDeleteBtn2')?.addEventListener('click', deleteNote);
document.getElementById('noteEditBtn')?.addEventListener('click', _showNoteEditMode);
document.getElementById('notePreviewBtn')?.addEventListener('click', _showNotePreview);
document.getElementById('noteCancelEditBtn')?.addEventListener('click', () => {
if (_currentNote) { _populateEditFields(_currentNote); _showNoteReadMode(); }
else showNotesList();
});
document.getElementById('notesFolderFilter')?.addEventListener('change', (e) => {
document.getElementById('notesSearchInput').value = '';
_exitSelectMode();
loadNotesList(e.target.value);
});
document.getElementById('notesSortSelect')?.addEventListener('change', (e) => {
_notesSort = e.target.value;
_exitSelectMode();
loadNotesList();
});
document.getElementById('notesSelectAll')?.addEventListener('change', (e) => {
_toggleSelectAll(e.target.checked);
});
document.getElementById('notesDeleteSelectedBtn')?.addEventListener('click', _bulkDeleteSelected);
document.getElementById('notesCancelSelectBtn')?.addEventListener('click', _exitSelectMode);
// Notes search with debounce
let _notesSearchTimer;
document.getElementById('notesSearchInput')?.addEventListener('input', (e) => {
clearTimeout(_notesSearchTimer);
const q = e.target.value.trim();
_notesSearchTimer = setTimeout(() => {
_exitSelectMode();
if (q.length >= 2) {
document.getElementById('notesFolderFilter').value = '';
loadNotesList(null, q);
} else if (q.length === 0) {
loadNotesList();
}
}, 300);
});
// No-op: kept for backward compatibility with app.js calling sequence.
// All wiring moved into _registerNotesPanel().
}