Commit 61547f1

HPCesia <me@hpcesia.com>
2026-08-21 13:07:39
desktop: add aesthetic
1 parent bb509ef
Changed files (11)
modules/desktop/aesthetic/gtk/dconf.nix
@@ -0,0 +1,37 @@
+{den, ...}: {
+  den.aspects.desktop.aesthetic.gtk.includes = [den.aspects.desktop.aesthetic.gtk.dconf];
+  den.aspects.desktop.aesthetic.gtk.dconf = {
+    nixos = {
+      programs.dconf.enable = true;
+    };
+
+    provides.to-users = {
+      hjem = {
+        pkgs,
+        lib,
+        config,
+        ...
+      }: {
+        options.dconf.settings = lib.mkOption {
+          type = lib.types.attrsOf (lib.types.attrsOf lib.types.anything);
+          default = {};
+        };
+
+        config = lib.mkIf (config.dconf.settings != {}) {
+          xdg.config.files."dconf/user" = {
+            source =
+              pkgs.runCommand "dconf-user-db" {
+                nativeBuildInputs = [(lib.getBin pkgs.dconf)];
+              } ''
+                dconf compile $out ${
+                  pkgs.writeTextDir "dconf-keyfiles" (lib.generators.toDconfINI config.dconf.settings)
+                }
+              '';
+            type = "copy";
+            clobber = true;
+          };
+        };
+      };
+    };
+  };
+}
modules/desktop/aesthetic/gtk/default.nix
@@ -0,0 +1,107 @@
+{lib, ...}: {
+  den.aspects.desktop.aesthetic.gtk = {
+    settings.host = {
+      theme = {
+        name = lib.mkOption {
+          type = lib.types.str;
+          default = "adw-gtk3";
+        };
+        package = lib.mkOption {
+          type = lib.types.functionTo lib.types.package;
+          default = pkgs: pkgs.adw-gtk3;
+        };
+      };
+    };
+
+    provides.to-users.hjem = {
+      host,
+      pkgs,
+      config,
+      ...
+    }: let
+      fonts = host.settings.desktop.aesthetic.fonts;
+      cursor = host.settings.desktop.aesthetic.cursor;
+      icon = host.settings.desktop.aesthetic.icon;
+      theme = host.settings.desktop.aesthetic.gtk.theme;
+
+      settings =
+        {"gtk-theme-name" = theme.name;}
+        // (lib.optionalAttrs (icon.name != null) {"gtk-icon-theme-name" = icon.name;})
+        // (lib.optionalAttrs (cursor.name != null) {
+          "gtk-cursor-theme-name" = cursor.name;
+          "gtk-cursor-theme-size" = toString cursor.size;
+        })
+        // {
+          "gtk-font-name" = "${(lib.head fonts.sansSerif).name} ${toString fonts.size}";
+        };
+
+      gtkINIGenerator = (pkgs.formats.ini {}).generate;
+
+      gtk2Generator = settings:
+        lib.concatMapAttrsStringSep "\n"
+        (n: v: "${n} = ${
+          if builtins.isBool v
+          then lib.trivial.boolToString v
+          else if builtins.isString v
+          then
+            if lib.strings.hasPrefix "GTK_" v
+            then v
+            else ''"${v}"''
+          else toString v
+        }")
+        settings;
+    in {
+      packages = lib.optional (theme != null) (theme.package pkgs);
+
+      xdg.config.files = {
+        "gtk-2.0/gtkrc" = {
+          generator = gtk2Generator;
+          value = settings;
+        };
+        "gtk-3.0/settings.ini" = {
+          generator = gtkINIGenerator "gtk-3.0-settings.ini";
+          value = {Settings = settings;};
+        };
+        "gtk-4.0/settings.ini" = {
+          generator = gtkINIGenerator "gtk-4.0-settings.ini";
+          value = {Settings = settings;};
+        };
+      };
+
+      dconf.settings."org/gnome/desktop/interface" = lib.filterAttrs (_: v: v != null) {
+        "font-name" = settings."gtk-font-name" or null;
+        "gtk-theme" = settings."gtk-theme-name" or null;
+        "icon-theme" = settings."gtk-icon-theme-name" or null;
+        "cursor-theme" = settings."gtk-cursor-theme-name" or null;
+        "cursor-size" = settings."gtk-cursor-theme-size" or null;
+      };
+
+      environment.sessionVariables = lib.optionalAttrs (theme != null) {
+        GTK2_RC_FILES = "${config.xdg.config.directory}/gtk-2.0/gtkrc";
+        GTK_THEME = theme.name;
+      };
+    };
+  };
+
+  den.aspects.desktop.aesthetic.gtk.themes = {
+    catppuccin = {
+      hjem = {pkgs, ...}: let
+        adw-color-catppuccin-mocha-mauve = pkgs.fetchurl {
+          url = "https://github.com/claymorwan/catppuccin/raw/54f7393990e672d3648c1bc8c4cc6d26e6bde852/adw/themes/mocha/catppuccin-mocha-mauve.css";
+          hash = "sha256-sj36YMvkpRym6FgzQzHuG0K8Nq/t/RHTZpxDdBiQybY=";
+        };
+      in {
+        xdg.config.files = {
+          "gtk-3.0/settings.ini".value.Settings = {"gtk-application-prefer-dark-theme" = true;};
+          "gtk-4.0/settings.ini".value.Settings = {"gtk-application-prefer-dark-theme" = true;};
+          "gtk-3.0/gtk.css".source = adw-color-catppuccin-mocha-mauve;
+          "gtk-4.0/gtk.css".source = adw-color-catppuccin-mocha-mauve;
+        };
+
+        dconf.settings."org/gnome/desktop/interface" = {
+          color-scheme = "prefer-dark";
+        };
+      };
+    };
+  };
+}
modules/desktop/aesthetic/cursor.nix
@@ -0,0 +1,84 @@
+{lib, ...}: {
+  den.aspects.desktop.aesthetic.cursor = {
+    settings.host = {
+      name = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        # default = null;
+        default = "Bibata-Modern-Classic";
+      };
+      package = lib.mkOption {
+        type = lib.types.nullOr (lib.types.functionTo lib.types.package);
+        # default = null;
+        default = pkgs: pkgs.bibata-cursors;
+      };
+      size = lib.mkOption {
+        type = lib.types.ints.positive;
+        default = 24;
+      };
+    };
+
+    nixos = {host, ...}: let
+      cfg = host.settings.desktop.aesthetic.cursor;
+      allOrNothing = (cfg.name != null) == (cfg.package != null);
+    in {
+      assertions = [
+        {
+          assertion = allOrNothing;
+          message = "desktop.aesthetic.cursor: name/package/size must be set all or none.";
+        }
+      ];
+
+      environment.variables = {
+        XCURSOR_SIZE = toString cfg.size;
+      };
+    };
+
+    provides.to-users.hjem = {
+      host,
+      pkgs,
+      config,
+      ...
+    }: let
+      cfg = host.settings.desktop.aesthetic.cursor;
+
+      defaultIndexThemePackage = pkgs.writeTextFile {
+        name = "index.theme";
+        destination = "/share/icons/default/index.theme";
+        # Set name in icons theme, for compatibility with AwesomeWM etc. See:
+        # https://github.com/nix-community/home-manager/issues/2081
+        # https://wiki.archlinux.org/title/Cursor_themes#XDG_specification
+        text = ''
+          [Icon Theme]
+          Name=Default
+          Comment=Default Cursor Theme
+          Inherits=${cfg.name}
+        '';
+      };
+    in
+      lib.optionalAttrs (cfg.package != null && cfg.name != null) {
+        packages = [
+          (cfg.package pkgs)
+          defaultIndexThemePackage
+        ];
+
+        environment.sessionVariables = {
+          XCURSOR_THEME = cfg.name;
+          XCURSOR_SIZE = toString cfg.size;
+          XCURSOR_PATH = "${config.xdg.data.directory}/icons";
+        };
+
+        xdg.data.files = {
+          "icons/default/index.theme".source = "${defaultIndexThemePackage}/share/icons/default/index.theme";
+          "icons/${cfg.name}".source = "${cfg.package pkgs}/share/icons/${cfg.name}";
+        };
+        files = {
+          ".icons/default/index.theme".source = "${defaultIndexThemePackage}/share/icons/default/index.theme";
+          ".icons/${cfg.name}".source = "${cfg.package pkgs}/share/icons/${cfg.name}";
+          ".Xresources".text = ''
+            Xcursor.size: ${toString cfg.size}
+            Xcursor.theme: ${cfg.name}
+          '';
+        };
+      };
+  };
+}
modules/desktop/aesthetic/default.nix
@@ -0,0 +1,10 @@
+{den, ...}: {
+  den.aspects.desktop.includes = [den.aspects.desktop.aesthetic];
+  den.aspects.desktop.aesthetic.includes = [
+    den.aspects.desktop.aesthetic.fonts
+    den.aspects.desktop.aesthetic.cursor
+    den.aspects.desktop.aesthetic.icon
+    den.aspects.desktop.aesthetic.gtk
+    den.aspects.desktop.aesthetic.qt
+  ];
+}
modules/desktop/aesthetic/fonts.nix
@@ -0,0 +1,88 @@
+{lib, ...}: {
+  den.aspects.desktop.aesthetic.fonts = {
+    settings.host = let
+      inherit (lib) mkOption types;
+
+      fontType = types.submodule {
+        options = {
+          name = mkOption {
+            type = types.str;
+          };
+          package = mkOption {
+            type = types.functionTo types.package;
+            example = lib.literalExpression "pkgs: pkgs.dejavu_fonts";
+          };
+        };
+      };
+    in {
+      size = mkOption {
+        type = types.ints.positive;
+        default = 12;
+      };
+      serif = mkOption {
+        type = types.listOf fontType;
+        default = [
+          {
+            name = "Noto Serif CJK SC";
+            package = pkgs: pkgs.noto-fonts-cjk-serif;
+          }
+        ];
+      };
+      sansSerif = mkOption {
+        type = types.listOf fontType;
+        default = [
+          {
+            name = "Sarasa Gothic SC";
+            package = pkgs: pkgs.sarasa-gothic;
+          }
+          {
+            name = "Noto Sans CJK SC";
+            package = pkgs: pkgs.noto-fonts-cjk-sans;
+          }
+        ];
+      };
+      monospace = mkOption {
+        type = types.listOf fontType;
+        default = [
+          {
+            name = "Maple Mono NF CN";
+            package = pkgs: pkgs.maple-mono.NF-CN;
+          }
+        ];
+      };
+      emoji = mkOption {
+        type = types.listOf fontType;
+        default = [
+          {
+            name = "Noto Color Emoji";
+            package = pkgs: pkgs.noto-fonts-color-emoji;
+          }
+        ];
+      };
+    };
+
+    nixos = {
+      host,
+      pkgs,
+      ...
+    }: let
+      cfg = host.settings.desktop.aesthetic.fonts;
+    in {
+      fonts = {
+        enableDefaultPackages = false;
+        fontDir.enable = true;
+
+        packages =
+          (map (x: x.package pkgs)
+            (lib.concatMap (x: cfg.${x}) ["serif" "sansSerif" "monospace" "emoji"]))
+          ++ (with pkgs; [
+            dejavu_fonts
+            noto-fonts-lgc-plus
+          ]);
+        fontconfig.defaultFonts =
+          lib.genAttrs ["serif" "sansSerif" "monospace" "emoji"]
+          (x: lib.unique (map (x: x.name) cfg.${x}));
+      };
+    };
+  };
+}
modules/desktop/aesthetic/icon.nix
@@ -0,0 +1,30 @@
+{lib, ...}: {
+  den.aspects.desktop.aesthetic.icon = {
+    settings.host = {
+      name = lib.mkOption {
+        type = lib.types.nullOr lib.types.str;
+        # default = null;
+        default = "WhiteSur";
+      };
+      package = lib.mkOption {
+        type = lib.types.nullOr (lib.types.functionTo lib.types.package);
+        # default = null;
+        default = pkgs:
+          pkgs.whitesur-icon-theme.override {
+            boldPanelIcons = true;
+            alternativeIcons = true;
+          };
+      };
+    };
+
+    provides.to-users.hjem = {
+      host,
+      pkgs,
+      ...
+    }: let
+      cfg = host.settings.desktop.aesthetic.icon;
+    in {
+      packages = lib.optional (cfg.package != null) (cfg.package pkgs);
+    };
+  };
+}
modules/desktop/aesthetic/qt.nix
@@ -0,0 +1,76 @@
+{lib, ...}: {
+  den.aspects.desktop.aesthetic.qt = {
+    nixos = {
+      qt = {
+        enable = true;
+        platformTheme = "qt5ct";
+      };
+    };
+
+    provides.to-users.hjem = {
+      host,
+      pkgs,
+      ...
+    }: let
+      fonts = host.settings.desktop.aesthetic.fonts;
+      icon = host.settings.desktop.aesthetic.icon;
+
+      qtctFormat = pkgs.formats.ini {
+        listToValue = values: lib.concatStringsSep ", " values;
+      };
+
+      qtctConf = {
+        Appearance =
+          lib.optionalAttrs (icon.name != null) {icon_theme = icon.name;};
+        Fonts = {
+          fixed = ''"${(lib.head fonts.monospace).name},${toString fonts.size}"'';
+          general = ''"${(lib.head fonts.sansSerif).name},${toString fonts.size}"'';
+        };
+      };
+    in {
+      packages = [
+        pkgs.libsForQt5.qt5ct
+        pkgs.qt6Packages.qt6ct
+      ];
+
+      xdg.config.files = {
+        "qt5ct/qt5ct.conf" = {
+          type = "symlink";
+          generator = qtctFormat.generate "qt5ct-config";
+          value = qtctConf;
+        };
+        "qt6ct/qt6ct.conf" = {
+          type = "symlink";
+          generator = qtctFormat.generate "qt6ct-config";
+          value = qtctConf;
+        };
+      };
+
+      environment.sessionVariables.QT_QPA_PLATFORMTHEME = "qt5ct";
+    };
+  };
+
+  den.aspects.desktop.aesthetic.qt.themes = {
+    catppuccin = {
+      hjem = {pkgs, ...}: let
+        qtctThemeConf = s: {
+          Appearance = {
+            custom_palette = true;
+            color_scheme_path = "${pkgs.catppuccin-qt5ct}/share/${s}/colors/catppuccin-mocha-mauve.conf";
+          };
+        };
+      in {
+        xdg.config.files = {
+          "qt5ct/qt5ct.conf".value = qtctThemeConf "qt5ct";
+          "qt6ct/qt6ct.conf".value = qtctThemeConf "qt6ct";
+        };
+
+        xdg.data.files."color-schemes".source = pkgs.fetchzip {
+          name = "Catppuccin-KDE-Mocha-color-schemes";
+          url = "https://github.com/catppuccin/kde/releases/download/v0.3.1/Mocha-color-schemes.tar.gz";
+          hash = "sha256-HlinXVRAPLKMGe+Puf91beYerdpfY7mbLX1SsNDXRho=";
+        };
+      };
+    };
+  };
+}
modules/desktop/app/browser/floorp/default.nix
@@ -12,7 +12,13 @@
       ];
     };
 
