Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8ba4cd2ad | |||
| 5a9b7bfff8 | |||
| 72a61e49ee | |||
| 069456799e |
+29
-17
@@ -51,7 +51,7 @@ Detaches all leaves of `WAYPOINT_VIEW_TYPE`.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface WaypointSettings {
|
interface WaypointSettings {
|
||||||
calendar: CalendarSettings; // firstDayOfWeek (0=Sun,1=Mon), showNoteIndicators
|
calendar: CalendarSettings; // week start, indicator visibility/style, daily indicator colour
|
||||||
daily: PeriodNoteSettings;
|
daily: PeriodNoteSettings;
|
||||||
weekly: PeriodNoteSettings;
|
weekly: PeriodNoteSettings;
|
||||||
monthly: PeriodNoteSettings;
|
monthly: PeriodNoteSettings;
|
||||||
@@ -71,7 +71,9 @@ interface PeriodNoteSettings {
|
|||||||
|
|
||||||
interface CalendarSettings {
|
interface CalendarSettings {
|
||||||
firstDayOfWeek: number; // 0 = Sunday, 1 = Monday
|
firstDayOfWeek: number; // 0 = Sunday, 1 = Monday
|
||||||
showNoteIndicators: boolean; // dot on days with existing .md files
|
showNoteIndicators: boolean; // show or hide all calendar markers
|
||||||
|
indicatorMode: 'any' | 'systems'; // defaults to systems; one neutral dot or one per date system
|
||||||
|
dailyIndicatorColor: string; // daily's colour in systems mode
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RecentFilesSettings {
|
interface RecentFilesSettings {
|
||||||
@@ -157,7 +159,6 @@ A **date system** is a folder of notes whose filenames begin with a date. Daily
|
|||||||
|
|
||||||
### `DateSystemSettings`
|
### `DateSystemSettings`
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface DateSystemSettings {
|
interface DateSystemSettings {
|
||||||
id: string; // stable across edits + reordering, so settings rows can key on it
|
id: string; // stable across edits + reordering, so settings rows can key on it
|
||||||
name: string; // menu label, e.g. "Journal"
|
name: string; // menu label, e.g. "Journal"
|
||||||
@@ -166,15 +167,18 @@ interface DateSystemSettings {
|
|||||||
templateFile: string; // may omit the .md extension
|
templateFile: string; // may omit the .md extension
|
||||||
typeProperty: string; // fallback frontmatter `type:` value
|
typeProperty: string; // fallback frontmatter `type:` value
|
||||||
icon: string; // Lucide icon name for the menu item
|
icon: string; // Lucide icon name for the menu item
|
||||||
|
indicatorColor: string; // calendar dot colour in systems mode
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Configured systems live in `settings.dateSystems`, where array order is menu order. `DEFAULT_DATE_SYSTEM` (in `settings.ts`, typed `Omit<DateSystemSettings, 'id'>`) supplies the field defaults for a newly added row **and** the merge base for saved ones, so a system persisted before a field existed still loads with that field defined. `DEFAULT_SETTINGS.dateSystems` ships two:
|
Configured systems live in `settings.dateSystems`, where array order is menu order. `DEFAULT_DATE_SYSTEM` (in `settings.ts`, typed `Omit<DateSystemSettings, 'id'>`) supplies the field defaults for a newly added row **and** the merge base for saved ones, so a system persisted before a field existed still loads with that field defined. `DEFAULT_SETTINGS.dateSystems` ships two:
|
||||||
|
|
||||||
| `id` | `name` | Folder | `nameFormat` | Notes per date |
|
| `id` | `name` | Folder | `nameFormat` | Indicator colour | Notes per date |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| `journal` | Journal | `periodic/journal` | `YYYY-MM-DD - [Journal]` | one |
|
| `journal` | Journal | `periodic/journal` | `YYYY-MM-DD - [Journal]` | green (`#22c55e`) | one |
|
||||||
| `meetings` | Meeting | `periodic/meetings` | `YYYY-MM-DD - {title}` | many |
|
| `meetings` | Meeting | `periodic/meetings` | `YYYY-MM-DD - {title}` | violet (`#a855f7`) | many |
|
||||||
|
|
||||||
|
The default calendar mode is `systems`, while `any` preserves the older one-neutral-dot behaviour. Template file fields in both Periodic Notes and Date systems use a native `datalist` populated from every Markdown path in the vault (without the optional `.md` extension), so templates stored outside a conventional `Templates/` folder remain discoverable.
|
||||||
|
|
||||||
### Templater folder triggers
|
### Templater folder triggers
|
||||||
|
|
||||||
@@ -210,21 +214,26 @@ Imports nothing from `'obsidian'` — callers make every moment call and pass th
|
|||||||
### Plugin API (`main.ts`)
|
### Plugin API (`main.ts`)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/** One existing note of a date system, with the label the menu should show. */
|
|
||||||
interface DateSystemNote {
|
interface DateSystemNote {
|
||||||
file: TFile;
|
file: TFile;
|
||||||
label: string; // free-text title for many-per-date systems, else the system name
|
label: string; // free-text title for many-per-date systems, else the system name
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A day-scoped system and the notes it already holds for one date. */
|
|
||||||
interface DateSystemNotes {
|
interface DateSystemNotes {
|
||||||
system: DateSystemSettings;
|
system: DateSystemSettings;
|
||||||
notes: DateSystemNote[]; // sorted by basename; empty when the date has no note
|
notes: DateSystemNote[];
|
||||||
multiple: boolean; // nameFormat carries {title}, i.e. many notes per date
|
multiple: boolean; // nameFormat carries {title}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DateSystemIndicator {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
dateSystems(): DateSystemSettings[]
|
dateSystems(): DateSystemSettings[]
|
||||||
findDateSystemNotes(date: moment.Moment): DateSystemNotes[]
|
findDateSystemNotes(date: moment.Moment): DateSystemNotes[]
|
||||||
|
getDateSystemIndicators(dates: moment.Moment[]): Map<string, DateSystemIndicator[]>
|
||||||
openDateSystemNote(
|
openDateSystemNote(
|
||||||
system: DateSystemSettings,
|
system: DateSystemSettings,
|
||||||
date: moment.Moment,
|
date: moment.Moment,
|
||||||
@@ -232,6 +241,8 @@ openDateSystemNote(
|
|||||||
): Promise<void>
|
): Promise<void>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**`getDateSystemIndicators(dates)`** — returns one `{ id, name, color }` marker per configured system with one or more notes on a requested day. The calendar calls it once for the visible month only in `indicatorMode: 'systems'`. It makes one vault pass, caches the result by displayed dates and date-system settings, and invalidates it on markdown create/delete/rename or any Settings change. It does not run on ordinary markdown edits: content edits cannot change a filename-derived indicator.
|
||||||
|
|
||||||
**`dateSystems()`** — every day-scoped system in menu order: the daily periodic note, synthesized into a `DateSystemSettings` from `settings.daily`, followed by `settings.dateSystems`. The daily note is therefore not a special case in any consumer.
|
**`dateSystems()`** — every day-scoped system in menu order: the daily periodic note, synthesized into a `DateSystemSettings` from `settings.daily`, followed by `settings.dateSystems`. The daily note is therefore not a special case in any consumer.
|
||||||
|
|
||||||
**`findDateSystemNotes(date)`** — **one** vault scan per call, not one per system. It formats each usable system's `before`/`after` affixes for `date` once, then walks the markdown file list a single time, bucketing each file into the system that claims it (`isInFolder` + `matchesSystemName`). Systems whose formats have no date token are omitted rather than offering an unsafe create action. It returns the remaining `DateSystemNotes` in `dateSystems()` order, each bucket sorted by basename. The calendar's day context menu is built from exactly one of these calls per right-click.
|
**`findDateSystemNotes(date)`** — **one** vault scan per call, not one per system. It formats each usable system's `before`/`after` affixes for `date` once, then walks the markdown file list a single time, bucketing each file into the system that claims it (`isInFolder` + `matchesSystemName`). Systems whose formats have no date token are omitted rather than offering an unsafe create action. It returns the remaining `DateSystemNotes` in `dateSystems()` order, each bucket sorted by basename. The calendar's day context menu is built from exactly one of these calls per right-click.
|
||||||
@@ -348,7 +359,7 @@ The last section (`waypoint-section:last-child`) gets `margin-top: auto`, pushin
|
|||||||
- **Breadcrumb:** Q-label, month name, year — each clickable to open that period note.
|
- **Breadcrumb:** Q-label, month name, year — each clickable to open that period note.
|
||||||
- **Nav buttons:** ◀/▶ shift month ±1. "Today" resets to current month.
|
- **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; middle-clicking opens it in a new tab.
|
- **Week number column:** Clicking a week number opens the weekly note for that week's Monday; middle-clicking opens it in a new tab.
|
||||||
- **Day cells:** Left-click opens the daily note, middle-click opens it in a new tab, right-click opens the day context menu (below). `.other-month` dimmed. `.today` has accent border. `.has-note` gets a dot indicator, decided by the synchronous O(1) `plugin.hasNoteForDate(dateStr)` (a `Set` lookup — no per-cell vault scan).
|
- **Day cells:** Left-click opens the daily note, middle-click opens it in a new tab, right-click opens the day context menu (below). `.other-month` is muted; `.today` has an inset accent ring; hover receives a quiet fill. With `indicatorMode: 'any'`, `.has-note` shows the existing single neutral dot through the O(1) `plugin.hasNoteForDate(dateStr)` lookup. With `indicatorMode: 'systems'`, the view calls `getDateSystemIndicators()` once for the month and renders one tooltip-labelled coloured dot per matching daily/journal/meeting/custom system.
|
||||||
- **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`.
|
- **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`.
|
||||||
|
|
||||||
**Day context menu (right-click):** Built from a single `plugin.findDateSystemNotes(day.date)` call. The first entry is a non-clickable header showing the full date. Then, per system in `dateSystems()` order:
|
**Day context menu (right-click):** Built from a single `plugin.findDateSystemNotes(day.date)` call. The first entry is a non-clickable header showing the full date. Then, per system in `dateSystems()` order:
|
||||||
@@ -423,17 +434,18 @@ All classes prefixed with `waypoint-`. Uses Obsidian CSS variables throughout:
|
|||||||
|
|
||||||
- `--font-ui-small`, `--font-ui-medium`, `--font-semibold`, `--font-medium`, `--font-light`
|
- `--font-ui-small`, `--font-ui-medium`, `--font-semibold`, `--font-medium`, `--font-light`
|
||||||
- `--text-muted`, `--text-faint`, `--text-accent`, `--text-on-accent`, `--text-error`
|
- `--text-muted`, `--text-faint`, `--text-accent`, `--text-on-accent`, `--text-error`
|
||||||
- `--background-modifier-border`, `--background-modifier-active-hover`, `--background-primary`, `--background-secondary`
|
- `--background-modifier-border`, `--background-modifier-active-hover`, `--background-modifier-hover`, `--background-primary`, `--background-primary-alt`, `--background-secondary`
|
||||||
- `--interactive-accent`
|
- `--interactive-accent`
|
||||||
- `--cursor-link` (pointer cursor, with a `pointer` fallback)
|
- `--cursor-link` (pointer cursor, with a `pointer` fallback)
|
||||||
|
|
||||||
Key layout:
|
Key layout:
|
||||||
- `.waypoint-view` — flex column, `overflow-y: auto`, 8px padding.
|
- `.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` — `flex-shrink: 0`, 16px bottom margin. Last section gets `margin-top: auto` (pins calendar to bottom).
|
||||||
- `.waypoint-section-header` — uppercase, muted, with bottom border.
|
- `.waypoint-calendar` — padded, bordered surface with separated day cells for clear scan lines.
|
||||||
- Calendar table — `table-layout: fixed`, `border-collapse: collapse`.
|
- Calendar table — `table-layout: fixed`, `border-collapse: separate`, 2px horizontal / 3px vertical cell spacing.
|
||||||
- `.waypoint-day.today` — accent color text + 1px accent border.
|
- `.waypoint-day.today` — accent text with an inset accent ring, avoiding layout shifts.
|
||||||
- `.waypoint-day.has-note::after` — 4px dot indicator.
|
- `.waypoint-day.has-note::after` — neutral single-dot indicator.
|
||||||
|
- `.waypoint-day-indicators` / `.waypoint-day-indicator` — compact ordered dot row; `--waypoint-indicator-color` carries each configured system colour.
|
||||||
- `.waypoint-bm-chevron` — `rotate(-90deg)` on collapsed groups.
|
- `.waypoint-bm-chevron` — `rotate(-90deg)` on collapsed groups.
|
||||||
- `.waypoint-bm-drop-line` / `.waypoint-bm-drop-below` — 3px accent border for drag indicators.
|
- `.waypoint-bm-drop-line` / `.waypoint-bm-drop-below` — 3px accent border for drag indicators.
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,18 @@
|
|||||||
- [ ] Note indicator dots show on days with existing .md files
|
- [ ] Note indicator dots show on days with existing .md files
|
||||||
- [ ] Today is highlighted with accent border
|
- [ ] Today is highlighted with accent border
|
||||||
|
|
||||||
|
## Calendar: System-coloured indicators
|
||||||
|
|
||||||
|
- [ ] Calendar → Indicator style → **Single dot** keeps one neutral dot for an existing date-named note
|
||||||
|
- [ ] Calendar → Indicator style → **Colour by note system** shows a blue dot for Daily, green for Journal, and violet for Meeting by default
|
||||||
|
- [ ] A day holding multiple meeting notes still shows exactly one Meeting dot
|
||||||
|
- [ ] A day holding Daily, Journal, and Meeting notes shows three compact dots in that order
|
||||||
|
- [ ] Hover each coloured dot → its date-system name is identified by a tooltip
|
||||||
|
- [ ] Change Daily/Journal/Meeting indicator colours in Settings → the visible calendar refreshes immediately
|
||||||
|
- [ ] Add a custom date system with its own colour and a matching note → its dot appears in system order
|
||||||
|
- [ ] Create, delete, or rename a date-system note → coloured dots refresh without changing months
|
||||||
|
- [ ] Start typing in any Template file field → matching vault Markdown paths appear as native autocomplete suggestions
|
||||||
|
|
||||||
|
|
||||||
## Calendar: Date systems
|
## Calendar: Date systems
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ Calendar, recent files, and custom bookmarks sidebar for Obsidian.
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Calendar panel** — month grid; left-click a day opens its daily note, middle-click opens it in a tab, and right-click reveals every configured note system for that date
|
- **Calendar panel** — refined month grid; left-click a day opens its daily note, middle-click opens it in a tab, and right-click reveals every configured note system for that date
|
||||||
- **Date systems** — browse or create daily, journal, meeting, and other date-prefixed notes from a single day menu
|
- **Calendar indicators** — retain a single neutral note dot or show a coloured dot per daily, journal, meeting, or custom date system
|
||||||
- **Recent files** — track recently opened/edited files
|
- **Recent files** — track recently opened/edited files
|
||||||
- **Favorites** — custom bookmarks with groups, icons, and rename
|
- **Favorites** — custom bookmarks with groups, icons, and rename
|
||||||
|
|
||||||
@@ -29,12 +29,21 @@ Right-click any calendar day to open its **date systems** menu. The daily note a
|
|||||||
| Journal | `periodic/journal` | `YYYY-MM-DD - [Journal]` | Opens or creates one journal note for the date |
|
| Journal | `periodic/journal` | `YYYY-MM-DD - [Journal]` | Opens or creates one journal note for the date |
|
||||||
| Meeting | `periodic/meetings` | `YYYY-MM-DD - {title}` | Lists every meeting for the date and can create another |
|
| Meeting | `periodic/meetings` | `YYYY-MM-DD - {title}` | Lists every meeting for the date and can create another |
|
||||||
|
|
||||||
Configure systems in **Settings → Waypoint Sidebar → Date systems**. Each system has a folder, filename format, template, fallback frontmatter type, and Lucide icon.
|
Configure systems in **Settings → Waypoint Sidebar → Date systems**. Each system has a folder, filename format, template, fallback frontmatter type, Lucide icon, and indicator colour. Template file fields autocomplete every Markdown path in the vault.
|
||||||
|
|
||||||
`Name format` uses moment.js tokens. Bracket-escape literal text: `YYYY-MM-DD - [Journal]`. Add `{title}` when a date can have multiple notes; it is replaced with the title requested when creating a note. Without `{title}`, the system has exactly one note per date.
|
`Name format` uses moment.js tokens. Bracket-escape literal text: `YYYY-MM-DD - [Journal]`. Add `{title}` when a date can have multiple notes; it is replaced with the title requested when creating a note. Without `{title}`, the system has exactly one note per date.
|
||||||
|
|
||||||
Ctrl/Cmd-click a menu entry opens it in a new tab.
|
Ctrl/Cmd-click a menu entry opens it in a new tab.
|
||||||
|
|
||||||
|
### Calendar indicators
|
||||||
|
|
||||||
|
Under **Settings → Waypoint Sidebar → Calendar**, choose either:
|
||||||
|
|
||||||
|
- **Colour by note system** — the default; one compact coloured dot per configured date system that has a note on that day. Hover a dot to identify its system.
|
||||||
|
- **Single dot** — a neutral marker for any note whose filename is exactly the date.
|
||||||
|
|
||||||
|
Daily uses the Calendar tab’s colour picker. Journal, Meeting, and every custom system have their own **Indicator colour** picker under **Date systems**. The defaults are blue for Daily, green for Journal, and violet for Meeting.
|
||||||
|
|
||||||
### Templater folder templates
|
### Templater folder templates
|
||||||
|
|
||||||
If a date system uses a Templater folder mapping, leave its Waypoint **Template file** field blank. Waypoint then creates a safe fallback note while Templater owns prompts, scripts, cursors, and rendered content.
|
If a date system uses a Templater folder mapping, leave its Waypoint **Template file** field blank. Waypoint then creates a safe fallback note while Templater owns prompts, scripts, cursors, and rendered content.
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "waypoint-sidebar",
|
"id": "waypoint-sidebar",
|
||||||
"name": "Waypoint Sidebar",
|
"name": "Waypoint Sidebar",
|
||||||
"version": "1.6.0",
|
"version": "1.7.0",
|
||||||
"minAppVersion": "1.4.4",
|
"minAppVersion": "1.4.4",
|
||||||
"description": "Calendar, recent files, and custom bookmarks sidebar.",
|
"description": "Calendar, recent files, and custom bookmarks sidebar.",
|
||||||
"author": "Olivier",
|
"author": "Olivier",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "waypoint",
|
"name": "waypoint",
|
||||||
"version": "1.6.0",
|
"version": "1.7.0",
|
||||||
"description": "Calendar, recent files, and custom bookmarks sidebar.",
|
"description": "Calendar, recent files, and custom bookmarks sidebar.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+97
-3
@@ -42,6 +42,13 @@ export interface DateSystemNotes {
|
|||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** One coloured calendar marker for a date system that has a note on a day. */
|
||||||
|
export interface DateSystemIndicator {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default class WaypointPlugin extends Plugin {
|
export default class WaypointPlugin extends Plugin {
|
||||||
public settings: WaypointSettings;
|
public settings: WaypointSettings;
|
||||||
public waypointData: WaypointData;
|
public waypointData: WaypointData;
|
||||||
@@ -51,6 +58,9 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
private savePromise: Promise<void> = Promise.resolve();
|
private savePromise: Promise<void> = Promise.resolve();
|
||||||
/** Basenames of every markdown file in the vault, for O(1) calendar lookups. */
|
/** Basenames of every markdown file in the vault, for O(1) calendar lookups. */
|
||||||
private markdownBasenames: Set<string> = new Set();
|
private markdownBasenames: Set<string> = new Set();
|
||||||
|
/** Results for the displayed month; invalidated by markdown-file changes. */
|
||||||
|
private dateSystemIndicators: Map<string, DateSystemIndicator[]> | null = null;
|
||||||
|
private dateSystemIndicatorKey = '';
|
||||||
|
|
||||||
async onload(): Promise<void> {
|
async onload(): Promise<void> {
|
||||||
console.debug('Waypoint: loading plugin v' + this.manifest.version);
|
console.debug('Waypoint: loading plugin v' + this.manifest.version);
|
||||||
@@ -73,6 +83,7 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
this.settings,
|
this.settings,
|
||||||
() => {
|
() => {
|
||||||
this.enforceRecentFilesLimit();
|
this.enforceRecentFilesLimit();
|
||||||
|
this.invalidateDateSystemIndicators();
|
||||||
this.redrawAll();
|
this.redrawAll();
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@@ -247,10 +258,14 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
// Cloned, not Object.assign'd in: the defaults array would otherwise be
|
// Cloned, not Object.assign'd in: the defaults array would otherwise be
|
||||||
// aliased into the live settings and the settings UI would edit
|
// aliased into the live settings and the settings UI would edit
|
||||||
// DEFAULT_SETTINGS itself. Saved entries merge over
|
// DEFAULT_DATE_SYSTEM so older configs pick up fields added since. Known
|
||||||
// DEFAULT_DATE_SYSTEM so older configs pick up fields added since.
|
// built-ins use their own defaults too, preserving Journal/Meeting colours
|
||||||
|
// when this field is first introduced.
|
||||||
this.settings.dateSystems = Array.isArray(s.dateSystems)
|
this.settings.dateSystems = Array.isArray(s.dateSystems)
|
||||||
? s.dateSystems.map(sys => Object.assign({}, DEFAULT_DATE_SYSTEM, sys))
|
? s.dateSystems.map(sys => {
|
||||||
|
const builtIn = DEFAULT_SETTINGS.dateSystems.find(defaultSystem => defaultSystem.id === sys.id);
|
||||||
|
return Object.assign({}, builtIn || DEFAULT_DATE_SYSTEM, sys);
|
||||||
|
})
|
||||||
: DEFAULT_SETTINGS.dateSystems.map(sys => Object.assign({}, sys));
|
: DEFAULT_SETTINGS.dateSystems.map(sys => Object.assign({}, sys));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,6 +407,7 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
* inside a renamed folder.
|
* inside a renamed folder.
|
||||||
*/
|
*/
|
||||||
private onRename(file: TAbstractFile, oldPath: string): void {
|
private onRename(file: TAbstractFile, oldPath: string): void {
|
||||||
|
this.invalidateDateSystemIndicators();
|
||||||
const indexChanged = this.syncIndexForRename(file, oldPath);
|
const indexChanged = this.syncIndexForRename(file, oldPath);
|
||||||
let dataChanged = false;
|
let dataChanged = false;
|
||||||
|
|
||||||
@@ -427,6 +443,7 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
private onVaultCreate(file: TAbstractFile): void {
|
private onVaultCreate(file: TAbstractFile): void {
|
||||||
if (file instanceof TFile && file.extension === 'md') {
|
if (file instanceof TFile && file.extension === 'md') {
|
||||||
this.markdownBasenames.add(file.basename);
|
this.markdownBasenames.add(file.basename);
|
||||||
|
this.invalidateDateSystemIndicators();
|
||||||
}
|
}
|
||||||
this.broadcastRedraw();
|
this.broadcastRedraw();
|
||||||
}
|
}
|
||||||
@@ -434,6 +451,7 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
private onVaultDelete(file: TAbstractFile): void {
|
private onVaultDelete(file: TAbstractFile): void {
|
||||||
if (file instanceof TFile && file.extension === 'md') {
|
if (file instanceof TFile && file.extension === 'md') {
|
||||||
this.removeFromMarkdownIndex(file.basename, file.path);
|
this.removeFromMarkdownIndex(file.basename, file.path);
|
||||||
|
this.invalidateDateSystemIndicators();
|
||||||
}
|
}
|
||||||
this.broadcastRedraw();
|
this.broadcastRedraw();
|
||||||
}
|
}
|
||||||
@@ -447,6 +465,12 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Forget a month result when markdown paths or date-system settings change. */
|
||||||
|
private invalidateDateSystemIndicators(): void {
|
||||||
|
this.dateSystemIndicators = null;
|
||||||
|
this.dateSystemIndicatorKey = '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drop a basename from the index, unless another markdown file still
|
* Drop a basename from the index, unless another markdown file still
|
||||||
* carries it. `path` is excluded from that check because the vault may not
|
* carries it. `path` is excluded from that check because the vault may not
|
||||||
@@ -555,6 +579,7 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
templateFile: periodSettings.templateFile,
|
templateFile: periodSettings.templateFile,
|
||||||
typeProperty: periodSettings.typeProperty,
|
typeProperty: periodSettings.typeProperty,
|
||||||
icon: 'calendar',
|
icon: 'calendar',
|
||||||
|
indicatorColor: this.settings.calendar.dailyIndicatorColor,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,6 +634,75 @@ export default class WaypointPlugin extends Plugin {
|
|||||||
.map(bucket => bucket.result);
|
.map(bucket => bucket.result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return one coloured indicator per system with a note on each requested day.
|
||||||
|
*
|
||||||
|
* The day grid calls this once per render. Its result is cached by the
|
||||||
|
* displayed dates and system settings, then invalidated by file changes, so
|
||||||
|
* a 42-cell calendar never repeats the vault scan per cell or per redraw.
|
||||||
|
*/
|
||||||
|
getDateSystemIndicators(dates: moment.Moment[]): Map<string, DateSystemIndicator[]> {
|
||||||
|
const dateStrings = dates.map(date => date.format('YYYY-MM-DD'));
|
||||||
|
const systems = this.dateSystems()
|
||||||
|
.filter(system => formatHasDateToken(system.nameFormat))
|
||||||
|
.map(system => {
|
||||||
|
const parts = splitNameFormat(system.nameFormat);
|
||||||
|
return {
|
||||||
|
system,
|
||||||
|
hasTitle: parts.hasTitle,
|
||||||
|
dates: dates.map((date, index) => ({
|
||||||
|
dateStr: dateStrings[index],
|
||||||
|
before: formatDatePart(date, parts.before),
|
||||||
|
after: formatDatePart(date, parts.after),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const key = JSON.stringify({
|
||||||
|
dates: dateStrings,
|
||||||
|
systems: systems.map(({ system }) => [
|
||||||
|
system.id,
|
||||||
|
system.name,
|
||||||
|
system.folder,
|
||||||
|
system.nameFormat,
|
||||||
|
system.indicatorColor,
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
if (this.dateSystemIndicators && this.dateSystemIndicatorKey === key) {
|
||||||
|
return this.dateSystemIndicators;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingIds = new Map<string, Set<string>>();
|
||||||
|
for (const dateStr of dateStrings) matchingIds.set(dateStr, new Set());
|
||||||
|
|
||||||
|
// The only vault traversal: filter a file by system folder first, then
|
||||||
|
// test it against the month's at-most-42 formatted day patterns.
|
||||||
|
for (const file of this.app.vault.getMarkdownFiles()) {
|
||||||
|
for (const entry of systems) {
|
||||||
|
if (!isInFolder(file.path, entry.system.folder)) continue;
|
||||||
|
for (const match of entry.dates) {
|
||||||
|
if (matchesSystemName(file.basename, match.before, match.after, entry.hasTitle)) {
|
||||||
|
matchingIds.get(match.dateStr)?.add(entry.system.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = new Map<string, DateSystemIndicator[]>();
|
||||||
|
for (const dateStr of dateStrings) {
|
||||||
|
const ids = matchingIds.get(dateStr);
|
||||||
|
result.set(dateStr, systems
|
||||||
|
.filter(({ system }) => ids?.has(system.id))
|
||||||
|
.map(({ system }) => ({
|
||||||
|
id: system.id,
|
||||||
|
name: system.name,
|
||||||
|
color: system.indicatorColor,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
this.dateSystemIndicatorKey = key;
|
||||||
|
this.dateSystemIndicators = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open (creating if needed) the note `system` holds for `date`.
|
* Open (creating if needed) the note `system` holds for `date`.
|
||||||
*
|
*
|
||||||
|
|||||||
+73
-8
@@ -96,6 +96,32 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
this.saveAndRefresh();
|
this.saveAndRefresh();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Setting(container)
|
||||||
|
.setName('Indicator style')
|
||||||
|
.setDesc('Show one neutral dot for any dated note, or one coloured dot for each configured date system.')
|
||||||
|
.addDropdown((dropdown) => {
|
||||||
|
dropdown
|
||||||
|
.addOption('any', 'Single dot')
|
||||||
|
.addOption('systems', 'Colour by note system')
|
||||||
|
.setValue(this.settings.calendar.indicatorMode)
|
||||||
|
.onChange((value: 'any' | 'systems') => {
|
||||||
|
this.settings.calendar.indicatorMode = value;
|
||||||
|
this.saveAndRefresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(container)
|
||||||
|
.setName('Daily indicator colour')
|
||||||
|
.setDesc('Colour for daily-note dots when using “Colour by note system”.')
|
||||||
|
.addColorPicker((color) => {
|
||||||
|
color
|
||||||
|
.setValue(this.settings.calendar.dailyIndicatorColor)
|
||||||
|
.onChange((value) => {
|
||||||
|
this.settings.calendar.dailyIndicatorColor = value;
|
||||||
|
this.saveAndRefresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════
|
// ═══════════════════════════════
|
||||||
@@ -103,14 +129,20 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
// ═══════════════════════════════
|
// ═══════════════════════════════
|
||||||
|
|
||||||
private renderPeriodicTab(container: HTMLElement): void {
|
private renderPeriodicTab(container: HTMLElement): void {
|
||||||
this.addPeriodNoteSettings(container, 'Daily', this.settings.daily);
|
const templateSuggestionsId = this.createTemplateSuggestions(container);
|
||||||
this.addPeriodNoteSettings(container, 'Weekly', this.settings.weekly);
|
this.addPeriodNoteSettings(container, 'Daily', this.settings.daily, templateSuggestionsId);
|
||||||
this.addPeriodNoteSettings(container, 'Monthly', this.settings.monthly);
|
this.addPeriodNoteSettings(container, 'Weekly', this.settings.weekly, templateSuggestionsId);
|
||||||
this.addPeriodNoteSettings(container, 'Quarterly', this.settings.quarterly);
|
this.addPeriodNoteSettings(container, 'Monthly', this.settings.monthly, templateSuggestionsId);
|
||||||
this.addPeriodNoteSettings(container, 'Yearly', this.settings.yearly);
|
this.addPeriodNoteSettings(container, 'Quarterly', this.settings.quarterly, templateSuggestionsId);
|
||||||
|
this.addPeriodNoteSettings(container, 'Yearly', this.settings.yearly, templateSuggestionsId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private addPeriodNoteSettings(container: HTMLElement, label: string, period: PeriodNoteSettings): void {
|
private addPeriodNoteSettings(
|
||||||
|
container: HTMLElement,
|
||||||
|
label: string,
|
||||||
|
period: PeriodNoteSettings,
|
||||||
|
templateSuggestionsId: string,
|
||||||
|
): void {
|
||||||
new Setting(container).setHeading().setName(label);
|
new Setting(container).setHeading().setName(label);
|
||||||
|
|
||||||
new Setting(container)
|
new Setting(container)
|
||||||
@@ -139,10 +171,11 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
new Setting(container)
|
new Setting(container)
|
||||||
.setName('Template file')
|
.setName('Template file')
|
||||||
.setDesc(`Path to the template file (without .md extension).`)
|
.setDesc('Path to the template file. The .md extension is optional.')
|
||||||
.addText((text) => {
|
.addText((text) => {
|
||||||
text.setPlaceholder('Templates/Daily note');
|
text.setPlaceholder('Templates/Daily note');
|
||||||
text.setValue(period.templateFile);
|
text.setValue(period.templateFile);
|
||||||
|
text.inputEl.setAttr('list', templateSuggestionsId);
|
||||||
text.onChange((value) => {
|
text.onChange((value) => {
|
||||||
period.templateFile = value;
|
period.templateFile = value;
|
||||||
this.saveAndRefresh();
|
this.saveAndRefresh();
|
||||||
@@ -178,6 +211,8 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
.setName('Date systems')
|
.setName('Date systems')
|
||||||
.setDesc(intro);
|
.setDesc(intro);
|
||||||
|
|
||||||
|
const templateSuggestionsId = this.createTemplateSuggestions(container);
|
||||||
|
|
||||||
this.settings.dateSystems.forEach((system, i, arr) => {
|
this.settings.dateSystems.forEach((system, i, arr) => {
|
||||||
new Setting(container)
|
new Setting(container)
|
||||||
.setHeading()
|
.setHeading()
|
||||||
@@ -244,7 +279,7 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
this.addSystemTextSetting(container,
|
this.addSystemTextSetting(container,
|
||||||
'Template file', 'Path to the template file. The .md extension is optional.',
|
'Template file', 'Path to the template file. The .md extension is optional.',
|
||||||
system, 'templateFile', 'resources/template/journal',
|
system, 'templateFile', 'resources/template/journal', templateSuggestionsId,
|
||||||
);
|
);
|
||||||
this.addSystemTextSetting(container,
|
this.addSystemTextSetting(container,
|
||||||
'Type property', `Fallback value for the 'type' frontmatter property, used when no template is found.`,
|
'Type property', `Fallback value for the 'type' frontmatter property, used when no template is found.`,
|
||||||
@@ -254,6 +289,18 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
'Icon', 'Lucide icon name for the menu item. Browse names at lucide.dev.',
|
'Icon', 'Lucide icon name for the menu item. Browse names at lucide.dev.',
|
||||||
system, 'icon', 'book-open',
|
system, 'icon', 'book-open',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
new Setting(container)
|
||||||
|
.setName('Indicator colour')
|
||||||
|
.setDesc('Colour for this system’s dot when using “Colour by note system”.')
|
||||||
|
.addColorPicker((color) => {
|
||||||
|
color
|
||||||
|
.setValue(system.indicatorColor)
|
||||||
|
.onChange((value) => {
|
||||||
|
system.indicatorColor = value;
|
||||||
|
this.saveAndRefresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(container)
|
new Setting(container)
|
||||||
@@ -280,6 +327,7 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
obj: Record<K, string>,
|
obj: Record<K, string>,
|
||||||
key: K,
|
key: K,
|
||||||
placeholder: string,
|
placeholder: string,
|
||||||
|
templateSuggestionsId?: string,
|
||||||
): Setting {
|
): Setting {
|
||||||
return new Setting(container)
|
return new Setting(container)
|
||||||
.setName(name)
|
.setName(name)
|
||||||
@@ -287,6 +335,7 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
.addText((text) => {
|
.addText((text) => {
|
||||||
text.setPlaceholder(placeholder);
|
text.setPlaceholder(placeholder);
|
||||||
text.setValue(obj[key]);
|
text.setValue(obj[key]);
|
||||||
|
if (templateSuggestionsId) text.inputEl.setAttr('list', templateSuggestionsId);
|
||||||
text.onChange((value) => {
|
text.onChange((value) => {
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
this.saveAndRefresh();
|
this.saveAndRefresh();
|
||||||
@@ -294,6 +343,22 @@ export class WaypointSettingTab extends PluginSettingTab {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native datalist keeps template paths searchable without another custom
|
||||||
|
* modal, and accepts templates stored anywhere in the vault.
|
||||||
|
*/
|
||||||
|
private createTemplateSuggestions(container: HTMLElement): string {
|
||||||
|
const id = 'waypoint-template-suggestions';
|
||||||
|
const list = container.createEl('datalist', { attr: { id } });
|
||||||
|
const paths = this.app.vault.getMarkdownFiles()
|
||||||
|
.map(file => file.path.replace(/\.md$/, ''))
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
for (const path of paths) {
|
||||||
|
list.createEl('option', { value: path });
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════
|
// ═══════════════════════════════
|
||||||
// Recent Files tab
|
// Recent Files tab
|
||||||
// ═══════════════════════════════
|
// ═══════════════════════════════
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export interface DateSystemSettings {
|
|||||||
typeProperty: string;
|
typeProperty: string;
|
||||||
/** Lucide icon name for the menu item. */
|
/** Lucide icon name for the menu item. */
|
||||||
icon: string;
|
icon: string;
|
||||||
|
/** CSS colour for this system's calendar indicator. */
|
||||||
|
indicatorColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Field defaults for a newly added system, and the merge base for saved ones. */
|
/** Field defaults for a newly added system, and the merge base for saved ones. */
|
||||||
@@ -37,11 +39,16 @@ export const DEFAULT_DATE_SYSTEM: Omit<DateSystemSettings, 'id'> = {
|
|||||||
templateFile: '',
|
templateFile: '',
|
||||||
typeProperty: '',
|
typeProperty: '',
|
||||||
icon: 'file',
|
icon: 'file',
|
||||||
|
indicatorColor: '#64748b',
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface CalendarSettings {
|
export interface CalendarSettings {
|
||||||
firstDayOfWeek: number; // 0=Sunday, 1=Monday
|
firstDayOfWeek: number; // 0=Sunday, 1=Monday
|
||||||
showNoteIndicators: boolean;
|
showNoteIndicators: boolean;
|
||||||
|
/** Single neutral dot, or a dot per day-scoped date system. */
|
||||||
|
indicatorMode: 'any' | 'systems';
|
||||||
|
/** Colour used by the synthesized daily system in `systems` mode. */
|
||||||
|
dailyIndicatorColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RecentFilesSettings {
|
export interface RecentFilesSettings {
|
||||||
@@ -78,6 +85,8 @@ export const DEFAULT_SETTINGS: WaypointSettings = {
|
|||||||
calendar: {
|
calendar: {
|
||||||
firstDayOfWeek: 1, // Monday
|
firstDayOfWeek: 1, // Monday
|
||||||
showNoteIndicators: true,
|
showNoteIndicators: true,
|
||||||
|
indicatorMode: 'systems',
|
||||||
|
dailyIndicatorColor: '#3b82f6',
|
||||||
},
|
},
|
||||||
daily: {
|
daily: {
|
||||||
folder: 'periodic/daily',
|
folder: 'periodic/daily',
|
||||||
@@ -118,6 +127,7 @@ export const DEFAULT_SETTINGS: WaypointSettings = {
|
|||||||
templateFile: '',
|
templateFile: '',
|
||||||
typeProperty: 'journal',
|
typeProperty: 'journal',
|
||||||
icon: 'book-open',
|
icon: 'book-open',
|
||||||
|
indicatorColor: '#22c55e',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'meetings',
|
id: 'meetings',
|
||||||
@@ -127,6 +137,7 @@ export const DEFAULT_SETTINGS: WaypointSettings = {
|
|||||||
templateFile: '',
|
templateFile: '',
|
||||||
typeProperty: 'meeting',
|
typeProperty: 'meeting',
|
||||||
icon: 'users',
|
icon: 'users',
|
||||||
|
indicatorColor: '#a855f7',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
recentFiles: {
|
recentFiles: {
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ export class WaypointView extends ItemView {
|
|||||||
|
|
||||||
private renderCalendar(): void {
|
private renderCalendar(): void {
|
||||||
const section = this.contentEl.createDiv({ cls: 'waypoint-section' });
|
const section = this.contentEl.createDiv({ cls: 'waypoint-section' });
|
||||||
section.createDiv({ cls: 'waypoint-section-header', text: 'Calendar' });
|
|
||||||
|
|
||||||
const cal = section.createDiv({ cls: 'waypoint-calendar' });
|
const cal = section.createDiv({ cls: 'waypoint-calendar' });
|
||||||
|
|
||||||
@@ -181,6 +180,14 @@ export class WaypointView extends ItemView {
|
|||||||
this.plugin.settings.calendar.firstDayOfWeek,
|
this.plugin.settings.calendar.firstDayOfWeek,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const systemIndicators = this.plugin.settings.calendar.showNoteIndicators
|
||||||
|
&& this.plugin.settings.calendar.indicatorMode === 'systems'
|
||||||
|
? this.plugin.getDateSystemIndicators(weeks.reduce<moment.Moment[]>(
|
||||||
|
(dates, week) => dates.concat(week.days.map(day => day.date)),
|
||||||
|
[],
|
||||||
|
))
|
||||||
|
: null;
|
||||||
|
|
||||||
for (const week of weeks) {
|
for (const week of weeks) {
|
||||||
const row = tbody.createEl('tr');
|
const row = tbody.createEl('tr');
|
||||||
|
|
||||||
@@ -211,9 +218,21 @@ export class WaypointView extends ItemView {
|
|||||||
|
|
||||||
if (this.plugin.settings.calendar.showNoteIndicators) {
|
if (this.plugin.settings.calendar.showNoteIndicators) {
|
||||||
const dateStr = day.date.format('YYYY-MM-DD');
|
const dateStr = day.date.format('YYYY-MM-DD');
|
||||||
|
if (this.plugin.settings.calendar.indicatorMode === 'any') {
|
||||||
if (this.plugin.hasNoteForDate(dateStr)) {
|
if (this.plugin.hasNoteForDate(dateStr)) {
|
||||||
cell.addClass('has-note');
|
cell.addClass('has-note');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const indicators = systemIndicators?.get(dateStr) || [];
|
||||||
|
if (indicators.length > 0) {
|
||||||
|
const dots = cell.createDiv({ cls: 'waypoint-day-indicators' });
|
||||||
|
for (const indicator of indicators) {
|
||||||
|
const dot = dots.createSpan({ cls: 'waypoint-day-indicator' });
|
||||||
|
dot.style.setProperty('--waypoint-indicator-color', indicator.color);
|
||||||
|
setTooltip(dot, indicator.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.addEventListener('click', () => {
|
cell.addEventListener('click', () => {
|
||||||
|
|||||||
+60
-20
@@ -58,29 +58,34 @@
|
|||||||
|
|
||||||
.waypoint-calendar {
|
.waypoint-calendar {
|
||||||
font-size: var(--font-ui-small);
|
font-size: var(--font-ui-small);
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--background-primary-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-top {
|
.waypoint-calendar-top {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-breadcrumb {
|
.waypoint-calendar-breadcrumb {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 4px;
|
||||||
font-size: var(--font-ui-medium);
|
font-size: var(--font-ui-medium);
|
||||||
font-weight: var(--font-semibold);
|
font-weight: var(--font-semibold);
|
||||||
padding: 4px 0;
|
padding: 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-breadcrumb .waypoint-clickable {
|
.waypoint-calendar-breadcrumb .waypoint-clickable {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
cursor: var(--cursor-link, pointer);
|
cursor: var(--cursor-link, pointer);
|
||||||
padding: 1px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
transition: color 80ms, background-color 80ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-breadcrumb .waypoint-clickable:hover {
|
.waypoint-calendar-breadcrumb .waypoint-clickable:hover {
|
||||||
@@ -90,23 +95,25 @@
|
|||||||
|
|
||||||
.waypoint-calendar .waypoint-separator {
|
.waypoint-calendar .waypoint-separator {
|
||||||
color: var(--text-faint);
|
color: var(--text-faint);
|
||||||
margin: 0 2px;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-today-group {
|
.waypoint-calendar-today-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 2px;
|
gap: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-today-group button {
|
.waypoint-calendar-today-group button {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: var(--cursor-link, pointer);
|
cursor: var(--cursor-link, pointer);
|
||||||
padding: 2px 6px;
|
padding: 2px 5px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: var(--font-ui-small);
|
font-size: var(--font-ui-small);
|
||||||
|
transition: color 80ms, background-color 80ms;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar-today-group button:hover {
|
.waypoint-calendar-today-group button:hover {
|
||||||
@@ -121,30 +128,34 @@
|
|||||||
.waypoint-calendar table {
|
.waypoint-calendar table {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: separate;
|
||||||
|
border-spacing: 2px 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar th,
|
.waypoint-calendar th,
|
||||||
.waypoint-calendar td {
|
.waypoint-calendar td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 4px 2px;
|
padding: 0;
|
||||||
font-size: var(--font-ui-small);
|
font-size: var(--font-ui-small);
|
||||||
line-height: 1.6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar th {
|
.waypoint-calendar th {
|
||||||
|
padding-bottom: 2px;
|
||||||
font-weight: var(--font-medium);
|
font-weight: var(--font-medium);
|
||||||
color: var(--text-faint);
|
color: var(--text-faint);
|
||||||
font-size: calc(var(--font-ui-small) * 0.85);
|
font-size: calc(var(--font-ui-small) * 0.78);
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-weeknum {
|
.waypoint-calendar .waypoint-weeknum {
|
||||||
font-size: calc(var(--font-ui-small) * 0.75);
|
width: 18px;
|
||||||
|
font-size: calc(var(--font-ui-small) * 0.72);
|
||||||
color: var(--text-faint);
|
color: var(--text-faint);
|
||||||
font-weight: var(--font-light);
|
font-weight: var(--font-light);
|
||||||
cursor: var(--cursor-link, pointer);
|
cursor: var(--cursor-link, pointer);
|
||||||
padding: 2px 0;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
transition: color 80ms, background-color 80ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-weeknum:hover {
|
.waypoint-calendar .waypoint-weeknum:hover {
|
||||||
@@ -154,42 +165,71 @@
|
|||||||
|
|
||||||
.waypoint-calendar .waypoint-day {
|
.waypoint-calendar .waypoint-day {
|
||||||
cursor: var(--cursor-link, pointer);
|
cursor: var(--cursor-link, pointer);
|
||||||
min-height: var(--wp-cal-cell-size, 32px);
|
height: var(--wp-cal-cell-size, 32px);
|
||||||
padding: 2px 0;
|
box-sizing: border-box;
|
||||||
|
padding: 2px 0 7px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
transition: color 80ms, background-color 80ms, box-shadow 80ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-day:hover {
|
.waypoint-calendar .waypoint-day:hover {
|
||||||
background-color: var(--background-modifier-active-hover);
|
background-color: var(--background-modifier-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-day.other-month {
|
.waypoint-calendar .waypoint-day.other-month {
|
||||||
opacity: 0.35;
|
color: var(--text-faint);
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-day.today {
|
.waypoint-calendar .waypoint-day.today {
|
||||||
color: var(--text-accent);
|
color: var(--text-accent);
|
||||||
border: 1px solid var(--text-accent);
|
|
||||||
font-weight: var(--font-semibold);
|
font-weight: var(--font-semibold);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--text-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waypoint-calendar .waypoint-day.today:hover {
|
||||||
|
background-color: var(--background-modifier-active-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Single-dot mode preserves the pre-date-systems indicator. */
|
||||||
.waypoint-calendar .waypoint-day.has-note::after {
|
.waypoint-calendar .waypoint-day.has-note::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 3px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: var(--text-faint);
|
background-color: var(--text-faint);
|
||||||
margin: 0 auto;
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.waypoint-calendar .waypoint-day.today.has-note::after {
|
.waypoint-calendar .waypoint-day.today.has-note::after {
|
||||||
background-color: var(--text-accent);
|
background-color: var(--text-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Colour-by-system mode: one dot per matching system, in Settings order. */
|
||||||
|
.waypoint-day-indicators {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 3px;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.waypoint-day-indicator {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--waypoint-indicator-color);
|
||||||
|
box-shadow: 0 0 0 1px var(--background-primary);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Recent Files ── */
|
/* ── Recent Files ── */
|
||||||
|
|
||||||
.waypoint-recent-filter {
|
.waypoint-recent-filter {
|
||||||
|
|||||||
Reference in New Issue
Block a user