feat(home): menu system, swaync, idle/lock, nm-applet, theme parity
- Themed fuzzel (modules/home/fuzzel.nix): palette/fonts/border from the
JSON, themes/<slug>/fuzzel.ini whole-swap mechanism. Plus the
nomarchy-menu dispatcher: root picker · power (SUPER+Escape) · theme
(SUPER+T) · clipboard (SUPER+CTRL+V, cliphist) · calc (qalc) · files
(fd→xdg-open) · web (DuckDuckGo).
- swaync notifications themed from the JSON (SUPER+N) — until now nothing
rendered notify-send (theme toasts, font warnings, welcome msg).
- hyprlock + hypridle (modules/home/idle.nix): lock 5min, dpms off 10,
suspend 30; enables the power menu's Lock entry. cliphist daemon on.
- NetworkManager applet in waybar's tray (preferStatusNotifierItems);
network module on-click → $TERMINAL -e nmtui.
- nomarchy.keyboard.layout/.variant option → Hyprland kb_layout/kb_variant
(the installer writes it; pairs with system-side xkb for tty/LUKS).
- Media-key/audio on-click moved to wpctl (pamixer was inconsistent).
- Theme parity: summer-day/night carry their legacy bar LAYOUTS as
waybar.jsonc whole-swaps (the original import took waybar.css but not
config.jsonc, so identity themes styled nonexistent modules). Dead
legacy script-modules dropped, Nerd-Fonts-v2 codepoints → FontAwesome/v3
(font-awesome now shipped), logo buttons open nomarchy-menu.
New toggles: nomarchy.{fuzzel,swaync,idle}.enable (all default true).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,20 @@
|
|||||||
./waybar.nix
|
./waybar.nix
|
||||||
./ghostty.nix
|
./ghostty.nix
|
||||||
./btop.nix
|
./btop.nix
|
||||||
|
./fuzzel.nix # launcher theming + the nomarchy-menu dispatcher
|
||||||
|
./swaync.nix # notification daemon, themed from the same JSON
|
||||||
|
./idle.nix # hyprlock + hypridle, themed from the same JSON
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Clipboard history (wl-paste watcher); browsed via the SUPER+CTRL+V
|
||||||
|
# menu module.
|
||||||
|
services.cliphist.enable = true;
|
||||||
|
|
||||||
|
# Wifi from the bar: nm-applet lives in waybar's tray (SNI flag via
|
||||||
|
# preferStatusNotifierItems — without it there is no tray icon).
|
||||||
|
services.network-manager-applet.enable = true;
|
||||||
|
xsession.preferStatusNotifierItems = true;
|
||||||
|
|
||||||
home.stateVersion = "26.05";
|
home.stateVersion = "26.05";
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
# Fuzzel — launcher, dmenu renderer for the menu system, themed from
|
# Fuzzel — launcher, dmenu renderer for the menu system, themed from
|
||||||
# theme-state.json like every other surface. Also home of nomarchy-menu,
|
# theme-state.json like every other surface. Also home of nomarchy-menu,
|
||||||
# the dispatcher script the menu roadmap grows out of (first module:
|
# the dispatcher script all menu modules grow out of.
|
||||||
# power).
|
#
|
||||||
|
# Per-theme identity: themes/<slug>/fuzzel.ini is a whole-swap (like
|
||||||
|
# waybar.css) — it replaces the generated config entirely, probed at
|
||||||
|
# eval time.
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
@@ -9,43 +12,125 @@ let
|
|||||||
t = cfg.theme;
|
t = cfg.theme;
|
||||||
c = t.colors;
|
c = t.colors;
|
||||||
|
|
||||||
|
# Per-theme override probe (same convention as waybar.nix).
|
||||||
|
iniOverride = cfg.themesDir + "/${t.slug}/fuzzel.ini";
|
||||||
|
hasIniOverride = builtins.pathExists iniOverride;
|
||||||
|
|
||||||
# fuzzel.ini colors are rrggbbaa, no leading #.
|
# fuzzel.ini colors are rrggbbaa, no leading #.
|
||||||
hexa = color: alpha: "${lib.removePrefix "#" color}${alpha}";
|
hexa = color: alpha: "${lib.removePrefix "#" color}${alpha}";
|
||||||
|
|
||||||
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
||||||
# Nomarchy menu dispatcher — thin presentation layer over
|
# Nomarchy menu dispatcher — thin presentation layer over
|
||||||
# `fuzzel --dmenu`; actions delegate to systemctl/hyprctl/
|
# `fuzzel --dmenu`; actions delegate to nomarchy-theme-sync,
|
||||||
# nomarchy-theme-sync. The icons are nf-md glyphs (any shipped
|
# systemctl, hyprctl and friends. Icons are nf-md glyphs (any
|
||||||
# Nerd Font carries them).
|
# shipped Nerd Font carries them). `nomarchy-menu` with no
|
||||||
|
# argument shows the module picker.
|
||||||
|
|
||||||
|
urlencode() {
|
||||||
|
local s="$1" out="" ch
|
||||||
|
for ((i = 0; i < ''${#s}; i++)); do
|
||||||
|
ch=''${s:i:1}
|
||||||
|
case "$ch" in
|
||||||
|
[a-zA-Z0-9.~_-]) out+="$ch" ;;
|
||||||
|
' ') out+="+" ;;
|
||||||
|
*) printf -v ch '%%%02X' "'$ch"; out+="$ch" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
case "''${1:-}" in
|
case "''${1:-}" in
|
||||||
power)
|
power)
|
||||||
choice=$(printf '%s\n' \
|
choice=$(printf '%s\n' \
|
||||||
|
" Lock" \
|
||||||
" Logout" \
|
" Logout" \
|
||||||
" Suspend" \
|
" Suspend" \
|
||||||
" Hibernate" \
|
" Hibernate" \
|
||||||
" Reboot" \
|
" Reboot" \
|
||||||
" Shutdown" \
|
" Shutdown" \
|
||||||
| fuzzel --dmenu --prompt "power " --lines 5 --width 24) || exit 0
|
| fuzzel --dmenu --prompt "power " --lines 6 --width 24) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
|
*Lock) loginctl lock-session ;;
|
||||||
*Logout) hyprctl dispatch exit ;;
|
*Logout) hyprctl dispatch exit ;;
|
||||||
*Suspend) systemctl suspend ;;
|
*Suspend) systemctl suspend ;;
|
||||||
*Hibernate) systemctl hibernate ;;
|
*Hibernate) systemctl hibernate ;;
|
||||||
*Reboot) systemctl reboot ;;
|
*Reboot) systemctl reboot ;;
|
||||||
*Shutdown) systemctl poweroff ;;
|
*Shutdown) systemctl poweroff ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
|
|
||||||
|
theme)
|
||||||
|
choice=$(nomarchy-theme-sync list \
|
||||||
|
| fuzzel --dmenu --prompt "theme ") || exit 0
|
||||||
|
[ -n "$choice" ] && exec nomarchy-theme-sync apply "$choice" ;;
|
||||||
|
|
||||||
|
clipboard)
|
||||||
|
sel=$(cliphist list | fuzzel --dmenu --prompt "clip " --width 60) || exit 0
|
||||||
|
printf '%s' "$sel" | cliphist decode | wl-copy ;;
|
||||||
|
|
||||||
|
calc)
|
||||||
|
expr=$(fuzzel --prompt-only "= ") || exit 0
|
||||||
|
[ -n "$expr" ] || exit 0
|
||||||
|
result=$(qalc -t -- "$expr" 2>&1 | tail -n 1)
|
||||||
|
choice=$(printf '%s\n' " Copy result" " New calculation" \
|
||||||
|
| fuzzel --dmenu --lines 2 --width 40 \
|
||||||
|
--prompt "= " --mesg "$expr = $result") || exit 0
|
||||||
|
case "$choice" in
|
||||||
|
*Copy*) printf '%s' "$result" | wl-copy ;;
|
||||||
|
*New*) exec "$0" calc ;;
|
||||||
|
esac ;;
|
||||||
|
|
||||||
|
files)
|
||||||
|
sel=$(fd . "$HOME" --type f --hidden --exclude .git --exclude .cache 2>/dev/null \
|
||||||
|
| head -n 50000 \
|
||||||
|
| sed "s|^$HOME/||" \
|
||||||
|
| fuzzel --dmenu --prompt "file " --width 60) || exit 0
|
||||||
|
[ -n "$sel" ] && exec xdg-open "$HOME/$sel" ;;
|
||||||
|
|
||||||
|
web)
|
||||||
|
q=$(fuzzel --prompt-only "search ") || exit 0
|
||||||
|
[ -n "$q" ] || exit 0
|
||||||
|
exec xdg-open "https://duckduckgo.com/?q=$(urlencode "$q")" ;;
|
||||||
|
|
||||||
|
"")
|
||||||
|
choice=$(printf '%s\n' \
|
||||||
|
" Apps" \
|
||||||
|
" Theme" \
|
||||||
|
" Clipboard" \
|
||||||
|
" Calculator" \
|
||||||
|
" Files" \
|
||||||
|
" Web search" \
|
||||||
|
" Power" \
|
||||||
|
| fuzzel --dmenu --prompt "menu " --lines 7 --width 24) || exit 0
|
||||||
|
case "$choice" in
|
||||||
|
*Apps*) exec fuzzel ;;
|
||||||
|
*Theme*) exec "$0" theme ;;
|
||||||
|
*Clipboard*) exec "$0" clipboard ;;
|
||||||
|
*Calc*) exec "$0" calc ;;
|
||||||
|
*Files*) exec "$0" files ;;
|
||||||
|
*Web*) exec "$0" web ;;
|
||||||
|
*Power*) exec "$0" power ;;
|
||||||
|
esac ;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "usage: nomarchy-menu power" >&2
|
echo "usage: nomarchy-menu [power|theme|clipboard|calc|files|web]" >&2
|
||||||
exit 64 ;;
|
exit 64 ;;
|
||||||
esac
|
esac
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf cfg.fuzzel.enable {
|
config = lib.mkIf cfg.fuzzel.enable {
|
||||||
home.packages = [ nomarchy-menu ];
|
home.packages = [
|
||||||
|
nomarchy-menu
|
||||||
|
pkgs.libqalculate # qalc, the calc module's engine
|
||||||
|
pkgs.fd # files module
|
||||||
|
pkgs.xdg-utils # xdg-open for files/web
|
||||||
|
];
|
||||||
|
|
||||||
programs.fuzzel = {
|
programs.fuzzel = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
# Whole-swap themes bring their own fuzzel.ini; otherwise the
|
||||||
|
# config is generated from the palette.
|
||||||
|
settings = lib.mkIf (!hasIniOverride) {
|
||||||
main = {
|
main = {
|
||||||
# UI font first; the mono Nerd Font follows so menu icons
|
# UI font first; the mono Nerd Font follows so menu icons
|
||||||
# (nf-md glyphs) resolve — fcft falls back per glyph.
|
# (nf-md glyphs) resolve — fcft falls back per glyph.
|
||||||
@@ -78,5 +163,9 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.configFile."fuzzel/fuzzel.ini" = lib.mkIf hasIniOverride {
|
||||||
|
source = iniOverride;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ in
|
|||||||
|
|
||||||
# ── Behaviour ──────────────────────────────────────────────────
|
# ── Behaviour ──────────────────────────────────────────────────
|
||||||
input = {
|
input = {
|
||||||
kb_layout = "us";
|
kb_layout = config.nomarchy.keyboard.layout;
|
||||||
|
kb_variant = config.nomarchy.keyboard.variant;
|
||||||
follow_mouse = 1;
|
follow_mouse = 1;
|
||||||
touchpad.natural_scroll = true;
|
touchpad.natural_scroll = true;
|
||||||
};
|
};
|
||||||
@@ -120,12 +121,21 @@ in
|
|||||||
"$mod, V, togglefloating"
|
"$mod, V, togglefloating"
|
||||||
"$mod SHIFT, E, exit"
|
"$mod SHIFT, E, exit"
|
||||||
|
|
||||||
# Theme picker: fuzzel menu over the presets; apply writes the
|
# Theme picker (menu dispatcher): apply writes the state and
|
||||||
# state and runs home-manager switch (progress via notify-send).
|
# runs home-manager switch (progress via notify-send).
|
||||||
"$mod, T, exec, nomarchy-theme-sync apply \"$(nomarchy-theme-sync list | fuzzel --dmenu --prompt 'theme> ')\""
|
"$mod, T, exec, nomarchy-menu theme"
|
||||||
# Cycle the current theme's wallpapers (instant, no rebuild).
|
# Cycle the current theme's wallpapers (instant, no rebuild).
|
||||||
"$mod SHIFT, T, exec, nomarchy-theme-sync bg next"
|
"$mod SHIFT, T, exec, nomarchy-theme-sync bg next"
|
||||||
|
|
||||||
|
# Power menu (fuzzel dmenu via the nomarchy-menu dispatcher).
|
||||||
|
"$mod, Escape, exec, nomarchy-menu power"
|
||||||
|
|
||||||
|
# Notification centre (swaync).
|
||||||
|
"$mod, N, exec, swaync-client -t"
|
||||||
|
|
||||||
|
# Clipboard history (cliphist via the menu dispatcher).
|
||||||
|
"$mod CTRL, V, exec, nomarchy-menu clipboard"
|
||||||
|
|
||||||
# Focus
|
# Focus
|
||||||
"$mod, H, movefocus, l"
|
"$mod, H, movefocus, l"
|
||||||
"$mod, L, movefocus, r"
|
"$mod, L, movefocus, r"
|
||||||
|
|||||||
@@ -23,6 +23,25 @@
|
|||||||
description = "Terminal emulator command, used by keybinds and $TERMINAL.";
|
description = "Terminal emulator command, used by keybinds and $TERMINAL.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
keyboard.layout = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "us";
|
||||||
|
example = "de";
|
||||||
|
description = ''
|
||||||
|
XKB layout for the Hyprland session. The console (and the LUKS
|
||||||
|
passphrase prompt) take theirs from the system side — the
|
||||||
|
installer writes services.xserver.xkb + console.useXkbConfig
|
||||||
|
into system.nix with the same value.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keyboard.variant = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
example = "nodeadkeys";
|
||||||
|
description = "XKB variant for the Hyprland session.";
|
||||||
|
};
|
||||||
|
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
default = pkgs.nomarchy-theme-sync;
|
default = pkgs.nomarchy-theme-sync;
|
||||||
@@ -44,6 +63,9 @@
|
|||||||
# ── Component toggles ──────────────────────────────────────────
|
# ── Component toggles ──────────────────────────────────────────
|
||||||
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
||||||
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar configuration" // { default = true; };
|
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar configuration" // { default = true; };
|
||||||
|
fuzzel.enable = lib.mkEnableOption "Nomarchy's themed fuzzel + the nomarchy-menu dispatcher (power menu)" // { default = true; };
|
||||||
|
swaync.enable = lib.mkEnableOption "swaync notifications, themed from the state file" // { default = true; };
|
||||||
|
idle.enable = lib.mkEnableOption "hyprlock + hypridle (idle lock, display off, suspend)" // { default = true; };
|
||||||
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
||||||
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
|
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
|
||||||
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
|
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ let
|
|||||||
format = "{icon} {volume}%";
|
format = "{icon} {volume}%";
|
||||||
format-muted = "";
|
format-muted = "";
|
||||||
format-icons.default = [ "" "" "" ];
|
format-icons.default = [ "" "" "" ];
|
||||||
on-click = "pamixer -t";
|
on-click = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
|
||||||
};
|
};
|
||||||
|
|
||||||
network = {
|
network = {
|
||||||
@@ -68,6 +68,9 @@ let
|
|||||||
format-ethernet = "";
|
format-ethernet = "";
|
||||||
format-disconnected = "";
|
format-disconnected = "";
|
||||||
tooltip-format = "{ipaddr} via {gwaddr}";
|
tooltip-format = "{ipaddr} via {gwaddr}";
|
||||||
|
# nm-applet sits in the tray for the GUI path; this is the
|
||||||
|
# keyboard-friendly one.
|
||||||
|
on-click = "${config.nomarchy.terminal} -e nmtui";
|
||||||
};
|
};
|
||||||
|
|
||||||
cpu.format = " {usage}%";
|
cpu.format = " {usage}%";
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ window#waybar {
|
|||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
#network,
|
#network,
|
||||||
#battery,
|
#battery,
|
||||||
|
#tray,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ window#waybar {
|
|||||||
#clock.date,
|
#clock.date,
|
||||||
#workspaces,
|
#workspaces,
|
||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
|
#network,
|
||||||
#idle_inhibitor,
|
#idle_inhibitor,
|
||||||
#custom-battery,
|
#battery,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
@@ -98,7 +99,6 @@ window#waybar {
|
|||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 21px;
|
padding-right: 21px;
|
||||||
font-family: Nomarchy;
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ window#waybar {
|
|||||||
padding-right: 23px;
|
padding-right: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-battery.preservation {
|
#battery.charging {
|
||||||
color: @green;
|
color: @green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user