From be8d8a7d9b2c79bd6866ee7043e2a12009811431 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Wed, 8 Jul 2026 20:19:30 +0100 Subject: [PATCH] feat(waybar): open a calendar (calcurse) on the clock click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Item 42, de-scoped by Bernardo to app-only — no account sync (the user configures that themselves locally). Clicking the Waybar date/clock now runs nomarchy-calendar → calcurse in a floating, centered ghostty window tagged --class=com.nomarchy.calendar (+ --gtk-single-instance=false for a fresh standalone window), matched by a float+size+center windowrule. The launcher self-gates on calcurse. Dropped the clock's format-alt date toggle (conflicts with on-click) and moved the long date into the tooltip. Parity: on-click added to all four whole-swap jsoncs. Ships calcurse + pwvucontrol uncommented in the downstream template (opt-out). Enforces ghostty always installed (ghostty.nix: enable = true unconditional; nomarchy.ghostty.enable now gates only the theming/config) so the --class launcher can rely on it. Verified: V0 green; four jsoncs valid JSON; V1 HM built — launcher ships, generated clock renders on-click=nomarchy-calendar (format-alt gone, date in tooltip), hyprland has the 3 calendar windowrules, ghostty in the HM profile. Click→float→calcurse month view is V3 (queued). Sync is deliberately the user's own config, not a distro feature. Co-Authored-By: Claude Opus 4.8 --- agent/BACKLOG.md | 49 ----------------------------- agent/HARDWARE-QUEUE.md | 11 +++++++ agent/JOURNAL.md | 29 +++++++++++++++++ modules/home/ghostty.nix | 9 ++++-- modules/home/hyprland.nix | 7 +++++ modules/home/waybar.nix | 29 ++++++++++++++--- templates/downstream/home.nix | 1 + themes/boreal/waybar.jsonc | 1 + themes/executive-slate/waybar.jsonc | 1 + themes/summer-day/waybar.jsonc | 1 + themes/summer-night/waybar.jsonc | 1 + 11 files changed, 83 insertions(+), 56 deletions(-) diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 91a4e90..fe27dd0 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -252,55 +252,6 @@ Next slice: on hardware, run `hyprctl clients` while each is open, read the real `class`, then append rules. Also revisit whether blueman/s-c-p actually float once seen (regex tolerance for the `.…-wrapped` form). -### 42. System calendar app synced to the user's accounts `[big]` -(Raised by Bernardo, 2026-07-08.) Clicking the Waybar **date/clock** -module should open a calendar that shows the user's real events, synced -from their calendar accounts (CalDAV / Google / Nextcloud / iCloud). Hard -requirement: it must open **instantly** on click — no Thunderbird/Evolution -multi-second cold start. - -_Investigation (2026-07-08 — Bernardo suggested calcurse; asked for the -best approach):_ the winning shape is **split sync from display** — a sync -daemon fills a local store, a fast local viewer reads it instantly. -- **Recommended (most Nomarchy-native): `khal` (TUI) in a floating ghostty - window + `vdirsyncer` for sync.** khal reads a local vdir instantly → - opens immediately; running it in ghostty means it **themes for free** off - the palette (pillar 4, zero new theming surface) and slots into the - float+center windowrule pattern (item 41). vdirsyncer is the de-facto - CalDAV→local-ics sync (Nextcloud/Fastmail/iCloud with an app password are - frictionless). Configs are file-based → in-flake friendly. -- **calcurse (Bernardo's pick):** viable, instant TUI, single self-contained - tool — but it's *local-first*; `calcurse-caldav` multi-account/Google sync - is clunkier than vdirsyncer. Fine if a one-tool solution is preferred over - sync robustness. -- **GNOME Calendar + GNOME Online Accounts:** the GUI path with the *best* - Google onboarding (GOA handles OAuth cleanly), themes via GTK — but it's - heavier and pulls evolution-data-server + GOA, and first-open is **not - instant**, so it fails the core requirement. Fallback only if easy account - setup outweighs instant-open. (`gcalcli` = Google-only, not general.) - -_Two real wrinkles to design around:_ -1. **Credentials are secrets** — account passwords / OAuth tokens can't live - in the git-tracked flake, so this is the one legitimate exception to - "no state outside the checkout" (see [[in-flake-state-philosophy]]). - Decide: a plain runtime path (`~/.config`, documented exception) vs - sops/agenix encrypted-in-flake. -2. **Google OAuth friction** — vdirsyncer needs a *self-registered* - `client_id`/`client_secret` (shipping one violates Google ToS). CalDAV - app-password providers are painless; Google is the sharp edge. GOA - sidesteps it but only on the heavy GUI path. - -_Slices (split before starting):_ (a) `[human]` pick the tool -(recommend khal+vdirsyncer; calcurse acceptable), then ship the viewer -bound to the clock `on-click` — launch it in a ghostty window with a -distinct `--class` so a float+center windowrule can target it; move the -current time↔date `format-alt` toggle to `on-click-right`/scroll; parity -across the four whole-swap jsoncs. Local-only first (an .ics on disk). -(b) add vdirsyncer + a sync systemd timer (like the update checker) + a -menu writer for accounts, resolving the secrets decision above. (c) optional -polish: upcoming events in the clock **tooltip** via a khal-backed script -(hover = next events, click = full calendar). - ## LATER - **Wallpapers artifact split** (ROADMAP § Faster switches — decided, diff --git a/agent/HARDWARE-QUEUE.md b/agent/HARDWARE-QUEUE.md index a0fe1ca..85a4008 100644 --- a/agent/HARDWARE-QUEUE.md +++ b/agent/HARDWARE-QUEUE.md @@ -293,6 +293,17 @@ QA machine), the **T14s** (webcam case). night, executive-slate, boreal) behave the same and their shutdown power-button (if present) still opens the lock/logout menu. +- [ ] **Calendar on the clock click** (iteration #68, item 42) — after + `home-update` + relogin: left-click the Waybar date/clock → calcurse + opens in a **floating, centered** ghostty window (~60×65% of screen), + showing the month calendar; closing calcurse (`q`) closes the window. + The `--class=com.nomarchy.calendar` must match the windowrule (if it + tiles, run `hyprctl clients` while open and check the real app-id). + Hover the clock → tooltip shows the long date + zone + month grid. + Same on a whole-swap bar (summer/boreal/executive-slate). If calcurse + was removed from home.packages, the click toasts "calcurse isn't + installed" instead of doing nothing. + ## AMD dev box only - [ ] **AMD runtime bits** — VA-API (`vainfo` → radeonsi), amd-pstate EPP active and PPD switching governors; opt-ins: ROCm (`rocminfo`, a GPU diff --git a/agent/JOURNAL.md b/agent/JOURNAL.md index 89e4d63..d36b573 100644 --- a/agent/JOURNAL.md +++ b/agent/JOURNAL.md @@ -17,6 +17,35 @@ Template: --- +## 2026-07-08 — Calendar on the clock click (iteration #68, item 42) +- **Task:** item 42, de-scoped live by Bernardo — DON'T hook up calendar + accounts; just ship a lightweight calendar that opens instantly on the + Waybar date click, user configures sync themselves. calcurse (his pick; + now the right one since it's self-contained for the user's own sync). +- **Did:** new `nomarchy-calendar` launcher (waybar.nix) → calcurse in a + ghostty window tagged `--class=com.nomarchy.calendar` + + `--gtk-single-instance=false` (fresh standalone window); self-gates on + calcurse. Clock `on-click = nomarchy-calendar`, dropped the format-alt + date-toggle (conflicts with on-click), moved the long date into the + tooltip. Parity: on-click in all four whole-swap jsoncs. windowrule + float+size(60/65%)+center on the class (hyprland.nix). Shipped calcurse + + pwvucontrol **uncommented** in the downstream template (opt-out). + Enforced **ghostty always installed** (ghostty.nix: `enable = true` + unconditional, the nomarchy.ghostty.enable option now gates only config) + so the launcher can rely on `--class`. +- **Verified:** V0 green; all four jsoncs valid JSON; V1 HM built — launcher + ships the right command, generated clock renders `on-click: + nomarchy-calendar` with format-alt gone + date in the tooltip, hyprland + has the 3 calendar windowrules, ghostty present in the HM profile. +- **Pending:** V3 — click the clock → calcurse floats centered (the + `--class`→windowrule match) and renders its month view; verify on a real + session (queued). Sync is deliberately the user's own local config, NOT + a distro feature (Bernardo's call) — a future iteration should not + re-propose account sync. +- **Next suggestion:** Bernardo's big new task — investigate whether THIS + machine (NixOS 25.11) can migrate to Nomarchy without a reinstall, + keeping all files, and plan it. + ## 2026-07-08 — Combined power menu on the bar icons (iteration #67, item 36b) - **Task:** BACKLOG item 36(b), now unblocked. Bernardo's calls: keep the granular System ▸ Battery limit / Power profile rows; build ONE combined diff --git a/modules/home/ghostty.nix b/modules/home/ghostty.nix index 1c54715..0ed7993 100644 --- a/modules/home/ghostty.nix +++ b/modules/home/ghostty.nix @@ -8,11 +8,16 @@ let c = t.colors; in { - programs.ghostty = lib.mkIf config.nomarchy.ghostty.enable { + # Ghostty is ALWAYS installed — it's Nomarchy's default terminal and is + # load-bearing (SUPER+E file manager, the calendar launcher's classed + # window, etc.), so the distro enforces it. `nomarchy.ghostty.enable` now + # gates only whether Nomarchy's theming/config is applied — a user can + # keep ghostty but drop our config, they just can't remove ghostty itself. + programs.ghostty = { enable = true; enableBashIntegration = true; - settings = { + settings = lib.mkIf config.nomarchy.ghostty.enable { # ── Typography (from theme-state.json) ──────────────────────── font-family = t.fonts.mono; font-size = t.fonts.size; diff --git a/modules/home/hyprland.nix b/modules/home/hyprland.nix index 4d71267..6bb8d44 100644 --- a/modules/home/hyprland.nix +++ b/modules/home/hyprland.nix @@ -458,6 +458,13 @@ in # Bluetooth manager (blueman) + CUPS printer admin. "float, class:(?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$" "center, class:(?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$" + + # Calendar popup (item 42): the Waybar clock's on-click runs + # nomarchy-calendar → calcurse in a ghostty window tagged with a + # distinct --class, so it floats centered instead of tiling. + "float, class:^(com\\.nomarchy\\.calendar)$" + "size 60% 65%, class:^(com\\.nomarchy\\.calendar)$" + "center, class:^(com\\.nomarchy\\.calendar)$" ]; # Rendered from ./keybinds.nix (the cheatsheet reads the same list), diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix index 5da16bc..fd4a61b 100644 --- a/modules/home/waybar.nix +++ b/modules/home/waybar.nix @@ -82,6 +82,22 @@ let [ -n "$next" ] && powerprofilesctl set "$next" ''; + # Opens calcurse (a lightweight TUI calendar, month view by default) in a + # floating, centered ghostty window — bound to the Waybar clock's on-click. + # A distinct --class gives the window a matchable app-id for the + # float+center+size windowrule (hyprland.nix); --gtk-single-instance=false + # forces a fresh standalone window (ghostty defaults single-instance on). + # calcurse ships uncommented in the downstream template (opt-out), so + # self-gate with a helpful notify if it's been removed. ghostty is always + # installed (ghostty.nix), so it can be relied on for the --class window. + calendarLauncher = pkgs.writeShellScriptBin "nomarchy-calendar" '' + if ! command -v calcurse >/dev/null 2>&1; then + notify-send "Calendar" "calcurse isn't installed (removed from home.packages?)." 2>/dev/null + exit 0 + fi + exec ghostty --class=com.nomarchy.calendar --gtk-single-instance=false -e calcurse + ''; + # VPN indicator — shows a shield when a NetworkManager VPN/WireGuard # connection is active OR Tailscale is up; prints nothing otherwise so the # module self-hides (like nightlight/updates). Click opens the VPN submenu. @@ -154,10 +170,13 @@ let clock = { format = "{:%H:%M}"; - format-alt = "{:%A %d %B %Y}"; - # Zone line first (LATER nicety): under auto-timezone the tz-watch - # SIGUSR2 reload keeps it showing the currently *detected* zone. - tooltip-format = "{:%Z (UTC%z)}\n{calendar}"; + # Left-click → the calendar (nomarchy-calendar → calcurse in a floating + # ghostty). Replaces the old format-alt date toggle; the long date now + # rides in the tooltip's first line, so nothing is lost on hover. + on-click = "nomarchy-calendar"; + # The zone line stays live under auto-timezone (the tz-watch SIGUSR2 + # reload keeps it showing the currently *detected* zone). + tooltip-format = "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n{calendar}"; }; # Active keyboard layout (per focused device) — only placed in @@ -431,5 +450,5 @@ in # whole-swap themes' static waybar.jsonc can exec them by name — plus # the supervisor hyprland.nix exec-onces. home.packages = lib.optionals config.nomarchy.waybar.enable - [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus doctorStatus ]; + [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus doctorStatus calendarLauncher ]; } diff --git a/templates/downstream/home.nix b/templates/downstream/home.nix index 1eff4db..96e120d 100644 --- a/templates/downstream/home.nix +++ b/templates/downstream/home.nix @@ -82,6 +82,7 @@ mpv # media player amberol # music player (local library; streaming → spotify below) pwvucontrol # PipeWire volume mixer (right-click the Waybar volume) + calcurse # TUI calendar — click the Waybar clock to open it # ── More apps — uncomment to add ───────────────────────────────── # Web browsers diff --git a/themes/boreal/waybar.jsonc b/themes/boreal/waybar.jsonc index 30c1f05..2c8e8f4 100644 --- a/themes/boreal/waybar.jsonc +++ b/themes/boreal/waybar.jsonc @@ -39,6 +39,7 @@ }, "clock": { "format": "{:%H:%M}", + "on-click": "nomarchy-calendar", "tooltip": true, "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" }, diff --git a/themes/executive-slate/waybar.jsonc b/themes/executive-slate/waybar.jsonc index 40a86db..00cb66b 100644 --- a/themes/executive-slate/waybar.jsonc +++ b/themes/executive-slate/waybar.jsonc @@ -46,6 +46,7 @@ }, "clock": { "format": "{:%H:%M}", + "on-click": "nomarchy-calendar", "tooltip": true, "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" }, diff --git a/themes/summer-day/waybar.jsonc b/themes/summer-day/waybar.jsonc index 6af034f..a9f6d1d 100644 --- a/themes/summer-day/waybar.jsonc +++ b/themes/summer-day/waybar.jsonc @@ -70,6 +70,7 @@ "clock": { "format": " {:%H:%M}", + "on-click": "nomarchy-calendar", "tooltip": true, "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" }, diff --git a/themes/summer-night/waybar.jsonc b/themes/summer-night/waybar.jsonc index a3ec3e5..9ff5fdf 100644 --- a/themes/summer-night/waybar.jsonc +++ b/themes/summer-night/waybar.jsonc @@ -69,6 +69,7 @@ "clock": { "format": " {:%H:%M}", + "on-click": "nomarchy-calendar", "tooltip": true, "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" },