Add basic theme config

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-06-23 14:50:50 +03:00
parent 48f391e3ad
commit e7d328cab5
23 changed files with 554 additions and 188 deletions

View File

@@ -2,7 +2,8 @@
let
users = lib.attrsets.filterAttrs (name: config: config.isNormalUser) config.users.users;
in {
in
{
programs.fuse.userAllowOther = lib.mkIf (users != [ ]) true;
systemd.tmpfiles.rules = lib.mkIf (users != [ ]) (
@@ -14,12 +15,14 @@ in {
lib.attrsets.mapAttrsToList (user: config: "d /cache${config.home} 0700 ${user} users -") users
);
home-manager.users = lib.attrsets.mapAttrs (user: config: ({
imports = [ inputs.impermanence.nixosModules.home-manager.impermanence ];
home-manager.users = lib.attrsets.mapAttrs
(user: config: ({
imports = [ inputs.impermanence.nixosModules.home-manager.impermanence ];
home.persistence = {
"/persist${config.home}".allowOther = true;
"/cache${config.home}".allowOther = true;
};
})) users;
home.persistence = {
"/persist${config.home}".allowOther = true;
"/cache${config.home}".allowOther = true;
};
}))
users;
}

View File

@@ -3,15 +3,18 @@
let
users = lib.attrsets.filterAttrs (name: config: config.isNormalUser) config.users.users;
sopsKeyPath = ".config/sops-nix/key.txt";
in {
home-manager.users = lib.attrsets.mapAttrs (user: config: ({
imports = [ inputs.sops-nix.homeManagerModules.sops ];
in
{
home-manager.users = lib.attrsets.mapAttrs
(user: config: ({
imports = [ inputs.sops-nix.homeManagerModules.sops ];
sops.age.keyFile = "/persist${config.home}/${sopsKeyPath}";
sops.age.keyFile = "/persist${config.home}/${sopsKeyPath}";
home = {
persistence."/persist${config.home}".files = [ sopsKeyPath ];
sessionVariables.SOPS_AGE_KEY_FILE = "${config.home}/${sopsKeyPath}";
};
})) users;
home = {
persistence."/persist${config.home}".files = [ sopsKeyPath ];
sessionVariables.SOPS_AGE_KEY_FILE = "${config.home}/${sopsKeyPath}";
};
}))
users;
}

View File

@@ -2,43 +2,49 @@
let
users = lib.attrsets.filterAttrs (name: config: config.isNormalUser) config.users.users;
in {
home-manager.users = lib.attrsets.mapAttrs (user: cfg: (let
cacheHome = "${cfg.home}/.cache";
configHome = "${cfg.home}/.config";
dataHome = "${cfg.home}/.local/share";
stateHome = "${cfg.home}/.local/state";
xdgVmDir = "${cfg.home}/VMs";
xdgGitDir = "${cfg.home}/git";
in {
xdg = {
enable = true;
mimeApps.enable = true;
in
{
home-manager.users = lib.attrsets.mapAttrs
(user: cfg: (
let
cacheHome = "${cfg.home}/.cache";
configHome = "${cfg.home}/.config";
dataHome = "${cfg.home}/.local/share";
stateHome = "${cfg.home}/.local/state";
xdgVmDir = "${cfg.home}/VMs";
xdgGitDir = "${cfg.home}/git";
in
{
xdg = {
enable = true;
mimeApps.enable = true;
inherit cacheHome;
inherit configHome;
inherit dataHome;
inherit stateHome;
inherit cacheHome;
inherit configHome;
inherit dataHome;
inherit stateHome;
userDirs = {
enable = true;
extraConfig = {
XDG_VM_DIR = xdgVmDir;
XDG_GIT_DIR = xdgGitDir;
userDirs = {
enable = true;
extraConfig = {
XDG_VM_DIR = xdgVmDir;
XDG_GIT_DIR = xdgGitDir;
};
};
};
};
};
home.persistence."/persist${cfg.home}".directories = [
"Desktop" # userDirs.desktop
"Documents" # userDirs.documents
"Downloads" # userDirs.download
"Music" # userDirs.music
"Pictures" # userDirs.pictures
"Templates" # userDirs.templates
"Videos" # userDirs.videos
"VMs" # xdgVmDir
"git" # xdgGitDir
];
})) users;
home.persistence."/persist${cfg.home}".directories = [
"Desktop" # userDirs.desktop
"Documents" # userDirs.documents
"Downloads" # userDirs.download
"Music" # userDirs.music
"Pictures" # userDirs.pictures
"Templates" # userDirs.templates
"Videos" # userDirs.videos
"VMs" # xdgVmDir
"git" # xdgGitDir
];
}
))
users;
}

View File

@@ -3,7 +3,7 @@
{
imports = [
inputs.home-manager.nixosModules.default
./options.nix
./options
./configs/persist
./configs/sops
./configs/xdg
@@ -14,6 +14,11 @@
backupFileExtension = "bak";
useGlobalPkgs = true;
sharedModules = [{
imports = [
./options/home-manager/matugen
./options/home-manager/theme
];
home.stateVersion = "24.05";
systemd.user.startServices = "sd-switch";
nix.settings = config.nix.settings;

View File

@@ -11,18 +11,9 @@ let
type = nullOr str;
description = "Full name of the user.";
};
options.wallpaper = mkOption {
type = path;
description = "Path to the user's wallpaper.";
};
options.base16Scheme = mkOption {
type = path;
description = "Base16 scheme to use for the user's color palette.";
};
};
in {
in
{
options = with lib; with types; {
users.users = mkOption {
type = attrsOf (submodule userOptions);

View File

@@ -0,0 +1,23 @@
{ config, pkgs, lib, ... }:
let
cfg = config.programs.matugen;
in
{
# https://github.com/Theaninova/matugen/blob/add-home-manager-module/hm-module.nix
options.programs.matugen = with lib; with types; {
enable = mkEnableOption "matugen";
package = mkPackageOption pkgs "matugen" { };
settings = mkOption {
type = attrs;
description = "Settings to write to config.toml.";
};
};
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
xdg.configFile."matugen/config.toml".source = lib.mkIf (cfg.settings != null) (
(pkgs.formats.toml { }).generate "matugen" cfg.settings
);
};
}

View File

@@ -0,0 +1,267 @@
{ config, lib, pkgs, ... }:
let
cfg = config.theme;
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";
};
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.";
};
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 =
let
name = "theme-init";
init = pkgs.writeShellApplication {
inherit name;
runtimeInputs = with pkgs; [ coreutils-full ];
text =
let
wallpaperPath = "${cfg.configDir}/wallpaper";
in
''
if [ ! -L "${wallpaperPath}" ]; then
ln -sf "${cfg.wallpaper}" "${wallpaperPath}"
fi
${cfg.extraConfig}
$
'';
};
in
lib.mkIf cfg.enable {
home = {
packages = [ init ];
pointerCursor = {
inherit (cfg.cursor) package name size;
gtk.enable = true;
x11.enable = true;
};
};
wayland.windowManager.hyprland.settings.exec-once = "${init}/bin/${name}";
};
}

View File

@@ -0,0 +1,3 @@
git interpret-trailers --if-exists doNothing --trailer \
"Signed-off-by: $(git config user.name) <$(git config user.email)>" \
--in-place "$1"

View File

@@ -2,7 +2,8 @@
let
hmConfig = config.home-manager.users."${user.name}";
in {
in
{
home-manager.users."${user.name}" = {
programs.git = {
enable = true;
@@ -14,14 +15,13 @@ in {
key = null;
};
extraConfig.credential.helper = "store";
hooks = let
commit-msg-hook = pkgs.writeShellScriptBin "git-commit-msg" ''
${pkgs.git}/bin/git interpret-trailers --if-exists doNothing --trailer \
"Signed-off-by: $(git config user.name) <$(git config user.email)>" \
--in-place "$1"
'';
in {
commit-msg = "${commit-msg-hook}/bin/git-commit-msg";
hooks = {
commit-msg = let name = "git-commit-msg-hook"; in
"${pkgs.writeShellApplication {
inherit name;
runtimeInputs = with pkgs; [ git ];
text = builtins.readFile ./commit-msg.sh;
}}/bin/${name}";
};
};

View File

@@ -18,42 +18,38 @@ in
};
systemd.user = {
services.gpg-agent-import = let
init = pkgs.writeShellScriptBin "import-gpg-keys" ''
export GNUPGHOME=${gpgPath}
services.gpg-agent-import =
let
name = "import-gpg-keys";
init = pkgs.writeShellApplication {
inherit name;
runtimeInputs = with pkgs; [
coreutils-full
gnugrep
gnupg
];
runtimeEnv = {
GNUPGHOME = gpgPath;
HOME = user.home;
};
text = builtins.readFile ./import-gpg-keys.sh;
};
in
{
Unit = {
Description = "Auto-import GPG keys";
Requires = [ "sops-nix.service" "gpg-agent.socket" ];
After = [ "sops-nix.service" "gpg-agent.socket" ];
};
for keyfile in "${user.home}"/.config/sops-nix/secrets/gpg-agent/*.key; do
passfile="''${keyfile%.key}.pass"
Service = {
Type = "oneshot";
ExecStart = "${init}/bin/${name}";
};
if [ -f "$passfile" ]; then
${pkgs.gnupg}/bin/gpg2 --batch --yes --pinentry-mode loopback --passphrase-file "$passfile" --import "$keyfile"
else
${pkgs.gnupg}/bin/gpg2 --batch --yes --import "$keyfile"
fi
${pkgs.gnupg}/bin/gpg2 --with-colons --import-options show-only --import "$keyfile" | grep '^fpr' | cut -d: -f10 | while read -r KEY_ID; do
echo "$KEY_ID:6:" >> "${gpgPath}"/otrust.txt
done
done
${pkgs.gnupg}/bin/gpg2 --import-ownertrust "${gpgPath}"/otrust.txt
rm "${gpgPath}"/otrust.txt
'';
in {
Unit = {
Description = "Auto-import GPG keys";
Requires = [ "sops-nix.service" "gpg-agent.socket" ];
After = [ "sops-nix.service" "gpg-agent.socket" ];
Install.WantedBy = [ "default.target" ];
};
Service = {
Type = "oneshot";
ExecStart = "${init}/bin/import-gpg-keys";
};
Install = { WantedBy = [ "default.target" ]; };
};
tmpfiles.rules = [ "d ${hmConfig.xdg.dataHome}/gnupg 0700 ${user.name} users -" ];
};

View File

@@ -0,0 +1,16 @@
for keyfile in "$HOME"/.config/sops-nix/secrets/gpg-agent/*.key; do
passfile="${keyfile%.key}.pass"
if [ -f "$passfile" ]; then
gpg2 --batch --yes --pinentry-mode loopback --passphrase-file "$passfile" --import "$keyfile"
else
gpg2 --batch --yes --import "$keyfile"
fi
gpg2 --with-colons --import-options show-only --import "$keyfile" | grep '^fpr' | cut -d: -f10 | while read -r KEY_ID; do
echo "$KEY_ID:6:" >> "$GNUPGHOME"/otrust.txt
done
done
gpg2 --import-ownertrust "$GNUPGHOME"/otrust.txt
rm "$GNUPGHOME"/otrust.txt

View File

@@ -96,24 +96,12 @@ in
"disable_hyprland_logo" = true;
"disable_splash_rendering" = true;
};
exec-once = let
init = pkgs.writeShellScriptBin "hyprland-init" ''
${pkgs.swww}/bin/swww-daemon &> /tmp/swww.log &
while ! ${pkgs.swww}/bin/swww query &> /dev/null; do
sleep 0.1
done
${pkgs.swww}/bin/swww img ${user.wallpaper}
'';
in "${init}/bin/hyprland-init";
};
};
programs.zsh.loginExtra = lib.mkAfter ''
if [ -z "''${WAYLAND_DISPLAY}" ] && [ ! -z "''${XDG_VTNR}" ] && [ "''${XDG_VTNR}" -eq 1 ]; then
${pkgs.hyprland}/bin/hyprland &> /tmp/hyprland.log
if [ -z "''${WAYLAND_DISPLAY}" ] && [ -n "''${XDG_VTNR}" ] && [ "''${XDG_VTNR}" -eq 1 ]; then
hyprland &> /tmp/hyprland.log
fi
'';

View File

@@ -0,0 +1,58 @@
{ user ? throw "user argument is required" }: { config, ... }:
let
hmConfig = config.home-manager.users."${user.name}";
in
{
home-manager.users."${user.name}" = {
programs.matugen = {
enable = true;
settings = {
config = {
custom_colors =
let
mkColor = category: color: {
color = hmConfig.theme.color.${category}.${color};
blend = hmConfig.theme.color.${category}.blend;
};
in
{
danger = mkColor "semantic" "danger";
warning = mkColor "semantic" "warning";
success = mkColor "semantic" "success";
info = mkColor "semantic" "info";
red = mkColor "ansi" "red";
green = mkColor "ansi" "green";
yellow = mkColor "ansi" "yellow";
orange = mkColor "ansi" "orange";
blue = mkColor "ansi" "blue";
magenta = mkColor "ansi" "magenta";
cyan = mkColor "ansi" "cyan";
keywords = mkColor "syntax" "keywords";
functions = mkColor "syntax" "functions";
properties = mkColor "syntax" "properties";
constants = mkColor "syntax" "constants";
strings = mkColor "syntax" "strings";
numbers = mkColor "syntax" "numbers";
structures = mkColor "syntax" "structures";
types = mkColor "syntax" "types";
};
custom_keywords = {
flavour = hmConfig.theme.flavour;
contrast = builtins.toString hmConfig.theme.contrast;
opacity = builtins.toString hmConfig.theme.opacity;
radius = builtins.toString hmConfig.theme.radius;
padding = builtins.toString hmConfig.theme.padding;
double_padding = builtins.toString (hmConfig.theme.padding * 2);
blur = builtins.toString hmConfig.theme.blur;
};
};
templates = { };
};
};
};
}

View File

@@ -1,13 +0,0 @@
{ user ? throw "user argument is required" }: { inputs, ... }:
{
home-manager.users."${user.name}" = {
imports = [ inputs.stylix.homeManagerModules.stylix ];
stylix = {
enable = true;
image = user.wallpaper;
base16Scheme = user.base16Scheme;
};
};
}

View File

@@ -1,10 +1,33 @@
{ user ? throw "user argument is required" }: { pkgs, ... }:
{ user ? throw "user argument is required" }: { config, pkgs, ... }:
let
hmConfig = config.home-manager.users."${user.name}";
in
{
home-manager.users."${user.name}" = {
home = {
packages = with pkgs; [ swww ];
persistence."/cache${user.home}".directories = [ ".cache/swww" ];
};
theme.extraConfig = let name = "theme-swww"; in
"${pkgs.writeShellApplication {
inherit name;
runtimeInputs = with pkgs; [
coreutils-full
swww
];
text = ''
if ! pgrep -x "swww-daemon" > /dev/null; then
swww-daemon &> /tmp/swww.log &
fi
while ! swww query &> /dev/null; do
sleep 0.1
done
swww img "${hmConfig.theme.configDir}/wallpaper"
'';
}}/bin/${name}";
};
}

View File

@@ -0,0 +1,8 @@
{ user ? throw "user argument is required" }: { pkgs, ... }:
{
home-manager.users."${user.name}" = {
theme.enable = true;
home.persistence."/persist${user.home}".directories = [ ".config/theme" ];
};
}

View File

@@ -1,27 +1,12 @@
{ user ? throw "user argument is required" }: { inputs, lib, pkgs, ... }:
let
configDir = ".config/Code";
cacheDirs = [
".config/Code/Cache"
".config/Code/CachedConfigurations"
".config/Code/CachedData"
".config/Code/CachedExtensionVSIXs"
".config/Code/CachedExtensions"
".config/Code/CachedProfilesData"
".config/Code/Code Cache"
".config/Code/DawnCache"
".config/Code/GPUCache"
".config/Code/Service Worker/CacheStorage"
".config/Code/Service Worker/ScriptCache"
];
inherit (pkgs.callPackage "${inputs.impermanence}/lib.nix" { }) sanitizeName concatPaths;
in {
{
home-manager.users."${user.name}" = {
programs.vscode = {
enable = true;
mutableExtensionsDir = false;
userSettings = {
"diffEditor.ignoreTrimWhitespace" = false;
"editor.accessibilitySupport" = "off";
"editor.cursorBlinking" = "phase";
"editor.cursorSmoothCaretAnimation" = "on";
@@ -76,27 +61,24 @@ in {
];
home.persistence = {
"/persist${user.home}".directories = [ configDir ];
"/persist${user.home}".directories = [ ".config/Code" ];
# Bastard: https://github.com/microsoft/vscode/issues/3884
"/cache${user.home}".directories = cacheDirs;
# Even bigger Bastards:
# - https://github.com/nix-community/impermanence/issues/22
# - https://github.com/nix-community/impermanence/pull/97
# "/cache${user.home}".directories = [
# ".config/Code/Cache"
# ".config/Code/CachedConfigurations"
# ".config/Code/CachedData"
# ".config/Code/CachedExtensionVSIXs"
# ".config/Code/CachedExtensions"
# ".config/Code/CachedProfilesData"
# ".config/Code/Code Cache"
# ".config/Code/DawnCache"
# ".config/Code/GPUCache"
# ".config/Code/Service Worker/CacheStorage"
# ".config/Code/Service Worker/ScriptCache"
# ];
};
# Some filthy fucking shit below, be warned.
# Microsoft stores cache under .config/Code instead of .cache/Code like normal people.
# Sometimes a race condition is caused if the cache bind mounts are created before the config one.
# So we do this. Sorry.
# https://github.com/nix-community/impermanence/blob/27979f1c3a0d3b9617a3563e2839114ba7d48d3f/home-manager.nix#L238
systemd.user.services = let
configDirService = "bindMount-${sanitizeName (lib.strings.escapeShellArg (concatPaths [ "/persist${user.home}" configDir ]))}.service";
in
builtins.listToAttrs (builtins.map (dir: {
name = "bindMount-${sanitizeName (lib.strings.escapeShellArg (concatPaths [ "/cache${user.home}" dir ]))}";
value = {
Unit = {
Requires = [ configDirService ];
After = [ configDirService ];
};
};
}) cacheDirs);
};
}

View File

@@ -5,7 +5,7 @@
userSettings = {
"nix.enableLanguageServer" = true;
"nix.formatterPath" = "nixpkgs-fmt";
"nix.serverSettings" = {};
"nix.serverSettings" = { };
};
extensions = with pkgs; with vscode-extensions; [
jnoortheen.nix-ide

View File

@@ -1,4 +1,4 @@
{ config, pkgs, ... }:
{ config, ... }:
let
user = config.users.users.nick;
@@ -6,6 +6,8 @@ in
{
imports = [
./nogui.nix
(import ../configs/theme { inherit user; })
(import ../configs/matugen { inherit user; })
(import ../configs/firefox { inherit user; })
(import ../configs/hyprland { inherit user; })
(import ../configs/rofi { inherit user; })
@@ -14,11 +16,9 @@ in
(import ../configs/vscode { inherit user; })
(import ../configs/gtk { inherit user; })
(import ../configs/x { inherit user; })
(import ../configs/stylix { inherit user; })
];
users.users.nick = {
wallpaper = ./wallpapers/clouds.png;
base16Scheme = "${pkgs.base16-schemes}/share/themes/seti.yaml";
home-manager.users.nick = {
theme.wallpaper = ./wallpapers/cats.jpg;
};
}

View File

@@ -2,7 +2,8 @@
let
user = config.users.users.nick;
in {
in
{
imports = [
../common
(import ../configs/zsh { inherit user; })