feat: parent notes (file bookmarks with children) + no default icon

- File bookmarks can now have children, rendered with a chevron
- Group bookmarks can have an associated filePath; clicking opens the file,
  clicking chevron toggles collapse
- 'Add as parent note' option in header context menu creates a group
  with the current file linked
- 'Add child note' option in group context menu creates a sub-group
  with the current file linked (parent note pattern)
- Default icon changed from 'file'/'folder' to '' (no icon)
- Chevron click always toggles collapse regardless of type
This commit is contained in:
2026-06-10 20:19:01 -04:00
parent 4278507ae2
commit 3c4fc2d91c
3 changed files with 85 additions and 18 deletions
+6 -6
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -254,7 +254,7 @@ export default class WaypointPlugin extends Plugin {
// ── Bookmarks ── // ── Bookmarks ──
addBookmark(filePath: string, label: string, type: 'file' | 'group' | 'separator' | 'spacer' = 'file', icon = 'file'): BookmarkItem { addBookmark(filePath: string, label: string, type: 'file' | 'group' | 'separator' | 'spacer' = 'file', icon = ''): BookmarkItem {
const id = `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`; const id = `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
const item: BookmarkItem = { const item: BookmarkItem = {
id, id,
+77 -10
View File
@@ -316,12 +316,25 @@ export class WaypointView extends ItemView {
this.plugin.addBookmark(file.path, file.basename, 'file'); this.plugin.addBookmark(file.path, file.basename, 'file');
}); });
}); });
menu.addItem((item) => {
item
.setTitle('Add as parent note')
.setIcon('folder-plus')
.onClick(() => {
const file = this.app.workspace.getActiveFile();
if (!file) return;
const bm = this.plugin.addBookmark(file.path, file.basename, 'group', '');
bm.filePath = file.path;
this.plugin.saveWaypointData();
this.redraw();
});
});
menu.addItem((item) => { menu.addItem((item) => {
item item
.setTitle('New group') .setTitle('New group')
.setIcon('folder-plus') .setIcon('folder-plus')
.onClick(() => { .onClick(() => {
this.plugin.addBookmark('', 'New Group', 'group', 'folder'); this.plugin.addBookmark('', 'New Group', 'group', '');
}); });
}); });
menu.addItem((item) => { menu.addItem((item) => {
@@ -534,23 +547,30 @@ export class WaypointView extends ItemView {
if (isGroup) { if (isGroup) {
const chevron = rowEl.createDiv({ cls: 'waypoint-bm-chevron' }); const chevron = rowEl.createDiv({ cls: 'waypoint-bm-chevron' });
setIcon(chevron, 'chevron-down'); setIcon(chevron, 'chevron-down');
chevron.addEventListener('click', (event: MouseEvent) => {
event.stopPropagation();
this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed });
});
const iconEl = rowEl.createDiv({ cls: 'waypoint-bm-icon' }); const iconEl = rowEl.createDiv({ cls: 'waypoint-bm-icon' });
setIcon(iconEl, item.icon || 'folder'); if (item.icon) setIcon(iconEl, item.icon);
const labelEl = rowEl.createDiv({ cls: 'waypoint-bm-label', text: item.label }); const labelEl = rowEl.createDiv({ cls: 'waypoint-bm-label', text: item.label });
// Click group row → open linked file (if any), otherwise toggle collapse
rowEl.addEventListener('click', (event: MouseEvent) => { rowEl.addEventListener('click', (event: MouseEvent) => {
// Mod+click opens group's linked file if (item.filePath) {
if (item.filePath && Keymap.isModEvent(event)) {
const tfile = this.app.vault.getFileByPath(item.filePath); const tfile = this.app.vault.getFileByPath(item.filePath);
if (tfile) this.app.workspace.getLeaf(false).openFile(tfile); if (tfile) {
const newLeaf = Keymap.isModEvent(event);
this.app.workspace.getLeaf(newLeaf as any).openFile(tfile);
return; return;
} }
}
this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed }); this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed });
}); });
// Middle click on group header → open group's linked file in new tab // Middle click on group → open in new tab
rowEl.addEventListener('mousedown', (event: MouseEvent) => { rowEl.addEventListener('mousedown', (event: MouseEvent) => {
if (event.button === 1 && item.filePath) { if (event.button === 1 && item.filePath) {
event.preventDefault(); event.preventDefault();
@@ -570,8 +590,22 @@ export class WaypointView extends ItemView {
// ── File: icon + label ── // ── File: icon + label ──
} else { } else {
// Chevron for file bookmarks that have children
if (item.children && item.children.length > 0) {
const chevron = rowEl.createDiv({ cls: 'waypoint-bm-chevron' });
setIcon(chevron, 'chevron-down');
chevron.addEventListener('click', (event: MouseEvent) => {
event.stopPropagation();
this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed });
});
if (item.collapsed) {
rowEl.addClass('collapsed');
chevron.style.transform = 'rotate(-90deg)';
}
}
const iconEl = rowEl.createDiv({ cls: 'waypoint-bm-icon' }); const iconEl = rowEl.createDiv({ cls: 'waypoint-bm-icon' });
setIcon(iconEl, item.icon || 'file'); if (item.icon) setIcon(iconEl, item.icon);
const labelEl = rowEl.createDiv({ cls: 'waypoint-bm-label', text: item.label }); const labelEl = rowEl.createDiv({ cls: 'waypoint-bm-label', text: item.label });
setTooltip(rowEl, item.filePath); setTooltip(rowEl, item.filePath);
@@ -599,6 +633,14 @@ export class WaypointView extends ItemView {
} }
} }
}); });
// Children container for file bookmarks with children
if (item.children && item.children.length > 0) {
const childrenContainer = container.createDiv({
cls: `waypoint-bookmark-children${item.collapsed ? ' collapsed' : ''}`,
});
this.renderBookmarkList(childrenContainer, item.children, depth + 1);
}
} }
// ── Right-click context menu (both types) ── // ── Right-click context menu (both types) ──
@@ -687,7 +729,7 @@ export class WaypointView extends ItemView {
menu.addItem((i) => menu.addItem((i) =>
i i
.setTitle('Add bookmark here') .setTitle('Add bookmark here')
.setIcon('plus') .setIcon('file-plus')
.onClick(() => { .onClick(() => {
const file = this.app.workspace.getActiveFile(); const file = this.app.workspace.getActiveFile();
if (!file) { if (!file) {
@@ -699,7 +741,32 @@ export class WaypointView extends ItemView {
type: 'file', type: 'file',
label: file.basename, label: file.basename,
filePath: file.path, filePath: file.path,
icon: 'file', icon: '',
children: [],
collapsed: false,
indent: item.indent + 1,
};
item.children.push(child);
this.plugin.saveWaypointData();
this.redraw();
}),
);
menu.addItem((i) =>
i
.setTitle('Add child note')
.setIcon('file-plus')
.onClick(() => {
const file = this.app.workspace.getActiveFile();
if (!file) {
new Notice('No active file');
return;
}
const child: BookmarkItem = {
id: `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
type: 'group',
label: file.basename,
filePath: file.path,
icon: '',
children: [], children: [],
collapsed: false, collapsed: false,
indent: item.indent + 1, indent: item.indent + 1,
@@ -719,7 +786,7 @@ export class WaypointView extends ItemView {
type: 'group', type: 'group',
label: 'New Group', label: 'New Group',
filePath: '', filePath: '',
icon: 'folder', icon: '',
children: [], children: [],
collapsed: false, collapsed: false,
indent: item.indent + 1, indent: item.indent + 1,