{ config, lib, pkgs, ... }: let cfg = config.theme; init = pkgs.writeShellApplication { name = "theme"; runtimeInputs = with pkgs; [ coreutils-full ]; bashOptions = [ "nounset" "pipefail" ]; text = '' if [ -z "''${WAYLAND_DISPLAY:-}" ]; then echo "No Wayland session active. Exiting." exit 0 fi [ ! -L "${cfg.configDir}/wallpaper" ] && ln -sf "${cfg.wallpaper}" "${cfg.configDir}/wallpaper" [ ! -f "${cfg.configDir}/mode" ] && echo "${cfg.mode}" > "${cfg.configDir}/mode" set_wallpaper() { if [ -f "$1" ]; then WALLPAPER="$1" else echo "Invalid wallpaper path: $1" exit 1 fi } set_mode() { if [ "$1" = "light" ] || [ "$1" = "dark" ]; then MODE="$1" else echo "Invalid mode: $1. Use 'light' or 'dark'." exit 1 fi } toggle_mode() { if [ "$(cat "${cfg.configDir}/mode")" = "light" ]; then MODE="dark" else MODE="light" fi } show_usage() { echo "Usage: theme {toggle|light|dark|mode |wallpaper [mode]}" } finish() { [ -n "$WALLPAPER" ] && ln -sf "$WALLPAPER" "${cfg.configDir}/wallpaper" [ -n "$MODE" ] && echo "$MODE" > "${cfg.configDir}/mode" { ${cfg.extraConfig} } > /dev/null } WALLPAPER="" MODE="" if [ $# -eq 0 ]; then finish else case "$1" in toggle) if [ $# -eq 1 ]; then toggle_mode else show_usage exit 1 fi ;; light) if [ $# -eq 1 ]; then set_mode "light" else show_usage exit 1 fi ;; dark) if [ $# -eq 1 ]; then set_mode "dark" else show_usage exit 1 fi ;; mode) if [ $# -eq 2 ]; then set_mode "$2" else show_usage exit 1 fi ;; wallpaper) if [ $# -ge 2 ] && [ $# -le 3 ]; then set_wallpaper "$2" [ $# -eq 3 ] && set_mode "$3" else show_usage exit 1 fi ;; *) show_usage exit 1 ;; esac finish fi ''; }; in { # https://github.com/Theaninova/TheaninovOS/blob/master/modules/home-manager/theme/md3-evo.nix options.theme = with lib; with types; { enable = mkEnableOption "theme"; configDir = mkOption { type = str; default = "${config.xdg.configHome}/theme"; description = "The path to the theme config directory."; }; wallpaper = mkOption { type = path; description = "The path to the default wallpaper"; }; pkg = mkOption { type = package; default = init; readOnly = true; description = "The package containing the `theme` script"; }; extraConfig = mkOption { type = lines; default = ""; description = "Extra configuration lines to add to the theme script."; }; flavour = mkOption { type = enum [ "content" "expressive" "fidelity" "fruit-salad" "monochrome" "neutral" "rainbow" "tonal-spot" ]; default = "tonal-spot"; description = "The flavour of the theme."; }; mode = mkOption { type = enum [ "dark" "light" ]; default = "dark"; description = "The default mode of the theme."; }; contrast = mkOption { type = numbers.between (-1) 1; default = 0; description = "Use a modified contrast."; }; opacity = mkOption { type = numbers.between 0 1; default = 1; description = "The opacity of apps."; }; radius = mkOption { type = ints.unsigned; default = 24; description = "The radius of corners."; }; padding = mkOption { type = ints.unsigned; default = 12; description = "The padding of windows."; }; blur = mkOption { type = ints.unsigned; default = 0; description = "The blur amount of windows."; }; color = { semantic = { blend = mkOption { type = bool; default = false; description = "Blend the colors."; }; danger = mkOption { type = str; default = "#ff0000"; description = "The color of danger."; }; warning = mkOption { type = str; default = "#ffff00"; description = "The color of warning."; }; success = mkOption { type = str; default = "#00ff00"; description = "The color of success."; }; info = mkOption { type = str; default = "#0000ff"; description = "The color of info."; }; }; syntax = { blend = mkOption { type = bool; default = true; description = "Blend the colors."; }; keywords = mkOption { type = str; default = "#ff8000"; description = "The color of keywords."; }; functions = mkOption { type = str; default = "#0000ff"; description = "The color of functions."; }; properties = mkOption { type = str; default = "#ff00ff"; description = "The color of properties."; }; constants = mkOption { type = str; default = "#ff00ff"; description = "The color of constants."; }; strings = mkOption { type = str; default = "#00ff00"; description = "The color of variables."; }; numbers = mkOption { type = str; default = "#00ffff"; description = "The color of numbers."; }; structures = mkOption { type = str; default = "#ffff00"; description = "The color of structures."; }; types = mkOption { type = str; default = "#00ffff"; description = "The color of types."; }; }; ansi = { blend = mkOption { type = bool; default = true; description = "Blend the colors."; }; red = mkOption { type = str; default = "#ff0000"; description = "The color of red."; }; green = mkOption { type = str; default = "#00ff00"; description = "The color of green."; }; yellow = mkOption { type = str; default = "#ffff00"; description = "The color of yellow."; }; orange = mkOption { type = str; default = "#ff8000"; description = "The color of orange."; }; blue = mkOption { type = str; default = "#0000ff"; description = "The color of blue."; }; magenta = mkOption { type = str; default = "#ff00ff"; description = "The color of magenta."; }; cyan = mkOption { type = str; default = "#00ffff"; description = "The color of cyan."; }; }; }; cursor = { package = mkOption { type = package; default = pkgs.gnome.adwaita-icon-theme; description = "The package providing the cursor theme."; }; name = mkOption { type = str; default = "Adwaita"; description = "The cursor name within the package."; }; size = mkOption { type = ints.positive; default = 32; description = "The cursor size."; }; }; }; config = lib.mkIf cfg.enable { home = { packages = [ cfg.pkg ]; pointerCursor = { inherit (cfg.cursor) package name size; gtk.enable = true; x11.enable = true; }; }; }; }