My nix-darwin and NixOS config
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: make Plasma + terminal config fully declarative and host-aware

+424 -294
+7 -6
flake.nix
··· 49 49 cfgLib = import ./lib { inherit lib; }; 50 50 51 51 # helper that returns the value to use as the home manager user module 52 - homeUser = { pkgsFor, isDarwin, hostName }: import ./home/home.nix { 52 + homeUser = { pkgsFor, isDarwin, isDesktop, hostName }: import ./home/home.nix { 53 53 pkgs = pkgsFor; 54 54 lib = lib; 55 55 isDarwin = isDarwin; 56 + isDesktop = isDesktop; 56 57 hostName = hostName; 57 58 }; 58 59 59 60 # DRY NixOS builder: compute pkgsForSystem and pass it explicitly into homeUser 60 - mkNixOS = { system, hostFile, hostName }: let 61 + mkNixOS = { system, hostFile, hostName, isDesktop ? true }: let 61 62 pkgsForSystem = import nixpkgs { 62 63 inherit system; 63 64 config = { allowUnfree = config.packages.allowUnfree; }; ··· 80 81 ragenix.homeManagerModules.default 81 82 ]; 82 83 home-manager.extraSpecialArgs = { inherit cfgLib; }; 83 - home-manager.users.${userConfig.username} = homeUser { pkgsFor = pkgsForSystem; isDarwin = false; inherit hostName; }; 84 + home-manager.users.${userConfig.username} = homeUser { pkgsFor = pkgsForSystem; isDarwin = false; inherit isDesktop hostName; }; 84 85 home-manager.backupFileExtension = "backup"; 85 86 } 86 87 ]; 87 88 }; 88 89 89 90 # DRY Darwin builder: compute pkgs for Darwin and pass into homeUser 90 - mkDarwin = { system, hostFile, hostName }: let 91 + mkDarwin = { system, hostFile, hostName, isDesktop ? false }: let 91 92 pkgsForDarwin = import nixpkgs-darwin { 92 93 inherit system; 93 94 config = { allowUnfree = config.packages.allowUnfree; }; ··· 111 112 ragenix.homeManagerModules.default 112 113 ]; 113 114 home-manager.extraSpecialArgs = { inherit cfgLib; }; 114 - home-manager.users.${userConfig.username} = homeUser { pkgsFor = pkgsForDarwin; isDarwin = true; inherit hostName; }; 115 + home-manager.users.${userConfig.username} = homeUser { pkgsFor = pkgsForDarwin; isDarwin = true; inherit isDesktop hostName; }; 115 116 home-manager.backupFileExtension = "backup"; 116 117 } 117 118 ]; ··· 120 121 nixosConfigurations = rec { 121 122 default = mkNixOS { system = "x86_64-linux"; hostFile = ./hosts/laptop; hostName = "laptop"; }; 122 123 laptop = default; 123 - server = mkNixOS { system = "x86_64-linux"; hostFile = ./hosts/server; hostName = "server"; }; 124 + server = mkNixOS { system = "x86_64-linux"; hostFile = ./hosts/server; hostName = "server"; isDesktop = false; }; 124 125 }; 125 126 126 127 darwinConfigurations = {
+4 -2
home/home.nix
··· 1 - { pkgs, lib, isDarwin, hostName, extraSpecialArgs ? {}, ... }: 1 + { pkgs, lib, isDarwin, isDesktop, hostName, extraSpecialArgs ? {}, ... }: 2 2 { config, cfgLib, ... }: 3 3 4 4 let ··· 30 30 ./programs/fastfetch.nix 31 31 ./programs/vscode.nix 32 32 ] ++ lib.optionals (!isDarwin) [ 33 - ./programs/kde.nix 33 + ./programs/terminal.nix # Konsole profile — all non-Darwin hosts 34 + ] ++ lib.optionals isDesktop [ 35 + ./programs/kde.nix # KDE Plasma settings — desktop only 34 36 ]; 35 37 36 38 home = {
+8 -51
home/programs/kde.nix
··· 1 - { config, pkgs, lib, cfgLib, ... }: 1 + # KDE Plasma desktop settings — desktop hosts only (not server). 2 + # Terminal profile lives in terminal.nix and is imported separately for all 3 + # non-Darwin hosts; this file is only the plasma-manager + wallpaper layer. 4 + { lib, cfgLib, ... }: 2 5 3 - let 4 - cfg = cfgLib.cfg; 5 - in 6 6 { 7 - # ─── Declarative plasma-manager settings ──────────────────────────────────── 8 - # settings/plasma/default.nix contains intentional layout / behaviour prefs. 9 - # Values below supplement it with config-driven values from settings/config/. 10 7 imports = [ 11 - ../../settings/plasma 8 + ../../settings/plasma # panels, KWin effects, shortcuts, fonts — all from cfg 12 9 ]; 13 10 14 - # ─── Konsole ──────────────────────────────────────────────────────────────── 15 - programs.konsole = { 16 - enable = true; 17 - defaultProfile = "Catppuccin Mocha"; 18 - profiles = { 19 - "Catppuccin Mocha" = { 20 - name = "Catppuccin Mocha"; 21 - # Name= field from the .colorscheme file installed by catppuccin/konsole 22 - colorScheme = "Catppuccin Mocha"; 23 - font = { 24 - name = cfg.desktop.monoFontConsole; 25 - size = 11; 26 - }; 27 - }; 28 - }; 29 - }; 30 - 31 - # ─── Config-derived plasma settings ────────────────────────────────────────── 32 - programs.plasma = { 33 - 34 - # Wallpaper – tracks wallpapers/wallpaper.jpg in this repo 35 - workspace.wallpaper = "${../../wallpapers/wallpaper.jpg}"; 36 - 37 - # Fonts – driven from settings/config/desktop.nix 38 - fonts = { 39 - # UI font: Noto Sans is the closest open-source match to macOS San Francisco. 40 - # Override with "Inter" if you add pkgs.inter to home.packages. 41 - general = { 42 - family = "Noto Sans"; 43 - pointSize = 10; 44 - }; 45 - fixedWidth = { 46 - family = "FiraCode Nerd Font Mono"; 47 - pointSize = 11; 48 - }; 49 - }; 50 - 51 - # Icon theme – driven from settings/config/desktop.nix 52 - # Catppuccin module installs catppuccin-papirus-folders; Papirus-Dark works 53 - # whether or not the catppuccin icon override is active. 54 - configFile."kdeglobals".Icons.Theme = cfg.desktop.iconTheme; 55 - 56 - }; 11 + # Wallpaper path is relative to this file, so it must live here rather than 12 + # in settings/plasma/default.nix. 13 + programs.plasma.workspace.wallpaper = "${../../wallpapers/wallpaper.jpg}"; 57 14 }
+22
home/programs/terminal.nix
··· 1 + # Terminal emulator profile — shared by all non-Darwin hosts (laptop + server). 2 + # Controls the font and colour scheme used by Konsole / any KDE-aware terminal. 3 + # Font and size come from settings/config/desktop.nix — never hardcoded here. 4 + { lib, cfgLib, ... }: 5 + 6 + let 7 + d = cfgLib.cfg.desktop; 8 + in 9 + { 10 + programs.konsole = { 11 + enable = true; 12 + defaultProfile = "Catppuccin Mocha"; 13 + profiles."Catppuccin Mocha" = { 14 + name = "Catppuccin Mocha"; 15 + colorScheme = "Catppuccin Mocha"; # installed by the catppuccin/konsole package 16 + font = { 17 + name = d.monoFontConsole; # "FiraCode Nerd Font Mono" 18 + size = d.monoFontSize; # 11 19 + }; 20 + }; 21 + }; 22 + }
+3
home/programs/zsh.nix
··· 51 51 "sudo nixos-rebuild switch --flake .#${hostName} && home-manager switch --flake .#${userName}"; 52 52 } 53 53 54 + # Shared Nix tool aliases (flake-bump, gen-diff, health-check) 55 + // cfg.shell.nixToolAliases 56 + 54 57 # Linux-specific 55 58 // (lib.optionalAttrs (!isDarwin) cfg.shell.linuxAliases) 56 59
+2 -2
hosts/macmini/default.nix
··· 22 22 # SMB/NetBIOS hostname (used by network discovery and file sharing) 23 23 system.defaults.smb.NetBIOSName = "macmini"; 24 24 25 - # Timezone 26 - time.timeZone = "Europe/London"; 25 + # Timezone — driven from settings/config/system.nix 26 + time.timeZone = cfg.system.timeZone; 27 27 28 28 users.users.${cfg.user.username} = { 29 29 home = "/Users/${cfg.user.username}";
+32 -14
settings/config/desktop.nix
··· 1 + let 2 + # ── Single-source font primitives ───────────────────────────────────────── 3 + # Change a name here and Konsole, KDE, and VS Code all update at once. 4 + monoFontBase = "FiraCode"; # root font family name 5 + monoFontFamily = "${monoFontBase} Nerd Font Mono"; # full name for KDE / Konsole 6 + monoFontSize = 11; 7 + 8 + uiFont = "Noto Sans"; # closest open-source match to macOS San Francisco 9 + uiFontSize = 10; 10 + in 1 11 { 2 12 # Desktop environment configuration (Linux) 3 - 4 - enable = true; 5 - 6 - # Desktop environment 7 - environment = "plasma6"; # "gnome", "plasma6", "xfce", etc. 8 - 9 - # Display manager 10 - displayManager = "sddm"; # "gdm", "sddm", "lightdm", etc. 13 + enable = true; 14 + environment = "plasma6"; # "gnome" | "plasma6" | "xfce" 15 + displayManager = "sddm"; # "gdm" | "sddm" | "lightdm" 11 16 12 17 # GTK/Qt theming 13 18 theme = "Catppuccin-Mocha-Standard-Green-Dark"; 14 19 iconTheme = "Papirus-Dark"; 15 20 16 - # Monospace font (used in Konsole, terminal emulators, IDE configs, etc.) 17 - monoFont = "FiraCode Nerd Font Mono 11"; 18 - monoFontConsole = "FiraCode Nerd Font Mono 11"; # Konsole uses the same font name as the system 21 + # ── Font primitives — single source of truth ────────────────────────────── 22 + # All consumers (KDE font roles, Konsole, VS Code) reference these; 23 + # nothing below is ever hardcoded elsewhere. 24 + inherit uiFont uiFontSize monoFontBase monoFontFamily monoFontSize; 19 25 20 - # KDE Plasma-specific settings 26 + # Computed composites — derived, never typed twice 27 + monoFont = "${monoFontFamily} ${toString monoFontSize}"; # "FiraCode Nerd Font Mono 11" 28 + monoFontConsole = monoFontFamily; # Konsole font.name = family only (no trailing size) 29 + 30 + # ── KDE Plasma-specific settings ─────────────────────────────────────────── 21 31 plasma = { 32 + # Color scheme applied by plasma-apply-colorscheme on login. 33 + # Mirrors macOS: NSGlobalDomain.AppleInterfaceStyle = "Dark" 34 + # NSGlobalDomain.AppleAccentColor = 3 (Green) 35 + colorScheme = "CatppuccinMochaGreen"; 36 + 37 + # Plasma desktop style (controls panel/widget chrome). 38 + desktopTheme = "breeze-dark"; 39 + 22 40 # Packages to exclude from the default KDE Plasma install. 23 41 # Must match attribute names under pkgs.kdePackages. 24 42 excludePackages = [ 25 - "oxygen" # Legacy Oxygen theme – use Breeze/Catppuccin instead 26 - "elisa" # KDE music player – use Spotify instead 43 + "oxygen" # Legacy Oxygen theme — use Breeze/Catppuccin instead 44 + "elisa" # KDE music player — use Spotify instead 27 45 ]; 28 46 }; 29 47 }
+22 -12
settings/config/development.nix
··· 1 + let 2 + # Pull the font primitives from the single source of truth so VS Code 3 + # stays in sync with KDE/Konsole without hardcoding "FiraCode" twice. 4 + desktop = import ./desktop.nix; 5 + 6 + # VS Code uses the bare family name (no "Nerd Font Mono" suffix) for the 7 + # editor pane, and the Nerd Font variant (without "Mono") for the terminal. 8 + editorFont = desktop.monoFontBase; # "FiraCode" 9 + terminalFont = "${desktop.monoFontBase} Nerd Font"; # "FiraCode Nerd Font" 10 + in 1 11 { 2 12 # Development configuration 3 13 ··· 7 17 8 18 # Theme 9 19 colorTheme = "Catppuccin Mocha"; 10 - iconTheme = "catppuccin-vsc-icons"; 20 + iconTheme = "catppuccin-vsc-icons"; 11 21 12 - # Editor appearance 13 - fontFamily = "'FiraCode', 'monospace'"; 14 - terminalFontFamily = "'FiraCode Nerd Font'"; 15 - fontSize = 14; 16 - terminalFontSize = 13; 17 - lineHeight = 22; 18 - fontLigatures = true; 22 + # Editor appearance — font strings derived from desktop.nix primitives 23 + fontFamily = "'${editorFont}', 'monospace'"; # "'FiraCode', 'monospace'" 24 + terminalFontFamily = "'${terminalFont}'"; # "'FiraCode Nerd Font'" 25 + fontSize = 14; 26 + terminalFontSize = 13; 27 + lineHeight = 22; 28 + fontLigatures = true; 19 29 20 - # Extensions from nixpkgs (pkgs.vscode-extensions.<publisher>.<n>). 30 + # Extensions from nixpkgs (pkgs.vscode-extensions.<publisher>.<name>). 21 31 # Must match attribute paths in the nixpkgs vscode-extensions set. 22 32 extensions = [ 23 33 # ── Nix ────────────────────────────────────────────────────────────────── ··· 65 75 ]; 66 76 67 77 # Extensions from the VS Code Marketplace via the nix-vscode-extensions 68 - # overlay (pkgs.vscode-marketplace.<publisher>.<n>). 78 + # overlay (pkgs.vscode-marketplace.<publisher>.<name>). 69 79 # Use this for extensions not packaged in base nixpkgs 25.11. 70 80 marketplaceExtensions = [ 71 - "golang.go" # Go language support (requires gopls on PATH) 72 - "svelte.svelte-vscode" # Svelte language server 81 + "golang.go" # Go language support (requires gopls on PATH) 82 + "svelte.svelte-vscode" # Svelte language server 73 83 "ms-vscode.makefile-tools" # Makefile syntax, build targets, IntelliSense 74 84 ]; 75 85 };
+49 -50
settings/config/shell.nix
··· 1 1 { 2 2 # Shell configuration 3 - 3 + 4 4 # Common aliases 5 5 aliases = { 6 6 # Modern CLI replacements 7 - ls = "eza --icons"; 8 - ll = "eza -l --icons --git"; 9 - la = "eza -la --icons --git"; 10 - lt = "eza --tree --level=2 --icons"; 7 + ls = "eza --icons"; 8 + ll = "eza -l --icons --git"; 9 + la = "eza -la --icons --git"; 10 + lt = "eza --tree --level=2 --icons"; 11 11 cat = "bat"; 12 - 12 + 13 13 # Navigation 14 - ".." = "cd .."; 15 - "..." = "cd ../.."; 14 + ".." = "cd .."; 15 + "..." = "cd ../.."; 16 16 "...." = "cd ../../.."; 17 - 17 + 18 18 # Safety nets 19 19 rm = "rm -i"; 20 20 cp = "cp -i"; 21 21 mv = "mv -i"; 22 - 22 + 23 23 # Shortcuts 24 24 h = "history"; 25 25 c = "clear"; 26 26 e = "$EDITOR"; 27 - 27 + 28 28 # Disk usage 29 29 du1 = "du -h -d 1"; 30 - df = "df -h"; 31 - 30 + df = "df -h"; 31 + 32 32 # Git shortcuts (use lazygit for TUI) 33 33 lg = "lazygit"; 34 34 }; 35 - 35 + 36 36 # Git aliases 37 37 gitAliases = { 38 38 # Status and info 39 - gs = "git status"; 40 - gss = "git status -s"; # Short status 41 - gl = "git log --oneline --graph --decorate"; 42 - 39 + gs = "git status"; 40 + gss = "git status -s"; # Short status 41 + gl = "git log --oneline --graph --decorate"; 42 + 43 43 # Adding and committing 44 - ga = "git add"; 45 - gaa = "git add -A"; # Add all 46 - gc = "git commit"; 47 - gcm = "git commit -m"; # Commit with message 44 + ga = "git add"; 45 + gaa = "git add -A"; # Add all 46 + gc = "git commit"; 47 + gcm = "git commit -m"; # Commit with message 48 48 gca = "git commit --amend"; 49 - 49 + 50 50 # Pushing and pulling 51 - gp = "git push"; 52 - gpf = "git push --force-with-lease"; # Safer force push 51 + gp = "git push"; 52 + gpf = "git push --force-with-lease"; # Safer force push 53 53 gpl = "git pull"; 54 - gpr = "git pull --rebase"; # Pull with rebase 55 - 54 + gpr = "git pull --rebase"; # Pull with rebase 55 + 56 56 # Branching 57 - gb = "git branch"; 57 + gb = "git branch"; 58 58 gco = "git checkout"; 59 - gcb = "git checkout -b"; # Create and checkout branch 60 - 59 + gcb = "git checkout -b"; # Create and checkout branch 60 + 61 61 # Diffs 62 - gd = "git diff"; 62 + gd = "git diff"; 63 63 gds = "git diff --staged"; 64 64 }; 65 - 66 - # Linux-specific aliases 67 - linuxAliases = { 68 - # nrs/nrb/nrt defined dynamically based on hostname 69 - cleanup = "sudo nix-collect-garbage -d && nix-collect-garbage -d"; 65 + 66 + # ── Nix tool aliases — shared by both platforms ─────────────────────────── 67 + # Any alias present on both Linux and macOS belongs here exactly once. 68 + # Platform-specific aliases (cleanup, nrs/nrb/nrt) stay in their sections. 69 + nixToolAliases = { 70 70 flake-bump = "nix run ~/.config/nix-config/tools#flake-bump"; 71 71 gen-diff = "nix run ~/.config/nix-config/tools#gen-diff"; 72 72 health-check = "nix run ~/.config/nix-config/tools#health-check"; 73 - # Removed: backup-gde (gnome-export retired — dconf now fully declarative) 74 - # Removed: secrets-setup (was a stub; health-check covers the age key check) 73 + }; 74 + 75 + # Linux-specific aliases 76 + linuxAliases = { 77 + # nixToolAliases are merged by zsh.nix — only put Linux-only entries here 78 + cleanup = "sudo nix-collect-garbage -d && nix-collect-garbage -d"; 75 79 }; 76 - 80 + 77 81 # macOS-specific aliases 78 82 darwinAliases = { 79 - # nrs/nrt defined dynamically based on hostname 80 - cleanup = "sudo nix-collect-garbage -d"; 81 - flake-bump = "nix run ~/.config/nix-config/tools#flake-bump"; 82 - gen-diff = "nix run ~/.config/nix-config/tools#gen-diff"; 83 - health-check = "nix run ~/.config/nix-config/tools#health-check"; 84 - # Removed: backup-dde (darwin-export retired — macOS settings now fully declarative) 85 - # Removed: secrets-setup (was a stub; health-check covers the age key check) 83 + # nixToolAliases are merged by zsh.nix — only put macOS-only entries here 84 + cleanup = "sudo nix-collect-garbage -d"; 86 85 }; 87 - 86 + 88 87 # History configuration 89 88 history = { 90 - size = 10000; 91 - saveSize = 10000; 92 - file = "~/.zsh_history"; 89 + size = 10000; 90 + saveSize = 10000; 91 + file = "~/.zsh_history"; 93 92 ignoreDups = true; 94 93 }; 95 94 }
+275 -157
settings/plasma/default.nix
··· 1 1 ############################################################################## 2 - # Declarative KDE Plasma 6 settings via plasma-manager. 2 + # Declarative KDE Plasma 6 settings — macOS-inspired layout. 3 3 # 4 4 # Philosophy: 5 5 # ✓ Only include values that express a deliberate preference 6 6 # ✗ No window positions, sidebar widths, last-opened panels, or scroll state 7 7 # ✗ No machine-specific paths or device UUIDs 8 8 # ✗ No internal migration flags or analytics timestamps 9 - # ✗ No duplicates of keys already set by home/programs/kde.nix 10 - # (wallpaper, fonts, icon theme — those come from settings/config/desktop.nix) 11 9 # 12 - # Settings are mirrored from settings/darwin/default.nix wherever possible, 13 - # so behaviour matches the macmini as closely as KDE allows. 10 + # All font families, sizes, color schemes, and icon themes come from 11 + # settings/config/desktop.nix — never hardcoded here. 12 + # Wallpaper and the Konsole profile live in home/programs/kde.nix. 14 13 # 15 14 # macOS-like layout: 16 - # ┌─────────────────────────────────────────────────────┐ 17 - # │ [NixLogo] [App Menu — File Edit View …] [Tray][🕐] │ ← top menu bar 18 - # ├─────────────────────────────────────────────────────┤ 19 - # │ desktop / windows │ 20 - # │ ╔══════════════════════════════════════════════╗ │ 21 - # │ ║ 🐬 📡 📝 🎵 🎮 💬 🦊 💻 ║ │ ← always-visible dock 22 - # │ ╚══════════════════════════════════════════════╝ │ 23 - # └─────────────────────────────────────────────────────┘ 15 + # ┌─────────────────────────────────────────────────────────────────┐ 16 + # │ [NixLogo] [File Edit View …] [Tray extras] [🕐] │ ← 28px menu bar 17 + # ├─────────────────────────────────────────────────────────────────┤ 18 + # │ desktop / windows │ 19 + # │ ╔═══════════════════════════════════════════════════════════╗ │ 20 + # │ ║ 🐬 📡 📝 🎵 🎮 💬 🦊 💻 ║ │ ← floating dock 21 + # │ ╚═══════════════════════════════════════════════════════════╝ │ 22 + # └─────────────────────────────────────────────────────────────────┘ 24 23 # 25 - # After editing, run `nixos-rebuild switch` to apply. 24 + # After editing: nixos-rebuild switch (or home-manager switch) 26 25 ############################################################################## 27 - { lib, ... }: 26 + { lib, cfgLib, ... }: 28 27 28 + let 29 + cfg = cfgLib.cfg; 30 + d = cfg.desktop; # shorthand 31 + in 29 32 { 30 33 programs.plasma = { 31 34 32 35 # ── Input – keyboard ─────────────────────────────────────────────────────── 33 - # Mac: InitialKeyRepeat = 15 (15 × 15ms = 225ms delay before repeat) 34 - # KeyRepeat = 2 (2 × 15ms = 30ms interval → ~33 repeats/s) 36 + # mac: InitialKeyRepeat = 15 (15 × 15 ms = 225 ms before first repeat) 37 + # KeyRepeat = 2 (2 × 15 ms = 30 ms → ~33 repeats / second) 35 38 input.keyboard = { 36 39 numlockOnStartup = "off"; 37 40 repeatDelay = 225; ··· 41 44 # ── KWin (window manager) ────────────────────────────────────────────────── 42 45 kwin = { 43 46 44 - # Four virtual desktops in a single row (macOS Spaces) 47 + # Four named virtual desktops in one row — analogous to macOS Spaces. 48 + # mac: "com.apple.spaces"."spans-displays" = 0 (per-display Spaces) 45 49 virtualDesktops = { 46 - number = 4; 47 - rows = 1; 50 + names = [ "Main" "Work" "Media" "Social" ]; 51 + rows = 1; 48 52 }; 49 53 50 - # Night light 54 + # Borderless maximised windows — mirrors macOS hiding the titlebar in 55 + # full-screen mode. 56 + borderlessMaximizedWindows = true; 57 + 58 + # Night light — constant warm tone at all times. 59 + # To switch to automatic sunset/sunrise for Birmingham UK, set: 60 + # mode = "location"; 61 + # location.latitude = "52.48"; 62 + # location.longitude = "-1.89"; 51 63 nightLight = { 52 64 enable = true; 53 - mode = "constantColor"; 65 + mode = "constant"; # valid: "constant" | "location" | "times" 54 66 temperature = { 55 - day = 6500; 56 - night = 4000; 67 + day = 6500; # neutral daylight white 68 + night = 4000; # warm amber (macOS default ≈ 3700 K) 57 69 }; 58 70 }; 59 71 72 + # Titlebar buttons on the LEFT — mac: close → minimise → maximise 73 + titlebarButtons.left = [ "close" "minimize" "maximize" ]; 74 + titlebarButtons.right = []; 75 + 76 + # KWin visual effects ──────────────────────────────────────────────────── 60 77 effects = { 61 - translucency.enable = true; # glass feel while moving/resizing 62 - shakeCursor.enable = false; # macOS doesn't shake cursor to locate it 78 + 79 + # Frosted-glass background behind panels and menus. 80 + # Mirrors NSVisualEffectView — the ubiquitous blur layer in macOS UI. 81 + blur = { 82 + enable = true; 83 + strength = 7; # 1–15; 7 ≈ macOS vibrancy intensity 84 + noiseStrength = 0; # no grain — macOS blur is clean 85 + }; 86 + 87 + # Magic Lamp minimise — window squishes into the dock icon. 88 + # mac: dock.minimize-to-application = true 89 + minimization = { 90 + animation = "magiclamp"; 91 + duration = 400; # ms; macOS default ≈ 300–400 ms 92 + }; 93 + 94 + # Glide for window open / close — closest to macOS scale + fade. 95 + windowOpenClose.animation = "glide"; 96 + 97 + # Slide between virtual desktops (macOS Spaces slide animation). 98 + desktopSwitching = { 99 + animation = "slide"; 100 + navigationWrapping = false; # macOS does not wrap around Spaces 101 + }; 102 + 103 + # Glass feel while moving / resizing windows. 104 + translucency.enable = true; 105 + 106 + # macOS does not shake the cursor to locate it. 107 + shakeCursor.enable = false; 108 + 109 + # macOS never dims inactive windows. 110 + dimInactive.enable = false; 111 + 63 112 }; 113 + 114 + }; # end kwin 115 + 116 + # ── KWin raw configFile (no first-class plasma-manager option yet) ───────── 117 + configFile."kwinrc" = { 118 + 119 + # Animation speed: 2 = Fast (KDE default 3 = Normal). 120 + Compositing.AnimationSpeed = 2; 121 + 122 + # Hot corners — mirrors macOS dock.wvous-* settings exactly: 123 + # BL → Mission Control (wvous-bl-corner = 2) 124 + # BR → Show Desktop (wvous-br-corner = 4) 125 + # TL → None (wvous-tl-corner = 1) 126 + # TR → Lock Screen (wvous-tr-corner = 5 ≈ Screen Saver) 127 + ElectricBorders = { 128 + BottomLeft = "Overview"; 129 + BottomRight = "ShowDesktop"; 130 + TopLeft = "None"; 131 + TopRight = "LockScreen"; 132 + }; 133 + 64 134 }; 65 135 66 - # ── Colour scheme and desktop theme ───────────────────────────────────────── 67 - # mac: NSGlobalDomain.AppleInterfaceStyle = "Dark" 68 - # CustomUserPreferences.NSGlobalDomain.AppleAccentColor = 3 (Green) 69 - # workspace.colorScheme sets the Qt/KDE colour palette (kdeglobals). 70 - # The catppuccin home-manager module also sets this via lib.mkDefault; 71 - # being explicit here ensures it is always set, even if that module changes. 72 - workspace.colorScheme = "CatppuccinMochaGreen"; 136 + # ── Workspace ───────────────────────────────────────────────────────────── 137 + # Wallpaper is set in home/programs/kde.nix (path relative to that file). 138 + workspace = { 73 139 74 - # Plasma desktop style (plasmarc Theme.name) — controls panel/widget chrome. 75 - # No catppuccin plasma *style* package exists; Breeze Dark is the best base. 76 - workspace.theme = "breeze-dark"; 140 + # Color scheme — from settings/config/desktop.nix. 141 + # Explicit here so it always wins, even if the catppuccin module changes 142 + # its lib.mkDefault later. 143 + colorScheme = d.plasma.colorScheme; # "CatppuccinMochaGreen" 77 144 78 - # ── Window decoration ────────────────────────────────────────────────────── 79 - workspace.windowDecorations = { 80 - theme = "Breeze"; 81 - library = "org.kde.breeze"; 145 + # Plasma desktop style — from settings/config/desktop.nix. 146 + theme = d.plasma.desktopTheme; # "breeze-dark" 147 + 148 + # Icon theme — from settings/config/desktop.nix. 149 + # Uses the proper API (runs plasma-changeicons on login) instead of the 150 + # raw configFile."kdeglobals".Icons.Theme approach. 151 + iconTheme = d.iconTheme; # "Papirus-Dark" 152 + 153 + # Window decorations — Breeze (left-side buttons configured in kwin above). 154 + windowDecorations = { 155 + library = "org.kde.breeze"; 156 + theme = "Breeze"; 157 + }; 158 + 159 + # No splash screen — macOS shows nothing on login. 160 + splashScreen.theme = "None"; 161 + 162 + # Single-click selects, double-click opens — standard macOS Finder behaviour. 163 + clickItemTo = "select"; 164 + 165 + # Disable middle-click paste — macOS has no X11 primary selection. 166 + enableMiddleClickPaste = false; 167 + 168 + # Tooltip delay — 500 ms ≈ macOS hover timing (KDE default 700 ms). 169 + tooltipDelay = 500; 170 + 171 + # Breeze widget style — cleanest, most macOS-like Qt widget rendering. 172 + widgetStyle = "breeze"; 173 + 174 + # Cursor theme — uncomment to use a macOS-inspired cursor. 175 + # Requires pkgs.capitaine-cursors (or pkgs.apple-cursor) in home.packages. 176 + # cursor = { 177 + # theme = "capitaine-cursors"; 178 + # size = 24; 179 + # cursorFeedback = "Bouncing"; # macOS: app icon bounces in dock on launch 180 + # }; 181 + 82 182 }; 83 183 84 - # Titlebar buttons on the LEFT, mac-style: close → minimise → maximise 85 - kwin.titlebarButtons.left = [ "close" "minimize" "maximize" ]; 86 - kwin.titlebarButtons.right = [ ]; 184 + # ── Fonts — all roles, all from settings/config/desktop.nix ─────────────── 185 + # d.uiFont / d.uiFontSize / d.monoFontFamily / d.monoFontSize are the 186 + # single source of truth; change them once, everything updates. 187 + fonts = { 188 + general = { 189 + family = d.uiFont; # "Noto Sans" 190 + pointSize = d.uiFontSize; # 10 191 + }; 192 + fixedWidth = { 193 + family = d.monoFontFamily; # "FiraCode Nerd Font Mono" 194 + pointSize = d.monoFontSize; # 11 195 + }; 196 + small = { 197 + family = d.uiFont; 198 + pointSize = d.uiFontSize - 2; # 8 — status bars, breadcrumbs, subtitles 199 + }; 200 + toolbar = { 201 + family = d.uiFont; 202 + pointSize = d.uiFontSize; 203 + }; 204 + menu = { 205 + family = d.uiFont; 206 + pointSize = d.uiFontSize; 207 + }; 208 + windowTitle = { 209 + family = d.uiFont; 210 + pointSize = d.uiFontSize; 211 + weight = "medium"; # macOS window titles are slightly heavier than body 212 + }; 213 + }; 87 214 88 - # ── Workspace ────────────────────────────────────────────────────────────── 89 - # Wallpaper and icon theme are set in home/programs/kde.nix. 90 - workspace.clickItemTo = "select"; # single-click selects, double-click opens 215 + # ── Windows ─────────────────────────────────────────────────────────────── 216 + # Allow apps to remember their own window positions. 217 + # mac: WindowServer stores geometry per app. 218 + windows.allowWindowsToRememberPositions = true; 219 + 220 + # ── KRunner — Spotlight equivalent (Meta+Space) ─────────────────────────── 221 + krunner = { 222 + position = "center"; # macOS Spotlight is a centred overlay 223 + activateWhenTypingOnDesktop = false; # Spotlight requires explicit shortcut 224 + shortcuts = { 225 + launch = [ "Meta+Space" "Alt+F2" ]; 226 + runCommandOnClipboard = [ "Meta+Shift+Space" "Alt+Shift+F2" ]; 227 + }; 228 + }; 91 229 92 230 # ── Keyboard shortcuts ───────────────────────────────────────────────────── 93 231 shortcuts = { 94 232 kwin = { 95 - # Virtual desktop switching 96 - "Switch to Desktop 1" = [ "Meta+1" ]; 97 - "Switch to Desktop 2" = [ "Meta+2" ]; 98 - "Switch to Desktop 3" = [ "Meta+3" ]; 99 - "Switch to Desktop 4" = [ "Meta+4" ]; 100 - "Switch One Desktop to the Left" = [ "Meta+Left" ]; 233 + # Virtual desktop / Spaces navigation 234 + # mac: Ctrl+1–4 and Ctrl+← / → switch Spaces 235 + "Switch to Desktop 1" = [ "Meta+1" ]; 236 + "Switch to Desktop 2" = [ "Meta+2" ]; 237 + "Switch to Desktop 3" = [ "Meta+3" ]; 238 + "Switch to Desktop 4" = [ "Meta+4" ]; 239 + "Switch One Desktop to the Left" = [ "Meta+Left" ]; 101 240 "Switch One Desktop to the Right" = [ "Meta+Right" ]; 102 - # Send window to desktop 241 + 242 + # Move window to a named Space 103 243 "Window to Desktop 1" = [ "Meta+Shift+1" ]; 104 244 "Window to Desktop 2" = [ "Meta+Shift+2" ]; 105 245 "Window to Desktop 3" = [ "Meta+Shift+3" ]; 106 246 "Window to Desktop 4" = [ "Meta+Shift+4" ]; 107 - # Window management 108 - "Window Close" = [ "Meta+Q" ]; # macOS Cmd+Q 109 - "Window Minimize" = [ "Meta+H" ]; # macOS Cmd+H (hide) 110 - "Toggle Window Maximized" = [ "Meta+Ctrl+F" ]; # macOS Ctrl+Cmd+F 247 + 248 + # Window management — macOS Cmd+* equivalents 249 + "Window Close" = [ "Meta+Q" ]; # Cmd+Q (quit) 250 + "Window Minimize" = [ "Meta+H" ]; # Cmd+H (hide / minimise) 251 + "Toggle Window Maximized" = [ "Meta+Ctrl+F" ]; # Ctrl+Cmd+F (full-screen toggle) 252 + 111 253 # Mission Control equivalents 112 - # mac: wvous-bl-corner = 2 (Mission Control) → Meta+W as keyboard shortcut 113 - "Overview" = [ "Meta+W" ]; # all desktops + windows 114 - "Expose" = [ "Meta+D" ]; # present windows on current desktop 115 - "Show Desktop" = [ "Meta+Shift+D" ]; 254 + "Overview" = [ "Meta+W" ]; # all desktops + all windows 255 + "Expose" = [ "Meta+D" ]; # windows on current desktop only 256 + "Show Desktop" = [ "Meta+Shift+D" ]; # reveal desktop (≡ Fn+F11 on mac) 116 257 }; 117 258 }; 118 259 119 - # ── Panels ──────────────────────────────────────────────────────────────── 260 + # ── Spectacle — macOS screenshot shortcut mapping ───────────────────────── 261 + # mac: Cmd+Shift+3 = full screen → Meta+Shift+3 262 + # Cmd+Shift+4 = region → Meta+Shift+4 263 + # Cmd+Shift+5 = UI → Meta+Shift+5 264 + spectacle.shortcuts = { 265 + captureEntireDesktop = [ "Meta+Shift+3" ]; 266 + captureRectangularRegion = [ "Meta+Shift+4" ]; 267 + launch = [ "Meta+Shift+5" ]; 268 + captureActiveWindow = [ "Meta+Shift+Alt+4" ]; 269 + }; 270 + 271 + # Spectacle save location and format 272 + # mac: system.defaults.screencapture.location = "~/Desktop", type = "png" 273 + configFile."spectaclerc" = { 274 + General.launchAction = "DoNotTakeScreenshot"; 275 + ImageSave.defaultFolder = "%DESKTOP%"; 276 + ImageSave.saveImageFormat = "PNG"; 277 + }; 278 + 279 + # ── Screen locker ────────────────────────────────────────────────────────── 280 + # mac: "Require password … after sleep or screen saver begins" (immediately) 281 + # + 5-minute idle auto-lock. 282 + kscreenlocker = { 283 + autoLock = true; 284 + timeout = 5; # lock after 5 min idle 285 + lockOnResume = true; # lock on wake from sleep 286 + passwordRequired = true; 287 + passwordRequiredDelay = 0; # no grace period 288 + }; 289 + 290 + # ── Notifications — top-right (macOS notification banner position) ───────── 291 + configFile."plasmanotifyrc".Notifications.PopupPosition = "TopRight"; 292 + 293 + # ── Dolphin — mirrors macOS Finder preferences ──────────────────────────── 294 + # mac: finder.AppleShowAllExtensions = true 295 + # finder._FXSortFoldersFirst = true 296 + # finder.ShowPathbar = true 297 + # finder.ShowStatusBar = false 298 + # finder._FXShowPosixPathInTitle = true 299 + # finder.FXDefaultSearchScope = "SCcf" 300 + configFile."dolphinrc" = { 301 + General = { 302 + ShowHiddenFiles = true; 303 + SortFoldersFirst = true; 304 + ShowStatusBar = false; 305 + BreadcrumbNavigation = true; 306 + }; 307 + DetailsMode."ExpandableFolders" = false; 308 + "KFileDialog Settings"."Show Full Path" = true; 309 + }; 310 + 311 + # ── Panels ───────────────────────────────────────────────────────────────── 120 312 121 313 panels = [ 122 314 123 - # ── Top menu bar ───────────────────────────────────────────────────────── 124 - # Full-width, always visible, 28 px — hosts the global app menu. 125 - # Mirrors the macOS menu bar: launcher on left, app menus inline, 126 - # tray + clock on right. 315 + # ── Top menu bar ────────────────────────────────────────────────────────── 316 + # Full-width, always visible, 28 px tall. 317 + # Left: [Launcher] [Global App Menu — File Edit View …] 318 + # Right: [System Tray] [Clock 12h + seconds] 127 319 { 128 320 location = "top"; 129 321 floating = false; ··· 131 323 132 324 widgets = [ 133 325 134 - # Application launcher (Apple menu equivalent) 326 + # Application launcher — the "Apple menu" / NixOS logo equivalent. 135 327 { 136 328 name = "org.kde.plasma.kickoff"; 137 329 config.General = { ··· 140 332 }; 141 333 } 142 334 143 - # Global app menu — active window's menus appear here 335 + # Global app menu — active window's menu bar appears inline here, 336 + # just as on macOS every app's menu bar lives at the top. 144 337 "org.kde.plasma.appmenu" 145 338 146 - # Flexible spacer 339 + # Flexible spacer — pushes tray + clock to the far right. 147 340 "org.kde.plasma.panelspacer" 148 341 149 - # System tray 342 + # System tray — equivalent to macOS menu-bar extras. 150 343 { 151 344 name = "org.kde.plasma.systemtray"; 152 345 config.General.shownItems = 3; 153 346 } 154 347 155 - # Clock — mirroring mac menuExtraClock: 156 - # ShowAMPM = true (12-hour) 157 - # ShowSeconds = true 158 - # ShowDate = 0 (never) 159 - # ShowDayOfWeek = false 348 + # Digital clock — mirrors macOS menuExtraClock: 349 + # ShowAMPM = true, ShowSeconds = true 350 + # ShowDate = 0 (never), ShowDayOfWeek = false 160 351 { 161 352 name = "org.kde.plasma.digitalclock"; 162 353 config.Appearance = { ··· 171 362 ]; 172 363 } 173 364 174 - # ── Bottom dock ─────────────────────────────────────────────────────────── 175 - # Floating, centred, always visible (mac dock.autohide = false). 176 - # Icon-only task manager — no labels — mirrors the macOS dock. 177 - # Height 56 ≈ tilesize 46 + padding (mac dock.tilesize = 46). 365 + # ── Bottom floating dock ────────────────────────────────────────────────── 366 + # Centred, floating, always visible. 367 + # mac: dock.autohide = false dock.tilesize = 46 dock.orientation = "bottom" 368 + # Height 56 px ≈ icon size 46 + padding. 178 369 { 179 370 location = "bottom"; 180 371 floating = true; 181 372 height = 56; 182 373 alignment = "center"; 183 - lengthMode = "fit"; 184 - hiding = "none"; # mac: dock.autohide = false 374 + lengthMode = "fit"; # shrinks to fit its launchers 375 + hiding = "none"; # always visible 185 376 186 377 widgets = [ 187 378 { ··· 190 381 showOnlyCurrentDesktop = "false"; 191 382 showOnlyCurrentScreen = "false"; 192 383 launchers = [ 193 - "applications:org.kde.dolphin.desktop" # Files (Finder) 384 + "applications:org.kde.dolphin.desktop" # Dolphin ≡ Finder 194 385 "applications:signal-desktop.desktop" 195 386 "applications:obsidian.desktop" 196 387 "applications:spotify.desktop" ··· 205 396 ]; 206 397 } 207 398 208 - ]; 209 - 210 - # ── KWin config via configFile ──────────────────────────────────────────── 211 - configFile."kwinrc" = { 212 - 213 - # Blur behind panels and menus (frosted-glass macOS look) 214 - Plugins.blurEnabled = true; 215 - "Effect-blur" = { 216 - BlurStrength = 7; 217 - NoiseStrength = 0; 218 - }; 219 - 220 - # Magic Lamp minimise animation — mirrors mac dock.minimize-to-application = true. 221 - # The window squishes into the dock icon rather than zooming to the centre. 222 - Plugins.magiclampEnabled = true; 223 - Plugins.squashEnabled = false; 224 - 225 - # Faster animations — snappier than KDE default (3) 226 - Compositing.AnimationSpeed = 2; 227 - 228 - # Hot corners — mirroring mac dock wvous-* settings: 229 - # BL → Mission Control (Overview in KDE = 9) 230 - # BR → Desktop (ShowDesktop = 4) 231 - # TL → None (None = 0) 232 - # TR → Screen Saver (LockScreen = 5, closest KDE equivalent) 233 - ElectricBorders = { 234 - BottomLeft = "Overview"; # mac: wvous-bl-corner = 2 (Mission Control) 235 - BottomRight = "ShowDesktop"; # mac: wvous-br-corner = 4 (Desktop) 236 - TopLeft = "None"; # mac: wvous-tl-corner = 1 (None) 237 - TopRight = "LockScreen"; # mac: wvous-tr-corner = 5 (Screen Saver) 238 - }; 239 - }; 240 - 241 - # ── KRunner = Spotlight (Meta+Space) ───────────────────────────────────── 242 - configFile."kglobalshortcutsrc".krunner = { 243 - _launch = "Meta+Space,Alt+F2,Run Command"; 244 - RunClipboard = "Meta+Shift+Space,Alt+Shift+F2,Run Command on clipboard contents"; 245 - }; 246 - 247 - # ── Notifications — top-right (macOS position) ──────────────────────────── 248 - configFile."plasmanotifyrc".Notifications.PopupPosition = "TopRight"; 249 - 250 - # ── Splash screen — none (macOS has none) ──────────────────────────────── 251 - configFile."ksplashrc".KSplash = { 252 - Engine = "none"; 253 - Theme = "None"; 254 - }; 255 - 256 - # ── Dolphin (file manager) ──────────────────────────────────────────────── 257 - # mirrors: finder.AppleShowAllExtensions = true 258 - # finder._FXSortFoldersFirst = true 259 - # finder.ShowPathbar = true 260 - # finder.ShowStatusBar = false 261 - # finder._FXShowPosixPathInTitle = true 262 - # finder.FXDefaultSearchScope = "SCcf" (search current folder) 263 - configFile."dolphinrc".General = { 264 - ShowHiddenFiles = true; 265 - SortFoldersFirst = true; # mac: finder._FXSortFoldersFirst = true 266 - ShowStatusBar = false; # mac: finder.ShowStatusBar = false 267 - BreadcrumbNavigation = true; # mac: finder.ShowPathbar = true 268 - }; 269 - configFile."dolphinrc".DetailsMode.ExpandableFolders = false; 399 + ]; # end panels 270 400 271 - # Display full posix path in the Dolphin title bar 272 - # mac: finder._FXShowPosixPathInTitle = true 273 - configFile."dolphinrc"."KFileDialog Settings"."Show Full Path" = true; 274 - 275 - # ── Spectacle (screenshot) ──────────────────────────────────────────────── 276 - # mac: screencapture.location = "~/Desktop" screencapture.type = "png" 277 - configFile."spectaclerc" = { 278 - General.launchAction = "DoNotTakeScreenshot"; 279 - ImageSave.defaultFolder = "%DESKTOP%"; 280 - ImageSave.saveImageFormat = "PNG"; 281 - }; 282 - 283 - }; 401 + }; # end programs.plasma 284 402 }