-    hjem = {pkgs, ...}: {
+    hjem = {
+      host,
+      pkgs,
+      ...
+    }: let
+      fontsCfg = host.settings.desktop.aesthetic.fonts;
+    in {
       imports = [./_hjem-module.nix];
 
       programs.floorp = {
@@ -116,6 +122,8 @@
             "browser.newtabpage.activity-stream.feeds.telemetry" = false;
             "browser.newtabpage.activity-stream.telemetry" = false;
             # == Appearance ==
+            "font.name.monospace.x-western" = (builtins.elemAt fontsCfg.monospace 0).name;
+            "font.name.sans-serif.x-western" = (builtins.elemAt fontsCfg.sansSerif 0).name;
             "browser.newtabpage.activity-stream.feeds.topsites" = false;
             "browser.newtabpage.activity-stream.default.sites" = "";
             "browser.toolbars.bookmarks.visibility" = "always";
modules/desktop/app/term/foot.nix
@@ -2,11 +2,14 @@
   den.aspects.desktop.app.term.foot = {
     includes = [den.aspects.desktop.app.term];
     hjem = {
+      host,
       user,
       pkgs,
       lib,
       ...
-    }: {
+    }: let
+      fontsCfg = host.settings.desktop.aesthetic.fonts;
+    in {
       packages = [pkgs.foot];
 
       xdg.config.files."foot/foot.ini" = {
@@ -14,6 +17,8 @@
         value = {
           main = {
             pad = "10x10";
+            font = "${(builtins.elemAt fontsCfg.monospace 0).name}:size=${toString fontsCfg.size}";
+            dpi-aware = "no";
           };
         };
       };
modules/desktop/kmscon.nix
@@ -1,12 +1,20 @@
 {den, ...}: {
   den.aspects.desktop.includes = [den.aspects.desktop.kmscon];
   den.aspects.desktop.kmscon = {
-    nixos = {config, ...}: {
+    nixos = {
+      host,
+      config,
+      ...
+    }: let
+      fontsCfg = host.settings.desktop.aesthetic.fonts;
+    in {
       services.kmscon = {
         enable = true;
         extraOptions = "--term xterm-256color";
         config = {
           hwaccel = config.hardware.facter.detected.graphics.enable or false;
+          font-name = (builtins.elemAt fontsCfg.monospace 0).name;
+          font-size = fontsCfg.size;
         };
       };
     };
modules/hosts/kevin/hardware.nix
@@ -1,4 +1,12 @@
 {den, ...}: {
+  den.hosts.kevin = {
+    settings = {
+      desktop.aesthetic = {
+        fonts.size = 13;
+      };
+    };
+  };
+
   den.aspects.kevin = {
     includes = with den.aspects.hardware; [
       cpu.intel