28 Commits

Author SHA1 Message Date
mjallen18
33385d5275 testing done 2025-08-21 20:54:43 -05:00
mjallen18
19bf815be8 end test 2025-08-21 20:52:13 -05:00
mjallen18
0152438472 more cleanup 2025-08-21 20:05:58 -05:00
mjallen18
f9b07deb19 cleanup 2025-08-21 19:45:03 -05:00
mjallen18
6e55d375d2 user updates 2025-08-21 19:40:32 -05:00
mjallen18
0e066cb4d7 move some apps to namespace 2025-08-21 19:06:51 -05:00
mjallen18
bd64283f04 idk 2025-08-21 16:17:17 -05:00
mjallen18
6025b6c4f1 bcfs root? 2025-08-21 16:10:04 -05:00
mjallen18
92b04773b2 move python-steam 2025-08-21 14:26:50 -05:00
mjallen18
783a7a3390 README 2025-08-21 14:17:33 -05:00
mjallen18
0ef4354c1a aarch 2025-08-21 13:24:04 -05:00
mjallen18
192a978d46 fix proxies 2025-08-21 11:45:06 -05:00
mjallen18
a4519904b6 fix pi4 hostname 2025-08-21 11:45:06 -05:00
mjallen18
83a6e45bf4 test 2025-08-20 22:02:24 -05:00
mjallen18
2ba6f3466f clev 2025-08-20 21:30:18 -05:00
mjallen18
b3f5b4b406 more pi stuff 2025-08-20 21:30:18 -05:00
mjallen18
2e680f2519 fix lol 2025-08-20 21:30:18 -05:00
mjallen18
445183f826 pi stuff 2025-08-20 21:30:18 -05:00
mjallen18
aec980e6fe sops but idk 2025-08-20 21:30:18 -05:00
mjallen18
68f732ec4b cleanup 2025-08-20 21:30:18 -05:00
mjallen18
dc382dcfcc cache 2025-08-20 21:30:18 -05:00
mjallen18
b1a06034f1 disable gnome 2025-08-20 21:30:18 -05:00
mjallen18
aa3e8cc263 finally update traefik 2025-08-20 21:30:18 -05:00
mjallen18
b680255bc5 macos 2025-08-20 21:30:18 -05:00
mjallen18
a3f7af4e39 sops 2025-08-20 21:30:18 -05:00
mjallen18
cd5c8a0034 no splash 2025-08-20 21:30:18 -05:00
mjallen18
1f14f020ed ssh 2025-08-20 21:30:18 -05:00
mjallen18
05affb6b1f test 2025-08-18 20:54:03 -05:00
488 changed files with 11678 additions and 263588 deletions

8
.gitignore vendored
View File

