Files
Nomarchy/modules/home/stylix.nix
Bernardo Magri e8658fea5f
Some checks failed
Check / eval (push) Failing after 1m26s
fix(gtk): tray-menu arrows via USER-priority counter-rule; show menu icons
Two corrections to ac7e6bd, which broke the bar it meant to spare:

1. Scoping the waybar '*' reset to 'window#waybar *' gave every reset
   property id-level specificity, so it started BEATING the later
   class rules (Boreal's pill border-radius/borders, workspace pills)
   that plain '*' correctly lost to — visibly wrecking the bar.
   Reverted all three stylesheets to the plain '*' block (bar restored
   byte-identical to pre-ac7e6bd) and instead restored the arrow where
   priority genuinely outranks waybar's stylesheet: stylix's gtk.css
   loads at USER priority (800) vs waybar's APPLICATION (600), so a
   'menu menuitem arrow { min-width/height: 16px }' there survives the
   reset in Waybar-hosted menus — the exact mechanism the neighbouring
   check/radio rule already uses for the same collapse. NB comments at
   each '*' block warn against re-scoping.

2. The 'missing icons' were never just arrows: GTK3 ships
   gtk-menu-images=false since 3.10, so image menu items (nm-applet's
   Wi-Fi list, udiskie) render iconless everywhere. Set
   gtk.gtk3.extraConfig.gtk-menu-images = 1 (merges into the
   settings.ini Stylix already writes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 08:01:01 +01:00

162 lines
6.3 KiB
Nix

# Stylix — themes the long tail of applications (GTK, Qt, cursors,
# fonts) from the same theme-state.json that drives the live engine.
#
# Division of labour: the hot-reload trio (Hyprland, Waybar, Ghostty)
# is owned by the Nomarchy engine and updates instantly; everything
# Stylix touches updates on the next home-manager switch. That is why
# autoEnable is off and the trio's Stylix targets stay disabled.
#
# Note: the stylix home module itself is imported by homeModules.nomarchy
# in flake.nix (it needs the stylix flake input).
{ config, lib, pkgs, ... }:
let
cfg = config.nomarchy;
t = cfg.theme;
c = t.colors;
hex = lib.removePrefix "#";
# Map the Nomarchy palette onto base16 roles.
base16 = {
base00 = hex c.base; # default background
base01 = hex c.mantle; # darker background (status bars)
base02 = hex c.surface; # selection background
base03 = hex c.muted; # comments
base04 = hex c.subtext; # dark foreground
base05 = hex c.text; # default foreground
base06 = hex c.text; # light foreground
base07 = hex c.text; # lightest foreground
base08 = hex c.bad; # red
base09 = hex c.warn; # orange
base0A = hex c.warn; # yellow
base0B = hex c.good; # green
base0C = hex (builtins.elemAt t.ansi 6); # cyan
base0D = hex c.accent; # blue
base0E = hex c.accentAlt;# magenta
base0F = hex c.bad; # brown/deprecated
};
in
{
config = lib.mkIf cfg.stylix.enable {
stylix = {
enable = true;
autoEnable = false; # explicit targets only — the engine owns the rest
polarity = if t.mode == "light" then "light" else "dark";
base16Scheme = base16;
targets = {
gtk = {
enable = true;
# nm-applet / classic GTK menus: Stylix base16 selection can
# collapse into surface/muted on dark themes (Boreal: selected
# row and submenu arrows were effectively invisible). High-
# contrast selected rows + explicit arrow colour. Appended to
# Stylix's generated gtk.css (not gtk.gtk3.extraCss — that is a
# no-op under Stylix).
extraCss = ''
menu menuitem, .menu menuitem, .context-menu menuitem {
color: #${base16.base05};
}
menu menuitem:hover, menu menuitem:selected,
.menu menuitem:hover, .menu menuitem:selected,
.context-menu menuitem:hover, .context-menu menuitem:selected,
menubar > menuitem:hover {
background-color: #${base16.base0D};
color: #${base16.base00};
}
menu menuitem:disabled, .menu menuitem:disabled {
color: #${base16.base03};
}
/* Submenu disclosure arrows need no icon remap: pan-end-symbolic
resolves via Papirus-Dark's breeze-dark inheritance. The
"invisible arrow" bug is Waybar's process-wide stylesheet:
its `* { min-height: 0; }` reset also hits the SNI tray menus
Waybar hosts and collapses the arrow node. This file loads at
USER priority (~/.config/gtk-3.0/gtk.css), which outranks any
waybar.css (APPLICATION priority) restore the arrow's box
here, exactly like the check/radio rule below already does
for the same collapse. */
menu menuitem arrow, .menu menuitem arrow, .context-menu menuitem arrow {
min-width: 16px;
min-height: 16px;
}
check, radio {
min-width: 14px;
min-height: 14px;
color: inherit;
}
/* GTK4 / popover menus (some portals). */
popover.menu contents modelbutton {
color: #${base16.base05};
}
popover.menu contents modelbutton:hover,
popover.menu contents modelbutton:selected {
background-color: #${base16.base0D};
color: #${base16.base00};
}
'';
};
qt.enable = true;
# No-op unless programs.zathura is on (viewers.nix enables it).
zathura.enable = true;
};
cursor = {
name = lib.mkDefault "Bibata-Modern-Classic";
package = lib.mkDefault pkgs.bibata-cursors;
size = lib.mkDefault 24;
};
# GTK/file-manager/rofi icon theme, resolved from the JSON in
# theme.nix (per-theme `icons`, else Papirus-Dark/Light by mode).
# Stylix sets gtk.iconTheme from this; both dark/light point at the
# already-mode-resolved name. The package is papirus by default and
# only unions in another pack when a theme's `icons` names one
# (theme.nix — opt-in, no default closure bloat).
icons = {
enable = true;
package = lib.mkDefault t.iconThemePackage;
dark = t.iconTheme;
light = t.iconTheme;
};
fonts = {
monospace = {
name = t.fonts.mono;
package = lib.mkDefault pkgs.nerd-fonts.jetbrains-mono;
};
sansSerif = {
name = t.fonts.ui;
package = lib.mkDefault pkgs.inter;
};
serif = {
name = t.fonts.ui;
package = lib.mkDefault pkgs.inter;
};
emoji = {
name = "Noto Color Emoji";
package = lib.mkDefault pkgs.noto-fonts-color-emoji;
};
sizes.terminal = t.fonts.size;
};
};
# GTK3 hides menu-item icons by default (gtk-menu-images was flipped
# off upstream in 3.10). Classic tray menus — nm-applet's Wi-Fi list,
# udiskie — are built as image menu items, so without this their icons
# silently vanish. Stylix drives the HM gtk module, so extraConfig
# merges into the same settings.ini it already writes.
gtk.gtk3.extraConfig."gtk-menu-images" = 1;
# GTK4/libadwaita and Qt6 apps decide dark vs light from the XDG
# portal's color-scheme (org.freedesktop.appearance), which
# xdg-desktop-portal-gtk sources from this gsettings key. Stylix sets
# the GTK theme and `polarity` but not this, so a light theme still
# rendered libadwaita/Qt apps dark (and vice-versa). Drive it from the
# palette mode. (programs.dconf.enable is already on system-side.)
dconf.settings."org/gnome/desktop/interface".color-scheme =
if t.mode == "light" then "prefer-light" else "prefer-dark";
};
}