Initial commit: Nomarchy NixOS configuration
An opinionated NixOS configuration with Hyprland, featuring: - Modular flake-based architecture - Parameterized user configuration (username, timezone, locale, etc.) - Classical/antiquity theme with Thomas Cole wallpapers - Full Hyprland setup with waybar, rofi, swaync - Custom utility scripts (screenshots, screen recording, WiFi QR) - Neovim with LSP support - Interactive installer for existing NixOS systems - ISO builder for fresh installations Flake outputs: - nixosConfigurations.example - Test configuration - nixosConfigurations.installer - ISO installer - packages.iso - Bootable ISO image - apps.default - Interactive installer - lib.mkHost - Host builder function - templates.default - Starter template Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
25
modules/core/boot.nix
Normal file
25
modules/core/boot.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
# Boot configuration
|
||||
# Supports both systemd-boot (default) and Limine
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: let
|
||||
# For ISO builds, we'll use Limine; for regular installs, systemd-boot
|
||||
useSystemdBoot = nomarchyConfig.bootloader or "systemd-boot" == "systemd-boot";
|
||||
in {
|
||||
# Systemd-boot (default for NixOS installs)
|
||||
boot.loader.systemd-boot = lib.mkIf useSystemdBoot {
|
||||
enable = true;
|
||||
configurationLimit = 10;
|
||||
};
|
||||
|
||||
boot.loader.efi.canTouchEfiVariables = useSystemdBoot;
|
||||
|
||||
# Limine support (for ISO)
|
||||
boot.loader.limine = lib.mkIf (!useSystemdBoot) {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
8
modules/core/default.nix
Normal file
8
modules/core/default.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
# Core system modules
|
||||
{...}: {
|
||||
imports = [
|
||||
./boot.nix
|
||||
./networking.nix
|
||||
./hardware.nix
|
||||
];
|
||||
}
|
||||
37
modules/core/hardware.nix
Normal file
37
modules/core/hardware.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
# Hardware configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# Bluetooth
|
||||
hardware.bluetooth = lib.mkIf (nomarchyConfig.enableBluetooth or true) {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
};
|
||||
services.blueman.enable = nomarchyConfig.enableBluetooth or true;
|
||||
|
||||
# Graphics - hardware acceleration
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
# Audio - PipeWire (modern audio stack)
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
|
||||
# Bluetooth audio support
|
||||
environment.systemPackages = lib.mkIf (nomarchyConfig.enableBluetooth or true) (with pkgs; [
|
||||
blueman
|
||||
bluez
|
||||
bluez-tools
|
||||
]);
|
||||
}
|
||||
34
modules/core/networking.nix
Normal file
34
modules/core/networking.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
# Networking configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# NetworkManager with iwd backend (better WiFi handling)
|
||||
networking.wireless.enable = false;
|
||||
networking.networkmanager = {
|
||||
enable = true;
|
||||
wifi.backend = "iwd";
|
||||
};
|
||||
|
||||
# Firewall - enabled by default, ports configurable
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
|
||||
# Syncthing ports (if enabled)
|
||||
allowedTCPPorts = lib.optionals (nomarchyConfig.enableSyncthing or true) [
|
||||
8384 # Syncthing GUI
|
||||
22000 # Syncthing transfer
|
||||
];
|
||||
|
||||
allowedUDPPorts = lib.optionals (nomarchyConfig.enableSyncthing or true) [
|
||||
22000 # Syncthing transfer
|
||||
21027 # Syncthing discovery
|
||||
];
|
||||
};
|
||||
|
||||
# DNS resolution
|
||||
services.resolved.enable = true;
|
||||
}
|
||||
10
modules/default.nix
Normal file
10
modules/default.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
# Main modules index
|
||||
{...}: {
|
||||
imports = [
|
||||
./core
|
||||
./desktop
|
||||
./services
|
||||
./programs
|
||||
./performance
|
||||
];
|
||||
}
|
||||
7
modules/desktop/default.nix
Normal file
7
modules/desktop/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
# Desktop environment modules
|
||||
{...}: {
|
||||
imports = [
|
||||
./hyprland.nix
|
||||
./display-manager.nix
|
||||
];
|
||||
}
|
||||
25
modules/desktop/display-manager.nix
Normal file
25
modules/desktop/display-manager.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
# Display manager configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# X11 server (for SDDM and fallback)
|
||||
services.xserver.enable = true;
|
||||
|
||||
# SDDM display manager with Wayland support
|
||||
services.displayManager.sddm = {
|
||||
enable = true;
|
||||
wayland.enable = true;
|
||||
};
|
||||
|
||||
# Plasma 6 as fallback desktop (optional)
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
|
||||
# KDE Connect for phone integration
|
||||
programs.kdeconnect.enable = true;
|
||||
|
||||
# X keyboard layout (for SDDM)
|
||||
services.xserver.xkb.layout = "us";
|
||||
}
|
||||
78
modules/desktop/hyprland.nix
Normal file
78
modules/desktop/hyprland.nix
Normal file
@@ -0,0 +1,78 @@
|
||||
# Hyprland window manager configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# Enable Hyprland as a session option
|
||||
services.displayManager.sessionPackages = [
|
||||
inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland
|
||||
];
|
||||
|
||||
# Enable polkit for privilege escalation
|
||||
security.polkit.enable = true;
|
||||
|
||||
# XDG portal for screen sharing and file dialogs
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
extraPortals = [pkgs.xdg-desktop-portal-hyprland];
|
||||
};
|
||||
|
||||
# Hyprland ecosystem packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland
|
||||
|
||||
# Core utilities
|
||||
waybar
|
||||
swaynotificationcenter
|
||||
rofi-wayland
|
||||
hyprpaper
|
||||
hyprlock
|
||||
hypridle
|
||||
hyprpicker
|
||||
|
||||
# Screenshot tools
|
||||
grim
|
||||
slurp
|
||||
swappy
|
||||
satty
|
||||
|
||||
# Screen recording
|
||||
wf-recorder
|
||||
ffmpeg
|
||||
|
||||
# Clipboard
|
||||
wl-clipboard
|
||||
cliphist
|
||||
|
||||
# Brightness and audio control
|
||||
brightnessctl
|
||||
playerctl
|
||||
|
||||
# System utilities
|
||||
pavucontrol
|
||||
wdisplays
|
||||
networkmanagerapplet
|
||||
|
||||
# Night light
|
||||
gammastep
|
||||
|
||||
# QR code generation (for WiFi sharing)
|
||||
qrencode
|
||||
imv
|
||||
|
||||
# Debugging
|
||||
wev
|
||||
];
|
||||
|
||||
# Wayland environment variables
|
||||
environment.sessionVariables = {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
XDG_CURRENT_DESKTOP = "Hyprland";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
XDG_SESSION_DESKTOP = "Hyprland";
|
||||
};
|
||||
}
|
||||
62
modules/home/default.nix
Normal file
62
modules/home/default.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
# Home-manager configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: let
|
||||
username = nomarchyConfig.username;
|
||||
homeDir = "/home/${username}";
|
||||
|
||||
# Keyboard layout formatting
|
||||
kbLayouts = builtins.concatStringsSep "," nomarchyConfig.keyboardLayouts;
|
||||
kbVariants = builtins.concatStringsSep "," nomarchyConfig.keyboardVariants;
|
||||
in {
|
||||
imports = [
|
||||
./hyprland.nix
|
||||
./waybar.nix
|
||||
./rofi.nix
|
||||
./scripts.nix
|
||||
./shell.nix
|
||||
./notifications.nix
|
||||
./neovim.nix
|
||||
];
|
||||
|
||||
home = {
|
||||
inherit username;
|
||||
homeDirectory = homeDir;
|
||||
stateVersion = "24.11";
|
||||
|
||||
packages = with pkgs; [
|
||||
# Fonts
|
||||
font-awesome
|
||||
nerd-fonts.jetbrains-mono
|
||||
nerd-fonts.iosevka
|
||||
nerd-fonts.victor-mono
|
||||
nerd-fonts.fantasque-sans-mono
|
||||
nerd-fonts.fira-code
|
||||
nerd-fonts.monaspace
|
||||
];
|
||||
|
||||
sessionVariables = {
|
||||
PATH = "$HOME/.cargo/bin:$HOME/.local/bin:$PATH";
|
||||
EDITOR = "nvim";
|
||||
VISUAL = "nvim";
|
||||
};
|
||||
};
|
||||
|
||||
fonts.fontconfig.enable = true;
|
||||
|
||||
# Pass keyboard config to hyprland module
|
||||
_module.args.keyboardConfig = {
|
||||
layouts = kbLayouts;
|
||||
variants = kbVariants;
|
||||
};
|
||||
|
||||
# Enable programs
|
||||
programs.nix-init.enable = true;
|
||||
programs.cmus.enable = true;
|
||||
programs.satty.enable = true;
|
||||
programs.yazi.enable = true;
|
||||
}
|
||||
258
modules/home/hyprland.nix
Normal file
258
modules/home/hyprland.nix
Normal file
@@ -0,0 +1,258 @@
|
||||
# Hyprland user configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: let
|
||||
username = nomarchyConfig.username;
|
||||
homeDir = "/home/${username}";
|
||||
|
||||
# Keyboard layouts
|
||||
kbLayouts = builtins.concatStringsSep "," nomarchyConfig.keyboardLayouts;
|
||||
kbVariants = builtins.concatStringsSep "," nomarchyConfig.keyboardVariants;
|
||||
|
||||
# Detect location for gammastep (default to UTC/0,0 if not set)
|
||||
location = nomarchyConfig.location or {lat = 0; lon = 0;};
|
||||
in {
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
systemd.enable = true;
|
||||
|
||||
settings = {
|
||||
"$mod" = "SUPER";
|
||||
"$terminal" = "ghostty";
|
||||
"$fileManager" = "dolphin";
|
||||
"$menu" = "rofi -show drun";
|
||||
"$browser" = "firefox";
|
||||
|
||||
monitor = ",preferred,auto,auto";
|
||||
|
||||
exec-once = [
|
||||
"$terminal"
|
||||
"waybar & hyprpaper & firefox"
|
||||
"nm-applet --indicator"
|
||||
"blueman-applet"
|
||||
"wl-paste --type text --watch cliphist store"
|
||||
"wl-paste --type image --watch cliphist store"
|
||||
"swaync"
|
||||
"gammastep -l ${toString location.lat}:${toString location.lon} -t 6500:3500"
|
||||
];
|
||||
|
||||
env = [
|
||||
"XCURSOR_SIZE,24"
|
||||
"HYPRCURSOR_SIZE,24"
|
||||
];
|
||||
|
||||
general = {
|
||||
gaps_in = 5;
|
||||
gaps_out = 20;
|
||||
border_size = 2;
|
||||
"col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
|
||||
"col.inactive_border" = "rgba(595959aa)";
|
||||
resize_on_border = false;
|
||||
allow_tearing = false;
|
||||
layout = "dwindle";
|
||||
};
|
||||
|
||||
decoration = {
|
||||
rounding = 10;
|
||||
active_opacity = 1.0;
|
||||
inactive_opacity = 1.0;
|
||||
|
||||
shadow = {
|
||||
enabled = true;
|
||||
range = 4;
|
||||
render_power = 3;
|
||||
color = "rgba(1a1a1aee)";
|
||||
};
|
||||
|
||||
blur = {
|
||||
enabled = true;
|
||||
size = 3;
|
||||
passes = 1;
|
||||
vibrancy = 0.1696;
|
||||
};
|
||||
};
|
||||
|
||||
animations = {
|
||||
enabled = true;
|
||||
bezier = [
|
||||
"easeOutQuint,0.23,1,0.32,1"
|
||||
"easeInOutCubic,0.65,0.05,0.36,1"
|
||||
"linear,0,0,1,1"
|
||||
"almostLinear,0.5,0.5,0.75,1.0"
|
||||
"quick,0.15,0,0.1,1"
|
||||
];
|
||||
animation = [
|
||||
"global, 1, 10, default"
|
||||
"border, 1, 5.39, easeOutQuint"
|
||||
"windows, 1, 4.79, easeOutQuint"
|
||||
"windowsIn, 1, 4.1, easeOutQuint, popin 87%"
|
||||
"windowsOut, 1, 1.49, linear, popin 87%"
|
||||
"fadeIn, 1, 1.73, almostLinear"
|
||||
"fadeOut, 1, 1.46, almostLinear"
|
||||
"fade, 1, 3.03, quick"
|
||||
"layers, 1, 3.81, easeOutQuint"
|
||||
"layersIn, 1, 4, easeOutQuint, fade"
|
||||
"layersOut, 1, 1.5, linear, fade"
|
||||
"fadeLayersIn, 1, 1.79, almostLinear"
|
||||
"fadeLayersOut, 1, 1.39, almostLinear"
|
||||
"workspaces, 1, 1.94, almostLinear, fade"
|
||||
"workspacesIn, 1, 1.21, almostLinear, fade"
|
||||
"workspacesOut, 1, 1.94, almostLinear, fade"
|
||||
];
|
||||
};
|
||||
|
||||
dwindle = {
|
||||
pseudotile = true;
|
||||
preserve_split = true;
|
||||
};
|
||||
|
||||
master = {
|
||||
new_status = "master";
|
||||
};
|
||||
|
||||
misc = {
|
||||
force_default_wallpaper = 1;
|
||||
disable_hyprland_logo = true;
|
||||
disable_splash_rendering = true;
|
||||
};
|
||||
|
||||
input = {
|
||||
kb_layout = kbLayouts;
|
||||
kb_variant = kbVariants;
|
||||
kb_options = "grp:ralt_toggle";
|
||||
repeat_delay = 150;
|
||||
repeat_rate = 50;
|
||||
follow_mouse = 1;
|
||||
sensitivity = 0;
|
||||
|
||||
touchpad = {
|
||||
natural_scroll = false;
|
||||
};
|
||||
};
|
||||
|
||||
device = {
|
||||
name = "epic-mouse-v1";
|
||||
sensitivity = "-0.5";
|
||||
};
|
||||
|
||||
bindm = [
|
||||
"$mod, mouse:272, movewindow"
|
||||
"$mod, mouse:273, resizewindow"
|
||||
];
|
||||
|
||||
bindel = [
|
||||
",XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
|
||||
",XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
|
||||
",XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
|
||||
",XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
|
||||
",XF86MonBrightnessUp, exec, brightnessctl s 10%+"
|
||||
",XF86MonBrightnessDown, exec, brightnessctl s 10%-"
|
||||
];
|
||||
|
||||
bindl = [
|
||||
", XF86AudioNext, exec, playerctl next"
|
||||
", XF86AudioPause, exec, playerctl play-pause"
|
||||
", XF86AudioPlay, exec, playerctl play-pause"
|
||||
", XF86AudioPrev, exec, playerctl previous"
|
||||
];
|
||||
|
||||
bind = [
|
||||
"$mod, Q, exec, $terminal"
|
||||
"$mod, W, killactive,"
|
||||
"$mod, M, exit,"
|
||||
"$mod, E, exec, $fileManager"
|
||||
"$mod, V, togglefloating,"
|
||||
"$mod, R, exec, $menu"
|
||||
"$mod, P, pseudo,"
|
||||
"$mod, J, togglesplit,"
|
||||
"$mod, B, exec, $browser"
|
||||
"$mod, F, fullscreen, 0"
|
||||
"$mod SHIFT, F, fullscreen, 1"
|
||||
|
||||
# Focus movement
|
||||
"$mod, left, movefocus, l"
|
||||
"$mod, right, movefocus, r"
|
||||
"$mod, up, movefocus, u"
|
||||
"$mod, down, movefocus, d"
|
||||
|
||||
# Workspaces
|
||||
"$mod, 1, workspace, 1"
|
||||
"$mod, 2, workspace, 2"
|
||||
"$mod, 3, workspace, 3"
|
||||
"$mod, 4, workspace, 4"
|
||||
"$mod, 5, workspace, 5"
|
||||
"$mod, 6, workspace, 6"
|
||||
"$mod, 7, workspace, 7"
|
||||
"$mod, 8, workspace, 8"
|
||||
"$mod, 9, workspace, 9"
|
||||
"$mod, 0, workspace, 10"
|
||||
|
||||
# Move to workspace
|
||||
"$mod SHIFT, 1, movetoworkspace, 1"
|
||||
"$mod SHIFT, 2, movetoworkspace, 2"
|
||||
"$mod SHIFT, 3, movetoworkspace, 3"
|
||||
"$mod SHIFT, 4, movetoworkspace, 4"
|
||||
"$mod SHIFT, 5, movetoworkspace, 5"
|
||||
"$mod SHIFT, 6, movetoworkspace, 6"
|
||||
"$mod SHIFT, 7, movetoworkspace, 7"
|
||||
"$mod SHIFT, 8, movetoworkspace, 8"
|
||||
"$mod SHIFT, 9, movetoworkspace, 9"
|
||||
"$mod SHIFT, 0, movetoworkspace, 10"
|
||||
|
||||
# Special workspace (scratchpad)
|
||||
"$mod, S, togglespecialworkspace, magic"
|
||||
"$mod SHIFT, S, movetoworkspace, special:magic"
|
||||
|
||||
# Scroll through workspaces
|
||||
"$mod, mouse_down, workspace, e+1"
|
||||
"$mod, mouse_up, workspace, e-1"
|
||||
|
||||
# Screenshots
|
||||
", Print, exec, grim - | wl-copy -t image/png"
|
||||
"$mod, Print, exec, ~/.local/bin/screenshot-region"
|
||||
"$mod SHIFT, Print, exec, grim -g \"$(slurp)\" - | wl-copy -t image/png"
|
||||
"$mod ALT, Print, exec, ~/.local/bin/screenshot-window"
|
||||
|
||||
# Screen recording toggle
|
||||
"$mod SHIFT, R, exec, ~/.local/bin/screen-record"
|
||||
|
||||
# Quick Actions menu
|
||||
"$mod, Space, exec, ~/.local/bin/quick-actions"
|
||||
"$mod, slash, exec, ~/.local/bin/quick-actions"
|
||||
|
||||
# Power menu
|
||||
"$mod, Escape, exec, ~/.local/bin/power-menu"
|
||||
|
||||
# Notification center
|
||||
"$mod, A, exec, swaync-client -t -sw"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Hyprpaper for wallpapers
|
||||
services.hyprpaper = {
|
||||
enable = true;
|
||||
settings = {
|
||||
splash = false;
|
||||
# Default wallpaper - users can override
|
||||
preload = [
|
||||
"${homeDir}/.config/nomarchy/wallpapers/default.jpg"
|
||||
];
|
||||
wallpaper = ["eDP-1,${homeDir}/.config/nomarchy/wallpapers/default.jpg"];
|
||||
};
|
||||
};
|
||||
|
||||
# Ghostty terminal
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
settings = {
|
||||
font-size = 14;
|
||||
background-opacity = 0.85;
|
||||
keybind = "shift+enter=text:\n";
|
||||
};
|
||||
};
|
||||
}
|
||||
156
modules/home/neovim.nix
Normal file
156
modules/home/neovim.nix
Normal file
@@ -0,0 +1,156 @@
|
||||
# Neovim configuration (basic setup - can be extended)
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.neovim = {
|
||||
enable = true;
|
||||
defaultEditor = true;
|
||||
viAlias = true;
|
||||
vimAlias = true;
|
||||
|
||||
extraPackages = with pkgs; [
|
||||
# LSP servers
|
||||
nil # Nix
|
||||
lua-language-server
|
||||
nodePackages.typescript-language-server
|
||||
nodePackages.vscode-langservers-extracted # HTML, CSS, JSON
|
||||
rust-analyzer
|
||||
zls # Zig
|
||||
gopls
|
||||
pyright
|
||||
marksman # Markdown
|
||||
taplo # TOML
|
||||
yaml-language-server
|
||||
ltex-ls # Grammar
|
||||
|
||||
# Formatters
|
||||
nixfmt
|
||||
stylua
|
||||
prettierd
|
||||
black
|
||||
rustfmt
|
||||
|
||||
# Tools
|
||||
ripgrep
|
||||
fd
|
||||
tree-sitter
|
||||
wl-clipboard
|
||||
];
|
||||
|
||||
plugins = with pkgs.vimPlugins; [
|
||||
# Core
|
||||
plenary-nvim
|
||||
nvim-web-devicons
|
||||
|
||||
# Fuzzy finder
|
||||
telescope-nvim
|
||||
|
||||
# Treesitter
|
||||
nvim-treesitter.withAllGrammars
|
||||
|
||||
# LSP
|
||||
nvim-lspconfig
|
||||
|
||||
# Completion
|
||||
nvim-cmp
|
||||
cmp-nvim-lsp
|
||||
cmp-buffer
|
||||
cmp-path
|
||||
luasnip
|
||||
cmp_luasnip
|
||||
|
||||
# UI
|
||||
lualine-nvim
|
||||
bufferline-nvim
|
||||
indent-blankline-nvim
|
||||
|
||||
# Git
|
||||
gitsigns-nvim
|
||||
|
||||
# File tree
|
||||
nvim-tree-lua
|
||||
|
||||
# Theme (can be customized to match nomarchy theme)
|
||||
tokyonight-nvim
|
||||
];
|
||||
|
||||
extraLuaConfig = /* backwards compat */ ''
|
||||
-- Basic settings
|
||||
vim.opt.number = true
|
||||
vim.opt.relativenumber = true
|
||||
vim.opt.expandtab = true
|
||||
vim.opt.tabstop = 2
|
||||
vim.opt.shiftwidth = 2
|
||||
vim.opt.smartindent = true
|
||||
vim.opt.termguicolors = true
|
||||
vim.opt.signcolumn = "yes"
|
||||
vim.opt.updatetime = 250
|
||||
vim.opt.clipboard = "unnamedplus"
|
||||
|
||||
-- Leader key
|
||||
vim.g.mapleader = " "
|
||||
|
||||
-- Theme
|
||||
vim.cmd.colorscheme("tokyonight-night")
|
||||
|
||||
-- Telescope keymaps
|
||||
local telescope = require("telescope.builtin")
|
||||
vim.keymap.set("n", "<leader>ff", telescope.find_files, { desc = "Find files" })
|
||||
vim.keymap.set("n", "<leader>fg", telescope.live_grep, { desc = "Live grep" })
|
||||
vim.keymap.set("n", "<leader>fb", telescope.buffers, { desc = "Buffers" })
|
||||
|
||||
-- LSP setup
|
||||
local lspconfig = require("lspconfig")
|
||||
local capabilities = require("cmp_nvim_lsp").default_capabilities()
|
||||
|
||||
local servers = {
|
||||
"nil_ls", "lua_ls", "ts_ls", "html", "cssls", "jsonls",
|
||||
"rust_analyzer", "zls", "gopls", "pyright", "marksman",
|
||||
"taplo", "yamlls"
|
||||
}
|
||||
|
||||
for _, server in ipairs(servers) do
|
||||
lspconfig[server].setup({ capabilities = capabilities })
|
||||
end
|
||||
|
||||
-- Completion
|
||||
local cmp = require("cmp")
|
||||
cmp.setup({
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
require("luasnip").lsp_expand(args.body)
|
||||
end,
|
||||
},
|
||||
mapping = cmp.mapping.preset.insert({
|
||||
["<C-b>"] = cmp.mapping.scroll_docs(-4),
|
||||
["<C-f>"] = cmp.mapping.scroll_docs(4),
|
||||
["<C-Space>"] = cmp.mapping.complete(),
|
||||
["<CR>"] = cmp.mapping.confirm({ select = true }),
|
||||
}),
|
||||
sources = cmp.config.sources({
|
||||
{ name = "nvim_lsp" },
|
||||
{ name = "luasnip" },
|
||||
}, {
|
||||
{ name = "buffer" },
|
||||
{ name = "path" },
|
||||
}),
|
||||
})
|
||||
|
||||
-- File tree
|
||||
require("nvim-tree").setup()
|
||||
vim.keymap.set("n", "<leader>e", ":NvimTreeToggle<CR>", { silent = true })
|
||||
|
||||
-- Git signs
|
||||
require("gitsigns").setup()
|
||||
|
||||
-- Status line
|
||||
require("lualine").setup()
|
||||
|
||||
-- Buffer line
|
||||
require("bufferline").setup()
|
||||
'';
|
||||
};
|
||||
}
|
||||
228
modules/home/notifications.nix
Normal file
228
modules/home/notifications.nix
Normal file
@@ -0,0 +1,228 @@
|
||||
# SwayNotificationCenter configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
services.swaync = {
|
||||
enable = true;
|
||||
settings = {
|
||||
positionX = "right";
|
||||
positionY = "top";
|
||||
layer = "overlay";
|
||||
control-center-layer = "top";
|
||||
layer-shell = true;
|
||||
cssPriority = "application";
|
||||
control-center-margin-top = 10;
|
||||
control-center-margin-bottom = 10;
|
||||
control-center-margin-right = 10;
|
||||
control-center-margin-left = 10;
|
||||
notification-icon-size = 64;
|
||||
notification-body-image-height = 100;
|
||||
notification-body-image-width = 200;
|
||||
timeout = 10;
|
||||
timeout-low = 5;
|
||||
timeout-critical = 0;
|
||||
fit-to-screen = true;
|
||||
control-center-width = 400;
|
||||
control-center-height = 600;
|
||||
notification-window-width = 400;
|
||||
keyboard-shortcuts = true;
|
||||
image-visibility = "when-available";
|
||||
transition-time = 200;
|
||||
hide-on-clear = false;
|
||||
hide-on-action = true;
|
||||
script-fail-notify = true;
|
||||
widgets = [
|
||||
"inhibitors"
|
||||
"title"
|
||||
"dnd"
|
||||
"notifications"
|
||||
"mpris"
|
||||
];
|
||||
widget-config = {
|
||||
inhibitors = {
|
||||
text = "Inhibitors";
|
||||
button-text = "Clear All";
|
||||
clear-all-button = true;
|
||||
};
|
||||
title = {
|
||||
text = "Notifications";
|
||||
clear-all-button = true;
|
||||
button-text = "Clear All";
|
||||
};
|
||||
dnd = {
|
||||
text = "Do Not Disturb";
|
||||
};
|
||||
mpris = {
|
||||
image-size = 96;
|
||||
image-radius = 12;
|
||||
};
|
||||
};
|
||||
};
|
||||
style = ''
|
||||
* {
|
||||
font-family: "JetBrainsMono Nerd Font Mono";
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.notification-row {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.notification-row:focus,
|
||||
.notification-row:hover {
|
||||
background: rgba(139, 90, 43, 0.15);
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-radius: 12px;
|
||||
margin: 6px;
|
||||
box-shadow: 0 0 0 1px rgba(139, 90, 43, 0.4);
|
||||
padding: 0;
|
||||
background: rgba(26, 22, 17, 0.95);
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
background: transparent;
|
||||
padding: 10px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background: rgba(166, 61, 64, 0.6);
|
||||
color: #d4c4a8;
|
||||
text-shadow: none;
|
||||
padding: 0;
|
||||
border-radius: 100%;
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
box-shadow: none;
|
||||
background: rgba(166, 61, 64, 0.9);
|
||||
}
|
||||
|
||||
.notification-default-action,
|
||||
.notification-action {
|
||||
padding: 4px;
|
||||
margin: 0;
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #d4c4a8;
|
||||
}
|
||||
|
||||
.notification-default-action:hover,
|
||||
.notification-action:hover {
|
||||
background: rgba(139, 90, 43, 0.2);
|
||||
}
|
||||
|
||||
.summary {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #d4a857;
|
||||
}
|
||||
|
||||
.body {
|
||||
font-size: 13px;
|
||||
color: #d4c4a8;
|
||||
}
|
||||
|
||||
.control-center {
|
||||
background: rgba(26, 22, 17, 0.95);
|
||||
border: 2px solid rgba(139, 90, 43, 0.6);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.control-center-list {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.control-center-list-placeholder {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.floating-notifications {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.blank-window {
|
||||
background: alpha(black, 0.1);
|
||||
}
|
||||
|
||||
.widget-title {
|
||||
margin: 8px;
|
||||
font-size: 1.2em;
|
||||
color: #d4a857;
|
||||
}
|
||||
|
||||
.widget-title > button {
|
||||
font-size: 0.9em;
|
||||
color: #d4c4a8;
|
||||
background: rgba(139, 90, 43, 0.3);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
.widget-title > button:hover {
|
||||
background: rgba(139, 90, 43, 0.5);
|
||||
}
|
||||
|
||||
.widget-dnd {
|
||||
margin: 8px;
|
||||
padding: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.widget-dnd > switch {
|
||||
background: rgba(92, 83, 70, 0.6);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.widget-dnd > switch:checked {
|
||||
background: rgba(212, 168, 87, 0.6);
|
||||
}
|
||||
|
||||
.widget-dnd > switch slider {
|
||||
background: #d4c4a8;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.widget-mpris {
|
||||
background: rgba(45, 38, 32, 0.85);
|
||||
border-radius: 12px;
|
||||
margin: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.widget-mpris-player {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.widget-mpris-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
color: #d4a857;
|
||||
}
|
||||
|
||||
.widget-mpris-subtitle {
|
||||
font-size: 0.9em;
|
||||
color: #8b7355;
|
||||
}
|
||||
|
||||
.widget-inhibitors {
|
||||
margin: 8px;
|
||||
padding: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
82
modules/home/rofi.nix
Normal file
82
modules/home/rofi.nix
Normal file
@@ -0,0 +1,82 @@
|
||||
# Rofi application launcher configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
home.file.".config/rofi/config.rasi".text = ''
|
||||
configuration {
|
||||
modi: "drun,run";
|
||||
show-icons: true;
|
||||
icon-theme: "Papirus";
|
||||
font: "JetBrainsMono Nerd Font 13";
|
||||
}
|
||||
|
||||
* {
|
||||
bg: rgba(26, 22, 17, 0.9);
|
||||
bg-alt: rgba(45, 38, 32, 0.95);
|
||||
fg: #d4c4a8;
|
||||
fg-alt: #8b7355;
|
||||
accent: #d4a857;
|
||||
urgent: #a63d40;
|
||||
|
||||
background-color: transparent;
|
||||
text-color: @fg;
|
||||
}
|
||||
|
||||
window {
|
||||
width: 500px;
|
||||
background-color: @bg;
|
||||
border: 2px solid;
|
||||
border-color: rgba(212, 168, 87, 0.5);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
inputbar {
|
||||
background-color: @bg-alt;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin: 0 0 15px 0;
|
||||
children: [prompt, entry];
|
||||
}
|
||||
|
||||
prompt {
|
||||
text-color: @accent;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
entry {
|
||||
text-color: @fg;
|
||||
placeholder: "Search...";
|
||||
placeholder-color: @fg-alt;
|
||||
cursor-color: @accent;
|
||||
}
|
||||
|
||||
listview {
|
||||
lines: 12;
|
||||
spacing: 5px;
|
||||
scrollbar: false;
|
||||
}
|
||||
|
||||
element {
|
||||
padding: 10px 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
element selected {
|
||||
background-color: rgba(212, 168, 87, 0.2);
|
||||
text-color: @accent;
|
||||
}
|
||||
|
||||
element-icon {
|
||||
size: 24px;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
element-text {
|
||||
text-color: inherit;
|
||||
}
|
||||
'';
|
||||
}
|
||||
331
modules/home/scripts.nix
Normal file
331
modules/home/scripts.nix
Normal file
@@ -0,0 +1,331 @@
|
||||
# Custom utility scripts
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: let
|
||||
homeDir = "/home/${nomarchyConfig.username}";
|
||||
in {
|
||||
# Screenshot region script
|
||||
home.file.".local/bin/screenshot-region" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
grim -g "$(slurp)" - | satty -f -
|
||||
'';
|
||||
};
|
||||
|
||||
# Screenshot active window script
|
||||
home.file.".local/bin/screenshot-window" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
GEOM=$(hyprctl activewindow -j | jq -r '"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')
|
||||
grim -g "$GEOM" - | satty -f -
|
||||
'';
|
||||
};
|
||||
|
||||
# Screen recording toggle script
|
||||
home.file.".local/bin/screen-record" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
PIDFILE="/tmp/wf-recorder.pid"
|
||||
STATUSFILE="/tmp/recording-status"
|
||||
OUTDIR="$HOME/Videos/Recordings"
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
kill -INT "$(cat $PIDFILE)" 2>/dev/null
|
||||
rm -f "$PIDFILE" "$STATUSFILE"
|
||||
notify-send -u normal "Recording Saved" "$(ls -t $OUTDIR/*.mp4 2>/dev/null | head -1)"
|
||||
else
|
||||
FILENAME="$OUTDIR/recording_$(date +%Y%m%d_%H%M%S).mp4"
|
||||
CHOICE=$(echo -e " Region\n Fullscreen" | rofi -dmenu -p "Record")
|
||||
|
||||
case "$CHOICE" in
|
||||
*"Region"*)
|
||||
GEOM=$(slurp)
|
||||
[ -z "$GEOM" ] && exit 1
|
||||
wf-recorder -g "$GEOM" -f "$FILENAME" &
|
||||
;;
|
||||
*"Fullscreen"*)
|
||||
wf-recorder -f "$FILENAME" &
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo $! > "$PIDFILE"
|
||||
echo "recording" > "$STATUSFILE"
|
||||
notify-send -u critical "Recording" "Click waybar or Super+/ to stop"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Quick Actions menu
|
||||
home.file.".local/bin/quick-actions" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
ACTION=$(cat << 'EOF' | rofi -dmenu -i -p ""
|
||||
Screenshot Region
|
||||
Screenshot Window
|
||||
Record Screen
|
||||
Clipboard History
|
||||
Share WiFi (QR Code)
|
||||
Change Wallpaper
|
||||
Color Picker
|
||||
Notifications
|
||||
System Settings
|
||||
Keybindings
|
||||
Lock
|
||||
Logout
|
||||
Reboot
|
||||
Shutdown
|
||||
EOF
|
||||
)
|
||||
|
||||
case "$ACTION" in
|
||||
*"Screenshot Region"*) ~/.local/bin/screenshot-region ;;
|
||||
*"Screenshot Window"*) ~/.local/bin/screenshot-window ;;
|
||||
*"Record Screen"*) ~/.local/bin/screen-record ;;
|
||||
*"Clipboard History"*) cliphist list | rofi -dmenu -p '' | cliphist decode | wl-copy ;;
|
||||
*"Share WiFi"*) ~/.local/bin/wifi-share ;;
|
||||
*"Change Wallpaper"*) ~/.local/bin/wallpaper-rotate && notify-send "Wallpaper changed" ;;
|
||||
*"Color Picker"*) hyprpicker -a && notify-send "Color copied to clipboard" ;;
|
||||
*"Notifications"*) swaync-client -t -sw ;;
|
||||
*"System Settings"*) ~/.local/bin/system-settings ;;
|
||||
*"Keybindings"*) ~/.local/bin/keybindings-help ;;
|
||||
*"Lock"*) hyprlock ;;
|
||||
*"Logout"*) hyprctl dispatch exit ;;
|
||||
*"Reboot"*) systemctl reboot ;;
|
||||
*"Shutdown"*) systemctl poweroff ;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# Keybindings help
|
||||
home.file.".local/bin/keybindings-help" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
cat << 'EOF' | rofi -dmenu -i -p "Keybindings (Super+)" -theme-str 'window {width: 400px;} listview {lines: 16;}'
|
||||
Q Terminal
|
||||
R App Launcher
|
||||
E File Manager
|
||||
B Browser
|
||||
W Close Window
|
||||
F Fullscreen
|
||||
V Float/Tile
|
||||
Arrows Move Focus
|
||||
1-9 Workspace
|
||||
/ Quick Actions
|
||||
A Notifications
|
||||
Space Switch Layout
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
|
||||
# Power menu
|
||||
home.file.".local/bin/power-menu" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
ACTION=$(echo -e " Lock\n Logout\n Reboot\n Shutdown" | rofi -dmenu -i -p "")
|
||||
|
||||
case "$ACTION" in
|
||||
*"Lock"*) hyprlock ;;
|
||||
*"Logout"*) hyprctl dispatch exit ;;
|
||||
*"Reboot"*) systemctl reboot ;;
|
||||
*"Shutdown"*) systemctl poweroff ;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# WiFi sharing with QR code
|
||||
home.file.".local/bin/wifi-share" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
SSID=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2)
|
||||
if [ -z "$SSID" ]; then
|
||||
notify-send "WiFi Share" "Not connected to WiFi"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PASSWORD=$(nmcli -s -g 802-11-wireless-security.psk connection show "$SSID" 2>/dev/null)
|
||||
if [ -z "$PASSWORD" ]; then
|
||||
notify-send "WiFi Share" "Could not retrieve password"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WIFI_STRING="WIFI:T:WPA;S:$SSID;P:$PASSWORD;;"
|
||||
QR_FILE="/tmp/wifi-qr.png"
|
||||
qrencode -o "$QR_FILE" -s 10 "$WIFI_STRING"
|
||||
|
||||
ACTION=$(echo -e " View QR Code\n Copy Password\n Copy SSID" | rofi -dmenu -i -p " $SSID")
|
||||
|
||||
case "$ACTION" in
|
||||
*"View QR"*)
|
||||
if command -v imv &> /dev/null; then
|
||||
imv "$QR_FILE" &
|
||||
else
|
||||
xdg-open "$QR_FILE" &
|
||||
fi
|
||||
notify-send "WiFi QR Code" "Scan to connect to $SSID"
|
||||
;;
|
||||
*"Copy Password"*)
|
||||
echo -n "$PASSWORD" | wl-copy
|
||||
notify-send "Password Copied" "$SSID password copied to clipboard"
|
||||
;;
|
||||
*"Copy SSID"*)
|
||||
echo -n "$SSID" | wl-copy
|
||||
notify-send "SSID Copied" "$SSID copied to clipboard"
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# System settings menu
|
||||
home.file.".local/bin/system-settings" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
ACTION=$(cat << 'EOF' | rofi -dmenu -i -p ""
|
||||
WiFi Settings
|
||||
Bluetooth
|
||||
Sound Settings
|
||||
Display Settings
|
||||
NixOS Generations
|
||||
Update System
|
||||
Garbage Collect
|
||||
EOF
|
||||
)
|
||||
|
||||
case "$ACTION" in
|
||||
*"WiFi"*) nm-connection-editor ;;
|
||||
*"Bluetooth"*) blueman-manager 2>/dev/null || notify-send "Bluetooth" "blueman not installed" ;;
|
||||
*"Sound"*) pavucontrol 2>/dev/null || notify-send "Sound" "pavucontrol not installed" ;;
|
||||
*"Display"*) wdisplays 2>/dev/null || notify-send "Display" "wdisplays not installed" ;;
|
||||
*"Generations"*) ghostty -e bash -c "sudo nix-env --profile /nix/var/nix/profiles/system --list-generations | tail -20; echo; read -p 'Press Enter to close...'" ;;
|
||||
*"Update"*) ghostty -e bash -c "cd ~/.config/nomarchy && nix flake update && sudo nixos-rebuild switch --flake .#; echo; read -p 'Press Enter to close...'" ;;
|
||||
*"Garbage"*) ghostty -e bash -c "sudo nix-collect-garbage -d; echo; read -p 'Press Enter to close...'" ;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# WiFi menu
|
||||
home.file.".local/bin/wifi-menu" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
CURRENT=$(nmcli -t -f active,ssid dev wifi | grep '^yes' | cut -d: -f2)
|
||||
|
||||
MENU=" Scan for networks\n"
|
||||
if [ -n "$CURRENT" ]; then
|
||||
MENU+=" Share WiFi (QR Code)\n"
|
||||
MENU+=" Disconnect ($CURRENT)\n"
|
||||
fi
|
||||
MENU+=" Toggle WiFi\n"
|
||||
MENU+="───────────────\n"
|
||||
|
||||
NETWORKS=$(nmcli -t -f ssid,signal,security dev wifi list | grep -v '^$' | head -10)
|
||||
while IFS=: read -r ssid signal security; do
|
||||
if [ -n "$ssid" ]; then
|
||||
if [ "$ssid" = "$CURRENT" ]; then
|
||||
MENU+=" $ssid ($signal%) ✓\n"
|
||||
elif [ -n "$security" ]; then
|
||||
MENU+=" $ssid ($signal%)\n"
|
||||
else
|
||||
MENU+=" $ssid ($signal%)\n"
|
||||
fi
|
||||
fi
|
||||
done <<< "$NETWORKS"
|
||||
|
||||
CHOICE=$(echo -e "$MENU" | rofi -dmenu -i -p "" | sed 's/^[^ ]* *//' | sed 's/ ([0-9]*%).*$//' | sed 's/ ✓$//')
|
||||
|
||||
case "$CHOICE" in
|
||||
"Scan for networks")
|
||||
notify-send "WiFi" "Scanning..."
|
||||
nmcli dev wifi rescan
|
||||
sleep 2
|
||||
~/.local/bin/wifi-menu
|
||||
;;
|
||||
"Share WiFi"*)
|
||||
~/.local/bin/wifi-share
|
||||
;;
|
||||
"Disconnect"*)
|
||||
nmcli dev disconnect wlan0
|
||||
notify-send "WiFi" "Disconnected"
|
||||
;;
|
||||
"Toggle WiFi")
|
||||
if nmcli radio wifi | grep -q "enabled"; then
|
||||
nmcli radio wifi off
|
||||
notify-send "WiFi" "Disabled"
|
||||
else
|
||||
nmcli radio wifi on
|
||||
notify-send "WiFi" "Enabled"
|
||||
fi
|
||||
;;
|
||||
"─"*) ;;
|
||||
"") ;;
|
||||
*)
|
||||
if nmcli -t -f name connection show | grep -q "^$CHOICE$"; then
|
||||
nmcli connection up "$CHOICE" && notify-send "WiFi" "Connected to $CHOICE"
|
||||
else
|
||||
PASS=$(rofi -dmenu -p "Password for $CHOICE" -password)
|
||||
if [ -n "$PASS" ]; then
|
||||
nmcli dev wifi connect "$CHOICE" password "$PASS" && notify-send "WiFi" "Connected to $CHOICE"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# Bluetooth toggle
|
||||
home.file.".local/bin/bluetooth-toggle" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
if bluetoothctl show | grep -q "Powered: yes"; then
|
||||
bluetoothctl power off
|
||||
notify-send "Bluetooth" "Disabled"
|
||||
else
|
||||
bluetoothctl power on
|
||||
notify-send "Bluetooth" "Enabled"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Wallpaper rotation script
|
||||
home.file.".local/bin/wallpaper-rotate" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/usr/bin/env bash
|
||||
WALLPAPER_DIR="${homeDir}/.config/nomarchy/wallpapers"
|
||||
MONITOR="eDP-1"
|
||||
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
XDG_RUNTIME_DIR="''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
HYPRLAND_INSTANCE_SIGNATURE="$(ls "$XDG_RUNTIME_DIR/hypr/" 2>/dev/null | head -1)"
|
||||
fi
|
||||
export HYPRLAND_INSTANCE_SIGNATURE
|
||||
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
echo "No Hyprland instance found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WALLPAPER=$(find "$WALLPAPER_DIR" -type f \( -name "*.jpg" -o -name "*.png" \) | shuf -n 1)
|
||||
|
||||
if [ -n "$WALLPAPER" ]; then
|
||||
hyprctl hyprpaper wallpaper "$MONITOR,$WALLPAPER"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
48
modules/home/shell.nix
Normal file
48
modules/home/shell.nix
Normal file
@@ -0,0 +1,48 @@
|
||||
# Shell configuration (Zsh + Starship)
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
shellAliases = {
|
||||
ls = "eza --icons";
|
||||
ll = "eza -l --icons";
|
||||
la = "eza -la --icons";
|
||||
update = "sudo nixos-rebuild switch --flake ~/.config/nomarchy#";
|
||||
gc = "sudo nix-collect-garbage -d";
|
||||
du = "dust";
|
||||
dua = "dust -d 1";
|
||||
duh = "dust ~";
|
||||
dus = "dust /nix/store -d 2";
|
||||
};
|
||||
};
|
||||
|
||||
# Zoxide for smart directory jumping
|
||||
programs.zoxide = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
};
|
||||
|
||||
# Starship prompt
|
||||
programs.starship = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
settings = {
|
||||
character = {
|
||||
success_symbol = "[>](bold green)";
|
||||
error_symbol = "[x](bold red)";
|
||||
};
|
||||
git_branch = {
|
||||
symbol = " ";
|
||||
style = "purple";
|
||||
};
|
||||
directory = {
|
||||
style = "blue";
|
||||
truncate_to_repo = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
267
modules/home/waybar.nix
Normal file
267
modules/home/waybar.nix
Normal file
@@ -0,0 +1,267 @@
|
||||
# Waybar status bar configuration
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.waybar = {
|
||||
enable = true;
|
||||
style = ''
|
||||
* {
|
||||
font-family: "JetBrainsMono Nerd Font Mono", "JetBrainsMono NF", monospace;
|
||||
font-size: 14px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
window#waybar {
|
||||
background-color: rgba(26, 22, 17, 0.92);
|
||||
color: #d4c4a8;
|
||||
border-bottom: 2px solid rgba(139, 90, 43, 0.6);
|
||||
}
|
||||
|
||||
#workspaces button {
|
||||
padding: 0 8px;
|
||||
color: #8b7355;
|
||||
border-radius: 4px;
|
||||
margin: 4px 2px;
|
||||
}
|
||||
|
||||
#workspaces button.active {
|
||||
color: #d4a857;
|
||||
background-color: rgba(180, 134, 11, 0.2);
|
||||
}
|
||||
|
||||
#workspaces button:hover {
|
||||
background-color: rgba(139, 90, 43, 0.15);
|
||||
}
|
||||
|
||||
#custom-help {
|
||||
padding: 0 10px;
|
||||
margin: 4px 2px;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(212, 168, 87, 0.3);
|
||||
color: #d4a857;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#custom-help:hover {
|
||||
background-color: rgba(212, 168, 87, 0.5);
|
||||
}
|
||||
|
||||
#clock, #battery, #network, #pulseaudio, #cpu, #memory, #tray {
|
||||
padding: 0 12px;
|
||||
margin: 4px 2px;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(45, 38, 32, 0.85);
|
||||
}
|
||||
|
||||
#clock {
|
||||
color: #d4a857;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#battery {
|
||||
color: #8a9a5b;
|
||||
}
|
||||
|
||||
#battery.charging {
|
||||
color: #d4a857;
|
||||
}
|
||||
|
||||
#battery.warning:not(.charging) {
|
||||
color: #c9a227;
|
||||
}
|
||||
|
||||
#battery.critical:not(.charging) {
|
||||
color: #a63d40;
|
||||
animation: blink 0.5s linear infinite alternate;
|
||||
}
|
||||
|
||||
#network {
|
||||
color: #7a9cb8;
|
||||
}
|
||||
|
||||
#network.disconnected {
|
||||
color: #a63d40;
|
||||
}
|
||||
|
||||
#bluetooth {
|
||||
color: #7a9cb8;
|
||||
}
|
||||
|
||||
#bluetooth.connected {
|
||||
color: #8a9a5b;
|
||||
}
|
||||
|
||||
#bluetooth.disabled {
|
||||
color: #5c5346;
|
||||
}
|
||||
|
||||
#language {
|
||||
color: #c67b5c;
|
||||
font-weight: bold;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
#pulseaudio {
|
||||
color: #c9a227;
|
||||
}
|
||||
|
||||
#pulseaudio.muted {
|
||||
color: #5c5346;
|
||||
}
|
||||
|
||||
#cpu {
|
||||
color: #b85c38;
|
||||
}
|
||||
|
||||
#memory {
|
||||
color: #c67b5c;
|
||||
}
|
||||
|
||||
#tray {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
to {
|
||||
background-color: #722f37;
|
||||
color: #d4c4a8;
|
||||
}
|
||||
}
|
||||
|
||||
#custom-recording {
|
||||
color: #ff4444;
|
||||
font-weight: bold;
|
||||
animation: blink 1s linear infinite;
|
||||
padding: 0 10px;
|
||||
}
|
||||
'';
|
||||
|
||||
settings = {
|
||||
mainBar = {
|
||||
layer = "top";
|
||||
position = "top";
|
||||
height = 34;
|
||||
spacing = 4;
|
||||
modules-left = ["custom/help" "hyprland/workspaces" "hyprland/window"];
|
||||
modules-center = ["custom/recording" "clock"];
|
||||
modules-right = ["hyprland/language" "tray" "cpu" "memory" "pulseaudio" "bluetooth" "network" "battery"];
|
||||
|
||||
"custom/recording" = {
|
||||
exec = "[ -f /tmp/recording-status ] && echo ' REC' || echo ''";
|
||||
interval = 1;
|
||||
format = "{}";
|
||||
on-click = "~/.local/bin/screen-record";
|
||||
tooltip = "Click to stop recording";
|
||||
};
|
||||
|
||||
"custom/help" = {
|
||||
format = "?";
|
||||
tooltip = "Quick Actions (Super+/)";
|
||||
on-click = "~/.local/bin/quick-actions";
|
||||
};
|
||||
|
||||
"hyprland/workspaces" = {
|
||||
format = "{name}";
|
||||
on-click = "activate";
|
||||
};
|
||||
|
||||
"hyprland/window" = {
|
||||
max-length = 50;
|
||||
separate-outputs = true;
|
||||
};
|
||||
|
||||
clock = {
|
||||
format = "{:%H:%M %a %b %d}";
|
||||
format-alt = "{:%I:%M %p %a %b %d}";
|
||||
tooltip-format = "<tt><small>{calendar}</small></tt>";
|
||||
calendar = {
|
||||
mode = "month";
|
||||
weeks-pos = "right";
|
||||
format = {
|
||||
months = "<span color='#d4a857'><b>{}</b></span>";
|
||||
days = "<span color='#d4c4a8'>{}</span>";
|
||||
weeks = "<span color='#8b7355'>W{}</span>";
|
||||
weekdays = "<span color='#c9a227'>{}</span>";
|
||||
today = "<span color='#a63d40'><b><u>{}</u></b></span>";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cpu = {
|
||||
format = "CPU {usage}%";
|
||||
tooltip = true;
|
||||
interval = 2;
|
||||
};
|
||||
|
||||
memory = {
|
||||
format = "RAM {percentage}%";
|
||||
tooltip-format = "{used:0.1f}GB / {total:0.1f}GB";
|
||||
interval = 2;
|
||||
};
|
||||
|
||||
battery = {
|
||||
states = {
|
||||
warning = 30;
|
||||
critical = 15;
|
||||
};
|
||||
format = "BAT {capacity}%";
|
||||
format-charging = "CHR {capacity}%";
|
||||
format-plugged = "PLG {capacity}%";
|
||||
format-icons = ["" "" "" "" ""];
|
||||
tooltip-format = "{timeTo}";
|
||||
};
|
||||
|
||||
network = {
|
||||
format-wifi = " {essid}";
|
||||
format-ethernet = " {ipaddr}";
|
||||
format-disconnected = " ";
|
||||
tooltip-format-wifi = "{essid} • {signalStrength}% • {ipaddr}";
|
||||
tooltip-format-ethernet = "IP: {ipaddr}";
|
||||
on-click = "~/.local/bin/wifi-menu";
|
||||
on-click-right = "nm-connection-editor";
|
||||
};
|
||||
|
||||
bluetooth = {
|
||||
format = "";
|
||||
format-connected = " {device_alias}";
|
||||
format-disabled = "";
|
||||
tooltip-format = "{controller_alias}\n{status}";
|
||||
tooltip-format-connected = "{controller_alias}\n{device_enumerate}";
|
||||
tooltip-format-enumerate-connected = "{device_alias}";
|
||||
on-click = "blueman-manager";
|
||||
on-click-right = "~/.local/bin/bluetooth-toggle";
|
||||
};
|
||||
|
||||
"hyprland/language" = {
|
||||
format = "{}";
|
||||
format-en = "EN";
|
||||
format-gr = "ΕΛ";
|
||||
tooltip-format = "{long} ({variant})";
|
||||
on-click = "hyprctl switchxkblayout all next";
|
||||
};
|
||||
|
||||
pulseaudio = {
|
||||
format = "{icon} {volume}%";
|
||||
format-muted = " ";
|
||||
format-icons = {
|
||||
default = ["" "" ""];
|
||||
headphone = "";
|
||||
};
|
||||
tooltip-format = "{desc}";
|
||||
on-click = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
|
||||
on-click-right = "pavucontrol";
|
||||
on-scroll-up = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+";
|
||||
on-scroll-down = "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-";
|
||||
};
|
||||
|
||||
tray = {
|
||||
icon-size = 18;
|
||||
spacing = 8;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
70
modules/performance/default.nix
Normal file
70
modules/performance/default.nix
Normal file
@@ -0,0 +1,70 @@
|
||||
# Performance optimizations
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# Zram swap for better memory management
|
||||
zramSwap = {
|
||||
enable = true;
|
||||
algorithm = "zstd";
|
||||
memoryPercent = 50;
|
||||
};
|
||||
|
||||
# Tmpfs for /tmp (faster, auto-cleans)
|
||||
boot.tmp = {
|
||||
useTmpfs = true;
|
||||
tmpfsSize = "50%";
|
||||
};
|
||||
|
||||
# Kernel parameters for performance
|
||||
boot.kernelParams =
|
||||
[
|
||||
"quiet"
|
||||
"splash"
|
||||
]
|
||||
# SECURITY WARNING: mitigations=off disables CPU vulnerability protections
|
||||
# Only enable if you understand the security implications
|
||||
++ lib.optionals (nomarchyConfig.enableMitigationsOff or false) [
|
||||
"mitigations=off"
|
||||
];
|
||||
|
||||
# Better I/O scheduler for SSDs
|
||||
services.udev.extraRules = ''
|
||||
ACTION=="add|change", KERNEL=="sd[a-z]*|nvme[0-9]*", ATTR{queue/scheduler}="mq-deadline"
|
||||
'';
|
||||
|
||||
# Kernel sysctl tuning
|
||||
boot.kernel.sysctl = {
|
||||
# Increase inotify watches for large projects (IDEs, file watchers)
|
||||
"fs.inotify.max_user_watches" = 524288;
|
||||
"fs.inotify.max_user_instances" = 1024;
|
||||
|
||||
# Memory management
|
||||
"vm.swappiness" = 10; # Prefer RAM over swap
|
||||
"vm.vfs_cache_pressure" = 50; # Balance inode/dentry cache
|
||||
};
|
||||
|
||||
# Nix garbage collection
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 7d";
|
||||
};
|
||||
|
||||
# Nix store optimization
|
||||
nix.settings = {
|
||||
auto-optimise-store = true;
|
||||
max-jobs = "auto";
|
||||
cores = 0; # Use all cores
|
||||
};
|
||||
|
||||
# Earlyoom to prevent OOM freezes
|
||||
services.earlyoom = {
|
||||
enable = true;
|
||||
freeMemThreshold = 5;
|
||||
freeSwapThreshold = 10;
|
||||
};
|
||||
}
|
||||
136
modules/programs/default.nix
Normal file
136
modules/programs/default.nix
Normal file
@@ -0,0 +1,136 @@
|
||||
# System programs
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
pkgs-stable,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# Shell
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
autosuggestions.enable = true;
|
||||
syntaxHighlighting.enable = true;
|
||||
};
|
||||
|
||||
# nix-ld for dynamically linked libraries
|
||||
programs.nix-ld = {
|
||||
enable = true;
|
||||
libraries = with pkgs; [
|
||||
zlib
|
||||
stdenv.cc.cc
|
||||
openssl
|
||||
];
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
# Core utilities
|
||||
wget
|
||||
git
|
||||
unzip
|
||||
jq
|
||||
lsof
|
||||
file
|
||||
ripgrep
|
||||
fd
|
||||
|
||||
# Development
|
||||
zig
|
||||
bun
|
||||
nodejs_22
|
||||
lazygit
|
||||
|
||||
# Networking
|
||||
wireguard-tools
|
||||
nmap
|
||||
arp-scan
|
||||
rclone
|
||||
rsync
|
||||
|
||||
# Privacy
|
||||
tor-browser
|
||||
gnupg
|
||||
pinentry-curses
|
||||
|
||||
# Media
|
||||
mpv
|
||||
yt-dlp
|
||||
imagemagick
|
||||
viu
|
||||
chafa
|
||||
|
||||
# Documents
|
||||
libreoffice-qt
|
||||
nb
|
||||
mdbook
|
||||
exiftool
|
||||
|
||||
# File management
|
||||
ranger
|
||||
dolphin
|
||||
|
||||
# Shell enhancements
|
||||
eza
|
||||
bat
|
||||
fzf
|
||||
starship
|
||||
btop
|
||||
zsh
|
||||
zoxide
|
||||
|
||||
# Browsers
|
||||
firefox
|
||||
chromium
|
||||
|
||||
# Applications
|
||||
anki
|
||||
|
||||
# NixOS tools
|
||||
nh
|
||||
nvd
|
||||
nix-tree
|
||||
|
||||
# Disk usage
|
||||
dust
|
||||
ncdu
|
||||
gdu
|
||||
duf
|
||||
|
||||
# Android
|
||||
android-tools
|
||||
|
||||
# Filesystem
|
||||
exfatprogs
|
||||
|
||||
# Graphviz
|
||||
graphviz
|
||||
|
||||
# Qt multimedia
|
||||
qt6.qtmultimedia
|
||||
|
||||
# Signal Desktop (from stable for reliability)
|
||||
pkgs-stable.signal-desktop
|
||||
|
||||
# Kate editor (KDE)
|
||||
kdePackages.kate
|
||||
|
||||
# FHS environment for non-NixOS binaries
|
||||
(let
|
||||
base = pkgs.appimageTools.defaultFhsEnvArgs;
|
||||
in
|
||||
pkgs.buildFHSEnv (base
|
||||
// {
|
||||
name = "fhs";
|
||||
targetPkgs = pkgs:
|
||||
(base.targetPkgs pkgs)
|
||||
++ (with pkgs; [
|
||||
pkg-config
|
||||
]);
|
||||
profile = "export FHS=1";
|
||||
runScript = "bash";
|
||||
extraOutputsToInstall = ["dev"];
|
||||
}))
|
||||
];
|
||||
}
|
||||
57
modules/services/default.nix
Normal file
57
modules/services/default.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
# System services
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nomarchyConfig,
|
||||
...
|
||||
}: {
|
||||
# Printing service
|
||||
services.printing = lib.mkIf (nomarchyConfig.enablePrinting or true) {
|
||||
enable = true;
|
||||
browsed.enable = true;
|
||||
drivers = with pkgs; [brlaser gutenprint];
|
||||
};
|
||||
|
||||
# Avahi for mDNS discovery (network printers)
|
||||
services.avahi = lib.mkIf (nomarchyConfig.enablePrinting or true) {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# Mullvad VPN
|
||||
services.mullvad-vpn.enable = nomarchyConfig.enableMullvad or false;
|
||||
|
||||
# Syncthing - parameterized user
|
||||
services.syncthing = lib.mkIf (nomarchyConfig.enableSyncthing or true) {
|
||||
enable = true;
|
||||
user = nomarchyConfig.username;
|
||||
dataDir = "/home/${nomarchyConfig.username}/.config/syncthing";
|
||||
configDir = "/home/${nomarchyConfig.username}/.config/syncthing";
|
||||
openDefaultPorts = true;
|
||||
guiAddress = "127.0.0.1:8384";
|
||||
};
|
||||
|
||||
# Auto-cpufreq for automatic CPU power management
|
||||
services.auto-cpufreq = {
|
||||
enable = true;
|
||||
settings = {
|
||||
battery = {
|
||||
governor = "powersave";
|
||||
turbo = "never";
|
||||
scaling_min_freq = 800000;
|
||||
scaling_max_freq = 2000000;
|
||||
};
|
||||
charger = {
|
||||
governor = "performance";
|
||||
turbo = "auto";
|
||||
scaling_min_freq = 800000;
|
||||
scaling_max_freq = 4500000;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Disable power-profiles-daemon (conflicts with auto-cpufreq)
|
||||
services.power-profiles-daemon.enable = false;
|
||||
}
|
||||
Reference in New Issue
Block a user