@@ -1,14 +1,10 @@
hosts/nas/*.conf
hosts/nas/*.users
result*
result
*.raw
.codegpt
.direnv
shell.nix
.vscode
**/*/*.py
.envrc
.DS_Store
*.qcow2
keys
iso-*
.envrc

View File

@@ -1,6 +1,5 @@
# See https://github.com/Mic92/dotfiles/blob/d6114726d859df36ccaa32891c4963ae5717ef7f/nixos/.sops.yaml
keys:
- &matt-pgp CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
- &matt age157jemphjzg6zmk373vpccuguyw6e75qnkqmz8pcnn2yue85p939swqqhy0
- &matt_pi4 age13g9a4d4jrvckfddpgn8sm4kjtzajr67le56pfdg78ktr5pd09phq32j89u
- &matt_pi5 age1wpvfpv5n32lruk7c0da4uaeapsmhjxdvg8z4ljehn06l6g2y0e0sum404l
@@ -11,18 +10,14 @@ keys:
- &pi5 age1t2d5scrukk0guva5sr97a8tge5j8kd865adezrcru7p269pzwvpsamkgje
- &deck age1c8qw59ffcq9l77gfmtyc3djtvt3md0u6dwhrjcgsm98ntyf72ufqugj7cg
- &steamdeck age1er5qucsc2mugrzrr7n3xhzv7kemkrqrw4m84r544fkk7nkg5g5eswxkqj0
- &matt_macbook-pro age12gu9hqhd56yl5x3t5yenkn9yg57du08h77vzjqsmnu5hdppne38qcur5a0
- &macbook-pro age1t7378n8kmd3f32fkye2gw3jj6qswv3exjdx0dq8kl0xra3tmcdnsvddq3u
- &nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0
- &admin_nuc age1yn82e39pxt0d0pgny34ux4lkge4ff7wxvsye8ragvwngehemt4ps27phyw
- &matt_allyx age1n5frpwgvps7c2348ynu9g7g47kqar4srdplw5kkcyn4x80eqzetqw3ej2m
- &allyx age1lvks0rdf743cn9rvvx90mzu3mjldydlzslpmv9608wn4j0m8u3xsmu7yew
- &matt_macbook-pro age19daqsncuzeh3j6cwk8uxp6yfj8h0qtz02jxlwwy4v8j0mfgznsvq30440g
- &macbook-pro age19w4zafpwnq9yhzuf8r5te2yhq7xlqj76rcgzcz935hllyrz4yvws4jn6ca
- &nuc age1wurzgc20e6ye79wsg85vvqk4aj3mmc0llxshcy9532ex8f4c6dqql76c78
- &admin_nuc age1luyejgmqjj0esydlr2jxqkg48vexmx57gdz7cy5gq7rz8kf5cups2rnfa9
creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *matt_pi4
- *matt_pi5
@@ -37,44 +32,32 @@ creation_rules:
- *macbook-pro
- *admin_nuc
- *nuc
- *matt_allyx
- *allyx
- path_regex: nas-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *desktop
- *admin
- *jallen-nas
- path_regex: desktop-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *desktop
- *admin
- *jallen-nas
- path_regex: steamdeck-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *desktop
- *deck
- *steamdeck
- *admin
- *jallen-nas
- *matt_allyx
- *allyx
- path_regex: pi4-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *matt_pi4
- *matt_pi5
@@ -85,9 +68,7 @@ creation_rules:
- *jallen-nas
- path_regex: pi5-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *matt_pi4
- *matt_pi5
@@ -98,9 +79,7 @@ creation_rules:
- *jallen-nas
- path_regex: mac-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- pgp:
- *matt-pgp
age:
- age:
- *matt
- *matt_pi5
- *desktop

View File

@@ -1,62 +0,0 @@
#!/usr/bin/env bash
disk=/dev/mapper/nuc-nixos-cryptroot
# sudo mkfs.vfat "$disk"1
# sudo bcachefs format --label ssd.ssd1 --compression=zstd --discard "$disk"
sudo mount -t tmpfs -o mode=755 none /mnt
sudo mkdir -p /mnt/{boot,home,root,etc,nix,var/log,tmp,persist}
sudo mount /dev/disk/by-partlabel/disk-main-nuc-nixos-EFI /mnt/boot
# sudo mkdir -p /mnt/boot/firmware
# sudo mount "$disk"2 /mnt/boot/firmware
# sudo mount "$disk"2 -o compress=zstd,subvol=home /mnt/home
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=root /mnt/root
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=etc /mnt/etc
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=nix /mnt/nix
# sudo mount "$disk"2 -o compress=zstd,noatime,subvol=log /mnt/var/log
# bcachefs unlock -k session /dev/disk/by-partlabel/disk-main-nuc-nixos-bcachefs-root
sudo cryptsetup open /dev/disk/by-partlabel/disk-main-nuc-nixos-cryptroot nuc-nixos-cryptroot
# sudo bcachefs unlock -k session "$disk"2
# sudo mount "$disk" /mnt/tmp
# cd /mnt/tmp
# ls -alh
# sudo bcachefs subvolume create nix
# sudo bcachefs subvolume create etc
# sudo bcachefs subvolume create log
# sudo bcachefs subvolume create root
# sudo bcachefs subvolume create persist
# sudo bcachefs subvolume create home
# ls -alh
# cd /etc/nixos
# sudo umount /mnt/tmp
sudo mount -o noatime,X-mount.subdir=nix "$disk" /mnt/nix
sudo mount -o noatime,X-mount.subdir=etc "$disk" /mnt/etc
sudo mount -o noatime,X-mount.subdir=log "$disk" /mnt/var/log
sudo mount -o noatime,X-mount.subdir=root "$disk" /mnt/root
sudo mount -o noatime,X-mount.subdir=persist "$disk" /mnt/persist
sudo mount -o X-mount.subdir=home "$disk" /mnt/home
# tree /mnt
# sudo nixos-install --flake /etc/nixos#nuc-nixos
# sudo umount /mnt/boot
# sudo umount /mnt/var/log
# sudo umount /mnt/persist
# sudo umount /mnt/home
# sudo umount /mnt/root
# sudo umount /mnt/etc
# sudo umount /mnt/nix
# sudo umount /mnt
# wpa_passphrase "Joey's Jungle 5G" "kR8v&3Qd" > 5g.conf
# wpa_supplicant -i wlp6s0 -c 5g.conf -B
# dhcpcd
# keyctl link @u @s
# clevis decrypt < "/etc/clevis/nas_pool.jwe" | bcachefs unlock /dev/disk/by-label/nas_pool

View File

@@ -7,7 +7,7 @@
let
inherit (inputs) pre-commit-hooks-nix;
in
pre-commit-hooks-nix.lib.${pkgs.stdenv.hostPlatform.system}.run {
pre-commit-hooks-nix.lib.${pkgs.system}.run {
src = ../..;
hooks = {
pre-commit-hook-ensure-sops.enable = true;

View File

@@ -1,208 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.invalid/version.schema.json",
"title": "Unified Package Version Schema",
"description": "Schema for a unified version.json used by packages/",
"type": "object",
"additionalProperties": false,
"required": [
"schemaVersion",
"sources"
],
"properties": {
"schemaVersion": {
"type": "integer",
"enum": [1],
"description": "Schema version. Start at 1; bump on breaking changes."
},
"variables": {
"type": "object",
"description": "Common variables available for template substitution in string fields.",
"additionalProperties": {
"type": "string"
}
},
"defaultVariant": {
"type": "string",
"description": "Optional default variant name for consumers."
},
"sources": {
"type": "object",
"description": "Base component sources keyed by component name.",
"minProperties": 1,
"additionalProperties": {
"$ref": "#/$defs/SourceSpec"
}
},
"variants": {
"type": "object",
"description": "Optional variants/channels/flavors; each overlays the base.",
"additionalProperties": {
"$ref": "#/$defs/VariantSpec"
}
},
"notes": {
"type": "object",
"description": "Optional free-form human notes/documentation.",
"additionalProperties": true
}
},
"$defs": {
"SourceSpecBase": {
"type": "object",
"additionalProperties": false,
"properties": {
"fetcher": {
"type": "string",
"enum": ["github", "git", "url", "pypi", "none"],
"description": "Fetcher type for this source."
},
"hash": {
"type": "string",
"pattern": "^sha[0-9]+-",
"description": "SRI hash for the fetched artifact. Required unless fetcher is 'none'."
},
"version": {
"type": "string",
"description": "Optional version string metadata for this component."
},
"extra": {
"type": "object",
"description": "Optional free-form metadata for consumer logic.",
"additionalProperties": true
},
"owner": { "type": "string", "description": "GitHub owner/org (github fetcher)." },
"repo": { "type": "string", "description": "GitHub repository (github fetcher)." },
"tag": { "type": "string", "description": "Git tag (github fetcher). Mutually exclusive with 'rev'." },
"rev": { "type": "string", "description": "Commit revision (github/git fetchers)." },
"submodules": { "type": "boolean", "description": "Whether to fetch submodules (github/git fetchers)." },
"url": { "type": "string", "description": "Final URL (url fetcher). May be templated." },
"urlTemplate": { "type": "string", "description": "Template for URL (url fetcher); supports ${var}." },
"name": { "type": "string", "description": "PyPI dist name (pypi fetcher)." }
}
},
"SourceSpec": {
"allOf": [
{ "$ref": "#/$defs/SourceSpecBase" },
{
"if": {
"properties": { "fetcher": { "const": "github" } },
"required": ["fetcher"]
},
"then": {
"required": ["owner", "repo"],
"oneOf": [
{ "required": ["tag"] },
{ "required": ["rev"] }
]
}
},
{
"if": {
"properties": { "fetcher": { "const": "git" } },
"required": ["fetcher"]
},
"then": {
"required": ["url", "rev"]
}
},
{
"if": {
"properties": { "fetcher": { "const": "url" } },
"required": ["fetcher"]
},
"then": {
"oneOf": [
{ "required": ["url"] },
{ "required": ["urlTemplate"] }
]
}
},
{
"if": {
"properties": { "fetcher": { "const": "pypi" } },
"required": ["fetcher"]
},
"then": {
"required": ["name", "version"]
}
},
{
"if": {
"properties": { "fetcher": { "enum": ["github", "git", "url", "pypi"] } },
"required": ["fetcher"]
},
"then": {
"required": ["hash"]
}
}
]
},
"SourceOverride": {
"type": "object",
"additionalProperties": false,
"description": "Partial override of a source within a variant. All fields optional.",
"properties": {
"fetcher": { "type": "string", "enum": ["github", "git", "url", "pypi", "none"] },
"hash": { "type": "string", "pattern": "^sha[0-9]+-" },
"version": { "type": "string" },
"extra": { "type": "object", "additionalProperties": true },
"owner": { "type": "string" },
"repo": { "type": "string" },
"tag": { "type": "string" },
"rev": { "type": "string" },
"submodules": { "type": "boolean" },
"url": { "type": "string" },
"urlTemplate": { "type": "string" },
"name": { "type": "string" }
}
},
"VariantSpec": {
"type": "object",
"additionalProperties": false,
"properties": {
"inherits": {
"type": "string",
"description": "Optional base variant to inherit from."
},
"variables": {
"type": "object",
"description": "Variant-level variables that overlay top-level variables.",
"additionalProperties": { "type": "string" }
},
"sources": {
"type": "object",
"description": "Per-component overrides for this variant.",
"additionalProperties": { "$ref": "#/$defs/SourceOverride" }
},
"platforms": {
"type": "object",
"description": "Optional per-system overrides to support differing hashes/fields by platform.",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"sources": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/SourceOverride" }
},
"variables": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
}
}
}
}
}
}

1290
flake.lock generated

File diff suppressed because it is too large Load Diff

173
flake.nix
View File

@@ -1,38 +1,25 @@
{
inputs = rec {
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs-otbr.url = "github:mrene/nixpkgs/openthread-border-router";
home-manager-stable = {
url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs-stable";
};
home-manager-unstable = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs-unstable";
};
nixpkgs = nixpkgs-unstable;
home-manager = home-manager-unstable;
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05";
# The name "snowfall-lib" is required due to how Snowfall Lib processes your
# flake's inputs.
snowfall-lib = {
url = "github:mjallen18/snowfall-lib";
url = "github:snowfallorg/lib";
inputs.nixpkgs.follows = "nixpkgs";
};
# nixos-generators = {
# url = "github:nix-community/nixos-generators";
# inputs.nixpkgs.follows = "nixpkgs";
# };
chaotic.url = "github:chaotic-cx/nyx/nyxpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
impermanence.url = "github:nix-community/impermanence";
lanzaboote.url = "github:nix-community/lanzaboote/v1.0.0";
lanzaboote.url = "github:nix-community/lanzaboote/v0.4.2";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
@@ -48,10 +35,9 @@
nix-vscode-extensions.url = "github:nix-community/nix-vscode-extensions";
authentik-nix = {
url = "github:nix-community/authentik-nix/version/2025.12.1";
# inputs.nixpkgs.follows = "nixpkgs-stable";
};
authentik-nix.url = "github:nix-community/authentik-nix";
crowdsec.url = "git+https://codeberg.org/kampka/nix-flake-crowdsec.git";
nixai.url = "github:olafkfreund/nix-ai-help";
@@ -62,7 +48,11 @@
inputs.nixpkgs.follows = "nixpkgs";
};
darwin.url = "github:nix-darwin/nix-darwin/master";
nixos-raspberrypi.url = "github:mjallen18/nixos-raspberrypi";
jovian.url = "github:Jovian-Experiments/Jovian-NixOS";
darwin.url = "github:LnL7/nix-darwin";
nix-homebrew.url = "github:zhaofengli/nix-homebrew";
@@ -78,10 +68,7 @@
nixos-apple-silicon.url = "github:nix-community/nixos-apple-silicon";
pre-commit-hooks-nix = {
url = "github:cachix/pre-commit-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
treefmt-nix = {
url = "github:numtide/treefmt-nix";
@@ -96,31 +83,9 @@
};
lsfg-vk = {
url = "github:pabloaul/lsfg-vk-flake";
url = "github:mjallen18/lsfg-vk-flake/main";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-plist-manager.url = "github:sushydev/nix-plist-manager";
nix-rosetta-builder = {
url = "github:cpick/nix-rosetta-builder";
inputs.nixpkgs.follows = "nixpkgs";
};
stylix = {
url = "github:nix-community/stylix";
inputs.nixpkgs.follows = "nixpkgs";
};
end4-dotfiles = {
url = "git+https://github.com/end-4/dots-hyprland?submodules=1";
flake = false;
};
illogical-flake = {
url = "github:soymou/illogical-flake";
inputs.nixpkgs.follows = "nixpkgs";
inputs.dotfiles.follows = "end4-dotfiles";
};
};
# We will handle this in the next section.
@@ -140,28 +105,20 @@
# common modules
modules.nixos = with inputs; [
authentik-nix.nixosModules.default
chaotic.nixosModules.default
crowdsec.nixosModules.crowdsec
crowdsec.nixosModules.crowdsec-firewall-bouncer
disko.nixosModules.disko
impermanence.nixosModules.impermanence
lanzaboote.nixosModules.lanzaboote
sops-nix.nixosModules.sops
home-manager.nixosModules.home-manager
nix-index-database.nixosModules.nix-index
stylix.nixosModules.stylix
];
modules.home = with inputs; [
nix-index-database.homeManagerModules.nix-index
illogical-flake.homeManagerModules.default
];
# common darwin modules
modules.darwin = with inputs; [
nix-homebrew.darwinModules.nix-homebrew
home-manager.darwinModules.home-manager
nix-plist-manager.darwinModules.default
nix-rosetta-builder.darwinModules.default
nix-index-database.darwinModules.nix-index
stylix.darwinModules.stylix
];
# Host config
@@ -169,11 +126,11 @@
# ######################################################
# Desktop #
# ######################################################
matt-nixos = {
desktop = {
modules = with inputs; [
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
@@ -184,26 +141,44 @@
# ######################################################
# NAS #
# ######################################################
jallen-nas = {
nas = {
modules = with inputs; [
nixos-hardware.nixosModules.common-pc
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-hidpi
home-manager.nixosModules.home-manager
];
# overlays = with inputs; [ crowdsec.overlays.default ];
};
# ######################################################
# Steamdeck #
# ######################################################
steamdeck = {
modules = with inputs; [
disko.nixosModules.disko
jovian.nixosModules.jovian
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
lsfg-vk.nixosModules.default
];
};
# ######################################################
# NUC #
# ######################################################
nuc-nixos = {
nuc = {
modules = with inputs; [
disko.nixosModules.disko
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-cpu-amd-pstate
# nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-cpu-amd-zenpower
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
@@ -216,6 +191,9 @@
pi4 = {
modules = with inputs; [
disko.nixosModules.disko
nixos-raspberrypi.nixosModules.raspberry-pi-4.base
nixos-raspberrypi.nixosModules.raspberry-pi-4.display-vc4
nixos-raspberrypi.lib.inject-overlays
];
};
@@ -225,6 +203,10 @@
pi5 = {
modules = with inputs; [
disko.nixosModules.disko
nixos-raspberrypi.nixosModules.raspberry-pi-5.base
nixos-raspberrypi.nixosModules.raspberry-pi-5.display-vc4
nixos-raspberrypi.nixosModules.raspberry-pi-5.bluetooth
nixos-raspberrypi.lib.inject-overlays
];
};
@@ -239,9 +221,31 @@
};
};
overlays = with inputs; [
nix-vscode-extensions.overlays.default
];
overlays = with inputs; [ nix-vscode-extensions.overlays.default ];
homes = {
modules = with inputs; [
nix-index-database.homeModules.nix-index
sops-nix.homeManagerModules.sops
];
overlays = with inputs; [
nix-vscode-extensions.overlays.default
];
users = {
# "matt@desktop" = {
# modules = with inputs; [
# sops-nix.homeManagerModules.sops
# ];
# };
"deck@steamdeck" = {
modules = with inputs; [
steam-rom-manager.homeManagerModules.default
];
};
};
};
};
# Configure Snowfall Lib, all of these settings are optional.
@@ -260,25 +264,8 @@
};
};
channels-config = {
allowUnfree = true;
allowUnsupportedSystem = true;
permittedInsecurePackages = [
# ...
# "libsoup-2.74.3"
# "mbedtls-2.28.10"
];
};
outputs-builder = channels: {
formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix;
# Add mjallen-lib to the flake outputs
overlays = {
mjallen-lib = _final: _prev: {
mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib;
};
};
};
};
}

View File

@@ -1,11 +1,10 @@
{
lib,
pkgs,
namespace,
home,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
shellAliases = {
update-switch = "darwin-rebuild switch --flake ~/nix-config";
update-flake = "nix flake update ~/nix-config";
@@ -15,9 +14,8 @@ let
age
cpufetch
deadnix
nixfmt
nodePackages.nodejs
uv
direnv
nixfmt-rfc-style
sops
tree
wget
@@ -31,7 +29,7 @@ in
homeDirectory = "/Users/mattjallen";
packages = lib.mkForce packages;
sessionVariables = {
NH_DARWIN_FLAKE = lib.mkForce "/Users/mattjallen/nix-config";
NH_DARWIN_FLAKE = "${home.homeDirectory}/nix-config#mac";
};
};
@@ -41,238 +39,20 @@ in
};
};
# programs.nix-plist-manager = {
# enable = true;
# options = {
# applications = {
# finder = {
# settings = {
# general = {
# showTheseItemsOnTheDesktop = {
# hardDisks = false;
# externalDisks = true;
# cdsDvdsAndiPods = false;
# connectedServers = false;
# };
# openFoldersInTabsInsteadOfNewWindows = true;
# };
# sidebar = {
# recentTags = true;
# };
# advanced = {
# removeItemsFromTheTrashAfter30Days = true;
# showAllFilenameExtensions = true;
# showWarningBeforeChangingAnExtension = true;
# showWarningBeforeRemovingFromiCloudDrive = true;
# showWarningBeforeEmptyingTheTrash = true;
# keepFoldersOnTop = {
# inWindowsWhenSortingByName = true;
# onDesktop = true;
# };
# whenPerformingASearch = "Search This Mac";
# };
# };
# menuBar = {
# view = {
# showTabBar = true;
# showSidebar = true;
# showPathBar = true;
# showStatusBar = true;
# };
# };
# };
# systemSettings = {
# appearance = {
# appearance = "Dark";
# accentColor = "Multicolor";
# # clickInTheScrollBarTo = "Jump to the next page";
# sidebarIconSize = "Medium";
# showScrollBars = "When scrolling";
# };
# controlCenter = {
# wifi = true;
# bluetooth = true;
# airdrop = true;
# stageManager = true;
# focusModes = "active";
# screenMirroring = "active";
# display = "never";
# sound = "always";
# nowPlaying = "active";
# accessibilityShortcuts = "unset";
# musicRecognition = {
# showInMenuBar = false;
# showInControlCenter = true;
# };
# hearing = "unset";
# fastUserSwitching = {
# showInMenuBar = false;
# showInControlCenter = true;
# };
# keyboardBrightness = {
# showInMenuBar = false;
# showInControlCenter = true;
# };
# battery = {
# showInMenuBar = false;
# showInControlCenter = false;
# };
# batteryShowPercentage = true;
# # menuBarOnly = {
# # spotlight = false;
# # siri = true;
# # };
# # automaticallyHideAndShowTheMenuBar = "In Full Screen Only";
# };
# desktopAndDock = {
# desktopAndStageManager = {
# showItems = {
# onDesktop = true;
# inStageManager = true;
# };
# clickWallpaperToRevealDesktop = "Always";
# stageManager = false;
# showRecentAppsInStageManager = true;
# showWindowsFromAnApplication = "All at Once";
# };
# dock = {
# animateOpeningApplications = true;
# automaticallyHideAndShowTheDock = enabled;
# doubleClickAWindowsTitleBarTo = "Minimize";
# magnification = disabled;
# minimizeWindowsIntoApplicationIcon = true;
# minimizeWindowsUsing = "Genie Effect";
# positionOnScreen = "Bottom";
# showIndicatorsForOpenApplications = true;
# showSuggestedAndRecentAppsInDock = false;
# size = 64; # 16 - 128
# # persistentApps = [
# # { app = "/Applications/Clock.app"; }
# # { folder = "/Applications"; }
# # { app = "/Applications/Safari.app"; }
# # { app = "/Applications/Firefox.app"; }
# # { app = "/Applications/Tabby.app"; }
# # { app = "/Applications/Termius.app"; }
# # { app = "/Applications/Muic.app"; }
# # { app = "/Applications/Vesktop.app"; }
# # { app = "/Applications/Messages.app"; }
# # { app = "/Applications/Calendar.app"; }
# # { app = "/Applications/Reminders.app"; }
# # { app = "/Applications/Notes.app"; }
# # { app = "/Applications/Weather.app"; }
# # { app = "/Applications/Maps.app"; }
# # { app = "/Applications/App Store.app"; }
# # { app = "/Applications/System Settings.app"; }
# # { app = "/Applications/ChatGPT.app"; }
# # { app = "/Applications/Nextcloud.app"; }
# # { app = "/Applications/VSCodium.app"; }
# # { app = "/Applications/Omnissa Horizon Client.app"; }
# # { app = "/Applications/Proton Pass.app"; }
# # { app = "/Applications/OrcaSlicer.app"; }
# # { app = "/Applications/AlDente.app"; }
# # ];
# # persistentOthers = [
# # "~/Downloads"
# # ];
# };
# hotCorners = {
# # ["-" "Mission Control" "Application Windows" "Desktop" "Start Screen Saver" "Disable Screen Saver" "Dashboard" "Put Display to Sleep" "Launchpad" "Notification Center" "Lock Screen" "Quick Note"]
# topLeft = "-";
# topRight = "-";
# bottomLeft = "-";
# bottomRight = "-";
# };
# missionControl = {
# automaticallyRearrangeSpacesBasedOnMostRecentUse = true;
# displaysHaveSeparateSpaces = true;
# dragWindowsToTopOfScreenToEnterMissionControl = true;
# groupWindowsByApplication = true;
# whenSwitchingToAnApplicationSwitchToAspaceWithOpenWindowsForTheApplication = true;
# };
# widgets = {
# showWidgets = {
# onDesktop = true;
# inStageManager = true;
# };
# widgetStyle = "Automatic";
# useIphoneWidgets = true;
# };
# windows = {
# askToKeepChangesWhenClosingDocuments = true;
# closeWindowsWhenQuittingAnApplication = true;
# dragWindowsToScreenEdgesToTile = true;
# dragWindowsToMenuBarToFillScreen = true;
# holdOptionKeyWhileDraggingWindowsToTile = true;
# preferTabsWhenOpeningDocuments = "In Full Screen";
# tiledWindowsHaveMargin = false;
# };
# };
# focus = {
# shareAcrossDevices = true;
# };
# # general.dateAndTime."24HourTime" = false;
# notifications = {
# notificationCenter = {
# showPreviews = "When Unlocked";
# summarizeNotifications = true;
# };
# };
# sound = {
# soundEffects = {
# alertSound = "Boop";
# alertVolume = 0.7;
# playFeedbackWhenVolumeIsChanged = true;
# playUserInterfaceSoundEffects = true;
# };
# };
# spotlight = {
# helpAppleImproveSearch = false;
# # searchResults = {
# # applications = true;
# # calculator = true;
# # contacts = true;
# # conversion = true;
# # definition = true;
# # developer = true;
# # documents = true;
# # eventsAndReminders = true;
# # folders = true;
# # fonts = false;
# # images = true;
# # mailAndMessages = true;
# # movies = true;
# # music = true;
# # other = false;
# # pdfDocuments = true;
# # presentations = true;
# # siriSuggestions = false;
# # systemSettings = true;
# # tips = false;
# # websites = true;
# };
# };
# };
# };
# };
# Manage bug in compilations - who uses manpages in 2024 anyways? :P
manual.manpages = enabled;
manual.manpages.enable = false;
# Override defaults that arent supported
programs = {
mangohud = lib.mkForce disabled;
mangohud.enable = lib.mkForce false;
nh = {
flake = lib.mkForce "/Users/mattjallen/nix-config";
flake = "${home.homeDirectory}/nix-config";
};
};
services = {
pass-secret-service = lib.mkForce disabled;
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
pass-secret-service.enable = lib.mkForce false;
nextcloud-client.enable = lib.mkForce false;
};
}

View File

@@ -1,11 +1,14 @@
{
lib,
pkgs,
namespace,
...
}:
{ pkgs, lib, ... }:
let
inherit (lib.${namespace}) enabled disabled;
theme = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10 --build-host admin@10.0.1.3";
update-flake = "nix flake update mac-nixpkgs mac-nixos-apple-silicon mac-home-manager mac-impermanence mac-sops-nix --flake /etc/nixos";
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@10.0.1.3 --build-host admin@10.0.1.3 --flake ~/nix-config#jallen-nas";
};
fontName = "JetBrainsMono NFM";
fontPackage = pkgs.nerd-fonts.jetbrains-mono;
# Displays
display = {
input = "eDP-1";
@@ -19,30 +22,17 @@ in
home.homeDirectory = "/home/matt";
home.stateVersion = "23.11";
${namespace} = {
desktop.gnome = enabled;
programs.hyprland = {
enable = false;
mjallen = {
desktop.hyprland = {
enable = true;
primaryDisplay = "eDP-1";
debug.disableScaleChecks = true;
monitorv2 = [
{
name = display.input;
mode = "${display.resolution}@${display.refreshRate}";
position = "0x0";
scale = 1.25;
extra = [
"bitdepth"
"10"
"cm"
"hdr"
"sdrbrightness"
"1.2"
"sdrsaturation"
"0.98"
];
}
wallpaper = [
"${display.input}, /run/wallpaper.jpg"
];
monitor = [
"${display.input},${display.resolution}@${display.refreshRate},0x0,1.25,bitdepth,10,cm,hdr,sdrbrightness,1.2,sdrsaturation,0.98"
];
workspace = [
@@ -52,46 +42,51 @@ in
];
windowRule = [
# "size 2160 3356, tag:horizonrdp"
"size 2160 3356, tag:horizonrdp"
];
hyprpaper = {
wallpaperPath = "/run/wallpaper.jpg";
};
keybinds = {
bind = [
"$mod, A, exec, chromium --app=\"https://music.apple.com\""
"SHIFT, XF86MonBrightnessUp, exec, lightctl -D kbd_backlight up"
"SHIFT, XF86MonBrightnessDown, exec, lightctl -D kbd_backlight down"
];
};
defaultApps = {
browser = pkgs.firefox;
};
extraConfig = ''
exec-once = brightnessctl -d kbd_backlight s 50%
'';
};
programs = {
btop = enabled;
kitty = disabled;
mako = disabled;
nwg-dock = disabled;
nwg-drawer = disabled;
nwg-panel = disabled;
btop.enable = true;
kitty = {
enable = true;
font = {
name = fontName;
package = fontPackage;
};
};
mako = {
enable = true;
fontName = fontName;
};
nwg-dock.enable = true;
nwg-drawer.enable = true;
nwg-panel = {
enable = true;
defaultApps = {
browser = pkgs.firefox;
};
};
waybar = {
enable = false;
enable = true;
layer = "bottom";
temperature = {
cpu = enabled;
gpu = enabled;
};
modules-right = [
"temperature"
"temperature#gpu"
"keyboard-state#capslock"
"keyboard-state#numlock"
"wireplumber#sink"
"bluetooth"
"network"
"idle_inhibitor"
"clock"
"battery"
"custom/weather"
];
extraModules = {
"custom/lights" = {
@@ -106,44 +101,34 @@ in
extraModulesStyle = ''
#custom-lights {
color: @base0C;
opacity: 0.85;
background-color: @base00;
color: ${theme.frost.nord8};
background-color: ${theme.polarNight.nord0};
${theme.defaultOpacity}
${theme.borderLeft}
}
#custom-lights:hover {
background: @base03;
background: ${theme.polarNight.nord3};
}
'';
windowOffset = 75;
};
wlogout = disabled;
wofi = disabled;
wlogout.enable = true;
wofi.enable = true;
};
};
home.packages =
with pkgs.${namespace};
[
# librepods
]
++ (with pkgs; [
bolt-launcher
iw
iwd
orca-slicer
vscodium
]);
services = {
kdeconnect = {
enable = lib.mkForce true;
indicator = lib.mkForce true;
};
};
home.packages = with pkgs; [
iw
iwd
orca-slicer
vscodium
];
programs = {
password-store = enabled;
password-store.enable = true;
zsh.shellAliases = shellAliases;
};
}

View File

@@ -1,10 +1,22 @@
{ lib, namespace, ... }:
let
inherit (lib.${namespace}) enabled disabled;
in
{ lib, ... }:
{
home.username = "matt";
mjallen = {
shell-aliases = {
enable = true;
flakeInputs = [
"pi4-nixpkgs"
"pi4-home-manager"
"pi4-impermanence"
"pi4-sops-nix"
"pi4-nixos-hardware"
"pi4-nixos-raspberrypi"
"pi4-disko"
];
};
};
sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
@@ -41,11 +53,11 @@ in
};
programs = {
mangohud = lib.mkForce enabled;
mangohud.enable = lib.mkForce true;
};
services = {
nextcloud-client = lib.mkForce disabled;
nextcloud-client.enable = lib.mkForce false;
kdeconnect = {
enable = false;
indicator = false;

View File

@@ -1,11 +1,15 @@
{
config,
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10 --build-host admin@10.0.1.3";
update-flake = "nix flake update pi5-nixpkgs pi5-home-manager pi5-impermanence pi5-nixos-hardware pi5-sops-nix nixos-raspberrypi --flake /etc/nixos";
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@10.0.1.3 --build-host admin@10.0.1.3 --flake ~/nix-config#jallen-nas";
nas-ssh = "kitten ssh admin@10.0.1.3";
};
in
{
@@ -50,8 +54,12 @@ in
};
};
programs = {
zsh.shellAliases = shellAliases;
};
services = {
nextcloud-client = lib.mkForce disabled;
nextcloud-client.enable = false;
kdeconnect = {
enable = false;
indicator = false;

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,15 +1,23 @@
{
lib,
namespace,
...
}:
{ config, lib, ... }:
let
inherit (lib.${namespace}) disabled;
shellAliases = {
update-boot = "nixos-rebuild boot --max-jobs 10";
update-switch = "nixos-rebuild switch --max-jobs 10";
};
in
{
home.username = "root";
home = {
username = "root";
homeDirectory = lib.mkForce "/${config.home.username}";
enableNixpkgsReleaseCheck = false;
};
programs = {
zsh.shellAliases = shellAliases;
};
services = {
nextcloud-client = lib.mkForce disabled;
nextcloud-client.enable = lib.mkForce false;
kdeconnect = {
enable = false;
indicator = false;

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,19 +1,25 @@
{ pkgs, namespace, ... }:
{ pkgs, ... }:
{
home = {
username = "admin";
packages =
with pkgs;
[
heroic
]
++ (with pkgs.${namespace}; [
moondeck-buddy
]);
};
home.username = "admin";
${namespace} = {
sops.enable = true;
# mjallen.home.enable = true;
mjallen = {
shell-aliases = {
enable = true;
buildHost = ""; # NAS builds locally
flakeInputs = [
"nas-nixpkgs"
"nas-authentik-nix"
"nas-cosmic"
"nas-crowdsec"
"nas-home-manager"
"nas-impermanence"
"nas-lanzaboote"
"nas-nixos-hardware"
"nas-sops-nix"
];
};
};
sops = {
@@ -65,23 +71,16 @@
}
];
};
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
# Optional: override default paths if needed
environmentVariables = {
romsDirectory = "/home/admin/Emulation/roms";
steamDirectory = "/home/admin/.local/share/Steam";
};
emulators = {
"Non-SRM Shortcuts" = {
enable = true;
parserType = "Non-SRM Shortcuts";
extraArgs = "";
};
};
};
};
# services.nixai = {
# enable = true;
# mcp = {
# enable = true;
# # Optional: custom socket path (uses `$HOME` expansion)
# socketPath = "$HOME/.local/share/nixai/mcp.sock";
# };
# # Optional: integrate with VS Code
# vscodeIntegration = true;
# };
}

View File

@@ -1,37 +0,0 @@
{
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "admin";
# Configure systemd user service for protonmail-bridge
systemd.user.services.protonmail-bridge = {
Service = {
Environment = [
"GNUPGHOME=/home/admin/.gnupg"
"PASSWORD_STORE_DIR=/home/admin/.local/password-store"
];
};
};
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
protonmail-bridge = {
enable = true;
extraPackages = with pkgs; [
pass
libsecret
];
};
};
}

View File

@@ -0,0 +1,15 @@
{ ... }:
let
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10";
update-switch = "sudo nixos-rebuild switch --max-jobs 10";
update-flake = "nix flake update nas-nixpkgs nas-authentik-nix nas-cosmic nas-crowdsec nas-home-manager nas-impermanence nas-lanzaboote nas-nixos-hardware nas-sops-nix --flake /etc/nixos";
};
in
{
home.username = "admin";
programs = {
zsh.shellAliases = shellAliases;
};
}

View File

@@ -0,0 +1,83 @@
{ pkgs, ... }:
let
shellAliases = {
update-boot = "sudo nixos-rebuild boot --max-jobs 10 --build-host admin@10.0.1.3";
update-switch = "sudo nixos-rebuild switch --max-jobs 10";
update-flake = "nix flake update steamdeck-nixpkgs steamdeck-chaotic steamdeck-home-manager steamdeck-impermanence steamdeck-jovian steamdeck-lanzaboote steamdeck-nixos-hardware steamdeck-sops-nix steamdeck-steam-rom-manager --flake /etc/nixos";
nas-ssh = "ssh admin@10.0.1.3";
};
in
{
home.username = "deck";
mjallen.desktop.gnome.enable = true;
sops = {
age.keyFile = "/home/deck/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/deck" = {
path = "/home/deck/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/deck" = {
path = "/home/deck/.ssh/id_ed25519";
mode = "0600";
};
};
};
programs = {
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
# Optional: override default paths if needed
environmentVariables = {
romsDirectory = "/home/deck/Emulation/roms";
steamDirectory = "/home/deck/.local/share/Steam";
};
emulators = {
ryujinx.enable = true;
dolphin-gamecube = {
enable = true;
package = pkgs.dolphin-emu;
romFolder = "gc";
fileTypes = [
".iso"
".ISO"
".gcm"
".GCM"
".ciso"
".CISO"
"rvz"
];
extraArgs = "-b -e \"\${filePath}\"";
};
pcsx2.enable = true;
mgba.enable = true;
"Non-SRM Shortcuts" = {
enable = true;
parserType = "Non-SRM Shortcuts";
extraArgs = "";
};
};
};
zsh.shellAliases = shellAliases;
};
home.packages = with pkgs; [
dolphin-emu
heroic
mgba
prismlauncher
ryujinx-greemdev
omnissa-horizon-client
];
}

View File

@@ -1,88 +0,0 @@
{
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled;
in
{
home.username = "matt";
${namespace}.desktop.gnome = enabled;
sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/matt" = {
path = "/home/matt/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/matt" = {
path = "/home/matt/.ssh/id_ed25519";
mode = "0600";
};
};
};
programs = {
steam-rom-manager = {
enable = true;
steamUsername = "mjallen18";
# Optional: override default paths if needed
environmentVariables = {
romsDirectory = "/home/matt/Emulation/roms";
steamDirectory = "/home/matt/.local/share/Steam";
};
emulators = {
ryujinx = enabled;
dolphin-gamecube = {
enable = true;
package = pkgs.dolphin-emu;
romFolder = "gc";
fileTypes = [
".iso"
".ISO"
".gcm"
".GCM"
".ciso"
".CISO"
"rvz"
];
extraArgs = "-b -e \"\${filePath}\"";
};
pcsx2 = enabled;
mgba = enabled;
"Non-SRM Shortcuts" = {
enable = true;
parserType = "Non-SRM Shortcuts";
extraArgs = "";
};
};
};
};
home.packages =
with pkgs;
[
dolphin-emu
heroic
mgba
moonlight-qt
prismlauncher
ryubing
omnissa-horizon-client
]
++ (with pkgs.${namespace}; [
discord-krisp
librepods-beta
]);
}

View File

@@ -0,0 +1,60 @@
{ pkgs, ... }:
{
home.username = "matt";
mjallen = {
sops = {
enable = true;
};
shell-aliases = {
enable = true;
flakeInputs = [
"desktop-nixpkgs"
"desktop-chaotic"
"desktop-home-manager"
"desktop-impermanence"
"desktop-lanzaboote"
"desktop-nixos-hardware"
"desktop-sops-nix"
"desktop-steam-rom-manager"
];
};
};
services = {
remmina = {
enable = true;
addRdpMimeTypeAssoc = true;
};
};
programs = {
password-store.enable = true;
};
home.packages = with pkgs; [
bottles
compose2nix
discord
distrobox
heroic
omnissa-horizon-client
jq
lutris
lzip
morph
orca-slicer
piper
prismlauncher
protontricks
protonvpn-gui
python3
runelite
smile
unigine-heaven
via
virt-manager
vorta
waydroid-helper
];
}

View File

@@ -1,246 +0,0 @@
{
inputs,
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
displayLeft = {
input = "DP-1";
resolution = "3840x2160";
refreshRate = "120.00000";
};
displayRight = {
input = "DP-2";
resolution = "3840x2160";
refreshRate = "240.00000";
};
in
{
home.username = "matt";
${namespace} = {
sops = {
enable = true;
};
shell-aliases = {
enable = true;
};
programs = {
hyprland = {
enable = true;
primaryDisplay = "DP-1";
monitorv2 = [
{
name = displayLeft.input;
mode = "${displayLeft.resolution}@${displayLeft.refreshRate}";
position = "0x0";
scale = 1.0;
extra = [
# "bitdepth"
# "10"
# "cm"
# "hdredid"
# "sdrbrightness"
# "1.2"
# "sdrsaturation"
# "0.98"
];
}
{
name = displayRight.input;
mode = "${displayRight.resolution}@${displayRight.refreshRate}";
position = "3840x0";
scale = 1.0;
extra = [
# "bitdepth"
# "10"
# "cm"
# "hdredid"
# "sdrbrightness"
# "1.5"
# "sdrsaturation"
# "0.98"
];
}
];
workspace = [
"name:firefox, monitor:${displayRight.input}, default:false, special, class:(.*firefox.*)"
"name:discord, monitor:${displayRight.input}, default:true, special, title:(.*vesktop.*), title:(.*Apple Music.*)"
"name:steam, monitor:${displayLeft.input}, default:false, special, class:(.*[Ss]team.*)"
];
windowRule = [
"match:tag horizonrdp, size 2160 7680"
];
autostartCommands = [
"[silent] firefox"
"[silent] discord"
"[silent] chromium --app=\"https://music.apple.com\""
"[silent] steam"
];
hyprpaper = {
wallpaperPath = "/run/wallpaper.jpg";
};
keybinds = {
bind = [
"$mod, A, exec, chromium --app=\"https://music.apple.com\""
"$mod, C, exec, discord"
"$mod, G, exec, steam"
];
};
defaultApps = {
browser = pkgs.firefox;
};
};
btop = enabled;
kitty = enabled;
mako = enabled;
nwg-dock = enabled;
nwg-drawer = enabled;
nwg-panel = {
enable = true;
defaultApps = {
browser = pkgs.firefox;
};
};
waybar = {
enable = true;
layer = "bottom";
network.interface = "wlp9s0";
temperature = {
cpu = enabled;
gpu = enabled;
};
extraModules = {
"custom/lights" = {
tooltip = false;
exec = "waybar-hass --get_light light.living_room_lights";
interval = "once";
format = "{text}"; # "󱉓";
on-click = "waybar-hass --toggle_light light.living_room_lights";
return-type = "json";
};
};
extraModulesStyle = ''
#custom-lights {
color: @base0C;
background-color: @base00;
opacity: 0.85;
border-left: 5px solid @base0C;
}
#custom-lights:hover {
background: @base03;
}
'';
};
wlogout = enabled;
wofi = enabled;
};
};
services = {
remmina = {
enable = true;
addRdpMimeTypeAssoc = true;
};
};
programs = {
password-store = enabled;
};
home.packages =
with pkgs;
[
bolt-launcher
clevis
compose2nix
distrobox
heroic
home-manager
omnissa-horizon-client
jq
lzip
morph
orca-slicer
piper
prismlauncher
protontricks
protonvpn-gui
runelite
smile
via
virt-manager
vorta
waydroid-helper
]
++ (with pkgs.${namespace}; [
discord-krisp
# librepods
]);
specialisation = {
"end4".configuration =
let
dotfiles = inputs.end4-dotfiles;
in {
programs = {
illogical-impulse = {
enable = true;
dotfiles = {
fish = lib.mkForce disabled;
starship = lib.mkForce disabled;
};
hyprland.plugins = [
pkgs.hyprlandPlugins.hyprbars
pkgs.hyprlandPlugins.hyprexpo
];
};
};
stylix.targets.qt = lib.mkForce disabled;
${namespace} = {
programs = {
mako = lib.mkForce disabled;
nwg-dock = lib.mkForce disabled;
nwg-drawer = lib.mkForce disabled;
nwg-panel = lib.mkForce disabled;
waybar = lib.mkForce disabled;
wlogout = lib.mkForce disabled;
wofi = lib.mkForce disabled;
};
};
};
"cosmic".configuration = {
${namespace} = {
programs = {
hyprland = lib.mkForce disabled;
kitty = lib.mkForce disabled;
mako = lib.mkForce disabled;
nwg-dock = lib.mkForce disabled;
nwg-drawer = lib.mkForce disabled;
nwg-panel = lib.mkForce disabled;
waybar = lib.mkForce disabled;
wlogout = lib.mkForce disabled;
wofi = lib.mkForce disabled;
};
};
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,18 +0,0 @@
{
lib,
namespace,
...
}:
let
inherit (lib.${namespace}) disabled;
in
{
home.username = "root";
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,17 @@
{ config, lib, ... }:
let
shellAliases = {
update-boot = "nixos-rebuild boot --max-jobs 10";
update-switch = "nixos-rebuild switch --max-jobs 10";
};
in
{
home = {
username = "root";
homeDirectory = lib.mkForce "/${config.home.username}";
};
programs = {
zsh.shellAliases = shellAliases;
};
}

View File

@@ -1,130 +0,0 @@
# mjallen-lib Utility Functions
This directory contains utility functions that can be used to enhance your Nix configuration. These functions are inspired by the khanelinix repository and provide a more explicit and modular approach to building Nix configurations.
## Directory Structure
- `default.nix`: Main entry point that imports and exposes all utility functions
- `module/`: Utilities for module creation and option handling
- `file/`: Utilities for file handling and module discovery
- `system/`: Utilities for system configuration building
## How to Use
### 1. Import the Library
The library is already imported in your flake.nix file through the outputs-builder:
```nix
outputs-builder = channels: {
formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix;
# Add mjallen-lib to the flake outputs
overlays = {
mjallen-lib = final: prev: {
mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib;
};
};
};
```
This makes the mjallen-lib available to all your modules through the extended lib.
### 2. Use the Module Utilities
The module utilities provide functions for creating modules with consistent options:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt;
in
mkModule {
name = "mymodule";
description = "My awesome module";
options = {
setting1 = mkOpt lib.types.str "default" "Description of setting1";
setting2 = mkBoolOpt false "Description of setting2";
};
config = {
# Module implementation
};
}
```
### 3. Use the File Utilities
The file utilities provide functions for file handling and module discovery:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.file) safeImport importModulesRecursive;
in
{
# Import a file with error handling
myConfig = safeImport ./my-config.nix {};
# Import all modules recursively
imports = importModulesRecursive ./modules;
}
```
### 4. Use the System Utilities
The system utilities provide functions for building system configurations:
```nix
{ lib, ... }:
let
inherit (lib.mjallen.system.common) mkHomeManagerConfig;
in
{
# Build home-manager configurations
homeManagerConfig = mkHomeManagerConfig {
extendedLib = lib;
inputs = inputs;
system = "x86_64-linux";
matchingHomes = { ... };
};
}
```
## Available Functions
### Module Utilities
- `mkModule`: Create a module with common options
- `mkOpt`: Create an option with a type, default value, and description
- `mkOpt'`: Create an option with a type and default value (no description)
- `mkBoolOpt`: Create a boolean option with a default value and description
- `mkBoolOpt'`: Create a boolean option with a default value (no description)
- `enabled`: Standard enable pattern
- `disabled`: Standard disable pattern
- `capitalize`: Capitalize a string
- `boolToNum`: Convert a boolean to a number
- `default-attrs`: Apply mkDefault to all attributes
- `force-attrs`: Apply mkForce to all attributes
- `nested-default-attrs`: Apply default-attrs to nested attributes
- `nested-force-attrs`: Apply force-attrs to nested attributes
### File Utilities
- `readFile`: Read a file and return its contents
- `pathExists`: Check if a file exists
- `safeImport`: Import a nix file with error handling
- `scanDir`: Scan a directory and return directory names
- `getFile`: Get a file path relative to the flake root
- `importModulesRecursive`: Recursively discover and import all Nix modules in a directory tree
- `scanSystems`: Recursively scan systems directory structure
- `filterNixOSSystems`: Filter systems for NixOS (Linux)
- `filterDarwinSystems`: Filter systems for Darwin (macOS)
- `scanHomes`: Scan homes directory structure for home configurations
### System Utilities
- `mkExtendedLib`: Extend the nixpkgs lib with mjallen-lib
- `mkNixpkgsConfig`: Create a nixpkgs configuration
- `mkHomeConfigs`: Create home configurations for a system and hostname
- `mkHomeManagerConfig`: Create a home-manager configuration
- `mkSpecialArgs`: Create special arguments for a system configuration

View File

@@ -1,3 +0,0 @@

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ

View File

@@ -1,62 +0,0 @@
{ inputs }:
let
inherit (inputs.nixpkgs.lib)
concatLists
concatMapStrings
foldl'
genList
hasSuffix
imap0
length
mod
nameValuePair
stringToCharacters
sublist
substring
take
;
in
rec {
base64Table = builtins.listToAttrs (
imap0 (i: c: nameValuePair c i) (
# The '=' is included so the main algorithm doesn't fail before we can trim the result
stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
)
);
# Generated using python3:
# print(''.join([ chr(n) for n in range(1, 256) ]), file=open('ascii', 'w'))
ascii = builtins.readFile ./ascii;
decode =
str:
let
paddingCount =
if hasSuffix "==" str then
2
else if hasSuffix "=" str then
1
else
0;
numbers64 = map (c: base64Table.${c}) (stringToCharacters str);
allBytes = concatLists (
genList (
i:
let
v = foldl' (acc: el: acc * 64 + el) 0 (sublist (i * 4) 4 numbers64);
in
[
(mod (v / 256 / 256) 256)
(mod (v / 256) 256)
(mod v 256)
]
) (length numbers64 / 4)
);
finalBytes = take (length allBytes - paddingCount) allBytes;
in
concatMapStrings (n: substring (n - 1) 1 ascii) finalBytes;
}

View File

@@ -1,25 +0,0 @@
{ inputs, ... }:
{
mjallen-lib = {
# Import module utilities
module = import ./module { inherit inputs; };
# Import file utilities
file = import ./file { inherit inputs; };
# Import system utilities
system = import ./system { inherit inputs; };
# Import reverse proxy utilities
reverseproxy = import ./reverseproxy { inherit inputs; };
# Import examples
examples = import ./examples { inherit inputs; };
# Import versioning utilities
versioning = import ./versioning {
lib = inputs.nixpkgs.lib;
inherit inputs;
};
};
}

View File

@@ -1,8 +0,0 @@
{ ... }:
{
# Import all examples
sops = import ./sops.nix;
homeSops = import ./home-sops.nix;
fileUtils = import ./file-utils.nix;
systemUtils = import ./system-utils.nix;
}

View File

@@ -1,60 +0,0 @@
{ lib, namespace, ... }:
let
inherit (lib.${namespace}.file)
readFile
pathExists
safeImport
scanDir
getFile
importModulesRecursive
scanSystems
filterNixOSSystems
filterDarwinSystems
scanHomes
;
in
{
# Example of reading a file
myFileContent = readFile ./example.txt;
# Example of checking if a file exists
fileExists = pathExists ./example.txt;
# Example of safely importing a file
myConfig = safeImport ./my-config.nix { };
# Example of scanning a directory
directoryContents = scanDir ./modules;
# Example of getting a file path relative to the flake root
flakeFile = getFile "flake.nix";
# Example of importing modules recursively
modules = importModulesRecursive ./modules;
# Example of scanning systems
allSystems = scanSystems ./systems;
# Example of filtering systems
nixosSystems = filterNixOSSystems allSystems;
darwinSystems = filterDarwinSystems allSystems;
# Example of scanning homes
allHomes = scanHomes ./homes;
# Example of using these functions together
nixosConfigurations = lib.mapAttrs' (
_name:
{ system, hostname, ... }:
{
name = hostname;
value = lib.nixosSystem {
inherit system;
modules = [
{ networking.hostName = hostname; }
]
++ importModulesRecursive ./modules/nixos;
};
}
) nixosSystems;
}

View File

@@ -1,40 +0,0 @@
{
config,
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}.module) mkModule mkOpt;
in
mkModule {
name = "sops";
description = "SOPS secret management for home-manager";
options = {
defaultSopsFile = mkOpt lib.types.path null "Default sops file.";
sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [ ] "SSH Key paths to use.";
};
config = {
home.packages = with pkgs; [
age
sops
ssh-to-age
];
sops = {
inherit (config.${namespace}.sops) defaultSopsFile;
defaultSopsFormat = "yaml";
age = {
generateKey = true;
keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
sshKeyPaths = [
"${config.home.homeDirectory}/.ssh/id_ed25519"
]
++ config.${namespace}.sops.sshKeyPaths;
};
};
};
}

View File

@@ -1,117 +0,0 @@
# Example usage of the reverse proxy utilities
{ lib, namespace, ... }:
let
inherit (lib.${namespace} - lib.reverseproxy)
mkReverseProxy
mkReverseProxies
templates
middlewares
urls
;
in
{
# Example 1: Simple reverse proxy for a local service
simpleProxy = mkReverseProxy {
name = "myapp";
subdomain = "myapp";
url = "http://127.0.0.1:3000";
};
# Example 2: Authenticated service with custom middlewares
authProxy = mkReverseProxy {
name = "admin-panel";
subdomain = "admin";
url = "http://127.0.0.1:8080";
middlewares = middlewares.authBasic;
};
# Example 3: Container-based service
containerProxy = mkReverseProxy {
name = "nextcloud";
subdomain = "cloud";
url = urls.container "nextcloud" 80;
middlewares = middlewares.basic;
};
# Example 4: Multiple proxies at once
multipleProxies = mkReverseProxies [
{
name = "grafana";
subdomain = "grafana";
url = urls.localhost 3000;
middlewares = middlewares.authBasic;
}
{
name = "prometheus";
subdomain = "prometheus";
url = urls.localhost 9090;
middlewares = middlewares.internal;
}
{
name = "alertmanager";
subdomain = "alerts";
url = urls.localhost 9093;
middlewares = middlewares.authBasic;
}
];
# Example 5: Using templates for common patterns
webappExample = templates.webapp {
name = "webapp";
subdomain = "app";
port = 8080;
};
authWebappExample = templates.authWebapp {
name = "secure-app";
subdomain = "secure";
port = 9000;
};
containerExample = templates.containerService {
name = "gitea";
subdomain = "git";
containerName = "gitea";
port = 3000;
};
internalExample = templates.internalService {
name = "internal-api";
subdomain = "api-internal";
port = 8000;
};
# Example 6: Custom domain and advanced configuration
customProxy = mkReverseProxy {
name = "custom-service";
subdomain = "custom";
url = "http://10.0.1.100:8080";
domain = "example.com";
priority = 20;
rule = "Host(`custom.example.com`) && PathPrefix(`/api`)";
middlewares = [
"crowdsec"
"whitelist-geoblock"
"rate-limit"
];
};
# Example usage in a Traefik configuration:
#
# mjallen.services.traefik = {
# enable = true;
# extraServices = multipleProxies.extraServices;
# extraRouters = multipleProxies.extraRouters;
# };
#
# Or for individual proxies:
#
# mjallen.services.traefik = {
# enable = true;
# extraServices = [ simpleProxy.service ];
# extraRouters = [{
# inherit (simpleProxy.router) subdomain entryPoints middlewares;
# service = simpleProxy.router.service;
# }];
# };
}

View File

@@ -1,45 +0,0 @@
{
config,
lib,
namespace,
...
}:
let
inherit (lib.${namespace}.module) mkModule mkOpt mkBoolOpt;
in
mkModule {
name = "sops";
description = "SOPS secret management";
options = {
defaultSopsFile = mkOpt lib.types.path null "Default sops file.";
generateAgeKey = mkBoolOpt true "Whether to automatically generate an age key if one doesn't exist.";
ageKeyPath =
mkOpt (lib.types.nullOr lib.types.str) null
"Custom path to the age key file. If null, will use the default path.";
sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [
"/etc/ssh/ssh_host_ed25519_key"
] "SSH Key paths to use.";
validateSopsFiles = mkBoolOpt false "Whether to validate that sops files exist.";
};
config = {
sops = {
inherit (config.${namespace}.sops) defaultSopsFile validateSopsFiles;
age = {
inherit (config.${namespace}.sops) generateAgeKey;
keyFile =
if config.${namespace}.sops.ageKeyPath != null then
config.${namespace}.sops.ageKeyPath
else
"${config.users.users.${config.${namespace}.user.name}.home}/.config/sops/age/keys.txt";
sshKeyPaths = config.${namespace}.sops.sshKeyPaths;
};
};
};
}

View File

@@ -1,132 +0,0 @@
{ inputs, namespace, ... }:
let
inherit (inputs.self.${namespace} - lib.system.common)
mkExtendedLib
mkNixpkgsConfig
mkHomeConfigs
mkHomeManagerConfig
mkSpecialArgs
;
in
{
# Example of creating NixOS configurations
nixosConfigurations =
let
# Get all systems
allSystems = inputs.self.${namespace} - lib.file.scanSystems ../systems;
# Filter for NixOS systems
nixosSystems = inputs.self.${namespace} - lib.file.filterNixOSSystems allSystems;
in
inputs.nixpkgs.lib.mapAttrs' (
_name:
{ system, hostname, ... }:
let
# Create extended lib with mjallen-lib
extendedLib = mkExtendedLib inputs.self inputs.nixpkgs;
# Find matching home configurations for this system
matchingHomes = mkHomeConfigs {
flake = inputs.self;
inherit system hostname;
};
# Create home-manager configuration
homeManagerConfig = mkHomeManagerConfig {
inherit
extendedLib
inputs
system
matchingHomes
;
isNixOS = true;
};
in
{
name = hostname;
value = inputs.nixpkgs.lib.nixosSystem {
inherit system;
# Pass special arguments to modules
specialArgs = mkSpecialArgs {
inherit inputs hostname extendedLib;
username = "mjallen";
};
modules = [
# Set lib to extended lib
{ _module.args.lib = extendedLib; }
# Configure nixpkgs
{
nixpkgs = {
inherit system;
}
// mkNixpkgsConfig inputs.self;
}
# Import home-manager module
inputs.home-manager.nixosModules.home-manager
# Auto-inject home configurations
homeManagerConfig
# Import all nixos modules recursively
../${system}/${hostname}
]
++ (extendedLib.${namespace}.file.importModulesRecursive ../modules/nixos);
};
}
) nixosSystems;
# Example of creating home-manager configurations
homeConfigurations =
let
# Get all homes
allHomes = inputs.self.${namespace} - lib.file.scanHomes ../homes;
in
inputs.nixpkgs.lib.mapAttrs' (
_name:
{
system,
username,
hostname,
userAtHost,
path,
...
}:
let
# Create extended lib with mjallen-lib
extendedLib = mkExtendedLib inputs.self inputs.nixpkgs;
in
{
name = userAtHost;
value = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = import inputs.nixpkgs {
inherit system;
inherit ((mkNixpkgsConfig inputs.self)) config overlays;
};
extraSpecialArgs = {
inherit
inputs
hostname
username
system
;
inherit (inputs) self;
lib = extendedLib;
};
modules = [
# Set lib to extended lib
{ _module.args.lib = extendedLib; }
# Import the home configuration
path
]
++ (extendedLib.${namespace}.file.importModulesRecursive ../modules/home);
};
}
) allHomes;
}

View File

@@ -1,127 +0,0 @@
{ inputs, ... }@args:
let
# Get self from args or default to ../.. (the flake root)
self = if args ? self then args.self else ../..;
inherit (inputs.nixpkgs.lib)
genAttrs
filterAttrs
hasPrefix
foldl'
;
in
{
# Read a file and return its contents
readFile = path: builtins.readFile path;
# Check if a file exists
pathExists = path: builtins.pathExists path;
# Import a nix file with error handling
safeImport = path: default: if builtins.pathExists path then import path else default;
# Scan a directory and return directory names
scanDir = path: builtins.attrNames (builtins.readDir path);
# Get a file path relative to the flake root (similar to Snowfall's get-file)
getFile = relativePath: self + "/${relativePath}";
# Recursively discover and import all Nix modules in a directory tree
importModulesRecursive =
path:
let
# Helper function to recursively walk directories
walkDir =
currentPath:
let
currentEntries = builtins.readDir currentPath;
entryNames = builtins.attrNames currentEntries;
# Get all directories that contain default.nix
directoriesWithDefault = builtins.filter (
name:
currentEntries.${name} == "directory" && builtins.pathExists (currentPath + "/${name}/default.nix")
) entryNames;
# Get ALL directories (to recurse into)
allDirectories = builtins.filter (name: currentEntries.${name} == "directory") entryNames;
# Import directories that have default.nix
directoryImports = map (name: currentPath + "/${name}") directoriesWithDefault;
# Recursively walk ALL subdirectories
subDirImports = builtins.concatLists (map (dir: walkDir (currentPath + "/${dir}")) allDirectories);
in
directoryImports ++ subDirImports;
in
walkDir path;
# Recursively scan systems directory structure
scanSystems =
systemsPath:
let
systemArchs = builtins.attrNames (builtins.readDir systemsPath);
generateSystemConfigs =
system:
let
systemPath = systemsPath + "/${system}";
hosts = builtins.attrNames (builtins.readDir systemPath);
in
genAttrs hosts (hostname: {
inherit system hostname;
path = systemPath + "/${hostname}";
});
in
foldl' (acc: system: acc // generateSystemConfigs system) { } systemArchs;
# Filter systems for NixOS (Linux)
filterNixOSSystems =
systems:
filterAttrs (
_name: { system, ... }: hasPrefix "x86_64-linux" system || hasPrefix "aarch64-linux" system
) systems;
# Filter systems for Darwin (macOS)
filterDarwinSystems =
systems:
filterAttrs (
_name: { system, ... }: hasPrefix "aarch64-darwin" system || hasPrefix "x86_64-darwin" system
) systems;
# Scan homes directory structure for home configurations
scanHomes =
homesPath:
let
systemArchs = builtins.attrNames (builtins.readDir homesPath);
generateHomeConfigs =
system:
let
systemPath = homesPath + "/${system}";
userAtHosts = builtins.attrNames (builtins.readDir systemPath);
parseUserAtHost =
userAtHost:
let
# Split "username@hostname" into parts
parts = builtins.split "@" userAtHost;
username = builtins.head parts;
hostname = builtins.elemAt parts 2; # After split: [username, "@", hostname]
in
{
inherit
system
username
hostname
userAtHost
;
path = systemPath + "/${userAtHost}";
};
in
genAttrs userAtHosts parseUserAtHost;
in
foldl' (acc: system: acc // generateHomeConfigs system) { } systemArchs;
}

View File

@@ -1,264 +0,0 @@
{
inputs,
lib,
namespace,
}:
let
inherit (inputs.nixpkgs.lib)
mapAttrs
mkOption
types
toUpper
substring
stringLength
mkDefault
mkForce
;
base64Lib = import ../base64 { inherit inputs; };
in
rec {
# Conditionally enable modules based on system
enableForSystem =
system: modules:
builtins.filter (
mod: mod.systems or [ ] == [ ] || builtins.elem system (mod.systems or [ ])
) modules;
# Create a module with common options
mkModule =
{
name,
description ? "",
options ? { },
moduleConfig ? { },
domain ? "services",
config,
serviceName ? name,
}:
let
cfg = config.${namespace}.${domain}.${name};
# Create reverse proxy configuration using mkReverseProxy
reverseProxyConfig = lib.${namespace}.mkReverseProxy {
inherit name;
subdomain = cfg.reverseProxy.subdomain;
url = "http://${config.${namespace}.network.ipv4.address}:${toString cfg.port}";
middlewares = cfg.reverseProxy.middlewares;
};
defaultConfig = {
${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
reverseProxies = [ reverseProxyConfig ];
};
# Open firewall
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
users = lib.mkIf cfg.createUser {
users.${name} = {
isSystemUser = true;
group = name;
home = cfg.configDir;
};
groups.${name} = { };
};
systemd.services.${serviceName} = {
requires = [
"media-nas-main.mount"
# "openvpn-us.protonvpn.udp.service"
];
after = lib.mkForce [
"media-nas-main.mount"
# "openvpn-us.protonvpn.udp.service"
];
# serviceConfig = {
# NetworkNamespacePath = lib.mkIf cfg.enableVpn "/run/netns/vpn";
# # Consider also setting DNS *inside* the netns (see note below).
# };
};
services = {
postgresql = lib.mkIf cfg.configureDb {
enable = true;
ensureDatabases = [ name ];
ensureUsers = [
{
name = name;
ensureDBOwnership = true;
}
];
};
redis.servers.${name} = lib.mkIf cfg.redis.enable {
enable = true;
port = cfg.redis.port;
};
};
# systemd.tmpfiles.rules = [
# "d ${cfg.configDir} 0700 ${name} ${name} - -"
# # "d ${cfg.configDir}/server-files 0775 ${name} ${name} - -"
# # "d ${cfg.configDir}/user-files 0775 ${name} ${name} - -"
# ];
}
// moduleConfig;
in
{ lib, ... }:
{
options.${namespace}.${domain}.${name} = lib.mkOption {
type = lib.types.submodule {
options = {
enable = lib.mkEnableOption description;
port = mkOpt types.int 80 "Port for ${name} to be hosted on";
configDir = mkOpt types.str "/media/nas/main/appdata" "Path to the config dir";
dataDir = mkOpt types.str "/media/nas/main" "Path to the data dir";
createUser = mkBoolOpt false "create a user for this module/service";
configureDb = mkBoolOpt false "Manage db for this service";
environmentFile = mkOpt types.str "" "Environment File";
puid = mkOpt types.str "911" "default user id";
pgid = mkOpt types.str "1000" "default group id";
timeZone = mkOpt types.str "America/Chicago" "default timezone";
listenAddress = mkOpt types.str "0.0.0.0" "Environment File";
openFirewall = mkBoolOpt true "Open the firewall";
enableVpn = mkBoolOpt true "Enable routing through VPN";
redis = {
enable = lib.mkEnableOption "enable redis";
port = mkOpt types.int 80 "Port for ${name} redis to be hosted on";
};
hashedPassword =
mkOpt (types.nullOr types.str)
"$y$j9T$EkPXmsmIMFFZ.WRrBYCxS1$P0kwo6e4.WM5DsqUcEqWC3MrZp5KfCjxffraMFZWu06"
"Hashed password for code-server authentication";
extraEnvironment =
mkOpt (types.attrsOf types.str) { }
"Extra environment variables for code-server";
reverseProxy = mkReverseProxyOpt name;
}
// options;
};
default = { };
};
config = lib.mkIf cfg.enable defaultConfig;
};
# container
mkContainer =
{
name,
localAddress ? "127.0.0.1",
ports ? [ 80 ],
bindMounts ? { },
config ? { },
}:
{ lib, ... }:
{
containers.${name} = {
inherit localAddress bindMounts;
config = config // {
networking = {
firewall = {
enable = true;
allowedTCPPorts = ports;
};
# Use systemd-resolved inside the container
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
useHostResolvConf = lib.mkForce false;
};
services.resolved.enable = true;
system.stateVersion = "23.11";
};
autoStart = lib.mkDefault true;
privateNetwork = lib.mkDefault true;
hostAddress = lib.mkDefault "10.0.1.3";
};
networking = {
nat.forwardPorts = map (port: {
destination = lib.mkDefault "${localAddress}:${toString port}";
sourcePort = lib.mkDefault port;
}) ports;
firewall = {
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
};
};
# Migrated mjallen utilities
# Option creation helpers
mkOpt =
type: default: description:
mkOption { inherit type default description; };
mkOpt' = type: default: mkOpt type default null;
mkBoolOpt = mkOpt types.bool;
mkBoolOpt' = mkOpt' types.bool;
mkReverseProxyOpt = name: {
enable = mkBoolOpt false "Enable reverse proxy support";
subdomain = mkOpt types.str name "subdomain of the service";
middlewares = mkOpt (types.listOf types.str) [
"crowdsec"
"whitelist-geoblock"
] "List of middlewares to use";
};
# Standard enable/disable patterns
enabled = {
enable = true;
};
disabled = {
enable = false;
};
# String utilities
capitalize =
s:
let
len = stringLength s;
in
if len == 0 then "" else (toUpper (substring 0 1 s)) + (substring 1 len s);
# Boolean utilities
boolToNum = bool: if bool then 1 else 0;
# Attribute manipulation utilities
default-attrs = mapAttrs (_key: mkDefault);
force-attrs = mapAttrs (_key: mkForce);
nested-default-attrs = mapAttrs (_key: default-attrs);
nested-force-attrs = mapAttrs (_key: force-attrs);
}
// base64Lib

View File

@@ -1,220 +0,0 @@
{ inputs }:
let
inherit (inputs.nixpkgs.lib)
listToAttrs
nameValuePair
;
in
rec {
# Create a service configuration for Traefik
mkService =
{
name,
url,
loadBalancer ? { },
}:
{
inherit name url;
config = {
loadBalancer = {
servers = [ { inherit url; } ];
}
// loadBalancer;
};
};
# Create a router configuration for Traefik
mkRouter =
{
subdomain,
domain ? "mjallen.dev",
service,
entryPoints ? [ "websecure" ],
middlewares ? [
"crowdsec"
"whitelist-geoblock"
],
priority ? null,
rule ? null,
tls ? {
certResolver = "letsencrypt";
},
}:
{
inherit
subdomain
service
entryPoints
middlewares
;
config = {
inherit
entryPoints
service
middlewares
tls
;
rule = if rule != null then rule else "Host(`${subdomain}.${domain}`)";
}
// (if priority != null then { inherit priority; } else { });
};
# Create both service and router for a simple reverse proxy setup
mkReverseProxy =
{
name,
subdomain,
url,
domain ? "mjallen.dev",
entryPoints ? [ "websecure" ],
middlewares ? [
"crowdsec"
"whitelist-geoblock"
],
priority ? null,
rule ? null,
tls ? {
certResolver = "letsencrypt";
},
loadBalancer ? { },
}:
{
service = mkService {
inherit name url loadBalancer;
};
router = mkRouter {
inherit
subdomain
domain
entryPoints
middlewares
priority
rule
tls
;
service = name;
};
};
# Convert a list of services to the format expected by Traefik module
servicesToConfig =
services: listToAttrs (map (service: nameValuePair service.name service.config) services);
# Convert a list of routers to the format expected by Traefik module
routersToConfig =
routers: listToAttrs (map (router: nameValuePair router.subdomain router.config) routers);
# Helper to create multiple reverse proxies at once
mkReverseProxies =
proxies:
let
results = map mkReverseProxy proxies;
services = map (result: result.service) results;
routers = map (result: result.router) results;
in
{
services = servicesToConfig services;
routers = routersToConfig routers;
extraServices = services;
extraRouters = map (router: {
inherit (router) subdomain entryPoints middlewares;
service = router.service;
}) routers;
};
# Common middleware configurations
middlewares = {
# Authentication middleware
auth = [ "authentik" ];
# Basic security (default)
basic = [
"crowdsec"
"whitelist-geoblock"
];
# Internal only access
internal = [
"crowdsec"
"whitelist-geoblock"
"internal-ipallowlist"
];
# WebSocket support
websocket = [
"crowdsec"
"whitelist-geoblock"
"onlyoffice-websocket"
];
# Authenticated with basic security
authBasic = [
"crowdsec"
"whitelist-geoblock"
"authentik"
];
};
# Common service URL builders
urls = {
# Local container service
container =
containerName: port: "http://\${config.containers.${containerName}.localAddress}:${toString port}";
# Local host service
localhost = port: "http://127.0.0.1:${toString port}";
# Network service
network = ip: port: "http://${ip}:${toString port}";
# Server IP service (using your server IP pattern)
server = port: "http://\${serverIp}:${toString port}";
};
# Pre-configured reverse proxy templates
templates = {
# Standard web application
webapp =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.basic;
}
// args
);
# Authenticated web application
authWebapp =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.authBasic;
}
// args
);
# Container-based service
containerService =
{ containerName, port, ... }@args:
mkReverseProxy (
{
url = urls.container containerName port;
middlewares = middlewares.basic;
}
// args
);
# Internal-only service
internalService =
{ port, ... }@args:
mkReverseProxy (
{
url = urls.localhost port;
middlewares = middlewares.internal;
}
// args
);
};
}

View File

@@ -1,103 +0,0 @@
{ inputs, namespace }:
let
inherit (inputs.nixpkgs.lib) filterAttrs mapAttrs';
in
{
mkExtendedLib =
flake: nixpkgs:
nixpkgs.lib.extend (
_final: _prev: {
mjallen = flake.${namespace} - lib;
}
);
mkNixpkgsConfig = flake: {
overlays = builtins.attrValues flake.overlays;
config = {
allowAliases = false;
allowUnfree = true;
permittedInsecurePackages = [
# Add any permitted insecure packages here
"mbedtls-2.28.10"
];
};
};
mkHomeConfigs =
{
flake,
system,
hostname,
}:
let
inherit (flake.${namespace} - lib.file) scanHomes;
homesPath = ../../homes;
allHomes = scanHomes homesPath;
in
filterAttrs (
_name: homeConfig: homeConfig.system == system && homeConfig.hostname == hostname
) allHomes;
mkHomeManagerConfig =
{
extendedLib,
inputs,
system,
matchingHomes,
isNixOS ? true,
}:
if matchingHomes != { } then
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit inputs system;
inherit (inputs) self;
lib = extendedLib;
};
sharedModules = [
{ _module.args.lib = extendedLib; }
]
++ (extendedLib.${namespace}.file.importModulesRecursive ../../modules/home);
users = mapAttrs' (_name: homeConfig: {
name = homeConfig.username;
value = {
imports = [ homeConfig.path ];
home = {
inherit (homeConfig) username;
homeDirectory = inputs.nixpkgs.lib.mkDefault (
if isNixOS then "/home/${homeConfig.username}" else "/Users/${homeConfig.username}"
);
};
}
// (
if isNixOS then
{
_module.args.username = homeConfig.username;
}
else
{ }
);
}) matchingHomes;
};
}
else
{ };
mkSpecialArgs =
{
inputs,
hostname,
username,
extendedLib,
}:
{
inherit inputs hostname username;
inherit (inputs) self;
lib = extendedLib;
namespace = "mjallen";
format = "system";
host = hostname;
};
}

View File

@@ -1,5 +0,0 @@
{ inputs }:
{
# Common utilities used by system builders
common = import ./common.nix { inherit inputs; };
}

View File

@@ -1,212 +0,0 @@
{
lib,
inputs,
system ? "aarch64-linux",
}:
let
pkgs = inputs.nixpkgs.legacyPackages.${system};
in
let
inherit (builtins)
isAttrs
isList
isString
hasAttr
getAttr
attrNames
toString
replaceStrings
;
mapAttrs = lib.mapAttrs;
recursiveUpdate = lib.recursiveUpdate;
# Deep-merge attrsets (right-biased).
deepMerge = a: b: recursiveUpdate a b;
# Merge component sources: base.sources overlaid by overrides (component-wise deep merge).
mergeSources =
baseSources: overrides:
baseSources
// mapAttrs (
name: ov: if hasAttr name baseSources then deepMerge (getAttr name baseSources) ov else ov
) overrides;
# Apply a single variant overlay (variables + sources).
applyVariantOnce =
selected: variant:
let
vVars = if variant ? variables then variant.variables else { };
vSrcs = if variant ? sources then variant.sources else { };
in
{
variables = selected.variables // vVars;
sources = mergeSources selected.sources vSrcs;
};
# Apply platform-specific overrides if present for the given system.
applyPlatforms =
selected: variant: system:
if system == null || !(variant ? platforms) || !(hasAttr system variant.platforms) then
selected
else
let
p = variant.platforms.${system};
pVars = if p ? variables then p.variables else { };
pSrcs = if p ? sources then p.sources else { };
in
{
variables = selected.variables // pVars;
sources = mergeSources selected.sources pSrcs;
};
# Resolve variant chain via inherits (ancestor first), then apply platforms.
resolveVariant =
spec: baseSelected: variantName: system:
if variantName == null || !(spec ? variants) || !(hasAttr variantName spec.variants) then
baseSelected
else
let
v = spec.variants.${variantName};
parentSelected =
if v ? inherits then resolveVariant spec baseSelected v.inherits system else baseSelected;
withVariant = applyVariantOnce parentSelected v;
in
applyPlatforms withVariant v system;
# Render ${var} substitutions in any string within attrs/lists.
renderValue =
value: vars:
if isString value then
let
keys = attrNames vars;
patterns = map (k: "\${" + k + "}") keys;
replacements = map (k: toString (getAttr k vars)) keys;
in
replaceStrings patterns replacements value
else if isAttrs value then
mapAttrs (_: v: renderValue v vars) value
else if isList value then
map (v: renderValue v vars) value
else
value;
# Decide fetcher for URL type based on optional extra.unpack hint.
useFetchZip = comp: comp ? extra && comp.extra ? unpack && comp.extra.unpack == "zip";
# Build a single src from a rendered component spec.
mkSrcFromRendered =
comp:
let
fetcher = if comp ? fetcher then comp.fetcher else "none";
in
if fetcher == "github" then
pkgs.fetchFromGitHub (
{
owner = comp.owner;
repo = comp.repo;
# Allow tag as rev (ignore null/empty tag)
rev = if comp ? tag && comp.tag != null && comp.tag != "" then comp.tag else comp.rev;
fetchSubmodules = if comp ? submodules then comp.submodules else false;
hash = comp.hash;
}
// lib.optionalAttrs (comp ? name) { name = comp.name; }
)
else if fetcher == "git" then
pkgs.fetchgit {
url = comp.url;
rev = comp.rev;
fetchSubmodules = if comp ? submodules then comp.submodules else false;
hash = comp.hash;
}
else if fetcher == "url" then
let
url = if comp ? url then comp.url else comp.urlTemplate;
in
if useFetchZip comp then
pkgs.fetchzip (
{
inherit url;
hash = comp.hash;
}
// lib.optionalAttrs (comp ? extra && comp.extra ? stripRoot) { stripRoot = comp.extra.stripRoot; }
)
else
pkgs.fetchurl {
inherit url;
hash = comp.hash;
}
else if fetcher == "pypi" then
pkgs.python3Packages.fetchPypi {
pname = comp.name;
version = comp.version;
hash = comp.hash;
}
else
# fetcher == "none": pass-through (e.g., linux version/hash consumed by custom logic)
comp;
in
rec {
/*
Select a variant from a loaded version.json specification.
Usage:
let selected = versioning.selectVariant spec variantName system;
- spec: attrset from lib.importJSON ./version.json
- variantName: string or null (when null, uses spec.defaultVariant if present)
- system: string like "x86_64-linux" or null (to apply platforms overrides)
*/
selectVariant =
spec: variantName: system:
let
chosen =
if variantName != null then
variantName
else
(if spec ? defaultVariant then spec.defaultVariant else null);
baseSelected = {
variables = if spec ? variables then spec.variables else { };
sources = if spec ? sources then spec.sources else { };
};
in
resolveVariant spec baseSelected chosen system;
/*
Render ${var} template substitutions across any value using provided variables.
Strings, attrsets, and lists are traversed.
*/
render = value: variables: renderValue value variables;
/*
Render a component with variables and then build its src (or pass-through for fetcher "none").
Prefer using mkAllSources, which handles rendering for all components.
*/
mkSrc =
comp: variables:
let
rendered = renderValue comp variables;
in
mkSrcFromRendered rendered;
/*
Produce an attrset of all sources for a selected spec:
mkAllSources selected
Where:
selected = selectVariant spec variantName system
Returns:
{ componentName = src | renderedComp (for "none"); ... }
*/
mkAllSources =
selected:
mapAttrs (
_name: comp:
if comp ? fetcher && comp.fetcher == "none" then
renderValue comp selected.variables
else
mkSrc (renderValue comp selected.variables) selected.variables
) selected.sources;
# Expose deepMerge for convenience (right-biased).
inherit deepMerge;
}

