Files
nocal/docs/PRODUCT.md
Bernardo Magri 8b6cf2e877 feat: add bounded agenda view
Add a read-only 42-day occurrence agenda with keyboard navigation, six-week paging, exact return-to-grid focus, search and calendar overlays, and bounded recurrence expansion.

Keep agenda state outside persistence, document month-only mutations, and cover empty windows, filtering, overlays, navigation, rendering, and terminal restoration.
2026-07-18 09:19:01 +01:00

112 lines
6.5 KiB
Markdown

# Nocal product and interaction specification
Nocal is a local-first, keyboard-driven month calendar for Linux terminals. Its
visual target is the information density of a desktop month view without
pretending that a terminal is a pixel canvas. The terminal emulator owns the
typeface and palette; Nocal owns hierarchy, spacing, and restrained emphasis.
## Product principles
1. **The month is the home screen.** Launching Nocal immediately shows six
complete Monday-first weeks. There is no dashboard or splash screen.
2. **Useful at a glance.** Every visible day shows as many appointments as fit,
ordered as all-day first and then by start time. A final `+N more` line is
used instead of clipping silently.
3. **Keyboard-native.** Arrow keys and Vim keys move by day or week; month and
today jumps are single keystrokes. Every action remains discoverable in the
footer and help overlay.
4. **Terminal-native aesthetics.** Nocal uses default foreground/background and
the terminal's ANSI semantic colors. It never paints a fixed RGB theme over
the user's Kitty, foot, Alacritty, or WezTerm theme.
5. **Local-first, sync-ready.** The canonical domain model is independent of
iCalendar files and of any future remote API. Sync engines translate into
domain objects and never leak provider-specific types into the UI.
6. **Fast enough to feel instant.** Startup should remain below 50 ms for a
normal local calendar and redraw should be flicker-free at interactive
resize rates.
## Month view
The full terminal is treated as a responsive canvas:
```text
JULY 2026 Today Fri 17 Jul
Mon Tue Wed Thu Fri Sat Sun
┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
│ 29 │ 30 │ 1 │ 2 │ 3 │ 4 │ 5 │
│ │ │ 09:30 Team │ │ All day … │ │ │
├────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
│ … │
└─────────────────────────────────────────────────────────────────────────────────────────┘
←↓↑→ move PgUp/PgDn month t today ? help q quit 2 appointments
```
- At 100 columns and above, Nocal draws the full bordered grid.
- Narrow cells abbreviate times and ellipsize summaries by display width.
- When height is constrained, appointment lines are reduced before structural
chrome. At extremely small sizes a clear minimum-size message replaces a
broken grid.
- Days outside the focused month remain visible but dim.
- The selected date is reverse-video, today is bold/underlined, and collisions
use semantic ANSI accents. These attributes work on monochrome terminals.
- The footer reports the selected day's appointment count and the most useful
keys for the available width.
## Interaction map
| Action | Keys |
| --- | --- |
| Previous/next day | `Left` / `Right`, `h` / `l` |
| Previous/next week | `Up` / `Down`, `k` / `j` |
| Previous/next month | `PageUp` / `PageDown`, `p` / `n` |
| Jump to today | `t` |
| Next/previous appointment | `Tab` / `Shift-Tab` |
| Read focused appointment | `Enter` |
| Browse inside reader | arrows, `h j k l`, `Tab` / `Shift-Tab` |
| Open/close 42-day agenda | `g`; `Esc` also closes |
| Choose agenda occurrence | arrows, `j` / `k`, `Tab` / `Shift-Tab`, then `Enter` |
| Shift agenda by 42 days | `PageUp` / `PageDown`, `p` / `n` |
| Add appointment | `a` |
| Edit focused appointment | `e` |
| Delete focused appointment | `d`, then `y` to confirm |
| Undo/redo successful mutation | `u` / `Ctrl-R` |
| Move between editor fields | `Tab` / `Shift-Tab`, arrows |
| Save/cancel editor | `Ctrl-S` / `Esc` |
| Return to month/unfocus | `Esc` |
| Search appointments | `/`, then type and press `Enter` |
| Choose search result | arrows, `j` / `k`, then `Enter` |
| Toggle calendar visibility | `c`, arrows or `j` / `k`, then `Enter` |
| Help | `?` |
| Quit | `q` |
The first usable foundation supports day and appointment navigation, a
full-frame reader, a read-only 42-day agenda, validated add/edit/delete forms,
and atomic `.ics` writes.
Dense days keep every appointment keyboard-reachable even when all lines do
not fit in the cell. Unknown or unsupported iCalendar content makes a source
read-only instead of being discarded. Saves reject external changes, retain a
last-known-good backup, and feed bounded session undo/redo history. Supported
recurring instances appear throughout the month, preserve civil time across
daylight-saving changes, and expose their source zone and whole-series mutation
semantics in the reader. `/` searches occurrence-aware title, description,
location, and calendar-ID matches in a finite ten-year window centered on the
selected date. `c` toggles session-only calendar visibility consistently across
the grid, appointment focus, and search without filtering the model supplied to
persistence. `g` opens an occurrence-aware agenda at the selected month date;
navigation is bounded to consecutive 42-day windows and `Enter` returns to the
exact occurrence in the month grid. `Esc` or `g` closes the agenda without
changing the month selection unless an occurrence was chosen. Hidden calendars
remain filtered there, while calendar selection and search can overlay the
agenda. Agenda navigation never persists state, and add/edit/delete remain in
the month workflow. The next local-data work adds advanced recurrence overrides
and rule editing.
## Accessibility
- Information is never encoded by color alone.
- `NO_COLOR` and terminals without color remain fully usable.
- Borders and icons have ASCII fallbacks; Unicode width is calculated rather
than assumed.
- Focus is always visible and keyboard operation is complete.
- Motion is limited to direct redraws; there are no decorative animations.