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:
2026-02-15 02:44:33 -05:00
commit 58e4232f2f
50 changed files with 3853 additions and 0 deletions

62
modules/home/default.nix Normal file
View 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
View 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
View 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()
'';
};
}

View 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
View 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
View 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
View 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
View 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;
};
};
};
};
}