2026-05-11 13:32:18 +01:00
|
|
|
{ config, pkgs, lib, inputs, ... }:
|
|
|
|
|
{
|
2026-05-30 11:11:33 +01:00
|
|
|
# Imported for all hosts via flake.nix.
|
2026-05-11 13:32:18 +01:00
|
|
|
|
2026-05-18 10:44:16 +01:00
|
|
|
config = {
|
2026-05-11 13:32:18 +01:00
|
|
|
stylix = {
|
|
|
|
|
enable = true;
|
2026-05-14 14:58:13 +01:00
|
|
|
# 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";
|
|
|
|
|
};
|
2026-05-11 13:32:18 +01:00
|
|
|
polarity = "dark";
|
|
|
|
|
|
2026-05-11 19:44:07 +01:00
|
|
|
# Let stylix theme every target it supports. Per-target opt-outs go
|
|
|
|
|
# under home-manager.users.fred.stylix.targets.<x>.enable = false.
|
|
|
|
|
autoEnable = true;
|
2026-05-11 13:32:18 +01:00
|
|
|
|
|
|
|
|
cursor = {
|
2026-05-12 11:48:28 +01:00
|
|
|
package = pkgs.bibata-cursors;
|
|
|
|
|
name = "Bibata-Modern-Ice";
|
2026-05-11 13:32:18 +01:00
|
|
|
size = 24;
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-29 21:46:13 +01:00
|
|
|
# caelestia's font set: Rubik for UI text, CaskaydiaCove NF for mono
|
|
|
|
|
# (still a nerd font, so terminal glyphs survive the swap).
|
2026-05-11 13:44:50 +01:00
|
|
|
fonts = {
|
|
|
|
|
monospace = {
|
2026-07-29 21:46:13 +01:00
|
|
|
package = pkgs.nerd-fonts.caskaydia-cove;
|
|
|
|
|
name = "CaskaydiaCove NF";
|
2026-05-11 13:44:50 +01:00
|
|
|
};
|
|
|
|
|
sansSerif = {
|
2026-07-29 21:46:13 +01:00
|
|
|
package = pkgs.rubik;
|
|
|
|
|
name = "Rubik";
|
2026-05-11 13:44:50 +01:00
|
|
|
};
|
|
|
|
|
serif = {
|
2026-07-29 21:46:13 +01:00
|
|
|
package = pkgs.rubik;
|
|
|
|
|
name = "Rubik";
|
2026-05-11 13:44:50 +01:00
|
|
|
};
|
2026-05-11 13:32:18 +01:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-18 13:53:19 +01:00
|
|
|
home-manager.users.fred = { config, lib, pkgs, osConfig, ... }: let
|
|
|
|
|
isDesktop = lib.elem osConfig.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ];
|
2026-05-11 20:08:36 +01:00
|
|
|
c = config.lib.stylix.colors;
|
2026-05-15 22:11:57 +01:00
|
|
|
|
|
|
|
|
# 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);
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-01 22:47:26 +01:00
|
|
|
# papirus-folders palette → the front-face fill of each
|
|
|
|
|
# folder-<color>.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-<name>-*.svg files silently
|
|
|
|
|
# recolours nothing).
|
2026-05-15 22:11:57 +01:00
|
|
|
pfPalette = {
|
2026-08-01 22:47:26 +01:00
|
|
|
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";
|
2026-05-15 22:11:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# 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.
|
2026-05-15 22:38:02 +01:00
|
|
|
# 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}" {} ''
|
2026-05-15 22:47:46 +01:00
|
|
|
# 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"
|
2026-05-15 22:20:56 +01:00
|
|
|
|
2026-05-15 22:47:46 +01:00
|
|
|
# Recolor folders. Papirus-Dark delegates 48x48 etc. to ../Papirus via
|
|
|
|
|
# symlinks, so we operate through those resolved paths in the temp tree.
|
2026-05-15 22:38:02 +01:00
|
|
|
for size in 22x22 24x24 32x32 48x48 64x64; do
|
2026-05-15 22:47:46 +01:00
|
|
|
places="$tmpthemes/Papirus-Dark/$size/places"
|
2026-05-15 22:38:02 +01:00
|
|
|
[ -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
|
2026-05-15 22:47:46 +01:00
|
|
|
|
|
|
|
|
# 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/
|
2026-05-15 22:11:57 +01:00
|
|
|
'';
|
|
|
|
|
|
2026-08-03 20:36:32 +01:00
|
|
|
# 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"})";
|
|
|
|
|
|
2026-05-20 17:45:11 +01:00
|
|
|
# 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.
|
2026-05-11 20:08:36 +01:00
|
|
|
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)
|
2026-08-03 20:36:32 +01:00
|
|
|
(tint 1.7) # surface container (urlbar, panels, dialogs)
|
2026-05-11 20:08:36 +01:00
|
|
|
"#${c.base00}" # surface container low
|
2026-08-03 20:36:32 +01:00
|
|
|
(tint 2.4) # surface container high (selected tab, focused urlbar)
|
2026-05-11 20:08:36 +01:00
|
|
|
"#${c.base05}" # on surface (fg)
|
|
|
|
|
"#${c.base04}" # on surface variant (muted fg)
|
|
|
|
|
"#${c.base03}" # outline
|
|
|
|
|
"#${c.base02}" # outline variant
|
|
|
|
|
];
|
2026-05-18 13:53:19 +01:00
|
|
|
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");
|
2026-05-11 20:08:36 +01:00
|
|
|
|
2026-05-18 13:53:19 +01:00
|
|
|
home.file.".config/vesktop/settings/quickCss.css".text =
|
|
|
|
|
stylixize (builtins.readFile "${inputs.self}/templates/vesktop-quickCss.css");
|
2026-05-11 20:08:36 +01:00
|
|
|
|
2026-05-18 13:53:19 +01:00
|
|
|
gtk.iconTheme = {
|
|
|
|
|
package = papirusDark;
|
|
|
|
|
name = "Papirus-Dark";
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
];
|
2026-05-11 13:32:18 +01:00
|
|
|
};
|
|
|
|
|
}
|