From a8a04377beab10c187e33b9af0536812dca9cd76 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 28 Jun 2026 13:55:36 -0400 Subject: feat(dashboard): add a weather launcher (wttrin) A Weather launcher joins the dashboard's top row after Agenda, on key w, drawn with the nf-weather-day_sunny_overcast Weather Icons glyph. It opens the wttrin forecast through call-interactively so wttrin's location prompt runs. A bare (wttrin) call errors, since the command takes the location as a required argument that its interactive form supplies. Row sizes move from 4-4-3-3 to 5-4-3-3. The launcher table stays the single source for both the navigator icons and the keymap. --- modules/dashboard-config.el | 7 +++++-- tests/test-dashboard-config-launchers.el | 30 ++++++++++++++++++------------ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/modules/dashboard-config.el b/modules/dashboard-config.el index daa75fe99..53f19b72b 100644 --- a/modules/dashboard-config.el +++ b/modules/dashboard-config.el @@ -54,6 +54,7 @@ (declare-function nerd-icons-mdicon "nerd-icons") (declare-function nerd-icons-codicon "nerd-icons") (declare-function nerd-icons-octicon "nerd-icons") +(declare-function nerd-icons-wicon "nerd-icons") ;; user-constants.el provides the home-directory constant. (defvar user-home-dir) @@ -139,6 +140,7 @@ Adjust this if the title doesn't appear centered under the banner image.") (list "d" #'nerd-icons-faicon "nf-fa-folder_o" "Files" "Dirvish File Manager" (lambda () (dirvish user-home-dir))) (list "t" #'nerd-icons-devicon "nf-dev-terminal" "Terminal" "Launch Terminal" (lambda () (cj/term-toggle))) (list "a" #'nerd-icons-mdicon "nf-md-calendar" "Agenda" "Main Org Agenda" (lambda () (cj/main-agenda-display))) + (list "w" #'nerd-icons-wicon "nf-weather-day_sunny_overcast" "Weather" "Wttrin Weather Forecast" (lambda () (call-interactively #'wttrin))) (list "r" #'nerd-icons-faicon "nf-fa-rss_square" "Feeds" "Elfeed Feed Reader" (lambda () (cj/elfeed-open))) (list "b" #'nerd-icons-codicon "nf-cod-library" "Books" "Calibre Ebook Reader" (lambda () (calibredb))) (list "f" #'nerd-icons-mdicon "nf-md-school" "Flashcards" "Org-Drill" (lambda () (cj/drill-start))) @@ -152,9 +154,10 @@ Adjust this if the title doesn't appear centered under the banner image.") "Dashboard launcher table: (KEY ICON-FN ICON-NAME LABEL TOOLTIP ACTION). Drives both `dashboard-navigator-buttons' and the dashboard-mode-map keys.") -(defconst cj/dashboard--row-sizes '(4 4 3 3) +(defconst cj/dashboard--row-sizes '(5 4 3 3) "Navigator row lengths. Must sum to the number of `cj/dashboard--launchers'. -The last row groups Slack, Linear, and Signal together.") +The top row carries Weather alongside the core tools; the last row groups +Slack, Linear, and Signal together.") (defun cj/dashboard--navigator-button (l) "Build a `dashboard-navigator-buttons' entry from launcher L." diff --git a/tests/test-dashboard-config-launchers.el b/tests/test-dashboard-config-launchers.el index e7e5dcd53..53c46caa9 100644 --- a/tests/test-dashboard-config-launchers.el +++ b/tests/test-dashboard-config-launchers.el @@ -27,19 +27,20 @@ ;; Telegram moved from "g" to "G" so "g" is free for dashboard refresh. ;; Signal ("S") added as the 14th launcher. -(defconst test-dash--keys '("c" "d" "t" "a" "r" "b" "f" "m" "e" "i" "G" "s" "l" "S")) +;; Weather ("w") added after Agenda as the 15th launcher (top-row daily glance). +(defconst test-dash--keys '("c" "d" "t" "a" "w" "r" "b" "f" "m" "e" "i" "G" "s" "l" "S")) ;; ----------------------------- launcher table -------------------------------- (ert-deftest test-dashboard-launchers-keys-in-order () - "Normal: 14 launchers with the expected keys in display order." - (should (= 14 (length cj/dashboard--launchers))) + "Normal: 15 launchers with the expected keys in display order." + (should (= 15 (length cj/dashboard--launchers))) (should (equal test-dash--keys (mapcar (lambda (l) (nth 0 l)) cj/dashboard--launchers)))) (ert-deftest test-dashboard-launchers-labels-in-order () "Normal: labels in display order (Telegram and Slack reordered so Slack sits next to Linear on the last navigator row)." - (should (equal '("Code" "Files" "Terminal" "Agenda" "Feeds" "Books" + (should (equal '("Code" "Files" "Terminal" "Agenda" "Weather" "Feeds" "Books" "Flashcards" "Music" "Email" "IRC" "Telegram" "Slack" "Linear" "Signal") (mapcar (lambda (l) (nth 3 l)) cj/dashboard--launchers)))) @@ -50,18 +51,19 @@ next to Linear on the last navigator row)." ;; --------------------------- navigator rows ---------------------------------- -(ert-deftest test-dashboard-navigator-rows-grouped-4-4-3-3 () - "Normal: navigator derives rows per `cj/dashboard--row-sizes' (4 4 3 3), with -Slack, Linear, and Signal sharing the last row." +(ert-deftest test-dashboard-navigator-rows-grouped-5-4-3-3 () + "Normal: navigator derives rows per `cj/dashboard--row-sizes' (5 4 3 3), with +Weather joining the top row and Slack, Linear, and Signal sharing the last row." (cl-letf (((symbol-function 'nerd-icons-faicon) (lambda (n &rest _) (concat "I:" n))) ((symbol-function 'nerd-icons-devicon) (lambda (n &rest _) (concat "I:" n))) ((symbol-function 'nerd-icons-mdicon) (lambda (n &rest _) (concat "I:" n))) ((symbol-function 'nerd-icons-octicon) (lambda (n &rest _) (concat "I:" n))) - ((symbol-function 'nerd-icons-codicon) (lambda (n &rest _) (concat "I:" n)))) + ((symbol-function 'nerd-icons-codicon) (lambda (n &rest _) (concat "I:" n))) + ((symbol-function 'nerd-icons-wicon) (lambda (n &rest _) (concat "I:" n)))) (let ((rows (cj/dashboard--navigator-rows))) (should (= 4 (length rows))) - (should (equal '(4 4 3 3) (mapcar #'length rows))) - (should (equal '("Code" "Files" "Terminal" "Agenda") + (should (equal '(5 4 3 3) (mapcar #'length rows))) + (should (equal '("Code" "Files" "Terminal" "Agenda" "Weather") (mapcar (lambda (b) (nth 1 b)) (nth 0 rows)))) (should (equal '("Slack" "Linear" "Signal") (mapcar (lambda (b) (nth 1 b)) (nth 3 rows)))) @@ -98,7 +100,10 @@ Slack, Linear, and Signal sharing the last row." ((symbol-function 'cj/slack-start) (lambda (&rest _) (push 'slack calls))) ((symbol-function 'cj/telega) (lambda (&rest _) (push 'tg calls))) ((symbol-function 'pearl-list-issues) (lambda (&rest _) (push 'linear calls))) - ((symbol-function 'cj/signel-message) (lambda (&rest _) (push 'signal calls)))) + ((symbol-function 'cj/signel-message) (lambda (&rest _) (push 'signal calls))) + ;; wttrin is invoked via `call-interactively', so the stub must be + ;; a command -- a plain variadic lambda masked the real arity bug. + ((symbol-function 'wttrin) (lambda (&rest _) (interactive) (push 'weather calls)))) (cj/dashboard--bind-launchers map) (dolist (key test-dash--keys) (call-interactively (keymap-lookup map key))) @@ -108,7 +113,8 @@ Slack, Linear, and Signal sharing the last row." (should (memq 'm-toggle calls)) (should (memq 'm-load calls)) (should (memq 'signal calls)) - (should (= 15 (length calls)))))) ; 14 keys, Music fires two + (should (memq 'weather calls)) + (should (= 16 (length calls)))))) ; 15 keys, Music fires two (provide 'test-dashboard-config-launchers) ;;; test-dashboard-config-launchers.el ends here -- cgit v1.2.3