View File

@@ -1,57 +0,0 @@
{
lib,
options,
namespace,
inputs,
...
}:
{
options.${namespace}.home = with lib.types; {
configFile = lib.mkOption {
type = attrs;
default = { };
description = "A set of files to be managed by home-manager's <option>xdg.configFile</option>.";
};
extraOptions = lib.mkOption {
type = attrs;
default = { };
description = "Options to pass directly to home-manager.";
};
file = lib.mkOption {
type = attrs;
default = { };
description = "A set of files to be managed by home-manager's <option>home.file</option>.";
};
};
config = {
home-manager = {
# enables backing up existing files instead of erroring if conflicts exist
backupFileExtension = "backup";
useGlobalPkgs = true;
useUserPackages = true;
# Pass inputs so external modules can access them
extraSpecialArgs = {
inherit inputs namespace;
# overlays = with inputs; [
# nix-vscode-extensions.overlays.default
# ];
};
# Make ALL external HM modules available globally
sharedModules = with inputs; [
sops-nix.homeManagerModules.sops
nix-plist-manager.homeManagerModules.default
nix-index-database.homeModules.nix-index
stylix.homeModules.stylix
# Add any other external HM modules here
];
users."mattjallen" = lib.mkAliasDefinitions options.${namespace}.home.extraOptions;
verbose = true;
};
};
}

