diff --git a/README.md b/README.md index b878af0..9a4229f 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,22 @@ nixos-config/ ## What's configured -- **KDE Plasma 6** on Wayland via SDDM +- **KDE Plasma 6** on Wayland via SDDM, Breeze Dark theme +- **Niri** scrollable-tiling compositor (available as a separate session at SDDM) - **Vietnamese input** via fcitx5 + unikey (Telex/VNI) - Open `fcitx5-configtool` → Input Method tab → add **Unikey** +- **Touchpad**: natural scroll, acceleration 0.4, scroll factor 0.75 +- **Shell**: zsh (default) with autosuggestions, syntax highlighting, starship prompt, zoxide - **Locale**: English UI, Vietnamese formats (currency, time, etc.), Asia/Ho_Chi_Minh timezone - **Pipewire** for audio -- **Packages**: firefox, kate, claude-code, git +- **Packages**: + - Browsers: firefox, zen-browser, claude-desktop + - Terminals: kitty, foot + - Editor: vscodium + - Niri tools: fuzzel, waybar, mako, wl-clipboard + - Daily apps: mpv, imv, grim + slurp, libreoffice, telegram-desktop + - CLI: btop, ripgrep, fzf, eza, bat, gh + - System: claude-code, git, kate ## Reproducing on a fresh machine diff --git a/flake.lock b/flake.lock index 1c79c83..b8f9ed0 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,42 @@ { "nodes": { + "claude-desktop": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1764098187, + "narHash": "sha256-H6JjWXhKqxZ8QLMoqndZx9e5x0Sv5AiipSmqvIxIbgo=", + "owner": "k3d3", + "repo": "claude-desktop-linux-flake", + "rev": "b2b040cb68231d2118906507d9cc8fd181ca6308", + "type": "github" + }, + "original": { + "owner": "k3d3", + "repo": "claude-desktop-linux-flake", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -23,11 +60,27 @@ }, "nixpkgs": { "locked": { - "lastModified": 1785858998, - "narHash": "sha256-fKCq5jphd6l/Ms6gc3dptkw/TcKLYub9lQE5g6rbbkc=", + "lastModified": 1749174413, + "narHash": "sha256-urN9UMK5cd1dzhR+Lx0xHeTgBp2MatA5+6g9JaxjuQs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "04607e1165ac22c5fde6dcc54c9e0b3c0487c555", + "rev": "6ad174a6dc07c7742fc64005265addf87ad08615", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1786089803, + "narHash": "sha256-ZuvZfVW2tB5tXYEcpcfhVXB3N4OhdZLOqOviy4OD4b4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ee48b147c18c7de1e6ec97dc74792be42724bed1", "type": "github" }, "original": { @@ -37,10 +90,71 @@ "type": "github" } }, + "plasma-manager": { + "inputs": { + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785762349, + "narHash": "sha256-jZhZkzAwc7f3exzcTDJWP2WCAchCv0iNC3UF/QsahdQ=", + "owner": "nix-community", + "repo": "plasma-manager", + "rev": "a19a2a029fa180911bd89c554dca1616e10f4c1d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "plasma-manager", + "type": "github" + } + }, "root": { "inputs": { + "claude-desktop": "claude-desktop", "home-manager": "home-manager", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2", + "plasma-manager": "plasma-manager", + "zen-browser": "zen-browser" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "zen-browser": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1786164819, + "narHash": "sha256-tvBlGAYyzHYdLwn035bRCrB1mcMjvNNavcNZ293AIIA=", + "owner": "youwen5", + "repo": "zen-browser-flake", + "rev": "f9af5f7017cea1c159e17922288fb38ff94d28cd", + "type": "github" + }, + "original": { + "owner": "youwen5", + "repo": "zen-browser-flake", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 21558c3..ec85d15 100644 --- a/flake.nix +++ b/flake.nix @@ -7,17 +7,34 @@ url = "github:nix-community/home-manager/release-26.05"; inputs.nixpkgs.follows = "nixpkgs"; }; + plasma-manager = { + url = "github:nix-community/plasma-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + zen-browser = { + url = "github:youwen5/zen-browser-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + claude-desktop.url = "github:k3d3/claude-desktop-linux-flake"; }; - outputs = { self, nixpkgs, home-manager, ... }: { + outputs = { self, nixpkgs, home-manager, plasma-manager, zen-browser, claude-desktop, ... }: { nixosConfigurations.nixos = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ ./hosts/nixos/configuration.nix home-manager.nixosModules.home-manager { + nixpkgs.overlays = [ + (_: _: { + zen-browser = zen-browser.packages.x86_64-linux.default; + claude-desktop = claude-desktop.packages.x86_64-linux.default; + }) + ]; home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; + home-manager.sharedModules = [ plasma-manager.homeModules.plasma-manager ]; home-manager.users.duynguyen = import ./home/duynguyen/default.nix; } ]; diff --git a/home/duynguyen/default.nix b/home/duynguyen/default.nix index c4c5154..d592c66 100644 --- a/home/duynguyen/default.nix +++ b/home/duynguyen/default.nix @@ -5,17 +5,97 @@ home.homeDirectory = "/home/duynguyen"; home.stateVersion = "26.05"; + # home-manager's fontconfig module references removed nodePackages; + # NixOS manages fontconfig at the system level anyway + fonts.fontconfig.enable = false; + home.packages = with pkgs; [ - # Add user-level packages here + # Browsers + zen-browser + claude-desktop + + # Terminals + kitty + foot # lightweight, good default for Niri + + # Niri supporting tools + fuzzel # app launcher + waybar # status bar + mako # notifications + wl-clipboard # copy/paste in Wayland terminal + swaylock # screen locker + swayidle # idle management + xwayland-satellite # X11 app support in Niri + + # Editor + vscodium + + # Daily apps + mpv + imv + grim # Wayland screenshot + slurp # region selector for grim + libreoffice + telegram-desktop + + # CLI tools + btop + ripgrep + fzf + eza # modern ls + bat # modern cat + + # Dev tools + gh ]; - programs.bash.enable = true; + # Required for Electron apps (VSCodium, Zen Browser, etc.) to use + # Wayland natively and work correctly with fcitx5 input + home.sessionVariables.NIXOS_OZONE_WL = "1"; + + programs.zsh = { + enable = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + }; + + programs.zoxide = { + enable = true; + enableZshIntegration = true; + }; + + programs.starship.enable = true; programs.git = { enable = true; - userName = "duynguyen"; - userEmail = "huonghaiduynhim@gmail.com"; + settings.user = { + name = "duynguyen"; + email = "huonghaiduynhim@gmail.com"; + }; }; + programs.plasma = { + enable = true; + workspace.lookAndFeel = "org.kde.breezedark.desktop"; + input.touchpads = [ + { + name = "SynPS/2 Synaptics TouchPad"; + vendorId = "2"; + productId = "7"; + naturalScroll = true; + pointerSpeed = 0.4; + scrollSpeed = 0.75; + } + ]; + }; + + xdg.configFile."niri/config.kdl".source = + pkgs.runCommand "niri-config-checked" + { nativeBuildInputs = [ pkgs.niri ]; } + '' + niri validate -c ${./niri.kdl} + cp ${./niri.kdl} $out + ''; + programs.home-manager.enable = true; } diff --git a/home/duynguyen/niri.kdl b/home/duynguyen/niri.kdl new file mode 100644 index 0000000..473fc9f --- /dev/null +++ b/home/duynguyen/niri.kdl @@ -0,0 +1,255 @@ +// This config is in the KDL format: https://kdl.dev +// "/-" comments out the following node. +// Check the wiki for a full description of the configuration: +// https://niri-wm.github.io/niri/Configuration:-Introduction + +input { + keyboard { + xkb { + // If this section is empty, niri will fetch xkb settings + // from org.freedesktop.locale1. You can control these using + // localectl set-x11-keymap. + } + numlock + } + + touchpad { + tap + natural-scroll + scroll-factor 0.3 + } + + mouse { + // natural-scroll + // accel-speed 0.2 + // accel-profile "flat" + } + + trackpoint { + // natural-scroll + // accel-speed 0.2 + } +} + +/-output "eDP-1" { + mode "1920x1080@120.030" + scale 2 + transform "normal" + position x=1280 y=0 +} + +layout { + gaps 16 + center-focused-column "never" + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + default-column-width { proportion 0.5; } + + focus-ring { + width 4 + active-color "#7fc8ff" + inactive-color "#505050" + } + + border { + off + width 4 + active-color "#ffc87f" + inactive-color "#505050" + urgent-color "#9b0000" + } + + shadow { + softness 30 + spread 5 + offset x=0 y=5 + color "#0007" + } + + struts { + // left 64 + // right 64 + // top 64 + // bottom 64 + } +} + +spawn-at-startup "waybar" +spawn-at-startup "xwayland-satellite" +spawn-at-startup "mako" + +hotkey-overlay { + // skip-at-startup +} + +screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + +animations { + // off + // slowdown 3.0 +} + +window-rule { + match app-id=r#"^org\.wezfurlong\.wezterm$"# + default-column-width {} +} + +window-rule { + match app-id=r#"firefox$"# title="^Picture-in-Picture$" + open-floating true +} + +binds { + Mod+Shift+Slash { show-hotkey-overlay; } + + Mod+T hotkey-overlay-title="Open a Terminal: kitty" { spawn "kitty"; } + Mod+D hotkey-overlay-title="Run an Application: fuzzel" { spawn "fuzzel"; } + Super+Alt+L hotkey-overlay-title="Lock the Screen: swaylock" { spawn "swaylock"; } + + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+ -l 1.0"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; } + XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; } + XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; } + + XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; } + XF86AudioPause allow-when-locked=true { spawn-sh "playerctl play-pause"; } + XF86AudioStop allow-when-locked=true { spawn-sh "playerctl stop"; } + XF86AudioPrev allow-when-locked=true { spawn-sh "playerctl previous"; } + XF86AudioNext allow-when-locked=true { spawn-sh "playerctl next"; } + + XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+10%"; } + XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "10%-"; } + + Mod+O repeat=false { toggle-overview; } + Mod+Q repeat=false { close-window; } + + Mod+Left { focus-column-left; } + Mod+Down { focus-window-down; } + Mod+Up { focus-window-up; } + Mod+Right { focus-column-right; } + Mod+H { focus-column-left; } + Mod+J { focus-window-down; } + Mod+K { focus-window-up; } + Mod+L { focus-column-right; } + + Mod+Ctrl+Left { move-column-left; } + Mod+Ctrl+Down { move-window-down; } + Mod+Ctrl+Up { move-window-up; } + Mod+Ctrl+Right { move-column-right; } + Mod+Ctrl+H { move-column-left; } + Mod+Ctrl+J { move-window-down; } + Mod+Ctrl+K { move-window-up; } + Mod+Ctrl+L { move-column-right; } + + Mod+Home { focus-column-first; } + Mod+End { focus-column-last; } + Mod+Ctrl+Home { move-column-to-first; } + Mod+Ctrl+End { move-column-to-last; } + + Mod+Shift+Left { focus-monitor-left; } + Mod+Shift+Down { focus-monitor-down; } + Mod+Shift+Up { focus-monitor-up; } + Mod+Shift+Right { focus-monitor-right; } + Mod+Shift+H { focus-monitor-left; } + Mod+Shift+J { focus-monitor-down; } + Mod+Shift+K { focus-monitor-up; } + Mod+Shift+L { focus-monitor-right; } + + Mod+Shift+Ctrl+Left { move-column-to-monitor-left; } + Mod+Shift+Ctrl+Down { move-column-to-monitor-down; } + Mod+Shift+Ctrl+Up { move-column-to-monitor-up; } + Mod+Shift+Ctrl+Right { move-column-to-monitor-right; } + Mod+Shift+Ctrl+H { move-column-to-monitor-left; } + Mod+Shift+Ctrl+J { move-column-to-monitor-down; } + Mod+Shift+Ctrl+K { move-column-to-monitor-up; } + Mod+Shift+Ctrl+L { move-column-to-monitor-right; } + + Mod+Page_Down { focus-workspace-down; } + Mod+Page_Up { focus-workspace-up; } + Mod+U { focus-workspace-down; } + Mod+I { focus-workspace-up; } + Mod+Ctrl+Page_Down { move-column-to-workspace-down; } + Mod+Ctrl+Page_Up { move-column-to-workspace-up; } + Mod+Ctrl+U { move-column-to-workspace-down; } + Mod+Ctrl+I { move-column-to-workspace-up; } + + Mod+Shift+Page_Down { move-workspace-down; } + Mod+Shift+Page_Up { move-workspace-up; } + Mod+Shift+U { move-workspace-down; } + Mod+Shift+I { move-workspace-up; } + + Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; } + Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; } + Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; } + Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; } + + Mod+WheelScrollRight { focus-column-right; } + Mod+WheelScrollLeft { focus-column-left; } + Mod+Ctrl+WheelScrollRight { move-column-right; } + Mod+Ctrl+WheelScrollLeft { move-column-left; } + + Mod+Shift+WheelScrollDown { focus-column-right; } + Mod+Shift+WheelScrollUp { focus-column-left; } + Mod+Ctrl+Shift+WheelScrollDown { move-column-right; } + Mod+Ctrl+Shift+WheelScrollUp { move-column-left; } + + Mod+1 { focus-workspace 1; } + Mod+2 { focus-workspace 2; } + Mod+3 { focus-workspace 3; } + Mod+4 { focus-workspace 4; } + Mod+5 { focus-workspace 5; } + Mod+6 { focus-workspace 6; } + Mod+7 { focus-workspace 7; } + Mod+8 { focus-workspace 8; } + Mod+9 { focus-workspace 9; } + Mod+Ctrl+1 { move-column-to-workspace 1; } + Mod+Ctrl+2 { move-column-to-workspace 2; } + Mod+Ctrl+3 { move-column-to-workspace 3; } + Mod+Ctrl+4 { move-column-to-workspace 4; } + Mod+Ctrl+5 { move-column-to-workspace 5; } + Mod+Ctrl+6 { move-column-to-workspace 6; } + Mod+Ctrl+7 { move-column-to-workspace 7; } + Mod+Ctrl+8 { move-column-to-workspace 8; } + Mod+Ctrl+9 { move-column-to-workspace 9; } + + Mod+BracketLeft { consume-or-expel-window-left; } + Mod+BracketRight { consume-or-expel-window-right; } + + Mod+Comma { consume-window-into-column; } + Mod+Period { expel-window-from-column; } + + Mod+R { switch-preset-column-width; } + Mod+Shift+R { switch-preset-column-width-back; } + Mod+Ctrl+Shift+R { switch-preset-window-height; } + Mod+Ctrl+R { reset-window-height; } + + Mod+F { maximize-column; } + Mod+Shift+F { fullscreen-window; } + Mod+M { maximize-window-to-edges; } + Mod+Ctrl+F { expand-column-to-available-width; } + Mod+C { center-column; } + Mod+Ctrl+C { center-visible-columns; } + + Mod+Minus { set-column-width "-10%"; } + Mod+Equal { set-column-width "+10%"; } + Mod+Shift+Minus { set-window-height "-10%"; } + Mod+Shift+Equal { set-window-height "+10%"; } + + Mod+V { toggle-window-floating; } + Mod+Shift+V { switch-focus-between-floating-and-tiling; } + Mod+W { toggle-column-tabbed-display; } + + Print { screenshot; } + Ctrl+Print { screenshot-screen; } + Alt+Print { screenshot-window; } + + Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + Mod+Shift+E { quit; } + Ctrl+Alt+Delete { quit; } + Mod+Shift+P { power-off-monitors; } +} diff --git a/hosts/nixos/configuration.nix b/hosts/nixos/configuration.nix index 5353e2e..a59230f 100644 --- a/hosts/nixos/configuration.nix +++ b/hosts/nixos/configuration.nix @@ -26,7 +26,6 @@ fcitx5.addons = with pkgs; [ qt6Packages.fcitx5-unikey fcitx5-gtk - fcitx5-configtool ]; }; @@ -65,6 +64,7 @@ users.users.duynguyen = { isNormalUser = true; description = "duynguyen"; + shell = pkgs.zsh; extraGroups = [ "networkmanager" "wheel" ]; packages = with pkgs; [ kdePackages.kate @@ -72,6 +72,10 @@ }; programs.firefox.enable = true; + programs.niri.enable = true; + programs.zsh.enable = true; + + security.polkit.enable = true; nixpkgs.config.allowUnfree = true;