fix(desktop): unfree CLI default, bar icon spacing, unified clock
All checks were successful
Check / eval (push) Successful in 3m0s

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).
This commit is contained in:
2026-07-10 12:58:37 +01:00
parent eb951569cf
commit d547393e7b
13 changed files with 143 additions and 130 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 = "<span size='${toString (t.fonts.size + 2)}pt'>{icon}</span> {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 = "<span size='${toString (t.fonts.size + 2)}pt'>{icon}</span> {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 = "<span size='${toString (t.fonts.size + 2)}pt'>{icon}</span> {capacity}%";
format-charging = "<span size='${toString (t.fonts.size + 2)}pt'>󰂄</span> {capacity}%";
format-icons = [ "󰁺" "󰁼" "󰁾" "󰂀" "󰁹" ];
format-charging = "<span size='${toString (t.fonts.size + 2)}pt'>󰂄 </span>{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 ];
}

View File

@@ -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

View File

@@ -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

View File

@@ -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; }

View File

@@ -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<tt><small>{calendar}</small></tt>"
},
"clock#date": {
"format": "{:%a %d %b}",
"tooltip": false
"tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n<tt><small>{calendar}</small></tt>"
},
"hyprland/workspaces": {
"disable-scroll": true,
@@ -101,21 +96,21 @@
},
"pulseaudio": {
"scroll-step": 5,
"format": "<span size='13pt'>{icon}</span> {volume}%",
"format-bluetooth": "<span size='13pt'>{icon}</span> {volume}%",
"format": "<span size='13pt'>{icon}</span>{volume}%",
"format-bluetooth": "<span size='13pt'>{icon} </span>{volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": "<span size='13pt'></span> muted",
"format-muted": "<span size='13pt'> </span>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": "<span size='13pt'>{icon}</span> {capacity}%",
"format-charging": "<span size='13pt'></span> {capacity}%",
"format-plugged": "<span size='13pt'></span> {capacity}%",
"format": "<span size='13pt'>{icon}</span>{capacity}%",
"format-charging": "<span size='13pt'> </span>{capacity}%",
"format-plugged": "<span size='13pt'> </span>{capacity}%",
"format-icons": [
"",
"",
"",
"",
""
" ",
" ",
" ",
" ",
" "
],
"on-click": "nomarchy-menu powermgmt",
"tooltip-format": "Battery status"

View File

@@ -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 ───────── */

View File

@@ -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<tt><small>{calendar}</small></tt>"
},
"clock#date": {
"format": "{:%a %d %b}",
"tooltip": false
"tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n<tt><small>{calendar}</small></tt>"
},
"custom/recording": {
"return-type": "json",
@@ -87,21 +82,21 @@
},
"pulseaudio": {
"scroll-step": 5,
"format": "<span size='13pt'>{icon}</span> {volume}%",
"format-bluetooth": "<span size='13pt'>{icon}</span> {volume}%",
"format": "<span size='13pt'>{icon}</span>{volume}%",
"format-bluetooth": "<span size='13pt'>{icon} </span>{volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": "<span size='13pt'></span> muted",
"format-muted": "<span size='13pt'> </span>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": "<span size='13pt'>{icon}</span> {capacity}%",
"format-charging": "<span size='13pt'></span> {capacity}%",
"format-plugged": "<span size='13pt'></span> {capacity}%",
"format": "<span size='13pt'>{icon}</span>{capacity}%",
"format-charging": "<span size='13pt'> </span>{capacity}%",
"format-plugged": "<span size='13pt'> </span>{capacity}%",
"format-icons": [
"",
"",
"",
"",
""
" ",
" ",
" ",
" ",
" "
],
"on-click": "nomarchy-menu powermgmt",
"tooltip-format": "Battery status"

View File

@@ -48,7 +48,6 @@ window#waybar {
#custom-recording,
#idle_inhibitor,
#clock,
#clock-date,
#workspaces,
#pulseaudio,
#custom-powerprofile,

View File

@@ -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": "<span size='13pt'>{icon}</span> {volume}%",
"format-bluetooth": "<span size='13pt'>{icon} </span> {volume}%",
"format": "<span size='13pt'>{icon}</span>{volume}%",
"format-bluetooth": "<span size='13pt'>{icon}  </span>{volume}%",
"format-bluetooth-muted": "  muted",
"format-muted": "<span size='13pt'></span> muted",
"format-muted": "<span size='13pt'> </span>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": "<span size='13pt'>{icon}</span> {capacity}%",
"format-charging": "<span size='13pt'></span> {capacity}%",
"format-plugged": "<span size='13pt'></span> {capacity}%",
"format-full": " 100%",
"format-icons": ["", "", "", "", ""],
"max-length": 14,
"format": "<span size='13pt'>{icon}</span>{capacity}%",
"format-charging": "<span size='13pt'> </span>{capacity}%",
"format-plugged": "<span size='13pt'> </span>{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<tt><small>{calendar}</small></tt>"
},
"clock#date": {
"format": " {:%A, %B %d, %Y}",
"tooltip": false
"tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n<tt><small>{calendar}</small></tt>"
},
"tray": { "spacing": 8 },

View File

@@ -53,7 +53,6 @@ window#waybar {
#custom-nomarchy,
#custom-recording,
#clock,
#clock.date,
#workspaces,
#pulseaudio,
#custom-powerprofile,

View File

@@ -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": "<span size='13pt'>{icon}</span> {volume}%",
"format-bluetooth": "<span size='13pt'>{icon}</span> {volume}%",
"format": "<span size='13pt'>{icon}</span>{volume}%",
"format-bluetooth": "<span size='13pt'>{icon} </span>{volume}%",
"format-bluetooth-muted": " {icon}",
"format-muted": "<span size='13pt'></span> muted",
"format-muted": "<span size='13pt'> </span>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": "<span size='13pt'>{icon}</span> {capacity}%",
"format-charging": "<span size='13pt'></span> {capacity}%",
"format-plugged": "<span size='13pt'></span> {capacity}%",
"format-icons": ["", "", "", "", ""],
"format": "<span size='13pt'>{icon}</span>{capacity}%",
"format-charging": "<span size='13pt'> </span>{capacity}%",
"format-plugged": "<span size='13pt'> </span>{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<tt><small>{calendar}</small></tt>"
},
"clock#date": {
"format": " {:%A, %B %d, %Y}",
"tooltip": false
"tooltip-format": "{:%A %d %B %Y}\n{:%Z (UTC%z)}\n<tt><small>{calendar}</small></tt>"
},
"tray": { "spacing": 8 },