View File

@@ -1,13 +0,0 @@
{ ... }:
{
config = {
programs.ssh.knownHosts = {
desktop = {
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTBMydhOc6SnOdB5WrEd7X07DrboAtagCUgXiOJjLov matt@matt-nixos";
};
nas = {
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIwoHWOLSTGVif9hAhaMLl0qDA4roIzCNuyR6kyIXDOj admin@jallen-nas";
};
};
};
}

View File

@@ -2,11 +2,10 @@
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.gnome;
cfg = config.mjallen.desktop.gnome;
in
{
imports = [ ./options.nix ];
@@ -23,9 +22,7 @@ in
gnomeExtensions.bing-wallpaper-changer
gnomeExtensions.dash-to-dock
gnomeExtensions.dash-to-panel
gnomeExtensions.caffeine
gnomeExtensions.gsconnect
gnomeExtensions.nasa-apod
gnomeExtensions.random-wallpaper
gnomeExtensions.tiling-assistant
gnomeExtensions.user-themes
@@ -56,25 +53,20 @@ in
"org/gnome/shell".enabled-extensions = [
"allowlockedremotedesktop@kamens.us"
"appindicatorsupport@rgcjonas.gmail.com"
"caffeine@patapon.info"
# "user-theme@gnome-shell-extensions.gcampax.github.com"
"user-theme@gnome-shell-extensions.gcampax.github.com"
"tiling-assistant@leleat-on-github"
"dash-to-dock@micxgx.gmail.com"
"BingWallpaper@ineffable-gmail.com"
"gsconnect@andyholmes.github.io"
];
"org/gnome/shell/extensions/bingwallpaper".override-lockscreen-blur = true;
"org/gnome/shell/extensions/bingwallpaper".random-mode-enabled = false;
"org/gnome/shell/extensions/bingwallpaper".selected-image = "current";
"org/gnome/shell/extensions/bingwallpaper".random-mode-enabled = true;
"org/gnome/shell/extensions/bingwallpaper".revert-to-current-image = false;
"org/gnome/shell/extensions/caffeine".enable-fullscreen = true;
"org/gnome/shell/extensions/caffeine".enable-mpris = true;
"org/gnome/shell/extensions/dash-to-panel".primary-monitor = 1;
"org/gnome/shell/extensions/dash-to-panel".multi-monitors = false;
"org/gnome/shell/extensions/gsconnect".id = "4db35bd2-0dcd-42a3-9f77-ef3e8bb83182";
"org/gnome/shell/extensions/gsconnect".name = "matt-nixos";
"org/gnome/shell/extensions/user-theme".name = lib.mkDefault "Colloid-Dark";
"org/gnome/system/location".enabled = true;
"org/gtk/settings/file-chooser".clock-format = "12h";
};
};

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.desktop.gnome = {
options.mjallen.desktop.gnome = {
enable = mkEnableOption "enable gnome settings";
};
}

View File

@@ -0,0 +1,410 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.mjallen.desktop.hyprland;
drawer = "nwg-drawer -fm nautilus -term kitty -mb 10 -mt 10 -ml 10 -mr 10 -pbuseicontheme -i ${cfg.iconThemeName}";
in
{
imports = [
./options.nix
./packages.nix
./theme.nix
./variables.nix
];
config = mkIf cfg.enable {
services = {
hyprpolkitagent.enable = true;
};
programs = {
vscode.profiles.default.userSettings."window"."titleBarStyle" = "custom";
};
wayland.windowManager.hyprland = {
enable = true;
xwayland.enable = true;
systemd.enable = true;
plugins = with pkgs.hyprlandPlugins; [
hyprgrass
];
settings = {
"$mod" = "SUPER";
# Mouse
# mouse_[up|down] - scroll wheel
# middle_mouse - 274
# thumb_up - 276
# thumb_down - 275
# l -> locked, will also work when an input inhibitor (e.g. a lockscreen) is active.
# r -> release, will trigger on release of a key.
# e -> repeat, will repeat when held.
# n -> non-consuming, key/mouse events will be passed to the active window in addition to triggering the dispatcher.
# m -> mouse, see below.
# t -> transparent, cannot be shadowed by other binds.
# i -> ignore mods, will ignore modifiers.
# s -> separate, will arbitrarily combine keys between each mod/key, see [Keysym combos](#keysym-combos) above.
# d -> has description, will allow you to write a description for your bind.
# p -> bypasses the app's requests to inhibit keybinds.
# https://wiki.hyprland.org/Configuring/Binds/
# https://wiki.hyprland.org/Configuring/Binds/#mouse-buttons
bind = [
"$mod, Return, exec, ${cfg.defaultApps.terminal.pname}"
"$mod, SPACE, exec, wofi --show drun"
", xf86Search, exec, wofi --show drun"
"$mod, Q, killactive, "
"$mod, M, exec, wlogout --protocol layer-shell"
"$mod, E, exec, ${cfg.defaultApps.fileExplorer.pname}"
"$mod, V, togglefloating, "
"$mod, D, exec, ${drawer}"
"$mod, P, pseudo, " # dwindle
"$mod, S, togglesplit, " # dwindle
"$mod SHIFT, Q, exec, hyprlock"
"$mod SHIFT, 4, exec, hyprshot -m region --clipboard-only"
"$mod, F, fullscreen, 1"
"$mod SHIFT, F, fullscreen, 0"
"$mod SHIFT, E, exec, smile"
"$mod, mouse:276, movecurrentworkspacetomonitor, ${cfg.display1.input}"
"$mod, mouse:275, movecurrentworkspacetomonitor, ${cfg.display2.input}"
# alt-tab between workspaces on active monitor
"$mod, Tab, workspace, m+1"
"$mod SHIFT, Tab, workspace, m-1"
"$mod, h, movefocus, l"
"$mod, l, movefocus, r"
"$mod, k, movefocus, u"
"$mod, j, movefocus, d"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod ALT, 1, movetoworkspace, 1"
"$mod ALT, 2, movetoworkspace, 2"
"$mod ALT, 3, movetoworkspace, 3"
"$mod ALT, 4, movetoworkspace, 4"
"$mod ALT, 5, movetoworkspace, 5"
"$mod ALT, 6, movetoworkspace, 6"
"$mod ALT, 7, movetoworkspace, 7"
"$mod ALT, 8, movetoworkspace, 8"
"$mod ALT, 9, movetoworkspace, 9"
"$mod ALT, 0, movetoworkspace, discord"
"$mod CTRL, l, resizeactive, 10 0"
"$mod CTRL, h, resizeactive, -10 0"
"$mod CTRL, k, resizeactive, 0 -10"
"$mod CTRL, j, resizeactive, 0 10"
"$mod SHIFT, l, movewindow, r"
"$mod SHIFT, h, movewindow, l"
"$mod SHIFT, k, movewindow, u"
"$mod SHIFT, j, movewindow, d"
"$mod, b, exec, ${cfg.defaultApps.browser.pname}"
];
bindm = [
# Move/resize windows with mod + LMB/RMB and dragging
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
# middle mouse will grab a window, mod + middle mouse will close it
"$mod SHIFT, mouse:274, movewindow"
];
bindel = [
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
];
bindl = [
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioPrev, exec, playerctl previous"
", XF86AudioNext, exec, playerctl next"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86MonBrightnessUp, exec, brightnessctl set +5%"
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
"$mod, XF86MonBrightnessUp, exec, brightnessctl -d kbd_backlight set +10%"
"$mod, XF86MonBrightnessDown, exec, brightnessctl -d kbd_backlight set 10%-"
];
monitor = cfg.monitor;
monitorv2 = cfg.monitorv2 or { };
render = {
cm_fs_passthrough = 1;
};
misc = {
vrr = 1;
};
general = {
gaps_in = 5;
gaps_out = 10;
border_size = 1;
"col.active_border" = "rgb(8aadf4) rgb(24273A) rgb(24273A) rgb(8aadf4) 45deg";
"col.inactive_border" = "rgb(24273A) rgb(24273A) rgb(24273A) rgb(24273A) 45deg";
layout = "dwindle";
allow_tearing = true;
};
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 2;
passes = 2;
new_optimizations = true;
xray = false;
};
# drop_shadow = "yes";
# shadow_range = 4;
# shadow_render_power = "3";
# "col.shadow" = "rgba(1a1a1aee)";
};
animations = {
enabled = "yes";
bezier = [
"overshot, 0.05, 0.9, 0.1, 1.05"
"smoothOut, 0.36, 0, 0.66, -0.56"
"smoothIn, 0.25, 1, 0.5, 1"
];
animation = [
"windows, 1, 5, overshot, slide"
"windowsOut, 1, 4, smoothOut, slide"
"windowsMove, 1, 4, default"
"border, 1, 10, default"
"fade, 1, 10, smoothIn"
"fadeDim, 1, 10, smoothIn"
"workspaces, 1, 6, default"
];
};
dwindle = {
pseudotile = "yes";
preserve_split = "yes";
};
misc = {
force_default_wallpaper = 0;
};
workspace = cfg.workspace;
windowrule = [
"float, title:(file_progress)"
"float, title:(.*[Cc]onfirm.*)"
"float, title:(.*[Dd]ialog.*)"
"float, title:(.*[Dd]ownload.*)"
"float, title:(.*[Nn]otification.*)"
"float, title:(.*[Ee]rror.*)"
"float, title:(.*[Ss]plash.*)"
"float, title:(.*[Cc]onfirmreset.*)"
"float, title:(.*[Ss]ign [Ii]n - .*)"
"float, title:(.*[Oo]pen [Ff]ile.*)"
"float, title:(.*branchdialog.*)"
"float, class:(.*pavucontrol.*)"
"move onscreen cursor 0% 0%, class:(.*pavucontrol.*)"
"float, class:(.*[Oo]verskride.*)"
"float, class:(.*FileRoller.*)"
"float, class:(.*wlogout.*)"
"idleinhibit stayfocused, title:(.*mpv.*)"
"float, class:(.*nm-connection-editor.*)"
"move onscreen cursor 0% 0%, class:(.*nm-connection-editor.*)"
"float, title:(Media viewer)"
"float, class:(it.mijorus.smile),title:(Smile)"
"float, class:(.blueman-manager-wrapped)$,title:(Bluetooth Devices)"
# Picture in picture windows
"float, title:(.*Picture-in-Picture.*)"
"pin, title::(.*Picture-in-Picture.*)"
# discord/vesktop
"workspace: name:discord, class:(.*vesktop)"
"float, class:(.*vesktop),title:(.*Discord Popout.*)"
"pin, class:(.*vesktop),title:(.*Discord Popout.*)"
# Music
"workspace: name:discord, class:(Apple Music.*)"
# Steam
"float, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"workspace name:steam silent, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"tile, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"float, class:(.*steam),title:(.*Friends List.*)"
# Code
"pin, class:(.*codium.*),title:(Save As)"
"float, class:(.*codium.*),title:(Save As)"
"float, class:(xdg-desktop-portal-gtk),title:(Open Workspace from File)"
# Game Tearing??? https://wiki.hyprland.org/Configuring/Tearing/
"immediate, class:(.*gamescope)"
# vmware
# this tag will set the below options to the vdi window
# this will have it auto open as a 2160x7680 window
# and makes multi-monitor work
"tag +horizonrdp, class:(.*[Hh]orizon-client),title:(USPS Next VDI)"
"noanim, tag:horizonrdp"
"noblur, tag:horizonrdp"
"norounding, tag:horizonrdp"
"noshadow, tag:horizonrdp"
"immediate, tag:horizonrdp"
"allowsinput, tag:horizonrdp"
"noborder, tag:horizonrdp"
"nodim, tag:horizonrdp"
"nomaxsize, tag:horizonrdp"
"renderunfocused, tag:horizonrdp"
"idleinhibit, tag:horizonrdp"
"float, tag:horizonrdp"
# "size 2160 7680, tag:horizonrdp"
# "move onscreen 0 0, tag:horizonrdp"
# float the vmware window cause its annoying to use in fullscreen
"float, class:(.*[Hh]orizon-client),title:([Oo]mnissa [Hh]orizon [Cc]lient)"
"tag +waydroid, class:([Ww]aydroid.*)"
"float, tag:waydroid"
"pin, tag:waydroid"
]
++ cfg.windowRule;
plugin = {
touch_gestures = {
# The default sensitivity is probably too low on tablet screens,
# I recommend turning it up to 4.0
sensitivity = "4.0";
# must be >= 3
workspace_swipe_fingers = "3";
# switching workspaces by swiping from an edge, this is separate from workspace_swipe_fingers
# and can be used at the same time
# possible values: l, r, u, or d
# to disable it set it to anything else
workspace_swipe_edge = "d";
# in milliseconds
long_press_delay = "400";
# resize windows by long-pressing on window borders and gaps.
# If general:resize_on_border is enabled, general:extend_border_grab_area is used for floating
# windows
resize_on_border_long_press = true;
# in pixels, the distance from the edge that is considered an edge
edge_margin = "10";
# emulates touchpad swipes when swiping in a direction that does not trigger workspace swipe.
# ONLY triggers when finger count is equal to workspace_swipe_fingers
#
# might be removed in the future in favor of event hooks
emulate_touchpad_swipe = false;
experimental = {
# send proper cancel events to windows instead of hacky touch_up events,
# NOT recommended as it crashed a few times, once it's stabilized I'll make it the default
send_cancel = "0";
};
hyprgrass-bind = [
# swipe left from right edge
", edge:r:l, workspace, +1"
# swipe up from bottom edge
", edge:d:u, exec, ${cfg.defaultApps.browser.pname}"
# swipe down from left edge
", edge:l:d, exec, pactl set-sink-volume @DEFAULT_SINK@ -4%"
# swipe down with 4 fingers
", swipe:4:d, killactive"
# swipe diagonally left and down with 3 fingers
# l (or r) must come before d and u
", swipe:3:ld, exec, foot"
# tap with 3 fingers
", tap:3, exec, foot"
# longpress can trigger mouse binds:
", longpress:2, movewindow"
", longpress:3, resizewindow"
];
};
};
gestures = {
workspace_swipe = true;
workspace_swipe_cancel_ratio = "0.15";
};
input = {
kb_layout = "us";
kb_variant = "";
kb_model = "";
kb_options = "";
kb_rules = "";
numlock_by_default = true;
follow_mouse = 1;
touchpad = {
clickfinger_behavior = 1;
natural_scroll = "yes";
};
sensitivity = 0; # -1.0 - 1.0, 0 means no modification.
};
experimental = {
xx_color_management_v4 = true;
};
debug = {
full_cm_proto = true;
disable_logs = true;
disable_scale_checks = true;
};
};
extraConfig = ''
exec-once = dbus-update-activation-environment --systemd --all
exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
exec-once = xhost +SI:localuser:root
exec-once = nwg-look -a
exec-once = nwg-dock-hyprland -d
''
+ cfg.extraConfig or '''';
};
};
}

View File

@@ -0,0 +1,147 @@
{ lib, pkgs, ... }:
with lib;
{
options.mjallen.desktop.hyprland = {
enable = mkEnableOption "enable hyprland desktop";
primaryDisplay = mkOption {
type = types.str;
default = "DP-1";
};
display1 = {
input = mkOption {
type = types.str;
default = "DP-1";
};
resolution = mkOption {
type = types.str;
default = "3840x2160";
};
refreshRate = mkOption {
type = types.str;
default = "240.00000";
};
};
display2 = {
input = mkOption {
type = types.str;
default = "DP-1";
};
resolution = mkOption {
type = types.str;
default = "3840x2160";
};
refreshRate = mkOption {
type = types.str;
default = "240.00000";
};
};
wallpaper = mkOption {
type = with types; listOf str;
default = [ ];
description = "list of hyprland wallpaper configs";
};
monitor = mkOption {
type = with types; listOf str;
default = [ ];
description = "list of hyprland monitor configs";
};
monitorv2 = mkOption {
type = with types; listOf str;
default = [ ];
description = "list of hyprland monitorv2 configs";
};
workspace = mkOption {
type = with types; listOf str;
default = [ ];
description = "list of hyprland workspace definitions";
};
windowRule = mkOption {
type = with types; listOf str;
default = [ ];
description = "list of hyprland window rules";
};
extraConfig = mkOption {
type = with types; str;
default = '''';
description = "any extra options";
};
iconThemeName = mkOption {
type = types.str;
default = "Colloid-Dark";
};
gtkThemeName = mkOption {
type = types.str;
default = "Colloid-Dark";
};
defaultApps = mkOption {
type = types.submodule {
options = {
browser = mkOption {
type = types.package;
default = pkgs.firefox;
};
editor = mkOption {
type = types.package;
default = pkgs.micro;
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nemo;
};
visual = mkOption {
type = types.package;
default = pkgs.vscodium;
};
terminal = mkOption {
type = types.package;
default = pkgs.kitty;
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-bin_latest;
};
video = mkOption {
type = types.package;
default = pkgs.vlc;
};
imageViewer = mkOption {
type = types.package;
default = pkgs.nomacs;
};
};
};
description = "Default applications used across the system.";
};
hyprIdle = {
lockScreenTimer = mkOption {
type = with types; int;
default = 300;
};
screenOffTimer = mkOption {
type = with types; int;
default = 900;
};
suspendTimer = mkOption {
type = with types; int;
default = 1800;
};
};
};
}

View File

@@ -0,0 +1,74 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.mjallen.desktop.hyprland;
in
{
config = mkIf cfg.enable {
home.packages = with pkgs; [
box64
brightnessctl
ddcutil
dunst
egl-wayland
file-roller
glib
gnome-calculator
gnome-calendar
gnome-disk-utility
gnome-firmware
gnome-firmware-updater
gnome-font-viewer
gnome-logs
gnome-photos
gnome-tweaks
gnome-weather
gsettings-desktop-schemas
hyprcursor
hyprland
hyprpaper
hyprshot
hyprsysteminfo
kdePackages.qtmultimedia
libnotify
libz
mako
meson
nautilus
networkmanagerapplet
nm-tray
nomacs
nwg-look
overskride
pamixer
pavucontrol
playerctl
polkit
polkit_gnome
qt5.qtwayland
qt6.qtwayland
rofi-wayland
waybar
wayland-protocols
wayland-utils
waypaper
wev
wl-clipboard
wlogout
wlroots
xdg-desktop-portal-hyprland
xdg-desktop-portal-gtk
xdg-desktop-portal-wlr
xorg.xhost
xsettingsd
xwayland
pkgs.mjallen.pipewire-python
];
};
}

View File

@@ -0,0 +1,46 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.hyprland;
in
{
imports = [ ../../options.nix ];
config = lib.mkIf cfg.enable {
services.hypridle = {
enable = true;
settings = {
general = {
before_sleep_cmd = "loginctl lock-session"; # lock before suspend.
after_sleep_cmd = "hyprctl dispatch dpms on"; # to avoid having to press a key twice to turn on the display.
ignore_dbus_inhibit = false;
lock_cmd = "pidof hyprlock || hyprlock"; # avoid starting multiple hyprlock instances.
};
listener = [
# {
# timeout = 300; # 5min
# on-timeout = "brightnessctl -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor.
# on-resume = "brightnessctl -r"; # monitor backlight restore.
# }
{
timeout = cfg.hyprIdle.lockScreenTimer;
on-timeout = "loginctl lock-session"; # lock screen when timeout has passed
}
{
timeout = cfg.hyprIdle.screenOffTimer;
on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed
on-resume = "hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired.
}
{
timeout = cfg.hyprIdle.suspendTimer;
on-timeout = "systemctl suspend"; # suspend pc
}
];
};
};
};
}

View File

@@ -0,0 +1,52 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.hyprland;
in
{
imports = [ ../../options.nix ];
config = lib.mkIf cfg.enable {
programs.hyprlock = {
enable = true;
settings = {
background = [
{
monitor = "";
path = cfg.wallpaper; # supports png, jpg, webp (no animations, though)
color = "rgba(25, 20, 20, 1.0)";
# all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations
blur_passes = "3"; # 0 disables blurring
blur_size = "7";
noise = "0.0117";
contrast = "0.8916";
brightness = "0.8172";
vibrancy = "0.1696";
vibrancy_darkness = "0.0";
}
];
input-field = [
{
size = "200, 50";
position = "0, -80";
monitor = cfg.primaryDisplay;
dots_center = true;
fade_on_empty = true;
font_color = "rgb(202, 211, 245)";
inner_color = "rgb(91, 96, 120)";
outer_color = "rgb(24, 25, 38)";
bothlock_color = -1;
outline_thickness = 5;
placeholder_text = ''<span foreground="##cad3f5">Password...</span>'';
shadow_passes = 2;
}
];
};
};
};
}

View File

@@ -0,0 +1,23 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.desktop.hyprland;
in
{
imports = [ ../../options.nix ];
config = lib.mkIf cfg.enable {
services.hyprpaper = {
enable = true;
settings = {
preload = [ "/run/wallpaper.jpg" ];
wallpaper = ",/run/wallpaper.jpg";
splash = false;
};
};
};
}

View File

@@ -0,0 +1,103 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.mjallen.desktop.hyprland;
themeSize = "compact"; # [ "standard" "compact" ]
themeAccent = "all"; # [ "default" "purple" "pink" "red" "orange" "yellow" "green" "teal" "grey" "all" ]
themeVariant = "nord"; # [ "nord" "dracula" "gruvbox" "everforest" "catppuccin" "all" "black" "rimless" "normal" "float" ]
themeColor = "dark"; # [ "standard" "light" "dark" ]
iconThemeVariant = "all"; # [ "default" "purple" "pink" "red" "orange" "yellow" "green" "teal" "grey" "all" ]
iconScheme = "nord"; # [ "default" "nord" "dracula" "gruvbox" "everforest" "catppuccin" "all" ]
# Cursor
cursorTheme = "macOS";
cursorThemePkg = pkgs.apple-cursor;
cursorSize = 24;
# GTK
# gtkThemeSize = themeSize;
# gtkThemeAccent = themeAccent;
# gtkThemeVariant = themeVariant;
# gtkThemeColor = themeColor;
gtkTheme = "Colloid-Dark-Compact-Nord";
gtkThemePkg = pkgs.colloid-gtk-theme.override {
sizeVariants = [ themeSize ];
colorVariants = [ themeColor ];
themeVariants = [ themeAccent ];
tweaks = [ themeVariant ];
};
# Icons
# iconThemeScheme = iconScheme;
iconTheme = "Colloid-Nord-Dark";
iconThemePkg = pkgs.colloid-icon-theme.override {
schemeVariants = [ iconScheme ];
colorVariants = [ iconThemeVariant ];
};
# Fonts
fontName = "JetBrainsMono NFM";
fontPackage = pkgs.nerd-fonts.jetbrains-mono;
fontSize = 12;
in
{
config = mkIf cfg.enable {
home = {
pointerCursor = {
gtk.enable = true;
package = cursorThemePkg;
name = cursorTheme;
size = cursorSize;
};
};
dconf = {
enable = true;
settings = {
"org/gnome/desktop/interface".color-scheme = "prefer-dark";
"org/gnome/desktop/interface".cursor-theme = cursorTheme;
"org/gnome/desktop/interface".gtk-theme = gtkTheme;
"org/gnome/desktop/interface".icon-theme = iconTheme;
};
};
gtk = {
enable = true;
cursorTheme = {
name = cursorTheme;
package = cursorThemePkg;
};
theme = {
name = gtkTheme;
package = gtkThemePkg;
};
iconTheme = {
name = iconTheme;
package = iconThemePkg;
};
gtk3.extraConfig = {
gtk-application-prefer-dark-theme = true;
};
gtk4.extraConfig = {
gtk-application-prefer-dark-theme = true;
};
font = {
name = fontName;
package = fontPackage;
size = fontSize;
};
};
};
}

