new
This commit is contained in:
@@ -0,0 +1,375 @@
|
|||||||
|
# Waypoint Sidebar — Technical Documentation
|
||||||
|
|
||||||
|
> Obsidian plugin (id: `waypoint-sidebar`) providing a unified sidebar with calendar, recent files, and custom bookmarks. Replaces separate Calendar and Bookmarks core plugins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── main.ts Plugin entry — lifecycle, commands, events, data persistence
|
||||||
|
├── settings.ts Interface definitions + DEFAULT_SETTINGS constant
|
||||||
|
├── settings-tab.ts PluginSettingTab UI (calendar, periodic paths, recent files)
|
||||||
|
├── models/
|
||||||
|
│ └── bookmark.ts BookmarkItem + WaypointData interfaces
|
||||||
|
├── utils/
|
||||||
|
│ └── date-utils.ts Moment.js helpers: period formatting, month grid, navigation
|
||||||
|
└── views/
|
||||||
|
└── waypoint-view.ts ItemView subclass — full sidebar rendering + interaction
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build:** esbuild bundles `src/main.ts` → `main.js`. TypeScript strict, ESNext target.
|
||||||
|
|
||||||
|
**Data persistence:** Single `data.json` via Obsidian `Plugin.loadData()/saveData()`. Top-level keys: `settings` (merged with `DEFAULT_SETTINGS`), `waypointData` (bookmark tree). Recent files are in-memory only (lost on vault close).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plugin Lifecycle
|
||||||
|
|
||||||
|
### `onload()`
|
||||||
|
|
||||||
|
1. **Load data** — `loadSettings()` then `loadWaypointData()`, both merge saved partials over defaults via `Object.assign({}, DEFAULT, partial)`.
|
||||||
|
2. **Register view** — `WAYPOINT_VIEW_TYPE = "waypoint-view"` maps to `WaypointView` factory `(leaf) => new WaypointView(leaf, this)`.
|
||||||
|
3. **Settings tab** — `WaypointSettingTab` receives the live `settings` object + `() => this.redrawAll()` callback for live preview.
|
||||||
|
4. **Register commands** (see Commands section below).
|
||||||
|
5. **Register events** — `file-open`, `vault:create`, `vault:delete`, `vault:rename`.
|
||||||
|
6. **Auto-open** — On `onLayoutReady`, if no existing leaves of the view type, opens one in the left sidebar.
|
||||||
|
7. **Midnight refresh** — 10-minute `setInterval` checks if `new Date().toDateString()` changed; if so, calls `redrawAll()` (calendar day indicators refresh).
|
||||||
|
|
||||||
|
### `onunload()`
|
||||||
|
|
||||||
|
Detaches all leaves of `WAYPOINT_VIEW_TYPE`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Models
|
||||||
|
|
||||||
|
### WaypointSettings
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface WaypointSettings {
|
||||||
|
calendar: CalendarSettings; // firstDayOfWeek (0=Sun,1=Mon), showNoteIndicators
|
||||||
|
daily: PeriodNoteSettings;
|
||||||
|
weekly: PeriodNoteSettings;
|
||||||
|
monthly: PeriodNoteSettings;
|
||||||
|
quarterly: PeriodNoteSettings;
|
||||||
|
yearly: PeriodNoteSettings;
|
||||||
|
recentFiles: RecentFilesSettings; // maxItems, updateOn, omittedPaths[], omittedTags[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PeriodNoteSettings {
|
||||||
|
folder: string; // e.g. "periodic/daily"
|
||||||
|
templateFile: string; // path without .md, e.g. "Templates/Daily note"
|
||||||
|
nameFormat: string; // moment.js format string
|
||||||
|
typeProperty: string; // frontmatter type value, e.g. "daily-note"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CalendarSettings {
|
||||||
|
firstDayOfWeek: number; // 0 = Sunday, 1 = Monday
|
||||||
|
showNoteIndicators: boolean; // dot on days with existing .md files
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RecentFilesSettings {
|
||||||
|
maxItems: number; // default 50
|
||||||
|
updateOn: 'file-open' | 'file-edit'; // trigger mode
|
||||||
|
omittedPaths: string[]; // regex patterns (one per line)
|
||||||
|
omittedTags: string[]; // regex patterns for frontmatter tags
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### BookmarkItem (recursive tree)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface BookmarkItem {
|
||||||
|
id: string; // "bm-{timestamp}-{random4}"
|
||||||
|
type: 'file' | 'group' | 'separator' | 'spacer';
|
||||||
|
label: string; // display text (empty for separator/spacer)
|
||||||
|
filePath: string; // vault-relative path (empty for non-file types)
|
||||||
|
icon: string; // Lucide icon name
|
||||||
|
children: BookmarkItem[]; // nested items (groups contain children)
|
||||||
|
collapsed: boolean; // group collapse state
|
||||||
|
indent: number; // depth level (0 = root)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WaypointData {
|
||||||
|
bookmarks: BookmarkItem[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The bookmark tree is stored flat in `data.json` under `waypointData.bookmarks` but rendered recursively. Groups contain children; files/separators/spacers are leaf nodes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Period note navigation (with default hotkeys)
|
||||||
|
|
||||||
|
| ID | Name | Hotkey |
|
||||||
|
|---|---|---|
|
||||||
|
| `waypoint-go-to-daily` | Go to daily note | `Mod+Shift+Alt+D` |
|
||||||
|
| `waypoint-go-to-weekly` | Go to weekly note | `Mod+Shift+Alt+W` |
|
||||||
|
| `waypoint-go-to-monthly` | Go to monthly note | `Mod+Shift+Alt+M` |
|
||||||
|
| `waypoint-go-to-quarterly` | Go to quarterly note | `Mod+Shift+Alt+Q` |
|
||||||
|
| `waypoint-go-to-yearly` | Go to yearly note | `Mod+Shift+Alt+Y` |
|
||||||
|
|
||||||
|
All call `openPeriodNote(period, moment())` — opens or creates the current period's note.
|
||||||
|
|
||||||
|
### Next/Previous period (no default hotkeys)
|
||||||
|
|
||||||
|
10 commands generated in a loop: `waypoint-go-to-{next|prev}-{daily|weekly|monthly|quarterly|yearly}`.
|
||||||
|
|
||||||
|
These call `navigatePeriodNote(direction)` which:
|
||||||
|
1. Gets the active file's basename.
|
||||||
|
2. Calls `detectPeriodType(basename)` — regex matching:
|
||||||
|
- `^\d{4}-\d{2}-\d{2}$` → daily
|
||||||
|
- `^\d{4}-W\d{2}$` → weekly
|
||||||
|
- `^\d{4}-\d{2}$` → monthly
|
||||||
|
- `^\d{4}-Q[1-4]$` → quarterly
|
||||||
|
- `^\d{4}$` → yearly
|
||||||
|
3. Parses date via `moment(basename, format)`.
|
||||||
|
4. Adds ±1 period (quarters add ±3 months).
|
||||||
|
5. Calls `openPeriodNote` for the new date.
|
||||||
|
|
||||||
|
### Other commands
|
||||||
|
|
||||||
|
| ID | Name |
|
||||||
|
|---|---|
|
||||||
|
| `waypoint-open-view` | Open Waypoint sidebar |
|
||||||
|
| `waypoint-add-bookmark` | Add current file as Waypoint bookmark |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Period Note Creation (`openPeriodNote`)
|
||||||
|
|
||||||
|
For a given period + moment date:
|
||||||
|
|
||||||
|
1. **Build filename:** `date.format(periodSettings.nameFormat) + ".md"`.
|
||||||
|
2. **Build full path:** If `periodSettings.folder` is set, prepend it; otherwise root.
|
||||||
|
3. **Check existence:** `vault.getFileByPath(fullPath)`.
|
||||||
|
4. **If not found, create:**
|
||||||
|
- Try to read template at `periodSettings.templateFile + ".md"`.
|
||||||
|
- If template exists → `vault.create(fullPath, templateContent)`.
|
||||||
|
- If no template → `vault.create(fullPath, minimalFrontmatter)` where frontmatter is `type: {typeProperty}` + `date: YYYY-MM-DD`.
|
||||||
|
5. **Open in new leaf:** `workspace.getLeaf(false).openFile(file)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Event Handling
|
||||||
|
|
||||||
|
### `file-open`
|
||||||
|
|
||||||
|
If `settings.recentFiles.updateOn === 'file-open'` → calls `addToRecentFiles(file)`.
|
||||||
|
|
||||||
|
If `updateOn === 'file-edit'` → currently skipped (placeholder for future edit-detection).
|
||||||
|
|
||||||
|
### `vault:create` / `vault:delete`
|
||||||
|
|
||||||
|
Both trigger `broadcastRedraw()` — tells all WaypointView instances to re-render (needed for calendar note indicators and stale recent file references).
|
||||||
|
|
||||||
|
### `vault:rename`
|
||||||
|
|
||||||
|
1. Updates `recentFiles` entry if path matches `oldPath`.
|
||||||
|
2. Calls `updateBookmarkPath(oldPath, newPath)` — recursively scans `waypointData.bookmarks` and updates any `filePath` matching `oldPath`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recent Files (in-memory)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
recentFiles: { path: string; basename: string }[]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update flow:**
|
||||||
|
1. `addToRecentFiles(file)` — dedupes (removes existing entry), prepends to front, truncates to `maxItems`.
|
||||||
|
2. Calls `broadcastRedraw()`.
|
||||||
|
|
||||||
|
**Omitted paths/tags:** Settings store regex patterns but the current `addToRecentFiles` does **not** filter by them — these are only exposed in the settings UI. The filtering is not yet wired up in the add logic.
|
||||||
|
|
||||||
|
**On file not found:** When clicking a recent file that no longer exists, `focusFile()` shows a Notice and removes the stale entry from `recentFiles`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sidebar View (`WaypointView`)
|
||||||
|
|
||||||
|
Extends `ItemView`. View type: `"waypoint-view"`, icon: `compass`.
|
||||||
|
|
||||||
|
### Rendering (`redraw`)
|
||||||
|
|
||||||
|
Called on every change. Full DOM rebuild — `contentEl.empty()` then three sections in order:
|
||||||
|
|
||||||
|
1. **Favorites** (`renderFavorites`) — bookmark tree
|
||||||
|
2. **Recent Files** (`renderRecentFiles`) — flat list
|
||||||
|
3. **Calendar** (`renderCalendar`) — month grid
|
||||||
|
|
||||||
|
The last section (`waypoint-section:last-child`) gets `margin-top: auto`, pushing it to the bottom of the sidebar.
|
||||||
|
|
||||||
|
### Calendar Panel
|
||||||
|
|
||||||
|
**State:** `currentDisplayMonth` (0-indexed), `currentDisplayYear` — allows navigating months independently of today.
|
||||||
|
|
||||||
|
**Layout:**
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────┐
|
||||||
|
│ Q2 June 2026 ◀ Today ▶ │ ← breadcrumb (clickable) + nav
|
||||||
|
├──┬───┬───┬───┬───┬───┬───┬───┤
|
||||||
|
│24│sun│mon│tue│wed│thu│fri│sat│ ← header row + week# col
|
||||||
|
├──┼───┼───┼───┼───┼───┼───┼───┤
|
||||||
|
│25│ 1 │ 2 │ 3 │... ← day cells (clickable)
|
||||||
|
└──┴───┴───┴───┴───┴───┴───┴───┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Breadcrumb:** Q-label, month name, year — each clickable to open that period note.
|
||||||
|
- **Nav buttons:** ◀/▶ shift month ±1. "Today" resets to current month.
|
||||||
|
- **Week number column:** Clicking a week number opens the weekly note for that week's Monday.
|
||||||
|
- **Day cells:** Click opens daily note. `.other-month` dimmed. `.today` has accent border. `.has-note` gets a dot indicator (checked via `vault.getFiles().some(f => f.basename === dateStr)`).
|
||||||
|
- **Grid generation:** `getMonthGrid(year, month, firstDayOfWeek)` in `date-utils.ts` produces up to 6 weeks, each with 7 `CalendarDay` objects containing `moment`, `dayOfMonth`, `isToday`, `isCurrentMonth`, `isoWeekNumber`.
|
||||||
|
|
||||||
|
### Recent Files Panel
|
||||||
|
|
||||||
|
Renders `plugin.recentFiles` as Obsidian-native `nav-file` elements using the file explorer's CSS classes (`tree-item`, `nav-file-title`, `nav-file-title-content`).
|
||||||
|
|
||||||
|
**Per-file features:**
|
||||||
|
- **Active indicator:** `.is-active` class if path matches `workspace.getActiveFile()`.
|
||||||
|
- **Remove button:** × icon, appears on hover (`.waypoint-recent-remove`), removes entry from array + saves settings + redraws.
|
||||||
|
- **Drag:** Uses `app.dragManager.dragFile()` for native Obsidian drag.
|
||||||
|
- **Hover preview:** Triggers `hover-link` event for Obsidian's page preview popup.
|
||||||
|
- **Context menu:** "Open in new tab" + Obsidian's native `file-menu` event.
|
||||||
|
- **Click:** `Keymap.isModEvent(event)` determines if opening in new leaf; otherwise same leaf.
|
||||||
|
- **Middle click:** Opens in new tab.
|
||||||
|
|
||||||
|
### Bookmarks/Favorites Panel
|
||||||
|
|
||||||
|
**Empty state:** Right-click on "Waypoint Bookmarks" header shows add menu:
|
||||||
|
- Add current file → `addBookmark(path, basename, 'file')`
|
||||||
|
- New group → `addBookmark('', 'New Group', 'group', 'folder')`
|
||||||
|
- Add separator → `addBookmark('', '', 'separator')`
|
||||||
|
- Add spacer → `addBookmark('', '', 'spacer')`
|
||||||
|
|
||||||
|
**Rendering:** `renderBookmarkList(container, items, depth)` recursively renders items with `paddingLeft: 8 + depth * 16px` for indentation.
|
||||||
|
|
||||||
|
**Item types:**
|
||||||
|
| Type | Render | Behavior |
|
||||||
|
|---|---|---|
|
||||||
|
| `file` | icon + label | Click opens file. Tooltip = filePath. |
|
||||||
|
| `group` | chevron + icon + label | Click toggles `collapsed`. Children rendered in nested `waypoint-bookmark-children` div (hidden when collapsed). |
|
||||||
|
| `separator` | horizontal line (::after pseudo-element) | No click handler. Context menu for delete. |
|
||||||
|
| `spacer` | 14px empty div | No click handler. Context menu for delete. |
|
||||||
|
|
||||||
|
**Drag-and-drop:** All bookmark items are draggable. Drop indicators show a 3px accent border above/below the target. On drop:
|
||||||
|
1. Remove dragged item from its current position (recursive search).
|
||||||
|
2. Insert at the target position (before or after based on cursor Y position relative to target midY).
|
||||||
|
3. If target not found (edge case), push to root.
|
||||||
|
4. Save + redraw.
|
||||||
|
|
||||||
|
**Context menu (right-click):**
|
||||||
|
- File items: "Open in new tab"
|
||||||
|
- File/Group items: "Rename" (opens `RenameModal`), "Change icon" (opens `IconSuggestModal`)
|
||||||
|
- "Move to group" submenu: Lists all available groups (excluding self + descendants) + "(Root)" for ungrouping
|
||||||
|
- Group items: "Expand/Collapse", "Add bookmark here", "New sub-group"
|
||||||
|
- All items: "Insert separator above/below", "Insert spacer above/below", "Remove"
|
||||||
|
|
||||||
|
**Move to group (`moveBookmarkToGroup`):**
|
||||||
|
1. Remove item from current position.
|
||||||
|
2. If targetGroupId: find group, set `item.indent = group.indent + 1`, push to group's children.
|
||||||
|
3. If null (root): set `item.indent = 0`, push to `waypointData.bookmarks`.
|
||||||
|
|
||||||
|
**Rename modal (`RenameModal`):** Simple Modal with text input + Cancel/Save buttons. Enter key submits.
|
||||||
|
|
||||||
|
**Icon picker (`IconSuggestModal`):** Modal with:
|
||||||
|
- Live preview of selected icon.
|
||||||
|
- Search input with 60ms debounce.
|
||||||
|
- Grid of matching icons (max 80 shown), loaded from `https://cdn.jsdelivr.net/npm/lucide-static@0.517.0/tags.json` with fallback to `https://lucide.dev/api/tags` and a hardcoded `FALLBACK_ICONS` object (~300 icons).
|
||||||
|
- Click to select, "No icon" link to clear, Save/Cancel buttons.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CSS Architecture (`styles.css`)
|
||||||
|
|
||||||
|
All classes prefixed with `waypoint-`. Uses Obsidian CSS variables throughout:
|
||||||
|
|
||||||
|
- `--font-ui-small`, `--font-ui-medium`, `--font-semibold`, `--font-medium`, `--font-light`
|
||||||
|
- `--text-muted`, `--text-faint`, `--text-accent`, `--text-on-accent`
|
||||||
|
- `--background-modifier-border`, `--background-modifier-active-hover`, `--background-primary`, `--background-secondary`
|
||||||
|
- `--interactive-accent`
|
||||||
|
- `--cursor` (for custom cursor support)
|
||||||
|
|
||||||
|
Key layout:
|
||||||
|
- `.waypoint-view` — flex column, `overflow-y: auto`, 8px padding.
|
||||||
|
- `.waypoint-section` — `flex-shrink: 0`, 16px bottom margin. Last section gets `margin-top: auto` (pins calendar to bottom).
|
||||||
|
- `.waypoint-section-header` — uppercase, muted, with bottom border.
|
||||||
|
- Calendar table — `table-layout: fixed`, `border-collapse: collapse`.
|
||||||
|
- `.waypoint-day.today` — accent color text + 1px accent border.
|
||||||
|
- `.waypoint-day.has-note::after` — 4px dot indicator.
|
||||||
|
- `.waypoint-bm-chevron` — `rotate(-90deg)` on collapsed groups.
|
||||||
|
- `.waypoint-bm-drop-line` / `.waypoint-bm-drop-below` — 3px accent border for drag indicators.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Date Utilities (`date-utils.ts`)
|
||||||
|
|
||||||
|
All use Obsidian's bundled `moment` (not the npm package).
|
||||||
|
|
||||||
|
| Function | Signature | Returns |
|
||||||
|
|---|---|---|
|
||||||
|
| `getPeriodInfo(date)` | `Moment → PeriodInfo` | `{day, week, month, quarter, year}` strings for the date |
|
||||||
|
| `getQuarterString(date)` | `Moment → string` | e.g. `"2026-Q3"` |
|
||||||
|
| `getTodayPeriod()` | `() → PeriodInfo` | Current date's period info |
|
||||||
|
| `getMonthGrid(year, month, firstDayOfWeek)` | `number, number, number → CalendarWeek[]` | Up to 6 weeks, each with 7 `CalendarDay` objects |
|
||||||
|
| `formatDateLabel(date)` | `Moment → string` | `"June 1st, 2026"` |
|
||||||
|
| `formatMonthLabel(date)` | `Moment → string` | `"June 2026"` |
|
||||||
|
| `formatQuarterLabel(date)` | `Moment → string` | `"Q3 2026"` |
|
||||||
|
| `navigateDate(date, period, delta)` | `Moment, period, number → Moment` | Clones + adds delta (quarters: delta×3 months) |
|
||||||
|
| `formatPeriodName(date, format)` | `Moment, string → string` | `date.format(format)` wrapper |
|
||||||
|
| `getISOWeek(date)` | `Moment → number` | `date.isoWeek()` |
|
||||||
|
|
||||||
|
**`getMonthGrid` algorithm:**
|
||||||
|
1. Find the first day to display by subtracting `(firstOfMonth.day() - firstDayOfWeek + 7) % 7` days from the 1st.
|
||||||
|
2. Iterate day-by-day, building 7-day weeks.
|
||||||
|
3. Each `CalendarDay` tracks: `date` (Moment), `dayOfMonth`, `isToday`, `isCurrentMonth`, `isoWeekNumber`.
|
||||||
|
4. Week's `weekNumber` = first day's ISO week number.
|
||||||
|
5. Safety break after 6 weeks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Settings Persistence
|
||||||
|
|
||||||
|
Settings and waypoint data share a single `data.json` via Obsidian's `Plugin.loadData()/saveData()`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// loadData() returns:
|
||||||
|
{
|
||||||
|
settings: { calendar: {...}, daily: {...}, ... },
|
||||||
|
waypointData: { bookmarks: [...] }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Both `loadSettings()` and `loadWaypointData()` read from the same file, merging partials over defaults. `saveSettings()` and `saveWaypointData()` each re-read the full data, update their key, and write back. This means they must not run concurrently (no locking — relies on Obsidian's synchronous save behavior).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Redraw Mechanism
|
||||||
|
|
||||||
|
`broadcastRedraw()` iterates all leaves of `WAYPOINT_VIEW_TYPE` and calls `view.redraw()` on each. `redraw()` is a full DOM rebuild (no virtual DOM, no diffing). This is triggered by:
|
||||||
|
|
||||||
|
- File open/create/delete/rename events
|
||||||
|
- Bookmark add/remove/update
|
||||||
|
- Period navigation
|
||||||
|
- Settings changes (via `onSettingsChange` callback)
|
||||||
|
- Midnight detection (10-min interval)
|
||||||
|
|
||||||
|
The sidebar is re-rendered from scratch on every change. For a small sidebar this is acceptable; for larger bookmark lists it may cause flicker.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Limitations / Gaps
|
||||||
|
|
||||||
|
1. **Recent files omittedPaths/omittedTags** — Settings UI exposes these regex filters, but `addToRecentFiles()` does not apply them. Files are never filtered out.
|
||||||
|
2. **`updateOn: 'file-edit'`** — The `file-open` handler returns early for this mode, but no edit-detection event is registered. Recent files never update in edit mode.
|
||||||
|
3. **No virtual DOM** — Full rebuild on every redraw. Bookmark drag/drop, rename, and any change tears down and rebuilds the entire sidebar.
|
||||||
|
4. **Concurrent saves** — `saveSettings()` and `saveWaypointData()` both re-read then write `data.json`. Rapid sequential calls could race.
|
||||||
|
5. **Recent files not persisted** — Cleared on vault reload. Only bookmarks survive restarts.
|
||||||
|
6. **Note indicators scan all vault files** — `hasNoteForDate()` iterates `vault.getFiles()` on every calendar render (called per day cell). For large vaults, this is O(days × files). Not cached.
|
||||||
|
7. **`detectPeriodType` uses hardcoded formats** — The regex patterns in `main.ts` don't read from `settings.*.nameFormat`. If a user changes the name format to something non-standard, next/prev navigation breaks.
|
||||||
|
8. **IconSuggestModal fetches from CDN** — Network dependency on first icon picker open. Falls back to hardcoded list on failure.
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
- [ ] bookmarks
|
||||||
- [ ] when user middle clicks on a bookmark, it should open in a new tab
|
- [ ] when user middle clicks on a bookmark, it should open in a new tab
|
||||||
- [ ] the sidebar should never scroll. the content of recent files should wrap after 10 files or so (no sidebar visible)
|
- [ ] in the bookmarks, i want to have notes that are parents to other notes
|
||||||
- [ ] it should be possible to add a separator line and/or an empty space
|
|
||||||
- [ ] by default, the bookmark should have no icon
|
- [ ] by default, the bookmark should have no icon
|
||||||
- [ ]
|
- [ ] the way to search for icons should be improved. on the lucide icon website, the search works by more than only the icon’s title. i want to be able to load all the icon (not by default though)
|
||||||
|
- [ ] calendar
|
||||||
|
- [ ] middle click on a date/week/etc. should open it in a new tab
|
||||||
|
- [ ] i want to improve the look of the calendar. more space, a bit more height
|
||||||
|
- [ ] when i hover over something that’s clickable, I should see the correct cursor
|
||||||
|
- [ ] recent files
|
||||||
|
- [ ] I want to be able to filter the recent files. i want to have a little tag, that when i selectt, wsill show only recents notes where type == meeting, type == person
|
||||||
Reference in New Issue
Block a user