From d547393e7b735eeb4a70a6744b9932b61915643b Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Fri, 10 Jul 2026 12:58:37 +0100 Subject: [PATCH] fix(desktop): unfree CLI default, bar icon spacing, unified clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardware findings on Latitude: nix-shell blocked unfree; whole-swap bars collided icon+percentage; clock needed calcurse + one module. - Export NIXPKGS_ALLOW_UNFREE=1 + ~/.config/nixpkgs/config.nix - Mono Nerd face + trailing spaces on battery/volume icons (all bars) - Single clock `HH:MM · Day DD Mon`; calcurse ships with waybar - V3 queue entries for laptop re-check Verification: V0 — nix flake check --no-build green; V2/V3 pending on session (user-visible bar + CLI unfree). --- agent/HARDWARE-QUEUE.md | 26 ++++++++++----- modules/home/default.nix | 10 ++++++ modules/home/waybar.nix | 31 +++++++++++------- modules/nixos/default.nix | 4 +++ templates/downstream/home.nix | 2 +- themes/boreal/waybar.css | 7 ++-- themes/boreal/waybar.jsonc | 51 +++++++++++++---------------- themes/executive-slate/waybar.css | 7 ++-- themes/executive-slate/waybar.jsonc | 51 +++++++++++++---------------- themes/summer-day/waybar.css | 1 - themes/summer-day/waybar.jsonc | 43 +++++++++++------------- themes/summer-night/waybar.css | 1 - themes/summer-night/waybar.jsonc | 39 ++++++++++------------ 13 files changed, 143 insertions(+), 130 deletions(-) diff --git a/agent/HARDWARE-QUEUE.md b/agent/HARDWARE-QUEUE.md index c9d03c7..61da91b 100644 --- a/agent/HARDWARE-QUEUE.md +++ b/agent/HARDWARE-QUEUE.md @@ -8,6 +8,16 @@ the failure as a NOW bug in BACKLOG.md. Machines: the **AMD dev box** QA machine), the **T14s** (webcam case). ## Any machine (dev box is fine) +- [ ] **Unfree CLI default (2026-07-10)** — after `sys-rebuild` + new + shell/login: `echo $NIXPKGS_ALLOW_UNFREE` → `1`; `nix-shell -p + vscode --run 'code --version'` (or another unfree pkg) succeeds + without a manual export; `cat ~/.config/nixpkgs/config.nix` has + `allowUnfree = true`. (Flake-pure `nix shell nixpkgs#…` still may + need `--impure` — that is expected.) +- [ ] **Waybar icon+percentage spacing (2026-07-10)** — switch to + executive-slate (and spot-check boreal/summer): battery glyph and + capacity% do not collide; volume glyph and volume% do not collide. + Unified clock reads as one module (`HH:MM · Day DD Mon`). - [ ] **Charge-limit live apply (2026-07-10)** — on a laptop with `charge_control_end_threshold`: System › Battery limit → 80%; confirm `cat …/charge_control_end_threshold` is 80 without rebuild; @@ -331,16 +341,16 @@ 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 +- [ ] **Calendar on the unified clock click** (iteration #68 + 2026-07-10 + bar polish) — after `home-update` + relogin: the bar shows **one** + clock module (`HH:MM · Day DD Mon`, not separate date/time modules); + left-click it → calcurse opens in a **floating, centered** ghostty + window (~60×65% of screen); closing calcurse (`q`) closes the window. + calcurse is a bar package (no template line required). 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. + Same on a whole-swap bar (summer/boreal/executive-slate). - [ ] **Screenshot annotation (satty)** (iteration #73) — after `home-update`: hit SUPER+SHIFT+Print (or Tools ▸ Capture ▸ Annotate region) → a region select (slurp) appears, then the `satty` UI opens in fullscreen with the diff --git a/modules/home/default.nix b/modules/home/default.nix index 63553a7..ab70b88 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -66,6 +66,9 @@ home.sessionVariables = { TERMINAL = config.nomarchy.terminal; NIXOS_OZONE_WL = "1"; # Electron/Chromium native Wayland + # Same gate as modules/nixos: CLI nix-shell/shell/run for unfree pkgs + # (system nixpkgs.config alone does not cover those entry points). + NIXPKGS_ALLOW_UNFREE = "1"; # Where the Nomarchy flake (and therefore theme-state.json) lives on # disk. nomarchy-theme-sync writes its state here; rebuilds read from @@ -73,5 +76,12 @@ NOMARCHY_PATH = "$HOME/.nomarchy"; }; + # Classic nix-shell / nix-env read this; pairs with NIXPKGS_ALLOW_UNFREE + # above so "allow unfree" is the default desktop experience, not a + # per-command export the user has to remember. + xdg.configFile."nixpkgs/config.nix".text = '' + { allowUnfree = true; } + ''; + programs.home-manager.enable = true; } diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix index 2bf37bc..de2d27f 100644 --- a/modules/home/waybar.nix +++ b/modules/home/waybar.nix @@ -94,9 +94,9 @@ let # 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. + # calcurse is installed with the bar (home.packages below); the gate is + # only for someone who force-removed it. 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 @@ -200,10 +200,12 @@ let }; clock = { - format = "{:%H:%M}"; + # Single module: time + short date (whole-swaps used to split these + # into clock + clock#date — one click surface for the calendar). + format = "{:%H:%M · %a %d %b}"; # 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. + # ghostty). Long weekday/month name + zone + month grid ride in the + # tooltip so the bar stays compact. on-click = "nomarchy-calendar"; # The zone line stays live under auto-timezone (the tz-watch SIGUSR2 # reload keeps it showing the currently *detected* zone). @@ -218,9 +220,12 @@ let }; pulseaudio = { - format = "{icon} {volume}%"; + # Trailing spaces on icons (not only between span and text): Nerd Font + # glyphs often have tight right bearings and otherwise collide with + # the percentage digits. + format = "{icon} {volume}%"; format-muted = "󰝟"; - format-icons.default = [ "󰕿" "󰖀" "󰕾" ]; + format-icons.default = [ "󰕿 " "󰖀 " "󰕾 " ]; on-click = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; # Right-click → the full mixer (per-app volumes) in a floating window # (item 35). pwvucontrol ships in the template suite; the Hyprland @@ -246,9 +251,10 @@ let battery = { states = { warning = 25; critical = 10; }; + # Same icon-bearing fix as pulseaudio (see format-icons note there). format = "{icon} {capacity}%"; - format-charging = "󰂄 {capacity}%"; - format-icons = [ "󰁺" "󰁼" "󰁾" "󰂀" "󰁹" ]; + format-charging = "󰂄 {capacity}%"; + format-icons = [ "󰁺 " "󰁼 " "󰁾 " "󰂀 " "󰁹 " ]; # Click either the battery or the power-profile icon → the combined # power menu (profile + charge cap). The granular System rows stay. on-click = "nomarchy-menu powermgmt"; @@ -498,7 +504,8 @@ in # The power-profile helpers on PATH, so both the generated bar and the # whole-swap themes' static waybar.jsonc can exec them by name — plus - # the supervisor hyprland.nix exec-onces. + # the supervisor hyprland.nix exec-onces. calcurse is the clock-click + # calendar (feature dependency of the bar, not an opt-in app). home.packages = lib.optionals config.nomarchy.waybar.enable - [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus doctorStatus calendarLauncher ]; + [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus doctorStatus calendarLauncher pkgs.calcurse ]; } diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 672151d..58d978c 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -69,7 +69,11 @@ in # GPU/wifi drivers, firmware, fonts, …). The custom nixpkgs-config # type can't carry a nested mkDefault; disagree with # `nixpkgs.config = lib.mkForce { allowUnfree = false; }`. + # `NIXPKGS_ALLOW_UNFREE` covers CLI `nix-shell` / `nix shell` / + # `nix run` (those ignore the system `nixpkgs.config`); pure flake + # eval still needs `--impure` when the env var is the only gate. nixpkgs.config.allowUnfree = true; + environment.variables.NIXPKGS_ALLOW_UNFREE = "1"; # ── One keyboard layout everywhere, incl. the LUKS prompt ──────── # services.xserver.xkb.layout is the single source of truth for the diff --git a/templates/downstream/home.nix b/templates/downstream/home.nix index e47ef01..c722e49 100644 --- a/templates/downstream/home.nix +++ b/templates/downstream/home.nix @@ -86,7 +86,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 + # calcurse ships with the Waybar clock (modules/home/waybar.nix) # ── More apps — uncomment to add ───────────────────────────────── # Web browsers diff --git a/themes/boreal/waybar.css b/themes/boreal/waybar.css index 2076eb7..08a5a5e 100644 --- a/themes/boreal/waybar.css +++ b/themes/boreal/waybar.css @@ -24,7 +24,9 @@ @define-color bad #E2818A; * { - font-family: "GeistMono Nerd Font", "Symbols Nerd Font"; + /* Mono Nerd face for status glyphs (tight right bearings on the + proportional Symbols face make icon+percentage collide). */ + font-family: "GeistMono Nerd Font", "Symbols Nerd Font Mono"; font-size: 13px; font-weight: 500; border: none; @@ -85,13 +87,12 @@ window#waybar { } #custom-nomarchy:hover { color: @accentAlt; } -/* ── Clock — mono digits align; date recedes to frost-grey ───────────*/ +/* ── Clock — unified time · date ─────────────────────────────────────*/ #clock { color: @text; font-weight: 600; padding-left: 4px; } -#clock.date { color: @subtext; font-weight: 500; } /* ── Workspaces — dots that bloom to an aurora pill when active ───────*/ #workspaces { padding: 0 2px; } diff --git a/themes/boreal/waybar.jsonc b/themes/boreal/waybar.jsonc index 6280ef1..937f621 100644 --- a/themes/boreal/waybar.jsonc +++ b/themes/boreal/waybar.jsonc @@ -10,8 +10,7 @@ "reload_style_on_change": true, "modules-left": [ "custom/nomarchy", - "clock", - "clock#date" + "clock" ], "modules-center": [ "hyprland/workspaces" @@ -38,14 +37,10 @@ "tooltip-format": "Nomarchy menu" }, "clock": { - "format": "{:%H:%M}", + "format": "{:%H:%M · %a %d %b}", "on-click": "nomarchy-calendar", "tooltip": true, - "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" - }, - "clock#date": { - "format": "{:%a %d %b}", - "tooltip": false + "tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n{calendar}" }, "hyprland/workspaces": { "disable-scroll": true, @@ -101,21 +96,21 @@ }, "pulseaudio": { "scroll-step": 5, - "format": "{icon} {volume}%", - "format-bluetooth": "{icon} {volume}%", + "format": "{icon}{volume}%", + "format-bluetooth": "{icon} {volume}%", "format-bluetooth-muted": " {icon}", - "format-muted": " muted", + "format-muted": "muted", "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", + "headphone": " ", + "hands-free": " ", + "headset": " ", + "phone": " ", + "portable": " ", + "car": " ", "default": [ - "", - "", - "" + " ", + " ", + " " ] }, "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", @@ -128,15 +123,15 @@ "warning": 25, "critical": 10 }, - "format": "{icon} {capacity}%", - "format-charging": " {capacity}%", - "format-plugged": " {capacity}%", + "format": "{icon}{capacity}%", + "format-charging": "{capacity}%", + "format-plugged": "{capacity}%", "format-icons": [ - "", - "", - "", - "", - "" + " ", + " ", + " ", + " ", + " " ], "on-click": "nomarchy-menu powermgmt", "tooltip-format": "Battery status" diff --git a/themes/executive-slate/waybar.css b/themes/executive-slate/waybar.css index 52ba94c..6408e72 100644 --- a/themes/executive-slate/waybar.css +++ b/themes/executive-slate/waybar.css @@ -22,7 +22,9 @@ @define-color bad #D06B71; * { - font-family: "Inter", "Symbols Nerd Font", "JetBrainsMono Nerd Font", sans-serif; + /* Mono Nerd face first for status glyphs: proportional "Symbols Nerd + Font" has tight right bearings that make icon+percentage collide. */ + font-family: "Symbols Nerd Font Mono", "Inter", "JetBrainsMono Nerd Font", sans-serif; font-size: 13px; font-weight: 500; border: none; @@ -114,10 +116,11 @@ window#waybar { border-bottom: 2px solid @bad; } -/* ── Clock — time (center) and date (left) share the #clock id ───── */ +/* ── Clock — unified time · date in one module ───────────────────── */ #clock { color: @text; font-weight: 600; + font-family: "Inter", "Symbols Nerd Font Mono", sans-serif; } /* ── Status cluster: neutral by default, semantic on state ───────── */ diff --git a/themes/executive-slate/waybar.jsonc b/themes/executive-slate/waybar.jsonc index 7f5f94d..5a29998 100644 --- a/themes/executive-slate/waybar.jsonc +++ b/themes/executive-slate/waybar.jsonc @@ -10,8 +10,7 @@ "reload_style_on_change": true, "modules-left": [ "custom/nomarchy", - "hyprland/workspaces", - "clock#date" + "hyprland/workspaces" ], "modules-center": [ "clock" @@ -45,14 +44,10 @@ "on-scroll-down": "hyprctl dispatch workspace r-1" }, "clock": { - "format": "{:%H:%M}", + "format": "{:%H:%M · %a %d %b}", "on-click": "nomarchy-calendar", "tooltip": true, - "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" - }, - "clock#date": { - "format": "{:%a %d %b}", - "tooltip": false + "tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n{calendar}" }, "custom/recording": { "return-type": "json", @@ -87,21 +82,21 @@ }, "pulseaudio": { "scroll-step": 5, - "format": "{icon} {volume}%", - "format-bluetooth": "{icon} {volume}%", + "format": "{icon}{volume}%", + "format-bluetooth": "{icon} {volume}%", "format-bluetooth-muted": " {icon}", - "format-muted": " muted", + "format-muted": "muted", "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", + "headphone": " ", + "hands-free": " ", + "headset": " ", + "phone": " ", + "portable": " ", + "car": " ", "default": [ - "", - "", - "" + " ", + " ", + " " ] }, "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", @@ -120,15 +115,15 @@ "warning": 25, "critical": 10 }, - "format": "{icon} {capacity}%", - "format-charging": " {capacity}%", - "format-plugged": " {capacity}%", + "format": "{icon}{capacity}%", + "format-charging": "{capacity}%", + "format-plugged": "{capacity}%", "format-icons": [ - "", - "", - "", - "", - "" + " ", + " ", + " ", + " ", + " " ], "on-click": "nomarchy-menu powermgmt", "tooltip-format": "Battery status" diff --git a/themes/summer-day/waybar.css b/themes/summer-day/waybar.css index 71d2888..6aaa952 100755 --- a/themes/summer-day/waybar.css +++ b/themes/summer-day/waybar.css @@ -48,7 +48,6 @@ window#waybar { #custom-recording, #idle_inhibitor, #clock, -#clock-date, #workspaces, #pulseaudio, #custom-powerprofile, diff --git a/themes/summer-day/waybar.jsonc b/themes/summer-day/waybar.jsonc index caa3b75..9aae8c6 100644 --- a/themes/summer-day/waybar.jsonc +++ b/themes/summer-day/waybar.jsonc @@ -9,7 +9,7 @@ "spacing": 15, "reload_style_on_change": true, - "modules-left": ["custom/launcher", "clock", "clock#date"], + "modules-left": ["custom/launcher", "clock"], "modules-center": ["hyprland/workspaces"], "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/doctor", "custom/notification", "custom/powermenu"], @@ -37,18 +37,18 @@ }, "pulseaudio": { - "format": "{icon} {volume}%", - "format-bluetooth": "{icon}  {volume}%", + "format": "{icon}{volume}%", + "format-bluetooth": "{icon}  {volume}%", "format-bluetooth-muted": "  muted", - "format-muted": " muted", + "format-muted": "muted", "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", - "default": ["", "", ""] + "headphone": " ", + "hands-free": " ", + "headset": " ", + "phone": " ", + "portable": " ", + "car": " ", + "default": [" ", " ", " "] }, "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", "on-click-right": "pwvucontrol", @@ -58,26 +58,21 @@ "battery": { "interval": 60, "states": { "warning": 25, "critical": 10 }, - "max-length": 10, - "format": "{icon} {capacity}%", - "format-charging": " {capacity}%", - "format-plugged": " {capacity}%", - "format-full": " 100%", - "format-icons": ["", "", "", "", ""], + "max-length": 14, + "format": "{icon}{capacity}%", + "format-charging": "{capacity}%", + "format-plugged": "{capacity}%", + "format-full": " 100%", + "format-icons": [" ", " ", " ", " ", " "], "on-click": "nomarchy-menu powermgmt", "tooltip-format": "Battery status" }, "clock": { - "format": " {:%H:%M}", + "format": " {:%H:%M · %a %d %b}", "on-click": "nomarchy-calendar", "tooltip": true, - "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" - }, - - "clock#date": { - "format": " {:%A, %B %d, %Y}", - "tooltip": false + "tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n{calendar}" }, "tray": { "spacing": 8 }, diff --git a/themes/summer-night/waybar.css b/themes/summer-night/waybar.css index f2f9c10..8627b52 100644 --- a/themes/summer-night/waybar.css +++ b/themes/summer-night/waybar.css @@ -53,7 +53,6 @@ window#waybar { #custom-nomarchy, #custom-recording, #clock, -#clock.date, #workspaces, #pulseaudio, #custom-powerprofile, diff --git a/themes/summer-night/waybar.jsonc b/themes/summer-night/waybar.jsonc index 07a0791..7435824 100644 --- a/themes/summer-night/waybar.jsonc +++ b/themes/summer-night/waybar.jsonc @@ -9,7 +9,7 @@ "spacing": 15, "reload_style_on_change": true, - "modules-left": ["custom/nomarchy", "clock", "clock#date"], + "modules-left": ["custom/nomarchy", "clock"], "modules-center": ["hyprland/workspaces"], "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/doctor", "custom/notification", "custom/powermenu"], @@ -38,18 +38,18 @@ "pulseaudio": { "scroll-step": 5, - "format": "{icon} {volume}%", - "format-bluetooth": "{icon} {volume}%", + "format": "{icon}{volume}%", + "format-bluetooth": "{icon} {volume}%", "format-bluetooth-muted": " {icon}", - "format-muted": " muted", + "format-muted": "muted", "format-icons": { - "headphone": "", - "hands-free": "", - "headset": "", - "phone": "", - "portable": "", - "car": "", - "default": ["", "", ""] + "headphone": " ", + "hands-free": " ", + "headset": " ", + "phone": " ", + "portable": " ", + "car": " ", + "default": [" ", " ", " "] }, "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", "on-click-right": "pwvucontrol", @@ -59,24 +59,19 @@ "battery": { "interval": 30, "states": { "warning": 25, "critical": 10 }, - "format": "{icon} {capacity}%", - "format-charging": " {capacity}%", - "format-plugged": " {capacity}%", - "format-icons": ["", "", "", "", ""], + "format": "{icon}{capacity}%", + "format-charging": "{capacity}%", + "format-plugged": "{capacity}%", + "format-icons": [" ", " ", " ", " ", " "], "on-click": "nomarchy-menu powermgmt", "tooltip-format": "Battery status" }, "clock": { - "format": " {:%H:%M}", + "format": " {:%H:%M · %a %d %b}", "on-click": "nomarchy-calendar", "tooltip": true, - "tooltip-format": "{:%Z (UTC%z)}\n{calendar}" - }, - - "clock#date": { - "format": " {:%A, %B %d, %Y}", - "tooltip": false + "tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n{calendar}" }, "tray": { "spacing": 8 },