View File

@@ -0,0 +1,39 @@
{ config, lib, ... }:
with lib;
let
cfg = config.mjallen.desktop.hyprland;
in
{
config = mkIf cfg.enable {
home.sessionVariables = {
BROWSER = "${cfg.defaultApps.browser.pname}";
CLUTTER_BACKEND = "wayland";
EDITOR = "${cfg.defaultApps.editor.pname}";
VISUAL = "${cfg.defaultApps.visual.pname}";
ICON_THEME = cfg.iconThemeName;
GTK_CSD = "0";
GTK_THEME = cfg.gtkThemeName;
GTK_USE_PORTAL = "1";
HYPRCURSOR_THEME = config.home.pointerCursor.name;
HYPRCURSOR_SIZE = config.home.pointerCursor.size;
MOZ_ENABLE_WAYLAND = "1";
NIXOS_OZONE_WL = "1";
NIXOS_XDG_OPEN_USE_PORTAL = "1";
QT_AUTO_SCREEN_SCALE_FACTOR = "1";
QT_QPA_PLATFORM = "wayland-egl";
QT_QPA_PLATFORMTHEME = "gtk3";
QT_SCALE_FACTOR = "1";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
SDL_VIDEODRIVER = "wayland";
TERMINAL = "${cfg.defaultApps.terminal.pname}";
XCURSOR_THEME = config.home.pointerCursor.name;
XCURSOR_SIZE = config.home.pointerCursor.size;
XDG_CACHE_HOME = "\${HOME}/.cache";
XDG_CONFIG_HOME = "\${HOME}/.config";
XDG_CURRENT_DESKTOP = "Hyprland";
XDG_DATA_HOME = "\${HOME}/.local/share";
XDG_SESSION_DESKTOP = "Hyprland";
XDG_SESSION_TYPE = "wayland";
};
};
}

View File

@@ -0,0 +1,62 @@
{
# Nord colors
# Opacity Hex alpha
# 100% FF
# 75% BF
# 50% 80
# 25% 40
# 10% 1A
# 0% 00
polarNight = {
nord0 = "#2e3440";
nord1 = "#3b4252";
nord2 = "#434c5e";
nord3 = "#4c566a";
};
snowStorm = {
nord4 = "#d8dee9";
nord5 = "#e5e9f0";
nord6 = "#eceff4";
};
frost = {
nord7 = "#8fbcbb";
nord8 = "#88c0d0";
nord9 = "#81a1c1";
nord10 = "#5e81ac";
};
aurora = {
nord11 = "#bf616a";
nord12 = "#d08770";
nord13 = "#ebcb8b";
nord14 = "#a3be8c";
nord15 = "#b48ead";
};
defaultOpacity = "opacity: 0.85;";
defaultBorderRadius = "border-radius: 1rem;";
defaultCenterOptions = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
'';
borderRight = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
border-radius: 0rem 1rem 1rem 0rem;
margin-right: 0.5rem;
'';
borderLeft = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
border-radius: 1rem 0rem 0rem 1rem;
margin-left: 0.5rem;
'';
}

View File

@@ -1,79 +0,0 @@
{ ... }:
{
programs = {
gpg = {
enable = true;
scdaemonSettings = {
disable-ccid = true;
pcsc-shared = true;
};
publicKeys = [
{
text = ''
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGipyhUBEADCal3wKbTCJHZ7qBTxe2zrJPGV9vu6V4+x/MBQq07jd33RrdgI
5R/YSviZLyTjY84xk+XTpxWe6PNxcrNlPrJgqR48UNYiG7rH2VWg073KQZaAEeX4
DRmfANtds9m9N9CadMv1XcHvVkEz+UlD3yYGNwrd1ZnWVBpUobIyZvFrVjpGBtOg
jgW3NepPn9SfguF+PV4t3Tn2iAFsDa/U3RpkMvYtfxgtxJPvbaVNc3Zq7UDWaXta
zZ7y/o5figLUn3q/2JrbzeXmNpShkTixXJHJwSjoD/27I6fVFz4EfwkBfyo8B9yX
goekY00wym0oIT2Jb5ZLFh8b60mX/ezUJcMhDkqTG77caRDRxw76yVxc0Jp+r+xZ
3ckcrdm+/UtnnD3VO0ktvhb4pU93Pj0PJhrm7qVZS/SEJ67vUx8Aem3aMWgSRsl5
51h08US7yfPaMNqKX9d2KaLSTGnQ2BSoXJEmbIqvlvazUTqVk85TDWZEYXgc2S2K
phyDfJiVmmUWekgrYE/Fyx0QJkCA6z8cNQWwpRe7oJG1VrnRjhIcuL+EpJb9Ytd9
NT39/6/rBot2iGmn64vdyqirji2shuLwrp34A9KWY3XUC5zv0GlHCFsF8lraFzKz
AsYv2cLRRja4kyuzoSwoHgXYu1MsifZHgF2+Y0sFW+odRqlo0A9ziXkB9QARAQAB
tCNNYXR0aGV3IEphbGxlbiA8amFsbGUwMDhAcHJvdG9uLm1lPokCVwQTAQgAQRYh
BMvLmximuJMLC2q/0cy4y+swYzaEBQJoqcoVAhsDBQkSzAMABQsJCAcCAiICBhUK
CQgLAgQWAgMBAh4HAheAAAoJEMy4y+swYzaEsrkP/3c/kW0QNv79dEgEHhpJy7nP
XyB8fTGr804Gq0ffaPgmn0G8iNzg9pgjgrA8oHpoP0ZbmKaO7JkpHsS0+fpMNuFE
dhthWgsYLAnC6rZb4Ib/b+wbUH19CJJIt6Rj9uqH3vDCxeG5TfiJnVA+x3O6VaM1
K2oyrXaXDrUKxFlLlnMOsdfRZwXoyYPuJm8Lip5GawIakHGV17FdwdZOcfy0JtdH
CwI0K5D390lQ2WNjIJx0vI8E3QYubciOjDzS+KNB12q4sSY6O3fKTXsi80JZ/y4C
z1dwsRxMlndBbK1SBJFmczRy4dZC0WbNaxEF2qnM7RENDpB+73HQ1/mSsFaTu609
9clDDjwCAUu4UrbL5veWLB+b+xUNy6Sgkbal1Q+pgGSTF9H8plGN0ymijC9xNmvX
JeeSTvfnzAThiJubIpZYLkoMmlyEiGrc4CQDdfbsVR9xFGZcau5akcW3e45kiOZC
is1H55HsXlBpezanvJCnX7ZEQlRP8vdquHADvgERf3D/qlVAgD/lGE8bzBKJxt1P
kxXvGZFxF0BCN/GCoYib1w3WJeTyxGlf9wHkwa/COjasEBGzsnkLToET637WdmHr
hgnTVm6CQQW4EUw6gOznDNQvd1EipAwJB7iEm2PneEAwauWeQN38+hc7QVIEqXRk
wdfxlU/9WD+rh6FfQ7d3uQINBGipyhUBEADUGJQW/FUWo3R6X7+Quv3TqZfVXJB/
bjX9Uv8SKOomUBAjQK9TklaZJvNiaD4qYV93kPfpclGhxdGahXVBC7SdGenaFig4
4WwUe5vrKIGbbfcC+dBW/8eAqueKjCWe6wFqXbKat1/4Y1atsFZX5Lf/GEi1VNXu
0NkSPKAqTdXyXrTuC7D5wARGdavbxO3BcF1NqpIPHiROQoOyP10jx8xcMYGoVIIr
uscckoqhdbyEua9m9zFesYyqiCfJeSCK8O4w7BU3dgHUz53hfeuNuGBPb/dQ9Ent
qKwrMxsPWJC9qN19Wvvsgy89QLn0CWmcUsmc/f4mWnKoSH9AZCuVCSgoSjknXGj0
MPBI6jY1gaqZAuyMH24ekUAdUtNK5IuPPPxrlE1ljAWSxvFGG7Dj4p78ELJizlT7
XXOtAPggwCFfXauQD+v43ILg5Zxz6fjTd0TZ8iSypqiZIQgQoiUUGcDZmjHhRHNj
GHlqmRECyef6mZVhb3zlyzAcQycnZvHtXFMmyrvfFs21pX9WEF3lQFDapnMAwODE
2BLQWrh2ed++/An3DJOh/Iwv9WBatDagMObJi3lsUszJ0l5iwteJOfXMR72zV+m7
7QzaEdGFDlNRSMmtjni7FLWbDA/CkihRsUtqgrXgj91oqLga0GmjlNnIZGwhcDUx
Yuo+kIRRM4DSDwARAQABiQI8BBgBCAAmFiEEy8ubGKa4kwsLar/RzLjL6zBjNoQF
AmipyhUCGwwFCRLMAwAACgkQzLjL6zBjNoS5/Q//SPmdM26wUq50A8QTuQ3r8xpc
3oGCdBAP7QJk6+W1kJcGVP4r2bFylbWUGyHWuhKTs47r6fh3Sd9MtmGQgtEEbGFW
a4pxaYBRPYGHvJuVwb4IvOzDuVj8yabk0c688jz2Wv1DW3+z4623TI2JeOfEoOqg
u4DGySVZkXA/F01HShP0QsGEGRkklEvysD101GbJrQuQ6ssHiFVF1m+/w+I8fYzP
F9BC61DOEabm62YjELf/xvKQ6aT8rB0F2p9udOmIlw9lkAJMsEz4mB5f4Bq/1vGt
aZ7K0tytT3aeTFFgLwtBPcjWvHavEp4/CDXUL58v/X5R+E6Z03zsWwspsACacblq
RW15f3aKI2j7u/w6oJ/iJbEXtZq/Hv1XACyZ/kD9WcYIPsNikCS6vSsnj9Hk/o88
yG0rQ6v9L7s9gqWm1IajnDQD6g7n3H4pXGJsE4sBGg6FfE0OJDcd4VqZGJGMz9rr
+V+3zUxs/RIVWTCdoVPTLBWrtsKbwObgE7SdkaUt4/1uhtdkR++brhr2uz3il0Kt
2QZAXJDcK2xzcOEz41lhclgMxUzjYTggQvpD8lu70xlGqgm94NJCBctPx6xJAN9f
H6dELHDuLAwB+vKB9YJIvMVaPNKRam8wGnZ0EKHUFvmIqqSOE8GR1LmgslYRNidv
ywgEIPcOpJGzt3TQprM=
=i8do
-----END PGP PUBLIC KEY BLOCK-----
'';
trust = "ultimate";
}
];
};
};
services = {
gpg-agent = {
enable = true;
enableZshIntegration = true;
enableSshSupport = true;
};
};
}

View File

@@ -2,76 +2,53 @@
config,
lib,
pkgs,
namespace,
hasDestopEnvironment ? true,
...
}:
let
inherit (lib.${namespace}) enabled;
in
{
home = {
enableNixpkgsReleaseCheck = lib.mkDefault false;
homeDirectory = lib.mkDefault "/home/${config.home.username}";
packages =
with pkgs;
[
age
clinfo
cpufetch
dbus
deadnix
lm_sensors
nano
nix-prefetch-scripts
nixfmt
pciutils
protonup-ng
rsync
smartmontools
sops
tailscale
tree
usbutils
vim
vulkan-tools
wget
]
++ (
if hasDestopEnvironment then
[
boxbuddy
stable.chromium
firefox
gamescope
gamescope-wsi
gparted
pkgs.unstable.goverlay
mission-center
parted
vesktop
# winboat
]
else
[ ]
);
packages = with pkgs; [
age
chromium
clinfo
cpufetch
deadnix
firefox
gamescope
gamescope-wsi
goverlay
gparted
lm_sensors
mission-center
nano
nixfmt-rfc-style
pciutils
protonup
rsync
smartmontools
sops
tailscale
tree
usbutils
vesktop
vim
vulkan-tools
wget
];
stateVersion = lib.mkDefault "23.11";
};
programs = {
nix-index-database.comma = enabled;
btop = {
enable = lib.mkDefault true;
package = pkgs.unstable.btop;
};
fastfetch = lib.mkDefault enabled;
home-manager = lib.mkDefault enabled;
btop.enable = lib.mkDefault true;
fastfetch.enable = lib.mkDefault true;
home-manager.enable = lib.mkDefault true;
java = {
enable = lib.mkDefault true;
};
mangohud.enable = lib.mkDefault hasDestopEnvironment;
password-store = enabled;
mangohud.enable = lib.mkDefault true;
password-store.enable = true;
nh = {
enable = true;
flake = "/etc/nixos";
@@ -133,12 +110,11 @@ in
};
services = {
nextcloud-client.enable = false; # lib.mkDefault hasDestopEnvironment;
pass-secret-service = lib.mkDefault enabled;
nextcloud-client.enable = lib.mkDefault true;
pass-secret-service.enable = lib.mkDefault true;
kdeconnect = {
enable = lib.mkDefault hasDestopEnvironment;
indicator = lib.mkDefault hasDestopEnvironment;
package = pkgs.kdePackages.kdeconnect-kde;
enable = lib.mkDefault true;
indicator = lib.mkDefault true;
};
};
}

View File

@@ -1,12 +1,8 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.btop;
cfg = config.mjallen.programs.btop;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -14,6 +10,8 @@ in
programs.btop = {
enable = true;
settings = {
color_theme = "nord"; # todo
theme_background = true;
truecolor = true;
force_tty = false;
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty";
@@ -77,6 +75,52 @@ in
selected_battery = "Auto";
log_level = "WARNING";
};
themes = {
nord = ''
theme[main_bg]="${nord.polarNight.nord0}"
theme[main_fg]="${nord.snowStorm.nord6}"
theme[title]="${nord.snowStorm.nord6}"
theme[hi_fg]="${nord.frost.nord7}"
theme[selected_bg]="${nord.polarNight.nord1}"
theme[selected_fg]="${nord.frost.nord7}"
theme[inactive_fg]="${nord.polarNight.nord2}"
theme[graph_text]="${nord.snowStorm.nord6}"
theme[meter_bg]="${nord.polarNight.nord1}"
theme[proc_misc]="${nord.snowStorm.nord6}"
theme[cpu_box]="${nord.aurora.nord15}"
theme[mem_box]="${nord.aurora.nord14}"
theme[net_box]="${nord.aurora.nord12}"
theme[proc_box]="${nord.aurora.nord11}"
theme[div_line]="${nord.polarNight.nord1}"
theme[temp_start]="${nord.aurora.nord14}"
theme[temp_mid]="${nord.aurora.nord13}"
theme[temp_end]="${nord.aurora.nord11}"
theme[cpu_start]="${nord.aurora.nord15}"
theme[cpu_mid]="${nord.aurora.nord12}"
theme[cpu_end]="${nord.aurora.nord11}"
theme[free_start]="${nord.aurora.nord14}"
theme[free_mid]="${nord.aurora.nord13}"
theme[free_end]="${nord.aurora.nord12}"
theme[cached_start]="${nord.aurora.nord14}"
theme[cached_mid]="${nord.aurora.nord13}"
theme[cached_end]="${nord.aurora.nord12}"
theme[available_start]="${nord.snowStorm.nord6}"
theme[available_mid]="${nord.aurora.nord11}"
theme[available_end]="${nord.aurora.nord11}"
theme[used_start]="${nord.aurora.nord14}"
theme[used_mid]="${nord.aurora.nord13}"
theme[used_end]="${nord.aurora.nord11}"
theme[download_start]="${nord.frost.nord8}"
theme[download_mid]="${nord.frost.nord8}"
theme[download_end]="${nord.aurora.nord12}"
theme[upload_start]="${nord.frost.nord7}"
theme[upload_mid]="${nord.frost.nord7}"
theme[upload_end]="${nord.aurora.nord12}"
theme[process_start]="${nord.aurora.nord15}"
theme[process_mid]="${nord.aurora.nord12}"
theme[process_end]="${nord.aurora.nord11}"
'';
};
};
};
}

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.btop = {
options.mjallen.programs.btop = {
enable = mkEnableOption "enable btop";
};
}

View File

