feat(desktop): dark fuzzel, curated launcher, dmenu power menu

Fuzzel ignores the portal color-scheme, so set its palette explicitly to
match waybar. Hide non-launcher `.desktop` entries (foot variants, mpv/
umpv, zathura, nvim) via `noDisplay` shadows. Replace the per-action
app-list power entries with a `$mod+Backspace` `fuzzel --dmenu` power
menu (Log Out / Reboot / Shut Down), colored Papirus icons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 20:36:52 +02:00
parent b2fabbc764
commit 7b44fe8bf1
+73 -2
View File
@@ -3,7 +3,7 @@
# user.name/email), host topology (SSH hosts, Syncthing peers) and personal app
# choices (grayjay, Claude Code, …) live in the inventory, not in this module.
{ config, pkgs, ... }:
{ config, pkgs, lib, ... }:
let
terminal = "foot";
@@ -50,6 +50,25 @@ let
${pkgs.libnotify}/bin/notify-send "Screenshot" "Saved $file"
fi
'';
# Session/power menu: a fuzzel --dmenu picker (not app-list entries), bound to
# $mod+Backspace. --index returns the chosen row number, so dispatch matches on
# position, not label text. Icons use the Papirus names via fuzzel's dmenu
# icon protocol (NUL + 0x1f after each label). Escape/no pick → fuzzel exits
# non-zero, command substitution is empty, case falls through → no-op.
#
# Icon names deliberately picked from Papirus's apps/ (colored) set that have
# NO actions/ variant: system-{reboot,shutdown,log-out} exist in both, and at
# dmenu line-height fuzzel resolves the monochrome actions/ copy. gnome-logout
# / system-restart / gnome-session-halt are apps-only, so they stay colored.
powerMenu = pkgs.writeShellScript "power-menu" ''
case $(printf 'Log Out\0icon\x1fgnome-logout\nReboot\0icon\x1fsystem-restart\nShut Down\0icon\x1fgnome-session-halt\n' \
| ${pkgs.fuzzel}/bin/fuzzel --dmenu --index --prompt 'power ') in
0) ${config.wayland.windowManager.hyprland.finalPackage}/bin/hyprctl dispatch exit ;;
1) ${pkgs.systemd}/bin/systemctl reboot ;;
2) ${pkgs.systemd}/bin/systemctl poweroff ;;
esac
'';
in
{
imports = [ ./gpg.nix ./media.nix ];
@@ -94,6 +113,8 @@ in
home.packages = with pkgs; [
librewolf
keepassxc # config in ~/.config/keepassxc
papirus-icon-theme # fuzzel icon-theme; ships non-symbolic power icons
# (Adwaita only has them as symbolic, which fuzzel skips)
# claude-code is installed by programs.claude-code below (its wrapped
# finalPackage) — do NOT also list it here, or buildEnv conflicts on the
# wrapper binary.
@@ -205,7 +226,56 @@ in
# so their stderr goes to the journal, not whatever terminal you're in.
programs.fuzzel = {
enable = true;
settings.main.font = "JetBrainsMono Nerd Font:size=11";
settings = {
main.font = "JetBrainsMono Nerd Font:size=11";
# Papirus for colored power icons in the $mod+Backspace dmenu (Adwaita
# ships those only as symbolic, and fuzzel skips symbolic dirs). It
# inherits hicolor, so app icons still resolve (recolored to Papirus).
main.icon-theme = "Papirus";
# Fuzzel ignores the portal color-scheme, and its built-in palette is
# light — dark has to be set here. Matches waybar (#222/#bbb + One Dark
# accents); flat, thin border, no rounding per the minimal look.
border = { width = 1; radius = 0; };
colors = {
background = "222222f2";
text = "bbbbbbff";
match = "e5c07bff";
selection = "333333ff";
selection-text = "ffffffff";
selection-match = "e5c07bff";
border = "444444ff";
};
};
};
# Curate what fuzzel's app-list mode shows. Fuzzel just enumerates XDG
# `.desktop` files, so we shape that set here. Shadow a package's entry by
# redefining its id with noDisplay = true: our ~/.local/share/applications
# copy wins over the profile's. noDisplay only hides from launchers/menus —
# the app stays wired up for xdg-open and "open with", so opening a file
# *with* mpv/zathura is unaffected. The attrset merges with anything a private
# host adds. noDisplay is mkDefault so a host can un-hide one (e.g. re-expose
# mpv) with a plain override, no conflict. (Power/session actions are not
# entries here — see the $mod+Backspace dmenu power menu above.)
xdg.desktopEntries = let
hide = exec: {
inherit exec;
name = "hidden";
noDisplay = lib.mkDefault true;
};
in {
# foot's three entries: launched via $mod+Return, never from a menu.
foot = hide "foot";
foot-server = hide "foot --server";
footclient = hide "footclient";
# mpv/zathura are file handlers, not things to launch bare from a menu.
mpv = hide "mpv %U";
umpv = hide "umpv %U";
"org.pwmt.zathura" = hide "zathura %U";
"org.pwmt.zathura-djvu" = hide "zathura %U";
"org.pwmt.zathura-cb" = hide "zathura %U";
# nvim is $EDITOR / opened from a terminal; no place in a GUI launcher.
nvim = hide "nvim %F";
};
programs.fzf.enable = true; # provides the ^f "cd into fzf dir" binding
@@ -413,6 +483,7 @@ in
"$mod SHIFT, f, fullscreen, 0"
"$mod, w, exec, ${browser}"
"$mod, d, exec, fuzzel"
"$mod, Backspace, exec, ${powerMenu}"
"$mod, j, layoutmsg, cyclenext"
"$mod SHIFT, j, layoutmsg, swapnext"
"$mod, k, layoutmsg, cycleprev"