From 68f37753f5f48af1b440344cff939f5f96e75b50 Mon Sep 17 00:00:00 2001 From: duynguyen Date: Fri, 14 Aug 2026 00:17:36 +0700 Subject: [PATCH] feat: replace waybar/walker/swaylock/swaybg with noctalia shell --- flake.nix | 3 +- home/duynguyen/config/niri/config.kdl | 277 ------------------ home/duynguyen/config/waybar/config.json | 154 ---------- home/duynguyen/config/waybar/style.css | 95 ------ home/duynguyen/default.nix | 248 ---------------- home/hosts/nixos.nix | 23 ++ home/modules/applications/default.nix | 93 ++++++ home/modules/cli/default.nix | 23 ++ home/modules/kitty/default.nix | 7 + home/modules/niri/default.nix | 98 +++++++ home/modules/niri/noctalia/default.nix | 78 +++++ .../niri/noctalia}/wallpapers/.gitkeep | 0 .../noctalia}/wallpapers/even-in-arcadia.png | Bin home/modules/niri/polkit/default.nix | 18 ++ 14 files changed, 342 insertions(+), 775 deletions(-) delete mode 100644 home/duynguyen/config/niri/config.kdl delete mode 100644 home/duynguyen/config/waybar/config.json delete mode 100644 home/duynguyen/config/waybar/style.css delete mode 100644 home/duynguyen/default.nix create mode 100644 home/hosts/nixos.nix create mode 100644 home/modules/applications/default.nix create mode 100644 home/modules/cli/default.nix create mode 100644 home/modules/kitty/default.nix create mode 100644 home/modules/niri/default.nix create mode 100644 home/modules/niri/noctalia/default.nix rename home/{duynguyen => modules/niri/noctalia}/wallpapers/.gitkeep (100%) rename home/{duynguyen => modules/niri/noctalia}/wallpapers/even-in-arcadia.png (100%) create mode 100644 home/modules/niri/polkit/default.nix diff --git a/flake.nix b/flake.nix index 5c07246..7ad5e47 100644 --- a/flake.nix +++ b/flake.nix @@ -38,8 +38,9 @@ home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; home-manager.extraSpecialArgs = { inherit inputs; }; + home-manager.backupFileExtension = "hm-back"; home-manager.sharedModules = [ plasma-manager.homeModules.plasma-manager ]; - home-manager.users.duynguyen = import ./home/duynguyen/default.nix; + home-manager.users.duynguyen = import ./home/hosts/nixos.nix; } ]; }; diff --git a/home/duynguyen/config/niri/config.kdl b/home/duynguyen/config/niri/config.kdl deleted file mode 100644 index 4731ef0..0000000 --- a/home/duynguyen/config/niri/config.kdl +++ /dev/null @@ -1,277 +0,0 @@ -// 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 - accel-profile "flat" - scroll-factor 1.0 - } - - 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 1.5 - transform "normal" - position x=1280 y=0 -} - -layout { - gaps 8 - 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 1 - 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 "noctalia" -spawn-at-startup "xwayland-satellite" - -hotkey-overlay { - skip-at-startup -} - -screenshot-path null - -gestures { - hot-corners { - off - } -} - -prefer-no-csd - -animations { - slowdown 0.5 -} - -window-rule { - match app-id=r#"^org\.wezfurlong\.wezterm$"# - default-column-width {} -} - -// Rounded corners -window-rule { - geometry-corner-radius 12 - clip-to-geometry true -} - -// Floating windows -window-rule { - match app-id=r#"^Tk$"# - match app-id=r#"^gimp$"# title=r#"Preferences"# - match app-id=r#"^mpv$"# - match app-id=r#"^soffice$"# title=r#"^Text Import"# - match app-id=r#"^thunar$"# title=r#"^Rename "# - match app-id=r#"^xarchiver$"# - match app-id=r#"firefox$"# title=r#"^(Picture-in-Picture|Library|About Mozilla Firefox|Firefox - Choose a profile)$"# - - open-floating true -} - -binds { - Mod+Shift+Slash { show-hotkey-overlay; } - - Mod+T hotkey-overlay-title="Open a Terminal: kitty" { spawn "kitty"; } - Mod+Space hotkey-overlay-title="Noctalia: Launcher" { spawn "noctalia-ipc" "panel-toggle" "launcher"; } - Mod+S hotkey-overlay-title="Noctalia: Control Center" { spawn "noctalia-ipc" "panel-toggle" "control-center"; } - Super+Alt+L hotkey-overlay-title="Noctalia: Lock" { spawn "noctalia-ipc" "session" "lock"; } - - 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+Shift+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+Shift+Left { move-column-left; } - Mod+Shift+Down { move-window-down; } - Mod+Shift+Up { move-window-up; } - Mod+Shift+Right { move-column-right; } - Mod+Shift+H { move-column-left; } - Mod+Shift+J { move-window-down; } - Mod+Shift+K { move-window-up; } - Mod+Shift+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+Ctrl+Left { focus-monitor-left; } - Mod+Ctrl+Down { focus-monitor-down; } - Mod+Ctrl+Up { focus-monitor-up; } - Mod+Ctrl+Right { focus-monitor-right; } - Mod+Ctrl+H { focus-monitor-left; } - Mod+Ctrl+J { focus-monitor-down; } - Mod+Ctrl+K { focus-monitor-up; } - Mod+Ctrl+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; } - Mod+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/home/duynguyen/config/waybar/config.json b/home/duynguyen/config/waybar/config.json deleted file mode 100644 index 2fe7657..0000000 --- a/home/duynguyen/config/waybar/config.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "reload_style_on_change": true, - "layer": "top", - "position": "top", - "spacing": 0, - "height": 24, - "modules-left": [ - "custom/menu", - "niri/workspaces" - ], - "modules-center": [ - "clock" - ], - "modules-right": [ - "group/tray-expander", - "pulseaudio", - "bluetooth", - "network", - "cpu", - "battery" - ], - - "custom/menu": { - "format": "󰣇", - "on-click": "walker", - "tooltip-format": "Open launcher" - }, - - "niri/workspaces": { - "on-click": "activate", - "on-click-right": "niri msg action toggle-overview", - "format": "{icon}", - "format-icons": { - "default": "", - "1": "1", - "2": "2", - "3": "3", - "4": "4", - "5": "5", - "6": "6", - "7": "7", - "8": "8", - "9": "9", - "active": "󱓻" - } - }, - - "clock": { - "format": "{:%I:%M %p %Z :: %a %b %d %Y}", - "format-alt": "{:%H:%M %Z :: %a %b %d %Y}", - "tooltip": true, - "tooltip-format": "{calendar}", - "timezones": ["", "UTC"], - "on-click-right": "xdg-open https://calendar.google.com", - "actions": { - "on-scroll-up": "tz_up", - "on-scroll-down": "tz_down" - }, - "calendar": { - "mode": "year", - "mode-mon-col": 3, - "weeks-pos": "right", - "on-scroll": 1, - "format": { - "months": "{}", - "days": "{}", - "weeks": "W{:%V}", - "weekdays": "{}", - "today": "{}" - } - } - }, - - "group/tray-expander": { - "orientation": "horizontal", - "drawer": { - "transition-duration": 300, - "children-class": "tray-group-item" - }, - "modules": [ - "custom/expand-icon", - "tray" - ] - }, - - "custom/expand-icon": { - "format": "", - "tooltip": false - }, - - "tray": { - "icon-size": 12, - "spacing": 12 - }, - - "pulseaudio": { - "format": "{icon}", - "on-click": "wiremix", - "on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", - "tooltip-format": "Playback volume: {volume}%", - "scroll-step": 5, - "format-muted": "󰝟", - "format-icons": { - "default": ["", "", ""] - } - }, - - "bluetooth": { - "format": "", - "format-disabled": "󰂲", - "format-connected": "", - "tooltip-format": "Devices connected: {num_connections}", - "on-click": "blueman-manager" - }, - - "network": { - "format-icons": ["󰤯", "󰤟", "󰤢", "󰤥", "󰤨"], - "format": "{icon}", - "format-wifi": "{icon}", - "format-ethernet": "󰀂", - "format-disconnected": "󰖪", - "tooltip-format-wifi": "{essid} ({frequency} GHz)\n⇣{bandwidthDownBytes} ⇡{bandwidthUpBytes}\n\n{ipaddr}", - "tooltip-format-ethernet": "⇣{bandwidthDownBytes} ⇡{bandwidthUpBytes}\n\n{ipaddr}", - "tooltip-format-disconnected": "Disconnected", - "interval": 10, - "on-click-right": "xdg-open https://speedtest.net" - }, - - "cpu": { - "interval": 5, - "format": "󰍛", - "on-click": "kitty -e btop", - "tooltip-format": "CPU usage: {usage}%" - }, - - "battery": { - "format": "{capacity}% {icon}", - "format-discharging": "{icon}", - "format-charging": "{icon}", - "format-plugged": "", - "format-icons": { - "charging": ["󰢜", "󰂆", "󰂇", "󰂈", "󰢝", "󰂉", "󰢞", "󰂊", "󰂋", "󰂅"], - "default": ["󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"] - }, - "format-full": "󰂅", - "tooltip-format-discharging": "{power:>1.0f}W↓ {capacity}%", - "tooltip-format-charging": "{power:>1.0f}W↑ {capacity}%", - "interval": 5, - "states": { - "warning": 20, - "critical": 10 - } - } -} diff --git a/home/duynguyen/config/waybar/style.css b/home/duynguyen/config/waybar/style.css deleted file mode 100644 index 4d6093a..0000000 --- a/home/duynguyen/config/waybar/style.css +++ /dev/null @@ -1,95 +0,0 @@ -* { - font-family: "JetBrainsMono Nerd Font", "Font Awesome 6 Free", "FreeSans", sans-serif; - font-size: 13px; - border: none; - border-radius: 0; - min-height: 0; - margin: 0; - padding: 0; -} - -window#waybar { - background-color: #1e1e2e; - color: #cdd6f4; -} - -.modules-left, -.modules-center, -.modules-right { - margin: 4px 8px; -} - -#workspaces button { - padding: 0 8px; - color: #6c7086; - background: transparent; -} - -#workspaces button.active { - color: #cdd6f4; - font-weight: bold; -} - -#workspaces button:hover { - color: #89b4fa; - box-shadow: none; - text-shadow: none; - background: transparent; -} - -#window { - color: #a6adc8; - padding: 0 8px; -} - -#clock, -#battery, -#network, -#pulseaudio, -#bluetooth, -#cpu, -#tray, -#custom-menu, -#custom-expand-icon { - padding: 0 10px; - color: #cdd6f4; -} - -#clock { - font-weight: bold; -} - -#custom-menu { - color: #89b4fa; - font-size: 16px; - padding: 0 12px; -} - -#custom-expand-icon { - padding: 0 6px; - color: #6c7086; -} - -.tray-group-item { - padding: 0 4px; -} - -#battery.warning { - color: #f9e2af; -} - -#battery.critical { - color: #f38ba8; -} - -#network.disconnected { - color: #f38ba8; -} - -#bluetooth.disabled { - color: #6c7086; -} - -#pulseaudio.muted { - color: #6c7086; -} diff --git a/home/duynguyen/default.nix b/home/duynguyen/default.nix deleted file mode 100644 index 102f45b..0000000 --- a/home/duynguyen/default.nix +++ /dev/null @@ -1,248 +0,0 @@ -{ config, pkgs, lib, inputs, ... }: - -let - wallpaperDir = "${config.home.homeDirectory}/.config/wallpapers"; - defaultWallpaper = "${wallpaperDir}/even-in-arcadia.png"; - - # Thin wrapper so niri keybinds can call noctalia msg - # without hard-coding the nix-store path. - noctaliaIpc = pkgs.writeShellScriptBin "noctalia-ipc" '' - set -eu - exec noctalia msg "$@" - ''; -in -{ - imports = [ - inputs.noctalia.homeModules.default - ]; - - home.username = "duynguyen"; - 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; [ - noctaliaIpc - - # Browsers - zen-browser - claude-desktop - - # Terminals - ghostty - kitty - foot - - # Niri supporting tools - xwayland-satellite # X11 app support in Niri - xdg-utils # xdg-open, file associations - inotify-tools # filesystem event tools - - # Polkit agent for Niri session (graphical auth dialogs) - kdePackages.polkit-kde-agent-1 - - # Editor - vscodium - - # Daily apps - mpv - imv - gimp - obs-studio - zathura - thunar - xfce.thunar-archive-plugin - xfce.tumbler - ffmpegthumbnailer - xarchiver - grim - slurp - swappy - libreoffice - telegram-desktop - pavucontrol - blueman - - # Clipboard - cliphist - wl-clipboard - - # CLI tools - vim - neovim - tmux - fastfetch - btop - ripgrep - fd - fzf - eza - bat - dust - jq - yq - shellcheck - ffmpeg - imagemagick - unzip - p7zip - wiremix - - # System control - brightnessctl - playerctl - - # Dev tools - gh - ]; - - # Required for Electron apps (VSCodium, Zen Browser, etc.) to use - # Wayland natively and work correctly with fcitx5 input - home.sessionVariables.NIXOS_OZONE_WL = "1"; - - # Wallpapers folder — add images to home/duynguyen/wallpapers/ in the repo - # and rebuild; noctalia reads from ~/.config/wallpapers - xdg.configFile."wallpapers".source = ./wallpapers; - - # Polkit agent as a systemd user service so it starts with the Niri session - systemd.user.services.polkit-kde-agent = { - Unit = { - Description = "KDE Polkit Authentication Agent"; - PartOf = [ "graphical-session.target" ]; - After = [ "graphical-session.target" ]; - }; - Service = { - ExecStart = "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1"; - Restart = "on-failure"; - RestartSec = 1; - }; - Install.WantedBy = [ "graphical-session.target" ]; - }; - - # ── Noctalia ────────────────────────────────────────────────────────────── - # Replaces: waybar, walker, swaylock, swaybg, swayidle, mako - programs.noctalia = { - enable = true; - settings = { - bar.default = { - start = [ "launcher" "clipboard" "cpu" "network" "ram" ]; - center = [ "clock" ]; - end = [ "notifications" "volume" "brightness" "battery" "control-center" "session" ]; - thickness = 40; - padding = 10; - radius = 0; - margin_edge = 0; - margin_ends = 0; - widget_spacing = 8; - }; - - idle = { - behavior_order = [ "lock" "screen-off" ]; - behavior = { - lock = { - action = "lock"; - enabled = true; - timeout = 600; # 10 min - }; - screen-off = { - action = "screen_off"; - enabled = true; - timeout = 660; - }; - }; - }; - - lockscreen.wallpaper = defaultWallpaper; - - nightlight.enabled = true; - - osd.position = "top_right"; - - shell = { - font_family = "JetBrainsMono Nerd Font"; - polkit_agent = true; - corner_radius_scale = 0.0; - animation.speed = 1.5; - panel = { - clipboard_placement = "attached"; - launcher_placement = "attached"; - launcher_session_search = true; - }; - shadow.alpha = 0.5; - }; - - theme.builtin = "Kanagawa"; - - wallpaper = { - enabled = true; - directory = wallpaperDir; - default.path = defaultWallpaper; - }; - }; - }; - - # ── Shell ───────────────────────────────────────────────────────────────── - programs.zsh = { - enable = true; - autosuggestion.enable = true; - syntaxHighlighting.enable = true; - }; - - programs.kitty = { - enable = true; - settings.wheel_scroll_multiplier = 10; - }; - - programs.zoxide = { - enable = true; - enableZshIntegration = true; - }; - - programs.starship.enable = true; - - programs.git = { - enable = true; - settings.user = { - name = "duynguyen"; - email = "huonghaiduynhim@gmail.com"; - }; - }; - - # ── KDE Plasma (for the Plasma session; dark theme + touchpad) ──────────── - 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; - } - ]; - }; - - # ── Zen Browser scroll speed ────────────────────────────────────────────── - home.activation.zenBrowserUserJs = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - for profile in "$HOME/.config/zen/"*.*/; do - [[ -d "$profile" ]] || continue - echo 'user_pref("mousewheel.default.delta_multiplier_y", 50);' > "$profile/user.js" - done - ''; - - # ── Niri config ─────────────────────────────────────────────────────────── - xdg.configFile."niri/config.kdl".source = - pkgs.runCommand "niri-config-checked" - { nativeBuildInputs = [ pkgs.niri ]; } - '' - niri validate -c ${./config/niri/config.kdl} - cp ${./config/niri/config.kdl} $out - ''; - - programs.home-manager.enable = true; -} diff --git a/home/hosts/nixos.nix b/home/hosts/nixos.nix new file mode 100644 index 0000000..28213f5 --- /dev/null +++ b/home/hosts/nixos.nix @@ -0,0 +1,23 @@ +{ lib, ... }: +{ + home.username = "duynguyen"; + home.homeDirectory = "/home/duynguyen"; + home.stateVersion = "26.05"; + + imports = [ + ../modules/niri + ../modules/kitty + ../modules/cli + ../modules/applications + ]; + + # Zen Browser scroll speed — written to all profiles so it survives profile ID changes + home.activation.zenBrowserUserJs = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + for profile in "$HOME/.config/zen/"*.*/; do + [[ -d "$profile" ]] || continue + echo 'user_pref("mousewheel.default.delta_multiplier_y", 50);' > "$profile/user.js" + done + ''; + + programs.home-manager.enable = true; +} diff --git a/home/modules/applications/default.nix b/home/modules/applications/default.nix new file mode 100644 index 0000000..b1c7263 --- /dev/null +++ b/home/modules/applications/default.nix @@ -0,0 +1,93 @@ +{ pkgs, ... }: +{ + # home-manager's fontconfig module references removed nodePackages; + # NixOS manages fontconfig at the system level anyway + fonts.fontconfig.enable = false; + + home.sessionVariables.NIXOS_OZONE_WL = "1"; + + home.packages = with pkgs; [ + # Browsers + zen-browser + claude-desktop + + # Terminals + ghostty + kitty + foot + + # Niri support + xdg-utils + inotify-tools + + # Editor + vscodium + + # Daily apps + mpv + imv + gimp + obs-studio + zathura + thunar + xfce.thunar-archive-plugin + xfce.tumbler + ffmpegthumbnailer + xarchiver + grim + slurp + swappy + libreoffice + telegram-desktop + pavucontrol + blueman + + # Clipboard + cliphist + wl-clipboard + + # CLI tools + vim + neovim + tmux + fastfetch + btop + ripgrep + fd + fzf + eza + bat + dust + jq + yq + shellcheck + ffmpeg + imagemagick + unzip + p7zip + wiremix + + # System control + brightnessctl + playerctl + + # Dev tools + gh + ]; + + # KDE Plasma session: dark theme + touchpad preferences + 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; + } + ]; + }; +} diff --git a/home/modules/cli/default.nix b/home/modules/cli/default.nix new file mode 100644 index 0000000..61c573f --- /dev/null +++ b/home/modules/cli/default.nix @@ -0,0 +1,23 @@ +{ ... }: +{ + programs.zsh = { + enable = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + }; + + programs.zoxide = { + enable = true; + enableZshIntegration = true; + }; + + programs.starship.enable = true; + + programs.git = { + enable = true; + settings.user = { + name = "duynguyen"; + email = "huonghaiduynhim@gmail.com"; + }; + }; +} diff --git a/home/modules/kitty/default.nix b/home/modules/kitty/default.nix new file mode 100644 index 0000000..e563220 --- /dev/null +++ b/home/modules/kitty/default.nix @@ -0,0 +1,7 @@ +{ ... }: +{ + programs.kitty = { + enable = true; + settings.wheel_scroll_multiplier = 10; + }; +} diff --git a/home/modules/niri/default.nix b/home/modules/niri/default.nix new file mode 100644 index 0000000..d1c5253 --- /dev/null +++ b/home/modules/niri/default.nix @@ -0,0 +1,98 @@ +{ pkgs, lib, ... }: +let + # Start from niri's own default config so we inherit every new default + # automatically on updates. We patch only what we need to change. + base = builtins.readFile "${pkgs.niri.doc}/share/doc/niri/default-config.kdl"; + + # waybar → noctalia + add xwayland-satellite + r1 = builtins.replaceStrings + [ "spawn-at-startup \"waybar\"\n" ] + [ "spawn-at-startup \"noctalia\"\nspawn-at-startup \"xwayland-satellite\"\n" ] + base; + + # terminal: alacritty → kitty + r2 = builtins.replaceStrings + [ " Mod+T hotkey-overlay-title=\"Open a Terminal: alacritty\" { spawn \"alacritty\"; }\n" ] + [ " Mod+T hotkey-overlay-title=\"Open a Terminal: kitty\" { spawn \"kitty\"; }\n" ] + r1; + + # launcher: fuzzel → noctalia launcher + control-center + r3 = builtins.replaceStrings + [ " Mod+D hotkey-overlay-title=\"Run an Application: fuzzel\" { spawn \"fuzzel\"; }\n" ] + [ " Mod+Space hotkey-overlay-title=\"Noctalia: Launcher\" { spawn \"noctalia-ipc\" \"panel-toggle\" \"launcher\"; }\n Mod+S hotkey-overlay-title=\"Noctalia: Control Center\" { spawn \"noctalia-ipc\" \"panel-toggle\" \"control-center\"; }\n" ] + r2; + + # lock: swaylock → noctalia + r4 = builtins.replaceStrings + [ " Super+Alt+L hotkey-overlay-title=\"Lock the Screen: swaylock\" { spawn \"swaylock\"; }\n" ] + [ " Super+Alt+L hotkey-overlay-title=\"Noctalia: Lock\" { spawn \"noctalia-ipc\" \"session\" \"lock\"; }\n" ] + r3; + + # skip the hotkey overlay pop-up at startup + r5 = builtins.replaceStrings + [ " // skip-at-startup\n" ] + [ " skip-at-startup\n" ] + r4; + + # tighter gaps + r6 = builtins.replaceStrings + [ " gaps 16\n" ] + [ " gaps 8\n" ] + r5; + + # enable animations slowdown + r7 = builtins.replaceStrings + [ " // slowdown 3.0\n" ] + [ " slowdown 0.5\n" ] + r6; + + # Our additions appended after the patched default config. + # A second `input { touchpad { } }` block overrides earlier touchpad settings. + customConfig = '' + + // ── Touchpad ───────────────────────────────────────────────────────────── + input { + touchpad { + tap + natural-scroll + accel-profile "flat" + scroll-factor 1.0 + } + } + + // ── Prefer no client-side decorations ──────────────────────────────────── + prefer-no-csd + + // ── Gestures ───────────────────────────────────────────────────────────── + gestures { + hot-corners { + off + } + } + + // ── Rounded corners ────────────────────────────────────────────────────── + window-rule { + geometry-corner-radius 12 + clip-to-geometry true + } + + // ── Floating windows ───────────────────────────────────────────────────── + window-rule { + match app-id=r#"^Tk$"# + match app-id=r#"^gimp$"# title=r#"Preferences"# + match app-id=r#"^mpv$"# + match app-id=r#"^soffice$"# title=r#"^Text Import"# + match app-id=r#"^thunar$"# title=r#"^Rename "# + match app-id=r#"^xarchiver$"# + match app-id=r#"firefox$"# title=r#"^Picture-in-Picture$"# + + open-floating true + } + ''; +in +{ + imports = [ ./noctalia ./polkit ]; + + # .text writes a real file (not a nix-store symlink) so niri auto-reloads on rebuild + xdg.configFile."niri/config.kdl".text = r7 + customConfig; +} diff --git a/home/modules/niri/noctalia/default.nix b/home/modules/niri/noctalia/default.nix new file mode 100644 index 0000000..f54d005 --- /dev/null +++ b/home/modules/niri/noctalia/default.nix @@ -0,0 +1,78 @@ +{ config, inputs, pkgs, ... }: +let + wallpaperDir = "${config.home.homeDirectory}/.config/wallpapers"; + defaultWallpaper = "${wallpaperDir}/even-in-arcadia.png"; + + noctaliaIpc = pkgs.writeShellScriptBin "noctalia-ipc" '' + set -eu + exec noctalia msg "$@" + ''; +in +{ + imports = [ inputs.noctalia.homeModules.default ]; + + home.packages = [ noctaliaIpc ]; + + # Wallpapers tracked in the repo; linked to ~/.config/wallpapers for noctalia + xdg.configFile."wallpapers".source = ./wallpapers; + + programs.noctalia = { + enable = true; + settings = { + bar.default = { + start = [ "launcher" "clipboard" "cpu" "network" "ram" ]; + center = [ "clock" ]; + end = [ "notifications" "volume" "brightness" "battery" "control-center" "session" ]; + thickness = 40; + padding = 10; + radius = 0; + margin_edge = 0; + margin_ends = 0; + widget_spacing = 8; + }; + + idle = { + behavior_order = [ "lock" "screen-off" ]; + behavior = { + lock = { + action = "lock"; + enabled = true; + timeout = 600; + }; + screen-off = { + action = "screen_off"; + enabled = true; + timeout = 660; + }; + }; + }; + + lockscreen.wallpaper = defaultWallpaper; + + nightlight.enabled = true; + + osd.position = "top_right"; + + shell = { + font_family = "JetBrainsMono Nerd Font"; + polkit_agent = true; + corner_radius_scale = 0.0; + animation.speed = 1.5; + panel = { + clipboard_placement = "attached"; + launcher_placement = "attached"; + launcher_session_search = true; + }; + shadow.alpha = 0.5; + }; + + theme.builtin = "Kanagawa"; + + wallpaper = { + enabled = true; + directory = wallpaperDir; + default.path = defaultWallpaper; + }; + }; + }; +} diff --git a/home/duynguyen/wallpapers/.gitkeep b/home/modules/niri/noctalia/wallpapers/.gitkeep similarity index 100% rename from home/duynguyen/wallpapers/.gitkeep rename to home/modules/niri/noctalia/wallpapers/.gitkeep diff --git a/home/duynguyen/wallpapers/even-in-arcadia.png b/home/modules/niri/noctalia/wallpapers/even-in-arcadia.png similarity index 100% rename from home/duynguyen/wallpapers/even-in-arcadia.png rename to home/modules/niri/noctalia/wallpapers/even-in-arcadia.png diff --git a/home/modules/niri/polkit/default.nix b/home/modules/niri/polkit/default.nix new file mode 100644 index 0000000..51a0a25 --- /dev/null +++ b/home/modules/niri/polkit/default.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: +{ + home.packages = [ pkgs.kdePackages.polkit-kde-agent-1 ]; + + systemd.user.services.polkit-kde-agent = { + Unit = { + Description = "KDE Polkit Authentication Agent"; + PartOf = [ "graphical-session.target" ]; + After = [ "graphical-session.target" ]; + }; + Service = { + ExecStart = "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1"; + Restart = "on-failure"; + RestartSec = 1; + }; + Install.WantedBy = [ "graphical-session.target" ]; + }; +}