Files
waypoint/PLAN.md
T

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)

  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:

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