2 Commits

Author SHA1 Message Date
olivier 3c7b6741f5 fix: calendar disappeared for existing users
Shallow Object.assign on settings meant filterTags (new in 1.5.0) was
undefined for anyone with prior saved settings. Accessing .length on
undefined threw, killing the entire redraw before calendar could render.

- Defensive fallback: filterTags || []
- Deep merge on loadSettings for recentFiles, calendar, display
2026-06-22 10:18:37 -04:00
olivier abf4d6ccf7 feat: configurable filter tags for recent files
New 'Filter tags' setting in Recent Files tab. Enter tag names one per line
to pin specific tags as filter pills. Leave empty to auto-detect from
frontmatter 'type' property (existing behavior).
2026-06-22 10:15:54 -04:00
7 changed files with 71 additions and 24 deletions
+17 -13
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{
"id": "waypoint-sidebar",
"name": "Waypoint Sidebar",
"version": "1.4.1",
"version": "1.5.1",
"minAppVersion": "0.16.3",
"description": "Calendar, recent files, and custom bookmarks sidebar.",
"author": "Olivier",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "waypoint",
"version": "1.4.1",
"version": "1.5.1",
"description": "Calendar, recent files, and custom bookmarks sidebar.",
"main": "main.js",
"scripts": {
+4
View File
@@ -199,6 +199,10 @@ export default class WaypointPlugin extends Plugin {
const saved = await this.loadData() as Record<string, unknown> | null;
const s = (saved?.settings || {}) as Partial<WaypointSettings>;
this.settings = Object.assign({}, DEFAULT_SETTINGS, s);
// Deep merge nested objects that might be missing new fields
this.settings.recentFiles = Object.assign({}, DEFAULT_SETTINGS.recentFiles, s.recentFiles || {});
this.settings.calendar = Object.assign({}, DEFAULT_SETTINGS.calendar, s.calendar || {});
this.settings.display = Object.assign({}, DEFAULT_SETTINGS.display, s.display || {});
}
async saveSettings(): Promise<void> {
+15
View File
@@ -220,6 +220,21 @@ export class WaypointSettingTab extends PluginSettingTab {
this.saveAndRefresh();
};
});
const filterDesc = new DocumentFragment();
filterDesc.appendText('Tags to show as filter pills above the file list. One per line. Leave empty to auto-detect from frontmatter `type` property.');
new Setting(container)
.setName('Filter tags')
.setDesc(filterDesc)
.addTextArea((text) => {
text.inputEl.setAttr('rows', 4);
text.setPlaceholder('meeting\nperson\nproject');
text.setValue(this.settings.recentFiles.filterTags.join('\n'));
text.inputEl.onblur = () => {
this.settings.recentFiles.filterTags = text.getValue().split('\n').filter(t => t.trim());
this.saveAndRefresh();
};
});
}
// ═══════════════════════════════
+2
View File
@@ -17,6 +17,7 @@ export interface RecentFilesSettings {
updateOn: 'file-open' | 'file-edit';
omittedPaths: string[];
omittedTags: string[];
filterTags: string[]; // tags to show as filter pills (empty = auto-detect from frontmatter)
}
export interface DisplaySettings {
@@ -79,6 +80,7 @@ export const DEFAULT_SETTINGS: WaypointSettings = {
updateOn: 'file-open',
omittedPaths: [],
omittedTags: [],
filterTags: [],
},
display: {
rowSize: 26,
+24 -2
View File
@@ -241,7 +241,26 @@ export class WaypointView extends ItemView {
}
// ── Type filter bar ──
const typeCounts: Record<string, number> = {};
const configuredTags = this.plugin.settings.recentFiles.filterTags || [];
let typeCounts: Record<string, number> = {};
if (configuredTags.length > 0) {
// Use configured tags — count occurrences in recent files
for (const tag of configuredTags) {
typeCounts[tag] = 0;
}
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.hasOwnProperty(type)) {
typeCounts[type]++;
}
}
}
} else {
// Auto-detect from frontmatter `type` property
for (const file of this.plugin.recentFiles) {
const tfile = this.app.vault.getAbstractFileByPath(file.path);
if (tfile instanceof TFile) {
@@ -252,6 +271,7 @@ export class WaypointView extends ItemView {
}
}
}
}
if (Object.keys(typeCounts).length > 0) {
const filterBar = section.createDiv({ cls: 'waypoint-recent-filter' });
@@ -262,7 +282,9 @@ export class WaypointView extends ItemView {
this.redraw();
});
// Type pills
const sortedTypes = Object.entries(typeCounts).sort(([,a], [,b]) => b - a);
const sortedTypes = configuredTags.length > 0
? Object.entries(typeCounts) // preserve configured order
: Object.entries(typeCounts).sort(([,a], [,b]) => b - a); // sort by count
for (const [type, count] of sortedTypes) {
const pill = filterBar.createSpan({ cls: `waypoint-recent-pill${this.recentFilesFilter === type ? ' is-active' : ''}` });
pill.setText(`${type} ${count}`);