15 KiB
Waypoint Plugin — Implementation Plan
Overview
A sidebar plugin for Obsidian that combines three panels into one coherent view: a periodic note calendar (day/week/month/quarter/year), a recent files list, and a custom favorites/bookmarks system with rename, icons, and grouping.
Features (from requirements)
- Calendar panel — shows a month grid with every day clickable
- Period indicators — day, week, month, quarter, year all displayed and clickable
- Note creation on click — clicking a period creates a note at a configurable path with a configurable template
- Recent files — list of recently opened/edited files
- Favorites/Bookmarks — custom bookmarks (distinct from Obsidian native bookmarks) with:
- Command: "Add current file as Waypoint bookmark"
- Rename without renaming the underlying file
- Assign an icon (from Lucide icons)
- Right-click context menu: rename, change icon, remove, move
- Foldable groups and indented hierarchy
- Settings — configure folder paths and templates for each period type
Architecture
Approach
- Plain ItemView (not React) — simpler, matches recent-files-obsidian's approach, avoids extra dependencies
- Single view type
waypoint-viewthat contains all three panels stacked vertically - Plugin data stored via
Plugin.loadData()/Plugin.saveData()for bookmarks and recent files - Settings via
PluginSettingTab
Why not React?
The daily-note-calendar plugin uses React, but that adds complexity (esbuild config for JSX, react-dom dependency). The recent-files plugin does everything with plain Obsidian DOM helpers (createDiv, setIcon, etc.) and is much simpler. We can build a clean, native-feeling UI without React. If the calendar grid becomes complex, we can reconsider.
File Structure
waypoint/
├── manifest.json
├── package.json
├── tsconfig.json
├── esbuild.config.mjs
├── styles.css
├── src/
│ ├── main.ts # Plugin entry point
│ ├── settings.ts # Settings interface + defaults + SettingTab
│ ├── views/
│ │ ├── waypoint-view.ts # Main ItemView (orchestrates panels)
│ │ ├── calendar-panel.ts # Calendar month grid + period indicators
│ │ ├── recent-files-panel.ts # Recent files list
│ │ └── favorites-panel.ts # Favorites/bookmarks tree
│ ├── models/
│ │ └── bookmark.ts # Bookmark item/group interfaces
│ ├── services/
│ │ ├── calendar-service.ts # Date math, period detection, note creation
│ │ ├── recent-files-service.ts # Track and filter recent files
│ │ └── favorites-service.ts # CRUD for custom bookmarks
│ └── utils/
│ ├── date-utils.ts # Date formatting, period navigation
│ └── icon-utils.ts # Icon picker modal
└── README.md
Component Details
1. Calendar Panel (calendar-panel.ts)
Visual layout (top to bottom):
┌─────────────────────────────────────┐
│ Q3 · June · 1st, 2026 │ ← Breadcrumb: quarter, month, day (all clickable)
├─────────────────────────────────────┤
│ ◀ June 2026 ▶ │ ← Month+Year header with nav
├─────────────────────────────────────┤
│ Mon Tue Wed Thu Fri Sat Sun │ ← Day-of-week headers
├─────────────────────────────────────┤
│ W22 1 2 3 4 5 6 │ ← Week rows (week number + 7 days)
│ W23 7 8 9 10 11 12 13 │
│ W24 14 15 16 17 18 19 20 │
│ W25 21 22 23 24 25 26 27 │
│ W26 28 29 30 │
├─────────────────────────────────────┤
│ ◀ [Today] ▶ │ ← Today navigation
└─────────────────────────────────────┘
Behavior:
- Click a day cell → open or create the daily note for that date
- Click week number → open/create the weekly note
- Click breadcrumb quarter → open/create the quarterly note
- Click breadcrumb month → open/create the monthly note
- Click breadcrumb day → open/create the daily note
- Left/right arrows on month header → navigate months
- "Today" button → jump to current month
- Dot indicator → show which days already have notes
- Today highlight → accent-colored border on current day
- Week numbers displayed as the first column, using ISO week numbering (weeks start on Monday)
Note creation logic:
- Check if a note exists at
{folder}/{nameTemplate}using the date - If it exists, open it
- If not, create it using the configured template file (via Obsidian API)
- Apply the
typeproperty matching the period type (daily-note, weekly-note, etc.)
2. Recent Files Panel (recent-files-panel.ts)
Based closely on the recent-files-obsidian plugin:
- Track file opens/edits via
app.workspace.on('file-open') - Store as ordered list of
{ path, basename } - Display in a
nav-folderstyled list (matches Obsidian's file explorer look) - Each item shows:
- File name (supporting frontmatter-title plugin if available)
- Hover preview via
hover-linkevent - Drag support (wikilink insertion)
- Right-click: "Open in new tab" + Obsidian file menu
- Middle-click / Ctrl+click: open in new pane
- X button on hover to remove from list
- Respect omitted paths/tags filter (from settings)
- Max length configurable
3. Favorites / Bookmarks Panel (favorites-panel.ts)
Data model:
interface BookmarkItem {
id: string; // unique ID
type: 'file' | 'group';
label: string; // display name (can differ from file name)
filePath: string; // path to the Obsidian file (empty for groups)
icon: string; // Lucide icon name (default: 'file')
children: BookmarkItem[]; // for groups
collapsed: boolean; // group fold state
indent: number; // indent level (0 = top level)
}
Visual layout:
── Waypoint Bookmarks ────
📁 Projects ← group (collapsible)
📄 Fabrique ← file bookmark
📄 Haro dashboard ← file bookmark
📁 References ← group
📄 CSS grid notes
📄 Inbox ← ungrouped bookmark
Behavior:
- Click file bookmark → opens the file
- Click group → toggles collapse/expand
- Drag to reorder (stretch goal — use Obsidian's drag system)
- Right-click on file bookmark → context menu:
- Rename bookmark
- Change icon (opens icon picker)
- Remove bookmark
- Move to group → submenu of existing groups
- Right-click on group → context menu:
- Rename group
- Change icon
- Remove group (and all children)
- Add bookmark to this group
- New sub-group
- Right-click on empty space → context menu:
- New group
- Add current file
Add current file command:
- Command ID:
waypoint:add-bookmark - Picks up the active file
- Shows a prompt to set the display name (defaults to file's basename)
- Shows an icon picker (default: file icon)
- Adds to root level (or active group if one is right-clicked)
4. Settings Tab (settings.ts)
┌── Waypoint Settings ──────────────────┐
│ │
│ 📅 Calendar │
│ ┌─ General ─────────────────────────┐ │
│ │ First day of week [Monday ▼] │ │
│ │ Week number standard [ISO ▼] │ │
│ │ Show note indicators [toggle] │ │
│ └──────────────────────────────────┘ │
│ │
│ ┌─ Periodic Note Paths ─────────────┐ │
│ │ Daily note │ │
│ │ Folder: [periodic/daily ] │ │
│ │ Template: [templates/daily ] │ │
│ │ Name: [yyyy-MM-dd ] │ │
│ │ Type: [daily-note ] │ │
│ │ │ │
│ │ Weekly note │ │
│ │ Folder: [periodic/weekly ] │ │
│ │ Template: [templates/weekly ] │ │
│ │ Name: [GGGG-[W]WW ] │ │
│ │ Type: [weekly-note ] │ │
│ │ │ │
│ │ Monthly note │ │
│ │ Folder: [periodic/monthly ] │ │
│ │ ... │ │
│ │ │ │
│ │ Quarterly note │ │
│ │ ... │ │
│ │ │ │
│ │ Yearly note │ │
│ │ ... │ │
│ └──────────────────────────────────┘ │
│ │
│ 📄 Recent Files │
│ ┌──────────────────────────────────┐ │
│ │ Max items: [50 ] │ │
│ │ Update on: [File opened ▼] │ │
│ │ Omitted paths: [textarea ] │ │
│ │ Omitted tags: [textarea ] │ │
│ └──────────────────────────────────┘ │
│ │
│ ⭐ Favorites │
│ ┌──────────────────────────────────┐ │
│ │ (No specific settings yet) │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────┘
Implementation Steps
Step 1: Project scaffolding
- Create
manifest.json,package.json,tsconfig.json,esbuild.config.mjs - Install deps:
obsidian,builtin-modules, typescript - Create folder structure
Step 2: Settings
- Define interfaces:
WaypointSettings,PeriodNoteSettings - Defaults matching O-vault convention:
- Daily:
periodic/daily/, templateTemplates/Daily note, nameyyyy-MM-dd - Weekly:
periodic/weekly/, templateTemplates/Weekly note, nameGGGG-[W]WW - Monthly:
periodic/monthly/, templateTemplates/Monthly note, nameyyyy-MM - Quarterly:
periodic/quarterly/, templateTemplates/Quarterly note, nameyyyy-[Q]Q - Yearly:
periodic/yearly/, templateTemplates/Yearly note, nameyyyy
- Daily:
- Implement
WaypointSettingTabwith sections for each period + recent files
Step 3: Calendar Service
getMonthGrid(year, month, firstDayOfWeek)→ array of weeks with day objectsgetPeriodFromDate(date)→ { day, week, month, quarter, year }findOrCreateNote(period, settings)→ checks vault, creates if missing- Date formatting using
moment()(bundled in Obsidian)
Step 4: Calendar Panel (ItemView section)
- Render the calendar grid using Obsidian DOM (
createDiv,createSpan) - Period header row (year/quarter/week)
- Month header with nav arrows
- Day-of-week header row
- Day cells (with today highlight, note indicators, other-month dimming)
- Arrow navigation for months
- Click handlers for each period type
Step 5: Recent Files Service
- Track
file-openevents - Maintain ordered list (max length, dedup)
- Support omitted paths/tags filtering
Step 6: Recent Files Panel
- Render the list in
nav-folderstyle - Click, hover, drag, right-click, middle-click, delete button
Step 7: Favorites Service
- CRUD operations on
BookmarkItem[] - Persist via
Plugin.loadData/saveData - Add current file command
- Rename, icon change, remove, grouping
Step 8: Favorites Panel
- Render tree with collapsible groups
- Context menus for items and groups
- Icon display using
setIcon() - Drag support (stretch)
Step 9: Waypoint View (main orchestrator)
ItemViewsubclass- On open: create three sections inside
contentEl - Redraw on data changes
- Register as sidebar view type
waypoint-view
Step 10: Main Plugin
onload(): load data, register view, register commands, register events, add settings tab- Auto-open on right sidebar on first load
- Commands:
waypoint:open-view→ reveal the waypoint sidebarwaypoint:add-bookmark→ add current file as bookmarkwaypoint:go-to-today→ open today's daily note
- Events:
file-open→ update recent files + redrawcreate,delete,rename→ update calendar note indicators + redraw- Midnight check → refresh today highlight
Key Design Decisions
-
No React — Using native Obsidian DOM APIs avoids build complexity and keeps the bundle small. The calendar grid is straightforward enough to render imperatively.
-
Flat data storage — Bookmarks and recent files stored via Plugin.loadData/saveData as JSON. This makes them portable and compatible with Obsidian sync.
-
Separate from native bookmarks — We never touch
app.internalPlugins.getEnabledPluginById('bookmarks'). These are entirely custom bookmarks with their own data store. -
Icon picker — We'll build a simple icon picker modal using Obsidian's
SuggestModalor a grid of Lucide icons that are commonly used (file, folder, star, heart, bookmark, flag, pin, etc.). We won't implement a searchable full icon browser initially — a curated selection of ~40 icons plus a text input for any Lucide icon name. -
O-vault aware — Default paths match Olivier's vault structure. All settings are overridable.
Stretch Goals (after MVP)
- Drag-and-drop reordering in favorites panel
- Search/filter within bookmarks
- Multiple bookmark lists / profiles
- Sync bookmarks with Obsidian Sync
- Show note previews on calendar hover
- Custom CSS classes per bookmark (color coding)
- Nested groups beyond 2 levels
- Collapse/expand all in favorites
- Keyboard shortcuts for bookmark navigation