Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
202 lines
8.5 KiB
JavaScript
202 lines
8.5 KiB
JavaScript
// ==========================================
|
|
// NotesPane Kit — Default Assembly
|
|
// ==========================================
|
|
// Wires useNotes + all sub-components into the standard
|
|
// notes experience. Surfaces that need a different
|
|
// layout import individual pieces instead.
|
|
//
|
|
// Usage:
|
|
// import { NotesPane } from './components/notes-pane/index.js';
|
|
// html`<${NotesPane} handleRef=${ref} standalone=${true} />`
|
|
//
|
|
// Re-exports all pieces for kit consumers:
|
|
// import { useNotes, NoteList, NoteEditor, ... } from './components/notes-pane/index.js';
|
|
|
|
import { useNotes } from './use-notes.js';
|
|
import { NoteList } from './note-list.js';
|
|
import { NoteListItem } from './note-list-item.js';
|
|
import { NoteEditor } from './note-editor.js';
|
|
import { NoteReader } from './note-reader.js';
|
|
import { QuickSwitcher, saveRecentNote } from './quick-switcher.js';
|
|
import { SaveToNoteDialog } from './save-to-note.js';
|
|
import { renderNoteMarkdown, attachWikilinkHandlers, resolveTransclusions, extractHeadings } from './markdown.js';
|
|
|
|
const { useState, useRef, useEffect, useCallback } = window.hooks;
|
|
const html = window.html;
|
|
|
|
/**
|
|
* Default NotesPane assembly.
|
|
*
|
|
* @param {{
|
|
* initialFolder?: string,
|
|
* initialNoteId?: string,
|
|
* standalone?: boolean,
|
|
* onNoteChange?: (note: object|null) => void,
|
|
* handleRef?: { current: any },
|
|
* className?: string,
|
|
* }} props
|
|
*/
|
|
export function NotesPane(props) {
|
|
const {
|
|
initialFolder,
|
|
initialNoteId,
|
|
standalone = true,
|
|
onNoteChange,
|
|
handleRef,
|
|
className,
|
|
} = props;
|
|
|
|
const notes = useNotes({
|
|
initialFolder,
|
|
initialNoteId,
|
|
onNoteChange,
|
|
standalone,
|
|
enableGraph: true,
|
|
enableQuickSwitcher: true,
|
|
});
|
|
|
|
// ── Lazy-load graph component ───────────
|
|
const [GraphComp, setGraphComp] = useState(null);
|
|
useEffect(() => {
|
|
if (notes.view === 'graph' && !GraphComp) {
|
|
import('./note-graph.js').then(m => setGraphComp(() => m.NoteGraph));
|
|
}
|
|
}, [notes.view, GraphComp]);
|
|
|
|
const graphHandleRef = useRef(null);
|
|
|
|
// ── Graph data loading ──────────────────
|
|
useEffect(() => {
|
|
if (notes.view === 'graph' && !notes.graphData) {
|
|
notes.loadGraph();
|
|
}
|
|
}, [notes.view]);
|
|
|
|
// ── Expose imperative handle ────────────
|
|
useEffect(() => {
|
|
if (handleRef) {
|
|
handleRef.current = {
|
|
getView() { return notes.view; },
|
|
setView(v) { notes.setView(v); },
|
|
openNote(id) { saveRecentNote({ id, title: '' }); notes.openNote(id); },
|
|
newNote() { notes.newNote(); },
|
|
openDailyNote() { notes.openDailyNote(); },
|
|
refreshList() { notes.refreshList(); },
|
|
getEditingId() { return notes.editingId; },
|
|
openQuickSwitcher() { notes.setQuickSwitcherOpen(true); },
|
|
// Surface-driven filter controls (v0.37.11)
|
|
setFolder(f) { notes.setFolder(f); },
|
|
setTagFilter(t) { notes.setTagFilter(t); },
|
|
setSearchQuery(q) { notes.setSearchQuery(q); },
|
|
getFolder() { return notes.folder; },
|
|
getTagFilter() { return notes.tagFilter; },
|
|
};
|
|
}
|
|
});
|
|
|
|
// ── Quick switcher create-new handler ───
|
|
const onQuickSwitcherCreate = useCallback((title) => {
|
|
notes.newNote();
|
|
// The editor will open blank — we can't pre-fill via state here
|
|
// but the title will be empty for the user to type
|
|
}, [notes.newNote]);
|
|
|
|
// ── View routing ────────────────────────
|
|
const renderView = () => {
|
|
switch (notes.view) {
|
|
case 'list':
|
|
return html`
|
|
<${NoteList}
|
|
notes=${notes.notes} loading=${notes.loading}
|
|
hasMore=${notes.hasMore} loadMore=${notes.loadMore}
|
|
folders=${notes.folders} folder=${notes.folder} setFolder=${notes.setFolder}
|
|
sort=${notes.sort} setSort=${notes.setSort}
|
|
searchQuery=${notes.searchQuery} setSearchQuery=${notes.setSearchQuery}
|
|
tagFilter=${notes.tagFilter} setTagFilter=${notes.setTagFilter}
|
|
selectMode=${notes.selectMode} selectedIds=${notes.selectedIds}
|
|
enterSelectMode=${notes.enterSelectMode} exitSelectMode=${notes.exitSelectMode}
|
|
toggleSelect=${notes.toggleSelect} toggleSelectAll=${notes.toggleSelectAll}
|
|
bulkDelete=${notes.bulkDelete}
|
|
onNoteClick=${(id) => { saveRecentNote({ id, title: '' }); notes.openNote(id); }}
|
|
onNewNote=${notes.newNote}
|
|
onDailyNote=${notes.openDailyNote}
|
|
onGraphClick=${() => notes.setView('graph')}
|
|
pinnedIds=${notes.pinnedIds} togglePin=${notes.togglePin}
|
|
standalone=${standalone} />`;
|
|
|
|
case 'editor':
|
|
return html`
|
|
<${NoteEditor}
|
|
currentNote=${notes.currentNote}
|
|
editingId=${notes.editingId}
|
|
folders=${notes.folders}
|
|
onSave=${notes.saveNote}
|
|
onCancel=${() => {
|
|
if (notes.currentNote) {
|
|
notes.setEditorMode('read');
|
|
notes.setView('reader');
|
|
} else {
|
|
notes.setView('list');
|
|
notes.refreshList();
|
|
}
|
|
}}
|
|
onDelete=${notes.deleteNote} />`;
|
|
|
|
case 'reader':
|
|
return html`
|
|
<${NoteReader}
|
|
note=${notes.currentNote}
|
|
backlinks=${notes.backlinks}
|
|
onEdit=${() => {
|
|
notes.setEditorMode('edit');
|
|
notes.setView('editor');
|
|
}}
|
|
onDelete=${notes.deleteNote}
|
|
onCopy=${notes.copyNote}
|
|
onNavigateLink=${notes.navigateToLink}
|
|
onBack=${() => { notes.setView('list'); notes.refreshList(); }}
|
|
isDailyNote=${notes.isDailyNote}
|
|
onDailyPrev=${() => notes.navigateDaily(-1)}
|
|
onDailyNext=${() => notes.navigateDaily(1)} />`;
|
|
|
|
case 'graph':
|
|
if (!GraphComp) {
|
|
return html`<div class="sw-notes-pane__loading">Loading graph\u2026</div>`;
|
|
}
|
|
return html`
|
|
<${GraphComp}
|
|
data=${notes.graphData}
|
|
onNodeClick=${(id) => { notes.openNote(id); }}
|
|
onGhostClick=${(title) => { notes.navigateToLink(title); }}
|
|
onBack=${() => notes.setView('list')}
|
|
handleRef=${graphHandleRef} />`;
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
return html`
|
|
<div class=${'sw-notes-pane' + (className ? ' ' + className : '')}>
|
|
${renderView()}
|
|
|
|
<${QuickSwitcher}
|
|
open=${notes.quickSwitcherOpen}
|
|
onClose=${() => notes.setQuickSwitcherOpen(false)}
|
|
onSelect=${(id) => notes.openNote(id)}
|
|
onCreateNew=${onQuickSwitcherCreate} />
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// ── Kit re-exports ─────────────────────────
|
|
export { useNotes } from './use-notes.js';
|
|
export { NoteList } from './note-list.js';
|
|
export { NoteListItem } from './note-list-item.js';
|
|
export { NoteEditor } from './note-editor.js';
|
|
export { NoteReader } from './note-reader.js';
|
|
export { NoteGraph } from './note-graph.js';
|
|
export { QuickSwitcher, saveRecentNote } from './quick-switcher.js';
|
|
export { SaveToNoteDialog } from './save-to-note.js';
|
|
export { renderNoteMarkdown, attachWikilinkHandlers, resolveTransclusions, extractHeadings } from './markdown.js';
|