3 Commits

Author SHA1 Message Date
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
olivier 141121878f feat: add About tab to settings with version and plugin description 2026-06-22 10:07:22 -04:00
olivier 6a89660cf4 release v1.4.1 2026-06-22 10:01:47 -04:00
6 changed files with 121 additions and 25 deletions
+17 -12
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.0",
"version": "1.5.0",
"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.0",
"version": "1.5.0",
"description": "Calendar, recent files, and custom bookmarks sidebar.",
"main": "main.js",
"scripts": {
+69 -2
View File
@@ -1,11 +1,11 @@
import { Setting, PluginSettingTab, App, Plugin } from 'obsidian';
import { Setting, PluginSettingTab, App, Plugin, setIcon } from 'obsidian';
import { WaypointSettings, DEFAULT_SETTINGS, PeriodNoteSettings } from 'src/settings';
export class WaypointSettingTab extends PluginSettingTab {
private plugin: Plugin;
private settings: WaypointSettings;
private onSettingsChange: () => void;
private activeTab: 'calendar' | 'periodic' | 'recent' | 'display' = 'calendar';
private activeTab: 'calendar' | 'periodic' | 'recent' | 'display' | 'about' = 'calendar';
constructor(app: App, plugin: Plugin, settings: WaypointSettings, onSettingsChange: () => void) {
super(app, plugin);
@@ -25,6 +25,7 @@ export class WaypointSettingTab extends PluginSettingTab {
{ key: 'periodic' as const, label: 'Periodic Notes' },
{ key: 'recent' as const, label: 'Recent Files' },
{ key: 'display' as const, label: 'Display' },
{ key: 'about' as const, label: 'About' },
];
for (const tab of tabs) {
@@ -53,6 +54,9 @@ export class WaypointSettingTab extends PluginSettingTab {
case 'display':
this.renderDisplayTab(tabContent);
break;
case 'about':
this.renderAboutTab(tabContent);
break;
}
}
@@ -216,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();
};
});
}
// ═══════════════════════════════
@@ -297,4 +316,52 @@ export class WaypointSettingTab extends PluginSettingTab {
await (this.plugin as any).saveSettings();
this.onSettingsChange();
}
// ═══════════════════════════════
// About tab
// ═══════════════════════════════
private renderAboutTab(container: HTMLElement): void {
const version = this.plugin.manifest.version;
const header = container.createDiv();
header.style.display = 'flex';
header.style.alignItems = 'center';
header.style.gap = '12px';
header.style.marginBottom = '16px';
const icon = header.createDiv();
icon.style.display = 'flex';
icon.style.alignItems = 'center';
icon.style.justifyContent = 'center';
icon.style.width = '48px';
icon.style.height = '48px';
icon.style.borderRadius = '12px';
icon.style.background = 'var(--interactive-accent)';
icon.style.color = 'var(--text-on-accent)';
icon.style.fontSize = '24px';
setIcon(icon, 'compass');
const titleGroup = header.createDiv();
const title = titleGroup.createEl('h2', { text: 'Waypoint Sidebar' });
title.style.margin = '0';
title.style.lineHeight = '1.2';
const subtitle = titleGroup.createDiv({ text: `v${version}` });
subtitle.style.color = 'var(--text-muted)';
subtitle.style.fontSize = 'var(--font-ui-small)';
const desc = container.createDiv();
desc.style.marginBottom = '20px';
desc.style.lineHeight = '1.6';
desc.style.color = 'var(--text-normal)';
desc.innerHTML = [
`<p><strong>Waypoint</strong> is a sidebar plugin that brings three essential panels into one view:</p>`,
`<ul style="padding-left: 20px; margin: 8px 0;">`,
`<li><strong>Calendar</strong> — a monthly grid for your periodic notes (daily, weekly, monthly, quarterly, yearly). Click any day, week, or month to open or create the corresponding note.</li>`,
`<li><strong>Recent Files</strong> — a list of recently opened files with type filtering, drag-and-drop, and right-click actions.</li>`,
`<li><strong>Bookmarks</strong> — custom bookmarks with icons, groups, nesting, and drag-and-drop reordering. Separate from Obsidian's native bookmarks.</li>`,
`</ul>`,
`<p style="color: var(--text-muted); font-size: var(--font-ui-small);">Made by Olivier. Licensed under MIT.</p>`,
].join('\n');
}
}
+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,
+31 -9
View File
@@ -241,14 +241,34 @@ export class WaypointView extends ItemView {
}
// ── 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;
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) {
const cache = this.app.metadataCache.getFileCache(tfile);
const type = cache?.frontmatter?.type;
if (type && typeof type === 'string') {
typeCounts[type] = (typeCounts[type] || 0) + 1;
}
}
}
}
@@ -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}`);