summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/calendar-phase-3.md
diff options
context:
space:
mode:
Diffstat (limited to '.rules/plan/calendar-phase-3.md')
-rw-r--r--.rules/plan/calendar-phase-3.md74
1 files changed, 74 insertions, 0 deletions
diff --git a/.rules/plan/calendar-phase-3.md b/.rules/plan/calendar-phase-3.md
new file mode 100644
index 0000000..228f7e0
--- /dev/null
+++ b/.rules/plan/calendar-phase-3.md
@@ -0,0 +1,74 @@
+# Phase 3: Calendar Renderer (`src/calendar/calendar-renderer.ts`)
+
+**Status:** Not started
+**Depends on:** Phase 2 (calendar-state.ts — reads state for rendering)
+**Output file:** `src/calendar/calendar-renderer.ts`
+
+---
+
+## Overview
+
+Pure DOM rendering — replaces `Calendar.svelte` and `obsidian-calendar-ui`. Builds the month grid using Obsidian's `createEl`/`createDiv` helpers. Subscribes to `CalendarState` and re-renders on changes.
+
+---
+
+## Design
+
+```
+class CalendarRenderer:
+ constructor(containerEl: HTMLElement, state: CalendarState, callbacks: CalendarCallbacks)
+
+ interface CalendarCallbacks:
+ onClickDay(date: Moment, event: MouseEvent): void
+ onClickWeek(date: Moment, event: MouseEvent): void
+ onClickMonth(date: Moment, event: MouseEvent): void // from fork: click month label
+ onClickYear(date: Moment, event: MouseEvent): void // from fork: click year label
+ onClickQuarter(date: Moment, event: MouseEvent): void // from fork: click quarter label
+ onContextMenuDay(date: Moment, event: MouseEvent): void
+ onContextMenuWeek(date: Moment, event: MouseEvent): void
+ onContextMenuMonth(date: Moment, event: MouseEvent): void // from fork
+ onContextMenuYear(date: Moment, event: MouseEvent): void // from fork
+ onContextMenuQuarter(date: Moment, event: MouseEvent): void // from fork
+ onHoverDay(date: Moment, targetEl: EventTarget, isMetaPressed: boolean): void
+ onHoverWeek(date: Moment, targetEl: EventTarget, isMetaPressed: boolean): void
+ onHoverMonth(date: Moment, targetEl: EventTarget, isMetaPressed: boolean): void // from fork
+ onHoverYear(date: Moment, targetEl: EventTarget, isMetaPressed: boolean): void // from fork
+ onHoverQuarter(date: Moment, targetEl: EventTarget, isMetaPressed: boolean): void // from fork
+
+ Methods:
+ - render(): void
+ Clears containerEl, builds:
+ - Navigation bar: [<] [Month Year] [>] [Today]
+ - Month and Year labels are clickable → callbacks.onClickMonth / onClickYear (from fork)
+ - Quarter label (e.g. Q1) shown if calendarShowQuarter is true (from fork)
+ - Weekday headers row (Mon, Tue, ...)
+ - Optional week number column (left or right based on calendarShowWeekNumbersRight — from fork)
+ - 6 rows × 7 day cells
+ Each day cell:
+ - CSS class: "today", "has-note", "active", "other-month"
+ - Dots container (word count, tasks — uses settings from Phase 5)
+ - Click handler → callbacks.onClickDay
+ - Context menu → callbacks.onContextMenuDay
+
+ - destroy(): void
+ Cleanup intervals, event listeners
+
+ private:
+ - renderNavBar(): HTMLElement
+ - renderDayHeaders(): HTMLElement
+ - renderWeeks(): HTMLElement
+ - renderDay(date: Moment): HTMLElement
+ - renderWeekNumber(date: Moment, position: "left" | "right"): HTMLElement // from fork: position option
+ - renderQuarterLabel(date: Moment): HTMLElement // from fork
+ - getDaysInMonthGrid(month: Moment): Moment[][]
+ Returns 6 rows of 7 days, padding with prev/next month days
+```
+
+---
+
+## Notes
+
+- All rendering uses Obsidian's `createEl`/`createDiv` helpers — no innerHTML.
+- CSS classes follow the `ai-pulse-calendar-*` naming convention (see Phase 9).
+- The renderer needs access to settings (week start, show week numbers, show quarter, words per dot) — these are passed via constructor or a settings reference.
+- Word count dots: read the file's cached metadata or content to count words, show N dots where N = floor(wordCount / wordsPerDot), capped at a reasonable max.