initial commit
This commit is contained in:
commit
90cff4f16a
59 changed files with 6855 additions and 0 deletions
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Nix build artifacts
|
||||||
|
result
|
||||||
|
result-*
|
||||||
|
|
||||||
|
# Secrets (never commit these)
|
||||||
|
secrets/
|
||||||
|
*.secret
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# Editor backups
|
||||||
|
*.backup
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Local overrides
|
||||||
|
local.nix
|
||||||
|
|
||||||
|
# Claude stuff
|
||||||
|
.claude/
|
||||||
|
|
||||||
|
# Quickshell generated theme files (generated by Nix)
|
||||||
|
Hyprland/Quickshell/bar/Theme.qml
|
||||||
|
Hyprland/Quickshell/control-center/Theme.qml
|
||||||
|
|
||||||
|
# nixos-hardware fork (now on GitHub)
|
||||||
|
nixos-hardware-fork/
|
||||||
|
|
||||||
|
# Hyprland wiki
|
||||||
|
hyprland-wiki/
|
||||||
|
|
||||||
|
/st/
|
||||||
|
|
||||||
|
/dwm/
|
||||||
409
Hetzner/axiomania.nix
Normal file
409
Hetzner/axiomania.nix
Normal file
|
|
@ -0,0 +1,409 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
|
||||||
|
networking.hostName = "axiomania";
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Firewall
|
||||||
|
# ============================================================================
|
||||||
|
networking.firewall = {
|
||||||
|
allowedTCPPorts = [ 22 80 443 2222 ];
|
||||||
|
allowedUDPPorts = [ 51820 53 ]; # Wireguard, Adguard DNS
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Forgejo
|
||||||
|
# ============================================================================
|
||||||
|
services.forgejo = {
|
||||||
|
enable = true;
|
||||||
|
database.type = "sqlite3";
|
||||||
|
settings = {
|
||||||
|
DEFAULT.APP_NAME = "Axiomania Git";
|
||||||
|
|
||||||
|
server = {
|
||||||
|
DOMAIN = "git.axiomania.org";
|
||||||
|
ROOT_URL = "https://git.axiomania.org/";
|
||||||
|
HTTP_ADDR = "127.0.0.1";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
SSH_DOMAIN = "git.axiomania.org";
|
||||||
|
SSH_PORT = 2222;
|
||||||
|
START_SSH_SERVER = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
service = {
|
||||||
|
DISABLE_REGISTRATION = true;
|
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
repository = {
|
||||||
|
DEFAULT_PRIVATE = "private";
|
||||||
|
};
|
||||||
|
|
||||||
|
api = {
|
||||||
|
ENABLE_SWAGGER = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
session = {
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
ENABLED = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Forgejo Actions Runner
|
||||||
|
# ============================================================================
|
||||||
|
# Requires a registration token from Forgejo.
|
||||||
|
# Generate one: ssh root@178.104.15.221, then:
|
||||||
|
# forgejo-runner register (follow prompts)
|
||||||
|
# Or via Forgejo web UI: Site Administration > Runners > Create Runner
|
||||||
|
# Then put the token in /var/lib/forgejo-runner/token
|
||||||
|
services.gitea-actions-runner.instances.default = {
|
||||||
|
enable = true;
|
||||||
|
name = "axiomania";
|
||||||
|
url = "https://git.axiomania.org";
|
||||||
|
tokenFile = "/var/lib/forgejo-runner/token";
|
||||||
|
labels = [ "native:host" ];
|
||||||
|
hostPackages = with pkgs; [
|
||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
curl
|
||||||
|
gawk
|
||||||
|
git
|
||||||
|
gnused
|
||||||
|
nodejs
|
||||||
|
nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Vaultwarden (Bitwarden-compatible password manager)
|
||||||
|
# ============================================================================
|
||||||
|
services.vaultwarden = {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
DOMAIN = "https://vault.axiomania.org";
|
||||||
|
SIGNUPS_ALLOWED = false;
|
||||||
|
ROCKET_ADDRESS = "127.0.0.1";
|
||||||
|
ROCKET_PORT = 8222;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Navidrome (music streaming)
|
||||||
|
# ============================================================================
|
||||||
|
services.navidrome = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
Address = "127.0.0.1";
|
||||||
|
Port = 4533;
|
||||||
|
MusicFolder = "/var/lib/navidrome/music";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Syncthing (file sync)
|
||||||
|
# ============================================================================
|
||||||
|
services.syncthing = {
|
||||||
|
enable = true;
|
||||||
|
openDefaultPorts = true;
|
||||||
|
dataDir = "/var/lib/syncthing";
|
||||||
|
settings.gui.insecureSkipHostcheck = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Attic (Nix binary cache)
|
||||||
|
# ============================================================================
|
||||||
|
# Requires a secret generated on the server:
|
||||||
|
# openssl genrsa -traditional 4096 | base64 -w0 > /var/lib/atticd/token-secret
|
||||||
|
# echo "ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=$(cat /var/lib/atticd/token-secret)" > /etc/atticd.env
|
||||||
|
services.atticd = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = "/etc/atticd.env";
|
||||||
|
settings = {
|
||||||
|
listen = "[::]:8080";
|
||||||
|
storage = {
|
||||||
|
type = "local";
|
||||||
|
path = "/var/lib/atticd/storage";
|
||||||
|
};
|
||||||
|
garbage-collection = {
|
||||||
|
default-retention-period = "3 months";
|
||||||
|
};
|
||||||
|
chunking = {
|
||||||
|
nar-size-threshold = 65536;
|
||||||
|
min-size = 16384;
|
||||||
|
avg-size = 65536;
|
||||||
|
max-size = 262144;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Kavita (ebook library)
|
||||||
|
# ============================================================================
|
||||||
|
# Generate token on the server:
|
||||||
|
# openssl rand -hex 128 > /var/lib/kavita/token-key
|
||||||
|
services.kavita = {
|
||||||
|
enable = true;
|
||||||
|
settings.Port = 5000;
|
||||||
|
tokenKeyFile = "/var/lib/kavita/token-key";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Audiobookshelf
|
||||||
|
# ============================================================================
|
||||||
|
services.audiobookshelf = {
|
||||||
|
enable = true;
|
||||||
|
port = 8234;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Paperless-ngx (document management)
|
||||||
|
# ============================================================================
|
||||||
|
services.paperless = {
|
||||||
|
enable = true;
|
||||||
|
port = 28981;
|
||||||
|
address = "127.0.0.1";
|
||||||
|
domain = "docs.axiomania.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Adguard Home (DNS ad blocker)
|
||||||
|
# ============================================================================
|
||||||
|
# Use as DNS server via Wireguard: set DNS = 10.100.0.1 in client config
|
||||||
|
services.adguardhome = {
|
||||||
|
enable = true;
|
||||||
|
port = 3300;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# SearXNG (private search engine)
|
||||||
|
# ============================================================================
|
||||||
|
# Generate secret on the server:
|
||||||
|
# echo "SEARX_SECRET=$(openssl rand -hex 32)" > /etc/searx/secrets.env
|
||||||
|
services.searx = {
|
||||||
|
enable = true;
|
||||||
|
redisCreateLocally = true;
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
bind_address = "127.0.0.1";
|
||||||
|
port = 8888;
|
||||||
|
secret_key = "$SEARX_SECRET";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environmentFile = "/etc/searx/secrets.env";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Homepage (services dashboard)
|
||||||
|
# ============================================================================
|
||||||
|
services.homepage-dashboard = {
|
||||||
|
enable = true;
|
||||||
|
listenPort = 8082;
|
||||||
|
allowedHosts = "home.axiomania.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Matrix Conduit (encrypted messaging)
|
||||||
|
# ============================================================================
|
||||||
|
services.matrix-conduit = {
|
||||||
|
enable = true;
|
||||||
|
settings.global = {
|
||||||
|
server_name = "axiomania.org";
|
||||||
|
port = 6167;
|
||||||
|
address = "127.0.0.1";
|
||||||
|
allow_registration = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Gokapi (file sharing) — disabled due to CVEs in stable
|
||||||
|
# ============================================================================
|
||||||
|
# services.gokapi = {
|
||||||
|
# enable = true;
|
||||||
|
# environment = {
|
||||||
|
# GOKAPI_PORT = 53842;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Wireguard VPN
|
||||||
|
# ============================================================================
|
||||||
|
# Generate keys on the server:
|
||||||
|
# wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key
|
||||||
|
networking.wireguard.interfaces.wg0 = {
|
||||||
|
ips = [ "10.100.0.1/24" ];
|
||||||
|
listenPort = 51820;
|
||||||
|
privateKeyFile = "/etc/wireguard/private.key";
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
# Minisforum V3 SE (local NixOS machine)
|
||||||
|
publicKey = "rEsHqzJVnv9AoOIEVTrdEF3x4G6rWxXqHLXTzAx88gc=";
|
||||||
|
allowedIPs = [ "10.100.0.2/32" ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Pixel 5
|
||||||
|
publicKey = "jP+rYdc8qKdNY4l3PDFmGiOA31SnJRgcmQIVu6AJ9EM=";
|
||||||
|
allowedIPs = [ "10.100.0.3/32" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# NAT for Wireguard clients to access the internet
|
||||||
|
networking.nat = {
|
||||||
|
enable = true;
|
||||||
|
externalInterface = "ens3";
|
||||||
|
internalInterfaces = [ "wg0" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Nginx reverse proxy + ACME
|
||||||
|
# ============================================================================
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
recommendedTlsSettings = true;
|
||||||
|
recommendedOptimisation = true;
|
||||||
|
recommendedGzipSettings = true;
|
||||||
|
|
||||||
|
# ── Public services ──
|
||||||
|
virtualHosts."git.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."matrix.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:6167";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."cache.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://[::1]:8080";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ── VPN-only services (WireGuard clients only) ──
|
||||||
|
virtualHosts."vault.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8222";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."music.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:4533";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."sync.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8384";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."books.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:5000";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."audio.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8234";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."docs.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:28981";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."search.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8888";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHosts."home.axiomania.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8082";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
extraConfig = "allow 10.100.0.0/24; allow 127.0.0.1; deny all;";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# virtualHosts."share.axiomania.org" = {
|
||||||
|
# enableACME = true;
|
||||||
|
# forceSSL = true;
|
||||||
|
# locations."/" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:53842";
|
||||||
|
# proxyWebsockets = true;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults.email = "gamma.kinematics@gmail.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Packages
|
||||||
|
# ============================================================================
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
vim
|
||||||
|
htop
|
||||||
|
wireguard-tools
|
||||||
|
];
|
||||||
|
}
|
||||||
26
Hetzner/builder.nix
Normal file
26
Hetzner/builder.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
|
||||||
|
networking.hostName = "builder";
|
||||||
|
|
||||||
|
nix.settings = {
|
||||||
|
max-jobs = "auto";
|
||||||
|
substituters = [
|
||||||
|
"https://cache.nixos.org"
|
||||||
|
"https://cache.axiomania.org/main"
|
||||||
|
];
|
||||||
|
trusted-public-keys = [
|
||||||
|
"main:Uz5F0MbXItVx2XCmBbEAMmQ0T6+DZDgLaXWalh1k++o="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
tmux
|
||||||
|
attic-client
|
||||||
|
vim
|
||||||
|
htop
|
||||||
|
];
|
||||||
|
}
|
||||||
34
Hetzner/common.nix
Normal file
34
Hetzner/common.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
./disk-config.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "25.11";
|
||||||
|
time.timeZone = "Europe/Berlin";
|
||||||
|
|
||||||
|
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||||
|
|
||||||
|
boot.loader.grub = {
|
||||||
|
enable = true;
|
||||||
|
efiSupport = true;
|
||||||
|
efiInstallAsRemovable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.qemuGuest.enable = true;
|
||||||
|
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA7XcPUNMwpUqXMqhwTlW3YV2BUj0I6efk0LxqFcyYgA gamma.kinematics@gmail.com"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
PermitRootLogin = "prohibit-password";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
34
Hetzner/disk-config.nix
Normal file
34
Hetzner/disk-config.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
disko.devices.disk.main = {
|
||||||
|
device = lib.mkDefault "/dev/sda";
|
||||||
|
type = "disk";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
boot = {
|
||||||
|
size = "1M";
|
||||||
|
type = "EF02"; # BIOS boot partition
|
||||||
|
};
|
||||||
|
esp = {
|
||||||
|
size = "512M";
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
mountOptions = [ "umask=0077" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
root = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
121
Hetzner/setup.nix
Normal file
121
Hetzner/setup.nix
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
sshKeyPath = "/home/lebowski/.ssh/id_ed25519";
|
||||||
|
sshKeyName = "V3";
|
||||||
|
serverName = "nix-builder";
|
||||||
|
serverType = "ccx43";
|
||||||
|
location = "nbg1";
|
||||||
|
|
||||||
|
sshCmd = "ssh -o StrictHostKeyChecking=no -o BatchMode=yes -i ${sshKeyPath}";
|
||||||
|
|
||||||
|
# Spin up a builder from the NixOS snapshot
|
||||||
|
builder-up = pkgs.writeShellApplication {
|
||||||
|
name = "builder-up";
|
||||||
|
runtimeInputs = with pkgs; [ hcloud openssh ];
|
||||||
|
text = ''
|
||||||
|
SERVER_NAME="${serverName}"
|
||||||
|
SSH_KEY_PATH="${sshKeyPath}"
|
||||||
|
|
||||||
|
# ── Check if server already exists ──
|
||||||
|
if hcloud server describe "$SERVER_NAME" &>/dev/null; then
|
||||||
|
IP=$(hcloud server ip "$SERVER_NAME")
|
||||||
|
echo "Server '$SERVER_NAME' already running at $IP"
|
||||||
|
echo " builder-ssh"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Find snapshot ──
|
||||||
|
SNAPSHOT_ID=$(hcloud image list --type snapshot --selector description="${snapshotDesc}" -o noheader -o columns=id 2>/dev/null | head -1)
|
||||||
|
if [ -z "$SNAPSHOT_ID" ]; then
|
||||||
|
# Fallback: search by description
|
||||||
|
SNAPSHOT_ID=$(hcloud image list --type snapshot -o noheader -o columns=id,description | grep "${snapshotDesc}" | awk '{print $1}' | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$SNAPSHOT_ID" ]; then
|
||||||
|
echo "ERROR: No snapshot '${snapshotDesc}' found."
|
||||||
|
echo " Create one with: builder-snapshot"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Create server from snapshot ──
|
||||||
|
echo "==> Creating ${serverType} in ${location} from snapshot $SNAPSHOT_ID..."
|
||||||
|
hcloud server create \
|
||||||
|
--name "$SERVER_NAME" \
|
||||||
|
--type "${serverType}" \
|
||||||
|
--image "$SNAPSHOT_ID" \
|
||||||
|
--location "${location}" \
|
||||||
|
--label role=nix-builder \
|
||||||
|
--ssh-key "${sshKeyName}"
|
||||||
|
|
||||||
|
IP=$(hcloud server ip "$SERVER_NAME")
|
||||||
|
|
||||||
|
# ── Wait for SSH ──
|
||||||
|
echo "==> Waiting for SSH..."
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if ${sshCmd} "root@''${IP}" true 2>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ "$i" -eq 30 ]; then
|
||||||
|
echo "ERROR: SSH did not become available after 150s"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── Update known_hosts ──
|
||||||
|
ssh-keygen -R "$IP" 2>/dev/null || true
|
||||||
|
ssh-keyscan -H "$IP" >> ~/.ssh/known_hosts 2>/dev/null
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Builder ready ==="
|
||||||
|
echo " builder-ssh"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SSH into the builder
|
||||||
|
builder-ssh = pkgs.writeShellApplication {
|
||||||
|
name = "builder-ssh";
|
||||||
|
runtimeInputs = with pkgs; [ hcloud openssh ];
|
||||||
|
text = ''
|
||||||
|
SERVER_NAME="${serverName}"
|
||||||
|
SSH_KEY_PATH="${sshKeyPath}"
|
||||||
|
|
||||||
|
if ! hcloud server describe "$SERVER_NAME" &>/dev/null; then
|
||||||
|
echo "No server '$SERVER_NAME' found. Run builder-up first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IP=$(hcloud server ip "$SERVER_NAME")
|
||||||
|
ssh -i "$SSH_KEY_PATH" -t "root@$IP" "tmux new-session -A -s build"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Tear down the builder
|
||||||
|
builder-down = pkgs.writeShellApplication {
|
||||||
|
name = "builder-down";
|
||||||
|
runtimeInputs = with pkgs; [ hcloud openssh ];
|
||||||
|
text = ''
|
||||||
|
SERVER_NAME="${serverName}"
|
||||||
|
|
||||||
|
if hcloud server describe "$SERVER_NAME" &>/dev/null; then
|
||||||
|
IP=$(hcloud server ip "$SERVER_NAME")
|
||||||
|
echo "==> Deleting '$SERVER_NAME' ($IP)..."
|
||||||
|
hcloud server delete "$SERVER_NAME"
|
||||||
|
ssh-keygen -R "$IP" 2>/dev/null || true
|
||||||
|
echo " Done."
|
||||||
|
else
|
||||||
|
echo "No server '$SERVER_NAME' found."
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.systemPackages = [
|
||||||
|
builder-up
|
||||||
|
builder-ssh
|
||||||
|
builder-down
|
||||||
|
pkgs.hcloud
|
||||||
|
];
|
||||||
|
}
|
||||||
41
Hyprsuck/home.nix
Normal file
41
Hyprsuck/home.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Hyprsuck home-manager configuration
|
||||||
|
# Unstable extras and autostart
|
||||||
|
{ pkgs-unstable, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hyprland/hyprland.nix
|
||||||
|
./waybar.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# Screenshot annotation tool
|
||||||
|
programs.swappy = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-unstable.swappy;
|
||||||
|
settings.Default = {
|
||||||
|
save_dir = "$HOME/Pictures/Screenshots";
|
||||||
|
save_filename_format = "%F_%T.png";
|
||||||
|
early_exit = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Clipboard history manager
|
||||||
|
services.cliphist = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-unstable.cliphist;
|
||||||
|
allowImages = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Terminal emulator (Wayland-native)
|
||||||
|
programs.foot = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-unstable.foot;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Auto-start Hyprland on tty1
|
||||||
|
programs.bash.profileExtra = ''
|
||||||
|
if [ -z "$WAYLAND_DISPLAY" ] && [ "$XDG_VTNR" = 1 ]; then
|
||||||
|
exec Hyprland
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
152
Hyprsuck/hyprland/bindings.nix
Normal file
152
Hyprsuck/hyprland/bindings.nix
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
# Hyprland keybindings configuration
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
# Variables
|
||||||
|
"$mod" = "SUPER";
|
||||||
|
"$terminal" = "foot";
|
||||||
|
"$browser" = "zen";
|
||||||
|
|
||||||
|
# Keybindings
|
||||||
|
bind = [
|
||||||
|
# Rofi
|
||||||
|
"$mod, Space, exec, rofi -show system:rofi-system"
|
||||||
|
"$mod ALT, Space, exec, rofi-websearch"
|
||||||
|
|
||||||
|
# Foot terminal - go to workspace 50, launch if not running
|
||||||
|
"$mod, A, exec, hyprctl dispatch workspace 50; hyprctl clients -j | grep -q foot || $terminal"
|
||||||
|
|
||||||
|
# Zed - go to workspace 60, launch if not running
|
||||||
|
"$mod, Z, exec, hyprctl dispatch workspace 60; hyprctl clients -j | grep -q dev.zed.Zed || zeditor"
|
||||||
|
|
||||||
|
# Zen Browser - workspace 70 (DP-3), launch if no browser on that workspace
|
||||||
|
"$mod, B, exec, hyprctl dispatch workspace 70; hyprctl clients -j | jq -e '.[] | select(.class == \"zen-twilight\" and .workspace.id == 70)' > /dev/null || hyprctl dispatch exec [workspace 70 silent] -- $browser"
|
||||||
|
# Zen Browser - workspace 71 (eDP-1), launch new window if no browser on that workspace
|
||||||
|
"$mod ALT, B, exec, hyprctl dispatch workspace 71; hyprctl clients -j | jq -e '.[] | select(.class == \"zen-twilight\" and .workspace.id == 71)' > /dev/null || hyprctl dispatch exec [workspace 71 silent] -- $browser --new-window"
|
||||||
|
|
||||||
|
# Nautilus - go to workspace 80, launch if not running
|
||||||
|
"$mod, N, exec, hyprctl dispatch workspace 80; hyprctl clients -j | grep -q org.gnome.Nautilus || nautilus"
|
||||||
|
|
||||||
|
# Haruna - go to workspace 90
|
||||||
|
"$mod, M, workspace, 90"
|
||||||
|
|
||||||
|
"$mod, Escape, exec, hyprlock"
|
||||||
|
|
||||||
|
# Switch to KiCad workspaces (both monitors)
|
||||||
|
"$mod, K, workspace, 101"
|
||||||
|
"$mod, K, workspace, 102"
|
||||||
|
# Launch KiCad project selector
|
||||||
|
"$mod CTRL, K, exec, kicad-projects"
|
||||||
|
# Launch library editors
|
||||||
|
"$mod, L, exec, kicad-lib-launch"
|
||||||
|
# Show project manager
|
||||||
|
"$mod SHIFT, K, togglespecialworkspace, kicad-pm"
|
||||||
|
# Swap SCH/PCB positions
|
||||||
|
"$mod ALT, K, exec, kicad-swap"
|
||||||
|
# Cycle through project instances
|
||||||
|
"$mod, bracketright, exec, kicad-cycle f"
|
||||||
|
"$mod, bracketleft, exec, kicad-cycle b"
|
||||||
|
|
||||||
|
# FreeCAD - go to workspace 110, launch if not running
|
||||||
|
"$mod, F, exec, hyprctl dispatch workspace 110; hyprctl clients -j | grep -q org.freecad.FreeCAD || env QT_QPA_PLATFORM=xcb FreeCAD --single-instance"
|
||||||
|
|
||||||
|
# Window management
|
||||||
|
"$mod, Q, killactive"
|
||||||
|
"$mod, W, fullscreen"
|
||||||
|
"$mod, R, togglefloating"
|
||||||
|
"$mod, P, pseudo"
|
||||||
|
"$mod, E, togglesplit"
|
||||||
|
|
||||||
|
# Focus movement
|
||||||
|
"$mod, left, movefocus, l"
|
||||||
|
"$mod, right, movefocus, r"
|
||||||
|
"$mod, up, movefocus, u"
|
||||||
|
"$mod, down, movefocus, d"
|
||||||
|
|
||||||
|
# Workspace switching
|
||||||
|
"$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"
|
||||||
|
|
||||||
|
# Move window to workspace
|
||||||
|
"$mod SHIFT, 1, movetoworkspace, 1"
|
||||||
|
"$mod SHIFT, 2, movetoworkspace, 2"
|
||||||
|
"$mod SHIFT, 3, movetoworkspace, 3"
|
||||||
|
"$mod SHIFT, 4, movetoworkspace, 4"
|
||||||
|
"$mod SHIFT, 5, movetoworkspace, 5"
|
||||||
|
"$mod SHIFT, 6, movetoworkspace, 6"
|
||||||
|
"$mod SHIFT, 7, movetoworkspace, 7"
|
||||||
|
"$mod SHIFT, 8, movetoworkspace, 8"
|
||||||
|
"$mod SHIFT, 9, movetoworkspace, 9"
|
||||||
|
"$mod SHIFT, 0, movetoworkspace, 10"
|
||||||
|
|
||||||
|
# Special workspace (scratchpad)
|
||||||
|
"$mod, S, togglespecialworkspace, magic"
|
||||||
|
"$mod SHIFT, S, movetoworkspace, special:magic"
|
||||||
|
|
||||||
|
# Exit Hyprland
|
||||||
|
"$mod SHIFT, E, exit"
|
||||||
|
|
||||||
|
# Scroll through workspaces on current monitor (vertical model)
|
||||||
|
"$mod, mouse_down, workspace, m-1"
|
||||||
|
"$mod, mouse_up, workspace, m+1"
|
||||||
|
|
||||||
|
# Keyboard workspace navigation (up/down)
|
||||||
|
"$mod CTRL, up, workspace, m-1"
|
||||||
|
"$mod CTRL, down, workspace, m+1"
|
||||||
|
"$mod CTRL SHIFT, up, movetoworkspace, m-1"
|
||||||
|
"$mod CTRL SHIFT, down, movetoworkspace, m+1"
|
||||||
|
|
||||||
|
# Clipboard history (SUPER+SHIFT+V)
|
||||||
|
"$mod SHIFT, V, exec, cliphist list | rofi -dmenu -p 'Clipboard' | cliphist decode | wl-copy"
|
||||||
|
|
||||||
|
# Screenshot bindings (saves to ~/Pictures/Screenshots/)
|
||||||
|
", Print, exec, mkdir -p ~/Pictures/Screenshots && grimblast --notify copysave area ~/Pictures/Screenshots/$(date +%F_%T).png"
|
||||||
|
"SHIFT, Print, exec, mkdir -p ~/Pictures/Screenshots && grimblast --notify copysave output ~/Pictures/Screenshots/$(date +%F_%T).png"
|
||||||
|
"CTRL, Print, exec, grimblast --notify save area - | swappy -f -"
|
||||||
|
|
||||||
|
# System menu (rofi)
|
||||||
|
"$mod, X, exec, rofi -show system -modes 'system:rofi-system'"
|
||||||
|
|
||||||
|
# On-screen keyboard toggle (for tablet mode)
|
||||||
|
# "$mod, K, exec, pkill wvkbd-mobintl || wvkbd-mobintl"
|
||||||
|
|
||||||
|
# Refresh waybar (for dock/undock)
|
||||||
|
"$mod CTRL, Space, exec, pkill waybar; waybar-start"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Mouse bindings
|
||||||
|
bindm = [
|
||||||
|
"$mod, mouse:272, movewindow"
|
||||||
|
"$mod, mouse:273, resizewindow"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Repeat bindings (hold key for continuous action)
|
||||||
|
binde = [
|
||||||
|
"$mod ALT, left, resizeactive, -20 0"
|
||||||
|
"$mod ALT, right, resizeactive, 20 0"
|
||||||
|
"$mod ALT, up, resizeactive, 0 -20"
|
||||||
|
"$mod ALT, down, resizeactive, 0 20"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Media/hardware key bindings (bindl = works even when locked)
|
||||||
|
bindl = [
|
||||||
|
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
|
||||||
|
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Volume keys with repeat (binde = repeat when held)
|
||||||
|
bindel = [
|
||||||
|
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+"
|
||||||
|
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
41
Hyprsuck/hyprland/hypridle.nix
Normal file
41
Hyprsuck/hyprland/hypridle.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Hypridle - Idle daemon configuration
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.hypridle = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hypridle;
|
||||||
|
settings = {
|
||||||
|
general = {
|
||||||
|
lock_cmd = "pidof hyprlock || hyprlock";
|
||||||
|
before_sleep_cmd = "loginctl lock-session";
|
||||||
|
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||||
|
};
|
||||||
|
|
||||||
|
listener = [
|
||||||
|
# Dim screen after 2.5 minutes
|
||||||
|
{
|
||||||
|
timeout = 150;
|
||||||
|
on-timeout = "brightnessctl -s set 10";
|
||||||
|
on-resume = "brightnessctl -r";
|
||||||
|
}
|
||||||
|
# Lock after 5 minutes
|
||||||
|
{
|
||||||
|
timeout = 300;
|
||||||
|
on-timeout = "loginctl lock-session";
|
||||||
|
}
|
||||||
|
# Screen off after 5.5 minutes
|
||||||
|
{
|
||||||
|
timeout = 330;
|
||||||
|
on-timeout = "hyprctl dispatch dpms off";
|
||||||
|
on-resume = "hyprctl dispatch dpms on";
|
||||||
|
}
|
||||||
|
# Suspend after 30 minutes
|
||||||
|
{
|
||||||
|
timeout = 1800;
|
||||||
|
on-timeout = "systemctl suspend";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
54
Hyprsuck/hyprland/hyprland.nix
Normal file
54
Hyprsuck/hyprland/hyprland.nix
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Hyprland ecosystem configuration (stable packages)
|
||||||
|
# Core hyprland WM and hypr* tools only
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./bindings.nix
|
||||||
|
./settings.nix
|
||||||
|
./monitors.nix
|
||||||
|
./rules.nix
|
||||||
|
./hyprlock.nix
|
||||||
|
./hypridle.nix
|
||||||
|
./hyprpaper.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Hyprland Window Manager (home-manager config)
|
||||||
|
# ============================================================================
|
||||||
|
# Package/portal set at NixOS level in hyprsuck.nix
|
||||||
|
wayland.windowManager.hyprland = {
|
||||||
|
enable = true;
|
||||||
|
systemd.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Hyprland ecosystem packages (stable)
|
||||||
|
# ============================================================================
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
# Tablet mode
|
||||||
|
iio-hyprland
|
||||||
|
|
||||||
|
# Monitor hotplug
|
||||||
|
hyprland-monitor-attached
|
||||||
|
];
|
||||||
|
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
exec-once = [
|
||||||
|
"iio-hyprland"
|
||||||
|
"hyprland-monitor-attached"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Polkit authentication agent
|
||||||
|
services.hyprpolkitagent = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hyprpolkitagent;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Blue light filter
|
||||||
|
services.hyprsunset = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hyprsunset;
|
||||||
|
};
|
||||||
|
}
|
||||||
39
Hyprsuck/hyprland/hyprlock.nix
Normal file
39
Hyprsuck/hyprland/hyprlock.nix
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Hyprlock - Screen locker configuration
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Disable Stylix's hyprlock theming (we use screenshot blur)
|
||||||
|
stylix.targets.hyprlock.enable = false;
|
||||||
|
|
||||||
|
programs.hyprlock = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hyprlock;
|
||||||
|
settings = {
|
||||||
|
general = {
|
||||||
|
hide_cursor = true;
|
||||||
|
grace = 5; # seconds before lock takes effect
|
||||||
|
};
|
||||||
|
|
||||||
|
background = [
|
||||||
|
{
|
||||||
|
path = "screenshot";
|
||||||
|
blur_passes = 3;
|
||||||
|
blur_size = 8;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
input-field = [
|
||||||
|
{
|
||||||
|
size = "200, 50";
|
||||||
|
position = "0, -80";
|
||||||
|
monitor = "";
|
||||||
|
dots_center = true;
|
||||||
|
fade_on_empty = false;
|
||||||
|
outline_thickness = 2;
|
||||||
|
placeholder_text = "Password...";
|
||||||
|
shadow_passes = 2;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
22
Hyprsuck/hyprland/hyprpaper.nix
Normal file
22
Hyprsuck/hyprland/hyprpaper.nix
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Hyprpaper - Wallpaper manager configuration
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
flakeDir = "${config.home.homeDirectory}/NixOS";
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
services.hyprpaper = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hyprpaper;
|
||||||
|
settings = {
|
||||||
|
ipc = "on";
|
||||||
|
splash = false;
|
||||||
|
|
||||||
|
# Change the wallpaper filename here
|
||||||
|
preload = [ "${flakeDir}/Wallpapers/Shift.png" ];
|
||||||
|
wallpaper = [ ", ${flakeDir}/Wallpapers/Shift.png" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
15
Hyprsuck/hyprland/monitors.nix
Normal file
15
Hyprsuck/hyprland/monitors.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Hyprland monitor configuration
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
# Monitor configuration
|
||||||
|
# eDP-1: Laptop display in portrait mode (rotated 270deg)
|
||||||
|
# DP-3: External monitor in landscape, positioned to the right
|
||||||
|
monitor = [
|
||||||
|
"eDP-1, 1920x1200@60, 0x0, 1.25, transform, 3"
|
||||||
|
"DP-3, 1920x1080@100, 960x-250, 1"
|
||||||
|
", preferred, auto, 1" # Fallback for any other monitor
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
59
Hyprsuck/hyprland/rules.nix
Normal file
59
Hyprsuck/hyprland/rules.nix
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
# Hyprland window rules and workspace configuration
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
# Window rules (old syntax for Hyprland 0.52.1)
|
||||||
|
windowrule = [
|
||||||
|
"float, class:^(pavucontrol)$"
|
||||||
|
"float, class:^(org.keepassxc.KeePassXC)$"
|
||||||
|
"float, title:^(Picture-in-Picture)$"
|
||||||
|
"pin, title:^(Picture-in-Picture)$"
|
||||||
|
|
||||||
|
# Foot terminal → workspace 50 (DP-3)
|
||||||
|
"workspace 50 silent, class:^(foot)$"
|
||||||
|
|
||||||
|
# Zed → workspace 60 (DP-3)
|
||||||
|
"workspace 60 silent, class:^(dev.zed.Zed)$"
|
||||||
|
|
||||||
|
# FreeCAD → workspace 110 (DP-3)
|
||||||
|
"workspace 110 silent, class:^(org.freecad.FreeCAD)$"
|
||||||
|
|
||||||
|
# Nautilus → workspace 80 (eDP-1)
|
||||||
|
"workspace 80 silent, class:^(org.gnome.Nautilus)$"
|
||||||
|
|
||||||
|
# Haruna → workspace 104, tabbed/grouped
|
||||||
|
"workspace 90 silent, class:^(org.kde.haruna)$"
|
||||||
|
"group set, class:^(org.kde.haruna)$"
|
||||||
|
|
||||||
|
# Schematic/Symbol Editor → workspace 102 (eDP-1), maximized, grouped
|
||||||
|
"workspace 102 silent, class:^(KiCad|kicad)$, title:.*Schematic Editor.*"
|
||||||
|
"maximize, class:^(KiCad|kicad)$, title:.*Schematic Editor.*"
|
||||||
|
"group set, class:^(KiCad|kicad)$, title:.*Schematic Editor.*"
|
||||||
|
"workspace 102 silent, class:^(KiCad|kicad)$, title:.*Symbol Editor.*"
|
||||||
|
"maximize, class:^(KiCad|kicad)$, title:.*Symbol Editor.*"
|
||||||
|
"group set, class:^(KiCad|kicad)$, title:.*Symbol Editor.*"
|
||||||
|
|
||||||
|
# PCB/Footprint Editor → workspace 101 (DP-3), maximized, grouped
|
||||||
|
"workspace 101 silent, class:^(KiCad|kicad)$, title:.*PCB Editor.*"
|
||||||
|
"maximize, class:^(KiCad|kicad)$, title:.*PCB Editor.*"
|
||||||
|
"group set, class:^(KiCad|kicad)$, title:.*PCB Editor.*"
|
||||||
|
"workspace 101 silent, class:^(KiCad|kicad)$, title:.*Footprint Editor.*"
|
||||||
|
"maximize, class:^(KiCad|kicad)$, title:.*Footprint Editor.*"
|
||||||
|
"group set, class:^(KiCad|kicad)$, title:.*Footprint Editor.*"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Workspace rules
|
||||||
|
workspace = [
|
||||||
|
"50, monitor:eDP-1, defaultName:terminal"
|
||||||
|
"60, monitor:DP-3, defaultName:code"
|
||||||
|
"70, monitor:DP-3, defaultName:browser"
|
||||||
|
"71, monitor:eDP-1, defaultName:browser"
|
||||||
|
"80, monitor:eDP-1, defaultName:files"
|
||||||
|
"90, monitor:DP-3, defaultName:video"
|
||||||
|
"101, monitor:DP-3, defaultName:kicad_prim"
|
||||||
|
"102, monitor:eDP-1, defaultName:kicad_sec"
|
||||||
|
"110, monitor:DP-3, defaultName:freecad"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
81
Hyprsuck/hyprland/settings.nix
Normal file
81
Hyprsuck/hyprland/settings.nix
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Hyprland general settings
|
||||||
|
# Input, appearance, layout, gestures, misc
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
# Input configuration
|
||||||
|
input = {
|
||||||
|
kb_layout = "us";
|
||||||
|
numlock_by_default = true;
|
||||||
|
|
||||||
|
follow_mouse = 1;
|
||||||
|
sensitivity = 0;
|
||||||
|
|
||||||
|
touchpad = {
|
||||||
|
natural_scroll = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# General settings
|
||||||
|
general = {
|
||||||
|
gaps_in = 5;
|
||||||
|
gaps_out = 5;
|
||||||
|
border_size = 2;
|
||||||
|
layout = "dwindle";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Decoration
|
||||||
|
decoration = {
|
||||||
|
rounding = 10;
|
||||||
|
# blur = {
|
||||||
|
# enabled = true;
|
||||||
|
# size = 3;
|
||||||
|
# passes = 1;
|
||||||
|
# };
|
||||||
|
# shadow = {
|
||||||
|
# enabled = true;
|
||||||
|
# range = 4;
|
||||||
|
# render_power = 3;
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
# Animations
|
||||||
|
animations = {
|
||||||
|
enabled = true;
|
||||||
|
# bezier = "myBezier, 0.05, 0.9, 0.1, 1.05";
|
||||||
|
animation = [
|
||||||
|
# "windows, 1, 7, myBezier"
|
||||||
|
# "windowsOut, 1, 7, default, popin 80%"
|
||||||
|
# "border, 1, 10, default"
|
||||||
|
# "fade, 1, 7, default"
|
||||||
|
"workspaces, 1, 4, default, slidevert"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Layout settings
|
||||||
|
dwindle = {
|
||||||
|
pseudotile = true;
|
||||||
|
preserve_split = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Gestures (Hyprland 0.51+ new syntax)
|
||||||
|
gestures = {
|
||||||
|
workspace_swipe_distance = 500;
|
||||||
|
workspace_swipe_invert = false;
|
||||||
|
workspace_swipe_create_new = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# New gesture bindings (replaces workspace_swipe)
|
||||||
|
# Vertical 3-finger swipe for workspace switching
|
||||||
|
gesture = [
|
||||||
|
"3, vertical, workspace"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
misc = {
|
||||||
|
force_default_wallpaper = 0;
|
||||||
|
disable_hyprland_logo = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
23
Hyprsuck/hyprsuck.nix
Normal file
23
Hyprsuck/hyprsuck.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Hyprsuck configuration entry point
|
||||||
|
# Wayland compositor setup with Hyprland
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# ============================================================================
|
||||||
|
# Hyprland - NixOS level config
|
||||||
|
# ============================================================================
|
||||||
|
programs.hyprland = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.hyprland;
|
||||||
|
portalPackage = pkgs.xdg-desktop-portal-hyprland;
|
||||||
|
xwayland.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
# Screenshot tool for Hyprland
|
||||||
|
grimblast
|
||||||
|
|
||||||
|
# Tablet mode
|
||||||
|
wvkbd
|
||||||
|
];
|
||||||
|
}
|
||||||
219
Hyprsuck/waybar.nix
Normal file
219
Hyprsuck/waybar.nix
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
# Waybar - Dynamic config based on connected monitors
|
||||||
|
# Docked (DP-3): external gets workspaces+clock, internal gets workspaces
|
||||||
|
# Undocked: internal gets workspaces+clock
|
||||||
|
{ pkgs-unstable, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
workspaceIcons = {
|
||||||
|
"terminal" = "";
|
||||||
|
"code" = "";
|
||||||
|
"browser" = "";
|
||||||
|
"files" = "";
|
||||||
|
"video" = "";
|
||||||
|
"kicad_prim" = "";
|
||||||
|
"kicad_sec" = "";
|
||||||
|
"freecad" = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
sharedStyle = ''
|
||||||
|
* {
|
||||||
|
font-family: "JetBrainsMono Nerd Font Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
window#waybar {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modules-left,
|
||||||
|
.modules-center,
|
||||||
|
.modules-right {
|
||||||
|
background: alpha(@theme_bg_color, 0.8);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
window#waybar.right .modules-center {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
window#waybar.left .modules-center {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modules-center #workspaces button,
|
||||||
|
.modules-left #workspaces button,
|
||||||
|
.modules-right #workspaces button {
|
||||||
|
padding: 1px 2px;
|
||||||
|
min-width: 14px;
|
||||||
|
min-height: 12px;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-bottom: none;
|
||||||
|
box-shadow: none;
|
||||||
|
text-shadow: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modules-center #workspaces button label,
|
||||||
|
.modules-left #workspaces button label,
|
||||||
|
.modules-right #workspaces button label {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modules-center #workspaces button.active,
|
||||||
|
.modules-left #workspaces button.active,
|
||||||
|
.modules-right #workspaces button.active {
|
||||||
|
color: @base0D;
|
||||||
|
border-bottom: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modules-center #workspaces button.active label,
|
||||||
|
.modules-left #workspaces button.active label,
|
||||||
|
.modules-right #workspaces button.active label {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#clock {
|
||||||
|
padding: 0px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# JSON config for docked mode (DP-3 primary)
|
||||||
|
dockedConfig = builtins.toJSON [
|
||||||
|
# DP-3: workspaces on right
|
||||||
|
{
|
||||||
|
name = "dp3-workspaces";
|
||||||
|
output = "DP-3";
|
||||||
|
layer = "top";
|
||||||
|
exclusive = false;
|
||||||
|
passthrough = true;
|
||||||
|
position = "right";
|
||||||
|
margin-right = 0;
|
||||||
|
modules-center = [ "hyprland/workspaces" ];
|
||||||
|
"hyprland/workspaces" = {
|
||||||
|
format = "{icon}";
|
||||||
|
format-icons = workspaceIcons;
|
||||||
|
show-special = false;
|
||||||
|
persistent-workspaces = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# DP-3: clock on left
|
||||||
|
{
|
||||||
|
name = "dp3-clock";
|
||||||
|
output = "DP-3";
|
||||||
|
layer = "top";
|
||||||
|
exclusive = false;
|
||||||
|
passthrough = true;
|
||||||
|
position = "left";
|
||||||
|
margin-left = 0;
|
||||||
|
modules-center = [ "clock" ];
|
||||||
|
clock = {
|
||||||
|
format = "{:%H\n%M}";
|
||||||
|
tooltip-format = "{:%A, %B %d, %Y}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# eDP-1: workspaces on left (secondary)
|
||||||
|
{
|
||||||
|
name = "edp1-workspaces";
|
||||||
|
output = "eDP-1";
|
||||||
|
layer = "top";
|
||||||
|
exclusive = false;
|
||||||
|
passthrough = true;
|
||||||
|
position = "left";
|
||||||
|
margin-left = 0;
|
||||||
|
modules-center = [ "hyprland/workspaces" ];
|
||||||
|
"hyprland/workspaces" = {
|
||||||
|
format = "{icon}";
|
||||||
|
format-icons = workspaceIcons;
|
||||||
|
show-special = false;
|
||||||
|
persistent-workspaces = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# JSON config for undocked mode (eDP-1 only)
|
||||||
|
undockedConfig = builtins.toJSON [
|
||||||
|
# eDP-1: workspaces on right
|
||||||
|
{
|
||||||
|
name = "edp1-workspaces";
|
||||||
|
output = "eDP-1";
|
||||||
|
layer = "top";
|
||||||
|
exclusive = false;
|
||||||
|
passthrough = true;
|
||||||
|
position = "right";
|
||||||
|
margin-right = 0;
|
||||||
|
modules-center = [ "hyprland/workspaces" ];
|
||||||
|
"hyprland/workspaces" = {
|
||||||
|
format = "{icon}";
|
||||||
|
format-icons = workspaceIcons;
|
||||||
|
show-special = false;
|
||||||
|
persistent-workspaces = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# eDP-1: clock on left
|
||||||
|
{
|
||||||
|
name = "edp1-clock";
|
||||||
|
output = "eDP-1";
|
||||||
|
layer = "top";
|
||||||
|
exclusive = false;
|
||||||
|
passthrough = true;
|
||||||
|
position = "left";
|
||||||
|
margin-left = 0;
|
||||||
|
modules-center = [ "clock" ];
|
||||||
|
clock = {
|
||||||
|
format = "{:%H\n%M}";
|
||||||
|
tooltip-format = "{:%A, %B %d, %Y}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Simple startup script - check for DP-3 and load appropriate config
|
||||||
|
startupScript = ''
|
||||||
|
sleep 1
|
||||||
|
CONFIG_DIR="$HOME/.config/waybar"
|
||||||
|
|
||||||
|
if hyprctl monitors -j | grep -q '"name": "DP-3"'; then
|
||||||
|
waybar -c "$CONFIG_DIR/config-docked.jsonc" &
|
||||||
|
else
|
||||||
|
waybar -c "$CONFIG_DIR/config-undocked.jsonc" &
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Waybar - disable systemd, we manage startup ourselves
|
||||||
|
programs.waybar = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-unstable.waybar;
|
||||||
|
systemd.enable = false;
|
||||||
|
style = sharedStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Write config files (style via programs.waybar.style to avoid conflict)
|
||||||
|
home.file.".config/waybar/config-docked.jsonc".text = dockedConfig;
|
||||||
|
home.file.".config/waybar/config-undocked.jsonc".text = undockedConfig;
|
||||||
|
|
||||||
|
# Waybar startup script
|
||||||
|
home.packages = [
|
||||||
|
(pkgs.writeShellScriptBin "waybar-start" startupScript)
|
||||||
|
];
|
||||||
|
|
||||||
|
# Start waybar
|
||||||
|
wayland.windowManager.hyprland.settings.exec-once = [
|
||||||
|
"waybar-start"
|
||||||
|
];
|
||||||
|
}
|
||||||
44
KiCad/Scripts/kicad-cycle.sh
Normal file
44
KiCad/Scripts/kicad-cycle.sh
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Cycle through KiCad windows/projects
|
||||||
|
# Usage: kicad-cycle [f|b] (forward/backward, default: f)
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
DIRECTION="${1:-f}"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
# Hyprland: Cycle through groups on both workspaces
|
||||||
|
hyprctl dispatch workspace 101
|
||||||
|
hyprctl dispatch changegroupactive "$DIRECTION"
|
||||||
|
hyprctl dispatch workspace 102
|
||||||
|
hyprctl dispatch changegroupactive "$DIRECTION"
|
||||||
|
else
|
||||||
|
# Ensure we're on kicad tag on both monitors first
|
||||||
|
kicad-show
|
||||||
|
|
||||||
|
# Determine focus direction
|
||||||
|
FOCUS_CMD="focus-next"
|
||||||
|
[[ "$DIRECTION" == "b" ]] && FOCUS_CMD="focus-prev"
|
||||||
|
|
||||||
|
if [[ $(autorandr --detected) != "mobile" ]]; then
|
||||||
|
# Multi-monitor: cycle on both monitors
|
||||||
|
echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "$FOCUS_CMD" > /tmp/dwm.fifo
|
||||||
|
echo "mon-sec" > /tmp/dwm.fifo
|
||||||
|
echo "$FOCUS_CMD" > /tmp/dwm.fifo
|
||||||
|
else
|
||||||
|
# Single monitor: just cycle windows
|
||||||
|
echo "$FOCUS_CMD" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
103
KiCad/Scripts/kicad-launch.sh
Normal file
103
KiCad/Scripts/kicad-launch.sh
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Launch KiCad with managed window layout
|
||||||
|
# Usage: kicad-launch <project.kicad_pro>
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main
|
||||||
|
# ==============================================================================
|
||||||
|
PROJECT="${1:-}"
|
||||||
|
if [[ -z "$PROJECT" ]]; then
|
||||||
|
echo "Usage: kicad-launch <project.kicad_pro>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PROJECT_NAME=$(basename "$PROJECT" .kicad_pro)
|
||||||
|
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
# Hyprland: Use special workspace for PM
|
||||||
|
hyprctl dispatch workspace 102
|
||||||
|
hyprctl dispatch togglespecialworkspace kicad-pm
|
||||||
|
hyprctl dispatch exec "[workspace special:kicad-pm silent]" -- env GDK_BACKEND=x11 kicad "$PROJECT"
|
||||||
|
|
||||||
|
# Wait for project manager window
|
||||||
|
PM_ADDR=""
|
||||||
|
for i in {1..50}; do
|
||||||
|
PM_ADDR=$(hyprctl clients -j | jq -r --arg name "$PROJECT_NAME" \
|
||||||
|
'.[] | select(.class == "KiCad" and (.title | test($name))) | .address' 2>/dev/null | head -1)
|
||||||
|
[[ -n "$PM_ADDR" ]] && break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$PM_ADDR" ]]; then
|
||||||
|
hyprctl dispatch togglespecialworkspace kicad-pm
|
||||||
|
echo "Failed to find KiCad project manager window"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Focus PM and open PCB editor
|
||||||
|
hyprctl dispatch focuswindow "address:$PM_ADDR"
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+p
|
||||||
|
sleep 0.25
|
||||||
|
|
||||||
|
# Hide special workspace
|
||||||
|
hyprctl dispatch togglespecialworkspace kicad-pm
|
||||||
|
|
||||||
|
# Focus PCB editor and open schematic
|
||||||
|
sleep 2
|
||||||
|
hyprctl dispatch workspace 101
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+e
|
||||||
|
sleep 0.25
|
||||||
|
|
||||||
|
# Switch to KiCad workspaces
|
||||||
|
hyprctl dispatch workspace 101
|
||||||
|
hyprctl dispatch workspace 102
|
||||||
|
|
||||||
|
else
|
||||||
|
# dwm: Launch KiCad, window rules handle placement
|
||||||
|
# Tag 16 = kicad-pm, Tag 17 = kicad (sch/pcb), Tag 18 = kicad-aux (mobile)
|
||||||
|
|
||||||
|
# Detect profile
|
||||||
|
PROFILE=$(autorandr --detected 2>/dev/null || echo "mobile")
|
||||||
|
|
||||||
|
# Switch to PM tag and launch
|
||||||
|
[[ "$PROFILE" != "mobile" ]] && echo "mon-sec" > /tmp/dwm.fifo
|
||||||
|
echo "kicad-pm" > /tmp/dwm.fifo
|
||||||
|
kicad "$PROJECT" &
|
||||||
|
|
||||||
|
# Wait for PM, open PCB editor
|
||||||
|
sleep 1
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+p
|
||||||
|
|
||||||
|
# Wait for PCB Editor
|
||||||
|
sleep 2
|
||||||
|
[[ "$PROFILE" != "mobile" ]] && echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
|
||||||
|
if [[ "$PROFILE" == "mobile" ]]; then
|
||||||
|
# Mobile: retag PCB to tag 18 (kicad-aux)
|
||||||
|
# PCB landed on tag 17, focus it, retag to 18, follow
|
||||||
|
xdotool search --name "PCB Editor" windowactivate --sync
|
||||||
|
sleep 0.25
|
||||||
|
echo "tag 18" > /tmp/dwm.fifo
|
||||||
|
echo "kicad-aux" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Focus PCB Editor, open Schematic
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+e
|
||||||
|
fi
|
||||||
45
KiCad/Scripts/kicad-lib-launch.sh
Normal file
45
KiCad/Scripts/kicad-lib-launch.sh
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Open Symbol + Footprint editors from running schematic/PCB editors
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
PROFILE=$(autorandr --detected 2>/dev/null || echo "mobile")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
# Hyprland: Focus workspaces and send keys
|
||||||
|
hyprctl dispatch workspace 101
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+u # Open Footprint Editor from PCB
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
hyprctl dispatch workspace 102
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+i # Open Symbol Editor from Schematic
|
||||||
|
else
|
||||||
|
# Focus PCB Editor, open Footprint Editor
|
||||||
|
[[ "$PROFILE" != "mobile" ]] && echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+u
|
||||||
|
|
||||||
|
sleep 0.5
|
||||||
|
|
||||||
|
# Focus right monitor, Schematic Editor, open Symbol Editor
|
||||||
|
[[ "$PROFILE" != "mobile" ]] && echo "mon-sec" > /tmp/dwm.fifo
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
sleep 0.25
|
||||||
|
xdotool key ctrl+i
|
||||||
|
fi
|
||||||
63
KiCad/Scripts/kicad-projects.sh
Normal file
63
KiCad/Scripts/kicad-projects.sh
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rofi KiCad project launcher
|
||||||
|
# Two-step: select folder, then select project
|
||||||
|
# Works with both Hyprland and dwm
|
||||||
|
|
||||||
|
# Define project folders: "Display Name|/path/to/folder"
|
||||||
|
PROJECT_FOLDERS=(
|
||||||
|
"CNC|/data/3D-Printer/Electronics/PCBs"
|
||||||
|
"Keyboard|/data/Keyboard/PCB"
|
||||||
|
"eGPU|/data/eGPU"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Step 1: Select project folder
|
||||||
|
FOLDER_MENU=""
|
||||||
|
for entry in "${PROJECT_FOLDERS[@]}"; do
|
||||||
|
FOLDER_MENU+="${entry%%|*}\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
SELECTED_FOLDER=$(echo -e "$FOLDER_MENU" | rofi -dmenu -p "KiCad Folder" -i)
|
||||||
|
[ -z "$SELECTED_FOLDER" ] && exit 0
|
||||||
|
|
||||||
|
# Get the path for selected folder
|
||||||
|
FOLDER_PATH=""
|
||||||
|
for entry in "${PROJECT_FOLDERS[@]}"; do
|
||||||
|
name="${entry%%|*}"
|
||||||
|
path="${entry#*|}"
|
||||||
|
if [ "$name" = "$SELECTED_FOLDER" ]; then
|
||||||
|
FOLDER_PATH="$path"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -z "$FOLDER_PATH" ] && exit 1
|
||||||
|
|
||||||
|
# Step 2: Find .kicad_pro files in selected folder
|
||||||
|
# Sort by path length (shallowest first) to handle submodule duplicates
|
||||||
|
mapfile -t PROJECTS < <(find "$FOLDER_PATH" -name "*.kicad_pro" -type f 2>/dev/null | awk '{print length, $0}' | sort -n | cut -d' ' -f2-)
|
||||||
|
|
||||||
|
if [ ${#PROJECTS[@]} -eq 0 ]; then
|
||||||
|
rofi -e "No KiCad projects found in $FOLDER_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build menu with duplicate filtering (keep shallowest path for each project name)
|
||||||
|
declare -A SEEN_PROJECTS
|
||||||
|
MENU=""
|
||||||
|
for project in "${PROJECTS[@]}"; do
|
||||||
|
name=$(basename "$project" .kicad_pro)
|
||||||
|
# Skip if we've already seen this project name (deeper path = submodule)
|
||||||
|
if [ -z "${SEEN_PROJECTS[$name]}" ]; then
|
||||||
|
SEEN_PROJECTS[$name]="$project"
|
||||||
|
MENU+="$name\n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Show rofi menu
|
||||||
|
SELECTED=$(echo -e "$MENU" | rofi -dmenu -p "Project" -i)
|
||||||
|
[ -z "$SELECTED" ] && exit 0
|
||||||
|
|
||||||
|
# Launch selected project
|
||||||
|
PROJECT_PATH="${SEEN_PROJECTS[$SELECTED]}"
|
||||||
|
if [ -n "$PROJECT_PATH" ]; then
|
||||||
|
kicad-launch "$PROJECT_PATH"
|
||||||
|
fi
|
||||||
31
KiCad/Scripts/kicad-show.sh
Normal file
31
KiCad/Scripts/kicad-show.sh
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Show KiCad tag on both monitors
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprctl dispatch workspace 101
|
||||||
|
hyprctl dispatch workspace 102
|
||||||
|
else
|
||||||
|
if [[ $(autorandr --detected) != "mobile" ]]; then
|
||||||
|
# Multi-monitor: set kicad tag on both monitors
|
||||||
|
echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
echo "mon-sec" > /tmp/dwm.fifo
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
else
|
||||||
|
# Single monitor: just switch to kicad tag
|
||||||
|
echo "kicad" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
23
KiCad/Scripts/kicad-swap.sh
Normal file
23
KiCad/Scripts/kicad-swap.sh
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Swap KiCad workspaces between monitors
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprctl dispatch swapactiveworkspaces DP-3 eDP-1
|
||||||
|
else
|
||||||
|
# Ensure we're on kicad tag on both monitors first
|
||||||
|
kicad-show
|
||||||
|
echo "mon-swap" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
20
KiCad/kicad.nix
Normal file
20
KiCad/kicad.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# KiCad configuration and scripts
|
||||||
|
# Works with both Hyprland (Wayland) and dwm (X11)
|
||||||
|
{ pkgs-stable, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
scriptsDir = ./Scripts;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
home.packages = with pkgs-stable; [
|
||||||
|
kicad
|
||||||
|
|
||||||
|
# Custom scripts
|
||||||
|
(writeShellScriptBin "kicad-launch" (builtins.readFile "${scriptsDir}/kicad-launch.sh"))
|
||||||
|
(writeShellScriptBin "kicad-projects" (builtins.readFile "${scriptsDir}/kicad-projects.sh"))
|
||||||
|
(writeShellScriptBin "kicad-show" (builtins.readFile "${scriptsDir}/kicad-show.sh"))
|
||||||
|
(writeShellScriptBin "kicad-swap" (builtins.readFile "${scriptsDir}/kicad-swap.sh"))
|
||||||
|
(writeShellScriptBin "kicad-cycle" (builtins.readFile "${scriptsDir}/kicad-cycle.sh"))
|
||||||
|
(writeShellScriptBin "kicad-lib-launch" (builtins.readFile "${scriptsDir}/kicad-lib-launch.sh"))
|
||||||
|
];
|
||||||
|
}
|
||||||
86
Rofi/Scripts/favorites.sh
Normal file
86
Rofi/Scripts/favorites.sh
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rofi Favorites - Reads Zen/Firefox bookmarks directly from SQLite
|
||||||
|
# Supports folder navigation with ROFI_DATA state tracking
|
||||||
|
# Works with both Hyprland and dwm (no WM-specific code)
|
||||||
|
|
||||||
|
PLACES_DB="$HOME/.zen/default/places.sqlite"
|
||||||
|
TEMP_DB="/tmp/rofi-bookmarks.sqlite"
|
||||||
|
STATE="${ROFI_DATA:-3}" # 3 = Bookmarks Toolbar folder ID
|
||||||
|
SELECTION="$1"
|
||||||
|
|
||||||
|
# Copy database to avoid lock issues (browser keeps it locked)
|
||||||
|
cp "$PLACES_DB" "$TEMP_DB" 2>/dev/null
|
||||||
|
|
||||||
|
show_folder() {
|
||||||
|
local folder_id="$1"
|
||||||
|
echo -en "\0data\x1f${folder_id}\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
|
||||||
|
# Show back option if not at root
|
||||||
|
[[ "$folder_id" != "3" ]] && echo " .."
|
||||||
|
|
||||||
|
# Query bookmarks in this folder
|
||||||
|
# type 1 = bookmark, type 2 = folder
|
||||||
|
sqlite3 -separator '|' "$TEMP_DB" "
|
||||||
|
SELECT
|
||||||
|
b.id,
|
||||||
|
b.type,
|
||||||
|
COALESCE(b.title, ''),
|
||||||
|
COALESCE(p.url, '')
|
||||||
|
FROM moz_bookmarks b
|
||||||
|
LEFT JOIN moz_places p ON b.fk = p.id
|
||||||
|
WHERE b.parent = $folder_id
|
||||||
|
AND b.title IS NOT NULL
|
||||||
|
AND b.title != ''
|
||||||
|
ORDER BY b.position;
|
||||||
|
" | while IFS='|' read -r id type title url; do
|
||||||
|
if [[ "$type" == "2" ]]; then
|
||||||
|
# Folder
|
||||||
|
echo -en " ${title}\0info\x1ffolder:${id}\n"
|
||||||
|
elif [[ "$type" == "1" && -n "$url" ]]; then
|
||||||
|
# Bookmark
|
||||||
|
echo -en " ${title}\0info\x1f${url}\n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_selection() {
|
||||||
|
local info="$ROFI_INFO"
|
||||||
|
|
||||||
|
# Back/parent
|
||||||
|
if [[ "$SELECTION" == " .." ]]; then
|
||||||
|
parent=$(sqlite3 "$TEMP_DB" "SELECT parent FROM moz_bookmarks WHERE id = $STATE;")
|
||||||
|
[[ -z "$parent" || "$parent" == "0" || "$parent" == "1" ]] && parent=3
|
||||||
|
show_folder "$parent"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Folder - navigate into it
|
||||||
|
if [[ "$info" == folder:* ]]; then
|
||||||
|
local folder_id="${info#folder:}"
|
||||||
|
show_folder "$folder_id"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# URL - open it
|
||||||
|
if [[ -n "$info" && "$info" != folder:* ]]; then
|
||||||
|
coproc (xdg-open "$info" &)
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
show_folder "$STATE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if database exists
|
||||||
|
if [[ ! -f "$PLACES_DB" ]]; then
|
||||||
|
echo " No Zen browser profile found"
|
||||||
|
echo " Expected: ~/.zen/default/places.sqlite"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Main entry
|
||||||
|
if [[ -z "$SELECTION" ]]; then
|
||||||
|
show_folder "$STATE"
|
||||||
|
else
|
||||||
|
handle_selection
|
||||||
|
fi
|
||||||
46
Rofi/Scripts/max30.sh
Normal file
46
Rofi/Scripts/max30.sh
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rofi Max30 mode - list and open video files with custom names
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
VIDEOS=(
|
||||||
|
"Max Out Cardio|/data-bis/Insanity MAX 30/Max Out Cardio.mkv"
|
||||||
|
"Max Out Power|/data-bis/Insanity MAX 30/Max Out Power.mkv"
|
||||||
|
"Max Out Sweat|/data-bis/Insanity MAX 30/Max Out Sweat.mkv"
|
||||||
|
"Max Out Strength|/data-bis/Insanity MAX 30/Max Out Strength.mkv"
|
||||||
|
"Friday Fight #2|/data-bis/Insanity MAX 30/Friday Fight Round 2.mkv"
|
||||||
|
)
|
||||||
|
|
||||||
|
# If no argument, list video names
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
for entry in "${VIDEOS[@]}"; do
|
||||||
|
echo "${entry%%|*}"
|
||||||
|
done
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If argument provided, find and open the matching video
|
||||||
|
SELECTED="$1"
|
||||||
|
for entry in "${VIDEOS[@]}"; do
|
||||||
|
name="${entry%%|*}"
|
||||||
|
path="${entry#*|}"
|
||||||
|
if [ "$name" = "$SELECTED" ]; then
|
||||||
|
setsid xdg-open "$path" >/dev/null 2>&1 &
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprctl dispatch workspace 90 >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# Focus primary monitor first if not on mobile (single monitor) profile
|
||||||
|
[[ $(autorandr --detected) != "mobile" ]] && echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "video" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
317
Rofi/Scripts/system.sh
Normal file
317
Rofi/Scripts/system.sh
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rofi System Menu - as rofi mode with inline submenus
|
||||||
|
# Uses ROFI_DATA for state tracking between calls
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
STATE="${ROFI_DATA:-main}"
|
||||||
|
SELECTION="$1"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Helper Functions
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
get_volume() { wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null | awk '{print int($2*100)}'; }
|
||||||
|
get_mic_volume() { wpctl get-volume @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | awk '{print int($2*100)}'; }
|
||||||
|
is_muted() { wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null | grep -q MUTED && echo "yes" || echo "no"; }
|
||||||
|
is_mic_muted() { wpctl get-volume @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | grep -q MUTED && echo "yes" || echo "no"; }
|
||||||
|
get_brightness_internal() { brightnessctl -m 2>/dev/null | cut -d',' -f4 | tr -d '%'; }
|
||||||
|
get_brightness_external() {
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
local val=$(busctl --user get-property rs.wl-gammarelay /outputs/DP_3 rs.wl.gammarelay Brightness 2>/dev/null | awk '{print $2}')
|
||||||
|
echo "${val:-1}" | awk '{print int($1*100)}'
|
||||||
|
else
|
||||||
|
# X11: Use xrandr gamma (approximate)
|
||||||
|
local gamma=$(xrandr --verbose | grep -A5 "DP-3" | grep "Brightness" | awk '{print $2}' 2>/dev/null)
|
||||||
|
echo "${gamma:-1}" | awk '{print int($1*100)}'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
get_power_profile() { powerprofilesctl get 2>/dev/null || echo "balanced"; }
|
||||||
|
|
||||||
|
get_default_sink_id() {
|
||||||
|
wpctl inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | head -1 | awk '{print $2}' | tr -d ','
|
||||||
|
}
|
||||||
|
|
||||||
|
get_default_source_id() {
|
||||||
|
wpctl inspect @DEFAULT_AUDIO_SOURCE@ 2>/dev/null | head -1 | awk '{print $2}' | tr -d ','
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sinks() {
|
||||||
|
local default_id=$(get_default_sink_id)
|
||||||
|
pw-cli list-objects Node 2>/dev/null | awk '
|
||||||
|
/^[[:space:]]*id [0-9]+/ { id = $2; gsub(",", "", id) }
|
||||||
|
/node.description = / { gsub(/.*node.description = "|"$/, ""); desc = $0 }
|
||||||
|
/media.class = "Audio\/Sink"/ { print id "|" desc }
|
||||||
|
' | while IFS='|' read -r id desc; do
|
||||||
|
if [[ "$id" == "$default_id" ]]; then
|
||||||
|
echo "✓ ${desc}|${id}"
|
||||||
|
else
|
||||||
|
echo "${desc}|${id}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
get_sources() {
|
||||||
|
local default_id=$(get_default_source_id)
|
||||||
|
pw-cli list-objects Node 2>/dev/null | awk '
|
||||||
|
/^[[:space:]]*id [0-9]+/ { id = $2; gsub(",", "", id) }
|
||||||
|
/node.description = / { gsub(/.*node.description = "|"$/, ""); desc = $0 }
|
||||||
|
/media.class = "Audio\/Source"/ { print id "|" desc }
|
||||||
|
' | while IFS='|' read -r id desc; do
|
||||||
|
if [[ "$id" == "$default_id" ]]; then
|
||||||
|
echo "✓ ${desc}|${id}"
|
||||||
|
else
|
||||||
|
echo "${desc}|${id}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Menu Display Functions
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
show_main() {
|
||||||
|
echo -en "\0data\x1fmain\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
echo " Sound"
|
||||||
|
echo " Brightness"
|
||||||
|
echo " WiFi"
|
||||||
|
echo " Bluetooth"
|
||||||
|
echo " Power Profile"
|
||||||
|
echo " Power"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_sound() {
|
||||||
|
echo -en "\0data\x1fsound\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
local vol=$(get_volume)
|
||||||
|
local mic=$(get_mic_volume)
|
||||||
|
local muted=$(is_muted)
|
||||||
|
local mic_muted=$(is_mic_muted)
|
||||||
|
local vol_icon=""; [[ "$muted" == "yes" ]] && vol_icon=""
|
||||||
|
local mic_icon=""; [[ "$mic_muted" == "yes" ]] && mic_icon=""
|
||||||
|
|
||||||
|
echo "$vol_icon Volume: ${vol}%"
|
||||||
|
echo " Volume +5%"
|
||||||
|
echo " Volume -5%"
|
||||||
|
echo " Output Device"
|
||||||
|
echo "$mic_icon Mic: ${mic}%"
|
||||||
|
echo " Mic +5%"
|
||||||
|
echo " Mic -5%"
|
||||||
|
echo " Input Device"
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_output() {
|
||||||
|
echo -en "\0data\x1foutput\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
get_sinks | while IFS='|' read -r name id; do
|
||||||
|
echo -en " ${name}\0info\x1f${id}\n"
|
||||||
|
done
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_input() {
|
||||||
|
echo -en "\0data\x1finput\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
get_sources | while IFS='|' read -r name id; do
|
||||||
|
echo -en " ${name}\0info\x1f${id}\n"
|
||||||
|
done
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_brightness() {
|
||||||
|
echo -en "\0data\x1fbrightness\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
local internal=$(get_brightness_internal)
|
||||||
|
local external=$(get_brightness_external)
|
||||||
|
|
||||||
|
echo " Internal: ${internal}%"
|
||||||
|
echo " Internal +5%"
|
||||||
|
echo " Internal -5%"
|
||||||
|
echo " External: ${external}%"
|
||||||
|
echo " External +5%"
|
||||||
|
echo " External -5%"
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_power_profile() {
|
||||||
|
echo -en "\0data\x1fprofile\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
local current=$(get_power_profile)
|
||||||
|
local perf="" bal="" saver=""
|
||||||
|
[[ "$current" == "performance" ]] && perf="✓ "
|
||||||
|
[[ "$current" == "balanced" ]] && bal="✓ "
|
||||||
|
[[ "$current" == "power-saver" ]] && saver="✓ "
|
||||||
|
|
||||||
|
echo "${perf} Performance"
|
||||||
|
echo "${bal} Balanced"
|
||||||
|
echo "${saver} Power Saver"
|
||||||
|
echo " Edit Tuning"
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_power() {
|
||||||
|
echo -en "\0data\x1fpower\n"
|
||||||
|
echo -en "\0keep-selection\x1ftrue\n"
|
||||||
|
echo " Shutdown"
|
||||||
|
echo " Reboot"
|
||||||
|
echo " Logout"
|
||||||
|
echo " Lock"
|
||||||
|
echo " Back"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Action Handlers
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
handle_main() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Sound"*) show_sound ;;
|
||||||
|
*"Brightness"*) show_brightness ;;
|
||||||
|
*"WiFi"*) coproc (rofi-network-manager &); exit 0 ;;
|
||||||
|
*"Bluetooth"*) coproc (rofi-bluetooth &); exit 0 ;;
|
||||||
|
*"Power Profile"*) show_power_profile ;;
|
||||||
|
*"Power"*) show_power ;;
|
||||||
|
*) show_main ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_sound() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Volume:"*) wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle; show_sound ;;
|
||||||
|
*"Volume +5%"*) wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ -l 1.0; show_sound ;;
|
||||||
|
*"Volume -5%"*) wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; show_sound ;;
|
||||||
|
*"Output Device"*) show_output ;;
|
||||||
|
*"Mic:"*) wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle; show_sound ;;
|
||||||
|
*"Mic +5%"*) wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%+ -l 1.0; show_sound ;;
|
||||||
|
*"Mic -5%"*) wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-; show_sound ;;
|
||||||
|
*"Input Device"*) show_input ;;
|
||||||
|
*"Back"*) show_main ;;
|
||||||
|
*) show_sound ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_output() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Back"*) show_sound ;;
|
||||||
|
*)
|
||||||
|
[[ -n "$ROFI_INFO" ]] && wpctl set-default "$ROFI_INFO"
|
||||||
|
show_output
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_input() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Back"*) show_sound ;;
|
||||||
|
*)
|
||||||
|
[[ -n "$ROFI_INFO" ]] && wpctl set-default "$ROFI_INFO"
|
||||||
|
show_input
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_brightness() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Internal +5%"*) brightnessctl -q set +5%; show_brightness ;;
|
||||||
|
*"Internal -5%"*) brightnessctl -q set 5%-; show_brightness ;;
|
||||||
|
*"External +5%"*)
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
current=$(get_brightness_external)
|
||||||
|
new=$((current + 5)); [[ $new -gt 100 ]] && new=100
|
||||||
|
val=$(echo "scale=2; $new/100" | bc)
|
||||||
|
busctl --user set-property rs.wl-gammarelay /outputs/DP_3 rs.wl.gammarelay Brightness d "$val" 2>/dev/null
|
||||||
|
else
|
||||||
|
current=$(get_brightness_external)
|
||||||
|
new=$((current + 5)); [[ $new -gt 100 ]] && new=100
|
||||||
|
val=$(echo "scale=2; $new/100" | bc)
|
||||||
|
xrandr --output DP-3 --brightness "$val" 2>/dev/null
|
||||||
|
fi
|
||||||
|
show_brightness ;;
|
||||||
|
*"External -5%"*)
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
current=$(get_brightness_external)
|
||||||
|
new=$((current - 5)); [[ $new -lt 5 ]] && new=5
|
||||||
|
val=$(echo "scale=2; $new/100" | bc)
|
||||||
|
busctl --user set-property rs.wl-gammarelay /outputs/DP_3 rs.wl.gammarelay Brightness d "$val" 2>/dev/null
|
||||||
|
else
|
||||||
|
current=$(get_brightness_external)
|
||||||
|
new=$((current - 5)); [[ $new -lt 5 ]] && new=5
|
||||||
|
val=$(echo "scale=2; $new/100" | bc)
|
||||||
|
xrandr --output DP-3 --brightness "$val" 2>/dev/null
|
||||||
|
fi
|
||||||
|
show_brightness ;;
|
||||||
|
*"Back"*) show_main ;;
|
||||||
|
*) show_brightness ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_power_profile() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
# systemd path watcher auto-applies power-tuning on profile change
|
||||||
|
*"Performance"*) powerprofilesctl set performance; show_power_profile ;;
|
||||||
|
*"Balanced"*) powerprofilesctl set balanced; show_power_profile ;;
|
||||||
|
*"Power Saver"*) powerprofilesctl set power-saver; show_power_profile ;;
|
||||||
|
*"Edit Tuning"*) coproc (zeditor "$HOME/NixOS/ryzenadj.nix" &); exit 0 ;;
|
||||||
|
*"Back"*) show_main ;;
|
||||||
|
*) show_power_profile ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_power() {
|
||||||
|
case "$SELECTION" in
|
||||||
|
*"Shutdown"*) systemctl poweroff ;;
|
||||||
|
*"Reboot"*) systemctl reboot ;;
|
||||||
|
*"Logout"*)
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprctl dispatch exit
|
||||||
|
else
|
||||||
|
pkill -x dwm
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*"Lock"*)
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprlock & exit 0
|
||||||
|
else
|
||||||
|
slock & exit 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*"Back"*) show_main ;;
|
||||||
|
*) show_power ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Main Entry Point
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
if [[ -z "$SELECTION" ]]; then
|
||||||
|
case "$STATE" in
|
||||||
|
sound) show_sound ;;
|
||||||
|
output) show_output ;;
|
||||||
|
input) show_input ;;
|
||||||
|
brightness) show_brightness ;;
|
||||||
|
profile) show_power_profile ;;
|
||||||
|
power) show_power ;;
|
||||||
|
*) show_main ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case "$STATE" in
|
||||||
|
sound) handle_sound ;;
|
||||||
|
output) handle_output ;;
|
||||||
|
input) handle_input ;;
|
||||||
|
brightness) handle_brightness ;;
|
||||||
|
profile) handle_power_profile ;;
|
||||||
|
power) handle_power ;;
|
||||||
|
*) handle_main ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
86
Rofi/Scripts/websearch.sh
Normal file
86
Rofi/Scripts/websearch.sh
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Rofi web search - with DuckDuckGo result preview
|
||||||
|
# Supports both Hyprland (Wayland) and dwm (X11)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Environment Detection
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||||
|
WM="hyprland"
|
||||||
|
else
|
||||||
|
WM="dwm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
switch_to_browser() {
|
||||||
|
if [[ "$WM" == "hyprland" ]]; then
|
||||||
|
hyprctl dispatch workspace 70
|
||||||
|
else
|
||||||
|
# Focus primary monitor first if not on mobile (single monitor) profile
|
||||||
|
[[ $(autorandr --detected) != "mobile" ]] && echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
echo "browser" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Step 1: Query input (no list)
|
||||||
|
QUERY=$(echo "" | rofi -dmenu -p "Search : " -l 0)
|
||||||
|
[ -z "$QUERY" ] && exit 0
|
||||||
|
|
||||||
|
# Check if input looks like a URL - open directly
|
||||||
|
if echo "$QUERY" | grep -qE '\.(com|org|net|io|dev|co|me|gov|edu|app|xyz|info)(/|$)'; then
|
||||||
|
# Add https:// if no protocol specified
|
||||||
|
[[ "$QUERY" =~ ^https?:// ]] || QUERY="https://$QUERY"
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "$QUERY"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 2: Engine selection (DuckDuckGo first)
|
||||||
|
ENGINE=$(printf " DuckDuckGo\n Google\n MyNixOS\n Nixpkgs\n NerdFonts" | rofi -dmenu -p "Engine : " -no-custom -l 5)
|
||||||
|
[ -z "$ENGINE" ] && exit 0
|
||||||
|
|
||||||
|
# Remove icon prefix
|
||||||
|
ENGINE="${ENGINE#* }"
|
||||||
|
|
||||||
|
ENCODED=$(echo "$QUERY" | sed 's/ /%20/g; s/&/%26/g; s/?/%3F/g; s/=/%3D/g')
|
||||||
|
|
||||||
|
case "$ENGINE" in
|
||||||
|
"DuckDuckGo")
|
||||||
|
# Fetch top 5 results using ddgr
|
||||||
|
RESULTS=$(ddgr --json -n 5 "$QUERY" 2>/dev/null | jq -r '.[] | "\(.title)\t\(.url)"')
|
||||||
|
|
||||||
|
if [ -z "$RESULTS" ]; then
|
||||||
|
# Fallback to direct search if no results
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "https://duckduckgo.com/?q=$ENCODED"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show results in rofi (title only)
|
||||||
|
TITLES=$(echo "$RESULTS" | cut -f1)
|
||||||
|
SELECTED=$(echo "$TITLES" | rofi -dmenu -p "Results : " -l 5)
|
||||||
|
[ -z "$SELECTED" ] && exit 0
|
||||||
|
|
||||||
|
# Get URL for selected title
|
||||||
|
URL=$(echo "$RESULTS" | grep "^$SELECTED " | cut -f2)
|
||||||
|
if [ -n "$URL" ]; then
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "$URL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"Google")
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "https://www.google.com/search?q=$ENCODED"
|
||||||
|
;;
|
||||||
|
"MyNixOS")
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "https://mynixos.com/search?q=$ENCODED"
|
||||||
|
;;
|
||||||
|
"Nixpkgs")
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "https://search.nixos.org/packages?query=$ENCODED"
|
||||||
|
;;
|
||||||
|
"NerdFonts")
|
||||||
|
switch_to_browser
|
||||||
|
xdg-open "https://www.nerdfonts.com/cheat-sheet?q=$ENCODED"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
162
Rofi/rofi.nix
Normal file
162
Rofi/rofi.nix
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
# Rofi configuration and scripts
|
||||||
|
# Works with both Hyprland (Wayland) and dwm (X11)
|
||||||
|
{
|
||||||
|
pkgs-stable,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
scriptsDir = ./Scripts;
|
||||||
|
|
||||||
|
# Detect if we're in Wayland or X11 based on session type
|
||||||
|
# This is evaluated at build time, so we need runtime detection in scripts
|
||||||
|
isWayland = config.wayland.windowManager.hyprland.enable or false;
|
||||||
|
|
||||||
|
# Terminal varies by environment
|
||||||
|
terminal = if isWayland then "foot" else "st";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Wayland-specific packages (only when using Hyprland)
|
||||||
|
home.packages =
|
||||||
|
with pkgs-stable;
|
||||||
|
[
|
||||||
|
rofi-bluetooth
|
||||||
|
rofi-network-manager
|
||||||
|
ddgr
|
||||||
|
brightnessctl
|
||||||
|
bc
|
||||||
|
sqlite
|
||||||
|
|
||||||
|
# Custom scripts (environment-aware)
|
||||||
|
(writeShellScriptBin "rofi-websearch" (builtins.readFile "${scriptsDir}/websearch.sh"))
|
||||||
|
(writeShellScriptBin "rofi-max30" (builtins.readFile "${scriptsDir}/max30.sh"))
|
||||||
|
(writeShellScriptBin "rofi-system" (builtins.readFile "${scriptsDir}/system.sh"))
|
||||||
|
(writeShellScriptBin "rofi-favorites" (builtins.readFile "${scriptsDir}/favorites.sh"))
|
||||||
|
]
|
||||||
|
++ (
|
||||||
|
if isWayland then
|
||||||
|
[
|
||||||
|
wl-gammarelay-rs
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
# Start wl-gammarelay-rs on Hyprland
|
||||||
|
wayland.windowManager.hyprland.settings = lib.mkIf isWayland {
|
||||||
|
exec-once = [ "wl-gammarelay-rs" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.rofi = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.rofi;
|
||||||
|
terminal = terminal;
|
||||||
|
|
||||||
|
plugins = with pkgs-stable; [
|
||||||
|
rofi-calc
|
||||||
|
rofi-emoji
|
||||||
|
];
|
||||||
|
|
||||||
|
modes = [
|
||||||
|
"system:rofi-system"
|
||||||
|
"favorites:rofi-favorites"
|
||||||
|
"drun"
|
||||||
|
"calc"
|
||||||
|
"emoji"
|
||||||
|
"max30:rofi-max30"
|
||||||
|
];
|
||||||
|
|
||||||
|
extraConfig = {
|
||||||
|
show-icons = true;
|
||||||
|
display-system = "";
|
||||||
|
display-favorites = "";
|
||||||
|
display-drun = "";
|
||||||
|
display-calc = "";
|
||||||
|
display-emoji = "";
|
||||||
|
display-max30 = "";
|
||||||
|
drun-display-format = "{name}";
|
||||||
|
scroll-method = 0;
|
||||||
|
disable-history = false;
|
||||||
|
sidebar-mode = false;
|
||||||
|
sort = true;
|
||||||
|
sorting-method = "fzf";
|
||||||
|
matching = "fuzzy";
|
||||||
|
|
||||||
|
kb-primary-paste = "Control+V,Shift+Insert";
|
||||||
|
kb-secondary-paste = "Control+v,Insert";
|
||||||
|
kb-secondary-copy = "Control+c";
|
||||||
|
kb-clear-line = "Control+w";
|
||||||
|
kb-move-front = "Control+a";
|
||||||
|
kb-move-end = "Control+e";
|
||||||
|
kb-move-word-back = "Alt+b,Control+Left";
|
||||||
|
kb-move-word-forward = "Alt+f,Control+Right";
|
||||||
|
kb-move-char-back = "Control+b";
|
||||||
|
kb-move-char-forward = "Control+f";
|
||||||
|
kb-remove-word-back = "Control+Alt+h,Control+BackSpace";
|
||||||
|
kb-remove-word-forward = "Control+Alt+d";
|
||||||
|
kb-remove-char-forward = "Delete,Control+d";
|
||||||
|
kb-remove-char-back = "BackSpace,Shift+BackSpace,Control+h";
|
||||||
|
kb-remove-to-eol = "";
|
||||||
|
kb-remove-to-sol = "Control+u";
|
||||||
|
kb-accept-entry = "Return,KP_Enter";
|
||||||
|
kb-accept-custom = "Control+Return";
|
||||||
|
kb-accept-custom-alt = "Control+Shift+Return";
|
||||||
|
kb-accept-alt = "Shift+Return";
|
||||||
|
kb-delete-entry = "Shift+Delete";
|
||||||
|
kb-mode-next = "Right";
|
||||||
|
kb-mode-previous = "Left";
|
||||||
|
kb-mode-complete = "Control+l";
|
||||||
|
kb-row-left = "Control+Page_Up";
|
||||||
|
kb-row-right = "Control+Page_Down";
|
||||||
|
kb-row-up = "Up";
|
||||||
|
kb-row-down = "Down";
|
||||||
|
kb-row-tab = "";
|
||||||
|
kb-element-next = "Tab";
|
||||||
|
kb-element-prev = "ISO_Left_Tab";
|
||||||
|
kb-page-prev = "Page_Up";
|
||||||
|
kb-page-next = "Page_Down";
|
||||||
|
kb-row-first = "Home,KP_Home";
|
||||||
|
kb-row-last = "End,KP_End";
|
||||||
|
kb-row-select = "Control+space";
|
||||||
|
kb-screenshot = "Alt+S";
|
||||||
|
kb-ellipsize = "Alt+period";
|
||||||
|
kb-toggle-case-sensitivity = "grave,dead_grave";
|
||||||
|
kb-toggle-sort = "Alt+grave";
|
||||||
|
kb-cancel = "Escape";
|
||||||
|
};
|
||||||
|
|
||||||
|
theme =
|
||||||
|
let
|
||||||
|
mkLiteral = value: {
|
||||||
|
_type = "literal";
|
||||||
|
value = value;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
window = {
|
||||||
|
width = mkLiteral "300px";
|
||||||
|
location = mkLiteral "center";
|
||||||
|
# border-radius = mkLiteral "12px";
|
||||||
|
border = mkLiteral "2px solid";
|
||||||
|
border-color = mkLiteral "@border-color";
|
||||||
|
};
|
||||||
|
listview = {
|
||||||
|
lines = 8;
|
||||||
|
fixed-height = false;
|
||||||
|
};
|
||||||
|
element = {
|
||||||
|
padding = mkLiteral "8px";
|
||||||
|
# border-radius = mkLiteral "6px";
|
||||||
|
};
|
||||||
|
# "element selected" = {
|
||||||
|
# border-radius = mkLiteral "6px";
|
||||||
|
# };
|
||||||
|
inputbar = {
|
||||||
|
padding = mkLiteral "8px";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
92
Suckless/dwm/api.nix
Normal file
92
Suckless/dwm/api.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
# dwm fifo API - control dwm via named pipe
|
||||||
|
# Usage: echo "command" > /tmp/dwm.fifo
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
/* dwmfifo - control dwm via named pipe */
|
||||||
|
static const char *dwmfifo = "/tmp/dwm.fifo";
|
||||||
|
static Command commands[] = {
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* TAG NAVIGATION - Semantic names matching workflow
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "view", view, .parse = parsetag }, /* Generic: view 5 */
|
||||||
|
{ "view-all", view, {.ui = ~0} }, /* All tags */
|
||||||
|
{ "view-prev", viewprev, {0} }, /* Previous tag */
|
||||||
|
{ "view-next", viewnext, {0} }, /* Next tag */
|
||||||
|
|
||||||
|
/* Semantic tag shortcuts (matching tags.nix) */
|
||||||
|
{ "terminal", view, {.ui = 1 << 9} }, /* Tag 10: */
|
||||||
|
{ "files", view, {.ui = 1 << 10} }, /* Tag 11: */
|
||||||
|
{ "video", view, {.ui = 1 << 11} }, /* Tag 12: */
|
||||||
|
{ "browser", view, {.ui = 1 << 12} }, /* Tag 13: */
|
||||||
|
{ "code", view, {.ui = 1 << 13} }, /* Tag 14: */
|
||||||
|
{ "freecad", view, {.ui = 1 << 14} }, /* Tag 15: */
|
||||||
|
{ "kicad-pm", view, {.ui = 1 << 15} }, /* Tag 16: (project manager) */
|
||||||
|
{ "kicad", view, {.ui = 1 << 16} }, /* Tag 17: (sch/pcb) */
|
||||||
|
{ "kicad-aux", view, {.ui = 1 << 17} }, /* Tag 18: (pcb mobile) */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* MONITOR CONTROL - Primary (left) / Secondary (right)
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "mon-prim", focusnthmon, {.i = 1} }, /* Focus primary monitor */
|
||||||
|
{ "mon-sec", focusnthmon, {.i = 0} }, /* Focus secondary monitor */
|
||||||
|
{ "mon-send-prim", tagnthmon, {.i = 1} }, /* Send window to primary */
|
||||||
|
{ "mon-send-sec", tagnthmon, {.i = 0} }, /* Send window to secondary */
|
||||||
|
{ "mon-swap", swapmon, {0} }, /* Swap monitor contents */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* WINDOW MANAGEMENT
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "focus-next", focusstack, {.i = +1} }, /* Next window in stack */
|
||||||
|
{ "focus-prev", focusstack, {.i = -1} }, /* Previous window */
|
||||||
|
{ "focus", focusstack, .parse = parseplusminus },/* Generic: focus +2 */
|
||||||
|
{ "kill", killclient, {0} }, /* Close window */
|
||||||
|
{ "zoom", zoom, {0} }, /* Promote to master */
|
||||||
|
{ "float", togglefloating, {0} }, /* Toggle floating */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* LAYOUT
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "layout-tile", setlayout, {.v = &layouts[0]} },
|
||||||
|
{ "layout-float", setlayout, {.v = &layouts[1]} },
|
||||||
|
{ "layout-mono", setlayout, {.v = &layouts[2]} },
|
||||||
|
{ "layout-toggle", setlayout, {0} }, /* Cycle layouts */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* MASTER AREA
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "master-inc", incnmaster, {.i = +1} },
|
||||||
|
{ "master-dec", incnmaster, {.i = -1} },
|
||||||
|
{ "mfact", setmfact, .parse = parseplusminus },/* mfact +0.05 */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* TAG MANAGEMENT
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "toggleview", toggleview, .parse = parsetag },
|
||||||
|
{ "tag", tag, .parse = parsetag },
|
||||||
|
{ "toggletag", toggletag, .parse = parsetag },
|
||||||
|
{ "tagmon", tagmon, .parse = parseplusminus },
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* ADVANCED (window targeting)
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "viewwin", viewwin, .parse = parsexid }, /* Focus by X window ID */
|
||||||
|
{ "viewname", viewname, .parse = parsestr }, /* Focus by name */
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* SPAWNS
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "spawn-term", spawn, {.v = termcmd} },
|
||||||
|
{ "spawn-browser", spawn, {.v = browsercmd} },
|
||||||
|
{ "spawn-rofi", spawn, {.v = roficmd} },
|
||||||
|
{ "spawn-files", spawn, {.v = filescmd} },
|
||||||
|
{ "spawn-editor", spawn, {.v = editorcmd} },
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════════════
|
||||||
|
* SESSION
|
||||||
|
* ═══════════════════════════════════════════════════════════════════════ */
|
||||||
|
{ "quit", quit, {0} },
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
}
|
||||||
39
Suckless/dwm/appearance.nix
Normal file
39
Suckless/dwm/appearance.nix
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# dwm appearance settings (colors, fonts, borders, gaps)
|
||||||
|
# Integrates with Stylix for consistent theming
|
||||||
|
{ config, lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
colors = config.lib.stylix.colors;
|
||||||
|
fonts = config.stylix.fonts;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
/* appearance */
|
||||||
|
static const unsigned int borderpx = 2; /* border pixel of windows */
|
||||||
|
static const unsigned int gappx = 5; /* gaps between windows */
|
||||||
|
static const unsigned int snap = 32; /* snap pixel */
|
||||||
|
static const int showbar = 0; /* 0 means no bar (holdbar shows on key hold) */
|
||||||
|
static const int topbar = 1; /* 0 means bottom bar */
|
||||||
|
/* Display modes of the tab bar: never shown, always shown, shown only in */
|
||||||
|
/* monocle mode in the presence of several windows. */
|
||||||
|
/* Modes after showtab_nmodes are disabled. */
|
||||||
|
enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
|
||||||
|
static const int showtab = showtab_auto; /* Default tab bar show mode */
|
||||||
|
static const int toptab = False; /* False means bottom tab bar */
|
||||||
|
|
||||||
|
static const char *fonts[] = { "${fonts.monospace.name}:size=${toString fonts.sizes.terminal}" };
|
||||||
|
static const char dmenufont[] = "${fonts.monospace.name}:size=${toString fonts.sizes.terminal}";
|
||||||
|
static const char col_gray1[] = "#${colors.base00}";
|
||||||
|
static const char col_gray2[] = "#${colors.base01}";
|
||||||
|
static const char col_gray3[] = "#${colors.base04}";
|
||||||
|
static const char col_gray4[] = "#${colors.base05}";
|
||||||
|
static const char col_cyan[] = "#${colors.base0D}";
|
||||||
|
static const char *colors[][3] = {
|
||||||
|
/* fg bg border */
|
||||||
|
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||||
|
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
}
|
||||||
1779
Suckless/dwm/dwm-lebowski.patch
Normal file
1779
Suckless/dwm/dwm-lebowski.patch
Normal file
File diff suppressed because it is too large
Load diff
100
Suckless/dwm/dwm.nix
Normal file
100
Suckless/dwm/dwm.nix
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
# dwm window manager configuration
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
# Patch Development Notes
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# Base: dwm 6.6 (matches nixpkgs)
|
||||||
|
# Clone: ~/NixOS/dwm
|
||||||
|
#
|
||||||
|
# Clean & Build Commands:
|
||||||
|
# cd ~/NixOS/dwm
|
||||||
|
# git reset --hard 6.6
|
||||||
|
# rm -f config.h drw.o dwm dwm.o util.o
|
||||||
|
# nix-shell -p xorg.libX11 xorg.libXft xorg.libXinerama xorg.libXcursor pkg-config gnumake gcc
|
||||||
|
# make clean && make
|
||||||
|
#
|
||||||
|
# Generate patch after all patches applied:
|
||||||
|
# git diff 6.6 > ~/NixOS/Suckless/dwm/dwm-lebowski.patch
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
# Patches (apply in order):
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# 1. pertag - Per-tag layouts (applied separately, then tab)
|
||||||
|
# 2. tab - Tabbed monocle bar
|
||||||
|
# 3. fullgaps - Simple gaps between windows
|
||||||
|
# 4. holdbar-modkey - Show bar while holding mod key
|
||||||
|
# 5. hide_vacant_tags - Only show occupied tags
|
||||||
|
# 6. bardwmlogo - DWM logo in bar
|
||||||
|
# 7. cursorwarp - Cursor follows focus
|
||||||
|
# 8. alwayscenter - Float windows spawn centered
|
||||||
|
# 9. swapmonitors - Swap tagsets between monitors
|
||||||
|
# 10. adjacenttag - Navigate tags with arrows (skipvacant)
|
||||||
|
# 11. accessnthmonitor - Focus/send to specific monitor by number
|
||||||
|
# 12. dwmfifo - Control dwm via named pipe
|
||||||
|
# 13. xcursor - Use system Xcursor theme (Stylix)
|
||||||
|
# 14. actualfullscreen
|
||||||
|
#
|
||||||
|
# Custom additions:
|
||||||
|
# - def_layouts array for per-tag default layouts
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
appearance = import ./appearance.nix { inherit config lib; };
|
||||||
|
tags = import ./tags.nix { inherit lib; };
|
||||||
|
rules = import ./rules.nix { inherit lib; };
|
||||||
|
layouts = import ./layouts.nix { inherit lib; };
|
||||||
|
keybindings = import ./keybindings.nix { inherit lib; };
|
||||||
|
api = import ./api.nix { inherit lib; };
|
||||||
|
|
||||||
|
configDefH = ''
|
||||||
|
${appearance.config}
|
||||||
|
|
||||||
|
${tags.config}
|
||||||
|
|
||||||
|
${rules.config}
|
||||||
|
|
||||||
|
${layouts.config}
|
||||||
|
|
||||||
|
${keybindings.config}
|
||||||
|
|
||||||
|
${api.config}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.xserver.windowManager.dwm = {
|
||||||
|
enable = true;
|
||||||
|
package =
|
||||||
|
(pkgs.dwm.override {
|
||||||
|
conf = configDefH;
|
||||||
|
}).overrideAttrs
|
||||||
|
(old: {
|
||||||
|
patches = [ ./dwm-lebowski.patch ];
|
||||||
|
buildInputs = old.buildInputs ++ [ pkgs.xorg.libXcursor ];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
(pkgs.writeShellScriptBin "vieworspawn" ''
|
||||||
|
mon=$1; tag=$2; class=$3; shift 3
|
||||||
|
# Focus monitor if multi-monitor setup (0=secondary, 1=primary)
|
||||||
|
if [[ $(${pkgs.autorandr}/bin/autorandr --detected) != "mobile" ]]; then
|
||||||
|
[[ "$mon" == "0" ]] && echo "mon-sec" > /tmp/dwm.fifo || echo "mon-prim" > /tmp/dwm.fifo
|
||||||
|
fi
|
||||||
|
echo "view $tag" > /tmp/dwm.fifo
|
||||||
|
sleep 0.02
|
||||||
|
if ! ${pkgs.xdotool}/bin/xdotool search --class "$class" >/dev/null 2>&1; then
|
||||||
|
exec "$@"
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
}
|
||||||
181
Suckless/dwm/keybindings.nix
Normal file
181
Suckless/dwm/keybindings.nix
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
# dwm keybindings
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
/* key definitions */
|
||||||
|
#define MODKEY Mod4Mask
|
||||||
|
#define TAGKEYS(KEY,TAG) \
|
||||||
|
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||||
|
#define HOLDKEY 0xffeb // 0 - disable; 0xffe9 - Mod1Mask; 0xffeb - Mod4Mask (Super)
|
||||||
|
|
||||||
|
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||||
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
|
|
||||||
|
/* commands */
|
||||||
|
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
|
||||||
|
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||||
|
static const char *roficmd[] = { "rofi", "-show", "system", NULL };
|
||||||
|
static const char *rofiwebcmd[] = { "rofi-websearch", NULL };
|
||||||
|
static const char *browsercmd[] = { "zen-twilight", NULL };
|
||||||
|
static const char *lockcmd[] = { "slock", NULL };
|
||||||
|
static const char *kicadshowcmd[] = { "kicad-show", NULL };
|
||||||
|
static const char *kicadprojectscmd[] = { "kicad-projects", NULL };
|
||||||
|
static const char *kicadlibcmd[] = { "kicad-lib-launch", NULL };
|
||||||
|
static const char *kicadswapcmd[] = { "kicad-swap", NULL };
|
||||||
|
static const char *kicadcyclefcmd[] = { "kicad-cycle", "f", NULL };
|
||||||
|
static const char *kicadcyclebcmd[] = { "kicad-cycle", "b", NULL };
|
||||||
|
static const char *screenshotcmd[] = { "flameshot", "gui", NULL };
|
||||||
|
static const char *screenshotfullcmd[] = { "flameshot", "full", "--path", "/home/lebowski/Pictures/Screenshots", NULL };
|
||||||
|
static const char *cliphistcmd[] = { "sh", "-c", "greenclip print | rofi -dmenu -p Clipboard | xclip -selection clipboard", NULL };
|
||||||
|
static const char *volmutecmd[] = { "wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle", NULL };
|
||||||
|
static const char *micmutecmd[] = { "wpctl", "set-mute", "@DEFAULT_AUDIO_SOURCE@", "toggle", NULL };
|
||||||
|
static const char *volupcmd[] = { "sh", "-c", "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+", NULL };
|
||||||
|
static const char *voldowncmd[] = { "wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%-", NULL };
|
||||||
|
|
||||||
|
/* vieworspawn: monitor, tag (1-based), class, cmd... */
|
||||||
|
static const char *termvos[] = { "vieworspawn", "0", "10", "st-256color", "st", NULL };
|
||||||
|
static const char *filesvos[] = { "vieworspawn", "0", "11", "Thunar", "thunar", NULL };
|
||||||
|
static const char *editorvos[] = { "vieworspawn", "1", "14", "dev.zed.Zed", "zeditor", NULL };
|
||||||
|
static const char *freecadvos[] = { "vieworspawn", "1", "15", "FreeCAD", "FreeCAD", "--single-instance", NULL };
|
||||||
|
static const char *bambuvos[] = { "vieworspawn", "1", "19", "BambuStudio", "bambu-studio", NULL };
|
||||||
|
|
||||||
|
/* fallback spawn commands */
|
||||||
|
static const char *termcmd[] = { "st", NULL };
|
||||||
|
static const char *filescmd[] = { "thunar", NULL };
|
||||||
|
static const char *editorcmd[] = { "zeditor", NULL };
|
||||||
|
static const char *freecadcmd[] = { "FreeCAD", "--single-instance", NULL };
|
||||||
|
static const char *bambucmd[] = { "bambu-studio", NULL };
|
||||||
|
|
||||||
|
static const Key keys[] = {
|
||||||
|
/* modifier key function argument */
|
||||||
|
|
||||||
|
/* Rofi */
|
||||||
|
{ MODKEY, XK_space, spawn, {.v = roficmd } },
|
||||||
|
{ MODKEY|Mod1Mask, XK_space, spawn, {.v = rofiwebcmd } },
|
||||||
|
|
||||||
|
/* Terminal */
|
||||||
|
{ MODKEY, XK_a, spawn, {.v = termvos } },
|
||||||
|
{ MODKEY|ShiftMask, XK_a, spawn, {.v = termcmd } },
|
||||||
|
|
||||||
|
/* Zed (code) */
|
||||||
|
{ MODKEY, XK_z, spawn, {.v = editorvos } },
|
||||||
|
{ MODKEY|ShiftMask, XK_z, spawn, {.v = editorcmd } },
|
||||||
|
|
||||||
|
/* Zen Browser (web) */
|
||||||
|
{ MODKEY, XK_x, view, {.ui = 1 << 12 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_x, spawn, {.v = browsercmd } },
|
||||||
|
|
||||||
|
/* Thunar (files) */
|
||||||
|
{ MODKEY, XK_n, spawn, {.v = filesvos } },
|
||||||
|
{ MODKEY|ShiftMask, XK_n, spawn, {.v = filescmd } },
|
||||||
|
|
||||||
|
/* Video */
|
||||||
|
{ MODKEY, XK_m, view, {.ui = 1 << 11 } },
|
||||||
|
|
||||||
|
/* Lock */
|
||||||
|
{ MODKEY, XK_Escape, spawn, {.v = lockcmd } },
|
||||||
|
|
||||||
|
/* KiCad */
|
||||||
|
{ MODKEY, XK_k, spawn, {.v = kicadshowcmd } },
|
||||||
|
{ MODKEY|ShiftMask, XK_k, spawn, {.v = kicadprojectscmd } },
|
||||||
|
{ MODKEY, XK_l, spawn, {.v = kicadlibcmd } },
|
||||||
|
{ MODKEY|ControlMask, XK_k, view, {.ui = 1 << 15 } },
|
||||||
|
{ MODKEY|Mod1Mask, XK_k, spawn, {.v = kicadswapcmd } },
|
||||||
|
{ MODKEY, XK_bracketright, spawn, {.v = kicadcyclefcmd } },
|
||||||
|
{ MODKEY, XK_bracketleft, spawn, {.v = kicadcyclebcmd } },
|
||||||
|
|
||||||
|
/* FreeCAD */
|
||||||
|
{ MODKEY, XK_f, spawn, {.v = freecadvos } },
|
||||||
|
{ MODKEY|ShiftMask, XK_f, spawn, {.v = freecadcmd } },
|
||||||
|
|
||||||
|
/* Bambu Studio */
|
||||||
|
{ MODKEY, XK_p, spawn, {.v = bambuvos } },
|
||||||
|
{ MODKEY|ShiftMask, XK_p, spawn, {.v = bambucmd } },
|
||||||
|
|
||||||
|
/* Window management */
|
||||||
|
{ MODKEY, XK_q, killclient, {0} },
|
||||||
|
{ MODKEY, XK_e, togglefloating, {0} },
|
||||||
|
{ MODKEY, XK_w, togglefullscr, {0} },
|
||||||
|
{ MODKEY, XK_t, tabmode, {-1} },
|
||||||
|
|
||||||
|
/* Focus movement - stack */
|
||||||
|
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_j, focusstack, {.i = -1 } },
|
||||||
|
|
||||||
|
/* Adjacent tags - Up/Down */
|
||||||
|
{ MODKEY, XK_Up, viewprev, {0} },
|
||||||
|
{ MODKEY, XK_Down, viewnext, {0} },
|
||||||
|
{ MODKEY|ShiftMask, XK_Up, tagtoprev, {0} },
|
||||||
|
{ MODKEY|ShiftMask, XK_Down, tagtonext, {0} },
|
||||||
|
|
||||||
|
/* Move to monitor */
|
||||||
|
{ MODKEY, XK_Left, focusnthmon, {.i = 1 } },
|
||||||
|
{ MODKEY, XK_Right, focusnthmon, {.i = 0 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_Left, tagnthmon, {.i = 1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_Right, tagnthmon, {.i = 0 } },
|
||||||
|
|
||||||
|
/* Swap monitors */
|
||||||
|
{ MODKEY|ShiftMask, XK_apostrophe, swapmon, {0} },
|
||||||
|
|
||||||
|
/* Resize master */
|
||||||
|
{ MODKEY|Mod1Mask, XK_Left, setmfact, {.f = -0.05} },
|
||||||
|
{ MODKEY|Mod1Mask, XK_Right, setmfact, {.f = +0.05} },
|
||||||
|
|
||||||
|
/* Tags */
|
||||||
|
TAGKEYS( XK_1, 0)
|
||||||
|
TAGKEYS( XK_2, 1)
|
||||||
|
TAGKEYS( XK_3, 2)
|
||||||
|
TAGKEYS( XK_4, 3)
|
||||||
|
TAGKEYS( XK_5, 4)
|
||||||
|
TAGKEYS( XK_6, 5)
|
||||||
|
TAGKEYS( XK_7, 6)
|
||||||
|
TAGKEYS( XK_8, 7)
|
||||||
|
TAGKEYS( XK_9, 8)
|
||||||
|
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||||
|
|
||||||
|
/* Clipboard */
|
||||||
|
{ MODKEY|ShiftMask, XK_v, spawn, {.v = cliphistcmd } },
|
||||||
|
|
||||||
|
/* Screenshots */
|
||||||
|
{ 0, XK_Print, spawn, {.v = screenshotcmd } },
|
||||||
|
{ ShiftMask, XK_Print, spawn, {.v = screenshotfullcmd } },
|
||||||
|
|
||||||
|
/* Media keys */
|
||||||
|
{ 0, XF86XK_AudioMute, spawn, {.v = volmutecmd } },
|
||||||
|
{ 0, XF86XK_AudioMicMute, spawn, {.v = micmutecmd } },
|
||||||
|
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = volupcmd } },
|
||||||
|
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = voldowncmd } },
|
||||||
|
|
||||||
|
/* Holdbar */
|
||||||
|
{ 0, HOLDKEY, holdbar, {0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* button definitions */
|
||||||
|
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||||
|
static const Button buttons[] = {
|
||||||
|
/* click event mask button function argument */
|
||||||
|
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||||
|
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||||
|
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||||
|
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||||
|
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||||
|
{ ClkTagBar, 0, Button1, view, {0} },
|
||||||
|
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
|
||||||
|
{ ClkTabBar, 0, Button1, focuswin, {0} },
|
||||||
|
/* Scroll through tags with Mod+scroll */
|
||||||
|
{ ClkRootWin, MODKEY, Button4, viewprev, {0} },
|
||||||
|
{ ClkRootWin, MODKEY, Button5, viewnext, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button4, viewprev, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button5, viewnext, {0} },
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
}
|
||||||
49
Suckless/dwm/layouts.nix
Normal file
49
Suckless/dwm/layouts.nix
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# dwm layouts
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Layout indices: 0 = tile, 1 = floating, 2 = monocle
|
||||||
|
defLayouts = [
|
||||||
|
0 # index 0: all-tags view
|
||||||
|
0 # tag 1
|
||||||
|
0 # tag 2
|
||||||
|
0 # tag 3
|
||||||
|
0 # tag 4
|
||||||
|
0 # tag 5
|
||||||
|
0 # tag 6
|
||||||
|
0 # tag 7
|
||||||
|
0 # tag 8
|
||||||
|
0 # tag 9
|
||||||
|
2 # tag 10: terminal
|
||||||
|
2 # tag 11: files
|
||||||
|
2 # tag 12: video
|
||||||
|
2 # tag 13: web/browser
|
||||||
|
2 # tag 14: code
|
||||||
|
2 # tag 15: freecad
|
||||||
|
2 # tag 16: kicad project manager
|
||||||
|
2 # tag 17: kicad (sch/pcb editors)
|
||||||
|
2 # tag 18: kicad-aux (pcb/footprint mobile)
|
||||||
|
2 # tag 19: bambu studio
|
||||||
|
];
|
||||||
|
defLayoutsStr = lib.concatMapStringsSep ", " toString defLayouts;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
/* layout(s) */
|
||||||
|
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||||
|
static const int nmaster = 1; /* number of clients in master area */
|
||||||
|
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
|
||||||
|
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||||
|
|
||||||
|
static const Layout layouts[] = {
|
||||||
|
/* symbol arrange function */
|
||||||
|
{ "[]=", tile }, /* 0: first entry is default */
|
||||||
|
{ "><>", NULL }, /* 1: floating */
|
||||||
|
{ "[M]", monocle }, /* 2: monocle (tabbed) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* default layout per tag */
|
||||||
|
/* 0 = tile, 1 = floating, 2 = monocle */
|
||||||
|
static int def_layouts[1 + LENGTH(tags)] = { ${defLayoutsStr} };
|
||||||
|
'';
|
||||||
|
}
|
||||||
41
Suckless/dwm/rules.nix
Normal file
41
Suckless/dwm/rules.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# dwm window rules
|
||||||
|
# Tag mapping: 1<<9=term, 1<<10=files, 1<<11=video, 1<<12=web, 1<<13=code,
|
||||||
|
# 1<<14=freecad, 1<<15=kicad-pm, 1<<16=kicad, 1<<17=kicad-aux
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
static const Rule rules[] = {
|
||||||
|
/* xprop(1):
|
||||||
|
* WM_CLASS(STRING) = instance, class
|
||||||
|
* WM_NAME(STRING) = title
|
||||||
|
*/
|
||||||
|
/* class instance title tags mask isfloating monitor */
|
||||||
|
{ "Polkit-gnome-authentication-agent-1", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ "KeePassXC", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "Picture-in-Picture", 0, 1, -1 },
|
||||||
|
{ "slint-viewer", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ "LVGL Simulator", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "Axium Browser", 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "Axium", 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "Fex", 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "@", 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "OSM", 0, 1, -1 },
|
||||||
|
{ NULL, NULL, "YouNix", 0, 1, -1 },
|
||||||
|
{ "st-256color", NULL, NULL, 1 << 9, 0, 0 }, /* terminal */
|
||||||
|
{ "Thunar", NULL, NULL, 1 << 10, 0, 0 }, /* files */
|
||||||
|
{ "haruna", NULL, NULL, 1 << 11, 0, 1 }, /* video */
|
||||||
|
{ "zen-twilight", NULL, "Zen Twilight", 1 << 12, 0, 1 }, /* web */
|
||||||
|
{ "dev.zed.Zed", NULL, NULL, 1 << 13, 0, 1 }, /* code */
|
||||||
|
{ "FreeCAD", NULL, "Expression editor", 0, 1, -1 }, /* freecad formula popup */
|
||||||
|
{ "FreeCAD", NULL, "Insert length", 0, 1, -1 }, /* freecad dimension popup */
|
||||||
|
{ "FreeCAD", NULL, NULL, 1 << 14, 0, 1 }, /* freecad */
|
||||||
|
{ "KiCad", NULL, "KiCad 9", 1 << 15, 0, 0 }, /* kicad-pm: tag 16 */
|
||||||
|
{ "KiCad", NULL, "Schematic Editor", 1 << 16, 0, 0 }, /* kicad: tag 17, mon 0 */
|
||||||
|
{ "KiCad", NULL, "Symbol Editor", 1 << 16, 0, 0 }, /* kicad: tag 17, mon 0 */
|
||||||
|
{ "KiCad", NULL, "PCB Editor", 1 << 16, 0, 1 }, /* kicad: tag 17, mon 1 */
|
||||||
|
{ "KiCad", NULL, "Footprint Editor", 1 << 16, 0, 1 }, /* kicad: tag 17, mon 1 */
|
||||||
|
{ "BambuStudio", NULL, NULL, 1 << 18, 0, 1 }, /* bambu studio */
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
}
|
||||||
33
Suckless/dwm/tags.nix
Normal file
33
Suckless/dwm/tags.nix
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# dwm tag names (Nerd Font icons for special workspaces)
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
tags = [
|
||||||
|
"1"
|
||||||
|
"2"
|
||||||
|
"3"
|
||||||
|
"4"
|
||||||
|
"5"
|
||||||
|
"6"
|
||||||
|
"7"
|
||||||
|
"8"
|
||||||
|
"9"
|
||||||
|
"" # 10: terminal
|
||||||
|
"" # 11: files
|
||||||
|
"" # 12: video
|
||||||
|
"" # 13: web/browser
|
||||||
|
"" # 14: code
|
||||||
|
"" # 15: freecad
|
||||||
|
"" # 16: kicad project manager
|
||||||
|
"" # 17: kicad (sch/pcb editors)
|
||||||
|
"" # 18: kicad-aux (pcb/footprint mobile)
|
||||||
|
"" # 19: bambu studio
|
||||||
|
];
|
||||||
|
tagsStr = lib.concatMapStringsSep ", " (t: ''"${t}"'') tags;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = ''
|
||||||
|
/* tagging */
|
||||||
|
static const char *tags[] = { ${tagsStr} };
|
||||||
|
'';
|
||||||
|
}
|
||||||
144
Suckless/home.nix
Normal file
144
Suckless/home.nix
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
# Suckless home-manager configuration
|
||||||
|
# X11-specific settings that integrate with home-manager
|
||||||
|
{ pkgs-stable, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Monitor management
|
||||||
|
programs.autorandr = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.autorandr;
|
||||||
|
hooks.postswitch = {
|
||||||
|
"set-xft-dpi" = "echo 'Xft.dpi: 96' | xrdb -merge";
|
||||||
|
"set-wallpaper" = ''
|
||||||
|
case "$AUTORANDR_CURRENT_PROFILE" in
|
||||||
|
docked)
|
||||||
|
xwallpaper --output eDP-1 --zoom ~/NixOS/Wallpapers/pearl.jpg --output DP-3 --zoom ~/NixOS/Wallpapers/siege.png
|
||||||
|
;;
|
||||||
|
mobile)
|
||||||
|
xwallpaper --output eDP-1 --zoom ~/NixOS/Wallpapers/siege.png
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
profiles = {
|
||||||
|
"docked" = {
|
||||||
|
fingerprint = {
|
||||||
|
eDP-1 = "00ffffffffffff002c831207000000001d220104a51e1378025645935e5b9325185054000000010101010101010101010101010101010f3c80a070b0204018303c002ebd10000018000000000000000000000000000000000000000000000000000000000000000000000000000000fe004b443134304e3336333041303100df";
|
||||||
|
DP-3 = "00ffffffffffff0061a906b00100000025220103803c2278afa545ad504da6260c5054a5cb0081809500a9c0b300d1c0010101010101023a801871382d40582c450055502100001e000000ff0035333738323030303434353132000000fd0030a561ba3c000a202020202020000000fc005032374642422d52410a20202001c0020319b349010311130414051f90e200ca67030c00100038448e4480a070382d40582c450055502100001e605980a0703814403024350055502100001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050";
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
DP-3 = {
|
||||||
|
enable = true;
|
||||||
|
primary = false;
|
||||||
|
mode = "1920x1080";
|
||||||
|
rate = "75.00";
|
||||||
|
dpi = 96;
|
||||||
|
position = "0x180";
|
||||||
|
};
|
||||||
|
eDP-1 = {
|
||||||
|
enable = true;
|
||||||
|
primary = true;
|
||||||
|
mode = "1920x1200";
|
||||||
|
rate = "60.00";
|
||||||
|
dpi = 96;
|
||||||
|
position = "1920x0";
|
||||||
|
rotate = "left";
|
||||||
|
scale = {
|
||||||
|
x = 0.75;
|
||||||
|
y = 0.75;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"mobile" = {
|
||||||
|
fingerprint = {
|
||||||
|
eDP-1 = "00ffffffffffff002c831207000000001d220104a51e1378025645935e5b9325185054000000010101010101010101010101010101010f3c80a070b0204018303c002ebd10000018000000000000000000000000000000000000000000000000000000000000000000000000000000fe004b443134304e3336333041303100df";
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
eDP-1 = {
|
||||||
|
enable = true;
|
||||||
|
primary = true;
|
||||||
|
mode = "1920x1200";
|
||||||
|
rate = "60.00";
|
||||||
|
dpi = 96;
|
||||||
|
position = "0x0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.autorandr = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.autorandr;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Screenshots
|
||||||
|
services.flameshot = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.flameshot;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Touchpad gestures (for mobile mode)
|
||||||
|
home.file.".config/libinput-gestures.conf".text = ''
|
||||||
|
# 3-finger up/down: tag navigation
|
||||||
|
gesture swipe up 3 sh -c 'echo "view-prev" > /tmp/dwm.fifo'
|
||||||
|
gesture swipe down 3 sh -c 'echo "view-next" > /tmp/dwm.fifo'
|
||||||
|
|
||||||
|
# 3-finger left/right: window cycling
|
||||||
|
gesture swipe left 3 sh -c 'echo "focus-prev" > /tmp/dwm.fifo'
|
||||||
|
gesture swipe right 3 sh -c 'echo "focus-next" > /tmp/dwm.fifo'
|
||||||
|
|
||||||
|
# 4-finger up/down: layout
|
||||||
|
gesture swipe up 4 sh -c 'echo "layout-mono" > /tmp/dwm.fifo'
|
||||||
|
gesture swipe down 4 sh -c 'echo "layout-tile" > /tmp/dwm.fifo'
|
||||||
|
|
||||||
|
# Pinch: rofi system menu / view all
|
||||||
|
gesture pinch in rofi -show system
|
||||||
|
gesture pinch out sh -c 'echo "view-all" > /tmp/dwm.fifo'
|
||||||
|
'';
|
||||||
|
|
||||||
|
# X11 startup script
|
||||||
|
home.file.".xinitrc".text = ''
|
||||||
|
# D-Bus environment for GTK apps (fixes slow first launch)
|
||||||
|
dbus-update-activation-environment --systemd DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY
|
||||||
|
|
||||||
|
# Apply monitor profile
|
||||||
|
autorandr --change --default mobile
|
||||||
|
|
||||||
|
# Disable DPMS and screen blanking
|
||||||
|
xset s off
|
||||||
|
xset -dpms
|
||||||
|
xset s noblank
|
||||||
|
|
||||||
|
# Numlock on
|
||||||
|
numlockx
|
||||||
|
|
||||||
|
# Status bar
|
||||||
|
slstatus &
|
||||||
|
|
||||||
|
# Compositor
|
||||||
|
# picom &
|
||||||
|
|
||||||
|
# Touchpad gestures
|
||||||
|
libinput-gestures-setup start &
|
||||||
|
|
||||||
|
# Auto-rotate
|
||||||
|
auto-rotate &
|
||||||
|
|
||||||
|
# KeePassXC (minimized, ready for browser extension)
|
||||||
|
keepassxc --minimized &
|
||||||
|
|
||||||
|
# Create dwmfifo for IPC
|
||||||
|
mkfifo /tmp/dwm.fifo 2>/dev/null || true
|
||||||
|
|
||||||
|
# Start dwm
|
||||||
|
exec dwm
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Auto-start X11/dwm on tty1
|
||||||
|
programs.bash.profileExtra = ''
|
||||||
|
if [ -z "$DISPLAY" ] && [ "$XDG_VTNR" = 1 ]; then
|
||||||
|
exec startx
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
93
Suckless/slstatus.nix
Normal file
93
Suckless/slstatus.nix
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
# slstatus - suckless status bar
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Dynamic icon scripts
|
||||||
|
batteryScript = pkgs.writeShellScript "slstatus-battery" ''
|
||||||
|
perc=$(cat /sys/class/power_supply/BATT/capacity 2>/dev/null || echo "0")
|
||||||
|
status=$(cat /sys/class/power_supply/BATT/status 2>/dev/null || echo "Unknown")
|
||||||
|
|
||||||
|
if [ "$status" = "Charging" ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 90 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 80 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 70 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 60 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 50 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 40 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 30 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 20 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 10 ]; then icon=""
|
||||||
|
else icon=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s %s%%" "$icon" "$perc"
|
||||||
|
'';
|
||||||
|
|
||||||
|
mouseScript = pkgs.writeShellScript "slstatus-mouse" ''
|
||||||
|
perc=$(cat /sys/class/power_supply/hidpp_battery_0/capacity 2>/dev/null || echo "")
|
||||||
|
[ -z "$perc" ] && exit 0
|
||||||
|
printf " %s%%" "$perc"
|
||||||
|
'';
|
||||||
|
|
||||||
|
volumeScript = pkgs.writeShellScript "slstatus-volume" ''
|
||||||
|
vol=$(${pkgs.wireplumber}/bin/wpctl get-volume @DEFAULT_AUDIO_SINK@ 2>/dev/null)
|
||||||
|
muted=$(echo "$vol" | grep -c MUTED)
|
||||||
|
perc=$(echo "$vol" | awk '{printf "%.0f", $2*100}')
|
||||||
|
|
||||||
|
if [ "$muted" -eq 1 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 66 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 33 ]; then icon=""
|
||||||
|
else icon=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s %s%%" "$icon" "$perc"
|
||||||
|
'';
|
||||||
|
|
||||||
|
wifiScript = pkgs.writeShellScript "slstatus-wifi" ''
|
||||||
|
essid=$(cat /sys/class/net/wlp2s0/wireless/../uevent 2>/dev/null | grep INTERFACE | cut -d= -f2)
|
||||||
|
essid=$(${pkgs.iw}/bin/iw dev wlp2s0 link 2>/dev/null | grep SSID | awk '{print $2}')
|
||||||
|
[ -z "$essid" ] && exit 0
|
||||||
|
|
||||||
|
perc=$(awk 'NR==3 {printf "%.0f", $3*100/70}' /proc/net/wireless 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [ "$perc" -ge 75 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 50 ]; then icon=""
|
||||||
|
elif [ "$perc" -ge 25 ]; then icon=""
|
||||||
|
else icon=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s %s %s%%" "$icon" "$essid" "$perc"
|
||||||
|
'';
|
||||||
|
|
||||||
|
config = ''
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
/* interval between updates (in ms) */
|
||||||
|
const unsigned int interval = 1000;
|
||||||
|
|
||||||
|
/* text to show if no value can be retrieved */
|
||||||
|
static const char unknown_str[] = "";
|
||||||
|
|
||||||
|
/* maximum output string length */
|
||||||
|
#define MAXLEN 512
|
||||||
|
|
||||||
|
static const struct arg args[] = {
|
||||||
|
/* function format argument */
|
||||||
|
{ cpu_freq, " %s/", NULL },
|
||||||
|
{ cpu_perc, "%s%% | ", NULL },
|
||||||
|
{ ram_used, " %s/", NULL },
|
||||||
|
{ ram_perc, "%s%% | ", NULL },
|
||||||
|
{ temp, " %s°C | ", "/sys/class/thermal/thermal_zone0/temp" },
|
||||||
|
{ run_command, "%s | ", "${wifiScript}" },
|
||||||
|
{ run_command, "%s | ", "${volumeScript}" },
|
||||||
|
{ run_command, "%s | ", "${batteryScript}" },
|
||||||
|
{ run_command, "%s | ", "${mouseScript}" },
|
||||||
|
{ datetime, " %s ", "%d/%m %H:%M:%S" },
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.systemPackages = [
|
||||||
|
(pkgs.slstatus.override { conf = config; })
|
||||||
|
];
|
||||||
|
}
|
||||||
46
Suckless/st/appearance.nix
Normal file
46
Suckless/st/appearance.nix
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# st appearance settings
|
||||||
|
{ config, lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
colors = config.lib.stylix.colors;
|
||||||
|
fonts = config.stylix.fonts;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
font = "${fonts.monospace.name}:pixelsize=${
|
||||||
|
toString (fonts.sizes.terminal + 6)
|
||||||
|
}:antialias=true:autohint=true";
|
||||||
|
alpha = "0.9";
|
||||||
|
|
||||||
|
colorsSed = ''
|
||||||
|
sed -i '/static const char \*colorname\[\]/,/^};/c\
|
||||||
|
static const char *colorname[] = {\
|
||||||
|
/* 8 normal colors */\
|
||||||
|
"#${colors.base00}",\
|
||||||
|
"#${colors.base08}",\
|
||||||
|
"#${colors.base0B}",\
|
||||||
|
"#${colors.base0A}",\
|
||||||
|
"#${colors.base0D}",\
|
||||||
|
"#${colors.base0E}",\
|
||||||
|
"#${colors.base0C}",\
|
||||||
|
"#${colors.base05}",\
|
||||||
|
\
|
||||||
|
/* 8 bright colors */\
|
||||||
|
"#${colors.base03}",\
|
||||||
|
"#${colors.base08}",\
|
||||||
|
"#${colors.base0B}",\
|
||||||
|
"#${colors.base0A}",\
|
||||||
|
"#${colors.base0D}",\
|
||||||
|
"#${colors.base0E}",\
|
||||||
|
"#${colors.base0C}",\
|
||||||
|
"#${colors.base07}",\
|
||||||
|
\
|
||||||
|
[255] = 0,\
|
||||||
|
\
|
||||||
|
/* more colors can be added after 255 to use with DefaultXX */\
|
||||||
|
"#${colors.base04}", /* 256: cursor */\
|
||||||
|
"#${colors.base03}", /* 257: reverse cursor */\
|
||||||
|
"#${colors.base05}", /* 258: foreground */\
|
||||||
|
"#${colors.base00}", /* 259: background */\
|
||||||
|
};' config.def.h
|
||||||
|
'';
|
||||||
|
}
|
||||||
69
Suckless/st/st.nix
Normal file
69
Suckless/st/st.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# st terminal configuration
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
appearance = import ./appearance.nix { inherit config lib; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [(final: prev: {
|
||||||
|
st = prev.st.overrideAttrs (oldAttrs: {
|
||||||
|
buildInputs = oldAttrs.buildInputs ++ [ final.harfbuzz ];
|
||||||
|
patches = (oldAttrs.patches or []) ++ [
|
||||||
|
# Scrollback (ringbuffer + float + mouse)
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/scrollback/st-scrollback-ringbuffer-0.9.2.diff";
|
||||||
|
sha256 = "1r23q4mi5bkam49ld5c3ccwaa1li7bbjx0ndjgm207p02az9h4cn";
|
||||||
|
})
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/scrollback/st-scrollback-float-0.9.2.diff";
|
||||||
|
sha256 = "01r1gdgkcpf9194257myjnr5nn1fj1baj13wjm9rf2nclbagifgm";
|
||||||
|
})
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/scrollback/st-scrollback-mouse-0.9.2.diff";
|
||||||
|
sha256 = "068s5rjvvw2174y34i5xxvpw4jvjy58akd1kgf025h1153hmf7jy";
|
||||||
|
})
|
||||||
|
# Alpha (transparency)
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/alpha/st-alpha-20240814-a0274bc.diff";
|
||||||
|
sha256 = "0hld9dwkk7i1f0z0k9biigx2g4wzlqa2yb7vdn5rrf6ymr5nlbsn";
|
||||||
|
})
|
||||||
|
# Anysize (no gaps)
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/anysize/st-expected-anysize-0.9.diff";
|
||||||
|
sha256 = "04gvkf80lhaiwyv3m7fdkf81msf8al1kfb7inx1bf02ygx9152v2";
|
||||||
|
})
|
||||||
|
# Bold is not bright
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/bold-is-not-bright/st-bold-is-not-bright-20190127-3be4cf1.diff";
|
||||||
|
sha256 = "1cpap2jz80n90izhq5fdv2cvg29hj6bhhvjxk40zkskwmjn6k49j";
|
||||||
|
})
|
||||||
|
# Clipboard
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/clipboard/st-clipboard-0.8.3.diff";
|
||||||
|
sha256 = "1h1nwilwws02h2lnxzmrzr69lyh6pwsym21hvalp9kmbacwy6p0g";
|
||||||
|
})
|
||||||
|
# Ligatures (scrollback-ringbuffer variant)
|
||||||
|
(final.fetchurl {
|
||||||
|
url = "https://st.suckless.org/patches/ligatures/0.9.3/st-ligatures-scrollback-ringbuffer-20251007-0.9.3.diff";
|
||||||
|
sha256 = "0c2w1p0siafiyarfx6skdighwzw29d1mydpjfrwgrvdsywwyq2di";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
postPatch = (oldAttrs.postPatch or "") + ''
|
||||||
|
# Font
|
||||||
|
substituteInPlace config.def.h \
|
||||||
|
--replace '"Liberation Mono:pixelsize=12:antialias=true:autohint=true"' \
|
||||||
|
'"${appearance.font}"'
|
||||||
|
|
||||||
|
# Alpha
|
||||||
|
substituteInPlace config.def.h \
|
||||||
|
--replace 'float alpha = 0.8;' \
|
||||||
|
'float alpha = ${appearance.alpha};'
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
${appearance.colorsSed}
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
})];
|
||||||
|
|
||||||
|
environment.systemPackages = [ pkgs.st ];
|
||||||
|
}
|
||||||
121
Suckless/suckless.nix
Normal file
121
Suckless/suckless.nix
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
# Suckless configuration entry point
|
||||||
|
# X11 window manager setup with dwm, st, and related tools
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./dwm/dwm.nix
|
||||||
|
./st/st.nix
|
||||||
|
./slstatus.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# X11 Display Server
|
||||||
|
# ============================================================================
|
||||||
|
services.xserver = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Keyboard layout
|
||||||
|
xkb.layout = "us";
|
||||||
|
|
||||||
|
displayManager.startx.enable = true;
|
||||||
|
|
||||||
|
# Auto-lock after 10 minutes of inactivity
|
||||||
|
xautolock = {
|
||||||
|
enable = true;
|
||||||
|
time = 10;
|
||||||
|
locker = "${pkgs.slock}/bin/slock";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Input (libinput)
|
||||||
|
services.libinput.enable = true;
|
||||||
|
|
||||||
|
# Tablet/stylus support
|
||||||
|
services.xserver.wacom.enable = true;
|
||||||
|
|
||||||
|
# Accelerometer for auto-rotation
|
||||||
|
hardware.sensor.iio.enable = true;
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Screen Locker
|
||||||
|
# ============================================================================
|
||||||
|
programs.slock = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.slock;
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# XDG Portal for X11
|
||||||
|
# ============================================================================
|
||||||
|
xdg.portal = {
|
||||||
|
enable = true;
|
||||||
|
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
|
||||||
|
config.common.default = "gtk";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# X11 ecosystem packages
|
||||||
|
# ============================================================================
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
# Clipboard
|
||||||
|
xclip
|
||||||
|
|
||||||
|
# Wallpaper
|
||||||
|
xwallpaper
|
||||||
|
|
||||||
|
# Numlock on startup
|
||||||
|
numlockx
|
||||||
|
|
||||||
|
# Touchpad gestures
|
||||||
|
libinput-gestures
|
||||||
|
|
||||||
|
# Auto-rotate based on accelerometer (with wallpaper switching, mobile only)
|
||||||
|
(writeShellScriptBin "auto-rotate" ''
|
||||||
|
export DISPLAY=''${DISPLAY:-:0}
|
||||||
|
WALLPAPER_DIR="$HOME/NixOS/Wallpapers"
|
||||||
|
|
||||||
|
${iio-sensor-proxy}/bin/monitor-sensor | while read -r line; do
|
||||||
|
# Skip rotation when docked (would mess up monitor positions)
|
||||||
|
[[ $(${autorandr}/bin/autorandr --detected) != "mobile" ]] && continue
|
||||||
|
|
||||||
|
case "$line" in
|
||||||
|
*"normal"*)
|
||||||
|
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate normal
|
||||||
|
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/siege.png"
|
||||||
|
;;
|
||||||
|
*"left-up"*)
|
||||||
|
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate left
|
||||||
|
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/pearl.jpg"
|
||||||
|
;;
|
||||||
|
*"right-up"*)
|
||||||
|
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate right
|
||||||
|
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/pearl.jpg"
|
||||||
|
;;
|
||||||
|
*"bottom-up"*)
|
||||||
|
${xorg.xrandr}/bin/xrandr --output eDP-1 --rotate inverted
|
||||||
|
${xwallpaper}/bin/xwallpaper --output eDP-1 --zoom "$WALLPAPER_DIR/siege.png"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Polkit authentication agent
|
||||||
|
# ============================================================================
|
||||||
|
security.polkit.enable = true;
|
||||||
|
systemd.user.services.polkit-gnome-authentication-agent-1 = {
|
||||||
|
description = "polkit-gnome-authentication-agent-1";
|
||||||
|
wantedBy = [ "graphical-session.target" ];
|
||||||
|
wants = [ "graphical-session.target" ];
|
||||||
|
after = [ "graphical-session.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 1;
|
||||||
|
TimeoutStopSec = 10;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
Wallpapers/Shift.png
Executable file
BIN
Wallpapers/Shift.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 573 KiB |
BIN
Wallpapers/caesar.png
Normal file
BIN
Wallpapers/caesar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4 MiB |
BIN
Wallpapers/norse.png
Normal file
BIN
Wallpapers/norse.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
BIN
Wallpapers/pearl.jpg
Normal file
BIN
Wallpapers/pearl.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3 MiB |
BIN
Wallpapers/shift_base.png
Executable file
BIN
Wallpapers/shift_base.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 606 KiB |
BIN
Wallpapers/siege.png
Normal file
BIN
Wallpapers/siege.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 MiB |
176
configuration.nix
Executable file
176
configuration.nix
Executable file
|
|
@ -0,0 +1,176 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix
|
||||||
|
./stylix.nix
|
||||||
|
# ./Hyprsuck/hyprsuck.nix
|
||||||
|
./Suckless/suckless.nix
|
||||||
|
./ryzenadj.nix
|
||||||
|
# ./virtualisation.nix
|
||||||
|
# ./Hetzner/setup.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
nix.settings = {
|
||||||
|
experimental-features = [
|
||||||
|
"nix-command"
|
||||||
|
"flakes"
|
||||||
|
];
|
||||||
|
# Axium binary caches
|
||||||
|
substituters = [
|
||||||
|
"https://cache.nixos.org"
|
||||||
|
"https://axium.cachix.org"
|
||||||
|
"https://cache.axiomania.org/main"
|
||||||
|
];
|
||||||
|
|
||||||
|
http-connections = 128;
|
||||||
|
max-substitution-jobs = 128;
|
||||||
|
max-jobs = "auto";
|
||||||
|
|
||||||
|
trusted-public-keys = [
|
||||||
|
"axium.cachix.org-1:BfzPfRTbbCYmaQrVLSWchgsR4ScA9ZCZ389FyWspUH8="
|
||||||
|
"main:Uz5F0MbXItVx2XCmBbEAMmQ0T6+DZDgLaXWalh1k++o="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nix.distributedBuilds = true;
|
||||||
|
|
||||||
|
# Required for home-manager xdg.portal with useUserPackages
|
||||||
|
environment.pathsToLink = [
|
||||||
|
"/share/applications"
|
||||||
|
"/share/xdg-desktop-portal"
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
boot.loader.systemd-boot.configurationLimit = 10;
|
||||||
|
boot.loader.timeout = 1;
|
||||||
|
|
||||||
|
networking.hostName = "v3";
|
||||||
|
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
hardware.bluetooth.enable = true;
|
||||||
|
|
||||||
|
time.timeZone = "Asia/Ho_Chi_Minh";
|
||||||
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
i18n.extraLocaleSettings = {
|
||||||
|
LC_ADDRESS = "en_US.UTF-8";
|
||||||
|
LC_IDENTIFICATION = "en_US.UTF-8";
|
||||||
|
LC_MEASUREMENT = "en_US.UTF-8";
|
||||||
|
LC_MONETARY = "en_US.UTF-8";
|
||||||
|
LC_NAME = "en_US.UTF-8";
|
||||||
|
LC_NUMERIC = "en_US.UTF-8";
|
||||||
|
LC_PAPER = "en_US.UTF-8";
|
||||||
|
LC_TELEPHONE = "en_US.UTF-8";
|
||||||
|
LC_TIME = "en_US.UTF-8";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.getty.autologinUser = "lebowski";
|
||||||
|
|
||||||
|
programs.nix-ld.enable = true;
|
||||||
|
|
||||||
|
services.pulseaudio.enable = false;
|
||||||
|
security.rtkit.enable = true;
|
||||||
|
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.lebowski = {
|
||||||
|
isNormalUser = true;
|
||||||
|
description = "Antoine Lespinasse";
|
||||||
|
extraGroups = [
|
||||||
|
"networkmanager"
|
||||||
|
"wheel"
|
||||||
|
"input"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# GVfs - for Nautilus trash, network shares, MTP devices
|
||||||
|
services.gvfs.enable = true;
|
||||||
|
|
||||||
|
# UPower - battery/power device monitoring
|
||||||
|
services.upower.enable = true;
|
||||||
|
|
||||||
|
# Power Profiles Daemon - power management (performance/balanced/power-saver)
|
||||||
|
services.power-profiles-daemon.enable = true;
|
||||||
|
|
||||||
|
# System packages (stable for core tools)
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
wget
|
||||||
|
git
|
||||||
|
bat
|
||||||
|
btop
|
||||||
|
ncdu
|
||||||
|
nmap
|
||||||
|
neofetch
|
||||||
|
xdotool
|
||||||
|
jq
|
||||||
|
attic-client
|
||||||
|
wireguard-tools
|
||||||
|
sox
|
||||||
|
|
||||||
|
ffmpegthumbnailer
|
||||||
|
gdk-pixbuf
|
||||||
|
librsvg
|
||||||
|
evince
|
||||||
|
libgsf
|
||||||
|
libjxl
|
||||||
|
libavif
|
||||||
|
|
||||||
|
# Disk utilities
|
||||||
|
gparted
|
||||||
|
gnome-disk-utility
|
||||||
|
|
||||||
|
# Image / PDF viewers
|
||||||
|
kdePackages.gwenview
|
||||||
|
kdePackages.okular
|
||||||
|
|
||||||
|
# File browser
|
||||||
|
xfce.thunar
|
||||||
|
xfce.thunar-volman
|
||||||
|
xfce.tumbler # thumbnails
|
||||||
|
];
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# WireGuard VPN profiles
|
||||||
|
# ============================================================================
|
||||||
|
# Generate keys: wg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
|
||||||
|
# Then add the public key as a peer on the VPS.
|
||||||
|
# Start/stop: sudo systemctl start/stop wg-quick-wg-services / wg-quick-wg-vpn
|
||||||
|
|
||||||
|
# Profile 1: Internal services only (split tunnel)
|
||||||
|
networking.wg-quick.interfaces.wg-services = {
|
||||||
|
autostart = false;
|
||||||
|
address = [ "10.100.0.2/24" ];
|
||||||
|
privateKeyFile = "/etc/wireguard/private.key";
|
||||||
|
peers = [{
|
||||||
|
publicKey = "F2hvz4vx9VrM6IZ2zMUG2FMPMCMwmfxGH9qocbe4q3U=";
|
||||||
|
endpoint = "178.104.15.221:51820";
|
||||||
|
allowedIPs = [ "10.100.0.0/24" "178.104.15.221/32" ];
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Profile 2: Full VPN + AdGuard DNS ad-blocking
|
||||||
|
networking.wg-quick.interfaces.wg-vpn = {
|
||||||
|
autostart = false;
|
||||||
|
address = [ "10.100.0.2/24" ];
|
||||||
|
dns = [ "10.100.0.1" ];
|
||||||
|
privateKeyFile = "/etc/wireguard/private.key";
|
||||||
|
peers = [{
|
||||||
|
publicKey = "F2hvz4vx9VrM6IZ2zMUG2FMPMCMwmfxGH9qocbe4q3U=";
|
||||||
|
endpoint = "178.104.15.221:51820";
|
||||||
|
allowedIPs = [ "0.0.0.0/0" ];
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
system.stateVersion = "25.11";
|
||||||
|
}
|
||||||
420
flake.lock
generated
Executable file
420
flake.lock
generated
Executable file
|
|
@ -0,0 +1,420 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"base16": {
|
||||||
|
"inputs": {
|
||||||
|
"fromYaml": "fromYaml"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1755819240,
|
||||||
|
"narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=",
|
||||||
|
"owner": "SenchoPens",
|
||||||
|
"repo": "base16.nix",
|
||||||
|
"rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "SenchoPens",
|
||||||
|
"repo": "base16.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"base16-fish": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765809053,
|
||||||
|
"narHash": "sha256-XCUQLoLfBJ8saWms2HCIj4NEN+xNsWBlU1NrEPcQG4s=",
|
||||||
|
"owner": "tomyun",
|
||||||
|
"repo": "base16-fish",
|
||||||
|
"rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tomyun",
|
||||||
|
"repo": "base16-fish",
|
||||||
|
"rev": "86cbea4dca62e08fb7fd83a70e96472f92574782",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"base16-helix": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1760703920,
|
||||||
|
"narHash": "sha256-m82fGUYns4uHd+ZTdoLX2vlHikzwzdu2s2rYM2bNwzw=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-helix",
|
||||||
|
"rev": "d646af9b7d14bff08824538164af99d0c521b185",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-helix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"base16-vim": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1732806396,
|
||||||
|
"narHash": "sha256-e0bpPySdJf0F68Ndanwm+KWHgQiZ0s7liLhvJSWDNsA=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-vim",
|
||||||
|
"rev": "577fe8125d74ff456cf942c733a85d769afe58b7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-vim",
|
||||||
|
"rev": "577fe8125d74ff456cf942c733a85d769afe58b7",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disko": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1773889306,
|
||||||
|
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"rev": "5ad85c82cc52264f4beddc934ba57f3789f28347",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"firefox-gnome-theme": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764873433,
|
||||||
|
"narHash": "sha256-1XPewtGMi+9wN9Ispoluxunw/RwozuTRVuuQOmxzt+A=",
|
||||||
|
"owner": "rafaelmardojai",
|
||||||
|
"repo": "firefox-gnome-theme",
|
||||||
|
"rev": "f7ffd917ac0d253dbd6a3bf3da06888f57c69f92",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "rafaelmardojai",
|
||||||
|
"repo": "firefox-gnome-theme",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"stylix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767609335,
|
||||||
|
"narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "250481aafeb741edfe23d29195671c19b36b6dca",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fromYaml": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731966426,
|
||||||
|
"narHash": "sha256-lq95WydhbUTWig/JpqiB7oViTcHFP8Lv41IGtayokA8=",
|
||||||
|
"owner": "SenchoPens",
|
||||||
|
"repo": "fromYaml",
|
||||||
|
"rev": "106af9e2f715e2d828df706c386a685698f3223b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "SenchoPens",
|
||||||
|
"repo": "fromYaml",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gnome-shell": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"host": "gitlab.gnome.org",
|
||||||
|
"lastModified": 1767737596,
|
||||||
|
"narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=",
|
||||||
|
"owner": "GNOME",
|
||||||
|
"repo": "gnome-shell",
|
||||||
|
"rev": "ef02db02bf0ff342734d525b5767814770d85b49",
|
||||||
|
"type": "gitlab"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"host": "gitlab.gnome.org",
|
||||||
|
"owner": "GNOME",
|
||||||
|
"ref": "gnome-49",
|
||||||
|
"repo": "gnome-shell",
|
||||||
|
"type": "gitlab"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1774738535,
|
||||||
|
"narHash": "sha256-2jfBEZUC67IlnxO5KItFCAd7Oc+1TvyV/jQlR+2ykGQ=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "769e07ef8f4cf7b1ec3b96ef015abec9bc6b1e2a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixos-hardware": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1766517411,
|
||||||
|
"narHash": "sha256-qilXvRpeyefgLRl1oyitQsacWGP5TrWf7f6V+KOUt38=",
|
||||||
|
"owner": "GammaKinematics",
|
||||||
|
"repo": "nixos-hardware",
|
||||||
|
"rev": "b1dfc15a77366c8f163af12b8b3c5f4d4f56812c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "GammaKinematics",
|
||||||
|
"repo": "nixos-hardware",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1774388614,
|
||||||
|
"narHash": "sha256-tFwzTI0DdDzovdE9+Ras6CUss0yn8P9XV4Ja6RjA+nU=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1073dad219cb244572b74da2b20c7fe39cb3fa9e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-25.11",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-unstable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1774386573,
|
||||||
|
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nur": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": [
|
||||||
|
"stylix",
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"stylix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767810917,
|
||||||
|
"narHash": "sha256-ZKqhk772+v/bujjhla9VABwcvz+hB2IaRyeLT6CFnT0=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "NUR",
|
||||||
|
"rev": "dead29c804adc928d3a69dfe7f9f12d0eec1f1a4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "NUR",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"disko": "disko",
|
||||||
|
"home-manager": "home-manager",
|
||||||
|
"nixos-hardware": "nixos-hardware",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
|
"stylix": "stylix",
|
||||||
|
"zen-browser": "zen-browser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stylix": {
|
||||||
|
"inputs": {
|
||||||
|
"base16": "base16",
|
||||||
|
"base16-fish": "base16-fish",
|
||||||
|
"base16-helix": "base16-helix",
|
||||||
|
"base16-vim": "base16-vim",
|
||||||
|
"firefox-gnome-theme": "firefox-gnome-theme",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"gnome-shell": "gnome-shell",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
],
|
||||||
|
"nur": "nur",
|
||||||
|
"systems": "systems",
|
||||||
|
"tinted-foot": "tinted-foot",
|
||||||
|
"tinted-kitty": "tinted-kitty",
|
||||||
|
"tinted-schemes": "tinted-schemes",
|
||||||
|
"tinted-tmux": "tinted-tmux",
|
||||||
|
"tinted-zed": "tinted-zed"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1774124764,
|
||||||
|
"narHash": "sha256-Poz9WTjiRlqZIf197CrMMJfTifZhrZpbHFv0eU1Nhtg=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "stylix",
|
||||||
|
"rev": "e31c79f571c5595a155f84b9d77ce53a84745494",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "stylix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tinted-foot": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1726913040,
|
||||||
|
"narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-foot",
|
||||||
|
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-foot",
|
||||||
|
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tinted-kitty": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735730497,
|
||||||
|
"narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-kitty",
|
||||||
|
"rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-kitty",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tinted-schemes": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767710407,
|
||||||
|
"narHash": "sha256-+W1EB79Jl0/gm4JqmO0Nuc5C7hRdp4vfsV/VdzI+des=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "schemes",
|
||||||
|
"rev": "2800e2b8ac90f678d7e4acebe4fa253f602e05b2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "schemes",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tinted-tmux": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767489635,
|
||||||
|
"narHash": "sha256-e6nnFnWXKBCJjCv4QG4bbcouJ6y3yeT70V9MofL32lU=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-tmux",
|
||||||
|
"rev": "3c32729ccae99be44fe8a125d20be06f8d7d8184",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "tinted-tmux",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tinted-zed": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767488740,
|
||||||
|
"narHash": "sha256-wVOj0qyil8m+ouSsVZcNjl5ZR+1GdOOAooAatQXHbuU=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-zed",
|
||||||
|
"rev": "11abb0b282ad3786a2aae088d3a01c60916f2e40",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-zed",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zen-browser": {
|
||||||
|
"inputs": {
|
||||||
|
"home-manager": [
|
||||||
|
"home-manager"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1774708879,
|
||||||
|
"narHash": "sha256-rTYvYkQL69/YkZB+MRA/IaX1qJ1lPx5KXoQS2/9+7Mw=",
|
||||||
|
"owner": "0xc000022070",
|
||||||
|
"repo": "zen-browser-flake",
|
||||||
|
"rev": "d01d23c798cceef42307d5789bfbce70515e8800",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "0xc000022070",
|
||||||
|
"repo": "zen-browser-flake",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
112
flake.nix
Executable file
112
flake.nix
Executable file
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
description = "NixOS - AL";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
# Stable nixpkgs for core system (kernel, boot, virtualization)
|
||||||
|
nixpkgs.url = "nixpkgs/nixos-25.11";
|
||||||
|
|
||||||
|
# Unstable nixpkgs for desktop/dev tools
|
||||||
|
nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
# Home Manager
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Zen Browser
|
||||||
|
zen-browser = {
|
||||||
|
url = "github:0xc000022070/zen-browser-flake";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
inputs.home-manager.follows = "home-manager";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Hardware-specific optimizations (fork with Minisforum V3 SE support)
|
||||||
|
nixos-hardware.url = "github:GammaKinematics/nixos-hardware";
|
||||||
|
|
||||||
|
# Stylix - system-wide theming
|
||||||
|
stylix = {
|
||||||
|
url = "github:nix-community/stylix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Disko - declarative disk partitioning (for VPS)
|
||||||
|
disko = {
|
||||||
|
url = "github:nix-community/disko";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
nixpkgs-unstable,
|
||||||
|
home-manager,
|
||||||
|
zen-browser,
|
||||||
|
...
|
||||||
|
}@inputs:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
|
||||||
|
|
||||||
|
# Stable pkgs for CAD/manufacturing (more reliable builds)
|
||||||
|
pkgs-stable = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Unstable pkgs for home-manager / desktop / dev
|
||||||
|
pkgs-unstable = import nixpkgs-unstable {
|
||||||
|
inherit system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# ── Hetzner VPS ──
|
||||||
|
nixosConfigurations.axiomania = nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
inputs.disko.nixosModules.disko
|
||||||
|
./Hetzner/axiomania.nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ── Hetzner ephemeral builder ──
|
||||||
|
nixosConfigurations.builder = nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
inputs.disko.nixosModules.disko
|
||||||
|
./Hetzner/builder.nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ── Local: Minisforum V3 SE ──
|
||||||
|
nixosConfigurations.v3 = nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
|
||||||
|
specialArgs = { inherit inputs; };
|
||||||
|
|
||||||
|
modules = [
|
||||||
|
inputs.stylix.nixosModules.stylix
|
||||||
|
inputs.nixos-hardware.nixosModules.minisforum-v3-se
|
||||||
|
|
||||||
|
./configuration.nix
|
||||||
|
|
||||||
|
home-manager.nixosModules.home-manager
|
||||||
|
{
|
||||||
|
home-manager = {
|
||||||
|
useGlobalPkgs = false;
|
||||||
|
useUserPackages = true;
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit inputs pkgs-unstable pkgs-stable;
|
||||||
|
};
|
||||||
|
users.lebowski = import ./home.nix;
|
||||||
|
backupFileExtension = "backup";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
68
git.nix
Normal file
68
git.nix
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
{ pkgs-stable, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# ============================================================================
|
||||||
|
# Git Configuration
|
||||||
|
# ============================================================================
|
||||||
|
programs.git = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.git;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
user.name = "GammaKinematics";
|
||||||
|
user.email = "gamma.kinematics@gmail.com";
|
||||||
|
init.defaultBranch = "main";
|
||||||
|
pull.rebase = true;
|
||||||
|
push.autoSetupRemote = true;
|
||||||
|
# Use SSH for GitHub
|
||||||
|
url."ssh://git@github.com/".insteadOf = "https://github.com/";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Delta - better diff viewer
|
||||||
|
# delta = {
|
||||||
|
# enable = true;
|
||||||
|
# options = {
|
||||||
|
# navigate = true;
|
||||||
|
# light = false;
|
||||||
|
# line-numbers = true;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# Aliases
|
||||||
|
# aliases = {
|
||||||
|
# co = "checkout";
|
||||||
|
# br = "branch";
|
||||||
|
# ci = "commit";
|
||||||
|
# st = "status";
|
||||||
|
# lg = "log --oneline --graph --decorate";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# SSH signing (for verified commits)
|
||||||
|
# signing = {
|
||||||
|
# key = "~/.ssh/id_ed25519.pub";
|
||||||
|
# signByDefault = true;
|
||||||
|
# };
|
||||||
|
# extraConfig.gpg.format = "ssh";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# SSH Configuration
|
||||||
|
# ============================================================================
|
||||||
|
programs.ssh = {
|
||||||
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
|
matchBlocks = {
|
||||||
|
"github.com" = {
|
||||||
|
host = "github.com";
|
||||||
|
identityFile = "~/.ssh/id_ed25519";
|
||||||
|
identitiesOnly = true;
|
||||||
|
};
|
||||||
|
# Add more hosts as needed
|
||||||
|
# "gitlab.com" = {
|
||||||
|
# host = "gitlab.com";
|
||||||
|
# identityFile = "~/.ssh/id_ed25519";
|
||||||
|
# identitiesOnly = true;
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
73
hardware-configuration.nix
Executable file
73
hardware-configuration.nix
Executable file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"nvme"
|
||||||
|
"xhci_pci"
|
||||||
|
"thunderbolt"
|
||||||
|
"usb_storage"
|
||||||
|
"usbhid"
|
||||||
|
"uas"
|
||||||
|
"sd_mod"
|
||||||
|
"rtsx_pci_sdmmc"
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-uuid/ea496278-ae69-48b0-9edb-b351b9620829";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-uuid/C267-DCFD";
|
||||||
|
fsType = "vfat";
|
||||||
|
options = [
|
||||||
|
"fmask=0077"
|
||||||
|
"dmask=0077"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/data" = {
|
||||||
|
device = "/dev/disk/by-label/DATA";
|
||||||
|
fsType = "ntfs";
|
||||||
|
options = [
|
||||||
|
"rw"
|
||||||
|
"uid=1000"
|
||||||
|
"gid=100"
|
||||||
|
"umask=022"
|
||||||
|
"nofail"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/data-bis" = {
|
||||||
|
device = "/dev/disk/by-label/DATA-bis";
|
||||||
|
fsType = "ntfs";
|
||||||
|
options = [
|
||||||
|
"rw"
|
||||||
|
"uid=1000"
|
||||||
|
"gid=100"
|
||||||
|
"umask=022"
|
||||||
|
"nofail"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
141
home.nix
Normal file
141
home.nix
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs-unstable,
|
||||||
|
pkgs-stable,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
flakeDir = "${config.home.homeDirectory}/NixOS";
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
# Fix home-manager xresources bug: pkgs.xrdb doesn't exist, should be xorg.xrdb
|
||||||
|
nixpkgs.overlays = [ (final: prev: { xrdb = prev.xorg.xrdb; }) ];
|
||||||
|
|
||||||
|
# Disable xresources - Stylix enables it by default but we don't need it (ST uses compile-time colors)
|
||||||
|
stylix.targets.xresources.enable = false;
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
./git.nix
|
||||||
|
./zed.nix
|
||||||
|
./zen.nix
|
||||||
|
./Rofi/rofi.nix
|
||||||
|
./KiCad/kicad.nix
|
||||||
|
|
||||||
|
# ./Hyprsuck/home.nix
|
||||||
|
./Suckless/home.nix # Uncomment for dwm (and comment Hyprsuck)
|
||||||
|
];
|
||||||
|
|
||||||
|
home.username = "lebowski";
|
||||||
|
home.homeDirectory = "/home/lebowski";
|
||||||
|
|
||||||
|
# Let Home Manager manage itself
|
||||||
|
programs.home-manager.enable = true;
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# User Packages (stable by default, unstable for bleeding-edge tools)
|
||||||
|
# ============================================================================
|
||||||
|
home.packages = with pkgs-stable; [
|
||||||
|
# Media & Creative
|
||||||
|
haruna
|
||||||
|
krita
|
||||||
|
xournalpp
|
||||||
|
|
||||||
|
# Office & Productivity
|
||||||
|
libreoffice-fresh
|
||||||
|
|
||||||
|
# CAD & Manufacturing
|
||||||
|
freecad
|
||||||
|
bambu-studio
|
||||||
|
|
||||||
|
# Dev tools (unstable for latest features)
|
||||||
|
pkgs-unstable.claude-code
|
||||||
|
pkgs-unstable.hcloud
|
||||||
|
];
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# GTK Icon Theme
|
||||||
|
# ============================================================================
|
||||||
|
gtk.iconTheme = {
|
||||||
|
package = pkgs-stable.papirus-icon-theme;
|
||||||
|
name = "Papirus-Dark";
|
||||||
|
};
|
||||||
|
gtk.gtk4.theme = null;
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Notifications (shared between Hyprland and dwm)
|
||||||
|
# ============================================================================
|
||||||
|
services.dunst = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.dunst;
|
||||||
|
settings.global.timeout = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Shell Aliases
|
||||||
|
# ============================================================================
|
||||||
|
home.shellAliases = {
|
||||||
|
# NixOS rebuild shortcuts
|
||||||
|
nrs = "sudo nixos-rebuild switch --flake ${flakeDir}";
|
||||||
|
nrb = "sudo nixos-rebuild boot --flake ${flakeDir}";
|
||||||
|
nrt = "sudo nixos-rebuild test --flake ${flakeDir}";
|
||||||
|
|
||||||
|
# Nix utilities
|
||||||
|
nfu = "nix flake update --flake ${flakeDir}";
|
||||||
|
ncg = "sudo nix-collect-garbage -d";
|
||||||
|
nso = "nix store optimise";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Optional: Additional program configurations
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# --- Bash shell ---
|
||||||
|
programs.bash = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.bash;
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- KeePassXC ---
|
||||||
|
programs.keepassxc = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.keepassxc;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.foliate = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.foliate;
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- SSH ---
|
||||||
|
programs.ssh = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-stable.openssh;
|
||||||
|
|
||||||
|
matchBlocks = {
|
||||||
|
"*" = {
|
||||||
|
addKeysToAgent = "yes";
|
||||||
|
serverAliveInterval = 60;
|
||||||
|
controlMaster = "auto";
|
||||||
|
controlPersist = "10m";
|
||||||
|
};
|
||||||
|
"git.axiomania.org" = {
|
||||||
|
port = 2222;
|
||||||
|
};
|
||||||
|
"vps" = {
|
||||||
|
hostname = "178.104.15.221";
|
||||||
|
user = "root";
|
||||||
|
identityFile = "~/.ssh/id_ed25519";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Disable version check - we intentionally use unstable home-manager with stable nixpkgs
|
||||||
|
# Note: This may cause issues if home-manager uses features not yet in stable
|
||||||
|
home.enableNixpkgsReleaseCheck = false;
|
||||||
|
|
||||||
|
home.stateVersion = "25.11";
|
||||||
|
}
|
||||||
181
ryzenadj.nix
Normal file
181
ryzenadj.nix
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
# RyzenAdj power tuning configuration
|
||||||
|
# Provides power-tuning script for Minisforum V3 SE power profile management
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Power profiles (values in mW for power, °C for temp)
|
||||||
|
profiles = {
|
||||||
|
saver = {
|
||||||
|
stapm = 15000;
|
||||||
|
fast = 18000;
|
||||||
|
slow = 16000;
|
||||||
|
temp = 80;
|
||||||
|
};
|
||||||
|
balanced = {
|
||||||
|
stapm = 22500;
|
||||||
|
fast = 30000;
|
||||||
|
slow = 25000;
|
||||||
|
temp = 90;
|
||||||
|
};
|
||||||
|
performance = {
|
||||||
|
stapm = 30000;
|
||||||
|
fast = 40000;
|
||||||
|
slow = 35000;
|
||||||
|
temp = 100;
|
||||||
|
};
|
||||||
|
compile = {
|
||||||
|
stapm = 40000;
|
||||||
|
fast = 50000;
|
||||||
|
slow = 45000;
|
||||||
|
temp = 100;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configFile = pkgs.writeText "power-tuning-config.json" (builtins.toJSON profiles);
|
||||||
|
|
||||||
|
power-tuning = pkgs.writeShellScriptBin "power-tuning" ''
|
||||||
|
CONFIG_FILE="${configFile}"
|
||||||
|
COMPILE_FLAG="/tmp/.power-tuning-compile-mode"
|
||||||
|
|
||||||
|
# Read a profile from config
|
||||||
|
get_profile() {
|
||||||
|
local profile="$1"
|
||||||
|
${pkgs.jq}/bin/jq -r ".$profile" "$CONFIG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply ryzenadj settings
|
||||||
|
apply_settings() {
|
||||||
|
local profile="$1"
|
||||||
|
local settings
|
||||||
|
settings=$(get_profile "$profile")
|
||||||
|
|
||||||
|
if [[ "$settings" == "null" ]]; then
|
||||||
|
echo "Error: Profile '$profile' not found in config"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local stapm fast slow temp
|
||||||
|
stapm=$(echo "$settings" | ${pkgs.jq}/bin/jq -r '.stapm')
|
||||||
|
fast=$(echo "$settings" | ${pkgs.jq}/bin/jq -r '.fast')
|
||||||
|
slow=$(echo "$settings" | ${pkgs.jq}/bin/jq -r '.slow')
|
||||||
|
temp=$(echo "$settings" | ${pkgs.jq}/bin/jq -r '.temp')
|
||||||
|
|
||||||
|
echo "Applying $profile: STAPM=''${stapm}mW Fast=''${fast}mW Slow=''${slow}mW Temp=''${temp}°C"
|
||||||
|
|
||||||
|
${pkgs.ryzenadj}/bin/ryzenadj \
|
||||||
|
--stapm-limit="$stapm" \
|
||||||
|
--fast-limit="$fast" \
|
||||||
|
--slow-limit="$slow" \
|
||||||
|
--tctl-temp="$temp" \
|
||||||
|
2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get current power profile from power-profiles-daemon
|
||||||
|
get_current_ppd_profile() {
|
||||||
|
local profile
|
||||||
|
profile=$(${pkgs.power-profiles-daemon}/bin/powerprofilesctl get 2>/dev/null)
|
||||||
|
|
||||||
|
case "$profile" in
|
||||||
|
"power-saver") echo "saver" ;;
|
||||||
|
"balanced") echo "balanced" ;;
|
||||||
|
"performance") echo "performance" ;;
|
||||||
|
*) echo "balanced" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if compile mode is active
|
||||||
|
is_compile_mode() {
|
||||||
|
[[ -f "$COMPILE_FLAG" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main command handling
|
||||||
|
case "''${1:-apply}" in
|
||||||
|
apply)
|
||||||
|
if is_compile_mode; then
|
||||||
|
echo "Compile mode active, using compile profile"
|
||||||
|
apply_settings "compile"
|
||||||
|
else
|
||||||
|
profile=$(get_current_ppd_profile)
|
||||||
|
echo "Current PPD profile: $profile"
|
||||||
|
apply_settings "$profile"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
compile-on)
|
||||||
|
touch "$COMPILE_FLAG"
|
||||||
|
echo "Compile mode enabled"
|
||||||
|
apply_settings "compile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
compile-off)
|
||||||
|
rm -f "$COMPILE_FLAG"
|
||||||
|
echo "Compile mode disabled"
|
||||||
|
profile=$(get_current_ppd_profile)
|
||||||
|
apply_settings "$profile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
status)
|
||||||
|
echo "=== Power Tuning Status ==="
|
||||||
|
echo "Config file: $CONFIG_FILE"
|
||||||
|
echo "PPD Profile: $(${pkgs.power-profiles-daemon}/bin/powerprofilesctl get 2>/dev/null || echo 'unknown')"
|
||||||
|
echo "Compile mode: $(is_compile_mode && echo 'ON' || echo 'OFF')"
|
||||||
|
echo ""
|
||||||
|
echo "Current presets:"
|
||||||
|
${pkgs.jq}/bin/jq '.' "$CONFIG_FILE"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Usage: power-tuning {apply|compile-on|compile-off|status}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Kernel module for SMU access
|
||||||
|
hardware.cpu.amd.ryzen-smu.enable = true;
|
||||||
|
|
||||||
|
# Permissions for ryzenadj to access SMU
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"z /sys/kernel/ryzen_smu_drv/smn 0660 root wheel -"
|
||||||
|
"z /sys/kernel/ryzen_smu_drv/smu_args 0660 root wheel -"
|
||||||
|
"z /sys/kernel/ryzen_smu_drv/mp1_smu_cmd 0660 root wheel -"
|
||||||
|
"z /sys/kernel/ryzen_smu_drv/rsmu_cmd 0660 root wheel -"
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
power-tuning
|
||||||
|
pkgs.ryzenadj
|
||||||
|
];
|
||||||
|
|
||||||
|
# Apply power tuning on boot and when power profile changes
|
||||||
|
systemd.services.power-tuning = {
|
||||||
|
description = "Apply RyzenAdj power tuning";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "power-profiles-daemon.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${power-tuning}/bin/power-tuning apply";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Re-apply when power profile changes
|
||||||
|
systemd.services.power-tuning-on-profile-change = {
|
||||||
|
description = "Apply RyzenAdj on power profile change";
|
||||||
|
after = [ "power-profiles-daemon.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${power-tuning}/bin/power-tuning apply";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Path trigger to watch for profile changes
|
||||||
|
systemd.paths.power-tuning-watch = {
|
||||||
|
description = "Watch for power profile changes";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathChanged = "/sys/firmware/acpi/platform_profile";
|
||||||
|
Unit = "power-tuning-on-profile-change.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
53
stylix.nix
Normal file
53
stylix.nix
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
stylix = {
|
||||||
|
enable = true;
|
||||||
|
enableReleaseChecks = false;
|
||||||
|
|
||||||
|
polarity = "dark";
|
||||||
|
|
||||||
|
# Catppuccin Mocha theme
|
||||||
|
base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-mocha.yaml";
|
||||||
|
|
||||||
|
# Wallpaper (used for color scheme generation)
|
||||||
|
image = ./Wallpapers/siege.png;
|
||||||
|
|
||||||
|
# Cursor
|
||||||
|
cursor = {
|
||||||
|
package = pkgs.bibata-cursors;
|
||||||
|
name = "Bibata-Modern-Ice";
|
||||||
|
size = 20;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
fonts = {
|
||||||
|
monospace = {
|
||||||
|
package = pkgs.nerd-fonts.jetbrains-mono;
|
||||||
|
name = "JetBrainsMono Nerd Font";
|
||||||
|
};
|
||||||
|
sansSerif = {
|
||||||
|
package = pkgs.dejavu_fonts;
|
||||||
|
name = "DejaVu Sans";
|
||||||
|
};
|
||||||
|
serif = {
|
||||||
|
package = pkgs.dejavu_fonts;
|
||||||
|
name = "DejaVu Serif";
|
||||||
|
};
|
||||||
|
emoji = {
|
||||||
|
package = pkgs.noto-fonts-color-emoji;
|
||||||
|
name = "Noto Color Emoji";
|
||||||
|
};
|
||||||
|
sizes = {
|
||||||
|
terminal = 11;
|
||||||
|
applications = 11;
|
||||||
|
desktop = 11;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Opacity settings
|
||||||
|
opacity = {
|
||||||
|
terminal = 0.9;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
19
virtualisation.nix
Normal file
19
virtualisation.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Libvirt/QEMU virtualisation
|
||||||
|
programs.virt-manager.enable = true;
|
||||||
|
users.groups.libvirtd.members = [ "lebowski" ];
|
||||||
|
virtualisation.libvirtd.enable = true;
|
||||||
|
virtualisation.spiceUSBRedirection.enable = true;
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
virtualisation.docker = {
|
||||||
|
enable = true;
|
||||||
|
# Use the rootless mode - run Docker daemon as non-root user
|
||||||
|
rootless = {
|
||||||
|
enable = true;
|
||||||
|
setSocketVariable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
73
zed.nix
Normal file
73
zed.nix
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# Zed Editor configuration
|
||||||
|
{ pkgs-unstable, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
programs.zed-editor = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs-unstable.zed-editor;
|
||||||
|
|
||||||
|
# This populates the userSettings "auto_install_extensions"
|
||||||
|
extensions = [
|
||||||
|
"nix"
|
||||||
|
"odin"
|
||||||
|
"astro"
|
||||||
|
"slint"
|
||||||
|
"dockerfile"
|
||||||
|
"docker-compose"
|
||||||
|
"latex"
|
||||||
|
"make"
|
||||||
|
"log"
|
||||||
|
"csv"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Everything inside of these brackets are Zed options
|
||||||
|
userSettings = {
|
||||||
|
# Disable all AI features (including Claude Code ACP agents)
|
||||||
|
disable_ai = true;
|
||||||
|
|
||||||
|
# Disable collaboration/AI features
|
||||||
|
assistant = { enabled = false; };
|
||||||
|
collaboration_panel = { button = false; };
|
||||||
|
chat_panel = { button = false; };
|
||||||
|
notification_panel = { button = false; };
|
||||||
|
title_bar = { show_sign_in = false; };
|
||||||
|
|
||||||
|
# Hide UI panels
|
||||||
|
diagnostics = { button = false; };
|
||||||
|
debugger = { button = false; };
|
||||||
|
|
||||||
|
# Disable edit predictions completely
|
||||||
|
features = { edit_prediction_provider = "none"; };
|
||||||
|
show_edit_predictions = false;
|
||||||
|
|
||||||
|
hour_format = "hour24";
|
||||||
|
auto_update = false;
|
||||||
|
|
||||||
|
terminal = {
|
||||||
|
alternate_scroll = "off";
|
||||||
|
blinking = "off";
|
||||||
|
copy_on_select = true;
|
||||||
|
dock = "right";
|
||||||
|
line_height = "comfortable";
|
||||||
|
shell = "system";
|
||||||
|
toolbar = {
|
||||||
|
title = true; # Shows terminal title (e.g. "zsh" or running command) in panel header
|
||||||
|
};
|
||||||
|
working_directory = "current_project_directory";
|
||||||
|
};
|
||||||
|
|
||||||
|
vim_mode = false;
|
||||||
|
|
||||||
|
base_keymap = "VSCode";
|
||||||
|
|
||||||
|
show_whitespaces = "selection";
|
||||||
|
|
||||||
|
# Disable all language servers globally
|
||||||
|
enable_language_server = false;
|
||||||
|
|
||||||
|
# Disable Claude Code integration (prevents auto-launching claude-code-acp)
|
||||||
|
context_servers = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
322
zen.nix
Normal file
322
zen.nix
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
{ config, lib, pkgs-unstable, inputs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Workaround for https://github.com/0xc000022070/zen-browser-flake/issues/285
|
||||||
|
# The twilight module generates profiles.ini as a read-only nix store symlink,
|
||||||
|
# which Zen can't write to, so it ignores it and creates a random-prefix profile.
|
||||||
|
# This replaces the symlink with a mutable copy.
|
||||||
|
home.activation.fixZenProfiles = lib.hm.dag.entryAfter ["linkGeneration"] ''
|
||||||
|
ZEN_DIR="$HOME/.zen"
|
||||||
|
if [ -L "$ZEN_DIR/profiles.ini" ]; then
|
||||||
|
REAL=$(readlink -f "$ZEN_DIR/profiles.ini")
|
||||||
|
rm "$ZEN_DIR/profiles.ini"
|
||||||
|
cp "$REAL" "$ZEN_DIR/profiles.ini"
|
||||||
|
chmod u+w "$ZEN_DIR/profiles.ini"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
# Tell Stylix which Zen profiles to theme
|
||||||
|
stylix.targets.zen-browser.profileNames = [ "default" ];
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
inputs.zen-browser.homeModules.twilight
|
||||||
|
];
|
||||||
|
|
||||||
|
# Set Zen as default browser for all relevant MIME types
|
||||||
|
xdg.mimeApps = let
|
||||||
|
associations = builtins.listToAttrs (map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = let
|
||||||
|
zen-browser = config.programs.zen-browser.package;
|
||||||
|
in
|
||||||
|
zen-browser.meta.desktopFileName;
|
||||||
|
}) [
|
||||||
|
"application/x-extension-shtml"
|
||||||
|
"application/x-extension-xhtml"
|
||||||
|
"application/x-extension-html"
|
||||||
|
"application/x-extension-xht"
|
||||||
|
"application/x-extension-htm"
|
||||||
|
"x-scheme-handler/unknown"
|
||||||
|
"x-scheme-handler/mailto"
|
||||||
|
"x-scheme-handler/chrome"
|
||||||
|
"x-scheme-handler/about"
|
||||||
|
"x-scheme-handler/https"
|
||||||
|
"x-scheme-handler/http"
|
||||||
|
"application/xhtml+xml"
|
||||||
|
"application/json"
|
||||||
|
"text/plain"
|
||||||
|
"text/html"
|
||||||
|
]);
|
||||||
|
in {
|
||||||
|
associations.added = associations;
|
||||||
|
defaultApplications = associations;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.zen-browser = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Native Messaging Hosts - required for KeePassXC browser integration
|
||||||
|
nativeMessagingHosts = [ pkgs-unstable.keepassxc ];
|
||||||
|
|
||||||
|
policies = let
|
||||||
|
# Helper to lock preferences
|
||||||
|
mkLockedAttrs = builtins.mapAttrs (_: value: {
|
||||||
|
Value = value;
|
||||||
|
Status = "locked";
|
||||||
|
});
|
||||||
|
|
||||||
|
# Helper to create extension install URL
|
||||||
|
mkPluginUrl = id: "https://addons.mozilla.org/firefox/downloads/latest/${id}/latest.xpi";
|
||||||
|
|
||||||
|
# Helper to create extension entry with options
|
||||||
|
mkExtensionEntry = {
|
||||||
|
id,
|
||||||
|
pinned ? false,
|
||||||
|
private_browsing ? true,
|
||||||
|
}: let
|
||||||
|
base = {
|
||||||
|
install_url = mkPluginUrl id;
|
||||||
|
installation_mode = "force_installed";
|
||||||
|
inherit private_browsing;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
if pinned
|
||||||
|
then base // { default_area = "navbar"; }
|
||||||
|
else base;
|
||||||
|
|
||||||
|
# Helper to process extension settings
|
||||||
|
mkExtensionSettings = builtins.mapAttrs (_: entry:
|
||||||
|
if builtins.isAttrs entry
|
||||||
|
then entry
|
||||||
|
else mkExtensionEntry { id = entry; });
|
||||||
|
in {
|
||||||
|
# App behavior
|
||||||
|
DisableAppUpdate = true;
|
||||||
|
DontCheckDefaultBrowser = true;
|
||||||
|
DisableFeedbackCommands = true;
|
||||||
|
|
||||||
|
# Privacy & Telemetry
|
||||||
|
DisableTelemetry = true;
|
||||||
|
DisableFirefoxStudies = true;
|
||||||
|
DisablePocket = true;
|
||||||
|
|
||||||
|
# Autofill
|
||||||
|
AutofillAddressEnabled = true;
|
||||||
|
AutofillCreditCardEnabled = false;
|
||||||
|
OfferToSaveLogins = false;
|
||||||
|
|
||||||
|
# Tracking Protection
|
||||||
|
EnableTrackingProtection = {
|
||||||
|
Value = true;
|
||||||
|
Locked = true;
|
||||||
|
Cryptomining = true;
|
||||||
|
Fingerprinting = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Clean up on shutdown (fresh instance)
|
||||||
|
SanitizeOnShutdown = {
|
||||||
|
Cache = true;
|
||||||
|
Cookies = false; # Keep logins
|
||||||
|
Downloads = true;
|
||||||
|
FormData = true;
|
||||||
|
History = false; # Keep history
|
||||||
|
Sessions = false; # Keep tabs on restart
|
||||||
|
SiteSettings = false;
|
||||||
|
OfflineApps = true;
|
||||||
|
Locked = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
ExtensionSettings = mkExtensionSettings {
|
||||||
|
# uBlock Origin - ad blocker (pinned to navbar)
|
||||||
|
"uBlock0@raymondhill.net" = mkExtensionEntry {
|
||||||
|
id = "ublock-origin";
|
||||||
|
pinned = true;
|
||||||
|
private_browsing = true;
|
||||||
|
};
|
||||||
|
# KeePassXC - password manager (pinned to navbar)
|
||||||
|
"keepassxc-browser@keepassxc.org" = mkExtensionEntry {
|
||||||
|
id = "keepassxc-browser";
|
||||||
|
pinned = true;
|
||||||
|
private_browsing = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- Privacy & Security ---
|
||||||
|
"{74145f27-f039-47ce-a470-a662b129930a}" = "clearurls"; # Remove tracking from URLs
|
||||||
|
"jid1-BoFifL9Vbdl2zQ@jetpack" = "decentraleyes"; # Local CDN emulation
|
||||||
|
"{3579f63b-d8ee-424f-bbb6-6d0ce3285e6a}" = "chameleon-ext"; # Spoof browser profile
|
||||||
|
|
||||||
|
# --- GitHub ---
|
||||||
|
"{a4c4eda4-fb84-4a84-b4a1-f7c1cbf2a1ad}" = "refined-github-"; # GitHub enhancements
|
||||||
|
"{85860b32-02a8-431a-b2b1-40fbd64c9c69}" = "github-file-icons"; # File icons in GitHub
|
||||||
|
"github-repository-size@pranavmangal" = "gh-repo-size"; # Show repo size
|
||||||
|
|
||||||
|
# --- YouTube ---
|
||||||
|
"{762f9885-5a13-4abd-9c77-433dcd38b8fd}" = "return-youtube-dislikes";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Locked preferences
|
||||||
|
Preferences = mkLockedAttrs {
|
||||||
|
"browser.aboutConfig.showWarning" = false;
|
||||||
|
"browser.tabs.warnOnClose" = false;
|
||||||
|
"media.videocontrols.picture-in-picture.video-toggle.enabled" = true;
|
||||||
|
|
||||||
|
# Translation (auto-translate all languages except en/fr)
|
||||||
|
"browser.translations.enable" = true;
|
||||||
|
"browser.translations.panelShown" = true;
|
||||||
|
"browser.translations.automaticallyPopup" = true;
|
||||||
|
"browser.translations.alwaysTranslateLanguages" = "ar,bg,cs,da,de,el,es,et,fi,hu,id,it,ja,ko,lt,lv,nl,no,pl,pt,ro,ru,sk,sl,sv,th,tr,uk,vi,zh";
|
||||||
|
"browser.translations.neverTranslateLanguages" = "en,fr";
|
||||||
|
|
||||||
|
# Privacy (balanced - removed slow options)
|
||||||
|
"privacy.spoof_english" = 1;
|
||||||
|
"network.cookie.cookieBehavior" = 5;
|
||||||
|
"dom.battery.enabled" = false;
|
||||||
|
|
||||||
|
# Performance & Speed
|
||||||
|
"gfx.webrender.all" = true;
|
||||||
|
"layers.acceleration.force-enabled" = true;
|
||||||
|
"network.http.http3.enabled" = true;
|
||||||
|
"network.dns.disablePrefetch" = false;
|
||||||
|
"network.prefetch-next" = true;
|
||||||
|
"browser.sessionstore.interval" = 60000; # Less frequent session saves (60s)
|
||||||
|
"browser.cache.memory.enable" = true;
|
||||||
|
"browser.cache.memory.capacity" = 524288; # 512MB memory cache
|
||||||
|
"content.notify.interval" = 100000;
|
||||||
|
"ui.submenuDelay" = 0; # Instant submenus
|
||||||
|
|
||||||
|
# Disable animations for snappiness
|
||||||
|
"toolkit.cosmeticAnimations.enabled" = false;
|
||||||
|
"browser.fullscreen.animate" = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
profiles.default = {
|
||||||
|
# Zen-specific settings
|
||||||
|
settings = {
|
||||||
|
"zen.workspaces.continue-where-left-off" = true; # Restore tabs
|
||||||
|
"zen.workspaces.natural-scroll" = true;
|
||||||
|
"zen.view.compact.hide-tabbar" = true;
|
||||||
|
"zen.view.compact.hide-toolbar" = true;
|
||||||
|
"zen.view.compact.animate-sidebar" = false;
|
||||||
|
"zen.welcome-screen.seen" = true;
|
||||||
|
"zen.urlbar.behavior" = "float";
|
||||||
|
|
||||||
|
# Restore previous session
|
||||||
|
"browser.startup.page" = 3; # Restore previous session
|
||||||
|
"browser.sessionstore.resume_from_crash" = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- Bookmarks ---
|
||||||
|
bookmarks = {
|
||||||
|
force = true;
|
||||||
|
settings = [
|
||||||
|
{
|
||||||
|
name = "Dev";
|
||||||
|
toolbar = true;
|
||||||
|
bookmarks = [
|
||||||
|
{ name = "GitHub"; url = "https://github.com"; }
|
||||||
|
{ name = "NixOS Wiki"; url = "https://wiki.nixos.org/"; }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- Containers ---
|
||||||
|
# containersForce = true;
|
||||||
|
# containers = {
|
||||||
|
# Personal = { color = "blue"; icon = "fingerprint"; id = 1; };
|
||||||
|
# Work = { color = "orange"; icon = "briefcase"; id = 2; };
|
||||||
|
# Shopping = { color = "yellow"; icon = "dollar"; id = 3; };
|
||||||
|
# Banking = { color = "green"; icon = "dollar"; id = 4; };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# --- Workspaces/Spaces ---
|
||||||
|
# spacesForce = true;
|
||||||
|
# spaces = {
|
||||||
|
# "Default" = {
|
||||||
|
# id = "generate-your-own-uuid"; # Use: uuidgen
|
||||||
|
# icon = "🏠";
|
||||||
|
# position = 1000;
|
||||||
|
# };
|
||||||
|
# "Work" = {
|
||||||
|
# id = "generate-your-own-uuid";
|
||||||
|
# icon = "💼";
|
||||||
|
# position = 1001;
|
||||||
|
# # container = containers."Work".id; # Link to container
|
||||||
|
# theme = {
|
||||||
|
# type = "gradient";
|
||||||
|
# colors = [
|
||||||
|
# {
|
||||||
|
# red = 100;
|
||||||
|
# green = 150;
|
||||||
|
# blue = 200;
|
||||||
|
# algorithm = "floating";
|
||||||
|
# type = "explicit-lightness";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# opacity = 0.5;
|
||||||
|
# texture = 0.3;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# --- Pinned tabs ---
|
||||||
|
# pinsForce = true;
|
||||||
|
# pins = {
|
||||||
|
# "GitHub" = {
|
||||||
|
# id = "generate-your-own-uuid";
|
||||||
|
# # workspace = spaces."Work".id;
|
||||||
|
# url = "https://github.com";
|
||||||
|
# position = 100;
|
||||||
|
# isEssential = false;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# --- Search engines ---
|
||||||
|
search = {
|
||||||
|
force = true;
|
||||||
|
default = "google";
|
||||||
|
engines = let
|
||||||
|
nixIcon = "${pkgs-unstable.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
|
||||||
|
in {
|
||||||
|
"Nix Packages" = {
|
||||||
|
urls = [{
|
||||||
|
template = "https://search.nixos.org/packages";
|
||||||
|
params = [
|
||||||
|
{ name = "type"; value = "packages"; }
|
||||||
|
{ name = "channel"; value = "unstable"; }
|
||||||
|
{ name = "query"; value = "{searchTerms}"; }
|
||||||
|
];
|
||||||
|
}];
|
||||||
|
icon = nixIcon;
|
||||||
|
definedAliases = [ "np" ];
|
||||||
|
};
|
||||||
|
"Nix Options" = {
|
||||||
|
urls = [{
|
||||||
|
template = "https://search.nixos.org/options";
|
||||||
|
params = [
|
||||||
|
{ name = "channel"; value = "unstable"; }
|
||||||
|
{ name = "query"; value = "{searchTerms}"; }
|
||||||
|
];
|
||||||
|
}];
|
||||||
|
icon = nixIcon;
|
||||||
|
definedAliases = [ "no" ];
|
||||||
|
};
|
||||||
|
"Home Manager Options" = {
|
||||||
|
urls = [{
|
||||||
|
template = "https://home-manager-options.extranix.com/";
|
||||||
|
params = [
|
||||||
|
{ name = "query"; value = "{searchTerms}"; }
|
||||||
|
{ name = "release"; value = "master"; }
|
||||||
|
];
|
||||||
|
}];
|
||||||
|
icon = nixIcon;
|
||||||
|
definedAliases = [ "hm" ];
|
||||||
|
};
|
||||||
|
# Hide unwanted default engines
|
||||||
|
"bing".metaData.hidden = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue