refactor: simplify bookmark menus — visible ⋯ button, flat context menus
Header: - Replace hidden right-click with visible ⋯ button (more-horizontal icon) - Menu: Add current file / Add as parent note / New group / separator / Add spacer File bookmark right-click (5 items, flat): Open in new tab / Rename / Change icon / Remove Group/parent note right-click (7 items max, flat): Open in new tab (only if linked) / Rename / Change icon / Expand|Collapse / Add child bookmark / Add child note / New sub-group / Remove Separator/Spacer right-click (1 item): Remove Removed dead code: insertAdjacent, collectGroups, collectDescendantIds, moveBookmarkToGroup — all moving is now drag-and-drop only
This commit is contained in:
+60
-142
@@ -303,8 +303,11 @@ export class WaypointView extends ItemView {
|
||||
const headerEl = section.createDiv({ cls: 'waypoint-section-header' });
|
||||
headerEl.setText('Waypoint Bookmarks');
|
||||
|
||||
// Right-click on header area → add bookmark / group
|
||||
headerEl.addEventListener('contextmenu', (event: MouseEvent) => {
|
||||
// ⋯ button — visible add menu
|
||||
const moreBtn = headerEl.createEl('button', { cls: 'waypoint-header-more' });
|
||||
setIcon(moreBtn, 'more-horizontal');
|
||||
setTooltip(moreBtn, 'Add bookmark');
|
||||
moreBtn.addEventListener('click', (event: MouseEvent) => {
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
@@ -337,6 +340,7 @@ export class WaypointView extends ItemView {
|
||||
this.plugin.addBookmark('', 'New Group', 'group', '');
|
||||
});
|
||||
});
|
||||
menu.addSeparator();
|
||||
menu.addItem((item) => {
|
||||
item
|
||||
.setTitle('Add separator')
|
||||
@@ -353,7 +357,6 @@ export class WaypointView extends ItemView {
|
||||
this.plugin.addBookmark('', '', 'spacer');
|
||||
});
|
||||
});
|
||||
|
||||
menu.showAtPosition({ x: event.clientX, y: event.clientY });
|
||||
});
|
||||
|
||||
@@ -655,6 +658,17 @@ export class WaypointView extends ItemView {
|
||||
private showBookmarkContextMenu(event: MouseEvent, item: BookmarkItem): void {
|
||||
const menu = new Menu();
|
||||
|
||||
if (item.type === 'separator' || item.type === 'spacer') {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Remove')
|
||||
.setIcon('trash')
|
||||
.onClick(() => this.plugin.removeBookmark(item.id)),
|
||||
);
|
||||
menu.showAtPosition({ x: event.clientX, y: event.clientY });
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.type === 'file') {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
@@ -662,80 +676,69 @@ export class WaypointView extends ItemView {
|
||||
.setIcon('file-plus')
|
||||
.onClick(() => {
|
||||
const tfile = this.app.vault.getFileByPath(item.filePath);
|
||||
if (tfile) {
|
||||
this.app.workspace.getLeaf('tab').openFile(tfile);
|
||||
}
|
||||
if (tfile) this.app.workspace.getLeaf('tab').openFile(tfile);
|
||||
}),
|
||||
);
|
||||
menu.addSeparator();
|
||||
}
|
||||
|
||||
if (item.type !== 'separator' && item.type !== 'spacer') {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Rename')
|
||||
.setIcon('pencil')
|
||||
.onClick(() => this.promptRename(item)),
|
||||
);
|
||||
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Change icon')
|
||||
.setIcon('image')
|
||||
.onClick(() => this.promptIcon(item)),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Move to group options ──
|
||||
const allGroups = this.collectGroups(this.plugin.waypointData.bookmarks);
|
||||
const ownIds = this.collectDescendantIds(item);
|
||||
const availableGroups = allGroups.filter(g => !ownIds.includes(g.id) && g.id !== item.id);
|
||||
|
||||
if ((availableGroups.length > 0 || item.type === 'file' || item.type === 'group') && item.type !== 'separator' && item.type !== 'spacer') {
|
||||
menu.addSeparator();
|
||||
if (availableGroups.length > 0) {
|
||||
for (const group of availableGroups) {
|
||||
menu.addItem((mi) =>
|
||||
mi
|
||||
.setTitle(` ${group.label}`)
|
||||
.setIcon(group.icon || 'folder')
|
||||
.onClick(() => {
|
||||
this.moveBookmarkToGroup(item.id, group.id);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
// Add "Root" option for ungrouping
|
||||
menu.addItem((mi) =>
|
||||
mi
|
||||
.setTitle(' (Root)')
|
||||
.setIcon('layout')
|
||||
.onClick(() => {
|
||||
this.moveBookmarkToGroup(item.id, null);
|
||||
}),
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Remove')
|
||||
.setIcon('trash')
|
||||
.onClick(() => this.plugin.removeBookmark(item.id)),
|
||||
);
|
||||
}
|
||||
} else if (item.type === 'group') {
|
||||
if (item.filePath) {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Open in new tab')
|
||||
.setIcon('file-plus')
|
||||
.onClick(() => {
|
||||
const tfile = this.app.vault.getFileByPath(item.filePath);
|
||||
if (tfile) this.app.workspace.getLeaf('tab').openFile(tfile);
|
||||
}),
|
||||
);
|
||||
menu.addSeparator();
|
||||
}
|
||||
|
||||
if (item.type === 'group') {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Rename')
|
||||
.setIcon('pencil')
|
||||
.onClick(() => this.promptRename(item)),
|
||||
);
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Change icon')
|
||||
.setIcon('image')
|
||||
.onClick(() => this.promptIcon(item)),
|
||||
);
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle(item.collapsed ? 'Expand' : 'Collapse')
|
||||
.setIcon(item.collapsed ? 'chevron-down' : 'chevron-up')
|
||||
.onClick(() => {
|
||||
this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed });
|
||||
}),
|
||||
.onClick(() => this.plugin.updateBookmark(item.id, { collapsed: !item.collapsed })),
|
||||
);
|
||||
menu.addSeparator();
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Add bookmark here')
|
||||
.setTitle('Add child bookmark')
|
||||
.setIcon('file-plus')
|
||||
.onClick(() => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (!file) {
|
||||
new Notice('No active file');
|
||||
return;
|
||||
}
|
||||
if (!file) { new Notice('No active file'); return; }
|
||||
const child: BookmarkItem = {
|
||||
id: `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
||||
type: 'file',
|
||||
@@ -754,13 +757,10 @@ export class WaypointView extends ItemView {
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Add child note')
|
||||
.setIcon('file-plus')
|
||||
.setIcon('folder-plus')
|
||||
.onClick(() => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (!file) {
|
||||
new Notice('No active file');
|
||||
return;
|
||||
}
|
||||
if (!file) { new Notice('No active file'); return; }
|
||||
const child: BookmarkItem = {
|
||||
id: `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
||||
type: 'group',
|
||||
@@ -796,100 +796,18 @@ export class WaypointView extends ItemView {
|
||||
this.redraw();
|
||||
}),
|
||||
);
|
||||
menu.addSeparator();
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Remove')
|
||||
.setIcon('trash')
|
||||
.onClick(() => this.plugin.removeBookmark(item.id)),
|
||||
);
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
// ── Insert separator / spacer ──
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Insert separator above')
|
||||
.setIcon('separator-vertical')
|
||||
.onClick(() => this.insertAdjacent(item.id, 'separator', 'above')),
|
||||
);
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Insert separator below')
|
||||
.setIcon('separator-vertical')
|
||||
.onClick(() => this.insertAdjacent(item.id, 'separator', 'below')),
|
||||
);
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Insert spacer above')
|
||||
.setIcon('space')
|
||||
.onClick(() => this.insertAdjacent(item.id, 'spacer', 'above')),
|
||||
);
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Insert spacer below')
|
||||
.setIcon('space')
|
||||
.onClick(() => this.insertAdjacent(item.id, 'spacer', 'below')),
|
||||
);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
menu.addItem((i) =>
|
||||
i
|
||||
.setTitle('Remove')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
this.plugin.removeBookmark(item.id);
|
||||
}),
|
||||
);
|
||||
|
||||
menu.showAtPosition({ x: event.clientX, y: event.clientY });
|
||||
}
|
||||
|
||||
private insertAdjacent(targetId: string, type: 'separator' | 'spacer', position: 'above' | 'below'): void {
|
||||
const newItem: BookmarkItem = {
|
||||
id: `bm-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
||||
type,
|
||||
label: '',
|
||||
filePath: '',
|
||||
icon: '',
|
||||
children: [],
|
||||
collapsed: false,
|
||||
indent: 0,
|
||||
};
|
||||
|
||||
const insert = (items: BookmarkItem[]): boolean => {
|
||||
const idx = items.findIndex(i => i.id === targetId);
|
||||
if (idx >= 0) {
|
||||
const insertIdx = position === 'above' ? idx : idx + 1;
|
||||
items.splice(insertIdx, 0, newItem);
|
||||
return true;
|
||||
}
|
||||
for (const item of items) {
|
||||
if (item.children && insert(item.children)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
insert(this.plugin.waypointData.bookmarks);
|
||||
this.plugin.saveWaypointData();
|
||||
this.redraw();
|
||||
}
|
||||
|
||||
private collectGroups(items: BookmarkItem[]): BookmarkItem[] {
|
||||
const groups: BookmarkItem[] = [];
|
||||
for (const item of items) {
|
||||
if (item.type === 'group') {
|
||||
groups.push(item);
|
||||
groups.push(...this.collectGroups(item.children));
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
private collectDescendantIds(item: BookmarkItem): string[] {
|
||||
const ids: string[] = [];
|
||||
for (const child of item.children) {
|
||||
ids.push(child.id);
|
||||
ids.push(...this.collectDescendantIds(child));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private showDropIndicator(el: HTMLElement, e: MouseEvent): void {
|
||||
// Clear indicator from all siblings first
|
||||
const parent = el.parentElement;
|
||||
|
||||
+22
@@ -27,6 +27,28 @@
|
||||
margin-bottom: 4px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.waypoint-header-more {
|
||||
margin-left: auto;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: var(--cursor);
|
||||
color: var(--text-faint);
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: color 80ms, background 80ms;
|
||||
}
|
||||
|
||||
.waypoint-header-more:hover {
|
||||
color: var(--text-accent);
|
||||
background-color: var(--background-modifier-active-hover);
|
||||
}
|
||||
|
||||
/* ── Calendar ── */
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
- [ ] in the bookmarks, i want to have notes that are parents to other notes
|
||||
- [ ] by default, the bookmark should have no icon
|
||||
- [ ] the way to search for icons should be improved. on the lucide icon website, the search works by more than only the icon’s title. i want to be able to load all the icon (not by default though)
|
||||
- [ ] add a right click menu on the recent files to make them bookmarks
|
||||
- [ ] improve the drag and drop to have identations and groups
|
||||
- [ ] calendar
|
||||
- [ ] middle click on a date/week/etc. should open it in a new tab
|
||||
- [ ] i want to improve the look of the calendar. more space, a bit more height
|
||||
|
||||
Reference in New Issue
Block a user