commit 58e4232f2f191661d1690afe7d1b3a4b9f8ca69d Author: Brandon Lucas Date: Sun Feb 15 02:44:33 2026 -0500 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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21681cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Nix build artifacts +result +result-* + +# Secrets (never commit unencrypted secrets) +secrets/*.age +!secrets/secrets.nix + +# Editor files +*.swp +*.swo +*~ +.idea/ +.vscode/ + +# OS files +.DS_Store +Thumbs.db + +# Local user config (generated by installer) +config.local.nix diff --git a/README.md b/README.md new file mode 100644 index 0000000..def032b --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# Nomarchy + +An opinionated NixOS configuration featuring Hyprland, designed for developers who want a beautiful, functional, and reproducible desktop environment. + +## Quick Start + +### For Existing NixOS Systems + +```bash +nix run github:blu/nomarchy +``` + +This launches an interactive installer that: +1. Prompts for your username, timezone, keyboard layout, etc. +2. Generates a configuration in `~/.config/nomarchy/` +3. Applies the configuration to your system + +### From ISO (Coming Soon) + +Download the ISO from the releases page and boot from it for a fresh installation with LUKS encryption. + +## Features + +- **Hyprland** - Modern Wayland compositor with smooth animations +- **Waybar** - Customizable status bar +- **Rofi** - Application launcher and quick actions +- **SwayNC** - Notification center +- **Neovim** - Fully configured with LSP support +- **Classical Theme** - Earthy, vintage aesthetic inspired by historical paintings + +## Keybindings + +| Key | Action | +|-----|--------| +| `Super + Q` | Terminal | +| `Super + R` | App Launcher | +| `Super + E` | File Manager | +| `Super + B` | Browser | +| `Super + W` | Close Window | +| `Super + F` | Fullscreen | +| `Super + V` | Toggle Float | +| `Super + /` | Quick Actions | +| `Super + A` | Notifications | +| `Super + Escape` | Power Menu | +| `Super + 1-9` | Workspaces | +| `Print` | Screenshot | +| `Super + Shift + R` | Record Screen | + +## Customization + +### Changing Theme + +Edit `~/.config/nomarchy/config.nix`: + +```nix +{ + theme = "classical"; # Currently the only theme, more coming soon +} +``` + +### Adding Packages + +Create a custom module: + +```nix +# ~/.config/nomarchy/my-packages.nix +{ pkgs, ... }: { + environment.systemPackages = with pkgs; [ + my-package + ]; +} +``` + +Add it to your flake: + +```nix +extraModules = [ + ./my-packages.nix +]; +``` + +### Wallpapers + +Copy your wallpapers to `~/.config/nomarchy/wallpapers/` and they'll be used for the random rotation. + +## Structure + +``` +nomarchy/ +├── flake.nix # Main flake +├── lib/ # Helper functions +├── modules/ +│ ├── core/ # Boot, networking, hardware +│ ├── desktop/ # Hyprland, display manager +│ ├── services/ # Syncthing, printing, VPN +│ ├── programs/ # System packages +│ ├── performance/ # Optimizations +│ └── home/ # Home-manager configs +├── themes/ +│ └── classical/ # Default theme +├── installer/ # Installation scripts +└── iso/ # ISO builder +``` + +## Security Note + +The `enableMitigationsOff` option disables CPU vulnerability mitigations (Spectre, Meltdown, etc.) for improved performance. This is **disabled by default** and should only be enabled if you understand the security implications. + +## Credits + +Inspired by [Omarchy](https://github.com/basecamp/omarchy) and the NixOS community. + +## License + +MIT diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md new file mode 100644 index 0000000..c083069 --- /dev/null +++ b/docs/CUSTOMIZATION.md @@ -0,0 +1,154 @@ +# Customization Guide + +## Configuration File + +Your configuration lives in `~/.config/nomarchy/config.nix`: + +```nix +{ + # User settings + username = "yourname"; + hostname = "yourhostname"; + timezone = "America/New_York"; + locale = "en_US.UTF-8"; + + # Keyboard (supports multiple layouts) + keyboardLayouts = ["us" "gr"]; + keyboardVariants = ["" "polytonic"]; + + # Location for night light + location = { + lat = 40.7; + lon = -74.0; + }; + + # Features + enableSyncthing = true; + enableMullvad = false; + enablePrinting = true; + enableBluetooth = true; + + # Performance (security tradeoff!) + enableMitigationsOff = false; + + # Theme + theme = "classical"; +} +``` + +## Adding Custom Modules + +Create a module in `~/.config/nomarchy/`: + +```nix +# ~/.config/nomarchy/custom.nix +{ config, pkgs, ... }: { + # System packages + environment.systemPackages = with pkgs; [ + discord + spotify + ]; + + # Services + services.docker.enable = true; + + # User groups + users.users.${config.nomarchy.username}.extraGroups = ["docker"]; +} +``` + +Add it to your flake: + +```nix +extraModules = [ + ./custom.nix +]; +``` + +## Wallpapers + +1. Copy images to `~/.config/nomarchy/wallpapers/` +2. Supported formats: `.jpg`, `.png` +3. Wallpapers rotate every 5 minutes automatically +4. Use Quick Actions (`Super + /`) → "Change Wallpaper" for immediate change + +## Theme Colors + +The classical theme colors are defined in the theme module. To override colors in your waybar or rofi, you can create custom CSS files. + +### Color Palette + +| Name | Hex | Usage | +|------|-----|-------| +| bg.primary | `#1a1611` | Main background | +| bg.secondary | `#2d2620` | Panels, inputs | +| fg.primary | `#d4c4a8` | Main text | +| accent.gold | `#d4a857` | Primary accent | +| accent.terracotta | `#c67b5c` | Secondary accent | +| status.success | `#8a9a5b` | Success states | +| status.error | `#a63d40` | Error states | + +## Shell Aliases + +Default aliases (in `~/.zshrc` via home-manager): + +```bash +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 +``` + +## Neovim + +The default Neovim configuration includes: +- LSP support for Nix, Lua, TypeScript, Rust, Go, Python, Markdown +- Telescope for fuzzy finding +- Treesitter for syntax highlighting +- Git integration with gitsigns + +To customize, create `~/.config/nvim/lua/custom/init.lua` (loaded after main config). + +## Terminal (Ghostty) + +Customize in `~/.config/ghostty/config`: + +``` +font-size = 16 +background-opacity = 0.9 +``` + +## Hyprland + +For advanced Hyprland customization, you can add settings via home-manager: + +```nix +# In your custom module +{ config, ... }: { + home-manager.users.${config.nomarchy.username} = { + wayland.windowManager.hyprland.settings = { + # Add your custom settings here + windowrulev2 = [ + "float,class:^(pavucontrol)$" + ]; + }; + }; +} +``` + +## Rebuilding + +After making changes: + +```bash +cd ~/.config/nomarchy +sudo nixos-rebuild switch --flake .#yourhostname +``` + +Or use the alias: + +```bash +update +``` diff --git a/docs/KEYBINDINGS.md b/docs/KEYBINDINGS.md new file mode 100644 index 0000000..e7307c9 --- /dev/null +++ b/docs/KEYBINDINGS.md @@ -0,0 +1,92 @@ +# Nomarchy Keybindings + +## Window Management + +| Key | Action | +|-----|--------| +| `Super + Q` | Open terminal (Ghostty) | +| `Super + W` | Close active window | +| `Super + M` | Exit Hyprland | +| `Super + F` | Toggle fullscreen (windowed) | +| `Super + Shift + F` | Toggle fullscreen (standalone) | +| `Super + V` | Toggle floating | +| `Super + P` | Pseudo tile | +| `Super + J` | Toggle split direction | + +## Focus & Movement + +| Key | Action | +|-----|--------| +| `Super + Left/Right/Up/Down` | Move focus | +| `Super + 1-9, 0` | Switch to workspace 1-10 | +| `Super + Shift + 1-9, 0` | Move window to workspace 1-10 | +| `Super + S` | Toggle scratchpad | +| `Super + Shift + S` | Move window to scratchpad | +| `Super + Mouse Wheel` | Scroll through workspaces | + +## Mouse Bindings + +| Key | Action | +|-----|--------| +| `Super + Left Click + Drag` | Move window | +| `Super + Right Click + Drag` | Resize window | + +## Applications + +| Key | Action | +|-----|--------| +| `Super + R` | Open app launcher (Rofi) | +| `Super + E` | Open file manager (Dolphin) | +| `Super + B` | Open browser (Firefox) | + +## Quick Actions + +| Key | Action | +|-----|--------| +| `Super + /` or `Super + Space` | Quick Actions menu | +| `Super + Escape` | Power menu | +| `Super + A` | Notification center | + +## Screenshots & Recording + +| Key | Action | +|-----|--------| +| `Print` | Screenshot to clipboard | +| `Super + Print` | Screenshot region (with Satty editor) | +| `Super + Shift + Print` | Screenshot region to clipboard | +| `Super + Alt + Print` | Screenshot active window | +| `Super + Shift + R` | Toggle screen recording | + +## Media & Brightness + +| Key | Action | +|-----|--------| +| `XF86AudioRaiseVolume` | Volume +5% | +| `XF86AudioLowerVolume` | Volume -5% | +| `XF86AudioMute` | Toggle mute | +| `XF86AudioMicMute` | Toggle mic mute | +| `XF86MonBrightnessUp` | Brightness +10% | +| `XF86MonBrightnessDown` | Brightness -10% | +| `XF86AudioNext/Prev/Play` | Media controls | + +## Keyboard Layout + +| Key | Action | +|-----|--------| +| `Right Alt` | Switch keyboard layout | + +## Quick Actions Menu Options + +The Quick Actions menu (`Super + /`) provides access to: + +- Screenshot Region +- Screenshot Window +- Record Screen +- Clipboard History +- Share WiFi (QR Code) +- Change Wallpaper +- Color Picker +- Notifications +- System Settings +- Keybindings Help +- Lock/Logout/Reboot/Shutdown diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..4ceaa0a --- /dev/null +++ b/flake.lock @@ -0,0 +1,649 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1770165109, + "narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=", + "owner": "ryantm", + "repo": "agenix", + "rev": "b027ee29d959fda4b60b57566d64c98a202e0feb", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "aquamarine": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1770895474, + "narHash": "sha256-JBcrq1Y0uw87VZdYsByVbv+GBuT6ECaCNb9txLX9UuU=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "a494d50d32b5567956b558437ceaa58a380712f7", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "hyprland", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1771132481, + "narHash": "sha256-Tc+YqZ/Q1K35vJK4ji4RbLB/qKGcEq6yh7p4CKoZF60=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "1e53254671f36cb7d0e2dcca08730f066d5e69b4", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "hyprcursor": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1753964049, + "narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=", + "owner": "hyprwm", + "repo": "hyprcursor", + "rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprcursor", + "type": "github" + } + }, + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1770511807, + "narHash": "sha256-suKmSbSk34uPOJDTg/GbPrKEJutzK08vj0VoTvAFBCA=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "7c75487edd43a71b61adb01cae8326d277aab683", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, + "hyprland": { + "inputs": { + "aquamarine": "aquamarine", + "hyprcursor": "hyprcursor", + "hyprgraphics": "hyprgraphics", + "hyprland-guiutils": "hyprland-guiutils", + "hyprland-protocols": "hyprland-protocols", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", + "hyprwire": "hyprwire", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks", + "systems": "systems_2", + "xdph": "xdph" + }, + "locked": { + "lastModified": 1771109637, + "narHash": "sha256-Tm3gxMhwoJGORXMnH4eZyJKQPQr6fWG5njd9I+k/sVI=", + "owner": "hyprwm", + "repo": "Hyprland", + "rev": "e6ca1413648407c9a7b14f33673f67c31b296410", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "Hyprland", + "type": "github" + } + }, + "hyprland-guiutils": { + "inputs": { + "aquamarine": [ + "hyprland", + "aquamarine" + ], + "hyprgraphics": [ + "hyprland", + "hyprgraphics" + ], + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "hyprtoolkit": "hyprtoolkit", + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1767023960, + "narHash": "sha256-R2HgtVS1G3KSIKAQ77aOZ+Q0HituOmPgXW9nBNkpp3Q=", + "owner": "hyprwm", + "repo": "hyprland-guiutils", + "rev": "c2e906261142f5dd1ee0bfc44abba23e2754c660", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-guiutils", + "type": "github" + } + }, + "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1765214753, + "narHash": "sha256-P9zdGXOzToJJgu5sVjv7oeOGPIIwrd9hAUAP3PsmBBs=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "3f3860b869014c00e8b9e0528c7b4ddc335c21ab", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprlang": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1767983607, + "narHash": "sha256-8C2co8NYfR4oMOUEsPROOJ9JHrv9/ktbJJ6X1WsTbXc=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "d4037379e6057246b408bbcf796cf3e9838af5b2", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprtoolkit": { + "inputs": { + "aquamarine": [ + "hyprland", + "hyprland-guiutils", + "aquamarine" + ], + "hyprgraphics": [ + "hyprland", + "hyprland-guiutils", + "hyprgraphics" + ], + "hyprlang": [ + "hyprland", + "hyprland-guiutils", + "hyprlang" + ], + "hyprutils": [ + "hyprland", + "hyprland-guiutils", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprland-guiutils", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "hyprland-guiutils", + "nixpkgs" + ], + "systems": [ + "hyprland", + "hyprland-guiutils", + "systems" + ] + }, + "locked": { + "lastModified": 1764592794, + "narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=", + "owner": "hyprwm", + "repo": "hyprtoolkit", + "rev": "5cfe0743f0e608e1462972303778d8a0859ee63e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprtoolkit", + "type": "github" + } + }, + "hyprutils": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1770139857, + "narHash": "sha256-bCqxcXjavgz5KBJ/1CBLqnagMMf9JvU1m9HmYVASKoc=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "9038eec033843c289b06b83557a381a2648d8fa5", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1770501770, + "narHash": "sha256-NWRM6+YxTRv+bT9yvlhhJ2iLae1B1pNH3mAL5wi2rlQ=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "0bd8b6cde9ec27d48aad9e5b4deefb3746909d40", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "type": "github" + } + }, + "hyprwire": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1770203293, + "narHash": "sha256-PR/KER+yiHabFC/h1Wjb+9fR2Uy0lWM3Qld7jPVaWkk=", + "owner": "hyprwm", + "repo": "hyprwire", + "rev": "37bc90eed02b0c8b5a77a0b00867baf3005cfb98", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwire", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1770882871, + "narHash": "sha256-nw5g+xl3veea+maxJ2/81tMEA/rPq9aF1H5XF35X+OE=", + "owner": "NixOS", + "repo": "nixos-hardware", + "rev": "af04cb78aa85b2a4d1c15fc7270347e0d0eda97b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1770841267, + "narHash": "sha256-9xejG0KoqsoKEGp2kVbXRlEYtFFcDTHjidiuX8hGO44=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ec7c70d12ce2fc37cb92aff673dcdca89d187bae", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1771008912, + "narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a82ccc39b39b621151d6732718e3e250109076fa", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "hyprland", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770726378, + "narHash": "sha256-kck+vIbGOaM/dHea7aTBxdFYpeUl/jHOy5W3eyRvVx8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "5eaaedde414f6eb1aea8b8525c466dc37bba95ae", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "home-manager": "home-manager_2", + "hyprland": "hyprland", + "nixos-hardware": "nixos-hardware", + "nixpkgs": "nixpkgs_2", + "nixpkgs-stable": "nixpkgs-stable" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "xdph": { + "inputs": { + "hyprland-protocols": [ + "hyprland", + "hyprland-protocols" + ], + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1761431178, + "narHash": "sha256-xzjC1CV3+wpUQKNF+GnadnkeGUCJX+vgaWIZsnz9tzI=", + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "rev": "4b8801228ff958d028f588f0c2b911dbf32297f9", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..2e1a7f3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,162 @@ +{ + description = "Nomarchy - An opinionated NixOS configuration with Hyprland"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11"; + + hyprland.url = "github:hyprwm/Hyprland"; + + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Secrets management + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Hardware quirks database + nixos-hardware.url = "github:NixOS/nixos-hardware"; + }; + + outputs = { + self, + nixpkgs, + nixpkgs-stable, + hyprland, + home-manager, + agenix, + nixos-hardware, + ... + } @ inputs: let + lib = nixpkgs.lib; + supportedSystems = ["x86_64-linux" "aarch64-linux"]; + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + + # Import helper functions + mkHost = import ./lib/mkHost.nix {inherit inputs lib;}; + + # Default configuration options + defaultConfig = { + username = "user"; + hostname = "nomarchy"; + timezone = "UTC"; + locale = "en_US.UTF-8"; + keyboardLayouts = ["us"]; + keyboardVariants = [""]; + + # Features (opinionated defaults, user can disable) + enableSyncthing = true; + enableMullvad = false; + enablePrinting = true; + enableBluetooth = true; + + # Performance (security-conscious defaults) + enableMitigationsOff = false; # Opt-in only + + # Theme + theme = "classical"; + }; + in { + # NixOS configurations + nixosConfigurations = { + # Example configuration (requires hardware-configuration.nix) + # Users create their own configuration via the installer + example = mkHost { + system = "x86_64-linux"; + config = defaultConfig // { + hostname = "nomarchy"; + }; + extraModules = [ + # Minimal test hardware config + ({...}: { + boot.loader.systemd-boot.enable = true; + fileSystems."/" = { + device = "/dev/disk/by-label/nixos"; + fsType = "ext4"; + }; + }) + ]; + }; + + # ISO installer configuration + installer = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs;}; + modules = [ + ./iso/default.nix + ]; + }; + }; + + # Flake apps + apps = forAllSystems (system: { + # Main installer app: nix run github:blu/nomarchy + default = { + type = "app"; + program = "${self.packages.${system}.nomarchy-install}/bin/nomarchy-install"; + }; + + # Interactive installer + install = { + type = "app"; + program = "${self.packages.${system}.nomarchy-install}/bin/nomarchy-install"; + }; + }); + + # Packages + packages = forAllSystems (system: let + pkgs = nixpkgs.legacyPackages.${system}; + in { + # Installer script + nomarchy-install = pkgs.writeShellScriptBin "nomarchy-install" (builtins.readFile ./installer/install.sh); + + # ISO image + iso = self.nixosConfigurations.installer.config.system.build.isoImage; + + default = self.packages.${system}.nomarchy-install; + }); + + # NixOS modules for users who want to import individual pieces + nixosModules = { + default = import ./modules; + hyprland = import ./modules/desktop/hyprland.nix; + theme = import ./themes/theme.nix; + performance = import ./modules/performance; + }; + + # Home-manager modules + homeManagerModules = { + default = import ./modules/home; + }; + + # Templates for users to bootstrap their own config + templates = { + default = { + path = ./templates/default; + description = "Basic nomarchy configuration"; + }; + }; + + # Export lib functions for users + lib = { + inherit mkHost; + }; + + # Development shell + devShells = forAllSystems (system: let + pkgs = nixpkgs.legacyPackages.${system}; + in { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + nil # Nix LSP + alejandra # Nix formatter + nixpkgs-fmt + ]; + }; + }); + }; +} diff --git a/installer/install.sh b/installer/install.sh new file mode 100755 index 0000000..22cdeef --- /dev/null +++ b/installer/install.sh @@ -0,0 +1,334 @@ +#!/usr/bin/env bash +# Nomarchy Installer +# Interactive TUI installer for existing NixOS systems + +set -euo pipefail + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color +BOLD='\033[1m' + +# Detect if we're running from flake or locally +NOMARCHY_FLAKE="${NOMARCHY_FLAKE:-github:blu/nomarchy}" + +print_banner() { + echo -e "${CYAN}" + cat << 'EOF' + _ __ __ + / | / /___ ____ ___ ____ _____/ /___ __ + / |/ / __ \/ __ `__ \/ __ `/ __/ / __/ / / + / /| / /_/ / / / / / / /_/ / / / / /__ / / +/_/ |_/\____/_/ /_/ /_/\__,_/_/ /_/\___//_/ + +EOF + echo -e "${NC}" + echo -e "${BOLD}An opinionated NixOS configuration with Hyprland${NC}" + echo "" +} + +check_requirements() { + echo -e "${BLUE}Checking requirements...${NC}" + + if [ ! -f /etc/NIXOS ]; then + echo -e "${RED}Error: This installer requires NixOS.${NC}" + echo "For other Linux distributions, please use the ISO installer." + exit 1 + fi + + if [ "$(id -u)" = "0" ]; then + echo -e "${RED}Error: Do not run this installer as root.${NC}" + echo "The installer will use sudo when needed." + exit 1 + fi + + echo -e "${GREEN}Requirements met!${NC}" + echo "" +} + +prompt_username() { + local current_user + current_user=$(whoami) + + echo -e "${BOLD}Username${NC}" + echo -e "Current user: ${CYAN}${current_user}${NC}" + read -rp "Enter username (press Enter for '${current_user}'): " username + username="${username:-$current_user}" + echo "" +} + +prompt_hostname() { + local current_hostname + current_hostname=$(hostname) + + echo -e "${BOLD}Hostname${NC}" + echo -e "Current hostname: ${CYAN}${current_hostname}${NC}" + read -rp "Enter hostname (press Enter for '${current_hostname}'): " hostname_input + hostname_input="${hostname_input:-$current_hostname}" + echo "" +} + +prompt_timezone() { + local current_tz + current_tz=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "UTC") + + echo -e "${BOLD}Timezone${NC}" + echo -e "Current timezone: ${CYAN}${current_tz}${NC}" + echo "Common timezones: America/New_York, America/Los_Angeles, Europe/London, Asia/Tokyo" + read -rp "Enter timezone (press Enter for '${current_tz}'): " timezone + timezone="${timezone:-$current_tz}" + echo "" +} + +prompt_locale() { + echo -e "${BOLD}Locale${NC}" + echo "Default: en_US.UTF-8" + read -rp "Enter locale (press Enter for 'en_US.UTF-8'): " locale + locale="${locale:-en_US.UTF-8}" + echo "" +} + +prompt_keyboard() { + echo -e "${BOLD}Keyboard Layout${NC}" + echo "Default: us" + echo "Examples: us, uk, de, fr, es, us,gr (multiple separated by comma)" + read -rp "Enter keyboard layout(s): " keyboard + keyboard="${keyboard:-us}" + + echo "Keyboard variants (leave empty for default):" + echo "Example: ,polytonic (for Greek polytonic as second layout)" + read -rp "Enter keyboard variant(s): " keyboard_variant + keyboard_variant="${keyboard_variant:-}" + echo "" +} + +prompt_location() { + echo -e "${BOLD}Location (for Gammastep night light)${NC}" + echo "Enter coordinates for automatic night light adjustment." + echo "Leave empty to disable or set manually later." + read -rp "Latitude (e.g., 40.7): " lat + read -rp "Longitude (e.g., -74.0): " lon + lat="${lat:-0}" + lon="${lon:-0}" + echo "" +} + +prompt_features() { + echo -e "${BOLD}Optional Features${NC}" + + read -rp "Enable Syncthing file sync? [Y/n]: " syncthing + syncthing="${syncthing:-y}" + [[ "$syncthing" =~ ^[Yy] ]] && enable_syncthing="true" || enable_syncthing="false" + + read -rp "Enable Mullvad VPN? [y/N]: " mullvad + mullvad="${mullvad:-n}" + [[ "$mullvad" =~ ^[Yy] ]] && enable_mullvad="true" || enable_mullvad="false" + + read -rp "Enable printing support? [Y/n]: " printing + printing="${printing:-y}" + [[ "$printing" =~ ^[Yy] ]] && enable_printing="true" || enable_printing="false" + + echo "" + echo -e "${YELLOW}WARNING: The following option disables CPU security mitigations.${NC}" + echo "This improves performance but reduces security. Only enable if you understand the risks." + read -rp "Enable mitigations=off (insecure)? [y/N]: " mitigations + mitigations="${mitigations:-n}" + [[ "$mitigations" =~ ^[Yy] ]] && enable_mitigations_off="true" || enable_mitigations_off="false" + + echo "" +} + +generate_config() { + local config_dir="$HOME/.config/nomarchy" + mkdir -p "$config_dir/wallpapers" + + echo -e "${BLUE}Generating configuration...${NC}" + + # Parse keyboard layouts into Nix list format + local kb_layouts_nix + kb_layouts_nix=$(echo "$keyboard" | sed 's/,/" "/g' | sed 's/^/"/' | sed 's/$/"/') + + local kb_variants_nix + if [ -n "$keyboard_variant" ]; then + kb_variants_nix=$(echo "$keyboard_variant" | sed 's/,/" "/g' | sed 's/^/"/' | sed 's/$/"/') + else + kb_variants_nix='""' + fi + + cat > "$config_dir/config.nix" << EOF +# Nomarchy User Configuration +# Generated by nomarchy-install on $(date) +{ + username = "${username}"; + hostname = "${hostname_input}"; + timezone = "${timezone}"; + locale = "${locale}"; + keyboardLayouts = [${kb_layouts_nix}]; + keyboardVariants = [${kb_variants_nix}]; + + # Location for Gammastep (night light) + location = { + lat = ${lat}; + lon = ${lon}; + }; + + # Features + enableSyncthing = ${enable_syncthing}; + enableMullvad = ${enable_mullvad}; + enablePrinting = ${enable_printing}; + enableBluetooth = true; + + # Performance (security tradeoff) + enableMitigationsOff = ${enable_mitigations_off}; + + # Theme + theme = "classical"; +} +EOF + + echo -e "${GREEN}Configuration saved to ${config_dir}/config.nix${NC}" + echo "" +} + +setup_flake() { + local config_dir="$HOME/.config/nomarchy" + + echo -e "${BLUE}Setting up flake...${NC}" + + cat > "$config_dir/flake.nix" << EOF +{ + description = "My Nomarchy Configuration"; + + inputs = { + nomarchy.url = "${NOMARCHY_FLAKE}"; + nixpkgs.follows = "nomarchy/nixpkgs"; + }; + + outputs = { self, nomarchy, nixpkgs, ... }@inputs: let + userConfig = import ./config.nix; + in { + nixosConfigurations.\${userConfig.hostname} = nomarchy.lib.mkHost { + system = "x86_64-linux"; + config = userConfig; + extraModules = [ + # Add your hardware-configuration.nix here + /etc/nixos/hardware-configuration.nix + + # Add any custom modules here + # ./my-custom-module.nix + ]; + }; + }; +} +EOF + + echo -e "${GREEN}Flake created at ${config_dir}/flake.nix${NC}" + echo "" +} + +download_wallpapers() { + local wallpaper_dir="$HOME/.config/nomarchy/wallpapers" + + echo -e "${BLUE}Setting up wallpapers...${NC}" + + # Create a default wallpaper (simple gradient) + # In production, this would download from the nomarchy repo + if command -v convert &> /dev/null; then + convert -size 1920x1080 gradient:'#1a1611-#2d2620' "$wallpaper_dir/default.jpg" 2>/dev/null || true + fi + + echo -e "${YELLOW}Note: Copy your wallpapers to ${wallpaper_dir}${NC}" + echo "" +} + +show_summary() { + echo -e "${BOLD}Configuration Summary${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo -e "Username: ${CYAN}${username}${NC}" + echo -e "Hostname: ${CYAN}${hostname_input}${NC}" + echo -e "Timezone: ${CYAN}${timezone}${NC}" + echo -e "Locale: ${CYAN}${locale}${NC}" + echo -e "Keyboard: ${CYAN}${keyboard}${NC}" + echo -e "Syncthing: ${CYAN}${enable_syncthing}${NC}" + echo -e "Mullvad: ${CYAN}${enable_mullvad}${NC}" + echo -e "Printing: ${CYAN}${enable_printing}${NC}" + echo -e "Mitigations: ${CYAN}${enable_mitigations_off}${NC}" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" +} + +apply_config() { + local config_dir="$HOME/.config/nomarchy" + + echo -e "${YELLOW}Ready to apply configuration.${NC}" + read -rp "Apply now? This will rebuild NixOS. [y/N]: " apply + + if [[ "$apply" =~ ^[Yy] ]]; then + echo -e "${BLUE}Applying configuration...${NC}" + echo "" + + cd "$config_dir" + + # Update flake inputs + nix flake update + + # Rebuild + sudo nixos-rebuild switch --flake ".#${hostname_input}" + + echo "" + echo -e "${GREEN}Configuration applied successfully!${NC}" + echo -e "Please ${BOLD}log out and log back in${NC} to start Hyprland." + else + echo "" + echo -e "${YELLOW}Configuration saved but not applied.${NC}" + echo "To apply later, run:" + echo -e " ${CYAN}cd ~/.config/nomarchy && sudo nixos-rebuild switch --flake .#${hostname_input}${NC}" + fi +} + +main() { + print_banner + check_requirements + + echo -e "${BOLD}Let's configure your Nomarchy installation.${NC}" + echo "" + + prompt_username + prompt_hostname + prompt_timezone + prompt_locale + prompt_keyboard + prompt_location + prompt_features + + show_summary + + read -rp "Proceed with this configuration? [Y/n]: " proceed + proceed="${proceed:-y}" + + if [[ ! "$proceed" =~ ^[Yy] ]]; then + echo "Installation cancelled." + exit 0 + fi + + generate_config + setup_flake + download_wallpapers + apply_config + + echo "" + echo -e "${GREEN}${BOLD}Nomarchy installation complete!${NC}" + echo "" + echo "Next steps:" + echo " 1. Log out and select 'Hyprland' from the session menu" + echo " 2. Press Super+/ for Quick Actions menu" + echo " 3. Press Super+R for app launcher" + echo " 4. See ~/.config/nomarchy/README.md for more info" + echo "" +} + +main "$@" diff --git a/iso/default.nix b/iso/default.nix new file mode 100644 index 0000000..ddb57da --- /dev/null +++ b/iso/default.nix @@ -0,0 +1,116 @@ +# ISO Installer Configuration +{ + config, + lib, + pkgs, + modulesPath, + inputs, + ... +}: { + imports = [ + "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" + "${modulesPath}/installer/cd-dvd/channel.nix" + ]; + + # ISO naming + isoImage.isoName = "nomarchy-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.iso"; + isoImage.volumeID = "NOMARCHY"; + + # Boot settings - use LTS kernel for ISO stability + boot.kernelPackages = pkgs.linuxPackages; + + # Disable ZFS (broken with latest kernels) + boot.supportedFilesystems = lib.mkForce ["btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" "ext4"]; + + # Limine bootloader for ISO (commented out until properly configured) + # boot.loader.limine.enable = true; + + # Enable SSH for headless installs + services.openssh = { + enable = true; + settings.PermitRootLogin = "yes"; + }; + + # Networking + networking = { + hostName = "nomarchy-installer"; + networkmanager.enable = true; + wireless.enable = lib.mkForce false; + }; + + # Installer environment packages + environment.systemPackages = with pkgs; [ + # Disk partitioning + parted + gptfdisk + dosfstools + cryptsetup + + # Filesystem tools + e2fsprogs + btrfs-progs + ntfs3g + + # Network + networkmanager + wpa_supplicant + + # TUI + dialog + newt # provides whiptail + + # Utilities + vim + git + curl + wget + jq + + # NixOS installation + nixos-install-tools + ]; + + # Auto-login to installer + services.getty.autologinUser = "nixos"; + + # Welcome message + environment.etc."motd".text = '' + + ╔═══════════════════════════════════════════════════════════╗ + ║ ║ + ║ Welcome to the Nomarchy Installer ║ + ║ ║ + ║ Run 'nomarchy-install' to begin installation ║ + ║ ║ + ║ For more information: https://github.com/blu/nomarchy ║ + ║ ║ + ╚═══════════════════════════════════════════════════════════╝ + + ''; + + # Copy installer script + system.activationScripts.installer = '' + mkdir -p /usr/local/bin + cat > /usr/local/bin/nomarchy-install << 'INSTALLER' + #!/usr/bin/env bash + # Nomarchy ISO Installer - coming soon + echo "ISO installer not yet implemented." + echo "Please use the NixOS manual installation process," + echo "then run: nix run github:blu/nomarchy" + INSTALLER + chmod +x /usr/local/bin/nomarchy-install + ''; + + # User account + users.users.nixos = { + isNormalUser = true; + extraGroups = ["wheel" "networkmanager"]; + initialPassword = "nomarchy"; + }; + + # Allow passwordless sudo + security.sudo.wheelNeedsPassword = false; + + # System state version + system.stateVersion = "24.11"; +} diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..fb39d28 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,4 @@ +# Nomarchy library functions +{inputs, lib}: { + mkHost = import ./mkHost.nix {inherit inputs lib;}; +} diff --git a/lib/mkHost.nix b/lib/mkHost.nix new file mode 100644 index 0000000..08eb46e --- /dev/null +++ b/lib/mkHost.nix @@ -0,0 +1,92 @@ +# Helper function to create a NixOS host configuration +{inputs, lib}: { + system, + config, + extraModules ? [], +}: let + pkgs = import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + }; + + pkgs-stable = import inputs.nixpkgs-stable { + inherit system; + config.allowUnfree = true; + }; +in + inputs.nixpkgs.lib.nixosSystem { + inherit system; + + specialArgs = { + inherit inputs pkgs-stable; + nomarchyConfig = config; + }; + + modules = + [ + # Core system modules + ../modules/core + ../modules/desktop + ../modules/services + ../modules/programs + ../modules/performance + + # Secrets management + inputs.agenix.nixosModules.default + + # Home-manager integration + inputs.home-manager.nixosModules.home-manager + { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + extraSpecialArgs = { + inherit inputs pkgs-stable; + nomarchyConfig = config; + }; + users.${config.username} = import ../modules/home; + }; + } + + # Theme + ../themes/theme.nix + + # Dynamic configuration based on user settings + ({...}: { + # Networking + networking.hostName = config.hostname; + + # Locale and timezone + time.timeZone = config.timezone; + i18n.defaultLocale = config.locale; + i18n.extraLocaleSettings = let + locale = config.locale; + in { + LC_ADDRESS = locale; + LC_IDENTIFICATION = locale; + LC_MEASUREMENT = locale; + LC_MONETARY = locale; + LC_NAME = locale; + LC_NUMERIC = locale; + LC_PAPER = locale; + LC_TELEPHONE = locale; + LC_TIME = locale; + }; + + # User account + users.users.${config.username} = { + isNormalUser = true; + description = config.username; + extraGroups = ["networkmanager" "wheel" "adbusers" "video" "audio"]; + shell = pkgs.zsh; + }; + + # Enable flakes + nix.settings.experimental-features = ["nix-command" "flakes"]; + + # State version + system.stateVersion = "24.11"; + }) + ] + ++ extraModules; + } diff --git a/modules/core/boot.nix b/modules/core/boot.nix new file mode 100644 index 0000000..952fc7e --- /dev/null +++ b/modules/core/boot.nix @@ -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; + }; +} diff --git a/modules/core/default.nix b/modules/core/default.nix new file mode 100644 index 0000000..df70217 --- /dev/null +++ b/modules/core/default.nix @@ -0,0 +1,8 @@ +# Core system modules +{...}: { + imports = [ + ./boot.nix + ./networking.nix + ./hardware.nix + ]; +} diff --git a/modules/core/hardware.nix b/modules/core/hardware.nix new file mode 100644 index 0000000..669af50 --- /dev/null +++ b/modules/core/hardware.nix @@ -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 + ]); +} diff --git a/modules/core/networking.nix b/modules/core/networking.nix new file mode 100644 index 0000000..f3e32c2 --- /dev/null +++ b/modules/core/networking.nix @@ -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; +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..cd72501 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,10 @@ +# Main modules index +{...}: { + imports = [ + ./core + ./desktop + ./services + ./programs + ./performance + ]; +} diff --git a/modules/desktop/default.nix b/modules/desktop/default.nix new file mode 100644 index 0000000..e619f47 --- /dev/null +++ b/modules/desktop/default.nix @@ -0,0 +1,7 @@ +# Desktop environment modules +{...}: { + imports = [ + ./hyprland.nix + ./display-manager.nix + ]; +} diff --git a/modules/desktop/display-manager.nix b/modules/desktop/display-manager.nix new file mode 100644 index 0000000..7bb94e8 --- /dev/null +++ b/modules/desktop/display-manager.nix @@ -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"; +} diff --git a/modules/desktop/hyprland.nix b/modules/desktop/hyprland.nix new file mode 100644 index 0000000..c3704c8 --- /dev/null +++ b/modules/desktop/hyprland.nix @@ -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"; + }; +} diff --git a/modules/home/default.nix b/modules/home/default.nix new file mode 100644 index 0000000..7b64443 --- /dev/null +++ b/modules/home/default.nix @@ -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; +} diff --git a/modules/home/hyprland.nix b/modules/home/hyprland.nix new file mode 100644 index 0000000..962c9b2 --- /dev/null +++ b/modules/home/hyprland.nix @@ -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"; + }; + }; +} diff --git a/modules/home/neovim.nix b/modules/home/neovim.nix new file mode 100644 index 0000000..67f4ba6 --- /dev/null +++ b/modules/home/neovim.nix @@ -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", "ff", telescope.find_files, { desc = "Find files" }) + vim.keymap.set("n", "fg", telescope.live_grep, { desc = "Live grep" }) + vim.keymap.set("n", "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({ + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete(), + [""] = 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", "e", ":NvimTreeToggle", { silent = true }) + + -- Git signs + require("gitsigns").setup() + + -- Status line + require("lualine").setup() + + -- Buffer line + require("bufferline").setup() + ''; + }; +} diff --git a/modules/home/notifications.nix b/modules/home/notifications.nix new file mode 100644 index 0000000..0d7308c --- /dev/null +++ b/modules/home/notifications.nix @@ -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; + } + ''; + }; +} diff --git a/modules/home/rofi.nix b/modules/home/rofi.nix new file mode 100644 index 0000000..c58a770 --- /dev/null +++ b/modules/home/rofi.nix @@ -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; + } + ''; +} diff --git a/modules/home/scripts.nix b/modules/home/scripts.nix new file mode 100644 index 0000000..4026ef1 --- /dev/null +++ b/modules/home/scripts.nix @@ -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 + ''; + }; +} diff --git a/modules/home/shell.nix b/modules/home/shell.nix new file mode 100644 index 0000000..2100673 --- /dev/null +++ b/modules/home/shell.nix @@ -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; + }; + }; + }; +} diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix new file mode 100644 index 0000000..3f01547 --- /dev/null +++ b/modules/home/waybar.nix @@ -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 = "{calendar}"; + calendar = { + mode = "month"; + weeks-pos = "right"; + format = { + months = "{}"; + days = "{}"; + weeks = "W{}"; + weekdays = "{}"; + today = "{}"; + }; + }; + }; + + 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; + }; + }; + }; + }; +} diff --git a/modules/performance/default.nix b/modules/performance/default.nix new file mode 100644 index 0000000..d8c96b0 --- /dev/null +++ b/modules/performance/default.nix @@ -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; + }; +} diff --git a/modules/programs/default.nix b/modules/programs/default.nix new file mode 100644 index 0000000..1b7ff3f --- /dev/null +++ b/modules/programs/default.nix @@ -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"]; + })) + ]; +} diff --git a/modules/services/default.nix b/modules/services/default.nix new file mode 100644 index 0000000..c7f67b5 --- /dev/null +++ b/modules/services/default.nix @@ -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; +} diff --git a/templates/default/flake.nix b/templates/default/flake.nix new file mode 100644 index 0000000..8c85efe --- /dev/null +++ b/templates/default/flake.nix @@ -0,0 +1,47 @@ +{ + description = "My Nomarchy Configuration"; + + inputs = { + nomarchy.url = "github:blu/nomarchy"; + nixpkgs.follows = "nomarchy/nixpkgs"; + }; + + outputs = { self, nomarchy, nixpkgs, ... }: let + # Edit this configuration + userConfig = { + username = "myuser"; + hostname = "myhostname"; + timezone = "America/New_York"; + locale = "en_US.UTF-8"; + keyboardLayouts = ["us"]; + keyboardVariants = [""]; + + # Location for night light (gammastep) + location = { lat = 40.7; lon = -74.0; }; + + # Features + enableSyncthing = true; + enableMullvad = false; + enablePrinting = true; + enableBluetooth = true; + + # Performance (security tradeoff - leave false unless you understand the risks) + enableMitigationsOff = false; + + # Theme + theme = "classical"; + }; + in { + nixosConfigurations.${userConfig.hostname} = nomarchy.lib.mkHost { + system = "x86_64-linux"; + config = userConfig; + extraModules = [ + # Import your hardware configuration + ./hardware-configuration.nix + + # Add custom modules here + # ./my-custom-module.nix + ]; + }; + }; +} diff --git a/themes/classical/colors.nix b/themes/classical/colors.nix new file mode 100644 index 0000000..733d527 --- /dev/null +++ b/themes/classical/colors.nix @@ -0,0 +1,94 @@ +# Classical / Antiquity Theme +# Inspired by Thomas Cole's "Course of Empire" series +{ + name = "classical"; + description = "Earthy, vintage aesthetic with gold and bronze accents"; + + colors = { + # Backgrounds (dark to light) + bg = { + primary = "#1a1611"; # Very dark brown (main background) + secondary = "#2d2620"; # Dark brown (panels, inputs) + tertiary = "#3d3428"; # Medium brown (hover states) + transparent = "rgba(26, 22, 17, 0.92)"; + panelTransparent = "rgba(45, 38, 32, 0.85)"; + }; + + # Foregrounds (text) + fg = { + primary = "#d4c4a8"; # Light tan (main text) + secondary = "#b8a88c"; # Muted tan (secondary text) + muted = "#8b7355"; # Brown (disabled/placeholder) + dark = "#5c5346"; # Dark muted (very subtle text) + }; + + # Accent colors + accent = { + gold = "#d4a857"; # Primary accent (buttons, highlights) + terracotta = "#c67b5c"; # Warm accent (memory, alt highlights) + olive = "#7a8450"; # Green accent (success, battery) + sky = "#6b98a6"; # Blue accent (info, network) + bronze = "#b85c38"; # Orange accent (CPU, warnings) + }; + + # Semantic colors + status = { + success = "#8a9a5b"; # Olive green + warning = "#c9a227"; # Amber gold + error = "#a63d40"; # Deep red + info = "#7a9cb8"; # Muted blue + }; + + # Border colors + border = { + primary = "rgba(139, 90, 43, 0.6)"; + accent = "rgba(212, 168, 87, 0.5)"; + subtle = "rgba(139, 90, 43, 0.4)"; + }; + + # Hyprland-specific (gradients for borders) + hyprland = { + activeBorder = "rgba(33ccffee) rgba(00ff99ee) 45deg"; + inactiveBorder = "rgba(595959aa)"; + shadow = "rgba(1a1a1aee)"; + }; + }; + + # Font configuration + fonts = { + mono = "JetBrainsMono Nerd Font"; + monoAlt = "VictorMono Nerd Font Mono"; + sans = "Inter"; + icon = "Font Awesome 6 Free"; + + size = { + small = 12; + normal = 14; + large = 16; + xlarge = 18; + }; + }; + + # Spacing and sizing + spacing = { + small = 4; + normal = 8; + large = 12; + xlarge = 20; + }; + + # Border radius + radius = { + small = 4; + normal = 8; + large = 12; + }; + + # Opacity + opacity = { + panel = 0.92; + window = 0.85; + inactive = 1.0; + active = 1.0; + }; +} diff --git a/themes/classical/wallpapers/Caspar_David_Friedrich_-_Wanderer_above_the_Sea_of_Fog.jpeg b/themes/classical/wallpapers/Caspar_David_Friedrich_-_Wanderer_above_the_Sea_of_Fog.jpeg new file mode 100644 index 0000000..9554bbf Binary files /dev/null and b/themes/classical/wallpapers/Caspar_David_Friedrich_-_Wanderer_above_the_Sea_of_Fog.jpeg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_The_Consummation_The_Course_of_the_Empire_1836.jpg b/themes/classical/wallpapers/Cole_Thomas_The_Consummation_The_Course_of_the_Empire_1836.jpg new file mode 100644 index 0000000..8073cfc Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_The_Consummation_The_Course_of_the_Empire_1836.jpg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Desolation_1836.jpg b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Desolation_1836.jpg new file mode 100644 index 0000000..76bc3b6 Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Desolation_1836.jpg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Destruction_1836.jpg b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Destruction_1836.jpg new file mode 100644 index 0000000..8109c02 Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_Destruction_1836.jpg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Arcadian_or_Pastoral_State_1836.jpg b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Arcadian_or_Pastoral_State_1836.jpg new file mode 100644 index 0000000..558d8d0 Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Arcadian_or_Pastoral_State_1836.jpg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Savage_State_1836.jpg b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Savage_State_1836.jpg new file mode 100644 index 0000000..1324b62 Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_The_Course_of_Empire_The_Savage_State_1836.jpg differ diff --git a/themes/classical/wallpapers/Cole_Thomas_View_of_Florence_from_San_Miniato_1837.jpg b/themes/classical/wallpapers/Cole_Thomas_View_of_Florence_from_San_Miniato_1837.jpg new file mode 100644 index 0000000..7656b6c Binary files /dev/null and b/themes/classical/wallpapers/Cole_Thomas_View_of_Florence_from_San_Miniato_1837.jpg differ diff --git a/themes/classical/wallpapers/David_-_The_Death_of_Socrates.jpg b/themes/classical/wallpapers/David_-_The_Death_of_Socrates.jpg new file mode 100644 index 0000000..b99983f Binary files /dev/null and b/themes/classical/wallpapers/David_-_The_Death_of_Socrates.jpg differ diff --git a/themes/classical/wallpapers/Home_in_the_Woods_1847_Thomas_Cole.jpeg b/themes/classical/wallpapers/Home_in_the_Woods_1847_Thomas_Cole.jpeg new file mode 100644 index 0000000..1e866e9 Binary files /dev/null and b/themes/classical/wallpapers/Home_in_the_Woods_1847_Thomas_Cole.jpeg differ diff --git a/themes/classical/wallpapers/Paris_-_The_Venus_de_Milo_-_2381.jpg b/themes/classical/wallpapers/Paris_-_The_Venus_de_Milo_-_2381.jpg new file mode 100644 index 0000000..fbe3941 Binary files /dev/null and b/themes/classical/wallpapers/Paris_-_The_Venus_de_Milo_-_2381.jpg differ diff --git a/themes/classical/wallpapers/The_Angel_Appearing_to_the_Shepherds_(Thomas_Cole).jpg b/themes/classical/wallpapers/The_Angel_Appearing_to_the_Shepherds_(Thomas_Cole).jpg new file mode 100644 index 0000000..7fca1c2 Binary files /dev/null and b/themes/classical/wallpapers/The_Angel_Appearing_to_the_Shepherds_(Thomas_Cole).jpg differ diff --git a/themes/classical/wallpapers/The_Return_A31154.jpg b/themes/classical/wallpapers/The_Return_A31154.jpg new file mode 100644 index 0000000..88dee25 Binary files /dev/null and b/themes/classical/wallpapers/The_Return_A31154.jpg differ diff --git a/themes/classical/wallpapers/The_School_of_Athens_Fresco_by_Raphael_(Ank_Kumar__Infosys_Limited)_02.jpg b/themes/classical/wallpapers/The_School_of_Athens_Fresco_by_Raphael_(Ank_Kumar__Infosys_Limited)_02.jpg new file mode 100644 index 0000000..eca1436 Binary files /dev/null and b/themes/classical/wallpapers/The_School_of_Athens_Fresco_by_Raphael_(Ank_Kumar__Infosys_Limited)_02.jpg differ diff --git a/themes/classical/wallpapers/Thomas_Cole_-_Architect’s_Dream_-_Google_Art_Project.jpg b/themes/classical/wallpapers/Thomas_Cole_-_Architect’s_Dream_-_Google_Art_Project.jpg new file mode 100644 index 0000000..96c8b98 Binary files /dev/null and b/themes/classical/wallpapers/Thomas_Cole_-_Architect’s_Dream_-_Google_Art_Project.jpg differ diff --git a/themes/classical/wallpapers/Thomas_Cole_-_Expulsion._Moon_and_Firelight.jpg b/themes/classical/wallpapers/Thomas_Cole_-_Expulsion._Moon_and_Firelight.jpg new file mode 100644 index 0000000..64a6d9a Binary files /dev/null and b/themes/classical/wallpapers/Thomas_Cole_-_Expulsion._Moon_and_Firelight.jpg differ diff --git a/themes/classical/wallpapers/Thomas_Cole_-_The_Mountain_Ford.jpg b/themes/classical/wallpapers/Thomas_Cole_-_The_Mountain_Ford.jpg new file mode 100644 index 0000000..cab2065 Binary files /dev/null and b/themes/classical/wallpapers/Thomas_Cole_-_The_Mountain_Ford.jpg differ diff --git a/themes/classical/wallpapers/parthenon.jpg b/themes/classical/wallpapers/parthenon.jpg new file mode 100644 index 0000000..e955810 Binary files /dev/null and b/themes/classical/wallpapers/parthenon.jpg differ diff --git a/themes/classical/wallpapers/washington-delaware.jpg b/themes/classical/wallpapers/washington-delaware.jpg new file mode 100644 index 0000000..8684443 Binary files /dev/null and b/themes/classical/wallpapers/washington-delaware.jpg differ diff --git a/themes/theme.nix b/themes/theme.nix new file mode 100644 index 0000000..ee4c005 --- /dev/null +++ b/themes/theme.nix @@ -0,0 +1,54 @@ +# Theme module - provides colors and styling to all nomarchy components +{ + config, + lib, + pkgs, + nomarchyConfig, + ... +}: let + # Load the selected theme + themeName = nomarchyConfig.theme or "classical"; + + # Available themes + themes = { + classical = import ./classical/colors.nix; + # Future themes can be added here: + # nord = import ./nord/colors.nix; + # catppuccin = import ./catppuccin/colors.nix; + }; + + # Get the active theme, falling back to classical + theme = themes.${themeName} or themes.classical; +in { + # Export theme as a module option for other modules to consume + options.nomarchy.theme = lib.mkOption { + type = lib.types.attrs; + default = theme; + description = "The active nomarchy theme configuration"; + }; + + config = { + # Set the theme in config + nomarchy.theme = theme; + + # Install theme fonts + fonts.packages = with pkgs; [ + 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 + inter + ]; + + fonts.fontconfig = { + enable = true; + defaultFonts = { + monospace = [theme.fonts.mono]; + sansSerif = [theme.fonts.sans]; + }; + }; + }; +}