# 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) 1. **Calendar panel** — shows a month grid with every day clickable 2. **Period indicators** — day, week, month, quarter, year all displayed and clickable 3. **Note creation on click** — clicking a period creates a note at a configurable path with a configurable template 4. **Recent files** — list of recently opened/edited files 5. **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 6. **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-view` that 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:** 1. Check if a note exists at `{folder}/{nameTemplate}` using the date 2. If it exists, open it 3. If not, create it using the configured template file (via Obsidian API) 4. Apply the `type` property 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-folder` styled list (matches Obsidian's file explorer look) - Each item shows: - File name (supporting frontmatter-title plugin if available) - Hover preview via `hover-link` event - 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:** ```typescript 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/`, template `Templates/Daily note`, name `yyyy-MM-dd` - Weekly: `periodic/weekly/`, template `Templates/Weekly note`, name `GGGG-[W]WW` - Monthly: `periodic/monthly/`, template `Templates/Monthly note`, name `yyyy-MM` - Quarterly: `periodic/quarterly/`, template `Templates/Quarterly note`, name `yyyy-[Q]Q` - Yearly: `periodic/yearly/`, template `Templates/Yearly note`, name `yyyy` - Implement `WaypointSettingTab` with sections for each period + recent files ### Step 3: Calendar Service - `getMonthGrid(year, month, firstDayOfWeek)` → array of weeks with day objects - `getPeriodFromDate(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-open` events - Maintain ordered list (max length, dedup) - Support omitted paths/tags filtering ### Step 6: Recent Files Panel - Render the list in `nav-folder` style - 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) - `ItemView` subclass - 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 sidebar - `waypoint:add-bookmark` → add current file as bookmark - `waypoint:go-to-today` → open today's daily note - Events: - `file-open` → update recent files + redraw - `create`, `delete`, `rename` → update calendar note indicators + redraw - Midnight check → refresh today highlight --- ## Key Design Decisions 1. **No React** — Using native Obsidian DOM APIs avoids build complexity and keeps the bundle small. The calendar grid is straightforward enough to render imperatively. 2. **Flat data storage** — Bookmarks and recent files stored via Plugin.loadData/saveData as JSON. This makes them portable and compatible with Obsidian sync. 3. **Separate from native bookmarks** — We never touch `app.internalPlugins.getEnabledPluginById('bookmarks')`. These are entirely custom bookmarks with their own data store. 4. **Icon picker** — We'll build a simple icon picker modal using Obsidian's `SuggestModal` or 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. 5. **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