diff --git a/home/duynguyen/niri.kdl b/home/duynguyen/config/niri/config.kdl
similarity index 83%
rename from home/duynguyen/niri.kdl
rename to home/duynguyen/config/niri/config.kdl
index 473fc9f..81e70f7 100644
--- a/home/duynguyen/niri.kdl
+++ b/home/duynguyen/config/niri/config.kdl
@@ -16,7 +16,8 @@ input {
touchpad {
tap
natural-scroll
- scroll-factor 0.3
+ accel-profile "flat"
+ scroll-factor 1.0
}
mouse {
@@ -33,13 +34,13 @@ input {
/-output "eDP-1" {
mode "1920x1080@120.030"
- scale 2
+ scale 1.5
transform "normal"
position x=1280 y=0
}
layout {
- gaps 16
+ gaps 8
center-focused-column "never"
preset-column-widths {
@@ -51,7 +52,7 @@ layout {
default-column-width { proportion 0.5; }
focus-ring {
- width 4
+ width 1
active-color "#7fc8ff"
inactive-color "#505050"
}
@@ -84,14 +85,21 @@ spawn-at-startup "xwayland-satellite"
spawn-at-startup "mako"
hotkey-overlay {
- // skip-at-startup
+ skip-at-startup
}
-screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
+screenshot-path null
+
+gestures {
+ hot-corners {
+ off
+ }
+}
+
+prefer-no-csd
animations {
- // off
- // slowdown 3.0
+ slowdown 0.5
}
window-rule {
@@ -99,8 +107,22 @@ window-rule {
default-column-width {}
}
+// Slight rounded corners
window-rule {
- match app-id=r#"firefox$"# title="^Picture-in-Picture$"
+ geometry-corner-radius 2
+ 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
}
@@ -126,7 +148,7 @@ binds {
XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "10%-"; }
Mod+O repeat=false { toggle-overview; }
- Mod+Q repeat=false { close-window; }
+ Mod+Shift+Q repeat=false { close-window; }
Mod+Left { focus-column-left; }
Mod+Down { focus-window-down; }
@@ -137,28 +159,28 @@ binds {
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+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+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+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; }
@@ -246,7 +268,7 @@ binds {
Print { screenshot; }
Ctrl+Print { screenshot-screen; }
- Alt+Print { screenshot-window; }
+ Mod+Print { screenshot-window; }
Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
Mod+Shift+E { quit; }
diff --git a/home/duynguyen/config/waybar/config.json b/home/duynguyen/config/waybar/config.json
new file mode 100644
index 0000000..2fe7657
--- /dev/null
+++ b/home/duynguyen/config/waybar/config.json
@@ -0,0 +1,154 @@
+{
+ "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
new file mode 100644
index 0000000..4d6093a
--- /dev/null
+++ b/home/duynguyen/config/waybar/style.css
@@ -0,0 +1,95 @@
+* {
+ 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
index d592c66..3de039e 100644
--- a/home/duynguyen/default.nix
+++ b/home/duynguyen/default.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
{
home.username = "duynguyen";
@@ -19,13 +19,18 @@
foot # lightweight, good default for Niri
# Niri supporting tools
- fuzzel # app launcher
- waybar # status bar
+ walker # app launcher
+ elephant # modular data provider for walker (clipboard, files, niri actions, etc.)
+ fuzzel # app launcher (alternative)
+ waybar
mako # notifications
wl-clipboard # copy/paste in Wayland terminal
swaylock # screen locker
swayidle # idle management
+ swaybg # wallpaper
xwayland-satellite # X11 app support in Niri
+ xdg-utils # xdg-open, file associations
+ inotify-tools # filesystem event tools
# Editor
vscodium
@@ -33,17 +38,49 @@
# Daily apps
mpv
imv
+ gimp
+ obs-studio
+ zathura # PDF viewer
+ thunar # file manager
+ xfce.thunar-archive-plugin # right-click archive operations
+ xfce.tumbler # thumbnail service
+ ffmpegthumbnailer # video thumbnails
+ xarchiver # archive manager GUI
grim # Wayland screenshot
slurp # region selector for grim
+ swappy # screenshot annotation
libreoffice
telegram-desktop
+ pavucontrol # audio GUI
+ blueman # Bluetooth GUI
+
+ # Clipboard
+ cliphist # clipboard history (pairs with wl-clipboard)
# CLI tools
+ vim
+ neovim
+ tmux
+ fastfetch
btop
ripgrep
+ fd # fast find alternative
fzf
eza # modern ls
bat # modern cat
+ dust # intuitive disk usage
+ jq # JSON processing
+ yq # YAML processing
+ shellcheck # shell script linter
+ ffmpeg
+ imagemagick
+ unzip
+ p7zip
+ wiremix # TUI PipeWire audio mixer
+
+ # System control
+ brightnessctl # brightness keys
+ playerctl # media keys
# Dev tools
gh
@@ -59,6 +96,17 @@
syntaxHighlighting.enable = true;
};
+ programs.waybar = {
+ enable = true;
+ style = builtins.readFile ./config/waybar/style.css;
+ settings = builtins.fromJSON (builtins.readFile ./config/waybar/config.json);
+ };
+
+ programs.kitty = {
+ enable = true;
+ settings.wheel_scroll_multiplier = 10;
+ };
+
programs.zoxide = {
enable = true;
enableZshIntegration = true;
@@ -89,12 +137,21 @@
];
};
+ # Zen Browser scroll speed — written to all profiles via activation script
+ # so it works even if the profile ID changes on a fresh install
+ 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
+ '';
+
xdg.configFile."niri/config.kdl".source =
pkgs.runCommand "niri-config-checked"
{ nativeBuildInputs = [ pkgs.niri ]; }
''
- niri validate -c ${./niri.kdl}
- cp ${./niri.kdl} $out
+ niri validate -c ${./config/niri/config.kdl}
+ cp ${./config/niri/config.kdl} $out
'';
programs.home-manager.enable = true;
diff --git a/hosts/nixos/configuration.nix b/hosts/nixos/configuration.nix
index a59230f..4c99a19 100644
--- a/hosts/nixos/configuration.nix
+++ b/hosts/nixos/configuration.nix
@@ -77,6 +77,21 @@
security.polkit.enable = true;
+ fonts.packages = with pkgs; [
+ freefont_ttf
+ noto-fonts-color-emoji
+ font-awesome
+ nerd-fonts.jetbrains-mono
+ ];
+
+ hardware.bluetooth.enable = true;
+ services.blueman.enable = true;
+
+ xdg.portal = {
+ enable = true;
+ extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
+ };
+
nixpkgs.config.allowUnfree = true;
environment.systemPackages = with pkgs; [