@@ -3,26 +3,19 @@
pkgs,
system,
namespace,
hasDestopEnvironment ? true,
...
}:
let
isArm = ("aarch64-linux" == system) || ("aarch64-darwin" == system);
isArm = "aarch64-linux" == system;
x86_only = with pkgs; [
vscode-extensions.redhat.vscode-xml
];
open-remote-ssh = pkgs.${namespace}.open-remote-ssh;
in
{
home.packages = with pkgs; [
nodePackages.nodejs
uv
];
programs = {
vscode = {
enable = hasDestopEnvironment;
enable = true;
package = pkgs.vscodium;
mutableExtensionsDir = false;
profiles = {
@@ -36,7 +29,7 @@ in
vscode-extensions.bbenoist.nix
vscode-extensions.brettm12345.nixfmt-vscode
vscode-extensions.cweijan.vscode-database-client2
# vscode-extensions.dendron.dendron-markdown-preview-enhanced
vscode-extensions.dendron.dendron-markdown-preview-enhanced
vscode-extensions.jnoortheen.nix-ide
vscode-extensions.mkhl.direnv
vscode-extensions.ms-python.debugpy

View File

@@ -14,12 +14,8 @@ in
{
programs.git = {
enable = true;
settings = {
user = {
name = "mjallen18";
email = "matt.l.jallen@gmail.com";
};
alias = gitAliases;
};
userName = "mjallen18";
userEmail = "matt.l.jallen@gmail.com";
aliases = gitAliases;
};
}

View File

@@ -1,25 +0,0 @@
{
config,
namespace,
lib,
...
}:
let
cfg = config.${namespace}.programs.hyprland;
in
{
config = lib.mkIf cfg.enable {
services.avizo = {
enable = true;
settings = {
default = {
time = 1.0;
y-offset = 0.5;
fade-in = 0.1;
fade-out = 0.2;
padding = 10;
};
};
};
};
}

View File

@@ -1,710 +0,0 @@
{
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.programs.hyprland;
drawer = "nwg-drawer -fm nautilus -term kitty -mb 10 -mt 10 -ml 10 -mr 10 -pbuseicontheme -i ${config.stylix.icons.dark}";
in
{
imports = [
./avizo.nix
./options.nix
];
config = mkIf cfg.enable {
# Home packages
home.packages =
with pkgs;
(
[
box64
brightnessctl
ddcutil
egl-wayland
file-roller
glib
gnome-calculator
gnome-calendar
gnome-disk-utility
gnome-firmware
gnome-font-viewer
gnome-logs
gnome-photos
gnome-tweaks
gnome-weather
gsettings-desktop-schemas
hyprcursor
hyprland
hyprpaper
hyprshot
hyprsysteminfo
kdePackages.qtmultimedia
libnotify
libz
meson
nautilus
nomacs
nwg-look
overskride
pamixer
pavucontrol
playerctl
qt5.qtwayland
qt6.qtwayland
waybar
wayland-protocols
wayland-utils
waypaper
wev
wl-clipboard
wlogout
wlroots
xorg.xhost
xsettingsd
xwayland
]
++ (if cfg.notificationDaemon == "mako" then [ mako ] else [ dunst ])
++ (if cfg.launcher == "wofi" then [ wofi ] else [ rofi ])
++ (with pkgs.${namespace}; [ pipewire-python ])
);
# Session variables
home.sessionVariables = {
BROWSER = "${cfg.defaultApps.browser.pname}";
CLUTTER_BACKEND = "wayland";
EDITOR = "${cfg.defaultApps.editor.pname}";
VISUAL = "${cfg.defaultApps.visual.pname}";
ICON_THEME = config.gtk.iconTheme.name;
GTK_CSD = "0";
GTK_THEME = config.gtk.theme.name;
GTK_USE_PORTAL = "1";
HYPRCURSOR_THEME = config.stylix.cursor.name;
HYPRCURSOR_SIZE = config.stylix.cursor.size;
MOZ_ENABLE_WAYLAND = "1";
NIXOS_OZONE_WL = "1";
NIXOS_XDG_OPEN_USE_PORTAL = "1";
QT_AUTO_SCREEN_SCALE_FACTOR = "1";
QT_QPA_PLATFORM = "wayland-egl";
QT_QPA_PLATFORMTHEME = lib.mkDefault "gtk3";
QT_SCALE_FACTOR = "1";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
SDL_VIDEODRIVER = "wayland";
TERMINAL = "${cfg.defaultApps.terminal.pname}";
XCURSOR_THEME = config.stylix.cursor.name;
XCURSOR_SIZE = config.stylix.cursor.size;
XDG_CACHE_HOME = "\${HOME}/.cache";
XDG_CONFIG_HOME = "\${HOME}/.config";
XDG_CURRENT_DESKTOP = "Hyprland";
XDG_DATA_HOME = "\${HOME}/.local/share";
XDG_SESSION_DESKTOP = "Hyprland";
XDG_SESSION_TYPE = "wayland";
};
# Services
services = {
hyprpolkitagent.enable = true;
hyprpaper = {
enable = true;
settings = {
preload = [ cfg.hyprpaper.wallpaperPath ];
wallpaper = [
{
monitor = "";
path = cfg.hyprpaper.wallpaperPath;
}
];
splash = false;
};
};
hypridle = {
enable = true;
settings = {
general = {
before_sleep_cmd = "loginctl lock-session"; # lock before suspend.
after_sleep_cmd = "hyprctl dispatch dpms on"; # to avoid having to press a key twice to turn on the display.
ignore_dbus_inhibit = false;
lock_cmd = "pidof hyprlock || hyprlock"; # avoid starting multiple hyprlock instances.
};
listener = [
# {
# timeout = 300; # 5min
# on-timeout = "brightnessctl -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor.
# on-resume = "brightnessctl -r"; # monitor backlight restore.
# }
{
timeout = cfg.hyprIdle.lockScreenTimer;
on-timeout = "loginctl lock-session"; # lock screen when timeout has passed
}
{
timeout = cfg.hyprIdle.screenOffTimer;
on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed
on-resume = "hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired.
}
{
timeout = cfg.hyprIdle.suspendTimer;
on-timeout = "systemctl suspend"; # suspend pc
}
];
};
};
};
# Programs
programs = {
vscode.profiles.default.userSettings."window"."titleBarStyle" = "custom";
hyprlock = {
enable = true;
settings = {
background = mkForce [
{
monitor = "";
path = "/run/wallpaper.jpg"; # supports png, jpg, webp (no animations, though)
color = mkDefault "rgba(25, 20, 20, 1.0";
# all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations
blur_passes = mkDefault "3"; # 0 disables blurring
blur_size = mkDefault "7";
noise = "0.0117";
contrast = "0.8916";
brightness = mkDefault "0.8172";
vibrancy = "0.1696";
vibrancy_darkness = "0.0";
}
];
label = [
# Date display
{
monitor = cfg.primaryDisplay;
text = "cmd[update:1000] echo -e \"$(LC_TIME=en_US.UTF-8 date +\"%A, %B %d\")\"";
color = config.lib.stylix.colors.base06;
font_size = "25";
font_family = lib.mkDefault config.stylix.fonts.monospace.name;
position = "0, 350";
halign = "center";
valign = "center";
}
# Time display
{
monitor = cfg.primaryDisplay;
text = "cmd[update:1000] echo \"<span>$(date +\"%I:%M\")</span>\"";
color = config.lib.stylix.colors.base06;
font_size = "120";
font_family = lib.mkDefault "${config.stylix.fonts.monospace.name} Bold";
position = "0, 230";
halign = "center";
valign = "center";
}
{
monitor = cfg.primaryDisplay;
text = "$USER";
color = config.lib.stylix.colors.base06;
outline_thickness = 2;
dots_size = 0.2;
dots_spacing = 0.2;
dots_center = true;
font_size = 18;
font_family = lib.mkDefault "${config.stylix.fonts.monospace.name} Bold";
position = "0, 0";
halign = "center";
valign = "center";
}
# weather
{
monitor = cfg.primaryDisplay;
text = "cmd[update:30000] waybar-weather --hyprlock";
color = config.lib.stylix.colors.base06;
font_size = "25";
font_family = lib.mkDefault config.stylix.fonts.monospace.name;
position = "-100, 100";
halign = "right";
valign = "bottom";
}
# media
{
monitor = cfg.primaryDisplay;
text = "cmd[update:1000] waybar-media";
color = config.lib.stylix.colors.base06;
font_size = "15";
font_family = lib.mkDefault config.stylix.fonts.monospace.name;
position = "100, 100";
halign = "left";
valign = "bottom";
}
];
# user box
shape = [
{
monitor = cfg.primaryDisplay;
size = "200, 50";
color = "rgba(46, 52, 64, .25";
rounding = -1;
border_size = "0";
position = "0, 0";
halign = "center";
valign = "center";
}
];
input-field = [
{
size = "200, 50";
position = "0, -80";
font_family = lib.mkDefault config.stylix.fonts.monospace.name;
monitor = cfg.primaryDisplay;
dots_center = true;
fade_on_empty = true;
font_color = config.lib.stylix.colors.base06;
inner_color = config.lib.stylix.colors.base03;
outer_color = config.lib.stylix.colors.base00;
bothlock_color = -1;
outline_thickness = 5;
placeholder_text = ''<span foreground="#${config.lib.stylix.colors.base00}">Password...</span>'';
shadow_passes = 2;
}
];
image = [
{
monitor = cfg.primaryDisplay;
# path = "/tmp/hyprlock-art";
reload_cmd = "waybar-media-art";
reload_time = 3;
size = 150;
rounding = 0;
position = "100, 150";
halign = "left";
valign = "bottom";
}
];
};
};
};
# Wayland configuration
wayland.windowManager.hyprland = {
enable = true;
xwayland.enable = true;
systemd = {
enable = true;
enableXdgAutostart = true;
};
plugins = with pkgs.hyprlandPlugins; [
# hyprgrass
];
settings =
let
useMonitorV2 = (lib.versionAtLeast pkgs.hyprland.version "0.40.0") && (cfg.monitorv2 != [ ]);
names =
if useMonitorV2 then
map (m: m.name) cfg.monitorv2
else
[
cfg.display1.input
cfg.display2.input
];
firstMonitor = builtins.elemAt names 0;
secondMonitor = if builtins.length names > 1 then builtins.elemAt names 1 else firstMonitor;
in
{
"$mod" = cfg.modKey;
# Mouse
# mouse_[up|down] - scroll wheel
# middle_mouse - 274
# thumb_up - 276
# thumb_down - 275
# l -> locked, will also work when an input inhibitor (e.g. a lockscreen) is active.
# r -> release, will trigger on release of a key.
# e -> repeat, will repeat when held.
# n -> non-consuming, key/mouse events will be passed to the active window in addition to triggering the dispatcher.
# m -> mouse, see below.
# t -> transparent, cannot be shadowed by other binds.
# i -> ignore mods, will ignore modifiers.
# s -> separate, will arbitrarily combine keys between each mod/key, see [Keysym combos](#keysym-combos) above.
# d -> has description, will allow you to write a description for your bind.
# p -> bypasses the app's requests to inhibit keybinds.
# https://wiki.hyprland.org/Configuring/Binds/
# https://wiki.hyprland.org/Configuring/Binds/#mouse-buttons
bind = [
"$mod, Return, exec, ${cfg.defaultApps.terminal.pname}"
"$mod, SPACE, exec, ${if cfg.launcher == "wofi" then "wofi --show drun" else "rofi -show drun"}"
", xf86Search, exec, ${if cfg.launcher == "wofi" then "wofi --show drun" else "rofi -show drun"}"
"$mod, Q, killactive, "
"$mod, M, exec, wlogout --protocol layer-shell"
"$mod, E, exec, ${cfg.defaultApps.fileExplorer.pname}"
"$mod, V, togglefloating, "
"$mod, D, exec, ${drawer}"
"$mod, P, pseudo, " # dwindle
"$mod, S, togglesplit, " # dwindle
"$mod SHIFT, Q, exec, hyprlock"
"$mod SHIFT, 4, exec, hyprshot -m region --clipboard-only"
"$mod, F, fullscreen, 1"
"$mod SHIFT, F, fullscreen, 0"
"$mod SHIFT, E, exec, smile"
"$mod, mouse:276, movecurrentworkspacetomonitor, ${firstMonitor}"
"$mod, mouse:275, movecurrentworkspacetomonitor, ${secondMonitor}"
# alt-tab between workspaces on active monitor
"$mod, Tab, workspace, m+1"
"$mod SHIFT, Tab, workspace, m-1"
"$mod, h, movefocus, l"
"$mod, l, movefocus, r"
"$mod, k, movefocus, u"
"$mod, j, movefocus, d"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod ALT, 1, movetoworkspace, 1"
"$mod ALT, 2, movetoworkspace, 2"
"$mod ALT, 3, movetoworkspace, 3"
"$mod ALT, 4, movetoworkspace, 4"
"$mod ALT, 5, movetoworkspace, 5"
"$mod ALT, 6, movetoworkspace, 6"
"$mod ALT, 7, movetoworkspace, 7"
"$mod ALT, 8, movetoworkspace, 8"
"$mod ALT, 9, movetoworkspace, 9"
"$mod ALT, 0, movetoworkspace, discord"
"$mod CTRL, l, resizeactive, 10 0"
"$mod CTRL, h, resizeactive, -10 0"
"$mod CTRL, k, resizeactive, 0 -10"
"$mod CTRL, j, resizeactive, 0 10"
"$mod SHIFT, l, movewindow, r"
"$mod SHIFT, h, movewindow, l"
"$mod SHIFT, k, movewindow, u"
"$mod SHIFT, j, movewindow, d"
"$mod, b, exec, ${cfg.defaultApps.browser.pname}"
]
++ cfg.keybinds.bind;
bindm = [
# Move/resize windows with mod + LMB/RMB and dragging
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
# middle mouse will grab a window, mod + middle mouse will close it
"$mod SHIFT, mouse:274, movewindow"
]
++ cfg.keybinds.bindm;
bindel = [
", XF86AudioRaiseVolume, exec, volumectl -u up"
", XF86AudioLowerVolume, exec, volumectl -u down"
]
++ cfg.keybinds.bindel;
bindl = [
", XF86AudioMute, exec, volumectl toggle-mute"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioPrev, exec, playerctl previous"
", XF86AudioNext, exec, playerctl next"
", XF86AudioMicMute, exec, volumectl -m toggle-mute"
", XF86MonBrightnessUp, exec, lightctl up"
", XF86MonBrightnessDown, exec, lightctl down"
]
++ cfg.keybinds.bindl;
monitor =
cfg.monitor
++ map (
m:
if m.disabled then
"${m.name}, disable"
else if m.mirrorOf != null then
"${m.name}, mirror, ${m.mirrorOf}"
else
let
mode = if m.mode == null then "preferred" else m.mode;
position = if m.position == null then "0x0" else m.position;
scale = if m.scale == null then "1" else (toString m.scale);
parts = [
m.name
mode
position
scale
];
# Append transform only when set, as "transform, <value>"
transformTokens =
if m.transform == null then
[ ]
else
[
"transform"
m.transform
];
tokens = parts ++ transformTokens ++ m.extra;
in
builtins.concatStringsSep ", " tokens
) cfg.monitorv2;
render = {
cm_fs_passthrough = 1;
};
misc = {
vrr = if cfg.enableVRR then 1 else 0;
force_default_wallpaper = 0;
};
general = {
gaps_in = 5;
gaps_out = 10;
border_size = 1;
# "col.active_border" = "rgb(8aadf4) rgb(24273A) rgb(24273A) rgb(8aadf4) 45deg";
# "col.inactive_border" = "rgb(24273A) rgb(24273A) rgb(24273A) rgb(24273A) 45deg";
layout = "dwindle";
allow_tearing = cfg.allowTearing;
};
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 2;
passes = 2;
new_optimizations = true;
xray = false;
};
};
animations = {
enabled = "yes";
bezier = [
"overshot, 0.05, 0.9, 0.1, 1.05"
"smoothOut, 0.36, 0, 0.66, -0.56"
"smoothIn, 0.25, 1, 0.5, 1"
];
animation = [
"windows, 1, 5, overshot, slide"
"windowsOut, 1, 4, smoothOut, slide"
"windowsMove, 1, 4, default"
"border, 1, 10, default"
"fade, 1, 10, smoothIn"
"fadeDim, 1, 10, smoothIn"
"workspaces, 1, 6, default"
];
};
dwindle = {
pseudotile = "yes";
preserve_split = "yes";
};
workspace = cfg.workspace;
windowrule = [
"match:title file_progress, float 1"
"match:title .*[Cc]onfirm.*, float 1"
"match:title .*[Dd]ialog.*, float 1"
"match:title .*[Dd]ownload.*, float 1"
"match:title .*[Nn]otification.*, float 1"
"match:title .*[Ee]rror.*, float 1"
"match:title .*[Ss]plash.*, float 1"
"match:title .*[Cc]onfirmreset.*, float 1"
"match:title .*[Ss]ign [Ii]n - .*, float 1"
"match:title .*[Oo]pen [Ff]ile.*, float 1"
"match:title .*branchdialog.*, float 1"
"match:class .*pavucontrol.*, float 1"
"match:class .*pavucontrol.*, move onscreen cursor 0% 0%"
"match:class .*[Oo]verskride.*, float 1"
"match:class .*FileRoller.*, float 1"
"match:class .*wlogout.*, float 1"
"match:title .*mpv.*, idle_inhibit stayfocused"
"match:class .*nm-connection-editor.*, float 1"
"match:class .*nm-connection-editor.*, move onscreen cursor 0% 0%"
"match:title Media viewer, float 1"
"match:class it.mijorus.smile),match:title Smile, float 1"
"match:class .blueman-manager-wrapped)$,match:title Bluetooth Devices, float 1"
# Picture in picture windows
"match:title .*Picture-in-Picture.*, float 1"
"match:title .*Picture-in-Picture.*, pin 1"
# discord/vesktop
# "workspace: name:discord, match:class .*vesktop"
# "match:class .*vesktop),match:title .*Discord Popout.*, float 1"
# "pin, match:class .*vesktop),match:title .*Discord Popout.*"
# Music
# "workspace: name:discord, match:class Apple Music.*"
# Steam
"match:class .*[Ss]team, match:title .*[Ss]team.*, float 1"
"match:class .*[Ss]team, match:title .*[Ss]team.*, workspace name:steam silent"
"match:class .*[Ss]team, match:title .*[Ss]team.*, tile 1"
"match:class .*steam,match:title .*Friends List.*, float 1"
# Code
"match:class .*codium.*, match:title Save As, pin 1"
"match:class .*codium.*, match:title Save As, float 1"
"match:class xdg-desktop-portal-gtk, match:title Open Workspace from File, float 1"
# Game Tearing??? https://wiki.hypr.land/Configuring/Tearing/
"match:class .*gamescope.*, idle_inhibit fullscreen, content game, immediate 1"
"match:xdg_tag proton-game, idle_inhibit fullscreen, content game, immediate 1"
"match:class steam_app_.*, idle_inhibit fullscreen, content game, immediate 1"
# vmware
# this tag will set the below options to the vdi window
# this will have it auto open as a 2160x7680 window
# and makes multi-monitor work
"match:class .*[Hh]orizon-client, match:title USPS Next VDI, tag +horizonrdp"
"match:tag horizonrdp, no_anim 1"
"match:tag horizonrdp, no_blur 1"
"match:tag horizonrdp, rounding 0"
"match:tag horizonrdp, no_shadow 1"
"match:tag horizonrdp, immediate 1"
"match:tag horizonrdp, allows_input 1"
"match:tag horizonrdp, border_size 0"
"match:tag horizonrdp, max_size 2160 7680"
"match:tag horizonrdp, min_size 1920 1080"
"match:tag horizonrdp, render_unfocused 1"
"match:tag horizonrdp, idle_inhibit 1"
"match:tag horizonrdp, float 1"
# float the vmware window cause its annoying to use in fullscreen
"match:class .*[Hh]orizon-client),match:title [Oo]mnissa [Hh]orizon [Cc]lient, float 1"
]
++ cfg.windowRule;
plugin = {
# touch_gestures = {
# # The default sensitivity is probably too low on tablet screens,
# # I recommend turning it up to 4.0
# sensitivity = "4.0";
# # must be >= 3
# workspace_swipe_fingers = "3";
# # switching workspaces by swiping from an edge, this is separate from workspace_swipe_fingers
# # and can be used at the same time
# # possible values: l, r, u, or d
# # to disable it set it to anything else
# workspace_swipe_edge = "d";
# # in milliseconds
# long_press_delay = "400";
# # resize windows by long-pressing on window borders and gaps.
# # If general:resize_on_border is enabled, general:extend_border_grab_area is used for floating
# # windows
# resize_on_border_long_press = true;
# # in pixels, the distance from the edge that is considered an edge
# edge_margin = "10";
# # emulates touchpad swipes when swiping in a direction that does not trigger workspace swipe.
# # ONLY triggers when finger count is equal to workspace_swipe_fingers
# #
# # might be removed in the future in favor of event hooks
# emulate_touchpad_swipe = false;
# experimental = {
# # send proper cancel events to windows instead of hacky touch_up events,
# # NOT recommended as it crashed a few times, once it's stabilized I'll make it the default
# send_cancel = "0";
# };
# hyprgrass-bind = [
# # swipe left from right edge
# ", edge:r:l, workspace, +1"
# # swipe up from bottom edge
# ", edge:d:u, exec, ${cfg.defaultApps.browser.pname}"
# # swipe down from left edge
# ", edge:l:d, exec, pactl set-sink-volume @DEFAULT_SINK@ -4%"
# # swipe down with 4 fingers
# ", swipe:4:d, killactive"
# # swipe diagonally left and down with 3 fingers
# # l (or r) must come before d and u
# ", swipe:3:ld, exec, foot"
# # tap with 3 fingers
# ", tap:3, exec, foot"
# # longpress can trigger mouse binds:
# ", longpress:2, movewindow"
# ", longpress:3, resizewindow"
# ];
# };
};
gesture = [
"3, horizontal, scale: 0.75, workspace" # swipe 3 fingers to change workspace
"3, pinch, mod: SUPER, resize"
"4, pinch, fullscreen"
];
input = {
kb_layout = "us";
kb_variant = "";
kb_model = "";
kb_options = "";
kb_rules = "";
numlock_by_default = true;
follow_mouse = 1;
touchpad = {
clickfinger_behavior = 1;
natural_scroll = "yes";
};
sensitivity = 0; # -1.0 - 1.0, 0 means no modification.
};
# experimental = {
# xx_color_management_v4 = true;
# };
debug = {
# full_cm_proto = cfg.debug.fullCmProto;
disable_logs = cfg.debug.disableLogs;
disable_scale_checks = cfg.debug.disableScaleChecks;
};
};
extraConfig =
let
autostarts = builtins.concatStringsSep "\n" (map (cmd: "exec-once = ${cmd}") cfg.autostartCommands);
in
''
exec-once = dbus-update-activation-environment --systemd --all
exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
exec-once = xhost +SI:localuser:root
''
+ autostarts
+ "\n"
+ (cfg.extraConfig or "");
};
};
}

View File

@@ -1,330 +0,0 @@
{
lib,
pkgs,
namespace,
...
}:
with lib;
{
options.${namespace}.programs.hyprland = {
enable = mkEnableOption "enable hyprland";
primaryDisplay = mkOption {
type = types.str;
default = "DP-1";
description = "Primary display identifier";
};
display1 = {
input = mkOption {
type = types.str;
default = "DP-1";
description = "First display identifier (Deprecated: prefer monitorv2)";
};
resolution = mkOption {
type = types.str;
default = "3840x2160";
description = "First display resolution (Deprecated: prefer monitorv2)";
};
refreshRate = mkOption {
type = types.str;
default = "240.00000";
description = "First display refresh rate (Deprecated: prefer monitorv2)";
};
};
display2 = {
input = mkOption {
type = types.str;
default = "DP-1";
description = "Second display identifier (Deprecated: prefer monitorv2)";
};
resolution = mkOption {
type = types.str;
default = "3840x2160";
description = "Second display resolution (Deprecated: prefer monitorv2)";
};
refreshRate = mkOption {
type = types.str;
default = "240.00000";
description = "Second display refresh rate (Deprecated: prefer monitorv2)";
};
};
# Deprecated: prefer hyprpaper.* options
wallpaper = mkOption {
type = with types; listOf str;
default = [ ];
description = "Deprecated: no longer used; prefer hyprpaper.wallpaperPath and hyprpaper.usePerMonitor.";
};
hyprpaper = mkOption {
type = types.submodule {
options = {
wallpaperPath = mkOption {
type = types.str;
default = "/run/wallpaper.jpg";
description = "Path to the wallpaper used by hyprpaper.";
};
usePerMonitor = mkOption {
type = types.bool;
default = true;
description = "If true, generate one wallpaper entry per monitor (monitorv2 preferred, falls back to display1/display2).";
};
};
};
default = { };
description = "Hyprpaper configuration.";
};
monitor = mkOption {
type = with types; listOf str;
default = [ ];
description = "List of Hyprland monitor configs (legacy). Example: [ \"eDP-1, 1920x1080@60, 0x0, 1\" ]";
};
monitorv2 = mkOption {
type =
with types;
listOf (
types.submodule {
options = {
name = mkOption {
type = types.str;
description = "Monitor name (e.g., DP-1, eDP-1).";
};
mode = mkOption {
type = types.nullOr types.str;
default = null;
description = "Resolution@Hz or keyword (e.g., \"3840x2160@144\" or \"preferred\").";
};
position = mkOption {
type = types.nullOr types.str;
default = null;
description = "Position like \"0x0\" or \"auto\".";
};
scale = mkOption {
type = types.nullOr types.float;
default = null;
description = "Scale factor (e.g., 1.0).";
};
transform = mkOption {
type = types.nullOr types.str;
default = null;
description = "Rotation/transform (e.g., \"normal\", \"90\", \"180\", \"270\", \"flipped\").";
};
disabled = mkOption {
type = types.bool;
default = false;
description = "Disable this monitor.";
};
mirrorOf = mkOption {
type = types.nullOr types.str;
default = null;
description = "Mirror another monitor by name.";
};
extra = mkOption {
type = with types; listOf str;
default = [ ];
description = "Additional monitorv2 flags appended as-is.";
};
};
}
);
default = [ ];
description = "Hyprland monitorv2 entries as structured options; rendered to lines like \"name, mode, position, scale, transform, ...\".";
};
workspace = mkOption {
type = with types; listOf str;
default = [ ];
description = "List of hyprland workspace definitions";
};
windowRule = mkOption {
type = with types; listOf str;
default = [ ];
description = "List of hyprland window rules";
};
extraConfig = mkOption {
type = with types; str;
default = "";
description = "Any extra configuration options";
};
defaultApps = mkOption {
type = types.submodule {
options = {
browser = mkOption {
type = types.package;
default = pkgs.firefox;
description = "Default browser";
};
editor = mkOption {
type = types.package;
default = pkgs.micro;
description = "Default text editor";
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nautilus;
description = "Default file explorer";
};
visual = mkOption {
type = types.package;
default = pkgs.vscodium;
description = "Default visual editor";
};
terminal = mkOption {
type = types.package;
default = pkgs.kitty;
description = "Default terminal";
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-desktopeditors;
description = "Default office suite";
};
video = mkOption {
type = types.package;
default = pkgs.vlc;
description = "Default video player";
};
imageViewer = mkOption {
type = types.package;
default = pkgs.nomacs;
description = "Default image viewer";
};
};
};
description = "Default applications used across the system";
};
autostartCommands = mkOption {
type = with types; listOf str;
default = [
"nwg-look -a"
"nwg-dock-hyprland -x"
];
description = "Commands to run via Hyprland exec-once";
};
launcher = mkOption {
type = types.enum [
"wofi"
"rofi"
];
default = "wofi";
description = "Application launcher to use in keybinds and packages.";
};
notificationDaemon = mkOption {
type = types.enum [
"mako"
"dunst"
];
default = "mako";
description = "Notification daemon to install.";
};
modKey = mkOption {
type = types.str;
default = "SUPER";
description = "Modifier key used for Hyprland binds (e.g., SUPER, ALT).";
};
enableVRR = mkOption {
type = types.bool;
default = true;
description = "Enable variable refresh rate (maps to Hyprland misc.vrr).";
};
allowTearing = mkOption {
type = types.bool;
default = true;
description = "Allow tearing (maps to Hyprland general.allow_tearing).";
};
debug = mkOption {
type = types.submodule {
options = {
disableLogs = mkOption {
type = types.bool;
default = false;
description = "Set Hyprland debug.disable_logs.";
};
fullCmProto = mkOption {
type = types.bool;
default = false;
description = "Set Hyprland debug.full_cm_proto.";
};
disableScaleChecks = mkOption {
type = types.bool;
default = false;
description = "Set Hyprland debug.disable_scale_checks.";
};
};
};
default = { };
description = "Hyprland debug flags.";
};
keybinds = mkOption {
type = types.submodule {
options = {
bind = mkOption {
type = with types; listOf str;
default = [ ];
description = "Hyprland bind entries.";
};
bindm = mkOption {
type = with types; listOf str;
default = [ ];
description = "Hyprland bindm entries.";
};
bindel = mkOption {
type = with types; listOf str;
default = [ ];
description = "Hyprland bindel entries.";
};
bindl = mkOption {
type = with types; listOf str;
default = [ ];
description = "Hyprland bindl entries.";
};
};
};
default = { };
description = "Keybinding lists for Hyprland; useful for host-level overrides.";
};
gestures = mkOption {
type = with types; listOf str;
default = [ ];
description = "Hyprland gesture entries.";
};
hyprIdle = {
lockScreenTimer = mkOption {
type = with types; int;
default = 300;
description = "Time in seconds before locking the screen";
};
screenOffTimer = mkOption {
type = with types; int;
default = 900;
description = "Time in seconds before turning off the screen";
};
suspendTimer = mkOption {
type = with types; int;
default = 1800;
description = "Time in seconds before suspending";
};
};
};
}

View File

@@ -1,12 +1,8 @@
{
lib,
config,
namespace,
...
}:
{ lib, config, ... }:
with lib;
let
cfg = config.${namespace}.programs.kitty;
cfg = config.mjallen.programs.kitty;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -16,6 +12,12 @@ in
enable = true;
shellIntegration.enableZshIntegration = true;
font = {
name = cfg.font.name;
package = cfg.font.package;
size = cfg.font.size;
};
settings = {
bold_font = "auto";
italic_font = "auto";
@@ -24,6 +26,80 @@ in
cursor_shape = "block";
url_style = "dotted";
confirm_os_window_close = "0";
background_opacity = "0.85";
# The basic colors
foreground = nord.snowStorm.nord6;
background = nord.polarNight.nord0;
selection_foreground = nord.polarNight.nord0;
selection_background = nord.aurora.nord15;
# Cursor colors
cursor = nord.aurora.nord15;
cursor_text_color = nord.polarNight.nord0;
# URL underline color when hovering with mouse
url_color = nord.aurora.nord15;
# Kitty window border colors
active_border_color = nord.frost.nord10;
inactive_border_color = nord.polarNight.nord1;
bell_border_color = nord.aurora.nord13;
# OS Window titlebar colors
wayland_titlebar_color = nord.polarNight.nord0;
macos_titlebar_color = nord.polarNight.nord0;
# Tab bar colors
active_tab_foreground = nord.polarNight.nord3;
active_tab_background = nord.aurora.nord15;
inactive_tab_foreground = nord.snowStorm.nord6;
inactive_tab_background = nord.polarNight.nord1;
tab_bar_background = nord.polarNight.nord3;
# Colors for marks (marked text in the terminal)
mark1_foreground = nord.polarNight.nord0;
mark1_background = nord.frost.nord10;
mark2_foreground = nord.polarNight.nord0;
mark2_background = nord.aurora.nord15;
mark3_foreground = nord.polarNight.nord0;
mark3_background = nord.frost.nord8;
# The 16 terminal colors
# black
color0 = nord.polarNight.nord0;
# Autosuggestion
color8 = nord.frost.nord10;
# red
color1 = nord.aurora.nord11;
color9 = nord.aurora.nord11;
# green
color2 = nord.aurora.nord14;
color10 = nord.aurora.nord14;
# yellow
color3 = nord.aurora.nord13;
color11 = nord.aurora.nord13;
# blue
color4 = nord.frost.nord10;
color12 = nord.frost.nord10;
# magenta
color5 = nord.aurora.nord15;
color13 = nord.aurora.nord15;
# cyan
color6 = nord.frost.nord8;
color14 = nord.frost.nord8;
# white
color7 = nord.snowStorm.nord5;
color15 = nord.snowStorm.nord4;
};
};
};

View File

@@ -1,7 +1,27 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.kitty = {
options.mjallen.programs.kitty = {
enable = mkEnableOption "enable kitty terminal";
font = {
name = mkOption {
type = types.str;
default = "DejaVu Sans";
};
package = mkOption {
type = types.package;
default = pkgs.dejavu_fonts;
};
size = mkOption {
type = with types; int;
default = 12;
};
};
theme = mkOption {
type = types.attrs;
default = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
};
};
}

View File

@@ -1,12 +1,8 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.mako;
cfg = config.mjallen.programs.mako;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -14,7 +10,7 @@ in
services.mako = {
enable = true;
settings = {
font = mkDefault cfg.fontName;
font = cfg.fontName;
icons = true;
ignore-timeout = true;
sort = "-time";
@@ -26,10 +22,10 @@ in
max-icon-size = 64;
default-timeout = 5000;
# background-color = mkDefault config.lib.stylix.colors.base00;
# text-color = mkDefault config.lib.stylix.colors.base06;
# border-color = mkDefault config.lib.stylix.colors.base0F;
# progress-color = mkDefault "over ${config.lib.stylix.colors.base0C}";
background-color = nord.polarNight.nord0;
text-color = nord.snowStorm.nord6;
border-color = nord.frost.nord10;
progress-color = "over ${nord.frost.nord8}";
};
};
};

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.mako = {
options.mjallen.programs.mako = {
enable = mkEnableOption "enable mako";
fontName = mkOption {

View File

@@ -2,12 +2,12 @@
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.programs.nwg-dock;
cfg = config.mjallen.programs.nwg-dock;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -16,86 +16,13 @@ in
home.packages = with pkgs; [ nwg-dock-hyprland ];
home.file = {
".config/nwg-dock-hyprland/config.json".text = ''
{
"position": "bottom",
"anchor": "center",
"margin": 12,
"icon_size": 48,
"icon_size_hover": 64,
"spacing": 6,
"padding": 8,
"autohide": false,
"autohide_timeout": 0.3,
"exclusive": true,
"layer": "top",
"height": 72,
"background_alpha": 0.55,
"rounded_corners": 16,
"show_labels": false,
"show_running": true,
"show_pinned": true,
"pinned": [
"firefox.desktop",
"org.wezfurlong.wezterm.desktop",
"codium.desktop",
"org.gnome.Nautilus.desktop"
]
}
'';
".config/nwg-dock-hyprland/style.css".text = ''
window {
background: #36364f;
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: rgba(156, 142, 122, 0.7)
}
#box {
/* Define attributes of the box surrounding icons here */
padding: 10px
}
#active {
/* This is to underline the button representing the currently active window */
border-bottom: solid 1px;
border-color: rgba(255, 255, 255, 0.3)
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: #999
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button:hover {
background-color: rgba(255, 255, 255, 0.15);
border-radius: 2px;
}
button:focus {
box-shadow: none
}
'';
".config/nwg-dock-hyprland/drawer.css".text = ''
window {
background: ${config.lib.stylix.colors.base00};
background: ${nord.polarNight.nord0};
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${config.lib.stylix.colors.base0E}b0
border-color: ${nord.aurora.nord15}b0
}
#box {
@@ -106,14 +33,14 @@ in
active {
/* This is to underline the button representing the currently active window */
border-bottom: solid 1px;
border-color: ${config.lib.stylix.colors.base0B}1a
border-color: ${nord.aurora.nord14}1a
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${config.lib.stylix.colors.base0F}
color: ${nord.frost.nord10}
}
button {
@@ -125,7 +52,7 @@ in
}
button:hover {
background-color: ${config.lib.stylix.colors.base00}1a;
background-color: ${nord.polarNight.nord0}1a;
border-radius: 2px;
}

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.nwg-dock = {
options.mjallen.programs.nwg-dock = {
enable = mkEnableOption "enable nwg-dock";
};
}

View File

@@ -2,12 +2,12 @@
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.programs.nwg-drawer;
cfg = config.mjallen.programs.nwg-drawer;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -18,13 +18,13 @@ in
home.file = {
".config/nwg-drawer/drawer.css".text = ''
window {
background-color: ${config.lib.stylix.colors.base00}bf;
color: ${config.lib.stylix.colors.base05}00
background-color: ${nord.polarNight.nord0}bf;
color: ${nord.snowStorm.nord5}00
}
/* search entry */
entry {
background-color: ${config.lib.stylix.colors.base01}0f
background-color: ${nord.polarNight.nord1}0f
}
button, image {
@@ -33,7 +33,7 @@ in
}
button:hover {
background-color: ${config.lib.stylix.colors.base0F}1a
background-color: ${nord.frost.nord10}1a
}
/* in case you wanted to give category buttons a different look */
@@ -43,12 +43,12 @@ in
#pinned-box {
padding-bottom: 5px;
border-bottom: 1px dotted ${config.lib.stylix.colors.base03}
border-bottom: 1px dotted ${nord.polarNight.nord3}
}
#files-box {
padding: 5px;
border: 1px dotted ${config.lib.stylix.colors.base03};
border: 1px dotted ${nord.polarNight.nord3};
border-radius: 15px
}
'';

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.nwg-drawer = {
options.mjallen.programs.nwg-drawer = {
enable = mkEnableOption "enable nwg-drawer";
};
}

View File

@@ -1,12 +1,7 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.nwg-panel;
cfg = config.mjallen.programs.nwg-panel;
in
{
imports = [ ./options.nix ];

View File

@@ -1,12 +1,7 @@
{
lib,
pkgs,
namespace,
...
}:
{ lib, pkgs, ... }:
with lib;
{
options.${namespace}.programs.nwg-panel = {
options.mjallen.programs.nwg-panel = {
enable = mkEnableOption "enable nwg-panel";
defaultApps = mkOption {
@@ -22,7 +17,7 @@ with lib;
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nautilus;
default = pkgs.nemo;
};
visual = mkOption {
type = types.package;
@@ -34,7 +29,7 @@ with lib;
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-desktopeditors;
default = pkgs.onlyoffice-bin_latest;
};
video = mkOption {
type = types.package;

View File

@@ -1,15 +1,10 @@
{
lib,
system,
hasDestopEnvironment ? true,
...
}:
{ lib, system, ... }:
let
isArm = "aarch64-linux" == system;
isArm = builtins.match "aarch64*" system != null;
in
{
programs.onlyoffice = {
enable = lib.mkDefault (!isArm && hasDestopEnvironment);
enable = lib.mkDefault (!isArm);
settings = {
UITheme = "theme-contrast-dark";
forcedRtl = false;

View File

@@ -1,290 +0,0 @@
{
config,
namespace,
pkgs,
...
}:
let
git-token = config.sops.secrets."github-token".path;
update-checker = pkgs.writeScriptBin "update-checker" ''
#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.pygithub python3Packages.feedparser python3Packages.requests nix-prefetch-scripts nix
import os
import json
import subprocess
from github import Github
from github import Auth
import feedparser
import requests
token = None
with open('${git-token}', 'r') as token_file:
token = token_file.readline()
auth = Auth.Token(token)
def check_github(owner, repo, version):
try:
release = None
result = None
prefetch = None
ghub = Github(auth=auth)
print(' getting repo ' + owner + '/' + repo)
repo = ghub.get_repo(owner + '/' + repo)
if '-b' in version:
release = repo.get_releases()[0]
latest_version = release.name
else:
try:
release = repo.get_latest_release()
latest_version = release.tag_name
except:
tags = repo.get_tags()
try:
if tags is not None:
latest_version = tags[0].name
except:
commits = repo.get_commits()
latest_version = commits[0].sha
if latest_version is not None:
if latest_version.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + latest_version)
result = subprocess.check_output(['nix-prefetch-git', '--quiet', repo.clone_url, '--rev', latest_version])
prefetch = json.loads(result)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
ghub.close()
except Exception as e:
print(e)
def check_codeberg(owner, repo, version):
feed = feedparser.parse('https://codeberg.org/{0}/{1}/releases.rss'.format(owner, repo))
if feed.status == 200:
entry = feed.entries[0]
if entry.title.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + entry.title)
sha256 = subprocess.check_output(['nix-prefetch-url', url.replace(''\'''\${version}', entry.title.replace('v', ''\''))])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
print(' New hash: ' + prefetch.decode('utf-8').strip())
else:
print(' no update')
def check_open_vsx(publisher, name, version):
open_vsx = requests.get('https://open-vsx.org/api/' + publisher + '/' + name)
if open_vsx.status_code == 200:
extension = open_vsx.json()
latest_version = extension.get('version')
url = extension.get('files').get('download')
if latest_version.replace('v',''\'') != version.replace('v',''\''):
print(' update found')
print(' Current version: ' + version)
print(' Latest version: ' + latest_version)
sha256 = subprocess.check_output(['nix-prefetch-url', url])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
print(' New hash: ' + prefetch.decode('utf-8').strip())
else:
print(' no update')
def parse_nix(package_spec):
version = None
url = None
current_hash = None
owner = None
repo = None
pname = None
name = None
publisher = None
for line in package_spec.readlines():
if 'owner = "' in line and owner is None:
owner = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'repo = "' in line and repo is None:
repo = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'version = "' in line and version is None:
version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'rev = "' in line and ''\'''\${version}' not in line:
version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'url = "' in line and url is None:
url = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'sha256 = "' in line or ' hash = "' in line and current_hash is None:
current_hash = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'pname = "' in line and pname is None:
pname = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if ' name = "' in line and name is None:
name = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if 'publisher = "' in line and publisher is None:
publisher = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'')
if url is None and repo is not None:
if 'pname' in repo:
repo = repo.replace(''\'''\${pname}', pname)
url = 'https://github.com/{0}/{1}/releases/tag/{2}'.format(owner, repo, version)
if url is not None and repo is None and 'github' in url:
owner = url.split('github.com/')[-1].split('/')[0]
repo = url.split('github.com/')[-1].split('/')[1]
if url is not None and repo is None and 'codeberg' in url:
owner = url.split('codeberg.org/')[-1].split('/')[0]
repo = url.split('codeberg.org/')[-1].split('/')[1]
if url is not None and version is None:
version = url.split('/')[-1].replace('.tar.gz', ''\'')
if url is not None and publisher is not None:
url = url.replace(''\'''\${publisher}', publisher).replace(''\'''\${name}', name)
return url, current_hash, owner, repo, pname, name, publisher, version
def parse_json(json_versions, flavor=''\''):
versions = json.load(json_versions)
linux_versions = versions.get('linux')
config_versions = versions.get('config')
patch_versions = versions.get('patches')
zfs_versions = versions.get('zfs')
check_kernel(linux_versions, flavor)
check_cachy_config(config_versions, flavor)
check_patch_versions(patch_versions, flavor)
check_zfs_versions(zfs_versions, flavor)
def check_kernel(linux_versions, flavor=''\''):
srcinfo = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/.SRCINFO')
for line in srcinfo.text.split('\n'):
if 'pkgver = ' in line:
kernel_version = line.split('=')[-1].strip()
if kernel_version[-2:] == '.0':
kernel_version = kernel_version[:-2]
if flavor in [''\'', '-lts', '-server', '-gcc', '-hardened']:
release_src = 'https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-' + kernel_version + '.tar.xz'
if flavor == '-rc':
release_src = 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/snapshot/linux-' + kernel_version.replace('.rc', '-rc') + '.tar.gz'
sha256 = subprocess.check_output(['nix-prefetch-url', release_src])
prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())])
current_version = linux_versions.get('version')
current_hash = linux_versions.get('hash')
latest_hash = prefetch.decode('utf-8').strip()
print(' Checking linux versions...')
if current_hash != latest_hash:
print(' Current rev: ' + current_version)
print(' Current hash: ' + current_hash)
print(' New rev: ' + kernel_version)
print(' New hash: ' + latest_hash)
else:
print(' no update')
def check_cachy_config(config_versions, flavor=''\''):
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/linux-cachyos.git'])
prefetch = json.loads(result)
current_version = config_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking config versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
def check_patch_versions(patch_versions, flavor=''\''):
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/kernel-patches.git'])
prefetch = json.loads(result)
current_version = patch_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking patch versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
def kconfig_to_nix(flavor=''\''):
kconfig_result = subprocess.check_output(['nix', 'build', '.#nixosConfigurations.jallen-nas.pkgs.linuxPackages_cachyos' + flavor + '.kernel.kconfigToNix', '--no-link', '--print-out-paths'])
config_file = kconfig_result.decode('utf-8').strip()
if flavor == ''\'':
cachy_flavor = '-gcc'
result = subprocess.check_output(['cat', config_file])
with open('/etc/nixos/packages/linux-cachyos/config-nix/cachyos' + cachy_flavor + '.x86_64-linux.nix', 'w') as config:
config.write(result.decode('utf-8').strip())
def check_zfs_versions(zfs_versions, flavor=''\''):
result = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/PKGBUILD')
for line in result.text.split('\n'):
if 'git+https://github.com/cachyos/zfs.git#commit=' in line:
zfs_rev = line.split('zfs.git#commit=')[-1].replace('")', ''\'')
result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/zfs.git', '--rev', zfs_rev])
prefetch = json.loads(result)
current_version = zfs_versions.get('rev')
latest_version = prefetch.get('rev')
print(' Checking zfs versions...')
if current_version != latest_version:
print(' Current rev: ' + current_version)
print(' New rev: ' + latest_version)
print(' New hash: ' + prefetch.get('hash'))
else:
print(' no update')
for (root,dirs,files) in os.walk('/etc/nixos/packages',topdown=True):
if 'default.nix' in files and 'versions.json' not in files:
print(root.split('/')[-1])
with open(root + '/default.nix', 'r') as package_spec:
url, current_hash, owner, repo, pname, name, publisher, version = parse_nix(package_spec)
if owner is not None and repo is not None and 'codeberg' in url:
check_codeberg(owner, repo, version)
elif owner is not None and repo is not None and 'github' in url:
check_github(owner, repo, version)
elif publisher is not None and 'open-vsx' in url:
check_open_vsx(publisher, name, version)
else:
if url is not None:
print(url)
if 'default.nix' in files and 'versions.json' in files:
with open(root + '/versions.json', 'r') as json_versions:
print('Checking Linux CachyOS')
parse_json(json_versions)
with open(root + '/versions-rc.json', 'r') as json_versions:
print('Checking Linux CachyOS RC')
parse_json(json_versions, '-rc')
with open(root + '/versions-lts.json', 'r') as json_versions:
print('Checking Linux CachyOS LTS')
parse_json(json_versions, '-lts')
with open(root + '/versions-hardened.json', 'r') as json_versions:
print('Checking Linux CachyOS Hardened')
parse_json(json_versions, '-hardened')
'';
in
{
config = {
sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"github-token" = { };
};
templates = {
".env".content = ''
GITHUB_TOKEN = "${config.sops.placeholder.github-token}"
'';
};
};
home.packages = [ update-checker ];
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,333 +1,69 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
let
inherit (types)
str
int
bool
listOf
attrs
path
nullOr
submodule
;
in
{
options.${namespace}.programs.waybar = {
enable = mkEnableOption "Waybar status bar";
options.mjallen.programs.waybar = {
enable = mkEnableOption "enable waybar";
# Legacy/compat options (kept for backwards compatibility)
layer = mkOption {
type = str;
type = types.str;
default = "top";
description = "Waybar layer (compat). Prefer layout + feature flags.";
};
modules-right = mkOption {
type = with types; listOf str;
default = [ ];
};
networkInterface = mkOption {
type = types.str;
default = "wlan0";
};
extraModules = mkOption {
type = attrs;
type = types.attrs;
default = { };
description = "Extra settings bars at top-level (compat with older module).";
};
extraModulesStyle = mkOption {
type = str;
type = types.str;
default = "";
description = "Extra CSS appended (compat). Prefer extra.style.";
};
windowOffset = mkOption {
type = int;
type = types.int;
default = 4;
description = "Right margin offset for the hyprland/window module (in rem).";
};
# Layout
layout = mkOption {
type = submodule {
options = {
left = mkOption {
type = listOf str;
default = [ "hyprland/workspaces" ];
description = "Modules shown on the left.";
};
center = mkOption {
type = listOf str;
default = [ "hyprland/window" ];
description = "Modules shown in the center.";
};
right = mkOption {
type = listOf str;
default = [
"tray"
"custom/left-end"
"temperature"
"temperature#gpu"
"keyboard-state#capslock"
"keyboard-state#numlock"
"wireplumber#sink"
"bluetooth"
"network"
"idle_inhibitor"
"custom/right-end"
"custom/left-end"
"clock"
"battery"
"custom/notifications"
"custom/weather"
"custom/power"
"custom/right-end"
];
description = "Modules shown on the right.";
};
};
};
default = { };
description = "Waybar module layout.";
};
# Network
network = mkOption {
type = submodule {
options = {
interface = mkOption {
type = str;
default = "wlan0";
description = "Primary network interface name.";
};
};
};
default = { };
description = "Network configuration.";
};
# Temperatures
temperature = mkOption {
type = submodule {
options = {
cpu = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
description = "Enable CPU temperature module.";
};
hwmonPath = mkOption {
type = str;
default = "/sys/devices/pci0000:00/0000:00:18.3/hwmon";
description = "CPU temperature hwmon path.";
};
hwmonFile = mkOption {
type = str;
default = "temp1_input";
description = "CPU temperature hwmon file.";
};
};
};
default = { };
};
gpu = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
description = "Enable GPU temperature module.";
};
hwmonPath = mkOption {
type = str;
default = "/sys/devices/pci0000:00/0000:00:01.1/0000:01:00.0/0000:02:00.0/0000:03:00.0/hwmon";
description = "GPU temperature hwmon path.";
};
hwmonFile = mkOption {
type = str;
default = "temp1_input";
description = "GPU temperature hwmon file.";
};
};
};
default = { };
};
};
};
default = { };
description = "Temperature module configuration.";
};
# Features
features = mkOption {
type = submodule {
options = {
tray = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
bluetooth = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
idleInhibitor = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
keyboardIndicators = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
audio = mkOption {
type = submodule {
options = {
sink = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
source = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = false;
};
};
};
default = { };
};
};
};
default = { };
};
weather = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
hass = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = false;
};
};
};
default = { };
};
clock = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
battery = mkOption {
type = submodule {
options = {
enable = mkOption {
type = bool;
default = true;
};
};
};
default = { };
};
};
};
default = { };
description = "Toggle optional Waybar features.";
};
# Styling
style = mkOption {
type = submodule {
options = {
file = mkOption {
type = nullOr path;
default = null;
description = "Optional external CSS file to use instead of the inline style.";
};
fragmentsDir = mkOption {
type = nullOr path;
default = null;
description = "Optional directory of CSS fragments to append.";
};
};
};
default = { };
description = "Styling configuration.";
};
# Extra overrides
extra = mkOption {
type = submodule {
options = {
settings = mkOption {
type = attrs;
default = { };
description = "Extra settings merged into settings.mainBar.";
};
style = mkOption {
type = str;
default = "";
description = "Extra CSS appended to the computed style.";
};
};
};
default = { };
description = "Extra settings/style hooks.";
};
# Waybar modules config
# modules = mkOption {
# type = types.submodule {
# options = {
# # Modules
# window = mkOption {
# type = types.submodule {
# options = {
# # Waybar Module CSS
# margin-right = mkOption {
# type = types.str;
# default = "4";
# };
# };
# };
# };
# temperature = mkOption {
# type = types.submodule {
# options = {
# # Waybar Module CSS
# margin-right = mkOption {
# type = types.str;
# default = "4";
# };
# };
# };
# };
# };
# };
# default = { };
# };
};
}

View File

@@ -1,40 +0,0 @@
{
config,
lib,
namespace,
pkgs,
...
}:
let
cfg = config.${namespace}.programs.waybar;
waybar-audio = pkgs.writeScriptBin "waybar-audio" ''
#!/usr/bin/env bash
# Extract sink entries: "ID Description"
choices=$(pw-dump | jq -r '
.. | objects
| select(.["media.class"] == "Audio/Sink")
| "\(.["object.id"]) \(.["node.description"])"
'
)
# Show wofi menu
selected=$(printf "%s\n" "$choices" | wofi --dmenu --prompt "Audio Output")
# Extract ID
id=$(echo "$selected" | awk '{print $1}')
# Switch to the selected device
if [ -n "$id" ]; then
wpctl set-default "$id"
fi
'';
in
{
imports = [ ../options.nix ];
config = lib.mkIf cfg.enable {
home.packages = [ waybar-audio ];
};
}

View File

@@ -6,13 +6,11 @@
...
}:
let
cfg = config.${namespace}.programs.waybar;
cfg = config.mjallen.programs.waybar;
pythonEnv = pkgs.python3.withPackages (
_ps: with pkgs.${namespace}; [
homeassistant-api
]
);
pythonEnv = pkgs.python3.withPackages (_ps: [
pkgs.${namespace}.homeassistant-api
]);
waybar-hass = pkgs.writeScriptBin "waybar-hass" ''
#!${pythonEnv}/bin/python

View File

@@ -1,61 +0,0 @@
{
config,
lib,
namespace,
pkgs,
...
}:
let
cfg = config.${namespace}.programs.waybar;
waybar-media = pkgs.writeScriptBin "waybar-media" ''
#!/usr/bin/env bash
# Get current playing song from playerctl
if command -v playerctl &> /dev/null; then
# Check if any player is running
if playerctl status &> /dev/null; then
artist=$(playerctl metadata xesam:artist 2>/dev/null)
title=$(playerctl metadata xesam:title 2>/dev/null)
if [[ -n "$artist" && -n "$title" ]]; then
echo " $artist - $title"
elif [[ -n "$title" ]]; then
echo " ''\${title//&/&amp;}"
else
echo " Music Playing"
fi
else
echo ""
fi
else
echo ""
fi
'';
waybar-media-art = pkgs.writeScriptBin "waybar-media-art" ''
#!/usr/bin/env bash
# Get current playing song from playerctl
if command -v playerctl &> /dev/null; then
# Check if any player is running
if playerctl status &> /dev/null; then
art=$(playerctl metadata mpris:artUrl 2>/dev/null)
if [[ -n "$art" ]]; then
echo ''\${art#file://}
fi
fi
fi
'';
in
{
imports = [ ../options.nix ];
config = lib.mkIf cfg.enable {
home.packages = [
waybar-media
waybar-media-art
];
};
}

View File

@@ -1,95 +0,0 @@
{
config,
lib,
namespace,
pkgs,
...
}:
let
cfg = config.${namespace}.programs.waybar;
waybar-notifications = pkgs.writeScriptBin "waybar-notifications" ''
#!/usr/bin/env python
import subprocess
import json
import codecs
import re
def check_notifications(args = "history"):
notifications = []
number = None
content = None
appname = None
urgency = None
cmd = "makoctl"
temp = subprocess.Popen([cmd, args], stdout = subprocess.PIPE)
output = str(temp.communicate()).replace("(b\'", "").replace("\', None)", "")
lines = output.split("\\n")
for line in lines:
if "Notification" in line:
number = line.split(":")[0].replace("Notification ", "")
content = re.sub(r"[\u2066\u2067\u2068\u2069, \u00e2\u0081\u00a8]", "", codecs.decode(line.split(": ")[-1].encode("latin1").decode("utf-8"), "unicode_escape"))
content = re.sub(r"[\u00a9]", " ", content)
if "App name" in line:
appname = line.split(": ")[-1]
if "Urgency" in line:
urgency = line.split(": ")[-1]
if number is not None and content is not None and appname is not None and urgency is not None:
notifications.append((number, content, appname, urgency))
number = None
content = None
appname = None
urgency = None
return notifications
def get_icon(notifications):
status = ""
icon = ""
for number, content, appname, urgency in notifications:
status = "notify"
if urgency != "normal":
status = "alert"
break
if status == "notify":
icon = "󰂞"
if status == "alert":
icon = "󰵙"
return icon, status
def build_tooltip(notifications):
tooltip = ""
for number, content, appname, urgency in notifications:
tooltip += "{0}: {1}\n".format(appname, content)
return tooltip
def main():
notifications = check_notifications()
data = {}
icon, status = get_icon(notifications)
data["text"] = icon
data["tooltip"] = build_tooltip(notifications)
data["class"] = status
print(json.dumps(data, ensure_ascii=False))
main()
'';
in
{
imports = [ ../options.nix ];
config = lib.mkIf cfg.enable {
home.packages = [ waybar-notifications ];
};
}

View File

@@ -2,11 +2,10 @@
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.programs.waybar;
cfg = config.mjallen.programs.waybar;
waybar-weather = pkgs.writeScriptBin "waybar-weather" ''
#!/usr/bin/env nix-shell
@@ -17,18 +16,9 @@ let
import json
import shutil
from datetime import datetime, timedelta
import argparse
import math
import requests
parser = argparse.ArgumentParser(prog='waybar-weather')
parser.add_argument('--waybar', action='store_true')
parser.add_argument('--hyprlock', action='store_true')
args = parser.parse_args()
# --- MAPPINGS ---
WWO_CODE = {
"113": "Sunny",
"116": "PartlyCloudy",
@@ -80,38 +70,6 @@ let
"395": "HeavySnowShowers",
}
# Maps WMO codes (OpenMeteo) to WWO codes (wttr.in)
WMO_TO_WWO = {
0: "113", # Clear sky -> Sunny
1: "113", # Mainly clear -> Sunny
2: "116", # Partly cloudy
3: "122", # Overcast -> VeryCloudy
45: "143", # Fog
48: "248", # Depositing rime fog
51: "266", # Drizzle: Light
53: "266", # Drizzle: Moderate (mapped to LightRain)
55: "296", # Drizzle: Dense intensity (LightRain usually suits better than heavy)
56: "281", # Freezing Drizzle: Light
57: "284", # Freezing Drizzle: Dense
61: "296", # Rain: Slight
63: "302", # Rain: Moderate
65: "308", # Rain: Heavy
66: "311", # Freezing Rain: Light
67: "314", # Freezing Rain: Heavy
71: "326", # Snow fall: Slight
73: "332", # Snow fall: Moderate
75: "338", # Snow fall: Heavy
77: "350", # Snow grains
80: "353", # Rain showers: Slight
81: "356", # Rain showers: Moderate
82: "359", # Rain showers: Violent
85: "368", # Snow showers: Slight
86: "371", # Snow showers: Heavy
95: "386", # Thunderstorm: Slight or moderate
96: "389", # Thunderstorm with slight hail
99: "395", # Thunderstorm with heavy hail
}
WEATHER_SYMBOL = {
"Unknown": "",
"Cloudy": "",
@@ -151,6 +109,10 @@ let
"SSE": "",
}
MOON_PHASES = (
"󰽤", "󰽧", "󰽡", "󰽨", "󰽢", "󰽦", "󰽣", "󰽥"
)
WEATHER_SYMBOL_WI_DAY = {
"Unknown": "",
"Cloudy": "",
@@ -227,117 +189,117 @@ let
' '],
"VeryCloudy": [
' ',
'<span foreground=\"#585858\" font-weight="bold"> .--. </span>',
'<span foreground=\"#585858\" font-weight="bold"> .-( ). </span>',
'<span foreground=\"#585858\" font-weight="bold"> (___.__)__) </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> .--. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> .-( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___.__)__) </span>',
' '],
"LightShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#87afff\"> </span>',
'<span foreground=\"#87afff\"> </span>'],
'<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"HeavyShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\" font-weight="bold">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\" font-weight="bold">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\" font-weight="bold">(___(__) </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>'],
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\"; font-weight: bold;">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\"; font-weight: bold;">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\"; font-weight: bold;">(___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>'],
"LightSnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#eeeeee\"> * * * </span>',
'<span foreground=\"#eeeeee\"> * * * </span>'],
'<span foreground=\"#eeeeee\";"> * * * </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"HeavySnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\" font-weight="bold">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\" font-weight="bold">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\" font-weight="bold">(___(__) </span>',
'<span foreground=\"#eeeeee\" font-weight="bold"> * * * * </span>',
'<span foreground=\"#eeeeee\" font-weight="bold"> * * * * </span>'],
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\"; font-weight: bold;">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\"; font-weight: bold;">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\"; font-weight: bold;">(___(__) </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>'],
"LightSleetShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">* </span>',
'<span foreground=\"#eeeeee\"> *</span>"<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> </span>'],
'<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>'],
"ThunderyShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#ffff87\"> \\</span>"<span foreground=\"#87afff\"> </span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#87afff\"> </span>',
'<span foreground=\"#87afff\"> </span>'],
'<span foreground=\"#ffff87\";"> \\</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"ThunderyHeavyRain": [
'<span foreground=\"#585858\" font-weight="bold"> .-. </span>',
'<span foreground=\"#585858\" font-weight="bold"> ( ). </span>',
'<span foreground=\"#585858\" font-weight="bold"> (___(__) </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#0000ff\"></span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#0000ff\"> </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#0000ff\"> </span>'],
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"></span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"> </span>'],
"ThunderySnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#eeeeee\"> *</span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#ffff87\">\\</span>"<span foreground=\"#eeeeee\">* </span>',
'<span foreground=\"#eeeeee\"> * * * </span>'],
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"LightRain": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#87afff\"> </span>',
'<span foreground=\"#87afff\"> </span>'],
'<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"HeavyRain": [
'<span foreground=\"#585858\" font-weight="bold"> .-. </span>',
'<span foreground=\"#585858\" font-weight="bold"> ( ). </span>',
'<span foreground=\"#585858\" font-weight="bold"> (___(__) </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>',
'<span foreground=\"#0000ff\" font-weight="bold"> </span>'],
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>'],
"LightSnow": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#eeeeee\"> * * * </span>',
'<span foreground=\"#eeeeee\"> * * * </span>'],
'<span foreground=\"#eeeeee\";"> * * * </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"HeavySnow": [
'<span foreground=\"#585858\" font-weight="bold"> .-. </span>',
'<span foreground=\"#585858\" font-weight="bold"> ( ). </span>',
'<span foreground=\"#585858\" font-weight="bold"> (___(__) </span>',
'<span foreground=\"#eeeeee\" font-weight="bold"> * * * * </span>',
'<span foreground=\"#eeeeee\" font-weight="bold"> * * * * </span>'],
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>'],
"LightSleet": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">* </span>',
'<span foreground=\"#eeeeee\"> *</span>"<span foreground=\"#87afff\"> </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> </span>'],
'<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>'],
"Fog": [
' ',
'<span foreground=\"#c0c0c0\"> _ - _ - _ - </span>',
'<span foreground=\"#c0c0c0\"> _ - _ - _ </span>',
'<span foreground=\"#c0c0c0\"> _ - _ - _ - </span>',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ - </span>',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ </span>',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ - </span>',
' '],
}
WEATHER_CODES_WEGO = {key: WEATHER_SYMBOL_WEGO[value] for key, value in WWO_CODE.items()}
CACHE_DIR = os.path.join(os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache")), "waybar-weather")
CACHE_FILE = os.path.join(CACHE_DIR, "wttr.json")
CACHE_MOON_FILE = os.path.join(CACHE_DIR, "moon.json")
CACHE_MOON_ICON_FILE = os.path.join(CACHE_DIR, "moon-icon")
CACHE_TTL = timedelta(minutes=10)
data = {}
data["text"] = ""
def format_time(time):
"""get the time formatted"""
return datetime.strptime(format_24_time(time), "%H").strftime("%I %p")
def format_24_time(time):
"""get the time formatted"""
return time.replace("00", "").zfill(2)
def format_temp(temp):
return (str(temp) + "°").ljust(3)
"""get the temp formatted"""
return (temp + "°").ljust(3)
def format_chances(hour):
"""get the chances formatted"""
chances = {
"chanceoffog": "Fog",
"chanceoffrost": "Frost",
@@ -348,67 +310,62 @@ let
"chanceofthunder": "Thunder",
"chanceofwindy": "Wind",
}
conditions = []
for chance, event in chances.items():
if int(hour.get(chance, 0)) > 0:
conditions.append(event + " " + str(hour[chance]) + "%")
if int(hour[chance]) > 0:
conditions.append(event + " " + hour[chance] + "%")
return ", ".join(conditions)
def deg_to_compass(num):
val = int((num / 22.5) + 0.5)
arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"]
return arr[(val % 16)]
def build_text(current_condition):
"""build the text string"""
feels_like_f = current_condition["FeelsLikeF"]
weather_code = current_condition["weatherCode"]
# Check if we have a mapped format; if not, fallback to Unknown
if weather_code not in WEATHER_CODES:
weather_code = "113" # Fallback to sunny/default to prevent crash
tempint = int(float(feels_like_f)) # float cast just in case
tempint = int(feels_like_f)
extrachar = ""
if 0 < tempint < 10:
extrachar = "+"
current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {int(feels_like_f)}°F"
current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {feels_like_f}°F"
return current_weather
def build_tooltip(current_condition, astronomy, moon_icon):
"""build the tooltip text"""
weather_description = current_condition['weatherDesc'][0]['value']
feels_like_f = current_condition["FeelsLikeF"]
temp_f = current_condition['temp_F']
humidity = current_condition['humidity']
wind_speed = current_condition['windspeedMiles']
wind_dir = current_condition['winddir16Point']
moon_phase = astronomy.get('moon_phase', 'Unknown')
weather_code = current_condition['weatherCode']
if weather_code not in WEATHER_CODES_WEGO:
weather_code = "113"
wego = WEATHER_CODES_WEGO[weather_code]
moon_phase = astronomy['moon_phase']
wego = WEATHER_CODES_WEGO[current_condition['weatherCode']]
current = f"{wego[0]}{weather_description} {temp_f}°\n"
feels = f"{wego[1]}Feels like: {feels_like_f}°\n"
wind = f"{wego[2]}Wind: {wind_speed}mph {WIND_DIRECTION.get(wind_dir, ''\'')}\n" # Safe get for direction
wind = f"{wego[2]}Wind: {wind_speed}mph {WIND_DIRECTION[wind_dir]}\n"
humidityl = f"{wego[3]}Humidity: {humidity}%\n"
moon = f"{wego[4]}Moon phase: {moon_phase} " + moon_icon + "\n"
tooltip = current + feels + wind + humidityl + moon
return tooltip
def build_forecast(weather):
"""build a 3 day forecast"""
tooltip = "\n"
for i, day in enumerate(weather):
# determine day
if i == 0:
tooltip += "Today, "
if i == 1:
tooltip += "Tomorrow, "
# format the date
date = datetime.strptime(day['date'], "%Y-%m-%d").strftime("%a %b %d %Y")
tooltip += f"<b>{date}</b>\n"
# set the high and low
max_temp = day['maxtempF']
min_temp = day['mintempF']
tooltip += f" {max_temp}°F {min_temp}°F"
@@ -420,34 +377,29 @@ let
tooltip += build_hourly_forecast(i, day['hourly'], sunrise, sunset)
return tooltip
def build_hourly_forecast(day_num, hourly, sunrise, sunset):
try:
sunrise_hour = datetime.strptime(sunrise, "%I:%M %p").hour
sunset_hour = datetime.strptime(sunset, "%I:%M %p").hour
except ValueError:
# Fallback if time format is different (OpenMeteo might send 24h)
sunrise_hour = int(sunrise.split(':')[0])
sunset_hour = int(sunset.split(':')[0])
def build_hourly_forecast(day_num, hourly, sunrise, sunset):
"""build an hourly forecast"""
sunrise_hour = datetime.strptime(sunrise, "%I:%M %p").hour
sunset_hour = datetime.strptime(sunset, "%I:%M %p").hour
current_hour = datetime.now().hour
tooltip = ""
for hour in hourly:
time_24_hr = int(format_24_time(hour["time"]))
if day_num == 0:
if time_24_hr < current_hour - 2:
continue
# determine which code to use
if is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
codes = WEATHER_CODES_WI_NIGHT
else:
codes = WEATHER_CODES_WI_DAY
current_time = format_time(hour['time'])
wcode = hour['weatherCode']
if wcode not in codes: wcode = "113" # Fallback
current_weather_code = codes[wcode]
current_weather_code = codes[hour['weatherCode']]
feels_like = format_temp(hour['FeelsLikeF'])
weather_desc = hour['weatherDesc'][0]['value']
current_chances = format_chances(hour)
@@ -458,188 +410,38 @@ let
return tooltip
def is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
"""returns true if the hour is night"""
before_sunrise = time_24_hr < sunrise_hour
after_sunset = time_24_hr > sunset_hour
return after_sunset or before_sunrise
def load_cache(path, ttl):
try:
if not os.path.exists(path):
return None
mtime = datetime.fromtimestamp(os.path.getmtime(path))
if datetime.now() - mtime > ttl:
return None
with open(path, "r") as f:
if path.endswith(".json"):
return json.load(f)
return f.read().strip()
except Exception:
return None
def get_wttr_json():
"""get the weather json"""
weather = requests.get("https://wttr.in/?u&format=j1", timeout=30).json()
moon = requests.get("https://wttr.in/?format=%m", timeout=30)
moon_icon = moon.text
def save_cache(path, data):
os.makedirs(os.path.dirname(path), exist_ok=True)
tmp = path + ".tmp"
try:
with open(tmp, "w") as f:
if isinstance(data, dict):
json.dump(data, f)
else:
f.write(str(data))
shutil.move(tmp, path)
except Exception:
pass
current_condition = weather["current_condition"][0]
astronomy = weather["weather"][0]['astronomy'][0]
# --- OPEN-METEO INTEGRATION HELPER FUNCTIONS ---
text = build_text(current_condition)
def get_lat_lon():
"""Attempt to get location via IP if using OpenMeteo"""
try:
resp = requests.get("http://ip-api.com/json/", timeout=5).json()
return resp.get('lat'), resp.get('lon')
except:
# Default to a generic location if IP fetch fails (NYC)
return 40.71, -74.00
tooltip = build_tooltip(current_condition, astronomy, moon_icon) + build_forecast(weather["weather"])
def fetch_open_meteo():
"""Fetch and Transform OpenMeteo data to match Wttr.in JSON structure"""
lat, lon = get_lat_lon()
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": lat,
"longitude": lon,
"current": "temperature_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m,wind_direction_10m,relative_humidity_2m",
"daily": "weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_probability_max",
"hourly": "temperature_2m,apparent_temperature,precipitation_probability,weather_code",
"temperature_unit": "fahrenheit",
"wind_speed_unit": "mph",
"precipitation_unit": "inch",
"timezone": "auto"
}
response = requests.get(url, params=params, timeout=10)
om_data = response.json()
# Transform Current Condition
current = om_data["current"]
wmo_code = current["weather_code"]
wwo_code = WMO_TO_WWO.get(wmo_code, "113")
wttr_current = {
"temp_F": str(int(current["temperature_2m"])),
"FeelsLikeF": str(int(current["apparent_temperature"])),
"weatherCode": wwo_code,
"weatherDesc": [{"value": WWO_CODE.get(wwo_code, "Unknown")}],
"humidity": str(current["relative_humidity_2m"]),
"windspeedMiles": str(int(current["wind_speed_10m"])),
"winddir16Point": deg_to_compass(current["wind_direction_10m"]),
}
# Transform Daily Forecast (OpenMeteo gives 7 days, we need 3)
wttr_weather = []
daily = om_data["daily"]
hourly = om_data["hourly"]
for i in range(3):
date_str = daily["time"][i]
# Build Hourly for this day (wttr uses 3-hour intervals: 0, 300, 600...)
# OpenMeteo gives 0, 1, 2...
wttr_hourly = []
for h in range(0, 24, 3): # Step by 3 hours to mimic wttr
idx = (i * 24) + h
h_code = hourly["weather_code"][idx]
h_wwo = WMO_TO_WWO.get(h_code, "113")
wttr_hourly.append({
"time": str(h * 100), # 0, 300, 600
"weatherCode": h_wwo,
"weatherDesc": [{"value": WWO_CODE.get(h_wwo, "Unknown")}],
"FeelsLikeF": str(int(hourly["apparent_temperature"][idx])),
"chanceofrain": str(hourly["precipitation_probability"][idx]),
# Fill other chances with 0 as API doesn't provide them easily
"chanceoffog": "0", "chanceofsnow": "0", "chanceofthunder": "0",
"chanceofwindy": "0", "chanceofsunshine": "0"
})
data["text"] = text
data["tooltip"] = tooltip
# Astronomy
sunrise = datetime.fromisoformat(daily["sunrise"][i]).strftime("%I:%M %p")
sunset = datetime.fromisoformat(daily["sunset"][i]).strftime("%I:%M %p")
wttr_weather.append({
"date": date_str,
"maxtempF": str(int(daily["temperature_2m_max"][i])),
"mintempF": str(int(daily["temperature_2m_min"][i])),
"astronomy": [{"sunrise": sunrise, "sunset": sunset, "moon_phase": "Unknown"}],
"hourly": wttr_hourly
})
return {
"current_condition": [wttr_current],
"weather": wttr_weather
}
def get_wttr_json(hyprlock=False):
# Try loading cached JSON
cached = load_cache(CACHE_FILE, CACHE_TTL)
cached_moon = load_cache(CACHE_MOON_FILE, CACHE_TTL)
cached_moon_icon = load_cache(CACHE_MOON_ICON_FILE, CACHE_TTL)
if cached and cached_moon and cached_moon_icon:
weather = cached
current_condition = weather["current_condition"][0]
astronomy = cached_moon
moon_icon = cached_moon_icon
else:
try:
# Primary Source: wttr.in
weather = requests.get("https://wttr.in/?u&format=j1", timeout=5).json()
moon = requests.get("https://wttr.in/?format=%m", timeout=5)
moon_icon = moon.text
current_condition = weather["current_condition"][0]
astronomy = weather["weather"][0]['astronomy'][0]
except Exception:
# Fallback Source: Open-Meteo
try:
print("open_mateo fallback")
weather = fetch_open_meteo()
current_condition = weather["current_condition"][0]
astronomy = weather["weather"][0]['astronomy'][0]
moon_icon = "" # Generic moon icon for fallback
except Exception as e:
# If both fail
raise e
# Save cache (works for both sources since we transformed OM data)
save_cache(CACHE_FILE, weather)
save_cache(CACHE_MOON_FILE, astronomy)
save_cache(CACHE_MOON_ICON_FILE, moon_icon)
if hyprlock:
return build_tooltip(current_condition, astronomy, moon_icon)
else:
text = build_text(current_condition)
tooltip = build_tooltip(current_condition, astronomy, moon_icon) + build_forecast(weather["weather"])
data["text"] = text
data["tooltip"] = tooltip
return json.dumps(data)
return json.dumps(data)
def main():
if args.hyprlock:
try:
print(get_wttr_json(hyprlock=True))
except Exception as e:
print("error")
# print(e) # Uncomment for debug
else:
try:
print(get_wttr_json())
except Exception as e:
print(json.dumps({"text": "Err", "tooltip": str(e)}))
if __name__ == "__main__":
main()
"""main"""
try:
print(get_wttr_json())
except Exception as e:
print("error")
print(e)
main()
'';
in
{

View File

@@ -1,12 +1,8 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.wlogout;
cfg = config.mjallen.programs.wlogout;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -57,13 +53,13 @@ in
}
window {
background-color: ${config.lib.stylix.colors.base00}f0
background-color: ${nord.polarNight.nord0}f0
}
button {
margin: 8px;
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base01};
color: ${nord.frost.nord7};
background-color: ${nord.polarNight.nord1};
border-style: solid;
border-width: 2px;
background-repeat: no-repeat;
@@ -74,8 +70,8 @@ in
button:active,
button:focus,
button:hover {
color: ${config.lib.stylix.colors.base0C};
background-color: ${config.lib.stylix.colors.base02Alt};
color: ${nord.frost.nord8};
background-color: ${nord.polarNight.nord2};
outline-style: none;
}

View File

@@ -1,7 +1,12 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.wlogout = {
options.mjallen.programs.wlogout = {
enable = mkEnableOption "enable wlogout";
fontName = mkOption {
type = types.str;
default = "Deja Vu Sans";
};
};
}

View File

@@ -1,12 +1,8 @@
{
config,
lib,
namespace,
...
}:
{ config, lib, ... }:
with lib;
let
cfg = config.${namespace}.programs.wofi;
cfg = config.mjallen.programs.wofi;
nord = import (lib.snowfall.fs.get-file "modules/home/desktop/theme/nord.nix");
in
{
imports = [ ./options.nix ];
@@ -24,9 +20,9 @@ in
window {
margin: 0px;
padding: 10px;
border: 0.16em solid ${config.lib.stylix.colors.base0E};
border: 0.16em solid ${nord.aurora.nord15};
border-radius: 0.1em;
background-color: ${config.lib.stylix.colors.base00};
background-color: ${nord.polarNight.nord0};
}
/* Inner Box */
@@ -34,7 +30,7 @@ in
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
background-color: ${nord.polarNight.nord0};
}
/* Outer Box */
@@ -42,7 +38,7 @@ in
margin: 5px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
background-color: ${nord.polarNight.nord0};
}
/* Scroll */
@@ -50,7 +46,7 @@ in
margin: 0px;
padding: 10px;
border: none;
background-color: ${config.lib.stylix.colors.base00};
background-color: ${nord.polarNight.nord0};
}
/* Input */
@@ -59,46 +55,46 @@ in
padding: 10px;
border: none;
border-radius: 0.1em;
color: ${config.lib.stylix.colors.base06};
background-color: ${config.lib.stylix.colors.base00};
color: ${nord.snowStorm.nord6};
background-color: ${nord.polarNight.nord0};
}
#input image {
border: none;
color: ${config.lib.stylix.colors.base08};
color: ${nord.aurora.nord11};
}
#input * {
outline: 4px solid ${config.lib.stylix.colors.base08}!important;
outline: 4px solid ${nord.aurora.nord11}!important;
}
/* Text */
#text {
margin: 5px;
border: none;
color: ${config.lib.stylix.colors.base06};
color: ${nord.snowStorm.nord6};
}
#entry {
background-color: ${config.lib.stylix.colors.base00};
background-color: ${nord.polarNight.nord0};
}
#entry arrow {
border: none;
color: ${config.lib.stylix.colors.base0E};
color: ${nord.aurora.nord15};
}
/* Selected Entry */
#entry:selected {
border: 0.11em solid ${config.lib.stylix.colors.base0E};
border: 0.11em solid ${nord.aurora.nord15};
}
#entry:selected #text {
color: ${config.lib.stylix.colors.base0C};
color: ${nord.frost.nord7};
}
#entry:drop(active) {
background-color: ${config.lib.stylix.colors.base0E}!important;
background-color: ${nord.aurora.nord15}!important;
}
'';
};

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.programs.wofi = {
options.mjallen.programs.wofi = {
enable = mkEnableOption "enable wofi";
fontName = mkOption {

View File

@@ -1,11 +0,0 @@
{
...
}:
{
#services.gnome-keyring.enable = false;
#home.packages = [ pkgs.gcr ];
services.pass-secret-service = {
enable = true;
};
}

View File

@@ -1,14 +1,13 @@
{
config,
lib,
namespace,
...
}:
let
cfg = config.${namespace}.shell-aliases;
cfg = config.mjallen.shell-aliases;
in
{
options.${namespace}.shell-aliases = {
options.mjallen.shell-aliases = {
enable = lib.mkEnableOption "Common shell aliases";
buildHost = lib.mkOption {

View File

@@ -5,24 +5,28 @@
...
}:
let
cfg = config.${namespace}.sops;
cfg = config.mjallen.sops;
user = config.${namespace}.user.name;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
sops = {
age.keyFile = "/home/${config.${namespace}.user.name}/.config/sops/age/keys.txt";
age.keyFile = "/home/${user}/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
# secrets = {
# "github-token" = { };
# };
# templates = {
# ".env".content = ''
# GITHUB_TOKEN = "${config.sops.placeholder.github-token}"
# '';
# };
secrets = {
"ssh-keys-public/desktop-nixos" = {
path = "/home/${user}/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/desktop-nixos" = {
path = "/home/${user}/.ssh/id_ed25519";
mode = "0600";
};
};
};
};
}

View File

@@ -1,7 +1,7 @@
{ lib, namespace, ... }:
{ lib, ... }:
with lib;
{
options.${namespace}.sops = {
options.mjallen.sops = {
enable = mkEnableOption "enable sops";
defaultSopsFile = mkOption {

View File

@@ -1,104 +0,0 @@
{
config,
pkgs,
system,
...
}:
let
# # Pull from global theme options
# themeSize = "standard"; # "standard" | "compact"
# themeAccent = "default"; # "default" | ... | "all"
# themeTweak = "normal"; # "normal" | "rimless" | "float" | "black"
# themeColor = "dark"; # "light" | "dark"
# iconThemeVariant = "default"; # "default" | ... | "all"
# iconScheme = "nord"; # "default" | "nord" | "dracula" | ...
# # GTK
# gtkTheme = "Colloid-dark-standard";
# gtkThemePkg = pkgs.colloid-gtk-theme.override {
# sizeVariants = [ themeSize ];
# colorVariants = [ themeColor ];
# themeVariants = [ themeAccent ];
# tweaks = [ themeTweak ];
# };
# # Icons
# iconTheme = "Colloid-nord-dark";
# iconThemePkg = pkgs.colloid-icon-theme.override {
# schemeVariants = [ iconScheme ];
# colorVariants = [ iconThemeVariant ];
# };
isDarwin = system == "aarch64-darwin";
in
{
stylix = {
enable = true;
overlays.enable = false;
enableReleaseChecks = false;
base16Scheme = "${pkgs.base16-schemes}/share/themes/nord.yaml";
polarity = "dark";
cursor = {
name = "macOS";
size = 24;
package = pkgs.apple-cursor;
};
fonts = {
serif = {
package = pkgs.dejavu_fonts;
name = "DejaVu Serif";
};
sansSerif = {
package = pkgs.dejavu_fonts;
name = "DejaVu Sans";
};
monospace = {
package = pkgs.nerd-fonts.jetbrains-mono;
name = "JetBrainsMono NFM";
};
emoji = {
package = pkgs.noto-fonts-color-emoji;
name = "Noto Color Emoji";
};
sizes = {
applications = if isDarwin then 10 else 12;
desktop = if isDarwin then 12 else 14;
popups = config.stylix.fonts.sizes.desktop;
terminal = config.stylix.fonts.sizes.applications;
};
};
icons = {
enable = true;
package = pkgs.colloid-icon-theme.override {
schemeVariants = [ "nord" ];
colorVariants = [ "default" ];
};
dark = "Colloid-Nord-Dark";
light = "Colloid-Nord-Light";
};
opacity = {
terminal = 0.85;
};
targets = {
hyprlock = {
enable = false;
useWallpaper = false;
};
firefox = {
enable = false;
profileNames = [
"default"
"954lxlok.default"
];
};
};
};
}

View File

@@ -115,8 +115,8 @@ in
tarnow = "${getExe pkgs.gnutar} -acf ";
untar = "${getExe pkgs.gnutar} -zxvf ";
wget = "${getExe pkgs.wget} -c ";
remove-empty = "${getExe' pkgs.findutils "find"} . -type d --empty --delete";
print-empty = "${getExe' pkgs.findutils "find"} . -type d --empty --print";
remove-empty = ''${getExe' pkgs.findutils "find"} . -type d --empty --delete'';
print-empty = ''${getExe' pkgs.findutils "find"} . -type d --empty --print'';
dfh = "${getExe' pkgs.coreutils "df"} -h";
duh = "${getExe' pkgs.coreutils "du"} -h";
usage = "${getExe' pkgs.coreutils "du"} -ah -d1 | sort -rn 2>/dev/null";

View File

@@ -0,0 +1,131 @@
{
config,
pkgs,
lib,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.services.actual;
dataDir = "/data";
hostAddress = "10.0.1.3";
actualUserId = config.users.users.nix-apps.uid;
actualGroupId = config.users.groups.jallen-nas.gid;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
containers.actual = {
autoStart = true;
privateNetwork = true;
hostAddress = hostAddress;
localAddress = cfg.localAddress;
bindMounts = {
${dataDir} = {
hostPath = cfg.dataDir;
isReadOnly = false;
};
};
config =
{ lib, ... }:
{
services.actual = {
enable = true;
openFirewall = true;
settings = {
trustedProxies = [ hostAddress ];
port = cfg.port;
dataDir = dataDir;
serverFiles = "${dataDir}/server-files";
userFiles = "${dataDir}/user-files";
};
};
users.users.actual = {
isSystemUser = true;
uid = lib.mkForce actualUserId;
group = "actual";
};
users.groups = {
actual = {
gid = lib.mkForce actualGroupId;
};
};
# System packages
environment.systemPackages = with pkgs; [
sqlite
];
# Create and set permissions for required directories
system.activationScripts.actual-dirs = ''
mkdir -p ${dataDir}
chown -R actual:actual ${dataDir}
chmod -R 0700 ${dataDir}
'';
systemd.services = {
actual = {
environment.ACTUAL_CONFIG_PATH = lib.mkForce "${dataDir}/config.json";
serviceConfig = {
ExecStart = lib.mkForce "${pkgs.actual-server}/bin/actual-server --config ${dataDir}/config.json";
WorkingDirectory = lib.mkForce dataDir;
StateDirectory = lib.mkForce dataDir;
StateDirectoryMode = lib.mkForce 700;
DynamicUser = lib.mkForce false;
ProtectSystem = lib.mkForce null;
};
};
};
networking = {
firewall = {
enable = true;
allowedTCPPorts = [ cfg.port ];
};
# Use systemd-resolved inside the container
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
useHostResolvConf = lib.mkForce false;
};
services.resolved.enable = true;
system.stateVersion = "23.11";
};
};
services.traefik.dynamicConfigOptions = lib.mkIf cfg.reverseProxy.enable {
services.actual.loadBalancer.servers = [
{
url = "http://${cfg.localAddress}:${toString cfg.port}";
}
];
routers.actual = {
entryPoints = [ "websecure" ];
rule = "Host(`${cfg.reverseProxy.host}`)";
service = "actual";
middlewares = cfg.reverseProxy.middlewares;
tls.certResolver = "letsencrypt";
};
};
networking = {
nat = {
forwardPorts = [
{
destination = "${cfg.localAddress}:${toString cfg.port}";
sourcePort = cfg.port;
}
];
};
firewall = {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
};
};
}

View File

@@ -0,0 +1,37 @@
{ lib, namespace, ... }:
with lib;
{
options.${namespace}.services.actual = {
enable = mkEnableOption "actual service";
port = mkOption {
type = types.int;
default = 80;
};
localAddress = mkOption {
type = types.str;
default = "127.0.0.1";
};
dataDir = mkOption {
type = types.str;
default = "";
};
reverseProxy = {
enable = mkOption {
type = types.bool;
default = false;
};
host = mkOption {
type = types.str;
default = "";
};
middlewares = mkOption {
type = with types; listOf str;
default = [ ];
};
};
};
}

70
modules/nixos/amd/default.nix Executable file
View File

@@ -0,0 +1,70 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.share.hardware.amd;
pkgsVersion = pkgs; # .unstable;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
boot = {
kernelModules = [ "nct6775" ];
kernelParams = [ (if cfg.enable then "amdgpu.ppfeaturemask=0xffffffff" else null) ];
};
# Configure programs
programs.corectrl = {
enable = cfg.corectrl.enable;
package = pkgsVersion.corectrl;
};
# Configure environment
environment = {
# Force radv
variables = {
AMD_VULKAN_ICD = "RADV";
STEAM_FORCE_DESKTOPUI_SCALING = "1.0";
GDK_SCALE = "1";
};
};
# Configure polkit
security.polkit = lib.mkIf cfg.corectrl.enablePolkit {
extraConfig = ''
polkit.addRule(function(action, subject) {
if ((action.id == "org.corectrl.helper.init" ||
action.id == "org.corectrl.helperkiller.init") &&
subject.local == true &&
subject.active == true &&
subject.isInGroup("${cfg.corectrl.polkitGroup}")) {
return polkit.Result.YES;
}
});
'';
};
# nixpkg is broken so need to manually define
systemd.services.lactd = lib.mkIf cfg.lact.enable {
description = "AMDGPU Control Daemon";
path = with pkgsVersion; [
bash
lact
];
script = ''
lact daemon
'';
wantedBy = [ "multi-user.target" ];
after = [ "multi-user.target" ];
};
# Configure environment
environment = {
systemPackages = with pkgsVersion; lib.mkIf cfg.lact.enable [ lact ];
};
};
}

27
modules/nixos/amd/options.nix Executable file
View File

@@ -0,0 +1,27 @@
{ lib, ... }:
with lib;
{
options.share.hardware.amd = {
enable = mkEnableOption "amd hardware config";
corectrl.enable = mkOption {
type = types.bool;
default = false;
};
corectrl.enablePolkit = mkOption {
type = types.bool;
default = false;
};
corectrl.polkitGroup = mkOption {
type = types.str;
default = "wheel";
};
lact.enable = mkOption {
type = types.bool;
default = false;
};
};
}

View File

@@ -1,18 +1,10 @@
{
lib,
pkgs,
system,
...
}:
let
isArm = "aarch64-linux" == system;
in
{ lib, pkgs, ... }:
{
boot = {
# Enable AppImage
binfmt.registrations.appimage = lib.mkIf (!isArm) {
binfmt.registrations.appimage = {
wrapInterpreterInShell = lib.mkDefault false;
interpreter = "${lib.getExe pkgs.appimage-run}/bin/appimage-run";
interpreter = "${pkgs.appimage-run}/bin/appimage-run";
recognitionType = "magic";
offset = 0;
mask = "\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x00\\xff\\xff\\xff";

Some files were not shown because too many files have changed in this diff Show More