feat: recent files type filter + calendar middle-click + calendar spacing
Recent files: - Type filter bar with pill tags above the list - Scans frontmatter 'type' property of each recent file - Click a pill to filter, click again or 'all' to clear - Active pill shows accent color Calendar: - Middle-click on day/week/quarter/month/year opens in new tab - openPeriodNoteInLeaf() method for leaf-targeted opening - More spacing: taller day cells, more padding, wider margins Bookmarks: - Right-click on recent file → 'Add to bookmarks' option
This commit is contained in:
@@ -63,6 +63,7 @@ export class WaypointView extends ItemView {
|
||||
private currentDisplayMonth: number = moment().month(); // 0-indexed
|
||||
private currentDisplayYear: number = moment().year();
|
||||
private dragId: string | null = null;
|
||||
private recentFilesFilter: string | null = null; // null = show all, else filter by type
|
||||
|
||||
private renderCalendar(): void {
|
||||
const section = this.contentEl.createDiv({ cls: 'waypoint-section' });
|
||||
@@ -230,17 +231,62 @@ export class WaypointView extends ItemView {
|
||||
return;
|
||||
}
|
||||
|
||||
const openFile = this.app.workspace.getActiveFile();
|
||||
// ── Type filter bar ──
|
||||
const typeCounts: Record<string, number> = {};
|
||||
for (const file of this.plugin.recentFiles) {
|
||||
const tfile = this.app.vault.getAbstractFileByPath(file.path);
|
||||
if (tfile instanceof TFile) {
|
||||
const cache = this.app.metadataCache.getFileCache(tfile);
|
||||
const type = cache?.frontmatter?.type;
|
||||
if (type && typeof type === 'string') {
|
||||
typeCounts[type] = (typeCounts[type] || 0) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(typeCounts).length > 0) {
|
||||
const filterBar = section.createDiv({ cls: 'waypoint-recent-filter' });
|
||||
// "All" pill
|
||||
const allPill = filterBar.createSpan({ cls: `waypoint-recent-pill${!this.recentFilesFilter ? ' is-active' : ''}`, text: 'all' });
|
||||
allPill.addEventListener('click', () => {
|
||||
this.recentFilesFilter = null;
|
||||
this.redraw();
|
||||
});
|
||||
// Type pills
|
||||
const sortedTypes = Object.entries(typeCounts).sort(([,a], [,b]) => b - a);
|
||||
for (const [type, count] of sortedTypes) {
|
||||
const pill = filterBar.createSpan({ cls: `waypoint-recent-pill${this.recentFilesFilter === type ? ' is-active' : ''}` });
|
||||
pill.setText(`${type} ${count}`);
|
||||
pill.addEventListener('click', () => {
|
||||
this.recentFilesFilter = this.recentFilesFilter === type ? null : type;
|
||||
this.redraw();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ── Filter the file list ──
|
||||
let filteredFiles = this.plugin.recentFiles;
|
||||
if (this.recentFilesFilter) {
|
||||
filteredFiles = this.plugin.recentFiles.filter(file => {
|
||||
const tfile = this.app.vault.getAbstractFileByPath(file.path);
|
||||
if (tfile instanceof TFile) {
|
||||
const cache = this.app.metadataCache.getFileCache(tfile);
|
||||
const type = cache?.frontmatter?.type;
|
||||
return type === this.recentFilesFilter;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
const openFile = this.app.workspace.getActiveFile();
|
||||
const rootEl = section.createDiv({ cls: 'nav-folder mod-root' });
|
||||
const childrenEl = rootEl.createDiv({ cls: 'nav-folder-children' });
|
||||
|
||||
for (const file of this.plugin.recentFiles) {
|
||||
for (const file of filteredFiles) {
|
||||
const navFile = childrenEl.createDiv({ cls: 'tree-item nav-file' });
|
||||
const navFileTitle = navFile.createDiv({ cls: 'tree-item-self is-clickable nav-file-title' });
|
||||
const navFileTitleContent = navFileTitle.createDiv({ cls: 'tree-item-inner nav-file-title-content' });
|
||||
navFileTitleContent.setText(file.basename);
|
||||
|
||||
const spacer = navFileTitle.createDiv({ cls: 'tree-item-spacer' });
|
||||
|
||||
// Remove button
|
||||
@@ -252,9 +298,7 @@ export class WaypointView extends ItemView {
|
||||
this.plugin.saveSettings();
|
||||
this.redraw();
|
||||
});
|
||||
|
||||
setTooltip(navFile, file.path);
|
||||
|
||||
if (openFile && file.path === openFile.path) {
|
||||
navFileTitle.addClass('is-active');
|
||||
}
|
||||
@@ -306,7 +350,8 @@ export class WaypointView extends ItemView {
|
||||
}
|
||||
menu.showAtPosition({ x: event.clientX, y: event.clientY });
|
||||
});
|
||||
// Left click
|
||||
|
||||
// Left click
|
||||
navFileTitle.addEventListener('click', (event: MouseEvent) => {
|
||||
const newLeaf = Keymap.isModEvent(event);
|
||||
this.focusFile(file, newLeaf);
|
||||
@@ -322,7 +367,7 @@ export class WaypointView extends ItemView {
|
||||
}
|
||||
}
|
||||
|
||||
private focusFile(file: { path: string; basename: string }, newLeaf: boolean | string | 'split'): void {
|
||||
private focusFile(file: { path: string; basename: string }, newLeaf: boolean | string | 'split'): void {
|
||||
const targetFile = this.app.vault.getFiles().find(f => f.path === file.path);
|
||||
if (targetFile) {
|
||||
const leaf = this.app.workspace.getLeaf(newLeaf as any);
|
||||
|
||||
+28
@@ -189,6 +189,34 @@
|
||||
}
|
||||
/* ── Recent Files ── */
|
||||
|
||||
.waypoint-recent-filter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.waypoint-recent-pill {
|
||||
font-size: var(--font-ui-smaller);
|
||||
color: var(--text-muted);
|
||||
background: var(--background-modifier-hover);
|
||||
padding: 1px 6px;
|
||||
border-radius: 10px;
|
||||
cursor: var(--cursor);
|
||||
transition: color 80ms, background 80ms;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.waypoint-recent-pill:hover {
|
||||
color: var(--text-normal);
|
||||
background: var(--background-modifier-active-hover);
|
||||
}
|
||||
|
||||
.waypoint-recent-pill.is-active {
|
||||
color: var(--text-on-accent);
|
||||
background: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.waypoint-recent-files .nav-file {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user