Files
nocal/docs/PRODUCT.md
Bernardo Magri 989332ef9a feat: make month week start configurable
Add a Monday-default --week-start option for every weekday and carry it through domain layout, full and compact rendering, event query windows, print mode, and the interactive TUI.

Preserve byte-compatible Monday output and cover rotated headers, spill dates, invalid input, sanitizer behavior, and live terminal restoration.
2026-07-18 09:58:27 +01:00

8.1 KiB

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 weeks, Monday-first by default. --week-start can rotate the grid to any weekday. 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:

  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, atomic .ics writes, and explicit non-interactive calendar import/export. 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. Week-start selection rotates only the month grid, header, and the visible range used by its month queries; storage, agenda windows, and recurrence rules are unchanged. The default remains Monday for backward compatibility. The CLI accepts the exact lowercase values monday, tuesday, wednesday, thursday, friday, saturday, and sunday. The next local-data work adds advanced recurrence overrides and rule editing.

Local file interchange

Import and export are explicit command-line workflows. They never contact the network and do not enter the interactive TUI.

  • nocal --import SOURCE --calendar TARGET atomically merges events into the target. Exact same-UID, same-field events are duplicates and are skipped. A differing same-UID event, an empty or duplicate UID or invalid event interval in either file, or content in either file that cannot be safely round-tripped rejects the complete import before the target is written. A successful merge keeps the target's exact previous bytes as its adjacent .bak; a duplicate-only import leaves both target and backup untouched.
  • nocal --export DESTINATION --calendar SOURCE validates the source and atomically creates a canonical calendar. It never overwrites an existing destination and refuses any source whose events are invalid or that cannot be safely round-tripped.

The two operations are mutually exclusive and cannot be combined with demo, frame printing, or backup restoration. These restrictions keep destructive ambiguity out of automation and make every file-writing mode deliberate.

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.