{ config, pkgs, lib, inputs, ... }: { # Imported for all hosts via flake.nix. config = { stylix = { enable = true; # builtins.path hashes only the image content, not the whole flake tree, # so palette.json is only rebuilt when the wallpaper itself changes. image = builtins.path { name = "wallpaper.png"; path = inputs.self + "/walls/wallpaper.png"; }; polarity = "dark"; # Let stylix theme every target it supports. Per-target opt-outs go # under home-manager.users.fred.stylix.targets..enable = false. autoEnable = true; cursor = { package = pkgs.bibata-cursors; name = "Bibata-Modern-Ice"; size = 24; }; # caelestia's font set: Rubik for UI text, CaskaydiaCove NF for mono # (still a nerd font, so terminal glyphs survive the swap). fonts = { monospace = { package = pkgs.nerd-fonts.caskaydia-cove; name = "CaskaydiaCove NF"; }; sansSerif = { package = pkgs.rubik; name = "Rubik"; }; serif = { package = pkgs.rubik; name = "Rubik"; }; }; }; home-manager.users.fred = { config, lib, pkgs, osConfig, ... }: let isDesktop = lib.elem osConfig.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]; c = config.lib.stylix.colors; # Pure-Nix hex parsing for color distance calculation. hexDigit = ch: { "0"=0;"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7; "8"=8;"9"=9;"a"=10;"b"=11;"c"=12;"d"=13;"e"=14;"f"=15; }.${ch}; hexByte = s: hexDigit (builtins.substring 0 1 s) * 16 + hexDigit (builtins.substring 1 1 s); hexToRgb = hex: let h = lib.toLower hex; in { r = hexByte (builtins.substring 0 2 h); g = hexByte (builtins.substring 2 2 h); b = hexByte (builtins.substring 4 2 h); }; # papirus-folders palette → the front-face fill of each # folder-.svg, read out of the icons themselves. # # NOT the Material Design values the names imply. Papirus paints the # front panel a good deal lighter than its own colour name: nordic's # face is 81a1c1, while 5e81ac is only the small back flap behind it. # Matching a teal accent against the nominal values is what made these # folders come out blue — the real darkcyan is 17x closer than nordic, # the nominal one wasn't. # # Every key here is a variant that actually ships (there is no # "palegreen"; a name with no folder--*.svg files silently # recolours nothing). pfPalette = { adwaita="93c0ea"; black="4f4f4f"; blue="5294e2"; bluegrey="607d8b"; breeze="57b8ec"; brown="ae8e6c"; carmine="a30002"; cyan="00bcd4"; darkcyan="45abb7"; deeporange="eb6637"; green="87b158"; grey="8e8e8e"; indigo="5c6bc0"; magenta="ca71df"; nordic="81a1c1"; orange="ee923a"; palebrown="d1bfae"; paleorange="eeca8f"; pink="f06292"; red="e25252"; teal="16a085"; violet="7e57c2"; white="e4e4e4"; yaru="676767"; yellow="f9bd30"; }; # Closest papirus-folders color to stylix's accent (base0D), chosen at # eval time via squared RGB distance — no runtime script needed. closestPfColor = let sq = x: x * x; dist = a: b: sq (a.r - b.r) + sq (a.g - b.g) + sq (a.b - b.b); accent = hexToRgb c.base0D; ranked = map (n: { name = n; d = dist accent (hexToRgb pfPalette.${n}); }) (builtins.attrNames pfPalette); in (builtins.foldl' (best: x: if x.d < best.d then x else best) (builtins.head ranked) (builtins.tail ranked)).name; # Papirus-Dark with folders recolored to the closest matching color. # Replicates papirus-folders' change_color logic directly: for each # colored variant (folder-{color}-*.svg), symlink the generic name # (folder-*.svg) to it. No papirus-folders binary needed. papirusDark = pkgs.runCommand "papirus-dark-${closestPfColor}" {} '' # Copy full icon tree so Papirus-Dark's ../Papirus/… symlinks resolve. tmpthemes=$(mktemp -d) cp -r ${pkgs.papirus-icon-theme}/share/icons/. "$tmpthemes/" chmod -R u+w "$tmpthemes" # Recolor folders. Papirus-Dark delegates 48x48 etc. to ../Papirus via # symlinks, so we operate through those resolved paths in the temp tree. for size in 22x22 24x24 32x32 48x48 64x64; do places="$tmpthemes/Papirus-Dark/$size/places" [ -d "$places" ] || continue for f in \ "$places/folder-${closestPfColor}"-*.svg \ "$places/folder-${closestPfColor}.svg" \ "$places/user-${closestPfColor}"-*.svg \ "$places/user-${closestPfColor}.svg"; do [ -f "$f" ] || continue fname=$(basename "$f") ln -sf "$fname" "$places/''${fname/-${closestPfColor}/}" done done # Copy Papirus-Dark with -L to dereference all symlinks, so the output # is self-contained — no dangling ../Papirus/… pointers. mkdir -p $out/share/icons cp -rL "$tmpthemes/Papirus-Dark" $out/share/icons/ ''; # Raised surfaces are tints of base00, matching quickshell's # Theme.base01/base02 and the GTK overrides in settings/desktop.nix. # Scaling all three channels is what Qt.lighter() does, so all three # toolkits land on the same #2f3440 / #434a5b. tint = f: let ch = k: toString (builtins.floor (builtins.fromJSON c."base00-rgb-${k}" * f)); in "rgb(${ch "r"}, ${ch "g"}, ${ch "b"})"; # Map Material You placeholders to the closest base16 slot in stylix's # palette. The mapping is approximate (Material You has more semantic # colours than base16), but covers the placeholders used in our Zen # userChrome and Vesktop quickCss templates. stylixize = builtins.replaceStrings [ "{{colors.primary.default.hex}}" "{{colors.primary_container.default.hex}}" "{{colors.secondary_container.default.hex}}" "{{colors.tertiary_container.default.hex}}" "{{colors.surface.default.hex}}" "{{colors.surface_container.default.hex}}" "{{colors.surface_container_low.default.hex}}" "{{colors.surface_container_high.default.hex}}" "{{colors.on_surface.default.hex}}" "{{colors.on_surface_variant.default.hex}}" "{{colors.outline.default.hex}}" "{{colors.outline_variant.default.hex}}" ] [ "#${c.base0D}" # primary accent "#${c.base02}" # primary container "#${c.base0C}" # secondary container (cyan) "#${c.base0E}" # tertiary container (purple) "#${c.base00}" # surface (main bg) (tint 1.7) # surface container (urlbar, panels, dialogs) "#${c.base00}" # surface container low (tint 2.4) # surface container high (selected tab, focused urlbar) "#${c.base05}" # on surface (fg) "#${c.base04}" # on surface variant (muted fg) "#${c.base03}" # outline "#${c.base02}" # outline variant ]; in lib.mkMerge [ # Desktop-only: Zen/Vesktop CSS and GTK icon theme (lib.mkIf isDesktop { home.file.".zen/fraudek5.Default Profile/chrome/userChrome.css".text = stylixize (builtins.readFile "${inputs.self}/templates/zen-userChrome.css"); home.file.".config/vesktop/settings/quickCss.css".text = stylixize (builtins.readFile "${inputs.self}/templates/vesktop-quickCss.css"); gtk.iconTheme = { package = papirusDark; name = "Papirus-Dark"; }; }) ]; }; }