Initial commit: Waypoint Obsidian plugin with calendar, recent files, and bookmarks
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user