695 Commits

Author SHA1 Message Date
mjallen18
3e232c3474 overlays lol 2026-03-16 14:25:26 -05:00
mjallen18
e6c9e21c62 termix 2026-03-16 14:06:22 -05:00
de8ec35cbb bruh 2026-03-16 12:14:02 -05:00
3e6e975ce5 ally 2026-03-16 12:12:02 -05:00
897ca32919 grrr 2026-03-16 12:00:43 -05:00
8d2b16825a up 2026-03-16 11:57:25 -05:00
33f0a085ef iwd 2026-03-16 11:38:44 -05:00
mjallen18
798f233ff2 asd 2026-03-15 20:20:14 -05:00
mjallen18
f968cc0e8d srm 2026-03-15 20:17:53 -05:00
mjallen18
cd6188775f srm 2026-03-15 20:08:20 -05:00
mjallen18
e13c19e698 asd 2026-03-15 20:07:41 -05:00
mjallen18
56c2ef7b96 srm 2026-03-15 20:06:27 -05:00
mjallen18
829b369ebe srm 2026-03-15 19:52:22 -05:00
mjallen18
9891b3abff a 2026-03-15 19:04:38 -05:00
mjallen18
8fc34adfc6 deck 2026-03-15 19:00:33 -05:00
mjallen18
56c3bfdd91 hass esphome 2026-03-14 13:52:54 -05:00
mjallen18
21a9b476e2 sleep? 2026-03-14 13:50:28 -05:00
mjallen18
2314dd3225 hhd 2026-03-14 13:29:40 -05:00
mjallen18
9cd0677ba0 hhd 2026-03-14 13:28:02 -05:00
mjallen18
2699bc0f0d drwin 2026-03-14 13:26:56 -05:00
mjallen18
996571a544 hass esphome 2026-03-14 12:36:49 -05:00
mjallen18
4f4b7865eb kek 2026-03-13 20:01:27 -05:00
mjallen18
c5e97ac853 kek 2026-03-13 19:11:58 -05:00
mjallen18
778e9ce02b lol 2026-03-13 19:11:43 -05:00
mjallen18
39b898bcf2 lol 2026-03-13 14:45:00 -05:00
mjallen18
9737b3af9f idk man 2026-03-13 13:38:53 -05:00
mjallen18
3862a6b651 up 2026-03-13 12:18:59 -05:00
mjallen18
2500f5ffa0 lol 2026-03-13 11:15:07 -05:00
mjallen18
8d3574e183 kek 2026-03-10 12:32:49 -05:00
mjallen18
631d7336f6 kek 2026-03-10 11:16:16 -05:00
mjallen18
01f6eeff7c lol 2026-03-10 11:13:25 -05:00
2fbfd9c2d3 lmfao 2026-03-10 11:05:14 -05:00
89196706c7 lmfao 2026-03-10 11:02:13 -05:00
mjallen18
1616c6766e lmao perhaps 2026-03-10 10:51:32 -05:00
mjallen18
c13ce86810 lol 2026-03-10 10:27:51 -05:00
mjallen18
cce8f2ea03 bring back allyx maybe 2026-03-10 10:06:55 -05:00
mjallen18
75c64f2499 bruh 2026-03-10 09:56:06 -05:00
mjallen18
9daf43e3f3 upd 2026-03-08 20:23:35 -05:00
mjallen18
f369128cb7 auth 2026-03-06 10:02:19 -06:00
mjallen18
6210605ac2 net 2026-03-06 09:26:24 -06:00
mjallen18
f1493146ab auth 2026-03-06 09:25:58 -06:00
mjallen18
86acd96e07 hasp 2026-03-05 16:01:07 -06:00
mjallen18
e5b7c403a3 hasp 2026-03-05 15:44:44 -06:00
mjallen18
805699d9d0 hasp 2026-03-05 15:41:45 -06:00
mjallen18
bcc7214c43 hasp ids 2026-03-05 15:37:19 -06:00
mjallen18
52bc808a0a fixes 2026-03-05 14:40:48 -06:00
mjallen18
0beecf9cce hasp? 2026-03-05 14:33:30 -06:00
mjallen18
eac037caf8 hasp? 2026-03-05 14:27:21 -06:00
mjallen18
56c4e1fcad conver 2026-03-05 10:34:34 -06:00
mjallen18
8d299980fb conver 2026-03-05 10:29:06 -06:00
a2ee0e2a55 fix pi5 2026-03-05 09:30:37 -06:00
mjallen18
401e5f7bd8 upd 2026-03-04 21:26:10 -06:00
mjallen18
2398b810dc upd 2026-03-04 21:18:59 -06:00
79b0fdf4c4 pi 7.0 2026-03-04 15:58:34 -06:00
mjallen18
46d35ab70e versions 2026-03-04 15:55:38 -06:00
mjallen18
0dc60c261b versions 2026-03-04 15:52:24 -06:00
mjallen18
23f5f6c3b3 versions 2026-03-04 15:31:10 -06:00
mjallen18
d17d096a97 versions 2026-03-04 13:43:18 -06:00
5f79421d9e code 2026-03-04 10:39:37 -06:00
5eaf1cce2a gnome notch 2026-03-04 10:33:51 -06:00
85b35eaedc gnome notch 2026-03-04 10:33:27 -06:00
mjallen18
3c4856ddca apps 2026-03-03 16:32:55 -06:00
ff92934cc4 port lol 2026-03-03 16:31:35 -06:00
c304fefb54 tunarr 2026-03-03 16:25:09 -06:00
mjallen18
9b1c9a6371 stuff 2026-03-03 15:21:30 -06:00
mjallen18
b0ecedaf2a stuff 2026-03-03 15:21:30 -06:00
mjallen18
8d7a112365 bcachefs 2026-03-03 14:50:56 -06:00
5994b99288 disks 2026-03-03 14:48:32 -06:00
mjallen18
9e755ab926 bcachefs 2026-03-03 14:41:24 -06:00
e277a56233 versions 2026-03-03 14:36:47 -06:00
41361e5bc1 versions 2026-03-03 14:33:17 -06:00
mjallen18
85b69d69ff idk 2026-03-03 14:18:44 -06:00
9a962363e8 asahi 2026-03-03 13:56:59 -06:00
mjallen18
d856b57f13 fix 2026-03-03 11:21:33 -06:00
mjallen18
7e85953133 up 2026-03-03 10:42:08 -06:00
mjallen18
3655680e7c drwin 2026-03-03 10:08:23 -06:00
mjallen18
1fc2a7a89f temp 2026-03-03 09:51:12 -06:00
mjallen18
ddd99ef396 upd 2026-03-03 09:49:00 -06:00
mjallen18
ff9aea7a58 cleanup 2026-02-24 14:18:47 -06:00
mjallen18
4c5118c181 cachy 2026-02-23 18:13:56 -06:00
mjallen18
2e0d6aebb5 sparky but broken testing 2026-02-21 11:36:50 -06:00
mjallen18
974b696ef8 cachy 2026-02-20 20:53:19 -06:00
afccded50c attempt omnissa on arm 2026-02-20 14:06:42 -06:00
mjallen18
0d835df1aa retire pi4 2026-02-19 18:47:05 -06:00
mjallen18
d7958927b5 retire pi4 2026-02-19 18:35:13 -06:00
a5162e9e76 rpi 2026-02-17 10:37:07 -06:00
ed19748358 asahi: 2026-02-17 08:49:24 -06:00
mjallen18
2efe3fa067 up 2026-02-16 14:28:22 -06:00
mjallen18
c7a3aa6897 cleanup 2026-02-16 12:07:05 -06:00
mjallen18
f7ecb901db nebula 2026-02-13 20:38:19 -06:00
mjallen18
66ee83167f stuff 2026-02-13 19:20:25 -06:00
mjallen18
1740116e6b bruh 2026-02-13 18:55:12 -06:00
mjallen18
80204acfb6 nbula 2026-02-13 18:27:31 -06:00
mjallen18
c50aa6d68e trust 2026-02-13 18:20:49 -06:00
mjallen18
99a6b40776 idk 2026-02-13 18:18:40 -06:00
mjallen18
d855e75e48 dns 2026-02-13 15:18:07 -06:00
mjallen18
ae9075e795 pi5 2026-02-13 15:11:57 -06:00
mjallen18
3b3ec68a3c sp 2026-02-13 14:28:28 -06:00
mjallen18
e771770ae2 neb2 2026-02-13 14:27:59 -06:00
mjallen18
17a1307343 neb 2026-02-13 14:27:00 -06:00
mjallen18
fe77b68446 bro 2026-02-13 14:22:12 -06:00
mjallen18
6ebc1bb103 nebula 2026-02-13 13:14:35 -06:00
mjallen18
869a320ede collabora 2026-02-12 21:57:00 -06:00
mjallen18
fd437ec528 nextcloud broke lmao 2026-02-12 20:12:58 -06:00
mjallen18
9a63c609fa nextcloud broke lmao 2026-02-12 14:54:05 -06:00
mjallen18
b46628a747 nextcloud 2026-02-12 14:31:22 -06:00
mjallen18
48d864bb64 caddy 2026-02-11 22:26:34 -06:00
mjallen18
92b6e7a822 caddy 2026-02-11 22:23:00 -06:00
mjallen18
89275509f3 uns-sm 2026-02-10 20:12:21 -06:00
mjallen18
28c6306182 kernels 2026-02-10 20:07:40 -06:00
mjallen18
535fdc2f86 ha 2026-02-10 19:44:41 -06:00
mjallen18
09d9b010b7 dummy 2026-02-10 13:51:19 -06:00
mjallen18
ec76404122 ha 2026-02-10 12:39:24 -06:00
5c94bd7fcb ha up 2026-02-10 12:34:05 -06:00
07e8fc704f bruh 2026-02-09 21:18:53 -06:00
mjallen18
27e0a448b8 secrets 2026-02-09 21:15:42 -06:00
50773eda54 for test 2026-02-09 21:15:31 -06:00
c8f8fce410 perms lol 2026-02-09 21:07:18 -06:00
2184135c7c perms? 2026-02-09 21:06:34 -06:00
60df52b090 books2 2026-02-09 21:05:25 -06:00
5e6edd00bb books 2026-02-09 21:05:02 -06:00
319923c57c m 2026-02-09 21:00:12 -06:00
eb2ebdca84 mariadb 2026-02-09 20:58:55 -06:00
mjallen18
d9c801530d idk 2026-02-09 18:31:19 -06:00
f5b0b16c22 cache 2026-02-09 18:23:37 -06:00
a95bc4db39 cache 2026-02-09 18:04:24 -06:00
b5b5bf43e2 mac key 2026-02-09 17:58:47 -06:00
49e60a0d27 cache 2026-02-09 17:55:30 -06:00
3d21a345c3 idk 2026-02-09 17:50:26 -06:00
a740e1c33a idk 2026-02-09 16:45:56 -06:00
mjallen18
bc16420869 secrets 2026-02-09 16:45:11 -06:00
mjallen18
1731647367 sab 2026-02-09 16:35:55 -06:00
mjallen18
9ad06425c8 idk 2026-02-09 16:35:55 -06:00
525cc60739 plymouth apple 2026-02-09 16:01:50 -06:00
mjallen18
3595428e02 upd 20260209 2026-02-09 08:54:19 -06:00
4ed90347f8 boxbuddy 2026-02-09 08:21:41 -06:00
b92dda099b gnome caffeine 2026-02-06 13:36:32 -06:00
mjallen18
f61dbc7190 sops sync 2026-02-06 09:34:43 -06:00
a48fc8fffe ke 2026-02-06 09:34:00 -06:00
mjallen18
4d107533ea ppd 2026-02-06 09:26:20 -06:00
mjallen18
2c3cc8ed18 sadasdad 2026-02-06 09:25:41 -06:00
mjallen18
334d69894e stuff 2026-02-06 09:25:05 -06:00
mjallen18
31a9957877 idk 2026-02-06 09:11:49 -06:00
mjallen18
dc25f02010 config 2026-02-06 08:56:16 -06:00
mjallen18
ef8e52b93f sops 2026-02-06 08:50:23 -06:00
mjallen18
bf48d8fcf0 nix 2026-02-06 08:48:46 -06:00
mjallen18
a68c91264f ice 2026-02-05 17:39:47 -06:00
mjallen18
75d7097e23 fix nuc stuff 2026-02-05 17:05:30 -06:00
mjallen18
b738f38267 idk 2026-02-05 16:59:54 -06:00
mjallen18
32b0e67a7a idk 2026-02-05 16:48:27 -06:00
mjallen18
f352ef1c05 idk 2026-02-05 16:14:35 -06:00
mjallen18
1ea8c8b6a9 mac 2026-02-04 22:38:54 -06:00
mjallen18
eac9c4b67d http1 traefik 2026-02-04 22:05:56 -06:00
mjallen18
ce4047b62f sad 2026-02-04 21:15:28 -06:00
mjallen18
aff6fa9ec6 fix nuc stuff 2026-02-04 21:11:23 -06:00
mjallen18
a9c1d71495 fmt 2026-02-04 20:40:34 -06:00
mjallen18
4d4808490b fix traefik stuff 2026-02-04 20:02:32 -06:00
mjallen18
1f99318fcd stuffs like bruh wtf 2026-02-04 19:40:00 -06:00
mjallen18
87fb1c96e5 stuffs 2026-02-04 13:08:39 -06:00
mjallen18
aa7fc9c228 rpi lin 2026-02-03 10:21:00 -06:00
mjallen18
f856076452 stuffs 2026-02-02 19:33:04 -06:00
mjallen18
d9d7760e58 nix fmt 2026-02-02 18:14:04 -06:00
mjallen18
bd8d1e6485 cleanup 2026-02-02 18:11:45 -06:00
mjallen18
8fa82bce90 stuffs 2026-02-02 11:13:19 -06:00
mjallen18
187b478c5d hyprland rules 2026-01-31 10:19:49 -06:00
mjallen18
25ef179d3a kerns 2026-01-30 23:46:05 -06:00
mjallen18
57d1a8d864 what 2026-01-30 23:38:24 -06:00
mjallen18
c83cfcf06b stuff 2026-01-30 23:37:53 -06:00
mjallen18
59268d1da3 what 2026-01-30 22:47:46 -06:00
mjallen18
bca4a13614 bruh 2026-01-30 22:45:46 -06:00
mjallen18
044bac7464 fix mount 2026-01-30 08:43:19 -06:00
mjallen18
10fa5498ee idk shits so fucked lol 2026-01-30 08:36:17 -06:00
mjallen18
1331e69b58 idk shits so fucked lol 2026-01-29 19:15:22 -06:00
mjallen18
9c8733431d idk 2026-01-28 10:18:25 -06:00
mjallen18
ad15679eb4 idk 2026-01-27 18:21:37 -06:00
mjallen18
01ae622391 perms 2026-01-27 13:01:36 -06:00
mjallen18
defbd725dd secrets 2026-01-27 12:44:16 -06:00
mjallen18
d2c1cbf987 what 2026-01-27 12:34:40 -06:00
mjallen18
14db694b90 testing 2026-01-27 11:21:42 -06:00
mjallen18
10fc7820e1 testing 2026-01-27 11:13:58 -06:00
mjallen18
176d0b7311 testing 2026-01-26 18:01:56 -06:00
mjallen18
1fc2ce66cf testing 2026-01-26 17:39:52 -06:00
mjallen18
f93d69a259 testing 2026-01-26 17:30:16 -06:00
mjallen18
d7afac2fb9 testing 2026-01-26 17:20:27 -06:00
mjallen18
3aa0407532 testing 2026-01-26 17:18:18 -06:00
mjallen18
c29ff231f9 testing 2026-01-26 17:16:33 -06:00
c5481909a1 isk 2026-01-26 23:08:34 +00:00
mjallen18
8b4489cf8f testing 2026-01-26 15:38:24 -06:00
mjallen18
d1d68e154d tpm unlock+moondeck 2026-01-23 23:26:02 -06:00
mjallen18
3ff7bed41d tpm unlock 2026-01-23 16:05:44 -06:00
mjallen18
19acd60ed7 flake 2026-01-23 14:40:41 -06:00
mjallen18
6cfb31fdc9 remove sd 2026-01-23 14:33:59 -06:00
mjallen18
e5dbeadbb6 upd 2026-01-23 14:21:03 -06:00
mjallen18
302d7f5af5 build2 2026-01-23 13:30:48 -06:00
mjallen18
148229f551 proton-cachy rename for convenience 2026-01-22 21:41:00 -06:00
mjallen18
5a22ad0f88 fmt 2026-01-22 16:08:24 -06:00
mjallen18
5b96b59e60 edk 2026-01-22 15:37:42 -06:00
mjallen18
bfd5e90613 what a mess 2026-01-22 13:57:21 -06:00
mjallen18
fdaa34191c build2 2026-01-22 13:54:07 -06:00
mjallen18
fde852b29b fixes 2026-01-22 13:39:46 -06:00
mjallen18
d4e0b93e4e fix cachy kernel 2026-01-22 13:25:34 -06:00
mjallen18
1410f0fe25 package upd tui 2026-01-22 12:55:23 -06:00
mjallen18
5fed9a649f pi5d0 2026-01-22 11:54:53 -06:00
mjallen18
9b87aa9d3e fixes 2026-01-22 11:54:10 -06:00
mjallen18
e7a6fdb644 cleanup 2026-01-22 11:28:43 -06:00
mjallen18
871f099dac start dynamic dt overlays 2026-01-22 09:42:16 -06:00
mjallen18
a07f694806 pi 2026-01-22 09:12:36 -06:00
mjallen18
45f40e45d8 stuff 2026-01-22 09:06:45 -06:00
mjallen18
7c7c1dc3f4 cleanup 2026-01-22 08:53:24 -06:00
mjallen18
bd44913ccc cleanup 2026-01-22 08:51:34 -06:00
mjallen18
a5b53e66e7 cleanup 2026-01-22 08:49:09 -06:00
mjallen18
5d9613ee13 stuff 2026-01-22 08:45:26 -06:00
mjallen18
3dea6e0a9e test 2026-01-22 08:38:50 -06:00
mjallen18
9ab1c99914 move 2026-01-22 08:37:01 -06:00
mjallen18
62ff7b829a aarch maybe 2026-01-22 08:34:47 -06:00
mjallen18
477b79bfb8 move 2026-01-21 21:47:08 -06:00
mjallen18
e2e2d814fe nix fmt 2026-01-21 21:43:31 -06:00
mjallen18
94c3d6d6ff packages 2026-01-21 21:41:01 -06:00
mjallen18
a336b0cf60 packages 2026-01-21 21:17:36 -06:00
mjallen18
a94e68514a scripts 2026-01-21 20:48:12 -06:00
mjallen18
fb68d25008 bulk versions.json 2026-01-21 20:47:21 -06:00
mjallen18
2b9908e760 bulk versions.json 2026-01-21 12:53:13 -06:00
mjallen18
7cc4e8c99e what a mess 2026-01-20 13:53:10 -06:00
mjallen18
fbdbbdf328 aarch maybe 2026-01-20 13:50:46 -06:00
mjallen18
d4799b6598 what a mess 2026-01-20 13:50:33 -06:00
mjallen18
6a9ec8f933 what a mess 2026-01-20 12:41:45 -06:00
mjallen18
fa236b7076 aarch maybe 2026-01-20 12:38:59 -06:00
mjallen18
05bd3f1a60 bruh 2026-01-20 12:34:23 -06:00
mjallen18
a3ade57500 what a mess 2026-01-20 12:25:06 -06:00
mjallen18
e40181ba04 bruh 2026-01-20 12:18:46 -06:00
mjallen18
cedd4051f7 what a mess 2026-01-20 12:17:57 -06:00
mjallen18
5a992567b8 bcachefs-tools for 6.19 2026-01-20 09:04:49 -06:00
mjallen18
631bdd3c2c idk 2026-01-19 12:35:11 -06:00
mjallen18
a968cb4b4f idk 2026-01-19 12:11:19 -06:00
mjallen18
d76fdcbab6 idk 2026-01-19 12:11:19 -06:00
mjallen18
e2dfca0245 nothing n 2026-01-19 10:54:27 -06:00
mjallen18
59500f3e50 update cachy kernel 2026-01-19 10:44:49 -06:00
mjallen18
a74305a444 ally keys 2026-01-16 21:43:46 -06:00
mjallen18
e39614a9c8 pw 2026-01-16 18:52:08 -06:00
mjallen18
b5de056631 force 2026-01-16 18:27:53 -06:00
mjallen18
49680a9188 greeter 2026-01-16 18:27:22 -06:00
mjallen18
c3865f2742 ally 2026-01-16 18:25:49 -06:00
mjallen18
341d522fd4 steam stuff 2026-01-16 17:49:46 -06:00
mjallen18
51f4b335b1 cosmic? 2026-01-16 17:41:18 -06:00
mjallen18
77dc15e0e1 maybe 2026-01-16 14:14:18 -06:00
mjallen18
a0c2753f37 fix sd 2026-01-16 12:40:35 -06:00
mjallen18
7320b0ee87 sd 2026-01-16 12:36:28 -06:00
mjallen18
10268e7677 kde 2026-01-16 12:25:36 -06:00
mjallen18
f57617e268 stuff 2026-01-16 10:47:07 -06:00
mjallen18
b613f941a6 idk: 2026-01-16 08:45:50 -06:00
mjallen18
b3138d0fca stuff 2026-01-16 08:45:27 -06:00
mjallen18
9376005a21 stuff 2026-01-15 13:53:59 -06:00
mjallen18
549580395f avizo + kbd backlight 2026-01-15 12:50:25 -06:00
mjallen18
3f5634317b ver 2026-01-15 09:42:21 -06:00
mjallen18
26746873f3 naming 2026-01-15 09:41:43 -06:00
mjallen18
a58a9da64e rev 2026-01-15 09:33:49 -06:00
mjallen18
8e7a0343c2 some versions 2026-01-15 09:29:21 -06:00
mjallen18
d47b092a8c nothing n 2026-01-14 18:45:49 -06:00
mjallen18
4de54dee30 lol 2026-01-14 18:39:33 -06:00
mjallen18
455ea26cdc cleanup 2026-01-14 18:38:22 -06:00
mjallen18
7306b08762 fmt 2026-01-14 18:00:52 -06:00
mjallen18
59b4729636 fix warning 2026-01-14 16:38:42 -06:00
mjallen18
afe04b88b0 lol 2026-01-14 15:34:47 -06:00
mjallen18
b1215da790 wtf 2026-01-14 10:37:22 -06:00
mjallen18
b1f2521260 edk2 pi5 building 2026-01-13 19:29:42 -06:00
mjallen18
57add82f95 edk2 pi5 building 2026-01-13 19:28:08 -06:00
mjallen18
49485c91a6 idk 2026-01-13 18:38:20 -06:00
mjallen18
a7c25fe70d pi4 edk2 builds 2026-01-13 14:54:55 -06:00
mjallen18
1dc075f405 fix 2026-01-12 20:22:09 -06:00
mjallen18
2a17112d50 idk man 2026-01-12 20:11:49 -06:00
mjallen18
a59d5ce3b1 hass stuff 2026-01-12 15:26:41 -06:00
mjallen18
639ce36cb0 otbr 2026-01-12 15:13:02 -06:00
mjallen18
42e771ef1f otbr 2026-01-12 15:11:47 -06:00
mjallen18
37d472c7db hass 2026-01-12 14:11:04 -06:00
mjallen18
382f059188 upd full 2026-01-12 12:08:36 -06:00
mjallen18
dfd8d9a1a8 tailscale 2026-01-10 13:36:57 -06:00
mjallen18
fcddde0c06 temp sunshine 2026-01-09 16:17:22 -06:00
mjallen18
ad16b47827 librepods rust 2026-01-09 15:49:19 -06:00
mjallen18
994fddba66 set uefi nvram for convenience 2026-01-09 13:19:29 -06:00
mjallen18
0483ea8a67 cleanup dsc 2026-01-09 13:09:14 -06:00
mjallen18
b6e5223d96 nvram 2026-01-09 13:08:02 -06:00
mjallen18
ed7656cf3e up kern 2026-01-09 12:10:37 -06:00
mjallen18
76b6255169 edk 2026-01-09 12:10:25 -06:00
mjallen18
5f5972f10f pi5 2026-01-09 10:44:17 -06:00
mjallen18
82dffdf505 pi5 kernel 2026-01-09 10:40:07 -06:00
mjallen18
741ab5c7ec config 2026-01-09 09:03:39 -06:00
mjallen18
3d0d5c878c darwin 2026-01-09 09:02:20 -06:00
mjallen18
0bb71bbb4f pi stufF 2026-01-09 08:54:17 -06:00
mjallen18
741de00ef7 edk 2026-01-08 23:04:40 -06:00
mjallen18
c7c5192c0c pi5 2026-01-08 11:50:24 -06:00
mjallen18
052f7a2838 pi stufF 2026-01-07 22:38:59 -06:00
mjallen18
ca17f0fe18 uefi stuff 2026-01-07 21:28:20 -06:00
mjallen18
e76f74e63a uefi stuff 2026-01-07 19:06:52 -06:00
mjallen18
88e81c9aaa pi stufF 2026-01-07 15:32:50 -06:00
mjallen18
8406714527 16k 2026-01-07 15:27:39 -06:00
mjallen18
97e4060b52 uefi stuff 2026-01-07 12:44:59 -06:00
mjallen18
59121cf43b uefi stuff 2026-01-07 12:44:33 -06:00
mjallen18
e15d62d03a oops 2026-01-07 09:57:56 -06:00
mjallen18
3268c28cc8 openrgb 2026-01-07 09:46:13 -06:00
mjallen18
e4ac3b99cd mac stuff 2026-01-07 09:18:26 -06:00
mjallen18
dabd791fac nix format 2026-01-07 09:17:34 -06:00
mjallen18
98c627531c hass unstable 2026-01-06 14:10:11 -06:00
mjallen18
c8f41cf7d8 disable cache, stable 2026-01-06 13:44:05 -06:00
mjallen18
78f8d1a733 idk man 2026-01-06 10:21:50 -06:00
mjallen18
b05067a3e1 kernels 2026-01-05 23:57:21 -06:00
mjallen18
3b780d4d78 bruh 2026-01-05 23:31:06 -06:00
mjallen18
77c76e6483 chack 2026-01-05 14:54:52 -06:00
mjallen18
cd03862e4b pi stuff 2026-01-03 11:22:12 -06:00
mjallen18
e6a69cc21f user 2026-01-03 11:14:49 -06:00
mjallen18
c6317cdd18 fixes 2026-01-03 11:10:23 -06:00
mjallen18
ca73743483 lock update 2026-01-03 11:04:58 -06:00
mjallen18
105ed3bcb8 nix format 2026-01-03 09:28:28 -06:00
mjallen18
4a6a68dad4 temp fix glance 2026-01-03 09:27:28 -06:00
mjallen18
56154fe941 check 2026-01-02 20:30:05 -06:00
mjallen18
b7380317b9 cleanup 2026-01-02 14:46:36 -06:00
mjallen18
579c83164e fix 2026-01-02 14:45:58 -06:00
mjallen18
56fb195967 upd 2026-01-02 14:41:08 -06:00
mjallen18
451f5aa726 pi4 2026-01-02 14:31:10 -06:00
mjallen18
5c359dca81 ccache 2026-01-02 12:22:51 -06:00
mjallen18
6b28a8df9c lto 2026-01-02 12:21:51 -06:00
mjallen18
dfc2c8faa4 oop 2026-01-02 11:56:31 -06:00
mjallen18
0f42ffeebd arm 2026-01-02 11:55:52 -06:00
mjallen18
1d5b1cf5e0 check 2026-01-02 11:05:48 -06:00
mjallen18
8fc40f265b pi stuff 2026-01-02 09:47:24 -06:00
mjallen18
cdf388cf17 mbp 2026-01-02 09:14:09 -06:00
mjallen18
8088ea0933 mbp 2026-01-02 09:14:09 -06:00
mjallen18
9305483e09 lol 2026-01-02 00:06:48 -06:00
mjallen18
687a3a6446 cachy stuff 2026-01-01 23:11:27 -06:00
mjallen18
1e5ef59d56 fix overlay and upd 2026-01-01 22:00:31 -06:00
mjallen18
a7389ac9b2 temp 2026-01-01 21:47:14 -06:00
mjallen18
501329def1 uefi testing 2026-01-01 19:18:20 -06:00
mjallen18
3063d6b161 uefi testing 2026-01-01 19:15:41 -06:00
mjallen18
c4ea874ae7 parted 2025-12-31 09:23:43 -06:00
mjallen18
68dbe98370 uh 2025-12-30 20:40:45 -06:00
mjallen18
374bd4348f pi4 stuff 2025-12-30 20:40:22 -06:00
mjallen18
5ee4da5b08 dtbs 2025-12-30 17:35:51 -06:00
mjallen18
bf31786735 tree 2025-12-30 17:30:41 -06:00
mjallen18
b216fe5215 bruh 2025-12-30 14:28:48 -06:00
mjallen18
b36ae0914c sunshine apps 2025-12-30 11:11:30 -06:00
mjallen18
edd6291176 sunshine apps 2025-12-30 09:48:36 -06:00
mjallen18
b91afbc323 sunshine ports 2025-12-30 09:05:00 -06:00
mjallen18
450dc1ad91 sd discord 2025-12-30 08:43:43 -06:00
mjallen18
eed1d28bd8 sunshine 2025-12-30 08:41:48 -06:00
mjallen18
ae8bcdf690 idk 2025-12-29 21:43:09 -06:00
mjallen18
4ac6de479c uh 2025-12-29 19:46:31 -06:00
mjallen18
14990b28e4 overlay 2025-12-29 19:44:53 -06:00
mjallen18
ede0bf5c10 maybe 2025-12-29 19:43:26 -06:00
mjallen18
ae95786d8e comment 2025-12-29 19:26:22 -06:00
mjallen18
209e776640 dtsoverlays 2025-12-29 19:22:11 -06:00
mjallen18
82e062a7e8 checkpoint lol 2025-12-29 15:18:59 -06:00
mjallen18
67fb7d7323 'building' 2025-12-29 15:18:05 -06:00
mjallen18
462494277a idk 2025-12-29 10:49:59 -06:00
mjallen18
8fbf8c54eb cache 2025-12-27 11:45:28 -06:00
mjallen18
f549723a61 'building' 2025-12-26 22:47:11 -06:00
mjallen18
c8aebb9e4a ugh 2025-12-26 18:22:49 -06:00
mjallen18
afb60fc031 stuff 2025-12-26 16:20:02 -06:00
mjallen18
4604e24ee5 stuff 2025-12-26 14:54:03 -06:00
mjallen18
3233955690 kernel test 2025-12-26 14:53:27 -06:00
mjallen18
c9f75a053c upd and cache 2025-12-26 11:45:05 -06:00
mjallen18
f7cb1cb217 nuc 2025-12-23 22:14:22 -06:00
mjallen18
d981fb20c2 fmt ++ 2025-12-23 21:04:21 -06:00
mjallen18
8f08f24761 idk 2025-12-23 18:41:22 -06:00
mjallen18
74e772582d stuff and thangs 2025-12-23 10:41:21 -06:00
mjallen18
15f186e3ce darwin 2025-12-23 10:37:03 -06:00
mjallen18
7d92e9b1cc fix linux-builder ccache 2025-12-22 15:28:42 -06:00
mjallen18
53a2d01a83 up 2025-12-22 14:55:32 -06:00
mjallen18
abdeddf751 darwin 2025-12-19 17:05:58 -06:00
mjallen18
1280cf9939 darwin 2025-12-19 16:59:18 -06:00
mjallen18
76265f9b1b fix updates lol 2025-12-19 16:33:44 -06:00
mjallen18
66fe87dd23 update packages 2025-12-19 14:49:44 -06:00
mjallen18
e8fcf96253 services require storage 2025-12-19 14:06:18 -06:00
mjallen18
479ac18f20 some sops 2025-12-19 13:32:07 -06:00
mjallen18
ba446f408a matrix sops 2025-12-19 13:02:58 -06:00
mjallen18
05486efb75 mkModule various + fixes 2025-12-18 17:20:21 -06:00
mjallen18
e0b1e72431 mkModule various + fixes 2025-12-18 16:47:12 -06:00
mjallen18
63bd725d64 mkModule various 2025-12-17 14:11:49 -06:00
mjallen18
96ce0001c5 mkModule various 2025-12-17 12:52:42 -06:00
mjallen18
50345adeb5 mkModule gitea 2025-12-15 20:07:48 -06:00
mjallen18
e74ea5f13b teml 2025-12-15 19:51:47 -06:00
mjallen18
367c3a16c5 nuc 2025-12-15 17:44:30 -06:00
mjallen18
4c784f5f33 pi stuff 2025-12-15 15:06:54 -06:00
mjallen18
fa0210e937 pi stuff 2025-12-15 15:00:11 -06:00
mjallen18
f803c37105 t 2025-12-15 14:59:12 -06:00
mjallen18
03b00c59b2 mkModule code-server 2025-12-15 09:17:26 -06:00
mjallen18
5c9a42fe71 mkModule calibre 2025-12-15 09:00:04 -06:00
mjallen18
3b95a97921 mkModule migration begin 2025-12-14 22:58:07 -06:00
mjallen18
2d03954a9f mkModule migration begin 2025-12-14 22:54:01 -06:00
mjallen18
3dc1055b54 mkModule migration begin 2025-12-14 22:47:59 -06:00
mjallen18
fedba849a7 mkModule migration begin 2025-12-14 22:47:51 -06:00
mjallen18
34539045e5 mkModule 2025-12-14 21:50:50 -06:00
mjallen18
0012a019fc upd 2025-12-14 20:33:39 -06:00
mjallen18
f09246dcba test 2025-12-14 10:19:28 -06:00
mjallen18
90daf80a88 icons 2025-12-14 09:50:53 -06:00
mjallen18
3c85ea0515 winboat 2025-12-13 14:31:21 -06:00
mjallen18
06e26e3be2 t 2025-12-12 15:08:26 -06:00
mjallen18
d76eff6f68 cleanup 2025-12-12 13:39:40 -06:00
mjallen18
ce39a330b1 cachy kernel naming 2025-12-12 13:25:50 -06:00
mjallen18
41063a1ef7 upd-scr 2025-12-11 22:06:40 -06:00
mjallen18
35206c8ed5 syntax 2025-12-11 22:01:11 -06:00
mjallen18
201ba0b780 checker 2025-12-11 21:39:37 -06:00
mjallen18
a273c701ab server-lto 2025-12-11 21:25:50 -06:00
mjallen18
2e4b629805 lto server 2025-12-11 21:19:40 -06:00
mjallen18
3364ae8fda nuc 2025-12-11 21:00:17 -06:00
mjallen18
15e0b9563f lto server 2025-12-11 20:45:11 -06:00
mjallen18
64f34892b7 server-lto 2025-12-11 19:55:17 -06:00
mjallen18
8d1a9312cb upd 2025-12-11 19:14:52 -06:00
mjallen18
31202f8b0e upd 2025-12-11 17:41:05 -06:00
mjallen18
82ecfba7db libre 2025-12-11 09:50:21 -06:00
mjallen18
f86808d86e discord w/ krisp 2025-12-11 09:38:39 -06:00
mjallen18
89c5d60be3 update cachy kernel 2025-12-10 13:53:35 -06:00
mjallen18
96c3a34449 cachy test 2025-12-10 10:49:41 -06:00
mjallen18
a5eba8ec68 init cachy kernel 2025-12-10 09:30:35 -06:00
mjallen18
764ce12aea clouds 2025-12-09 20:26:18 -06:00
mjallen18
989e717e4e opencloud fucked still lmao 2025-12-09 17:15:49 -06:00
mjallen18
4b53a89030 upd 2025-12-09 16:05:59 -06:00
mjallen18
70a54b208e upd 2025-12-08 10:20:27 -06:00
mjallen18
0b4d63fd09 update ha components 2025-12-05 17:22:51 -06:00
mjallen18
f54285bfe6 up 2025-12-05 12:30:46 -06:00
mjallen18
a94f5c20aa ld 2025-12-05 10:23:34 -06:00
mjallen18
adf1cc7ca6 yubi 2025-12-05 09:35:01 -06:00
mjallen18
d32826dc36 ccache? 2025-12-04 20:09:27 -06:00
mjallen18
3c1c5b6292 stylix 2025-12-04 19:36:22 -06:00
mjallen18
73a11e1ac8 stylix 2025-12-04 19:35:47 -06:00
mjallen18
88e29f74de lower refresh cause artifact 2025-12-04 19:16:49 -06:00
mjallen18
59702e15cf darwin 2025-12-04 14:00:20 -06:00
mjallen18
6c8d306d38 kmscon theme 2025-12-01 17:29:31 -06:00
f172707b15 stylix (#3)
Co-authored-by: mjallen18 <matt.l.jallen@gmail.com>
Reviewed-on: #3
2025-12-01 17:26:26 -06:00
mjallen18
672221f471 pi stuff 2025-12-01 12:06:00 -06:00
mjallen18
73581fd8f0 darwin 2025-12-01 11:22:24 -06:00
mjallen18
421c1e155b lib fixes, upd 2025-12-01 09:53:26 -06:00
mjallen18
be9be7a4c5 darwin 2025-12-01 09:50:06 -06:00
mjallen18
db988e9761 upd nixpkgs stable to 25.11 2025-11-30 21:55:18 -06:00
mjallen18
e1706274fd upd 2025-11-30 21:52:11 -06:00
mjallen18
96eda0dae7 fixes 2025-11-25 18:11:05 -06:00
mjallen18
33c00f0d7c protonmail bridge sucks 2025-11-25 15:35:42 -06:00
mjallen18
001f465153 whatev 2025-11-25 14:44:01 -06:00
mjallen18
61532d5149 maybe? 2025-11-25 14:43:38 -06:00
mjallen18
e1ccf848cf idk 2025-11-25 13:41:20 -06:00
mjallen18
091ecdc10f testng 2025-11-25 13:34:29 -06:00
mjallen18
e9084fe9ca fix 2025-11-25 13:32:31 -06:00
mjallen18
f1074d7b24 protonmail 2025-11-25 13:17:35 -06:00
mjallen18
16151dffdb scaling 2025-11-25 10:16:45 -06:00
mjallen18
34181aa0c9 testing 2025-11-25 10:16:30 -06:00
mjallen18
b62f49b362 darwin 2025-11-25 08:22:36 -06:00
mjallen18
e985d6e104 power menu 2025-11-24 18:45:35 -06:00
mjallen18
5aaae9ca99 fmt 2025-11-24 15:12:14 -06:00
mjallen18
875498d07b fix 2025-11-24 14:44:12 -06:00
mjallen18
02daab7686 full upd 2025-11-24 11:58:51 -06:00
mjallen18
821d594292 semicolon 2025-11-24 11:44:11 -06:00
mjallen18
b4c1cb2a9f oops 2025-11-24 11:43:56 -06:00
mjallen18
daa85b2ab3 move 2025-11-24 11:43:42 -06:00
mjallen18
c9d5d469c8 lanzaboote 2025-11-24 11:33:48 -06:00
mjallen18
bb788d1de3 upd 2025-11-24 11:19:38 -06:00
mjallen18
f085f17fe8 logs 2025-11-24 09:48:54 -06:00
mjallen18
37316dd1c8 add some parsers 2025-11-24 09:41:25 -06:00
mjallen18
297a49a8f6 testing 2025-11-24 09:22:12 -06:00
mjallen18
eb12e2271d light hass automations 2025-11-22 10:33:09 -06:00
mjallen18
bf0290df38 testing 2025-11-22 10:20:06 -06:00
mjallen18
4c839eb867 test 2025-11-22 10:18:44 -06:00
mjallen18
98aeb1646d ?? 2025-11-22 09:59:16 -06:00
mjallen18
c6357aa6a6 test 2025-11-21 19:07:44 -06:00
mjallen18
5de3cc2ba1 testing 2025-11-21 19:01:05 -06:00
mjallen18
2e54f153ed multiple light automation 2025-11-21 15:12:25 -06:00
mjallen18
9334a35d3b test 2025-11-21 15:11:22 -06:00
mjallen18
f91ce5ad84 maybe? 2025-11-21 14:44:26 -06:00
mjallen18
af57fdfb9f testing 2025-11-21 13:47:11 -06:00
mjallen18
81b8bd9ec5 test 2025-11-21 12:14:07 -06:00
mjallen18
8705f7336b test idk 2025-11-21 11:46:34 -06:00
mjallen18
71b8fc9d0f testing 2025-11-21 11:37:59 -06:00
mjallen18
66fefbe907 testing 2025-11-21 11:37:53 -06:00
mjallen18
9ff8fe8399 testing 2025-11-21 11:28:57 -06:00
mjallen18
d49a2744d2 format 2025-11-21 11:28:17 -06:00
mjallen18
9cadcf2eed ert 2025-11-21 08:28:10 -06:00
mjallen18
66ab57fce0 muas 2025-11-20 21:55:55 -06:00
mjallen18
84b2315aa5 fix fw 2025-11-20 21:23:21 -06:00
mjallen18
f5161b237a update packages 2025-11-20 21:22:53 -06:00
mjallen18
aee0a4b34b temp 2025-11-20 19:50:38 -06:00
mjallen18
75d97dd9ff audio output handling 2025-11-20 18:05:52 -06:00
mjallen18
2c4cc7c6b7 fix waybar hwmon 2025-11-20 17:42:54 -06:00
mjallen18
585689db43 update jovian 2025-11-20 16:47:12 -06:00
mjallen18
140b9b5e32 stuff 2025-11-20 16:32:06 -06:00
mjallen18
f3cac97463 add mac nix key 2025-11-20 16:28:37 -06:00
mjallen18
53a64aaf52 formatting 2025-11-20 16:18:28 -06:00
mjallen18
babe314199 old librepods 2025-11-20 16:17:41 -06:00
mjallen18
778a7c93b3 librepods rust beta 2025-11-20 16:02:35 -06:00
mjallen18
2e3d8e6e7d update librepods 2025-11-20 15:01:11 -06:00
mjallen18
0eed44ef6d battery charge limit 2025-11-20 14:58:21 -06:00
mjallen18
76f0e8f176 music assistant 2025-11-20 10:43:34 -06:00
mjallen18
3cad7ae079 music 2025-11-20 10:29:18 -06:00
mjallen18
c482cf1106 seting 2025-11-20 08:55:34 -06:00
mjallen18
ca69b2294f darwin plist 2025-11-19 22:00:42 -06:00
mjallen18
5e4d16297e darwin modules 2025-11-19 21:54:01 -06:00
mjallen18
c0dbceefb9 macos 2025-11-19 19:47:55 -06:00
mjallen18
c75f1e9131 maybe 2025-11-19 18:30:07 -06:00
mjallen18
b615cfe2e9 addr 2025-11-19 17:28:23 -06:00
mjallen18
e2433d7367 ip 2025-11-19 17:25:48 -06:00
mjallen18
ca448410f0 ports 2025-11-19 17:24:10 -06:00
mjallen18
f47678cd12 matrix 2025-11-19 17:09:50 -06:00
mjallen18
31aba7d0a5 test 2025-11-19 17:01:20 -06:00
mjallen18
3f3641bf3d formatting, warning fixes 2025-11-19 16:46:06 -06:00
mjallen18
2eb2e902b2 script stuff 2025-11-17 17:29:46 -06:00
mjallen18
c71c3b8ed2 stuff 2025-11-17 16:33:45 -06:00
mjallen18
108bb31e8e librepods 2025-11-17 16:31:05 -06:00
mjallen18
34b6399d24 pin rev 2025-11-16 20:18:13 -06:00
mjallen18
1c1dc71cd7 fix git aliases, librepods 2025-11-16 20:14:12 -06:00
mjallen18
6dc81d0cbf fix 2025-11-16 19:22:39 -06:00
mjallen18
2a77d233f9 upd 2025-11-16 19:10:06 -06:00
mjallen18
0e93ea159f idk 2025-11-14 10:47:49 -06:00
mjallen18
582561ae12 temp 2025-11-13 13:35:02 -06:00
mjallen18
c2766e82af fix 2025-11-12 20:01:54 -06:00
mjallen18
b42d9eff71 steamdeck 2025-11-12 17:42:38 -06:00
mjallen18
5ae2d51961 nuc 2025-11-12 15:30:41 -06:00
mjallen18
ed2ec3a875 hass 2025-11-11 17:42:31 -06:00
mjallen18
66281a5fd2 remove cmake overlay 2025-11-11 17:21:27 -06:00
mjallen18
6068832fe6 ? 2025-11-11 12:41:36 -06:00
mjallen18
c9588fbb95 darwin updates 2025-11-10 11:36:05 -06:00
mjallen18
627636ab9a upd 2025-11-10 10:39:21 -06:00
mjallen18
63173a6262 upd 2025-11-10 09:10:58 -06:00
mjallen18
65bdf1124d fix nas 2025-10-28 10:48:22 -05:00
mjallen18
b3f9b50be5 upd 2025-10-27 17:38:54 -05:00
mjallen18
97560f1bc9 hass remote db 2025-10-27 17:14:29 -05:00
mjallen18
840f3c9120 fmt 2025-10-24 10:26:55 -05:00
mjallen18
2b5614a07b nixfmt 2025-10-24 09:59:44 -05:00
mjallen18
9582ca5392 theme edits 2025-10-24 09:59:14 -05:00
mjallen18
1b125aecd0 home 2025-10-24 09:58:59 -05:00
mjallen18
35733e1044 hyprland 2025-10-24 09:58:59 -05:00
mjallen18
b748aa86a0 steamdeck cosmic? 2025-10-24 09:10:49 -05:00
mjallen18
57c5926dac darwin updates 2025-10-23 20:33:53 -05:00
mjallen18
b77f2a3c45 hypr 2025-10-23 16:06:01 -05:00
mjallen18
8177cfdfdd touchpad in hyprland 2025-10-23 15:15:58 -05:00
mjallen18
2a4b734b7f pi stuff 2025-10-23 09:14:35 -05:00
mjallen18
f90324ca49 temp pi 2025-10-23 09:13:33 -05:00
mjallen18
9f1c57ddf2 hass 2025-10-22 20:18:45 -05:00
mjallen18
ee486f52bb fixes 2025-10-22 19:10:44 -05:00
mjallen18
6b6cf3eee1 idk 2025-10-21 22:21:31 -05:00
mjallen18
52fc211dbf pgsql 2025-10-21 17:01:39 -05:00
mjallen18
d9e415870c sd 2025-10-21 13:32:51 -05:00
mjallen18
d61dfda3d5 upd 2025-10-21 11:31:20 -05:00
mjallen18
2cfbc6d854 upd 2025-10-16 20:28:28 -05:00
mjallen18
bf8b3d226a desktop enc 2025-10-15 10:12:46 -05:00
mjallen18
843304def7 desk 2025-10-15 09:54:34 -05:00
mjallen18
41105e3f5a nas stuff and upd 2025-10-14 18:42:33 -05:00
mjallen18
1fecd14b02 nas stuff and upd 2025-10-14 10:24:09 -05:00
mjallen18
76c0cd98d8 un container 2025-10-09 17:48:27 -05:00
mjallen18
ef22231dd7 crowdsec 2025-10-09 14:53:19 -05:00
mjallen18
8677ca747a idk hard broken 2025-10-08 15:45:53 -05:00
mjallen18
02b5dd32a2 containers 2025-10-05 22:16:44 -05:00
mjallen18
ee48ca08bd unmanic, calibre 2025-10-02 21:26:27 -05:00
mjallen18
e72d1b5d93 fmt 2025-09-30 20:54:58 -05:00
mjallen18
5d6e7e35d5 disko upd 2025-09-30 20:44:36 -05:00
mjallen18
751b4f9f69 test 2025-09-30 18:29:34 -05:00
mjallen18
ec23a7fe14 upd 2025-09-26 20:37:54 -05:00
mjallen18
117912045c pi4 2025-09-25 17:03:03 -05:00
mjallen18
5ebb66d7d4 ip 2025-09-25 15:30:38 -05:00
mjallen18
7a7b9cc01b fixes 2025-09-25 15:30:04 -05:00
mjallen18
4a00394402 temp 2025-09-23 19:06:19 -05:00
mjallen18
aa0d09d3c9 temp 2025-09-22 07:48:44 -05:00
mjallen18
0a40f7712a mac 2025-09-17 19:29:34 -05:00
mjallen18
02debc8387 fix bolt launcher and install to desktop 2025-09-17 16:17:27 -05:00
mjallen18
e6d386d362 bolt? 2025-09-17 14:18:30 -05:00
mjallen18
208aaf3f27 temp 2025-09-17 10:18:57 -05:00
mjallen18
6c9d4ccc86 bedjet 2025-09-16 10:47:51 -05:00
mjallen18
1f0def655c data 2025-09-16 08:08:20 -05:00
mjallen18
c5e8fff07d temp 2025-09-15 15:34:22 -05:00
mjallen18
7295254fe9 cleanup 2025-09-09 21:58:37 -05:00
mjallen18
efbbfde6f5 cleanup 2025-09-09 21:43:09 -05:00
mjallen18
fc4096d5d9 proxy testing 2025-09-09 21:03:08 -05:00
mjallen18
f58006cf8a reverse proxy stuff 2025-09-09 20:41:37 -05:00
mjallen18
6567bb1348 lol 2025-09-09 10:43:52 -05:00
mjallen18
b71ca02d25 test 2025-09-09 09:47:01 -05:00
44b17502a0 temp 2025-09-09 01:06:46 +00:00
mjallen18
bf70c50b80 upd 2025-09-08 14:47:14 -05:00
mjallen18
d50fbb5f73 upd 2025-09-08 14:25:49 -05:00
mjallen18
30fb21e062 temp 2025-09-06 10:28:07 -05:00
mjallen18
6b44792e06 changes 2025-09-05 12:08:39 -05:00
mjallen18
c7ac858ec5 temp 2025-09-05 12:07:55 -05:00
mjallen18
73cb9010e2 pi stuff 2025-09-05 11:25:59 -05:00
mjallen18
3c1b5d5072 stuff 2025-09-05 11:19:35 -05:00
mjallen18
a8873d9435 port 2025-09-03 20:22:40 -05:00
mjallen18
d2c60d8157 tabby-web testing 2025-09-03 20:01:19 -05:00
mjallen18
bb96cf2406 fix nuc 2025-09-03 18:37:49 -05:00
mjallen18
c4911b9d5f fixes 2025-09-03 17:54:33 -05:00
mjallen18
67b840c40f update macos 2025-09-03 10:53:07 -05:00
mjallen18
e7276cadf6 cleaup 2025-09-03 09:43:56 -05:00
mjallen18
36ca3ed90e stuff 2025-09-03 09:43:56 -05:00
mjallen18
57a079a86f getexe 2025-09-02 21:22:10 -05:00
mjallen18
0691806032 more cleanup 2025-09-02 21:08:09 -05:00
mjallen18
a6167bf31c stuff 2025-09-02 19:23:08 -05:00
mjallen18
e79ae984a3 pi5 2025-09-01 20:15:56 -05:00
mjallen18
81471cc582 cleanup 2025-09-01 18:39:30 -05:00
mjallen18
6e1f6c23fe upd 2025-09-01 18:20:34 -05:00
mjallen18
93c698c2de fix traefik 2025-09-01 10:48:15 -05:00
mjallen18
92855d5d31 cleanup 2025-08-28 12:32:39 -05:00
mjallen18
6c6d6325c9 cleanup nas I think or something 2025-08-27 12:03:53 -05:00
mjallen18
83f8b3543c cleanup homes 2025-08-26 20:31:51 -05:00
mjallen18
d6ae29f16f cleanup names 2025-08-26 20:28:55 -05:00
mjallen18
02085e7ff1 cleanup hass some 2025-08-26 20:14:18 -05:00
mjallen18
68f6ced410 cleanup 2025-08-26 19:47:36 -05:00
mjallen18
3fda24b5ac cleanup 2025-08-26 19:12:28 -05:00
mjallen18
baa831d002 cleanup 2025-08-26 18:30:57 -05:00
mjallen18
9ebb187a85 cleanup 2025-08-26 17:54:01 -05:00
mjallen18
c50bcd4120 move 2025-08-26 17:22:05 -05:00
mjallen18
72d314b1e2 oops 2025-08-26 17:20:33 -05:00
mjallen18
d15762b199 move stuff 2025-08-26 17:20:27 -05:00
mjallen18
f66c0726b0 mid 2025-08-25 21:41:17 -05:00
mjallen18
b3090b49e2 nbxyz 2025-08-25 21:36:09 -05:00
mjallen18
3bbd0d4432 nb 2025-08-25 21:33:48 -05:00
mjallen18
281bb7cb55 atticd 2025-08-25 21:10:59 -05:00
mjallen18
46ea1e681a fix pi4 2025-08-25 19:57:01 -05:00
mjallen18
c759baed06 network 2025-08-25 19:57:01 -05:00
mjallen18
d19191bb14 pi5 fix 2025-08-25 19:55:15 -05:00
mjallen18
81e78a6809 nas sops 2025-08-25 19:33:01 -05:00
mjallen18
5749de77a9 sops 2025-08-25 19:20:17 -05:00
mjallen18
921f186665 fix conflict 2025-08-25 18:16:52 -05:00
mjallen18
b098c2ad36 music assistant 2025-08-25 10:38:17 -05:00
mjallen18
2ea82a643d cleanup 2025-08-24 18:56:51 -05:00
mjallen18
cfaf900db6 keys 2025-08-23 21:21:50 -05:00
mjallen18
7b44863814 fix wallpaper 2025-08-23 20:50:31 -05:00
mjallen18
d3274d8a59 fix 2025-08-23 20:28:58 -05:00
mjallen18
b367df3f4e sops 2025-08-23 20:24:18 -05:00
mjallen18
ac84ea8a7a rev 2025-08-23 20:19:06 -05:00
mjallen18
e0ee270075 clean 2025-08-23 20:16:47 -05:00
mjallen18
76134f4533 upd build 2025-08-23 20:14:41 -05:00
mjallen18
36010a4230 lib 2025-08-23 19:54:05 -05:00
mjallen18
c90bd0cd07 vscode 2025-08-23 18:49:04 -05:00
mjallen18
6c9a010c3c test stuff 2025-08-23 18:00:05 -05:00
mjallen18
c680392513 temp testing 2025-08-23 14:34:45 -05:00
mjallen18
a233606e8d gpg 2025-08-23 14:12:49 -05:00
mjallen18
bc18b0775b merge 2025-08-23 10:26:12 -05:00
mjallen18
a96b8ddf86 delete 2025-08-22 21:13:05 -05:00
mjallen18
d6e7be7db1 cleanup 2025-08-22 21:13:05 -05:00
mjallen18
999fbbf022 imp fix 2025-08-22 12:11:26 -05:00
mjallen18
f8adf906e3 fix darwin 2025-08-22 09:44:21 -05:00
mjallen18
c2bbac4020 merge 2025-08-22 09:36:02 -05:00
mjallen18
5ad754f5e9 testing done 2025-08-21 21:04:11 -05:00
mjallen18
814451041a end test 2025-08-21 21:04:11 -05:00
mjallen18
1f9af9618f more cleanup 2025-08-21 21:04:11 -05:00
mjallen18
2601629e47 cleanup 2025-08-21 21:04:11 -05:00
mjallen18
09b3fcb825 user updates 2025-08-21 21:04:11 -05:00
mjallen18
34746e865b move some apps to namespace 2025-08-21 21:04:11 -05:00
mjallen18
7e82df3df7 idk 2025-08-21 21:04:11 -05:00
mjallen18
1faa099900 bcfs root? 2025-08-21 21:04:11 -05:00
mjallen18
f1295e17d6 move python-steam 2025-08-21 21:04:11 -05:00
mjallen18
fd34e5719d README 2025-08-21 21:04:11 -05:00
mjallen18
87f0941d61 aarch 2025-08-21 21:04:11 -05:00
mjallen18
7ebe9a9c8d test 2025-08-21 21:04:11 -05:00
mjallen18
c2d0993d9d cleanup 2025-08-21 21:03:47 -05:00
mjallen18
8b6c35ff3c macos 2025-08-21 21:02:58 -05:00
mjallen18
b0c812ac7a no splash 2025-08-21 21:02:00 -05:00
mjallen18
83116ee596 ssh 2025-08-21 21:01:14 -05:00
mjallen18
929786cb12 test 2025-08-21 21:00:39 -05:00
mjallen18
0364333921 fix proxies 2025-08-21 09:28:31 -05:00
mjallen18
9d93ba8e07 fix pi4 hostname 2025-08-21 09:24:14 -05:00
mjallen18
aacb72b78d clev 2025-08-20 21:27:45 -05:00
mjallen18
83f7f3261c more pi stuff 2025-08-20 20:01:35 -05:00
mjallen18
022f67554b fix lol 2025-08-20 19:58:40 -05:00
mjallen18
2c339a22f4 pi stuff 2025-08-20 19:57:13 -05:00
mjallen18
e4c6f9d7fe sops but idk 2025-08-20 18:37:44 -05:00
mjallen18
24c1580452 cleanup 2025-08-20 18:19:20 -05:00
mjallen18
b937a85dcc cache 2025-08-19 22:51:06 -05:00
mjallen18
db43ca4b10 disable gnome 2025-08-19 22:46:18 -05:00
mjallen18
8e3e1ef6cc finally update traefik 2025-08-19 22:15:45 -05:00
mjallen18
26ecfe79eb macos 2025-08-19 20:49:06 -05:00
mjallen18
5dd2876fb5 sops 2025-08-19 20:33:33 -05:00
mjallen18
807e964f34 no splash 2025-08-18 22:21:17 -05:00
mjallen18
8a1714eeb6 ssh 2025-08-18 20:54:35 -05:00
mjallen18
2623efc997 update hass addons 2025-08-18 19:52:09 -05:00
mjallen18
c053da2e30 bcachefs 2025-08-17 21:01:59 -05:00
mjallen18
533d6a4170 pi5 upd 2025-08-17 20:58:54 -05:00
mjallen18
5b3e01820b desktop omnissa 2025-08-12 21:25:07 -05:00
5cef58ade0 fix 2025-08-12 17:04:25 +00:00
mjallen18
981b41f4c2 upd 2025-08-12 08:18:19 -05:00
mjallen18
ae8039dba0 weather 2025-08-07 22:30:20 -05:00
mjallen18
54f56c3f83 upd 2025-08-07 22:30:01 -05:00
mjallen18
ce142bb64a fix this package 2025-07-30 21:44:57 -05:00
mjallen18
fd3f61a0ac lsfg 2025-07-29 20:02:37 -05:00
mjallen18
d0ac22c211 bcachefs 2025-07-29 19:34:10 -05:00
mjallen18
caa326d496 test 2025-07-29 18:26:50 -05:00
mjallen18
04ef2a4b8c temp 2025-07-29 16:43:51 -05:00
mjallen18
7e35a27b2e lsfg-vk 2025-07-28 15:16:56 -05:00
mjallen18
48108e693a gnome home manager on steamdeck 2025-07-28 14:49:03 -05:00
mjallen18
8e3d3e4281 openhasp 2025-07-28 14:18:54 -05:00
mjallen18
c7c99b339b fix package 2025-07-28 11:27:06 -05:00
mjallen18
c8f5547727 openhasp 2025-07-28 11:27:00 -05:00
mjallen18
6f5e592d8c cleanup 2025-07-28 11:06:32 -05:00
mjallen18
5ae3f1a9ef desktop home sops 2025-07-28 09:33:54 -05:00
mjallen18
1a3b091588 desktop stuff 2025-07-28 09:32:31 -05:00
mjallen18
5b34456571 yamlfmt 2025-07-24 11:25:18 -05:00
mjallen18
5918611469 yamlfmt 2025-07-24 11:22:29 -05:00
mjallen18
f3aafffcaa deadnix 2025-07-24 11:19:19 -05:00
mjallen18
3d213c8769 nixfmt 2025-07-24 11:06:08 -05:00
mjallen18
f05972d6ae move commented file: 2025-07-24 10:38:13 -05:00
mjallen18
b77dda0e6f fix some stuff 2025-07-24 10:31:50 -05:00
mjallen18
3c1a956c81 cleanup 2025-07-24 10:19:32 -05:00
mjallen18
5dc1a96f6d cleanup 2025-07-23 19:36:06 -05:00
511 changed files with 31004 additions and 20821 deletions

8
.gitignore vendored
View File

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

View File

@@ -1,90 +1,92 @@
# See https://github.com/Mic92/dotfiles/blob/d6114726d859df36ccaa32891c4963ae5717ef7f/nixos/.sops.yaml
keys:
- &matt-pgp CBCB9B18A6B8930B0B6ABFD1CCB8CBEB30633684
- &matt age157jemphjzg6zmk373vpccuguyw6e75qnkqmz8pcnn2yue85p939swqqhy0
- &matt_pi4 age13g9a4d4jrvckfddpgn8sm4kjtzajr67le56pfdg78ktr5pd09phq32j89u
- &matt_pi5 age1wpvfpv5n32lruk7c0da4uaeapsmhjxdvg8z4ljehn06l6g2y0e0sum404l
- &desktop age1jv8ap5zwa49ftv0gg7wqf5ps0e68uuwxe2fekjsn0zkyql964unqyc58rf
- &admin age1pm3fehmmk0vmnrscz9vm96rakn46aaldr5ydpscmde3v9x0k3faswwdzxs
- &jallen-nas age1mn2afyp9my7y7hcyzum0wdwt49zufnkt8swnyy8pj30cwzs4zvgsthj0lt
- &pi4 age1ykkjw57t3z3deup3gtp7dujyaslskn74e0d9hsmqaha2pj3rvazqgndw5a
- &pi5 age1t2d5scrukk0guva5sr97a8tge5j8kd865adezrcru7p269pzwvpsamkgje
- &deck age1c8qw59ffcq9l77gfmtyc3djtvt3md0u6dwhrjcgsm98ntyf72ufqugj7cg
- &steamdeck age1er5qucsc2mugrzrr7n3xhzv7kemkrqrw4m84r544fkk7nkg5g5eswxkqj0
- &matt_macbook-pro age1xg6mvj3x6s3t8058c6rsk3q4kskvm6nsffwckxkkjzhyn7r6tczqgkj23p
- &macbook-pro age1rdn39ywgzmc8wlsl5lrfe77e652wzjmjx58gx4k2ydghd35kdqvqscrf3h
- &nuc age1wurzgc20e6ye79wsg85vvqk4aj3mmc0llxshcy9532ex8f4c6dqql76c78
- &admin_nuc age1luyejgmqjj0esydlr2jxqkg48vexmx57gdz7cy5gq7rz8kf5cups2rnfa9
- &matt_macbook-pro age12gu9hqhd56yl5x3t5yenkn9yg57du08h77vzjqsmnu5hdppne38qcur5a0
- &macbook-pro age1t7378n8kmd3f32fkye2gw3jj6qswv3exjdx0dq8kl0xra3tmcdnsvddq3u
- &nuc age102el4snus37dj807rwvsmlvwu2sg2d8rw3vfmtntgczfkz04l9nshetcq0
- &admin_nuc age1yn82e39pxt0d0pgny34ux4lkge4ff7wxvsye8ragvwngehemt4ps27phyw
- &matt_allyx age18z4ctyyj7eq0cmt23eelfzjuacq4fa6hsplyg779d3rdg7ac2q5q2njxqh
- &allyx age164xpf9cepfjqvcn7v5ahcaq9zmm5u3yl9t04d098e3e2zkfjcyws02rx42
creation_rules:
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *admin
- *jallen-nas
- *pi4
- *pi5
- *deck
- *steamdeck
- *matt_macbook-pro
- *macbook-pro
- *admin_nuc
- *nuc
- pgp:
- *matt-pgp
age:
- *matt
- *matt_pi5
- *desktop
- *admin
- *jallen-nas
- *pi5
- *deck
- *steamdeck
- *matt_macbook-pro
- *macbook-pro
- *admin_nuc
- *nuc
- *matt_allyx
- *allyx
- path_regex: nas-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *desktop
- *admin
- *jallen-nas
- pgp:
- *matt-pgp
age:
- *matt
- *desktop
- *admin
- *jallen-nas
- path_regex: desktop-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *desktop
- *admin
- *jallen-nas
- path_regex: steamdeck-secrets/[^/]+\.(yaml|json|env|ini)$
- pgp:
- *matt-pgp
age:
- *matt
- *desktop
- *admin
- *jallen-nas
- path_regex: allyx-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *desktop
- *deck
- *steamdeck
- *admin
- *jallen-nas
- path_regex: pi4-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *pi4
- *pi5
- *admin
- *jallen-nas
- pgp:
- *matt-pgp
age:
- *matt
- *desktop
- *deck
- *steamdeck
- *admin
- *jallen-nas
- *matt_allyx
- *allyx
- path_regex: pi5-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *matt_pi4
- *matt_pi5
- *desktop
- *pi4
- *pi5
- *admin
- *jallen-nas
- pgp:
- *matt-pgp
age:
- *matt
- *matt_pi5
- *desktop
- *pi5
- *admin
- *jallen-nas
- path_regex: mac-secrets/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *matt
- *matt_pi5
- *desktop
- *pi5
- *admin
- *jallen-nas
- *matt_macbook-pro
- *macbook-pro
- pgp:
- *matt-pgp
age:
- *matt
- *matt_pi5
- *desktop
- *pi5
- *admin
- *jallen-nas
- *matt_macbook-pro
- *macbook-pro

167
README.md
View File

@@ -1,50 +1,129 @@
# nixOS Config
# NixOS Configuration Repository
### Common Files
* [flake.nix](./flake.nix)
* [impermenance.nix](./share/impermanence/default.nix)
* [share](./share)
* [overlays](./overlays)
This repository contains my personal NixOS configurations for multiple systems, managed using [Snowfall Lib](https://github.com/snowfallorg/lib) and the Nix Flakes system.
## Overview
This repository provides a centralized, declarative configuration for all my systems, including:
- Desktop PC (AMD)
- NAS server
- Steam Deck
- Intel NUC
- Raspberry Pi 4
- Raspberry Pi 5
- MacBook Pro (NixOS on Apple Silicon)
- MacBook Pro (Darwin/macOS)
## Repository Structure
```
.
├── checks/ # Pre-commit hooks and other checks
├── flake.nix # Main flake configuration
├── homes/ # Home-manager configurations for users
│ ├── aarch64-darwin/ # macOS home configurations
│ ├── aarch64-linux/ # ARM Linux home configurations
│ └── x86_64-linux/ # x86 Linux home configurations
├── modules/ # Reusable configuration modules
│ ├── home/ # Home-manager modules
│ └── nixos/ # NixOS system modules
├── overlays/ # Nixpkgs overlays
├── packages/ # Custom package definitions
├── secrets/ # Encrypted secrets (managed with sops-nix)
└── systems/ # System-specific configurations
├── aarch64-darwin/ # macOS system configurations
├── aarch64-linux/ # ARM Linux system configurations
└── x86_64-linux/ # x86 Linux system configurations
```
## Key Features
- **Modular Design**: Reusable modules for various system components
- **Multi-System Support**: Configurations for different hardware platforms
- **Home Manager Integration**: User environment management
- **Secret Management**: Encrypted secrets with sops-nix
- **Disk Management**: Declarative disk partitioning with disko
- **State Management**: Persistent state management with impermanence
- **Desktop Environments**: Support for GNOME, Hyprland, and COSMIC
- **Hardware-Specific Optimizations**: Tailored configurations for different hardware
## Key Technologies
- [Nix](https://nixos.org/) and [NixOS](https://nixos.org/)
- [Nix Flakes](https://nixos.wiki/wiki/Flakes)
- [Snowfall Lib](https://github.com/snowfallorg/lib)
- [Home Manager](https://github.com/nix-community/home-manager)
- [sops-nix](https://github.com/Mic92/sops-nix)
- [disko](https://github.com/nix-community/disko)
- [impermanence](https://github.com/nix-community/impermanence)
- [lanzaboote](https://github.com/nix-community/lanzaboote) (Secure Boot)
## Notable System Configurations
### Desktop
* [boot.nix](./hosts/desktop/boot.nix)
* [configuration.nix](./hosts/desktop/configuration.nix)
* [hardware-configuration.nix](./hosts/desktop/hardware-configuration.nix)
* [filesystems.nix](./hosts/desktop/filesystems.nix)
* [home.nix](./hosts/desktop/home.nix)
* [sops.nix](./hosts/desktop/sops.nix)
* [specialisations.hyprland](./hosts/desktop/hyprland)
* [specialisations.gnome](./hosts/desktop/gnome)
* [specialisations.cosmic](./hosts/desktop/cosmic)
A powerful AMD-based desktop with gaming capabilities, featuring:
- AMD CPU and GPU optimizations
- Multiple desktop environment options (GNOME, Hyprland, COSMIC)
- Gaming setup with Steam and related tools
### NAS
* [boot.nix](./hosts/nas/boot.nix)
* [configuration.nix](./hosts/nas/configuration.nix)
* [hardware-configuration.nix](./hosts/nas/hardware-configuration.nix)
* [impermenance.nix](./hosts/nas/impermenance.nix)
* [apps.nix](./hosts/desktop/apps.nix)
* [home.nix](./hosts/desktop/home.nix)
* [networking.nix](./hosts/desktop/networking.nix)
* [services.nix](./hosts/desktop/services.nix)
* [sops.nix](./hosts/desktop/sops.nix)
* [ups.nix](./hosts/desktop/ups.nix)
* [samba](./modules/samba)
* nas-apps
* [arrs](./hosts/nas/apps/arrs/default.nix)
* [free-games-claimer](./modules/apps/free-games-claimer)
* [jackett](./modules/apps/jackett)
* [jellyfin](./hosts/nas/apps/jellyfin/default.nix)
* [jellyseerr](./hosts/nas/apps/jellyseerr/default.nix)
* [jackett](./modules/apps/manyfold)
* [mariadb](./modules/apps/mariadb)
* [mealie](./modules/apps/mealie)
* [nextcloud+onlyoffice](./hosts/nas/apps/nextcloud/default.nix)
* [ollama](./hosts/nas/apps/ollama/default.nix)
* [paperless](./hosts/nas/apps/paperless/default.nix)
* [tdarr](./modules/apps/tdarr)
* [traefik](./hosts/nas/apps/traefik/default.nix)
* [wireguard](./modules/apps/your-spotify)
### Raspberry Pi 4
* [configuration.nix](./hosts/pi4/configuration.nix)
* [hardware-configuration.nix](./hosts/pi4/hardware-configuration.nix)
A home server with various self-hosted services:
- Media management (Jellyfin, Jellyseerr)
- Download automation (Sonarr, Radarr, etc.)
- Document management (Paperless)
- File sharing (Samba, Nextcloud)
- AI services (Ollama)
### Raspberry Pi
Configurations for both Pi 4 and Pi 5:
- Hardware-specific optimizations
- Disk partitioning suitable for ARM devices
- Bluetooth and wireless support
### Steam Deck
Custom NixOS configuration for the Steam Deck:
- Integration with Jovian for Steam Deck compatibility
- Gaming optimizations
- Steam ROM Manager
### MacBook Pro
Configurations for both:
- NixOS on Apple Silicon
- nix-darwin for macOS
## Usage
### Building a System Configuration
```bash
# Build and activate a system configuration
sudo nixos-rebuild switch --flake .#hostname
```
### Building a Home Configuration
```bash
# Build and activate a home configuration
home-manager switch --flake .#username@hostname
```
## Documentation
Comprehensive documentation is available in the [docs](./docs) directory:
- [Getting Started](./docs/getting-started.md) - Instructions for setting up new systems
- [Architecture](./docs/architecture.md) - Overview of the repository structure
- [System Configurations](./docs/systems/README.md) - Details about each system
- [Home Assistant](./docs/home-assistant/README.md) - Home Assistant setup and automations
- [Custom Modules](./docs/modules/README.md) - Details about reusable configuration modules
- [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
## License
This project is licensed under the MIT License - see the LICENSE file for details.

62
checks/disksnstuff.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/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

@@ -1,19 +1,22 @@
{
inputs,
pkgs,
lib,
...
}:
let
inherit (inputs) git-hooks-nix;
inherit (inputs) pre-commit-hooks-nix;
in
git-hooks-nix.lib.${pkgs.system}.run {
pre-commit-hooks-nix.lib.${pkgs.stdenv.hostPlatform.system}.run {
src = ../..;
hooks = {
pre-commit-hook-ensure-sops.enable = true;
treefmt = {
enable = true;
settings.fail-on-change = false;
packageOverrides.treefmt = inputs.treefmt-nix.lib.mkWrapper pkgs ../../treefmt.nix;
enable = lib.mkForce true;
settings.fail-on-change = lib.mkForce false;
packageOverrides.treefmt = inputs.treefmt-nix.lib.mkWrapper pkgs (
lib.snowfall.fs.get-file "treefmt.nix"
);
};
};
}
}

12
docs/README.md Normal file
View File

@@ -0,0 +1,12 @@
# Documentation
This directory contains comprehensive documentation for the NixOS configuration.
## Contents
- [Getting Started](./getting-started.md) - Instructions for setting up new systems
- [System Configurations](./systems/README.md) - Detailed information about each system
- [Home Assistant](./home-assistant/README.md) - Documentation for the Home Assistant setup
- [Custom Modules](./modules/README.md) - Information about reusable modules
- [Architecture](./architecture.md) - Overview of the repository architecture
- [Troubleshooting](./troubleshooting.md) - Common issues and solutions

104
docs/architecture.md Normal file
View File

@@ -0,0 +1,104 @@
# Repository Architecture
This document provides an overview of the repository architecture, explaining how the various components fit together.
## Overview
This NixOS configuration repository is built using [Nix Flakes](https://nixos.wiki/wiki/Flakes) and [Snowfall Lib](https://github.com/snowfallorg/lib) to provide a modular, maintainable configuration for multiple systems.
## Directory Structure
```
.
├── checks/ # Pre-commit hooks and other checks
├── flake.nix # Main flake configuration
├── homes/ # Home-manager configurations for users
│ ├── aarch64-darwin/ # macOS home configurations
│ ├── aarch64-linux/ # ARM Linux home configurations
│ └── x86_64-linux/ # x86 Linux home configurations
├── modules/ # Reusable configuration modules
│ ├── home/ # Home-manager modules
│ └── nixos/ # NixOS system modules
│ ├── boot/ # Boot configuration modules
│ ├── desktop/ # Desktop environment modules
│ ├── hardware/ # Hardware-specific modules
│ ├── homeassistant/ # Home Assistant modules
│ ├── network/ # Network configuration modules
│ ├── services/ # Service configuration modules
│ └── ... # Other module categories
├── overlays/ # Nixpkgs overlays
├── packages/ # Custom package definitions
├── secrets/ # Encrypted secrets (managed with sops-nix)
└── systems/ # System-specific configurations
├── aarch64-darwin/ # macOS system configurations
├── aarch64-linux/ # ARM Linux system configurations
└── x86_64-linux/ # x86 Linux system configurations
├── jallen-nas/ # NAS server configuration
├── matt-nixos/ # Desktop configuration
├── nuc-nixos/ # NUC configuration
└── ... # Other system configurations
```
## Flake Structure
The `flake.nix` file defines the inputs (external dependencies) and outputs (configurations) of this repository:
### Inputs
- **nixpkgs-unstable**: The unstable channel of Nixpkgs
- **nixpkgs-stable**: The stable channel of Nixpkgs (25.11)
- **home-manager**: User environment management
- **snowfall-lib**: Library for structuring flake repositories
- **impermanence**: Persistent state management
- **lanzaboote**: Secure boot implementation
- **nixos-hardware**: Hardware-specific configurations
- **sops-nix**: Secret management
- **disko**: Disk partitioning and formatting
- **And more specialized inputs**
### Outputs
The outputs are generated using Snowfall Lib's `mkFlake` function, which automatically discovers and assembles:
- **NixOS system configurations**: For each system in the `systems/` directory
- **Home Manager configurations**: For each configuration in the `homes/` directory
- **Packages**: From the `packages/` directory
- **Modules**: From the `modules/` directory
- **Overlays**: From the `overlays/` directory
## Module System
The module system uses a modular approach where:
1. **Common modules** are defined in `modules/nixos/` and `modules/home/`
2. **System-specific modules** are defined in `systems/<architecture>/<hostname>/`
Each module follows the NixOS module pattern, with:
- `default.nix`: Main module implementation
- `options.nix`: Option declarations
## Integration with Snowfall Lib
Snowfall Lib provides:
1. **Automatic discovery** of modules, overlays, and packages
2. **Consistent structure** across the repository
3. **Common utilities** for working with flakes
## Secrets Management
Secrets are managed using [sops-nix](https://github.com/Mic92/sops-nix), with:
- Encrypted secret files in the `secrets/` directory
- `.sops.yaml` configuration file in the root
- Key management integrated into the configuration
## Deployment Process
Systems are built and deployed using:
```bash
nixos-rebuild switch --flake .#hostname
```
This command:
1. Evaluates the flake for the specified hostname
2. Builds the resulting configuration
3. Activates it on the current system

172
docs/getting-started.md Normal file
View File

@@ -0,0 +1,172 @@
# Getting Started
This guide will help you get started with this NixOS configuration repository.
## Prerequisites
- Basic knowledge of NixOS and the Nix language
- Git installed on your system
- Physical access to the machine you want to configure
## Initial Setup
### 1. Cloning the Repository
Clone this repository to your local machine:
```bash
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git
cd nix-config
```
### 2. Setting Up a New System
#### Option 1: Using an Existing Configuration
If you're setting up a new machine that should be identical to an existing configuration:
1. Boot from a NixOS installation media
2. Mount your target partitions to `/mnt`
3. Clone this repository:
```bash
nixos-enter
cd /mnt
mkdir -p /mnt/etc/nixos
git clone ssh://nix-apps@localhost:2222/mjallen/nix-config.git /mnt/etc/nixos
```
4. Install NixOS with the desired system profile:
```bash
nixos-install --flake /mnt/etc/nixos#hostname
```
Replace `hostname` with the target system name (e.g., `matt-nixos`, `jallen-nas`, etc.)
#### Option 2: Creating a New System Configuration
If you're adding a completely new system:
1. Create a new directory for your system configuration:
```bash
mkdir -p systems/$(uname -m)-linux/new-hostname
```
2. Create the basic configuration files:
```bash
cat > systems/$(uname -m)-linux/new-hostname/default.nix << EOF
{ lib, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
# Add other needed module imports here
];
networking.hostName = "new-hostname";
# Add your system-specific configuration here
}
EOF
```
3. Generate the hardware configuration:
```bash
nixos-generate-config --no-filesystems --dir systems/$(uname -m)-linux/new-hostname/
```
4. Add your new system to the flake by adding it to the `hosts` section in `flake.nix`
5. Build and install the configuration:
```bash
sudo nixos-rebuild switch --flake .#new-hostname
```
## Secret Management
### Setting Up Sops-Nix
1. Create a GPG key if you don't already have one:
```bash
gpg --full-generate-key
```
2. Add your key to `.sops.yaml`:
```bash
# Get your key fingerprint
gpg --list-secret-keys --keyid-format=long
# Edit the .sops.yaml file to add your key
```
3. Create a new encrypted secret:
```bash
sops secrets/newsecret.yaml
```
## Common Tasks
### Updating the Repository
```bash
git pull
sudo nixos-rebuild switch --flake .#hostname
```
### Adding a New Package
1. For standard packages, add them to your system or home configuration:
```nix
environment.systemPackages = with pkgs; [
new-package
];
```
2. For custom packages, add them to the `packages` directory:
```bash
mkdir -p packages/new-package
# Create the necessary Nix files
```
### Adding a New Module
1. Create a new module directory:
```bash
mkdir -p modules/nixos/new-module
```
2. Create the module files:
```bash
# Create options.nix
cat > modules/nixos/new-module/options.nix << EOF
{ lib, namespace, ... }:
with lib;
{
options.${namespace}.new-module = {
enable = mkEnableOption "Enable new module";
# Add other options here
};
}
EOF
# Create default.nix
cat > modules/nixos/new-module/default.nix << EOF
{ config, lib, namespace, ... }:
let
cfg = config.${namespace}.new-module;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Add your configuration here
};
}
EOF
```
3. Import your module in your system configuration:
```nix
imports = [
# ...
../../../modules/nixos/new-module
];
${namespace}.new-module.enable = true;
```

View File

@@ -0,0 +1,188 @@
# Home Assistant Configuration
This document provides comprehensive information about the Home Assistant setup in this NixOS configuration.
## Overview
Home Assistant is configured as a NixOS service with custom components, integrations, and automations. The configuration uses a modular approach with separate files for different aspects of the setup.
## Module Structure
The Home Assistant configuration is organized in the following structure:
```
modules/nixos/homeassistant/
├── automations/ # Automation configurations
│ ├── lightswitch/ # Light switch automations
│ └── motion-light/ # Motion-activated light automations
├── default.nix # Main module configuration
├── options.nix # Module options definition
└── services/ # Related service configurations
├── govee2mqtt/ # Govee integration via MQTT
├── homeassistant/ # Core Home Assistant service
├── music-assistant/ # Music Assistant integration
├── thread/ # Thread border router
└── zigbee2mqtt/ # Zigbee to MQTT bridge
```
## Installation
The Home Assistant module is enabled in the system configuration by setting:
```nix
mjallen.services.home-assistant.enable = true;
```
This activates Home Assistant and related services such as MQTT, Zigbee2MQTT, and the Matter server.
## Configuration Options
The module provides several configuration options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enable` | boolean | `false` | Enable Home Assistant and related services |
| `mosquittoPort` | integer | `1883` | Port for the MQTT broker |
| `zigbee2mqttPort` | integer | `8080` | Port for the Zigbee2MQTT web interface |
| `zigbeeDevicePath` | string | `/dev/ttyUSB0` | Path to the Zigbee USB device |
## Core Services
### Home Assistant
The main Home Assistant service is configured in `services/homeassistant/default.nix` with:
- PostgreSQL database backend
- Custom components
- Custom Lovelace modules
- HTTPS access with authentication
- Integration with other services
### MQTT
MQTT is used as a messaging protocol for various smart home devices. The Mosquitto MQTT broker is automatically configured when Home Assistant is enabled.
### Zigbee2MQTT
Zigbee2MQTT allows integration with Zigbee devices. It's configured with:
- Automatic discovery for Home Assistant
- OTA updates for Zigbee devices
- Web interface for management
### Thread Border Router
The Thread Border Router provides integration with Thread-based devices like Matter devices.
## Custom Components
The following custom components are included:
- `ha-anycubic` - Anycubic 3D printer integration
- `ha-bambulab` - Bambu Lab 3D printer integration
- `ha-bedjet` - BedJet climate control integration
- `ha-gehome` - GE Home appliance integration
- `ha-icloud3` - Enhanced iCloud device tracking
- `ha-local-llm` - Local LLM integration
- `ha-mail-and-packages` - Mail and package delivery tracking
- `ha-nanokvm` - NanoKVM integration
- `ha-openhasp` - openHASP integration for DIY displays
- `ha-overseerr` - Overseerr media request integration
- `ha-petlibro` - PetLibro pet feeder integration
- `ha-wyzeapi` - Wyze device integration
## Automations
### Light Switch Automations
The light switch automations handle physical switch inputs for controlling smart lights.
### Motion Light Automations
Motion light automations turn lights on when motion is detected and off after a period of inactivity.
### Custom Automations
Additional automations are placed in the `/etc/hass` directory and are included in the Home Assistant configuration. These include:
- `fountain_automation.yaml` - Toggles the water dispensing mode on the Dockstream Smart RFID Fountain every 15 minutes between constant and intermittent flow.
## Smart Home Devices
The configuration includes support for various smart home devices:
### Lighting
- Various smart lights throughout the home
### Climate
- Smart thermostat
- Humidifier control
### Pet Care
- Dockstream Smart RFID Fountain with scheduling
- Smart pet feeders for pets named Joey and Luci
- Litter-Robot 4 smart litter box
### Media
- Google Cast devices
- Smart TVs
- Media players
### Sensors
- Temperature, humidity, and motion sensors
- Door and window sensors
- Presence detection
## Integration with Other Services
Home Assistant is integrated with:
- **Music Assistant** - For enhanced music streaming capabilities
- **Govee Integration** - For Govee smart devices
- **Matter** - For Matter-compatible devices
## Adding New Automations
To add a new automation:
1. Create a YAML file with the automation definition
2. Place it in `/etc/hass`
3. The automation will be automatically included in Home Assistant
Example automation format:
```yaml
alias: "Automation Name"
description: "Description of what the automation does"
trigger:
- platform: state
entity_id: binary_sensor.motion_sensor
to: "on"
condition: []
action:
- service: light.turn_on
target:
entity_id: light.living_room
mode: single
```
## Troubleshooting
### Common Issues
1. **Zigbee Device Pairing Issues**
- Make sure the Zigbee coordinator is properly connected
- Check the Zigbee2MQTT logs for errors
2. **Service Unavailable**
- Check if all related services are running
- Verify firewall rules allow access to the services
3. **Database Issues**
- Check PostgreSQL service status
- Verify database connection settings

View File

@@ -0,0 +1,148 @@
# Home Assistant Automations
This document details the automations configured in the Home Assistant setup.
## Automation Types
Automations in this configuration are managed in several ways:
1. **Module-Based Automations**: Defined in Nix modules within the `modules/nixos/homeassistant/automations/` directory
2. **YAML Automations**: Defined in YAML files and included via the `automation manual` directive
3. **UI-Created Automations**: Created through the Home Assistant UI and stored in `automations.yaml`
## Module-Based Automations
### Light Switch Automations
**Location**: `modules/nixos/homeassistant/automations/lightswitch/`
These automations link physical light switches to smart lights:
- **Bedroom Light Switch**: Controls the bedroom lights
- **Living Room Light Switch**: Controls the living room lights
- **Bedroom Closet Lights**: Controls the closet lights
### Motion-Activated Light Automations
**Location**: `modules/nixos/homeassistant/automations/motion-light/`
These automations turn lights on when motion is detected and off after a period of inactivity.
## YAML Automations
### Fountain Cycling Automation
**Location**: `/etc/nixos/fountain_automation.yaml`
This automation toggles the water dispensing mode on the Dockstream Smart RFID Fountain every 15 minutes:
```yaml
alias: "Fountain Cycle Mode"
description: "Toggles fountain water mode every 15 minutes between constant and intermittent flow"
trigger:
- platform: time_pattern
minutes: "/15" # Every 15 minutes
condition: []
action:
- service: select.select_next
target:
entity_id: select.dockstream_smart_rfid_fountain_water_dispensing_mode
mode: single
id: fountain_cycle_mode
```
This automation:
1. Triggers every 15 minutes
2. Uses the `select.select_next` service to toggle between the two available options:
- "Flowing Water (Constant)"
- "Intermittent Water (Scheduled)"
The fountain is also configured with:
- Water Interval: 10 minutes
- Water Dispensing Duration: 15 minutes
## Creating New Automations
### Method 1: Module-Based Automation
For reusable, complex automations that should be managed in code:
1. Create a new directory in `modules/nixos/homeassistant/automations/`
2. Create a `default.nix` file with the automation logic
Example:
```nix
{ config, lib, ... }:
{
config = {
services.home-assistant.config."automation manual" = [
{
alias = "Example Automation";
description = "Example automation created via Nix module";
trigger = [
{
platform = "state";
entity_id = "binary_sensor.example_sensor";
to = "on";
}
];
action = [
{
service = "light.turn_on";
target.entity_id = "light.example_light";
}
];
mode = "single";
}
];
};
}
```
### Method 2: YAML Automation
For simpler automations:
1. Create a YAML file with the automation definition
2. Place it in `/etc/hass/`
Example:
```yaml
alias: "Example Automation"
description: "Example automation in YAML"
trigger:
- platform: state
entity_id: binary_sensor.example_sensor
to: "on"
action:
- service: light.turn_on
target:
entity_id: light.example_light
mode: single
```
### Method 3: UI Creation
For quick prototyping or simple automations:
1. Go to Home Assistant UI > Settings > Automations & Scenes
2. Click "+ Add Automation"
3. Configure using the UI editor
## Testing Automations
To test an automation:
1. In the Home Assistant UI, go to Developer Tools > Services
2. Select `automation.trigger` as the service
3. Enter the entity_id of your automation in the service data field
4. Click "Call Service" to trigger the automation manually
## Troubleshooting
If an automation isn't working as expected:
1. Check the Home Assistant logs for errors
2. Verify entity names and service calls are correct
3. Test individual triggers and actions separately
4. Use the "Debug" section in the automation editor to trace execution

View File

@@ -0,0 +1,96 @@
# Pet Fountain Automation
This document details the automation for the Dockstream Smart RFID Fountain device.
## Overview
The Dockstream Smart RFID Fountain is a smart pet fountain controlled through Home Assistant. A custom automation has been created to toggle the water dispensing mode between constant flow and intermittent flow every 15 minutes. This cycling helps keep the water fresh while reducing energy consumption.
## Fountain Configuration
The Dockstream Smart RFID Fountain has the following settings in Home Assistant:
| Setting | Entity ID | Value | Description |
|---------|-----------|-------|-------------|
| Water Dispensing Mode | `select.dockstream_smart_rfid_fountain_water_dispensing_mode` | Toggles between modes | Controls how water flows |
| Water Interval | `number.dockstream_smart_rfid_fountain_water_interval` | 10 minutes | Time between water dispensing in intermittent mode |
| Water Dispensing Duration | `number.dockstream_smart_rfid_fountain_water_dispensing_duration` | 15 minutes | How long water flows in intermittent mode |
| Cleaning Cycle | `number.dockstream_smart_rfid_fountain_cleaning_cycle` | 14 days | Reminder interval for cleaning |
## Available Modes
The fountain supports two water dispensing modes:
1. **Flowing Water (Constant)** - Water flows continuously
2. **Intermittent Water (Scheduled)** - Water flows according to the interval and duration settings
## Automation Details
The fountain cycling automation is defined in `/etc/nixos/fountain_automation.yaml`:
```yaml
alias: "Fountain Cycle Mode"
description: "Toggles fountain water mode every 15 minutes between constant and intermittent flow"
trigger:
- platform: time_pattern
minutes: "/15" # Every 15 minutes
condition: []
action:
- service: select.select_next
target:
entity_id: select.dockstream_smart_rfid_fountain_water_dispensing_mode
mode: single
id: fountain_cycle_mode
```
### How It Works
1. **Trigger**: The automation runs every 15 minutes based on the time pattern trigger
2. **Action**: It uses the `select.select_next` service to toggle to the next available option
3. **Mode**: Set to "single" to prevent multiple executions if triggers overlap
## Installation
The automation is included in Home Assistant via the `automation manual` directive in the Home Assistant configuration:
```yaml
"automation manual" = "!include_dir_merge_list /etc/hass";
```
The YAML file needs to be placed in the `/etc/hass` directory to be loaded.
## Testing
To manually test the automation:
1. In Home Assistant UI, go to Developer Tools > Services
2. Select `automation.trigger` as the service
3. Enter the following service data:
```yaml
entity_id: automation.fountain_cycle_mode
```
4. Click "Call Service" to trigger the automation
## Customizing
To adjust the cycling interval:
1. Edit the YAML file at `/etc/nixos/fountain_automation.yaml`
2. Change the `minutes` value in the trigger section (e.g., from `"/15"` to `"/30"` for every 30 minutes)
3. Save the file
4. Restart Home Assistant or reload automations
To adjust fountain settings:
1. In Home Assistant UI, go to Settings > Devices & Services
2. Find the Dockstream Smart RFID Fountain device
3. Adjust the water interval or dispensing duration settings
## Troubleshooting
If the automation is not working as expected:
1. Check that the entity ID is correct and the fountain is online
2. Verify that Home Assistant is including the automation file correctly
3. Look for errors in the Home Assistant logs related to the automation or the fountain
4. Try manually controlling the fountain to ensure it responds to commands

116
docs/modules/README.md Normal file
View File

@@ -0,0 +1,116 @@
# Custom Modules
This directory contains documentation for the custom modules used in this NixOS configuration.
## Module Types
The repository uses two main types of modules:
1. **NixOS Modules** - System-level configurations in `modules/nixos/`
2. **Home Manager Modules** - User-level configurations in `modules/home/`
## NixOS Modules
These modules configure the system-level aspects of NixOS:
- [Boot Modules](./boot.md) - Boot loader and kernel configurations
- [Desktop Modules](./desktop.md) - Desktop environment configurations
- [Development Modules](./development.md) - Development tools and environments
- [Hardware Modules](./hardware.md) - Hardware-specific configurations
- [Home Assistant Modules](./homeassistant.md) - Home automation configuration
- [Networking Modules](./network.md) - Network configuration and services
- [Security Modules](./security.md) - Security-related configurations
- [Services Modules](./services.md) - Various service configurations
- [System Modules](./system.md) - General system configurations
- [Virtualization Modules](./virtualization.md) - Virtualization and containerization
## Home Manager Modules
These modules configure user environments:
- [Applications](./home/applications.md) - User applications
- [Desktop](./home/desktop.md) - User desktop environments
- [Development](./home/development.md) - User development environments
- [Media](./home/media.md) - Media applications
- [Shell](./home/shell.md) - Shell configurations
## Module Structure
Each module follows a standard structure:
```
modules/nixos/example-module/
├── default.nix # Main implementation
├── options.nix # Option declarations
└── submodule/ # Optional submodules
└── default.nix # Submodule implementation
```
### default.nix
The `default.nix` file contains the main implementation of the module:
```nix
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.${namespace}.example-module;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Module implementation when enabled
};
}
```
### options.nix
The `options.nix` file declares the module's configuration options:
```nix
{ lib, namespace, ... }:
with lib;
let
inherit (lib.${namespace}) mkOpt;
in
{
options.${namespace}.example-module = {
enable = mkEnableOption "enable example module";
# Other option declarations
};
}
```
## Using Modules
To use a module in your system configuration:
1. Enable the module in your system configuration:
```nix
{ config, ... }:
{
mjallen.example-module = {
enable = true;
# Other options
};
}
```
## Creating New Modules
To create a new module:
1. Create a new directory in `modules/nixos/` or `modules/home/`
2. Create `default.nix` and `options.nix` files
3. Implement your module functionality
4. Import the module in your system configuration
See the [Getting Started](../getting-started.md) guide for more details on creating modules.

View File

@@ -0,0 +1,190 @@
# Home Assistant Module
This document details the Home Assistant module configuration.
## Module Structure
The Home Assistant module is organized in the following structure:
```
modules/nixos/homeassistant/
├── automations/ # Automation configurations
│ ├── lightswitch/ # Light switch automations
│ └── motion-light/ # Motion-activated light automations
├── default.nix # Main module configuration
├── options.nix # Module options definition
└── services/ # Related service configurations
├── govee2mqtt/ # Govee integration via MQTT
├── homeassistant/ # Core Home Assistant service
├── music-assistant/ # Music Assistant integration
├── thread/ # Thread border router
└── zigbee2mqtt/ # Zigbee to MQTT bridge
```
## Module Options
The module is configured through options defined in `options.nix`:
```nix
options.${namespace}.services.home-assistant = {
enable = mkEnableOption "enable home-assistant";
mosquittoPort = mkOpt types.int 1883 "Port for MQTT";
zigbee2mqttPort = mkOpt types.int 8080 "Port for zigbee2mqtt web interface";
zigbeeDevicePath = mkOpt types.str "/dev/ttyUSB0" "Path to zigbee usb device";
};
```
## Main Configuration
The main module configuration in `default.nix` includes:
1. **Activation Scripts** - For setting up custom components
2. **Service Configurations** - For Matter, PostgreSQL, etc.
3. **Firewall Rules** - For allowing required ports
```nix
config = lib.mkIf cfg.enable {
# Activation script for custom components
system.activationScripts.installCustomComponents = ''
chown -R hass:hass ${config.services.home-assistant.configDir}
chmod -R 750 ${config.services.home-assistant.configDir}
'';
# Service configurations
services = {
matter-server.enable = true;
postgresql = {
enable = false;
ensureDatabases = [ "hass" ];
ensureUsers = [
{
name = "hass";
ensureDBOwnership = true;
}
];
};
};
# Firewall rules
networking.firewall.allowedTCPPorts = [
cfg.mosquittoPort
cfg.zigbee2mqttPort
8095 # music-assistant
8097 # home-assistant
5580 # matter-server
];
};
```
## Home Assistant Service
The core Home Assistant service configuration in `services/homeassistant/default.nix` includes:
1. **Package Selection** - Using the standard Home Assistant package
2. **Component Configuration** - Enabling required components
3. **Custom Components** - Adding custom components from packages
4. **Lovelace Modules** - Adding custom UI components
5. **Integration Configuration** - Setting up integrations with other systems
```nix
services.home-assistant = {
enable = true;
package = pkgs.home-assistant;
openFirewall = true;
configDir = "/var/lib/homeassistant";
configWritable = true;
# Components
extraComponents = [
"mqtt"
"zha"
"homekit"
# ... many more components
];
# Custom components
customComponents = [
# ... custom components
];
# Lovelace modules
customLovelaceModules = [
# ... custom UI modules
];
# Configuration
config = {
# ... Home Assistant configuration
};
};
```
## Related Services
### Zigbee2MQTT
The Zigbee2MQTT service in `services/zigbee2mqtt/default.nix` connects Zigbee devices to MQTT:
```nix
services.zigbee2mqtt = {
enable = true;
settings = {
mqtt = {
server = "mqtt://localhost:${toString cfg.mosquittoPort}";
};
serial = {
port = cfg.zigbeeDevicePath;
};
# ... additional settings
};
};
```
### MQTT
MQTT is configured as a dependency for the Home Assistant module.
### Thread Border Router
The Thread Border Router in `services/thread/default.nix` provides Thread network connectivity for Matter devices.
## Automations
The module includes predefined automations in the `automations/` directory:
1. **Light Switch Automations** - For controlling lights via physical switches
2. **Motion Light Automations** - For motion-activated lighting
## Using the Module
To use this module in a system configuration:
```nix
{ config, ... }:
{
mjallen.services.home-assistant = {
enable = true;
# Optional: customize ports and device paths
mosquittoPort = 1883;
zigbee2mqttPort = 8080;
zigbeeDevicePath = "/dev/ttyUSB0";
};
}
```
## Extending the Module
### Adding Custom Components
To add a custom component:
1. Add the package to `packages/`
2. Add it to the `customComponents` list in `services/homeassistant/default.nix`
### Adding Custom Automations
To add a custom automation:
1. Create a new directory in `automations/`
2. Implement the automation in `default.nix`
3. Import it in the system configuration

22
docs/systems/README.md Normal file
View File

@@ -0,0 +1,22 @@
# System Configurations
This directory contains documentation for each system configuration in this repository.
## Systems
- [Desktop (matt-nixos)](./matt-nixos.md) - Main desktop computer
- [NAS (jallen-nas)](./jallen-nas.md) - Home server and NAS
- [NUC (nuc-nixos)](./nuc-nixos.md) - Intel NUC
- [Raspberry Pi 5](./pi5.md) - Raspberry Pi 5
- [MacBook Pro (nixOS)](./macbook-pro-nixos.md) - MacBook Pro running NixOS
## Common Configuration
All systems share certain common configurations through the modules system. These include:
- Base system configuration
- User management
- Network configuration
- Security settings
Each system then adds its specific configurations on top of these common modules.

101
docs/systems/jallen-nas.md Normal file
View File

@@ -0,0 +1,101 @@
# NAS Server (jallen-nas)
This document describes the configuration for the NAS server system.
## Hardware
The NAS server is built on AMD hardware:
- CPU: AMD processor
- Hardware-specific modules:
- `nixos-hardware.nixosModules.common-pc`
- `nixos-hardware.nixosModules.common-cpu-amd`
- `nixos-hardware.nixosModules.common-cpu-amd-pstate`
- `nixos-hardware.nixosModules.common-hidpi`
## Services
The NAS hosts various services:
### Media Services
- **Jellyfin** - Media server
- **Jellyseerr** - Media request manager
- **Sonarr** - TV show management
- **Radarr** - Movie management
- **Lidarr** - Music management
- **Bazarr** - Subtitle management
- **Music Assistant** - Music streaming integration with Home Assistant
### Download Services
- **Transmission** - Torrent client
- **NZBGet** - Usenet downloader
- **Prowlarr** - Indexer manager
### Document Management
- **Paperless-ngx** - Document management system
### File Sharing
- **Samba** - Windows file sharing
- **Nextcloud** - Self-hosted cloud storage
### AI Services
- **Ollama** - Local AI model hosting
### Smart Home
- **Home Assistant** - Smart home controller
- **Zigbee2MQTT** - Zigbee device integration
- **MQTT** - Message broker for IoT devices
- **Thread Border Router** - Thread network for smart home devices
## Storage Configuration
The NAS uses multiple storage devices:
1. **System Drive** - For the operating system
2. **Data Drives** - Configured as a storage array for media and data
## Network Configuration
The NAS is configured with:
- Static IP address
- Firewall rules for the various services
- Tailscale for secure remote access
## Backup Strategy
The NAS implements a comprehensive backup strategy:
1. **System Backup** - Regular backups of the NixOS configuration
2. **Data Backup** - Backups of important data to secondary storage
3. **Off-site Backup** - Critical data is backed up off-site
## Usage and Management
### Accessing Services
Most services are available through a reverse proxy, which provides:
- HTTPS access
- Authentication via Authentik
- Subdomain-based routing
### Adding Storage
To add additional storage to the NAS:
1. Add the physical drive to the system
2. Update the disko configuration
3. Rebuild the system with `nixos-rebuild switch`
### Monitoring
The system can be monitored through:
- Prometheus metrics
- Grafana dashboards
- Home Assistant sensors

213
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,213 @@
# Troubleshooting Guide
This guide provides solutions for common issues that may arise when using this NixOS configuration.
## System Issues
### Failed System Build
**Problem**: `nixos-rebuild switch` fails with an error.
**Solutions**:
1. **Syntax Errors**:
- Check the error message for file and line number information
- Verify the syntax in the mentioned file
- Common issues include missing semicolons, curly braces, or mismatched quotes
2. **Missing Dependencies**:
- If the error mentions a missing package or dependency:
```
git pull # Update to the latest version
nix flake update # Update the flake inputs
```
3. **Conflicting Modules**:
- Look for modules that might be configuring the same options incompatibly
- Disable one of the conflicting modules or adjust their configurations
4. **Disk Space Issues**:
- Check available disk space with `df -h`
- Clear old generations: `sudo nix-collect-garbage -d`
### Boot Issues
**Problem**: System fails to boot after a configuration change.
**Solutions**:
1. **Boot into a Previous Generation**:
- At the boot menu, select an older generation
- Once booted, revert the problematic change:
```
cd /etc/nixos
git revert HEAD # Or edit the files directly
sudo nixos-rebuild switch
```
2. **Boot from Installation Media**:
- Boot from a NixOS installation media
- Mount your system:
```
sudo mount /dev/disk/by-label/nixos /mnt
sudo mount /dev/disk/by-label/boot /mnt/boot # If separate boot partition
```
- Chroot into your system:
```
sudo nixos-enter --root /mnt
cd /etc/nixos
git revert HEAD # Or edit the files directly
nixos-rebuild switch --install-bootloader
```
## Home Assistant Issues
### Home Assistant Fails to Start
**Problem**: Home Assistant service fails to start.
**Solutions**:
1. **Check Service Status**:
```
systemctl status home-assistant
journalctl -u home-assistant -n 100
```
2. **Database Issues**:
- Check PostgreSQL is running: `systemctl status postgresql`
- Verify database connection settings in Home Assistant configuration
3. **Permission Issues**:
- Check ownership and permissions on config directory:
```
ls -la /var/lib/homeassistant
sudo chown -R hass:hass /var/lib/homeassistant
sudo chmod -R 750 /var/lib/homeassistant
```
4. **Custom Component Issues**:
- Try disabling custom components to isolate the issue:
- Edit `modules/nixos/homeassistant/services/homeassistant/default.nix`
- Comment out the `customComponents` section
- Rebuild: `sudo nixos-rebuild switch`
### Zigbee Device Connection Issues
**Problem**: Zigbee devices fail to connect or are unstable.
**Solutions**:
1. **Verify Device Path**:
- Check the Zigbee coordinator is properly detected:
```
ls -la /dev/ttyUSB*
```
- Update the device path if needed:
- Edit your system configuration
- Set `mjallen.services.home-assistant.zigbeeDevicePath` to the correct path
- Rebuild: `sudo nixos-rebuild switch`
2. **Interference Issues**:
- Move the Zigbee coordinator away from other wireless devices
- Try a USB extension cable to improve positioning
- Change Zigbee channel in Zigbee2MQTT configuration
3. **Reset Zigbee2MQTT**:
```
systemctl restart zigbee2mqtt
```
### Automation Issues
**Problem**: Automations don't run as expected.
**Solutions**:
1. **Check Automation Status**:
- In Home Assistant UI, verify the automation is enabled
- Check Home Assistant logs for automation execution errors
2. **Entity Issues**:
- Verify entity IDs are correct
- Check if entities are available/connected
- Test direct service calls to verify entity control works
3. **Trigger Issues**:
- Test the automation manually via Developer Tools > Services
- Use `automation.trigger` service with the automation's entity_id
## Flake Issues
### Flake Input Update Errors
**Problem**: `nix flake update` fails or causes issues.
**Solutions**:
1. **Selective Updates**:
- Update specific inputs instead of all at once:
```
nix flake lock --update-input nixpkgs
```
2. **Rollback Flake Lock**:
- If an update causes issues, revert to previous flake.lock:
```
git checkout HEAD^ -- flake.lock
```
3. **Pin to Specific Revisions**:
- In `flake.nix`, pin problematic inputs to specific revisions:
```nix
nixpkgs-stable.url = "github:NixOS/nixpkgs/5233fd2ba76a3accb05f88b08917450363be8899";
```
## Secret Management Issues
### Sops Decryption Errors
**Problem**: Sops fails to decrypt secrets.
**Solutions**:
1. **Key Issues**:
- Verify your GPG key is available and unlocked
- Check `.sops.yaml` includes your key fingerprint
2. **Permission Issues**:
- Check file permissions on secret files
- Make sure the user running `nixos-rebuild` has access to the GPG key
## Network Issues
### Firewall Blocks Services
**Problem**: Services are not accessible due to firewall rules.
**Solutions**:
1. **Check Firewall Status**:
```
sudo nix-shell -p iptables --run "iptables -L"
```
2. **Verify Firewall Configuration**:
- Check if ports are properly allowed in the configuration
- Add missing ports if necessary
3. **Temporary Disable Firewall** (for testing only):
```
sudo systemctl stop firewall
# After testing
sudo systemctl start firewall
```
## Getting Help
If you encounter an issue not covered in this guide:
1. Check the NixOS Wiki: https://nixos.wiki/
2. Search the NixOS Discourse forum: https://discourse.nixos.org/
3. Join the NixOS Matrix/Discord community for real-time help
4. File an issue in the repository if you believe you've found a bug

208
docs/version.schema.json Normal file
View File

@@ -0,0 +1,208 @@
{
"$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" }
}
}
}
}
}
}
}
}

1410
flake.lock generated

File diff suppressed because it is too large Load Diff

227
flake.nix
View File

@@ -1,30 +1,45 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05";
inputs = rec {
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";
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;
# The name "snowfall-lib" is required due to how Snowfall Lib processes your
# flake's inputs.
snowfall-lib = {
url = "github:snowfallorg/lib";
inputs.nixpkgs.follows = "nixpkgs";
};
chaotic.url = "github:chaotic-cx/nyx/nyxpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
url = "github:mjallen18/snowfall-lib";
inputs.nixpkgs.follows = "nixpkgs";
};
# nixos-generators = {
# url = "github:nix-community/nixos-generators";
# inputs.nixpkgs.follows = "nixpkgs";
# };
impermanence.url = "github:nix-community/impermanence";
lanzaboote.url = "github:nix-community/lanzaboote/v0.4.2";
lanzaboote.url = "github:nix-community/lanzaboote/v1.0.0";
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
sops-nix.url = "github:Mic92/sops-nix";
nix-cachyos-kernel.url = "github:xddxdd/nix-cachyos-kernel/release";
steam-rom-manager = {
url = "github:mjallen18/nix-steam-rom-manager";
inputs.nixpkgs.follows = "nixpkgs";
@@ -35,24 +50,21 @@
nix-vscode-extensions.url = "github:nix-community/nix-vscode-extensions";
authentik-nix.url = "github:nix-community/authentik-nix";
crowdsec.url = "git+https://codeberg.org/kampka/nix-flake-crowdsec.git";
authentik-nix = {
url = "github:nix-community/authentik-nix";
# inputs.nixpkgs.follows = "nixpkgs-stable";
};
nixai.url = "github:olafkfreund/nix-ai-help";
disko = {
# the fork is needed for partition attributes support
url = "github:nvmd/disko/gpt-attrs";
# url = "github:nix-community/disko";
# url = "github:nvmd/disko/gpt-attrs";
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
nixos-raspberrypi.url = "github:mjallen18/nixos-raspberrypi";
jovian.url = "github:Jovian-Experiments/Jovian-NixOS";
darwin.url = "github:LnL7/nix-darwin";
darwin.url = "github:nix-darwin/nix-darwin/master";
nix-homebrew.url = "github:zhaofengli/nix-homebrew";
@@ -68,7 +80,10 @@
nixos-apple-silicon.url = "github:nix-community/nixos-apple-silicon";
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
pre-commit-hooks-nix = {
url = "github:cachix/pre-commit-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
treefmt-nix = {
url = "github:numtide/treefmt-nix";
@@ -81,12 +96,34 @@
nixpkgs.follows = "nixpkgs";
};
};
lsfg-vk = {
url = "github:pabloaul/lsfg-vk-flake";
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";
};
jovian = {
url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs";
};
};
# We will handle this in the next section.
outputs = inputs:
let
snowfall = inputs.snowfall-lib.mkFlake {
outputs =
inputs:
inputs.snowfall-lib.mkFlake {
# You must provide our flake inputs to Snowfall Lib.
inherit inputs;
@@ -95,25 +132,39 @@
# Nix files to a separate directory.
src = ./.;
overlays = with inputs; [
nix-vscode-extensions.overlays.default
nix-cachyos-kernel.overlays.default
];
# Add a module to a specific host.
systems = {
# common modules
modules.nixos = with inputs; [
# nix-cachyos-kernel.nixosModules.default
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
steam-rom-manager.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
@@ -121,85 +172,53 @@
# ######################################################
# Desktop #
# ######################################################
desktop = {
matt-nixos = {
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
lsfg-vk.nixosModules.default
];
};
# ######################################################
# NAS #
# ######################################################
nas = {
jallen-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 #
# ######################################################
deck = {
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
];
};
# ######################################################
# NUC #
# ######################################################
nuc = {
nuc-nixos = {
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
];
};
# ######################################################
# Pi4 #
# ######################################################
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
];
};
# ######################################################
# Pi5 #
# ######################################################
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
];
};
@@ -209,33 +228,24 @@
macbook-pro-nixos = {
modules = with inputs; [
nixos-apple-silicon.nixosModules.default
lsfg-vk.nixosModules.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@deck" = {
modules = with inputs; [
steam-rom-manager.homeManagerModules.default
];
};
# ######################################################
# AllyX #
# ######################################################
allyx = {
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-gpu-amd
nixos-hardware.nixosModules.common-hidpi
nixos-hardware.nixosModules.common-pc
lsfg-vk.nixosModules.default
jovian.nixosModules.jovian
];
};
};
};
@@ -248,20 +258,33 @@
# Add flake metadata that can be processed by tools like Snowfall Frost.
meta = {
# A slug to use in documentation when displaying things like file paths.
name = "mjallen";
# A slug to use in documentation when displaying things like file paths.
name = "mjallen";
# A title to show for your flake, typically the name.
title = "mjallen Flake";
# A title to show for your flake, typically the name.
title = "mjallen Flake";
};
};
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;
};
};
};
};
in
snowfall // {
nixosConfigurations = snowfall.nixosConfigurations;
};
}
}

View File

@@ -1,5 +1,11 @@
{ lib, pkgs, home, ... }:
{
lib,
pkgs,
namespace,
...
}:
let
inherit (lib.${namespace}) enabled disabled;
shellAliases = {
update-switch = "darwin-rebuild switch --flake ~/nix-config";
update-flake = "nix flake update ~/nix-config";
@@ -9,20 +15,17 @@ let
age
cpufetch
deadnix
direnv
nixfmt-rfc-style
iproute2mac
nebula
nixfmt
nodePackages.nodejs
uv
sops
tree
wget
];
in
{
# imports = [
# ../../modules/home/defaults.nix
# ../../modules/home/git.nix
# ../../modules/home/shell.nix
# ../../modules/home/vscode.nix
# ];
# Home Manager needs a bit of information about you and the
# paths it should manage.
home = {
@@ -30,7 +33,7 @@ in
homeDirectory = "/Users/mattjallen";
packages = lib.mkForce packages;
sessionVariables = {
NH_DARWIN_FLAKE = "${home.homeDirectory}/nix-config#mac";
NH_DARWIN_FLAKE = lib.mkForce "/Users/mattjallen/nix-config";
};
};
@@ -40,20 +43,238 @@ 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.enable = false;
manual.manpages = enabled;
# Override defaults that arent supported
programs = {
mangohud.enable = lib.mkForce false;
mangohud = lib.mkForce disabled;
nh = {
flake = "${home.homeDirectory}/nix-config";
flake = lib.mkForce "/Users/mattjallen/nix-config";
};
};
services = {
pass-secret-service.enable = lib.mkForce false;
nextcloud-client.enable = lib.mkForce false;
pass-secret-service = lib.mkForce disabled;
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -1,14 +1,11 @@
{ pkgs, lib, ... }:
{
lib,
pkgs,
namespace,
...
}:
let
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;
inherit (lib.${namespace}) enabled disabled;
# Displays
display = {
input = "eDP-1";
@@ -22,17 +19,30 @@ in
home.homeDirectory = "/home/matt";
home.stateVersion = "23.11";
mjallen = {
desktop.hyprland = {
enable = true;
${namespace} = {
desktop.gnome = enabled;
programs.hyprland = {
enable = false;
primaryDisplay = "eDP-1";
debug.disableScaleChecks = true;
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"
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"
];
}
];
workspace = [
@@ -41,61 +51,54 @@ in
"name:steam, monitor:${display.input}, default:false, special, class:(.*[Ss]team.*)"
];
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.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;
};
};
btop = enabled;
kitty = disabled;
mako = disabled;
nwg-dock = disabled;
nwg-drawer = disabled;
nwg-panel = disabled;
waybar = {
enable = true;
enable = false;
layer = "bottom";
modules-right = [
"tray"
"temperature"
"temperature#gpu"
"keyboard-state#capslock"
"keyboard-state#numlock"
"wireplumber#sink"
"bluetooth"
"network"
"idle_inhibitor"
"clock"
"battery"
"custom/weather"
];
temperature = {
cpu = enabled;
gpu = enabled;
};
extraModules = {
"custom/lights" = {
tooltip = false;
exec = "waybar-hass --get_light light.living_room_lights";
interval = "once";
format = "{text}";#"󱉓";
format = "{text}"; # "󱉓";
on-click = "waybar-hass --toggle_light light.living_room_lights";
return-type = "json";
};
@@ -103,32 +106,70 @@ in
extraModulesStyle = ''
#custom-lights {
color: ${theme.frost.nord8};
background-color: ${theme.polarNight.nord0};
${theme.defaultOpacity}
${theme.borderLeft}
color: @base0C;
opacity: 0.85;
background-color: @base00;
}
#custom-lights:hover {
background: ${theme.polarNight.nord3};
background: @base03;
}
'';
windowOffset = 75;
};
wlogout.enable = true;
wofi.enable = true;
wlogout = disabled;
wofi = disabled;
};
};
home.packages = with pkgs; [
iw
iwd
orca-slicer
vscodium
];
home.packages =
with pkgs.${namespace};
[
# librepods
librepods-beta
]
++ (with pkgs; [
bolt-launcher
iw
iwd
orca-slicer
vscodium
gnomeExtensions.notch-clock-offset
]);
services = {
kdeconnect = {
enable = lib.mkForce true;
indicator = lib.mkForce true;
};
};
programs = {
password-store.enable = true;
password-store = enabled;
};
zsh.shellAliases = shellAliases;
dconf = {
enable = true;
settings = {
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".name = "Keyboard Backlight +";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".binding = "<Super>MonBrightnessUp";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0".command = "brightnessctl -d kbd_backlight s +10";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".name = "Keyboard Backlight -";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".binding = "<Super>MonBrightnessDown";
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1".command = "brightnessctl -d kbd_backlight s 10-";
"org/gnome/shell".enabled-extensions = [
"notch-clock-offset@christophbrill.de"
];
"org/gnome/shell/extensions/notch-clock-offset".percent = 40;
"org/gnome/settings-daemon/plugins/media-keys".custom-keybindings = [
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/"
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1/"
];
};
};
}

View File

@@ -1,65 +0,0 @@
{ lib, ... }:
let
shellAliases = {
ll = "ls -alh";
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 pi4-nixpkgs pi4-home-manager pi4-impermanence pi4-sops-nix pi4-nixos-hardware pi4-nixos-raspberrypi pi4-disko --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";
ducks = "du -cksh * | sort -hr | head -n 15";
};
in
{
imports = [
../../../modules/home/home
../../../modules/home/programs/git
../../../modules/home/programs/zsh
];
home.username = "matt";
sops = {
age.keyFile = "/home/matt/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/pi4" = {
path = "/home/matt/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/pi4" = {
path = "/home/matt/.ssh/id_ed25519";
mode = "0600";
};
# "ssh-keys-public/desktop-nixos" = {
# path = "/home/matt/.ssh/authorized_keys";
# mode = "0600";
# };
# "ssh-keys-public/desktop-nixos-root" = {
# path = "/home/matt/.ssh/authorized_keys2";
# mode = "0600";
# };
# "ssh-keys-public/desktop-windows" = {
# path = "/home/matt/.ssh/authorized_keys3";
# mode = "0600";
# };
# "ssh-keys-public/macbook-macos" = {
# path = "/home/matt/.ssh/authorized_keys4";
# mode = "0600";
# };
};
};
programs = {
mangohud.enable = lib.mkForce true;
zsh.shellAliases = shellAliases;
};
services = {
nextcloud-client.enable = lib.mkForce true;
};
}

View File

@@ -1,12 +1,11 @@
{ pkgs, lib, config, namespace, ... }:
{
config,
lib,
namespace,
...
}:
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 --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";
};
inherit (lib.${namespace}) disabled;
in
{
@@ -51,7 +50,11 @@ in
};
};
programs = {
zsh.shellAliases = shellAliases;
services = {
nextcloud-client = lib.mkForce disabled;
kdeconnect = {
enable = false;
indicator = false;
};
};
}

View File

@@ -0,0 +1,18 @@
{
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 @@
{ 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}";
enableNixpkgsReleaseCheck = false;
};
programs = {
zsh.shellAliases = shellAliases;
};
}

View File

@@ -0,0 +1,18 @@
{
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,175 @@
{ pkgs, namespace, ... }:
{
home = {
username = "admin";
packages =
with pkgs;
[
heroic
python3
python3Packages.requests
python3Packages.mcp
jq
]
++ (with pkgs.${namespace}; [
moondeck-buddy
]);
};
${namespace} = {
sops.enable = true;
};
sops = {
age.keyFile = "/home/admin/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/jallen-nas" = {
path = "/home/admin/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/jallen-nas" = {
path = "/home/admin/.ssh/id_ed25519";
mode = "0600";
};
"ssh-keys-public/desktop-nixos" = {
path = "/home/admin/.ssh/authorized_keys";
mode = "0600";
};
"ssh-keys-public/desktop-nixos-root" = {
path = "/home/admin/.ssh/authorized_keys2";
mode = "0600";
};
"ssh-keys-public/desktop-windows" = {
path = "/home/admin/.ssh/authorized_keys3";
mode = "0600";
};
"ssh-keys-public/macbook-macos" = {
path = "/home/admin/.ssh/authorized_keys4";
mode = "0600";
};
};
};
programs = {
bash = {
shellAliases = {
"llama-status" =
"curl -s http://localhost:8127/health 2>/dev/null && echo 'LLaMA.cpp server is running' || echo 'LLaMA.cpp server is not responding'";
};
};
neovim = {
enable = true;
viAlias = true;
vimAlias = true;
defaultEditor = true;
plugins = [
pkgs.vimPlugins.nvim-tree-lua
{
plugin = pkgs.vimPlugins.vim-startify;
config = "let g:startify_change_to_vcs_root = 0";
}
];
};
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 = "";
};
};
};
opencode = {
enable = true;
enableMcpIntegration = true;
settings = {
provider = {
nas = {
npm = "@ai-sdk/openai-compatible";
name = "llama-server (local)";
options = {
baseURL = "http://jallen-nas.local:8127/v1";
};
models = {
Qwen3-Coder-Next-Q4_0 = {
name = "Qwen3 Coder (local)";
modalities = {
input = [
"image"
"text"
];
output = [ "text" ];
};
limit = {
context = 262144;
output = 262144;
};
};
# "GLM-4.7-Flash-REAP-23B-A3B-UD-Q3_K_XL": {
# "name": "GLM 4.7 Flash (local)",
# "modalities": { "input": ["image", "text"], "output": ["text"] },
# "limit": {
# "context": 262144,
# "output": 262144
# }
# };
# "Nemotron-3-Nano-30B-A3B-IQ4_XS": {
# "name": "Nemotron-3-Nano (local)",
# "modalities": { "input": ["image", "text"], "output": ["text"] },
# "limit": {
# "context": 262144,
# "output": 262144
# }
# };
};
};
};
};
};
mcp = {
enable = true;
servers = {
nixos = {
command = "nix";
args = [
"run"
"github:utensils/mcp-nixos"
"--"
];
};
hass-mcp = {
command = "uvx";
args = [ "hass-mcp" ];
env = {
HA_URL = "http://nuc-nixos.local:8123";
HA_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1ZDM2MTliNWNjMGY0ZGI2OWQzOTQ4Mjk0ZDFmNjAxMCIsImlhdCI6MTc3MDc2MjA1NywiZXhwIjoyMDg2MTIyMDU3fQ.P52jeX8GQcdGdzpbU3NCWZMUjkJZHFnOeR8--jy9dF8";
};
};
mcp-server-code-runner = {
command = "npm";
args = [
"-y"
"mcp-server-code-runner@latest"
];
};
};
};
};
}

View File

@@ -1,77 +0,0 @@
{ pkgs, ... }:
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";
# mjallen.home.enable = true;
sops = {
age.keyFile = "/home/admin/.config/sops/age/keys.txt";
defaultSopsFile = "/etc/nixos/secrets/secrets.yaml";
validateSopsFiles = false;
secrets = {
"ssh-keys-public/jallen-nas" = {
path = "/home/admin/.ssh/id_ed25519.pub";
mode = "0644";
};
"ssh-keys-private/jallen-nas" = {
path = "/home/admin/.ssh/id_ed25519";
mode = "0600";
};
"ssh-keys-public/desktop-nixos" = {
path = "/home/admin/.ssh/authorized_keys";
mode = "0600";
};
"ssh-keys-public/desktop-nixos-root" = {
path = "/home/admin/.ssh/authorized_keys2";
mode = "0600";
};
"ssh-keys-public/desktop-windows" = {
path = "/home/admin/.ssh/authorized_keys3";
mode = "0600";
};
"ssh-keys-public/macbook-macos" = {
path = "/home/admin/.ssh/authorized_keys4";
mode = "0600";
};
};
};
programs = {
neovim = {
enable = true;
viAlias = true;
vimAlias = true;
defaultEditor = true;
plugins = [
pkgs.vimPlugins.nvim-tree-lua
{
plugin = pkgs.vimPlugins.vim-startify;
config = "let g:startify_change_to_vcs_root = 0";
}
];
};
zsh.shellAliases = shellAliases;
};
# 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

@@ -0,0 +1,37 @@
{
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

@@ -1,15 +0,0 @@
{ pkgs,... }:
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

@@ -1,73 +0,0 @@
{ 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";
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
vmware-horizon-client
];
}

View File

@@ -0,0 +1,89 @@
{
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";
environmentVariables = {
romsDirectory = "/media/sdcard/Emulation/roms";
steamDirectory = "/home/matt/.local/share/Steam";
};
enabledProviders = [ "sgdb" "steamCDN" ];
imageProviderSettings.sgdb = {
nsfw = false;
humor = false;
imageMotionTypes = [ "static" ];
};
emulators = {
# --- Nintendo ---
ryujinx.enable = true; # Switch (ryubing fork)
yuzu.enable = true; # Switch (eden fork)
dolphin-emu.enable = true; # GameCube / Wii
cemu.enable = true; # Wii U
melonDS.enable = true; # DS
citra.enable = true; # 3DS (azahar fork)
mgba.enable = true; # Game Boy / GBC
mgba-gba.enable = true; # Game Boy Advance
# --- Sony ---
duckstation.enable = false; # PS1
pcsx2.enable = true; # PS2
rpcs3.enable = true; # PS3
ppsspp.enable = true; # PSP
# --- Microsoft ---
xemu.enable = true; # Xbox
# --- Platform parsers (no ROM scanning; artwork only / launcher integration) ---
"Non-SRM Shortcuts".enable = true;
};
};
};
home.packages =
with pkgs;
[
dolphin-emu
heroic
mgba
moonlight-qt
prismlauncher
ryubing
omnissa-horizon-client
]
++ (with pkgs.${namespace}; [
discord-krisp
# librepods-beta
]);
}

View File

@@ -1,50 +0,0 @@
{ pkgs, namespace, ... }:
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 --build-host admin@10.0.1.3";
update-flake = "nix flake update desktop-nixpkgs desktop-chaotic desktop-home-manager desktop-impermanence desktop-lanzaboote desktop-nixos-hardware desktop-sops-nix desktop-steam-rom-manager --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";
};
in
{
home.username = "matt";
services = {
remmina = {
enable = true;
addRdpMimeTypeAssoc = true;
};
};
programs = {
password-store.enable = true;
zsh.shellAliases = shellAliases;
};
home.packages = with pkgs; [
bottles
compose2nix
discord
distrobox
heroic
stable.vmware-horizon-client
jq
lutris
lzip
morph
orca-slicer
piper
prismlauncher
protontricks
protonvpn-gui
python3
smile
unigine-heaven
via
virt-manager
vorta
waydroid-helper
];
}

View File

@@ -0,0 +1,210 @@
{
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;
};
desktop.gnome = enabled;
programs = {
hyprland = {
enable = false;
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 = disabled;
mako = disabled;
nwg-dock = disabled;
nwg-drawer = disabled;
nwg-panel = disabled;
waybar = {
enable = false;
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 = disabled;
wofi = disabled;
};
};
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 = {
"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

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

View File

@@ -0,0 +1,18 @@
{
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,18 @@
{
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,18 @@
{
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,18 @@
{
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,18 @@
{
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,17 +0,0 @@
{ 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;
};
}

130
lib/README.md Normal file
View File

@@ -0,0 +1,130 @@
# 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

3
lib/base64/ascii Normal file
View File

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

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

62
lib/base64/default.nix Normal file
View File

@@ -0,0 +1,62 @@
{ 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;
}

25
lib/default.nix Normal file
View File

@@ -0,0 +1,25 @@
{ 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;
};
};
}

8
lib/examples/default.nix Normal file
View File

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

View File

@@ -0,0 +1,60 @@
{ 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

@@ -0,0 +1,40 @@
{
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

@@ -0,0 +1,117 @@
# 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;
# }];
# };
}

45
lib/examples/sops.nix Normal file
View File

@@ -0,0 +1,45 @@
{
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

@@ -0,0 +1,132 @@
{ 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;
}

127
lib/file/default.nix Normal file
View File

@@ -0,0 +1,127 @@
{ 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;
}

264
lib/module/default.nix Normal file
View File

@@ -0,0 +1,264 @@
{
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

@@ -0,0 +1,220 @@
{ 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
);
};
}

103
lib/system/common.nix Normal file
View File

@@ -0,0 +1,103 @@
{ 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;
};
}

5
lib/system/default.nix Normal file
View File

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

212
lib/versioning/default.nix Normal file
View File

@@ -0,0 +1,212 @@
{
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

@@ -0,0 +1,54 @@
{
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;
};
# 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

@@ -0,0 +1,58 @@
{
config,
lib,
namespace,
...
}:
{
nix = {
settings = {
# extra-sandbox-paths = [ config.programs.ccache.cacheDir ];
substituters = [
"http://jallen-nas.local:9012/nas-cache"
"https://nixos-apple-silicon.cachix.org"
"https://nixos-raspberrypi.cachix.org"
"https://nix-community.cachix.org"
"https://cache.nixos.org/"
];
trusted-public-keys = [
"nas-cache:eK0eRVAt9QNwbkLIyOo9N5Z5+zi6ukI4mSlL196C7Yg="
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
warn-dirty = lib.mkForce false;
experimental-features = lib.mkForce [
"nix-command"
"flakes"
];
trusted-users = [
"@wheel"
"@admin"
];
builders-use-substitutes = true;
connect-timeout = lib.mkDefault 5;
fallback = true;
log-lines = lib.mkDefault 25;
max-free = lib.mkDefault (3000 * 1024 * 1024);
min-free = lib.mkDefault (512 * 1024 * 1024);
};
# Garbage collect automatically every week
gc = {
automatic = lib.mkDefault true;
options = lib.mkDefault "--delete-older-than 30d";
};
optimise.automatic = lib.mkDefault true;
};
nixpkgs = {
config = {
cudaSupport = lib.mkDefault config.${namespace}.hardware.nvidia.enable;
rocmSupport = lib.mkDefault config.${namespace}.hardware.amd.enable;
allowUnsupportedSystem = true;
};
};
}

View File

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

View File

@@ -1,6 +1,12 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.mjallen.desktop.gnome;
cfg = config.${namespace}.desktop.gnome;
in
{
imports = [ ./options.nix ];
@@ -17,7 +23,9 @@ 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
@@ -29,17 +37,22 @@ in
dconf = {
enable = true;
settings = {
"org/gnome/desktop/interface".clock-format = "12h";
"org/gnome/desktop/interface".color-scheme = "prefer-dark";
"org/gnome/desktop/interface".cursor-theme = lib.mkDefault "macOS";
"org/gnome/desktop/interface".enable-hot-corners = false;
"org/gnome/desktop/interface".font-antialiasing = "grayscale";
"org/gnome/desktop/interface".font-hinting = "slight";
"org/gnome/desktop/interface".gtk-theme = lib.mkDefault "Colloid-Dark";
"org/gnome/desktop/interface".icon-theme = lib.mkDefault "Colloid-Dark";
"io/missioncenter/MissionCenter".performance-page-cpu-graph = 2; # logical processors
"org/gnome/desktop/interface" = {
clock-format = "12h";
color-scheme = "prefer-dark";
cursor-theme = lib.mkDefault "macOS";
enable-hot-corners = false;
font-antialiasing = "grayscale";
font-hinting = "slight";
gtk-theme = lib.mkDefault "Colloid-Dark";
icon-theme = lib.mkDefault "Colloid-Dark";
};
"org/gnome/desktop/peripherals/mouse".accel-profile = "flat";
"org/gnome/desktop/peripherals/touchpad".two-finger-scrolling-enabled = true;
"org/gnome/desktop/peripherals/touchpad".tap-to-click = true;
"org/gnome/desktop/peripherals/touchpad" = {
two-finger-scrolling-enabled = true;
tap-to-click = true;
};
"org/gnome/mutter".experimental-features = [
"scale-monitor-framebuffer"
"variable-refresh-rate"
@@ -48,22 +61,38 @@ in
"org/gnome/shell".enabled-extensions = [
"allowlockedremotedesktop@kamens.us"
"appindicatorsupport@rgcjonas.gmail.com"
"caffeine@patapon.info"
"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 = true;
"org/gnome/shell/extensions/bingwallpaper".revert-to-current-image = false;
"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/bingwallpaper" = {
override-lockscreen-blur = true;
random-mode-enabled = false;
selected-image = "current";
revert-to-current-image = false;
};
"org/gnome/shell/extensions/caffeine" = {
enable-fullscreen = true;
enable-mpris = true;
inhibit-apps = [
"horizon-client.desktop"
];
};
"org/gnome/shell/extensions/dash-to-panel" = {
primary-monitor = 1;
multi-monitors = false;
};
"org/gnome/shell/extensions/gsconnect" = {
id = "4db35bd2-0dcd-42a3-9f77-ef3e8bb83182";
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, ... }:
{ lib, namespace, ... }:
with lib;
{
options.mjallen.desktop.gnome = {
options.${namespace}.desktop.gnome = {
enable = mkEnableOption "enable gnome settings";
};
}
}

View File

@@ -1,403 +0,0 @@
{ 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:(.*[Vv][Mm]ware-view),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:(.*[Vv][Mm]ware-view),title:([Vv][Mm]ware [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

@@ -1,123 +0,0 @@
{ 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 = 5;
};
screenOffTimer = mkOption {
type = with types; int;
default = 15;
};
suspendTimer = mkOption {
type = with types; int;
default = 30;
};
};
};
}

View File

@@ -1,67 +0,0 @@
{ 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
];
};
}

View File

@@ -1,41 +0,0 @@
{ config, lib, namespace, ... }:
let
cfg = config.${namespace}.desktop.hyprland;
in
{
imports = [ ../../options.nix ];
config = lib.mkIf cfg.enable {
services.hypridle = {
enable = false;
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

@@ -1,47 +0,0 @@
{ 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

@@ -1,18 +0,0 @@
{ 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

@@ -1,98 +0,0 @@
{ 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

@@ -1,39 +0,0 @@
{ 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

@@ -1,62 +0,0 @@
{
# 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

@@ -0,0 +1,79 @@
{ ... }:
{
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

@@ -1,56 +1,96 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
namespace,
hasDestopEnvironment ? true,
system,
...
}:
let
inherit (lib.${namespace}) enabled;
isArm = ("aarch64-linux" == system) || ("aarch64-darwin" == system);
in
{
home = {
enableNixpkgsReleaseCheck = lib.mkDefault false;
homeDirectory = lib.mkDefault "/home/${config.home.username}";
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
];
packages =
with pkgs;
[
age
clinfo
cpufetch
dbus
deadnix
lm_sensors
nano
nebula
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
mission-center
parted
vesktop
] ++ (
if !isArm then
[
# goverlay
# winboat
]
else [ ]
)
else
[ ]
);
stateVersion = lib.mkDefault "23.11";
};
programs = {
btop.enable = lib.mkDefault true;
fastfetch.enable = lib.mkDefault true;
home-manager.enable = lib.mkDefault true;
nix-index-database.comma = enabled;
btop = {
enable = lib.mkDefault true;
package = pkgs.unstable.btop;
};
fastfetch = lib.mkDefault enabled;
home-manager = lib.mkDefault enabled;
java = {
enable = lib.mkDefault true;
};
mangohud.enable = lib.mkDefault true;
password-store.enable = true;
mangohud.enable = lib.mkDefault hasDestopEnvironment;
password-store = enabled;
nh = {
enable = true;
flake = "/etc/nixos";
clean = {
enable = true;
extraArgs = "--keep 5";
};
};
micro = {
enable = true;
enable = lib.mkDefault true;
settings = {
autoindent = true;
autosu = true;
@@ -61,7 +101,7 @@
};
tmux = {
enable = true;
enable = lib.mkDefault true;
terminal = "screen-256color";
sensibleOnTop = true;
focusEvents = true;
@@ -101,11 +141,12 @@
};
services = {
nextcloud-client.enable = lib.mkDefault true;
pass-secret-service.enable = lib.mkDefault true;
nextcloud-client.enable = false; # lib.mkDefault hasDestopEnvironment;
pass-secret-service = lib.mkDefault enabled;
kdeconnect = {
enable = true;
indicator = true;
enable = lib.mkDefault hasDestopEnvironment;
indicator = lib.mkDefault hasDestopEnvironment;
package = pkgs.kdePackages.kdeconnect-kde;
};
};
}

View File

@@ -1,8 +1,12 @@
{ config, lib, ... }:
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.btop;
nord = import ../../desktop/theme/nord.nix;
cfg = config.${namespace}.programs.btop;
in
{
imports = [ ./options.nix ];
@@ -10,8 +14,6 @@ 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";
@@ -75,52 +77,6 @@ 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, ... }:
{ lib, namespace, ... }:
with lib;
{
options.mjallen.programs.btop = {
options.${namespace}.programs.btop = {
enable = mkEnableOption "enable btop";
};
}
}

View File

@@ -1,77 +1,83 @@
{ config, lib, pkgs, system, ... }:
{
config,
pkgs,
system,
namespace,
hasDestopEnvironment ? true,
...
}:
let
isArm = "aarch64-linux" == system;
open-remote-ssh = pkgs.vscode-utils.buildVscodeExtension {
pname = "open-remote-ssh";
version = "0.0.49";
vscodeExtPublisher = "jeanp413";
vscodeExtName = "open-remote-ssh";
vscodeExtUniqueId = "jeanp413.open-remote-ssh";
src = pkgs.fetchurl {
url = "https://open-vsx.org/api/jeanp413/open-remote-ssh/0.0.49/file/jeanp413.open-remote-ssh-0.0.49.vsix";
sha256 = "sha256-QfJnAAx+kO2iJ1EzWoO5HLogJKg3RiC3hg1/u2Jm6t4";
name = "open-remote-ssh.zip";
};
};
isArm = ("aarch64-linux" == system) || ("aarch64-darwin" == system);
isDarwin = ("aarch64-darwin" == 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 = true;
enable = hasDestopEnvironment;
package = pkgs.vscodium;
mutableExtensionsDir = false;
profiles = {
default = {
enableUpdateCheck = false;
enableExtensionUpdateCheck = false;
extensions = with pkgs; [
vscode-extensions.arrterian.nix-env-selector
vscode-extensions.bbenoist.nix
vscode-extensions.brettm12345.nixfmt-vscode
vscode-extensions.cweijan.vscode-database-client2
vscode-extensions.dendron.dendron-markdown-preview-enhanced
vscode-extensions.jnoortheen.nix-ide
vscode-extensions.mkhl.direnv
vscode-extensions.ms-python.debugpy
vscode-extensions.ms-python.pylint
vscode-extensions.ms-python.python
# vscode-extensions.ms-python.vscode-pylance
vscode-extensions.redhat.vscode-yaml
vscode-extensions.yy0931.vscode-sqlite3-editor
extensions =
with pkgs;
[
vscode-extensions.arrterian.nix-env-selector
vscode-extensions.bbenoist.nix
vscode-extensions.brettm12345.nixfmt-vscode
vscode-extensions.cweijan.vscode-database-client2
# vscode-extensions.dendron.dendron-markdown-preview-enhanced
vscode-extensions.jnoortheen.nix-ide
vscode-extensions.mkhl.direnv
vscode-extensions.ms-python.debugpy
vscode-extensions.ms-python.pylint
vscode-extensions.ms-python.python
# vscode-extensions.ms-python.vscode-pylance
vscode-extensions.redhat.vscode-yaml
vscode-extensions.yy0931.vscode-sqlite3-editor
# open-remote-ssh
# nix-vscode-extensions.open-vsx.jeanp413.open-remote-ssh
# open-vsx.jeanp413.open-remote-ssh
] ++ ( if !isArm then x86_only else [ ] ) ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
{
name = "copilot-mcp";
publisher = "automatalabs";
version = "0.0.49";
sha256 = "sha256-+G2OQl5SCN7bh7MzGdYiRclIZefBE7lWnGg1kNpCvnA=";
}
{
name = "mcp-server-runner";
publisher = "zebradev";
version = "0.1.0";
sha256 = "sha256-StydVt3VzQUSS/pYp76jnIwtZlEj8gWAGzOARs93J+E=";
}
{
name = "claude-dev";
publisher = "saoudrizwan";
version = "3.17.9";
sha256 = "sha256-y3bFtMe5vZrO3DFb31KDvkzjD2jM76wK89mKhgJXC70=";
}
];
nix-vscode-extensions.open-vsx.jeanp413.open-remote-ssh
]
++ (if !isArm then x86_only else [ ]);
# ++ (if !isDarwin then [ open-remote-ssh ] else [ ]);
# ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
# {
# name = "copilot-mcp";
# publisher = "automatalabs";
# version = "0.0.49";
# sha256 = "sha256-+G2OQl5SCN7bh7MzGdYiRclIZefBE7lWnGg1kNpCvnA=";
# }
# {
# name = "mcp-server-runner";
# publisher = "zebradev";
# version = "0.1.0";
# sha256 = "sha256-StydVt3VzQUSS/pYp76jnIwtZlEj8gWAGzOARs93J+E=";
# }
# {
# name = "claude-dev";
# publisher = "saoudrizwan";
# version = "3.17.9";
# sha256 = "sha256-y3bFtMe5vZrO3DFb31KDvkzjD2jM76wK89mKhgJXC70=";
# }
# ];
userSettings = {
"database-client.autoSync" = true;
"editor" = {
"defaultFormatter" = "brettm12345.nixfmt-vscode";
"fontFamily" = "fira-code-nerd, FiraCode Nerd Font, Consolas, 'Courier New', monospace";
"fontLigatures" = true;
"renderWhitespace" = "all";
};
@@ -79,7 +85,11 @@ in
"confirmDelete" = false;
"confirmDragAndDrop" = false;
};
"extensions." = {
"autoCheckUpdates" = false;
};
"git" = {
"confirmSync" = false;
"enableSmartCommit" = true;
@@ -110,10 +120,12 @@ in
# You can write arbitary Nix expressions here, to produce valid "options" declaration result.
# Tip: for flake-based configuration, utilize `builtins.getFlake`
"nixos" = {
"expr" = "(builtins.getFlake \"${config.home.homeDirectory}/nix-config\").nixosConfigurations.<name>.options";
"expr" =
"(builtins.getFlake \"${config.home.homeDirectory}/nix-config\").nixosConfigurations.<name>.options";
};
"home-manager" = {
"expr" = "(builtins.getFlake \"${config.home.homeDirectory}/nix-config\").homeConfigurations.<name>.options";
"expr" =
"(builtins.getFlake \"${config.home.homeDirectory}/nix-config\").homeConfigurations.<name>.options";
};
# # Tip: use ${workspaceFolder} variable to define path
# "nix-darwin" = {
@@ -133,12 +145,16 @@ in
"security.workspace.trust.untrustedFiles" = "open";
"update.mode" = "none";
"workbench" = {
"colorCustomizations" = null;
"editorAssociations" = {
"*.db" = "default";
};
};
"enable-proposed-api" = [ "jeanp413.open-remote-ssh" ];
};
};
};
@@ -149,4 +165,4 @@ in
enableZshIntegration = true;
};
};
}
}

View File

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

View File

@@ -0,0 +1,25 @@
{
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

@@ -0,0 +1,710 @@
{
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
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

@@ -0,0 +1,330 @@
{
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,8 +1,12 @@
{ lib, config, ... }:
{
lib,
config,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.kitty;
nord = import ../../desktop/theme/nord.nix;
cfg = config.${namespace}.programs.kitty;
in
{
imports = [ ./options.nix ];
@@ -12,12 +16,6 @@ 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";
@@ -26,80 +24,6 @@ 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,27 +1,7 @@
{ lib, ... }:
{ lib, namespace, ... }:
with lib;
{
options.mjallen.programs.kitty = {
options.${namespace}.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 = 8;
};
};
theme = mkOption {
type = types.attrs;
default = import ../../desktop/theme/nord.nix;
};
};
}
}

View File

@@ -36,7 +36,8 @@
"browser.newtabpage.activity-stream.topSitesRows" = 3; # Set number of rows for top sites on new tab page
"layout.css.light-dark.enabled" = true; # Enable light/dark theme support
"extensions.activeThemeID" = "default-theme@mozilla.org"; # Set active theme
"extensions.webextensions.uuids" = "{\"formautofill@mozilla.org\" =\"851c83b7-26d5-449c-8cc9-d8951a0ce78d\",\"pictureinpicture@mozilla.org\" =\"42fa2650-5134-4bef-bafa-b73f9ae51bad\",\"screenshots@mozilla.org\" =\"efd2b692-43c4-433a-aea5-0cb79f8312d4\",\"webcompat-reporter@mozilla.org\" =\"c43a6be2-fb56-4253-b384-ce8e09a89999\",\"webcompat@mozilla.org\" =\"e25fd1bb-7c53-413f-9528-bb922c322a56\",\"default-theme@mozilla.org\" =\"610b67c3-9145-46f7-814f-d8ee2cc8edff\",\"addons-search-detection@mozilla.com\:\"caedb3ca-5cf5-4e23-a251-d742f23e6fc8\",\"uBlock0@raymondhill.net\" =\"7e7d9fd9-12bf-42d3-9c7c-9ffd05420ec7\",\"78272b6fa58f4a1abaac99321d503a20@proton.me\" =\"7242a067-06d8-430b-94a3-00d264cdd57b\",\"addon@darkreader.org\" =\"2f02b112-6acd-4bdc-af2c-1432eb527339\",\"jid1-xUfzOsOFlzSOXg@jetpack\" =\"d0c72046-9903-4118-8160-a028840bf928\",\"chrome-gnome-shell@gnome.org\" =\"a1ab53e6-b765-4f25-8349-383cc04682a0\",\"user-agent-switcher@ninetailed.ninja\" =\"259d07cc-bb32-4ed5-b90f-6d73abdeb7bb\",\"firefoxdav@icloud.com\" =\"110e6e2c-18f8-461d-9f26-b8f04482b6f1\",\"ciscowebexstart1@cisco.com\" =\"a4062240-e73a-4353-bddb-d608d84881f7\",\"{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}\" =\"9164e437-812b-4a07-8dfd-2fd73b39329b\",\"{036a55b4-5e72-4d05-a06c-cba2dfcc134a}\" =\"648fc678-a6fb-47cd-9792-fb9520678c17\",\"{446900e4-71c2-419f-a6a7-df9c091e268b}\" =\"f0b43422-070e-466e-85c9-6543f209f075\",\"jid1-MnnxcxisBPnSXQ@jetpack\" =\"4c448202-c843-4cae-b5c3-d11f2da58fa3\",\"soundfixer@unrelenting.technology\" =\"59b35eb8-1c85-4919-a905-80d120993ddc\",\"floccus@handmadeideas.org\" =\"8ad2956c-8091-41af-a689-7d2108f5958d\",\"{79b9dbcf-cc5a-4cda-89ef-c4ab097eb074}\" =\"c2a223a7-32e0-4726-9f20-17236702b1f5\",\"linkgopher@oooninja.com\" =\"a257858c-0dce-415b-b123-6222876cf843\"}";
"extensions.webextensions.uuids" =
"{\"formautofill@mozilla.org\" =\"851c83b7-26d5-449c-8cc9-d8951a0ce78d\",\"pictureinpicture@mozilla.org\" =\"42fa2650-5134-4bef-bafa-b73f9ae51bad\",\"screenshots@mozilla.org\" =\"efd2b692-43c4-433a-aea5-0cb79f8312d4\",\"webcompat-reporter@mozilla.org\" =\"c43a6be2-fb56-4253-b384-ce8e09a89999\",\"webcompat@mozilla.org\" =\"e25fd1bb-7c53-413f-9528-bb922c322a56\",\"default-theme@mozilla.org\" =\"610b67c3-9145-46f7-814f-d8ee2cc8edff\",\"addons-search-detection@mozilla.com\:\"caedb3ca-5cf5-4e23-a251-d742f23e6fc8\",\"uBlock0@raymondhill.net\" =\"7e7d9fd9-12bf-42d3-9c7c-9ffd05420ec7\",\"78272b6fa58f4a1abaac99321d503a20@proton.me\" =\"7242a067-06d8-430b-94a3-00d264cdd57b\",\"addon@darkreader.org\" =\"2f02b112-6acd-4bdc-af2c-1432eb527339\",\"jid1-xUfzOsOFlzSOXg@jetpack\" =\"d0c72046-9903-4118-8160-a028840bf928\",\"chrome-gnome-shell@gnome.org\" =\"a1ab53e6-b765-4f25-8349-383cc04682a0\",\"user-agent-switcher@ninetailed.ninja\" =\"259d07cc-bb32-4ed5-b90f-6d73abdeb7bb\",\"firefoxdav@icloud.com\" =\"110e6e2c-18f8-461d-9f26-b8f04482b6f1\",\"ciscowebexstart1@cisco.com\" =\"a4062240-e73a-4353-bddb-d608d84881f7\",\"{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}\" =\"9164e437-812b-4a07-8dfd-2fd73b39329b\",\"{036a55b4-5e72-4d05-a06c-cba2dfcc134a}\" =\"648fc678-a6fb-47cd-9792-fb9520678c17\",\"{446900e4-71c2-419f-a6a7-df9c091e268b}\" =\"f0b43422-070e-466e-85c9-6543f209f075\",\"jid1-MnnxcxisBPnSXQ@jetpack\" =\"4c448202-c843-4cae-b5c3-d11f2da58fa3\",\"soundfixer@unrelenting.technology\" =\"59b35eb8-1c85-4919-a905-80d120993ddc\",\"floccus@handmadeideas.org\" =\"8ad2956c-8091-41af-a689-7d2108f5958d\",\"{79b9dbcf-cc5a-4cda-89ef-c4ab097eb074}\" =\"c2a223a7-32e0-4726-9f20-17236702b1f5\",\"linkgopher@oooninja.com\" =\"a257858c-0dce-415b-b123-6222876cf843\"}";
};
};
}
}

View File

@@ -1,8 +1,12 @@
{ config, lib, ... }:
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.mako;
nord = import ../../desktop/theme/nord.nix;
cfg = config.${namespace}.programs.mako;
in
{
imports = [ ./options.nix ];
@@ -10,7 +14,7 @@ in
services.mako = {
enable = true;
settings = {
font = cfg.fontName;
font = mkDefault cfg.fontName;
icons = true;
ignore-timeout = true;
sort = "-time";
@@ -22,10 +26,10 @@ in
max-icon-size = 64;
default-timeout = 5000;
background-color = nord.polarNight.nord0;
text-color = nord.snowStorm.nord6;
border-color = nord.frost.nord10;
progress-color = "over ${nord.frost.nord8}";
# 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}";
};
};
};

View File

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

View File

@@ -1,23 +1,56 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.nwg-dock;
nord = import ../../desktop/theme/nord.nix;
cfg = config.${namespace}.programs.nwg-dock;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
home.packages = with pkgs; [ nwg-dock-hyprland ];
home.file = {
".config/nwg-dock-hyprland/drawer.css".text = ''
".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: ${nord.polarNight.nord0};
background: #36364f;
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${nord.aurora.nord15}b0
border-color: rgba(156, 142, 122, 0.7)
}
#box {
@@ -25,17 +58,17 @@ in
padding: 10px
}
active {
#active {
/* This is to underline the button representing the currently active window */
border-bottom: solid 1px;
border-color: ${nord.aurora.nord14}1a
border-color: rgba(255, 255, 255, 0.3)
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${nord.frost.nord10}
color: #999
}
button {
@@ -47,7 +80,52 @@ in
}
button:hover {
background-color: ${nord.polarNight.nord0}1a;
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};
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${config.lib.stylix.colors.base0E}b0
}
#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: ${config.lib.stylix.colors.base0B}1a
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${config.lib.stylix.colors.base0F}
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button:hover {
background-color: ${config.lib.stylix.colors.base00}1a;
border-radius: 2px;
}

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,12 @@
{ config, lib, ... }:
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.mjallen.programs.nwg-panel;
cfg = config.${namespace}.programs.nwg-panel;
in
{
imports = [ ./options.nix ];
@@ -12,15 +17,15 @@ in
'';
".config/nwg-panel/preferred-apps.json".text = ''
{
"\\.pdf$": "${cfg.defaultApps.browser.pname}",
"\\.svg$": "inkscape",
"\\.(jpg|png|tiff|gif)$": "${cfg.defaultApps.imageViewer.pname}",
"\\.(mp3|ogg|flac|wav|wma)$": "audacious",
"\\.(avi|mp4|mkv|mov|wav)$": "${cfg.defaultApps.video.pname}",
"\\.(doc|docx|xls|xlsx)$": "${cfg.defaultApps.office.pname}"
}
{
"\\.pdf$": "${cfg.defaultApps.browser.pname}",
"\\.svg$": "inkscape",
"\\.(jpg|png|tiff|gif)$": "${cfg.defaultApps.imageViewer.pname}",
"\\.(mp3|ogg|flac|wav|wma)$": "audacious",
"\\.(avi|mp4|mkv|mov|wav)$": "${cfg.defaultApps.video.pname}",
"\\.(doc|docx|xls|xlsx)$": "${cfg.defaultApps.office.pname}"
}
'';
};
};
}
}

View File

@@ -1,23 +1,52 @@
{ lib, pkgs, ... }:
{
lib,
pkgs,
namespace,
...
}:
with lib;
{
options.mjallen.programs.nwg-panel = {
options.${namespace}.programs.nwg-panel = {
enable = mkEnableOption "enable nwg-panel";
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.gnome-photos; };
browser = mkOption {
type = types.package;
default = pkgs.firefox;
};
editor = mkOption {
type = types.package;
default = pkgs.micro;
};
fileExplorer = mkOption {
type = types.package;
default = pkgs.nautilus;
};
visual = mkOption {
type = types.package;
default = pkgs.vscodium;
};
terminal = mkOption {
type = types.package;
default = pkgs.kitty;
};
office = mkOption {
type = types.package;
default = pkgs.onlyoffice-desktopeditors;
};
video = mkOption {
type = types.package;
default = pkgs.vlc;
};
imageViewer = mkOption {
type = types.package;
default = pkgs.gnome-photos;
};
};
};
description = "Default applications used across the system.";
};
};
}
}

View File

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

View File

@@ -0,0 +1,290 @@
{
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,32 +1,333 @@
{ lib, ... }:
{ lib, namespace, ... }:
with lib;
let
inherit (types)
str
int
bool
listOf
attrs
path
nullOr
submodule
;
in
{
options.mjallen.programs.waybar = {
enable = mkEnableOption "enable waybar";
options.${namespace}.programs.waybar = {
enable = mkEnableOption "Waybar status bar";
# Legacy/compat options (kept for backwards compatibility)
layer = mkOption {
type = types.str;
type = str;
default = "top";
};
modules-right = mkOption {
type = with types; listOf str;
default = [];
};
networkInterface = mkOption {
type = types.str;
default = "wlan0";
description = "Waybar layer (compat). Prefer layout + feature flags.";
};
extraModules = mkOption {
type = types.attrs;
type = attrs;
default = { };
description = "Extra settings bars at top-level (compat with older module).";
};
extraModulesStyle = mkOption {
type = types.str;
type = str;
default = "";
description = "Extra CSS appended (compat). Prefer extra.style.";
};
windowOffset = mkOption {
type = 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.";
};
};
}
}

View File

@@ -0,0 +1,40 @@
{
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

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

View File

@@ -0,0 +1,61 @@
{
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

@@ -0,0 +1,95 @@
{
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

@@ -1,20 +1,34 @@
{ config, lib, pkgs, ... }:
{
config,
lib,
pkgs,
namespace,
...
}:
let
cfg = config.mjallen.programs.waybar;
cfg = config.${namespace}.programs.waybar;
waybar-weather = pkgs.writeScriptBin "waybar-weather" ''
#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.requests
"""get waybar weather"""
import os
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",
@@ -66,6 +80,38 @@ 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": "",
@@ -93,18 +139,18 @@ let
WIND_DIRECTION = {
"S": "",
"SW": "",
"SSW": "",
"W": "",
"NW": "",
"NNW": "",
"N": "",
"NE": "",
"NNE": "",
"E": "",
"SE": "",
"SSE": "",
}
MOON_PHASES = (
"󰽤", "󰽧", "󰽡", "󰽨", "󰽢", "󰽦", "󰽣", "󰽥"
)
WEATHER_SYMBOL_WI_DAY = {
"Unknown": "",
"Cloudy": "",
@@ -181,117 +227,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()}
data = {}
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):
"""get the temp formatted"""
return (temp + "°").ljust(3)
return (str(temp) + "°").ljust(3)
def format_chances(hour):
"""get the chances formatted"""
chances = {
"chanceoffog": "Fog",
"chanceoffrost": "Frost",
@@ -302,60 +348,67 @@ let
"chanceofthunder": "Thunder",
"chanceofwindy": "Wind",
}
conditions = []
for chance, event in chances.items():
if int(hour[chance]) > 0:
conditions.append(event + " " + hour[chance] + "%")
if int(hour.get(chance, 0)) > 0:
conditions.append(event + " " + str(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(feels_like_f)
tempint = int(float(feels_like_f)) # float cast just in case
extrachar = ""
if 0 < tempint < 10:
extrachar = "+"
current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {feels_like_f}°F"
current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {int(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['moon_phase']
wego = WEATHER_CODES_WEGO[current_condition['weatherCode']]
moon_phase = astronomy.get('moon_phase', 'Unknown')
weather_code = current_condition['weatherCode']
if weather_code not in WEATHER_CODES_WEGO:
weather_code = "113"
tooltip = f"{wego[0]}{weather_description} {temp_f}°\n"
tooltip += f"{wego[1]}Feels like: {feels_like_f}°\n"
tooltip += f"{wego[2]}Wind: {wind_speed}mph {WIND_DIRECTION[wind_dir]}\n"
tooltip += f"{wego[3]}Humidity: {humidity}%\n"
tooltip += f"{wego[4]}Moon phase: {moon_phase} " + moon_icon + "\n"
wego = WEATHER_CODES_WEGO[weather_code]
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
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"
@@ -367,29 +420,34 @@ let
tooltip += build_hourly_forecast(i, day['hourly'], sunrise, sunset)
return tooltip
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
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])
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'])
current_weather_code = codes[hour['weatherCode']]
wcode = hour['weatherCode']
if wcode not in codes: wcode = "113" # Fallback
current_weather_code = codes[wcode]
feels_like = format_temp(hour['FeelsLikeF'])
weather_desc = hour['weatherDesc'][0]['value']
current_chances = format_chances(hour)
@@ -400,34 +458,188 @@ 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 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 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
current_condition = weather["current_condition"][0]
astronomy = weather["weather"][0]['astronomy'][0]
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
data["text"] = build_text(current_condition)
data["tooltip"] = build_tooltip(current_condition, astronomy, moon_icon)
data["tooltip"] += build_forecast(weather["weather"])
# --- OPEN-METEO INTEGRATION HELPER FUNCTIONS ---
return json.dumps(data)
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
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"
})
# 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)
def main():
"""main"""
try:
print(get_wttr_json())
except Exception as e:
print(e)
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()
'';
in
{

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