Compare commits
4 Commits
1ba1eeed64
...
583708d78c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
583708d78c | ||
|
|
6763bef73e | ||
|
|
465f013155 | ||
|
|
eda8461304 |
83
README.md
83
README.md
@@ -54,7 +54,10 @@ Flat on purpose. Two module trees, one options file each, no hidden layers.
|
|||||||
│ ├── hyprland.nix # all JSON-driven
|
│ ├── hyprland.nix # all JSON-driven
|
||||||
│ ├── waybar.nix
|
│ ├── waybar.nix
|
||||||
│ ├── ghostty.nix
|
│ ├── ghostty.nix
|
||||||
│ └── btop.nix
|
│ ├── btop.nix
|
||||||
|
│ ├── fuzzel.nix # launcher + nomarchy-menu (power, clip)
|
||||||
|
│ ├── swaync.nix # notifications, same JSON
|
||||||
|
│ └── idle.nix # hyprlock + hypridle, same JSON
|
||||||
├── hosts/
|
├── hosts/
|
||||||
│ ├── default/ # reference machine (thin: boot, user, hostname)
|
│ ├── default/ # reference machine (thin: boot, user, hostname)
|
||||||
│ └── live.nix # bootable live ISO (try the distro, no install)
|
│ └── live.nix # bootable live ISO (try the distro, no install)
|
||||||
@@ -144,6 +147,13 @@ sudo nixos-rebuild switch --flake .#default # system: rare
|
|||||||
home-manager switch --flake .#me # desktop: every theme change, no sudo
|
home-manager switch --flake .#me # desktop: every theme change, no sudo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Day-to-day you'll use the shipped shortcuts instead:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sys-update # nix flake update + system rebuild (BTRFS snapshot first when available)
|
||||||
|
home-update # home-manager switch (no flake update, no sudo)
|
||||||
|
```
|
||||||
|
|
||||||
Override anything with plain NixOS/HM options (the distro uses `mkDefault`
|
Override anything with plain NixOS/HM options (the distro uses `mkDefault`
|
||||||
throughout) or the `nomarchy.*` surface:
|
throughout) or the `nomarchy.*` surface:
|
||||||
|
|
||||||
@@ -151,12 +161,18 @@ throughout) or the `nomarchy.*` surface:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json |
|
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json |
|
||||||
| `nomarchy.terminal` | `"ghostty"` | Terminal for keybinds and `$TERMINAL` |
|
| `nomarchy.terminal` | `"ghostty"` | Terminal for keybinds and `$TERMINAL` |
|
||||||
|
| `nomarchy.keyboard.layout` | `"us"` | XKB layout for the Hyprland session (installer writes it; pairs with xkb + `console.useXkbConfig` in system.nix) |
|
||||||
|
| `nomarchy.keyboard.variant` | `""` | XKB variant for the session |
|
||||||
| `nomarchy.hyprland.enable` | `true` | Nomarchy's Hyprland config |
|
| `nomarchy.hyprland.enable` | `true` | Nomarchy's Hyprland config |
|
||||||
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
||||||
|
| `nomarchy.fuzzel.enable` | `true` | Themed fuzzel + `nomarchy-menu` (power menu) |
|
||||||
|
| `nomarchy.swaync.enable` | `true` | swaync notifications, themed |
|
||||||
|
| `nomarchy.idle.enable` | `true` | hyprlock + hypridle (idle lock 5 min, display off 10, suspend 30) |
|
||||||
| `nomarchy.ghostty.enable` | `true` | Nomarchy's Ghostty |
|
| `nomarchy.ghostty.enable` | `true` | Nomarchy's Ghostty |
|
||||||
| `nomarchy.btop.enable` | `true` | btop with per-theme colors |
|
| `nomarchy.btop.enable` | `true` | btop with per-theme colors |
|
||||||
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
|
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
|
||||||
| `nomarchy.themesDir` | Nomarchy's `themes/` | Where per-theme app overrides are probed |
|
| `nomarchy.themesDir` | Nomarchy's `themes/` | Where per-theme app overrides are probed |
|
||||||
|
| `nomarchy.system.plymouth.enable` | `true` | Branded boot splash, background from the theme JSON (recolors on system rebuilds) |
|
||||||
| `nomarchy.system.greeter.enable` | `true` | greetd/tuigreet |
|
| `nomarchy.system.greeter.enable` | `true` | greetd/tuigreet |
|
||||||
| `nomarchy.system.audio.enable` | `true` | Pipewire stack |
|
| `nomarchy.system.audio.enable` | `true` | Pipewire stack |
|
||||||
| `nomarchy.system.bluetooth.enable` | `true` | Bluetooth + blueman |
|
| `nomarchy.system.bluetooth.enable` | `true` | Bluetooth + blueman |
|
||||||
@@ -199,6 +215,7 @@ per theme — a single place to look, unlike the old distro's split:
|
|||||||
| `btop.theme` | baked into the generation (generated from the palette when absent) |
|
| `btop.theme` | baked into the generation (generated from the palette when absent) |
|
||||||
| `waybar.css` | **whole-swap**: replaces the generated bar style entirely (probed at eval time, self-contained) |
|
| `waybar.css` | **whole-swap**: replaces the generated bar style entirely (probed at eval time, self-contained) |
|
||||||
| `waybar.jsonc` | whole-swap for the bar *layout* (must be plain JSON) |
|
| `waybar.jsonc` | whole-swap for the bar *layout* (must be plain JSON) |
|
||||||
|
| `fuzzel.ini` | **whole-swap**: replaces the generated launcher/menu config entirely |
|
||||||
|
|
||||||
Six ported themes ship a `waybar.css` identity (catppuccin, lumon, nord,
|
Six ported themes ship a `waybar.css` identity (catppuccin, lumon, nord,
|
||||||
retro-82, summer-day, summer-night). Custom user themes can live in
|
retro-82, summer-day, summer-night). Custom user themes can live in
|
||||||
@@ -214,11 +231,14 @@ nomarchy-theme-sync set ui.gapsOut 16 # tweak one knob (also a switch)
|
|||||||
nomarchy-theme-sync bg next # cycle wallpapers — instant, no rebuild
|
nomarchy-theme-sync bg next # cycle wallpapers — instant, no rebuild
|
||||||
nomarchy-theme-sync bg auto # back to the theme's default wallpaper
|
nomarchy-theme-sync bg auto # back to the theme's default wallpaper
|
||||||
nomarchy-theme-sync get colors.accent
|
nomarchy-theme-sync get colors.accent
|
||||||
|
sys-update # update inputs + rebuild the system (snapshots first)
|
||||||
|
home-update # rebuild just the desktop layer
|
||||||
```
|
```
|
||||||
|
|
||||||
Keybinds: `SUPER+Return` terminal · `SUPER+D` launcher · `SUPER+T` theme
|
Keybinds: `SUPER+Return` terminal · `SUPER+D` launcher · `SUPER+T` theme
|
||||||
picker · `SUPER+SHIFT+T` next wallpaper · `SUPER+Q` close · `SUPER+1..9`
|
picker · `SUPER+SHIFT+T` next wallpaper · `SUPER+Escape` power menu ·
|
||||||
workspaces · `Print` region screenshot.
|
`SUPER+N` notifications · `SUPER+CTRL+V` clipboard history · `SUPER+Q`
|
||||||
|
close · `SUPER+1..9` workspaces · `Print` region screenshot.
|
||||||
|
|
||||||
## 6. Extending
|
## 6. Extending
|
||||||
|
|
||||||
@@ -234,40 +254,45 @@ workspaces · `Print` region screenshot.
|
|||||||
on fuzzel — already shipped for SUPER+D/SUPER+T, dmenu mode does nested
|
on fuzzel — already shipped for SUPER+D/SUPER+T, dmenu mode does nested
|
||||||
menus and per-entry icons, and its INI theme can be baked from
|
menus and per-entry icons, and its INI theme can be baked from
|
||||||
theme-state.json like every other app:
|
theme-state.json like every other app:
|
||||||
- `modules/home/fuzzel.nix`: colors/fonts from the theme JSON (today the
|
- ✓ shipped: `modules/home/fuzzel.nix` (palette/fonts/border from the
|
||||||
launcher is the one surface that ignores the theme)
|
theme JSON, `themes/<slug>/fuzzel.ini` whole-swap) and the
|
||||||
- `nomarchy-menu` dispatcher script over `fuzzel --dmenu`, Omarchy-style
|
`nomarchy-menu` dispatcher: root picker (no args) · `power`
|
||||||
nesting: Theme ▸ (apply/wallpaper) · Network ▸ nmtui · Bluetooth ▸
|
(lock/logout/suspend/hibernate/reboot/shutdown, SUPER+Escape) ·
|
||||||
blueman · Power ▸ lock/suspend/reboot/poweroff · Capture ▸ screenshot;
|
`theme` (SUPER+T) · `clipboard` (cliphist, SUPER+CTRL+V) · `calc`
|
||||||
actions delegate to nomarchy-theme-sync and friends
|
(qalc, copy/chain) · `files` (fd → xdg-open) · `web` (DuckDuckGo)
|
||||||
- script modules (each a small dmenu pipeline, no plugin framework):
|
- next modules: Network ▸ nmtui · Bluetooth ▸ blueman · Capture ▸
|
||||||
calculator (`--prompt-only` → `qalc -t` → result re-shown via `--mesg`,
|
screenshot · **ask Claude**: `--prompt-only` →
|
||||||
Enter copies / chains; needs libqalculate) · clipboard history
|
`$TERMINAL -e claude "<question>"` — the claude CLI auths via OAuth
|
||||||
(cliphist ⇄ fuzzel ⇄ wl-copy; also adds clipboard persistence) · file
|
against a Pro/Max subscription (no API key); REPL stays open for
|
||||||
open (`fd . ~` → xdg-open) · web search (query → xdg-open) · **ask
|
follow-ups (claude-code in nixpkgs is unfree — allowUnfree is on)
|
||||||
Claude**: `--prompt-only` → `$TERMINAL -e claude "<question>"` — the
|
|
||||||
claude CLI auths via OAuth against a Pro/Max subscription (no API
|
|
||||||
key); REPL stays open for follow-ups (claude-code in nixpkgs is
|
|
||||||
unfree — needs a per-package allowUnfree)
|
|
||||||
- known limits accepted for now: no live-as-you-type results (dmenu
|
- known limits accepted for now: no live-as-you-type results (dmenu
|
||||||
input is static per invocation) and no image previews
|
input is static per invocation) and no image previews
|
||||||
- decision record: this resolves the old Walker/Lua question in favor of
|
- decision record: this resolves the old Walker/Lua question in favor of
|
||||||
simplicity — no GTK4 launcher, no second theming pipeline, no image
|
simplicity — no GTK4 launcher, no second theming pipeline, no image
|
||||||
previews (instant `bg next` covers wallpaper browsing); the dispatcher
|
previews (instant `bg next` covers wallpaper browsing); the dispatcher
|
||||||
owns the menu structure, so the renderer stays swappable
|
owns the menu structure, so the renderer stays swappable
|
||||||
- We need to add networkManager applet to waybar so user can easily connect to internet
|
- **Theme parity with legacy:** summer-day/night now carry their legacy
|
||||||
|
bar layouts as `waybar.jsonc` whole-swaps (adapted: dead legacy script
|
||||||
|
modules dropped, Nerd-Fonts-v2 codepoints remapped to FontAwesome/v3,
|
||||||
|
logo button opens nomarchy-menu); the other four identity themes are
|
||||||
|
palette recolors and already match. Remaining: a visual pass over all
|
||||||
|
six on the live ISO
|
||||||
|
- **Per-theme fuzzel identity:** the `themes/<slug>/fuzzel.ini` whole-swap
|
||||||
|
mechanism ships; what remains is authoring the inis for the six identity
|
||||||
|
themes from their legacy rofi.rasi files (per-element colors like
|
||||||
|
summer-night's green inputbar aren't expressible in fuzzel's flat
|
||||||
|
scheme — approximate, note the rest as a renderer limitation)
|
||||||
- **Faster switches:** move `backgrounds/` out of the flake source (the 86 MB
|
- **Faster switches:** move `backgrounds/` out of the flake source (the 86 MB
|
||||||
re-copy on every state write is the main eval tax), then pre-built theme
|
re-copy on every state write is the main eval tax), then pre-built theme
|
||||||
variants if still needed
|
variants if still needed
|
||||||
- Plymouth + SDDM/greeter theming from the same JSON
|
- Greeter (tuigreet/SDDM) theming from the same JSON (Plymouth ships since
|
||||||
|
v1: `nomarchy.system.plymouth.*`, background tinted from the state file)
|
||||||
- Installer round 2: multi-disk BTRFS RAID, impermanence, BIOS/legacy
|
- Installer round 2: multi-disk BTRFS RAID, impermanence, BIOS/legacy
|
||||||
boot (v1 `nomarchy-install` is single-disk UEFI — see `pkgs/nomarchy-install`)
|
boot (v1 `nomarchy-install` is single-disk UEFI — see `pkgs/nomarchy-install`)
|
||||||
- `hyprlock`/`hypridle`, swayosd, launch-or-focus UX scripts
|
- swayosd (volume/brightness OSD), launch-or-focus UX scripts
|
||||||
- swaync notification center (notify-send currently renders bare)
|
- **Distro branding, round 2:** `distroName = "Nomarchy"` ships
|
||||||
- **Distro branding:** replace the NixOS brand with Nomarchy everywhere it
|
(os-release `PRETTY_NAME`, systemd-boot entries, ISO menu label).
|
||||||
surfaces — `system.nixos.distroName`/`distroId` (flows into
|
Remaining: `isoImage.splashImage`/`grubTheme` art for the ISO boot
|
||||||
`/etc/os-release`, the live ISO's boot-menu label and the installed
|
screen, tuigreet/MOTD text, and the `distroId` question (it changes
|
||||||
system's systemd-boot entries), `isoImage.splashImage`/`grubTheme` for
|
`DEFAULT_HOSTNAME` and upstream `isNixos` checks — needs a test pass;
|
||||||
the ISO boot screen, tuigreet/MOTD text. Caveats: `distroId` also
|
nixos-* CLI names stay regardless)
|
||||||
changes `DEFAULT_HOSTNAME` and some upstream `isNixos` checks, and
|
|
||||||
nixos-* CLI names stay (renaming tooling is not worth the drift)
|
|
||||||
|
|||||||
32
flake.nix
32
flake.nix
@@ -148,6 +148,7 @@
|
|||||||
specialArgs = { inherit username; };
|
specialArgs = { inherit username; };
|
||||||
modules = [
|
modules = [
|
||||||
self.nixosModules.nomarchy
|
self.nixosModules.nomarchy
|
||||||
|
{ nomarchy.system.stateFile = ./theme-state.json; }
|
||||||
./hosts/default/configuration.nix
|
./hosts/default/configuration.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -251,6 +252,20 @@
|
|||||||
({ lib, ... }: {
|
({ lib, ... }: {
|
||||||
nomarchy.system.snapper.enable = true;
|
nomarchy.system.snapper.enable = true;
|
||||||
nomarchy.system.greeter.autoLogin = username;
|
nomarchy.system.greeter.autoLogin = username;
|
||||||
|
# The installer writes these (keyboard-everywhere
|
||||||
|
# incl. the LUKS prompt) — mirror them or the
|
||||||
|
# initrd/vconsole pins don't match an offline
|
||||||
|
# install's rebuild set.
|
||||||
|
console.useXkbConfig = true;
|
||||||
|
boot.initrd.systemd.enable = true;
|
||||||
|
# nixos-generate-config keys microcode off
|
||||||
|
# enableRedistributableFirmware (now on): the
|
||||||
|
# real machine enables exactly one vendor —
|
||||||
|
# pin both, or the offline install builds
|
||||||
|
# amd-ucode/intel-ucode from source (found the
|
||||||
|
# hard way: the 2700s regression hang).
|
||||||
|
hardware.cpu.amd.updateMicrocode = true;
|
||||||
|
hardware.cpu.intel.updateMicrocode = true;
|
||||||
swapDevices = [{ device = "/swap/swapfile"; }];
|
swapDevices = [{ device = "/swap/swapfile"; }];
|
||||||
boot.resumeDevice = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000";
|
boot.resumeDevice = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000";
|
||||||
boot.kernelParams = [ "resume_offset=1" ];
|
boot.kernelParams = [ "resume_offset=1" ];
|
||||||
@@ -298,6 +313,11 @@
|
|||||||
representativeInstall.config.system.build.etc.inputDerivation
|
representativeInstall.config.system.build.etc.inputDerivation
|
||||||
representativeInstall.config.system.build.initialRamdisk.inputDerivation
|
representativeInstall.config.system.build.initialRamdisk.inputDerivation
|
||||||
template.homeConfigurations.${username}.activationPackage.inputDerivation
|
template.homeConfigurations.${username}.activationPackage.inputDerivation
|
||||||
|
# home-files COPIES user-dbus-services instead of
|
||||||
|
# referencing it (same story as the self pin above) —
|
||||||
|
# a custom-username install rebuilds home-files and
|
||||||
|
# needs its direct inputs present.
|
||||||
|
template.homeConfigurations.${username}.config.home-files.inputDerivation
|
||||||
] ++ [
|
] ++ [
|
||||||
# A theme switch re-renders stylix's base16 templates
|
# A theme switch re-renders stylix's base16 templates
|
||||||
# (gtk.css, kvantum, …) on the machine: the renderer and
|
# (gtk.css, kvantum, …) on the machine: the renderer and
|
||||||
@@ -328,6 +348,18 @@
|
|||||||
# tries to BUILD remarshal, whose test closure pulls
|
# tries to BUILD remarshal, whose test closure pulls
|
||||||
# matplotlib/ffmpeg/x265 (the ~1900-drv cascade).
|
# matplotlib/ffmpeg/x265 (the ~1900-drv cascade).
|
||||||
pkgs.remarshal
|
pkgs.remarshal
|
||||||
|
# system-path/initrd-bin-env are buildEnvs rebuilt per
|
||||||
|
# machine; their shared builder.pl is build-time-only
|
||||||
|
# (never in any runtime closure) — an empty env's
|
||||||
|
# inputDerivation retains it.
|
||||||
|
(pkgs.buildEnv { name = "nomarchy-pin-buildenv"; paths = [ ]; }).inputDerivation
|
||||||
|
# /etc/dbus-1 reassembly wants this setup hook.
|
||||||
|
pkgs.findXMLCatalogs
|
||||||
|
# nixos-generate-config keys microcode off
|
||||||
|
# enableRedistributableFirmware (now on): exactly one
|
||||||
|
# vendor per real machine, so pin both ucode cpios.
|
||||||
|
pkgs.microcode-amd
|
||||||
|
pkgs.microcode-intel
|
||||||
|
|
||||||
# …and one representative disko script: its tool closure
|
# …and one representative disko script: its tool closure
|
||||||
# (file, which, wrapper hooks, …) isn't otherwise on the
|
# (file, which, wrapper hooks, …) isn't otherwise on the
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
# Ghostty silently falls back to the wrong font (seen on the
|
# Ghostty silently falls back to the wrong font (seen on the
|
||||||
# Latitude 5410). Normal priority (100) beats the override.
|
# Latitude 5410). Normal priority (100) beats the override.
|
||||||
fonts.fontconfig.enable = true;
|
fonts.fontconfig.enable = true;
|
||||||
|
|
||||||
|
# No boot splash on the install medium: the installer ISO boots its
|
||||||
|
# own initrd path (squashfs), and visibility of boot messages is
|
||||||
|
# worth more than polish here. Installed systems get the splash.
|
||||||
|
nomarchy.system.plymouth.enable = false;
|
||||||
xdg.icons.enable = true;
|
xdg.icons.enable = true;
|
||||||
xdg.mime.enable = true;
|
xdg.mime.enable = true;
|
||||||
xdg.autostart.enable = true;
|
xdg.autostart.enable = true;
|
||||||
@@ -85,6 +90,12 @@
|
|||||||
|
|
||||||
# ── Live-session desktop tweaks ─────────────────────────────────────
|
# ── Live-session desktop tweaks ─────────────────────────────────────
|
||||||
home-manager.users.${username} = {
|
home-manager.users.${username} = {
|
||||||
|
# No idle lock/suspend on the install medium: an offline install
|
||||||
|
# runs 20-30 min unattended, and hypridle would blank the display
|
||||||
|
# then SUSPEND the machine mid-install (it did — the install-hung
|
||||||
|
# regression). Installed systems keep idle management.
|
||||||
|
nomarchy.idle.enable = false;
|
||||||
|
|
||||||
wayland.windowManager.hyprland.settings = {
|
wayland.windowManager.hyprland.settings = {
|
||||||
# QEMU (and some panels) report a tiny "preferred" mode; ask for
|
# QEMU (and some panels) report a tiny "preferred" mode; ask for
|
||||||
# the highest resolution instead.
|
# the highest resolution instead.
|
||||||
|
|||||||
3
lib.nix
3
lib.nix
@@ -65,6 +65,9 @@
|
|||||||
# (`nomarchy-theme-sync apply` → `home-manager switch`) works
|
# (`nomarchy-theme-sync apply` → `home-manager switch`) works
|
||||||
# out of the box — same pinned input as the desktop modules.
|
# out of the box — same pinned input as the desktop modules.
|
||||||
{ environment.systemPackages = [ home-manager.packages.${system}.home-manager ]; }
|
{ environment.systemPackages = [ home-manager.packages.${system}.home-manager ]; }
|
||||||
|
# System-side theme consumers (Plymouth splash background)
|
||||||
|
# read the same JSON the desktop does.
|
||||||
|
{ nomarchy.system.stateFile = src + "/theme-state.json"; }
|
||||||
]
|
]
|
||||||
++ hardwareModules
|
++ hardwareModules
|
||||||
++ [
|
++ [
|
||||||
|
|||||||
@@ -12,8 +12,20 @@
|
|||||||
./waybar.nix
|
./waybar.nix
|
||||||
./ghostty.nix
|
./ghostty.nix
|
||||||
./btop.nix
|
./btop.nix
|
||||||
|
./fuzzel.nix # launcher theming + the nomarchy-menu dispatcher
|
||||||
|
./swaync.nix # notification daemon, themed from the same JSON
|
||||||
|
./idle.nix # hyprlock + hypridle, themed from the same JSON
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Clipboard history (wl-paste watcher); browsed via the SUPER+CTRL+V
|
||||||
|
# menu module.
|
||||||
|
services.cliphist.enable = true;
|
||||||
|
|
||||||
|
# Wifi from the bar: nm-applet lives in waybar's tray (SNI flag via
|
||||||
|
# preferStatusNotifierItems — without it there is no tray icon).
|
||||||
|
services.network-manager-applet.enable = true;
|
||||||
|
xsession.preferStatusNotifierItems = true;
|
||||||
|
|
||||||
home.stateVersion = "26.05";
|
home.stateVersion = "26.05";
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
|
|||||||
171
modules/home/fuzzel.nix
Normal file
171
modules/home/fuzzel.nix
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# Fuzzel — launcher, dmenu renderer for the menu system, themed from
|
||||||
|
# theme-state.json like every other surface. Also home of nomarchy-menu,
|
||||||
|
# the dispatcher script all menu modules grow out of.
|
||||||
|
#
|
||||||
|
# Per-theme identity: themes/<slug>/fuzzel.ini is a whole-swap (like
|
||||||
|
# waybar.css) — it replaces the generated config entirely, probed at
|
||||||
|
# eval time.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nomarchy;
|
||||||
|
t = cfg.theme;
|
||||||
|
c = t.colors;
|
||||||
|
|
||||||
|
# Per-theme override probe (same convention as waybar.nix).
|
||||||
|
iniOverride = cfg.themesDir + "/${t.slug}/fuzzel.ini";
|
||||||
|
hasIniOverride = builtins.pathExists iniOverride;
|
||||||
|
|
||||||
|
# fuzzel.ini colors are rrggbbaa, no leading #.
|
||||||
|
hexa = color: alpha: "${lib.removePrefix "#" color}${alpha}";
|
||||||
|
|
||||||
|
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
||||||
|
# Nomarchy menu dispatcher — thin presentation layer over
|
||||||
|
# `fuzzel --dmenu`; actions delegate to nomarchy-theme-sync,
|
||||||
|
# systemctl, hyprctl and friends. Icons are nf-md glyphs (any
|
||||||
|
# shipped Nerd Font carries them). `nomarchy-menu` with no
|
||||||
|
# argument shows the module picker.
|
||||||
|
|
||||||
|
urlencode() {
|
||||||
|
local s="$1" out="" ch
|
||||||
|
for ((i = 0; i < ''${#s}; i++)); do
|
||||||
|
ch=''${s:i:1}
|
||||||
|
case "$ch" in
|
||||||
|
[a-zA-Z0-9.~_-]) out+="$ch" ;;
|
||||||
|
' ') out+="+" ;;
|
||||||
|
*) printf -v ch '%%%02X' "'$ch"; out+="$ch" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "''${1:-}" in
|
||||||
|
power)
|
||||||
|
choice=$(printf '%s\n' \
|
||||||
|
" Lock" \
|
||||||
|
" Logout" \
|
||||||
|
" Suspend" \
|
||||||
|
" Hibernate" \
|
||||||
|
" Reboot" \
|
||||||
|
" Shutdown" \
|
||||||
|
| fuzzel --dmenu --prompt "power " --lines 6 --width 24) || exit 0
|
||||||
|
case "$choice" in
|
||||||
|
*Lock) loginctl lock-session ;;
|
||||||
|
*Logout) hyprctl dispatch exit ;;
|
||||||
|
*Suspend) systemctl suspend ;;
|
||||||
|
*Hibernate) systemctl hibernate ;;
|
||||||
|
*Reboot) systemctl reboot ;;
|
||||||
|
*Shutdown) systemctl poweroff ;;
|
||||||
|
esac ;;
|
||||||
|
|
||||||
|
theme)
|
||||||
|
choice=$(nomarchy-theme-sync list \
|
||||||
|
| fuzzel --dmenu --prompt "theme ") || exit 0
|
||||||
|
[ -n "$choice" ] && exec nomarchy-theme-sync apply "$choice" ;;
|
||||||
|
|
||||||
|
clipboard)
|
||||||
|
sel=$(cliphist list | fuzzel --dmenu --prompt "clip " --width 60) || exit 0
|
||||||
|
printf '%s' "$sel" | cliphist decode | wl-copy ;;
|
||||||
|
|
||||||
|
calc)
|
||||||
|
expr=$(fuzzel --prompt-only "= ") || exit 0
|
||||||
|
[ -n "$expr" ] || exit 0
|
||||||
|
result=$(qalc -t -- "$expr" 2>&1 | tail -n 1)
|
||||||
|
choice=$(printf '%s\n' " Copy result" " New calculation" \
|
||||||
|
| fuzzel --dmenu --lines 2 --width 40 \
|
||||||
|
--prompt "= " --mesg "$expr = $result") || exit 0
|
||||||
|
case "$choice" in
|
||||||
|
*Copy*) printf '%s' "$result" | wl-copy ;;
|
||||||
|
*New*) exec "$0" calc ;;
|
||||||
|
esac ;;
|
||||||
|
|
||||||
|
files)
|
||||||
|
sel=$(fd . "$HOME" --type f --hidden --exclude .git --exclude .cache 2>/dev/null \
|
||||||
|
| head -n 50000 \
|
||||||
|
| sed "s|^$HOME/||" \
|
||||||
|
| fuzzel --dmenu --prompt "file " --width 60) || exit 0
|
||||||
|
[ -n "$sel" ] && exec xdg-open "$HOME/$sel" ;;
|
||||||
|
|
||||||
|
web)
|
||||||
|
q=$(fuzzel --prompt-only "search ") || exit 0
|
||||||
|
[ -n "$q" ] || exit 0
|
||||||
|
exec xdg-open "https://duckduckgo.com/?q=$(urlencode "$q")" ;;
|
||||||
|
|
||||||
|
"")
|
||||||
|
choice=$(printf '%s\n' \
|
||||||
|
" Apps" \
|
||||||
|
" Theme" \
|
||||||
|
" Clipboard" \
|
||||||
|
" Calculator" \
|
||||||
|
" Files" \
|
||||||
|
" Web search" \
|
||||||
|
" Power" \
|
||||||
|
| fuzzel --dmenu --prompt "menu " --lines 7 --width 24) || exit 0
|
||||||
|
case "$choice" in
|
||||||
|
*Apps*) exec fuzzel ;;
|
||||||
|
*Theme*) exec "$0" theme ;;
|
||||||
|
*Clipboard*) exec "$0" clipboard ;;
|
||||||
|
*Calc*) exec "$0" calc ;;
|
||||||
|
*Files*) exec "$0" files ;;
|
||||||
|
*Web*) exec "$0" web ;;
|
||||||
|
*Power*) exec "$0" power ;;
|
||||||
|
esac ;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "usage: nomarchy-menu [power|theme|clipboard|calc|files|web]" >&2
|
||||||
|
exit 64 ;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkIf cfg.fuzzel.enable {
|
||||||
|
home.packages = [
|
||||||
|
nomarchy-menu
|
||||||
|
pkgs.libqalculate # qalc, the calc module's engine
|
||||||
|
pkgs.fd # files module
|
||||||
|
pkgs.xdg-utils # xdg-open for files/web
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.fuzzel = {
|
||||||
|
enable = true;
|
||||||
|
# Whole-swap themes bring their own fuzzel.ini; otherwise the
|
||||||
|
# config is generated from the palette.
|
||||||
|
settings = lib.mkIf (!hasIniOverride) {
|
||||||
|
main = {
|
||||||
|
# UI font first; the mono Nerd Font follows so menu icons
|
||||||
|
# (nf-md glyphs) resolve — fcft falls back per glyph.
|
||||||
|
font = "${t.fonts.ui}:size=${toString (t.fonts.size + 1)}, ${t.fonts.mono}:size=${toString (t.fonts.size + 1)}";
|
||||||
|
terminal = cfg.terminal;
|
||||||
|
layer = "overlay";
|
||||||
|
lines = 12;
|
||||||
|
width = 40;
|
||||||
|
horizontal-pad = 24;
|
||||||
|
vertical-pad = 16;
|
||||||
|
inner-pad = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
colors = {
|
||||||
|
background = hexa c.base "f2";
|
||||||
|
text = hexa c.text "ff";
|
||||||
|
prompt = hexa c.subtext "ff";
|
||||||
|
placeholder = hexa c.muted "ff";
|
||||||
|
input = hexa c.text "ff";
|
||||||
|
match = hexa c.accent "ff";
|
||||||
|
selection = hexa c.surface "ff";
|
||||||
|
selection-text = hexa c.text "ff";
|
||||||
|
selection-match = hexa c.accent "ff";
|
||||||
|
border = hexa c.accent "ee";
|
||||||
|
};
|
||||||
|
|
||||||
|
border = {
|
||||||
|
width = t.ui.borderSize;
|
||||||
|
radius = t.ui.rounding;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
xdg.configFile."fuzzel/fuzzel.ini" = lib.mkIf hasIniOverride {
|
||||||
|
source = iniOverride;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -90,7 +90,8 @@ in
|
|||||||
|
|
||||||
# ── Behaviour ──────────────────────────────────────────────────
|
# ── Behaviour ──────────────────────────────────────────────────
|
||||||
input = {
|
input = {
|
||||||
kb_layout = "us";
|
kb_layout = config.nomarchy.keyboard.layout;
|
||||||
|
kb_variant = config.nomarchy.keyboard.variant;
|
||||||
follow_mouse = 1;
|
follow_mouse = 1;
|
||||||
touchpad.natural_scroll = true;
|
touchpad.natural_scroll = true;
|
||||||
};
|
};
|
||||||
@@ -120,12 +121,21 @@ in
|
|||||||
"$mod, V, togglefloating"
|
"$mod, V, togglefloating"
|
||||||
"$mod SHIFT, E, exit"
|
"$mod SHIFT, E, exit"
|
||||||
|
|
||||||
# Theme picker: fuzzel menu over the presets; apply writes the
|
# Theme picker (menu dispatcher): apply writes the state and
|
||||||
# state and runs home-manager switch (progress via notify-send).
|
# runs home-manager switch (progress via notify-send).
|
||||||
"$mod, T, exec, nomarchy-theme-sync apply \"$(nomarchy-theme-sync list | fuzzel --dmenu --prompt 'theme> ')\""
|
"$mod, T, exec, nomarchy-menu theme"
|
||||||
# Cycle the current theme's wallpapers (instant, no rebuild).
|
# Cycle the current theme's wallpapers (instant, no rebuild).
|
||||||
"$mod SHIFT, T, exec, nomarchy-theme-sync bg next"
|
"$mod SHIFT, T, exec, nomarchy-theme-sync bg next"
|
||||||
|
|
||||||
|
# Power menu (fuzzel dmenu via the nomarchy-menu dispatcher).
|
||||||
|
"$mod, Escape, exec, nomarchy-menu power"
|
||||||
|
|
||||||
|
# Notification centre (swaync).
|
||||||
|
"$mod, N, exec, swaync-client -t"
|
||||||
|
|
||||||
|
# Clipboard history (cliphist via the menu dispatcher).
|
||||||
|
"$mod CTRL, V, exec, nomarchy-menu clipboard"
|
||||||
|
|
||||||
# Focus
|
# Focus
|
||||||
"$mod, H, movefocus, l"
|
"$mod, H, movefocus, l"
|
||||||
"$mod, L, movefocus, r"
|
"$mod, L, movefocus, r"
|
||||||
|
|||||||
72
modules/home/idle.nix
Normal file
72
modules/home/idle.nix
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# hyprlock + hypridle — screen locking and idle management, themed from
|
||||||
|
# theme-state.json. One concern, one file: hypridle drives WHEN (idle
|
||||||
|
# lock, display off, suspend, lock-before-sleep), hyprlock is the
|
||||||
|
# themed lock screen itself (also behind the power menu's Lock entry).
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nomarchy;
|
||||||
|
t = cfg.theme;
|
||||||
|
c = t.colors;
|
||||||
|
inherit (config.nomarchy.lib) rgb;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkIf cfg.idle.enable {
|
||||||
|
programs.hyprlock = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
general.hide_cursor = true;
|
||||||
|
|
||||||
|
background = [{
|
||||||
|
monitor = "";
|
||||||
|
color = rgb c.base;
|
||||||
|
}];
|
||||||
|
|
||||||
|
input-field = [{
|
||||||
|
monitor = "";
|
||||||
|
size = "300, 50";
|
||||||
|
outline_thickness = t.ui.borderSize;
|
||||||
|
dots_size = 0.25;
|
||||||
|
outer_color = rgb c.accent;
|
||||||
|
inner_color = rgb c.surface;
|
||||||
|
font_color = rgb c.text;
|
||||||
|
check_color = rgb c.warn;
|
||||||
|
fail_color = rgb c.bad;
|
||||||
|
rounding = t.ui.rounding;
|
||||||
|
placeholder_text = "<i>password…</i>";
|
||||||
|
}];
|
||||||
|
|
||||||
|
label = [{
|
||||||
|
monitor = "";
|
||||||
|
text = "$TIME";
|
||||||
|
color = rgb c.text;
|
||||||
|
font_size = 64;
|
||||||
|
font_family = t.fonts.ui;
|
||||||
|
position = "0, 120";
|
||||||
|
halign = "center";
|
||||||
|
valign = "center";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.hypridle = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
general = {
|
||||||
|
lock_cmd = "pidof hyprlock || hyprlock";
|
||||||
|
before_sleep_cmd = "loginctl lock-session";
|
||||||
|
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||||
|
};
|
||||||
|
listener = [
|
||||||
|
{ timeout = 300; on-timeout = "loginctl lock-session"; }
|
||||||
|
{
|
||||||
|
timeout = 600;
|
||||||
|
on-timeout = "hyprctl dispatch dpms off";
|
||||||
|
on-resume = "hyprctl dispatch dpms on";
|
||||||
|
}
|
||||||
|
{ timeout = 1800; on-timeout = "systemctl suspend"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,6 +23,25 @@
|
|||||||
description = "Terminal emulator command, used by keybinds and $TERMINAL.";
|
description = "Terminal emulator command, used by keybinds and $TERMINAL.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
keyboard.layout = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "us";
|
||||||
|
example = "de";
|
||||||
|
description = ''
|
||||||
|
XKB layout for the Hyprland session. The console (and the LUKS
|
||||||
|
passphrase prompt) take theirs from the system side — the
|
||||||
|
installer writes services.xserver.xkb + console.useXkbConfig
|
||||||
|
into system.nix with the same value.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
keyboard.variant = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
example = "nodeadkeys";
|
||||||
|
description = "XKB variant for the Hyprland session.";
|
||||||
|
};
|
||||||
|
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
default = pkgs.nomarchy-theme-sync;
|
default = pkgs.nomarchy-theme-sync;
|
||||||
@@ -44,6 +63,9 @@
|
|||||||
# ── Component toggles ──────────────────────────────────────────
|
# ── Component toggles ──────────────────────────────────────────
|
||||||
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
||||||
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar configuration" // { default = true; };
|
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar configuration" // { default = true; };
|
||||||
|
fuzzel.enable = lib.mkEnableOption "Nomarchy's themed fuzzel + the nomarchy-menu dispatcher (power menu)" // { default = true; };
|
||||||
|
swaync.enable = lib.mkEnableOption "swaync notifications, themed from the state file" // { default = true; };
|
||||||
|
idle.enable = lib.mkEnableOption "hyprlock + hypridle (idle lock, display off, suspend)" // { default = true; };
|
||||||
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
||||||
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
|
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
|
||||||
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
|
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
|
||||||
|
|||||||
92
modules/home/swaync.nix
Normal file
92
modules/home/swaync.nix
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# swaync — notification daemon + control centre, themed from
|
||||||
|
# theme-state.json. Until this shipped, nothing rendered notify-send at
|
||||||
|
# all: the theme-switch progress toasts, the CLI's font warnings and the
|
||||||
|
# live ISO's welcome message were all invisible.
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nomarchy;
|
||||||
|
t = cfg.theme;
|
||||||
|
c = t.colors;
|
||||||
|
r = toString t.ui.rounding;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkIf cfg.swaync.enable {
|
||||||
|
services.swaync = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
positionX = "right";
|
||||||
|
positionY = "top";
|
||||||
|
control-center-margin-top = t.ui.gapsOut;
|
||||||
|
control-center-margin-right = t.ui.gapsOut;
|
||||||
|
control-center-width = 420;
|
||||||
|
notification-window-width = 400;
|
||||||
|
notification-icon-size = 48;
|
||||||
|
timeout = 6;
|
||||||
|
timeout-low = 3;
|
||||||
|
timeout-critical = 0; # critical stays until dismissed
|
||||||
|
};
|
||||||
|
|
||||||
|
style = ''
|
||||||
|
/* Palette baked from theme-state.json */
|
||||||
|
@define-color base ${c.base};
|
||||||
|
@define-color surface ${c.surface};
|
||||||
|
@define-color text ${c.text};
|
||||||
|
@define-color subtext ${c.subtext};
|
||||||
|
@define-color accent ${c.accent};
|
||||||
|
@define-color bad ${c.bad};
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
background: alpha(@base, 0.95);
|
||||||
|
border: ${toString t.ui.borderSize}px solid alpha(@accent, 0.4);
|
||||||
|
border-radius: ${r}px;
|
||||||
|
color: @text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content .summary {
|
||||||
|
color: @text;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content .body {
|
||||||
|
color: @subtext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.critical {
|
||||||
|
border-color: @bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center {
|
||||||
|
background: alpha(@base, 0.95);
|
||||||
|
border: ${toString t.ui.borderSize}px solid alpha(@accent, 0.4);
|
||||||
|
border-radius: ${r}px;
|
||||||
|
color: @text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-row:focus,
|
||||||
|
.control-center .notification-row:hover {
|
||||||
|
background: alpha(@surface, 0.6);
|
||||||
|
border-radius: ${r}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title {
|
||||||
|
color: @text;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title > button {
|
||||||
|
background: @surface;
|
||||||
|
color: @text;
|
||||||
|
border: none;
|
||||||
|
border-radius: ${r}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-title > button:hover {
|
||||||
|
background: @accent;
|
||||||
|
color: @base;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ let
|
|||||||
format = "{icon} {volume}%";
|
format = "{icon} {volume}%";
|
||||||
format-muted = "";
|
format-muted = "";
|
||||||
format-icons.default = [ "" "" "" ];
|
format-icons.default = [ "" "" "" ];
|
||||||
on-click = "pamixer -t";
|
on-click = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
|
||||||
};
|
};
|
||||||
|
|
||||||
network = {
|
network = {
|
||||||
@@ -68,6 +68,9 @@ let
|
|||||||
format-ethernet = "";
|
format-ethernet = "";
|
||||||
format-disconnected = "";
|
format-disconnected = "";
|
||||||
tooltip-format = "{ipaddr} via {gwaddr}";
|
tooltip-format = "{ipaddr} via {gwaddr}";
|
||||||
|
# nm-applet sits in the tray for the GUI path; this is the
|
||||||
|
# keyboard-friendly one.
|
||||||
|
on-click = "${config.nomarchy.terminal} -e nmtui";
|
||||||
};
|
};
|
||||||
|
|
||||||
cpu.format = " {usage}%";
|
cpu.format = " {usage}%";
|
||||||
|
|||||||
@@ -11,9 +11,15 @@ let
|
|||||||
cfg = config.nomarchy.system;
|
cfg = config.nomarchy.system;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./options.nix ];
|
imports = [ ./options.nix ./plymouth.nix ];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
# The safe half of distro branding: distroName flows into
|
||||||
|
# /etc/os-release PRETTY_NAME, systemd-boot entry titles and the
|
||||||
|
# ISO boot-menu label. distroId stays "nixos" on purpose — it feeds
|
||||||
|
# DEFAULT_HOSTNAME and upstream isNixos checks (see roadmap).
|
||||||
|
system.nixos.distroName = lib.mkDefault "Nomarchy";
|
||||||
|
|
||||||
# Unfree allowed distro-wide: pragmatic-desktop territory (claude-code
|
# Unfree allowed distro-wide: pragmatic-desktop territory (claude-code
|
||||||
# for the menu's ask-Claude module, vendor drivers, …). The custom
|
# for the menu's ask-Claude module, vendor drivers, …). The custom
|
||||||
# nixpkgs-config type can't carry a nested mkDefault; disagree with
|
# nixpkgs-config type can't carry a nested mkDefault; disagree with
|
||||||
@@ -114,6 +120,9 @@ in
|
|||||||
inter
|
inter
|
||||||
noto-fonts
|
noto-fonts
|
||||||
noto-fonts-color-emoji
|
noto-fonts-color-emoji
|
||||||
|
# The legacy-ported waybar identities (summer-day/night) use
|
||||||
|
# FontAwesome codepoints in their layouts and list it in css.
|
||||||
|
font-awesome
|
||||||
];
|
];
|
||||||
fontconfig.defaultFonts = {
|
fontconfig.defaultFonts = {
|
||||||
monospace = lib.mkDefault [ "JetBrainsMono Nerd Font" ];
|
monospace = lib.mkDefault [ "JetBrainsMono Nerd Font" ];
|
||||||
@@ -125,6 +134,31 @@ in
|
|||||||
# ── Essential packages ───────────────────────────────────────────
|
# ── Essential packages ───────────────────────────────────────────
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
nomarchy-theme-sync # provided by overlays.default
|
nomarchy-theme-sync # provided by overlays.default
|
||||||
|
|
||||||
|
# Friendly wrappers for the two rebuild paths (README §3). Run as
|
||||||
|
# your user: `nix flake update` must NOT run as root (libgit2
|
||||||
|
# refuses the user-owned flake repo) — sudo happens inside, only
|
||||||
|
# for the system switch.
|
||||||
|
(pkgs.writeShellScriptBin "sys-update" ''
|
||||||
|
set -e
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
echo "sys-update: run as your normal user (it sudos the rebuild itself)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}"
|
||||||
|
echo "sys-update: updating flake inputs in $flake"
|
||||||
|
nix flake update --flake "$flake"
|
||||||
|
if command -v nixos-rebuild-snap >/dev/null 2>&1; then
|
||||||
|
sudo nixos-rebuild-snap "$@" # BTRFS snapshot first
|
||||||
|
else
|
||||||
|
sudo nixos-rebuild switch --flake "$flake#default" "$@"
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
(pkgs.writeShellScriptBin "home-update" ''
|
||||||
|
set -e
|
||||||
|
exec home-manager switch --flake "''${NOMARCHY_PATH:-$HOME/.nomarchy}" "$@"
|
||||||
|
'')
|
||||||
|
|
||||||
git
|
git
|
||||||
vim
|
vim
|
||||||
wget
|
wget
|
||||||
@@ -152,6 +186,9 @@ in
|
|||||||
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
||||||
'');
|
'');
|
||||||
|
|
||||||
|
# Don't let boot entries fill the ESP over the years.
|
||||||
|
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
|
||||||
|
|
||||||
# ── Nix itself ───────────────────────────────────────────────────
|
# ── Nix itself ───────────────────────────────────────────────────
|
||||||
nix = {
|
nix = {
|
||||||
settings = {
|
settings = {
|
||||||
|
|||||||
@@ -21,6 +21,22 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
plymouth.enable = lib.mkEnableOption ''
|
||||||
|
the Nomarchy Plymouth boot splash (logo + progress + LUKS prompt),
|
||||||
|
background-tinted from theme-state.json via nomarchy.system.stateFile.
|
||||||
|
Recolors on system rebuilds — theme switches don't touch the initrd'' // { default = true; };
|
||||||
|
|
||||||
|
stateFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
example = lib.literalExpression "./theme-state.json";
|
||||||
|
description = ''
|
||||||
|
theme-state.json for the system-side consumers (currently the
|
||||||
|
Plymouth splash background). lib.mkFlake wires it automatically
|
||||||
|
from your flake; null falls back to the Tokyo Night base color.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
audio.enable = lib.mkEnableOption "the Pipewire audio stack" // { default = true; };
|
audio.enable = lib.mkEnableOption "the Pipewire audio stack" // { default = true; };
|
||||||
bluetooth.enable = lib.mkEnableOption "Bluetooth support with blueman" // { default = true; };
|
bluetooth.enable = lib.mkEnableOption "Bluetooth support with blueman" // { default = true; };
|
||||||
|
|
||||||
|
|||||||
87
modules/nixos/plymouth.nix
Normal file
87
modules/nixos/plymouth.nix
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Plymouth boot splash — Nomarchy-branded (ported from the legacy
|
||||||
|
# iteration), background tinted from the same theme-state.json that
|
||||||
|
# drives the desktop (nomarchy.system.stateFile, wired automatically by
|
||||||
|
# lib.mkFlake). One caveat by design: theme switches are Home
|
||||||
|
# Manager-only and never touch the initrd, so the splash follows the
|
||||||
|
# theme as of the last SYSTEM rebuild (`sys-update`), not the last
|
||||||
|
# `nomarchy-theme-sync apply`.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nomarchy.system;
|
||||||
|
|
||||||
|
state =
|
||||||
|
if cfg.stateFile != null
|
||||||
|
then builtins.fromJSON (builtins.readFile cfg.stateFile)
|
||||||
|
else { };
|
||||||
|
base = lib.removePrefix "#" ((state.colors or { }).base or "#1a1b26");
|
||||||
|
|
||||||
|
# Plymouth's Window.SetBackgroundTopColor takes three floats in
|
||||||
|
# 0.0–1.0; the .plymouth metadata's ConsoleLogBackgroundColor takes a
|
||||||
|
# 0xRRGGBB hex. Nix has no float math: multiply, integer-divide, pad.
|
||||||
|
byteToFloat = n:
|
||||||
|
let
|
||||||
|
thousandths = (n * 1000) / 255;
|
||||||
|
s = toString thousandths;
|
||||||
|
padded =
|
||||||
|
if lib.stringLength s == 1 then "00${s}"
|
||||||
|
else if lib.stringLength s == 2 then "0${s}"
|
||||||
|
else s;
|
||||||
|
in "0.${padded}";
|
||||||
|
channel = off: byteToFloat (lib.fromHexString (lib.substring off 2 base));
|
||||||
|
|
||||||
|
nomarchy-plymouth = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "nomarchy-plymouth";
|
||||||
|
version = "1.0";
|
||||||
|
|
||||||
|
src = ./plymouth;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/share/plymouth/themes/nomarchy
|
||||||
|
cp * $out/share/plymouth/themes/nomarchy/
|
||||||
|
|
||||||
|
# Point the .plymouth metadata into the store
|
||||||
|
sed -i "s|/usr/share/plymouth/themes/nomarchy|$out/share/plymouth/themes/nomarchy|g" \
|
||||||
|
$out/share/plymouth/themes/nomarchy/nomarchy.plymouth
|
||||||
|
|
||||||
|
# Bake the theme's base color: RGB floats for the script's
|
||||||
|
# Window.SetBackground* calls, 0xRRGGBB for ConsoleLogBackground.
|
||||||
|
sed -i \
|
||||||
|
-e 's|@BG_R@|${channel 0}|g' \
|
||||||
|
-e 's|@BG_G@|${channel 2}|g' \
|
||||||
|
-e 's|@BG_B@|${channel 4}|g' \
|
||||||
|
$out/share/plymouth/themes/nomarchy/nomarchy.script
|
||||||
|
sed -i 's|@BG_HEX@|${base}|g' \
|
||||||
|
$out/share/plymouth/themes/nomarchy/nomarchy.plymouth
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = lib.mkIf cfg.plymouth.enable {
|
||||||
|
# Plymouth wants the systemd initrd (also what applies the keyboard
|
||||||
|
# layout to the LUKS prompt) and a quiet console around it.
|
||||||
|
boot.initrd.systemd.enable = lib.mkDefault true;
|
||||||
|
boot.initrd.verbose = lib.mkDefault false;
|
||||||
|
console.earlySetup = lib.mkDefault true;
|
||||||
|
boot.consoleLogLevel = lib.mkDefault 0;
|
||||||
|
|
||||||
|
boot.plymouth = {
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
themePackages = lib.mkDefault [ nomarchy-plymouth ];
|
||||||
|
theme = lib.mkDefault "nomarchy";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Not mkDefault: kernelParams is a list other modules add to at
|
||||||
|
# normal priority — a mkDefault def would be dropped entirely,
|
||||||
|
# losing the quiet/splash boot. These merge with the rest.
|
||||||
|
boot.kernelParams = [
|
||||||
|
"quiet"
|
||||||
|
"splash"
|
||||||
|
"loglevel=3"
|
||||||
|
"rd.systemd.show_status=false"
|
||||||
|
"rd.udev.log_level=3"
|
||||||
|
"udev.log_priority=3"
|
||||||
|
"boot.shell_on_fail"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
modules/nixos/plymouth/bullet.png
Normal file
BIN
modules/nixos/plymouth/bullet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 293 B |
BIN
modules/nixos/plymouth/entry.png
Normal file
BIN
modules/nixos/plymouth/entry.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 694 B |
BIN
modules/nixos/plymouth/lock.png
Normal file
BIN
modules/nixos/plymouth/lock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
modules/nixos/plymouth/logo.png
Normal file
BIN
modules/nixos/plymouth/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
11
modules/nixos/plymouth/nomarchy.plymouth
Normal file
11
modules/nixos/plymouth/nomarchy.plymouth
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Plymouth Theme]
|
||||||
|
Name=Nomarchy
|
||||||
|
Description=Nomarchy splash screen.
|
||||||
|
ModuleName=script
|
||||||
|
|
||||||
|
[script]
|
||||||
|
ImageDir=/usr/share/plymouth/themes/nomarchy
|
||||||
|
ScriptFile=/usr/share/plymouth/themes/nomarchy/nomarchy.script
|
||||||
|
ConsoleLogBackgroundColor=0x@BG_HEX@
|
||||||
|
MonospaceFont=Cantarell 11
|
||||||
|
Font=Cantarell 11
|
||||||
271
modules/nixos/plymouth/nomarchy.script
Normal file
271
modules/nixos/plymouth/nomarchy.script
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
# Nomarchy Plymouth Theme Script
|
||||||
|
|
||||||
|
Window.SetBackgroundTopColor(@BG_R@, @BG_G@, @BG_B@);
|
||||||
|
Window.SetBackgroundBottomColor(@BG_R@, @BG_G@, @BG_B@);
|
||||||
|
|
||||||
|
logo.image = Image("logo.png");
|
||||||
|
|
||||||
|
# Calculate scale factor to make logo ~15% of screen height
|
||||||
|
logo_scale_factor = (Window.GetHeight() * 0.15) / logo.image.GetHeight();
|
||||||
|
logo_width = logo.image.GetWidth() * logo_scale_factor;
|
||||||
|
logo_height = logo.image.GetHeight() * logo_scale_factor;
|
||||||
|
logo.image = logo.image.Scale(logo_width, logo_height);
|
||||||
|
|
||||||
|
logo.sprite = Sprite(logo.image);
|
||||||
|
logo.sprite.SetX (Window.GetWidth() / 2 - logo.image.GetWidth() / 2);
|
||||||
|
logo.sprite.SetY (Window.GetHeight() / 2 - logo.image.GetHeight() / 2);
|
||||||
|
logo.sprite.SetOpacity (1);
|
||||||
|
|
||||||
|
# Use these to adjust the progress bar timing
|
||||||
|
global.fake_progress_limit = 0.7; # Target percentage for fake progress (0.0 to 1.0)
|
||||||
|
global.fake_progress_duration = 15.0; # Duration in seconds to reach limit
|
||||||
|
|
||||||
|
# Progress bar animation variables
|
||||||
|
global.fake_progress = 0.0;
|
||||||
|
global.real_progress = 0.0;
|
||||||
|
global.fake_progress_active = 0; # 0 / 1 boolean
|
||||||
|
global.animation_frame = 0;
|
||||||
|
global.fake_progress_start_time = 0; # Track when fake progress started
|
||||||
|
global.password_shown = 0; # Track if password dialog has been shown
|
||||||
|
global.max_progress = 0.0; # Track the maximum progress reached to prevent backwards movement
|
||||||
|
|
||||||
|
fun refresh_callback ()
|
||||||
|
{
|
||||||
|
global.animation_frame++;
|
||||||
|
|
||||||
|
# Animate fake progress to limit over time with easing
|
||||||
|
if (global.fake_progress_active == 1)
|
||||||
|
{
|
||||||
|
# Calculate elapsed time since start
|
||||||
|
elapsed_time = global.animation_frame / 50.0; # Convert frames to seconds (50 FPS)
|
||||||
|
|
||||||
|
# Calculate linear progress ratio (0 to 1) based on time
|
||||||
|
time_ratio = elapsed_time / global.fake_progress_duration;
|
||||||
|
if (time_ratio > 1.0)
|
||||||
|
time_ratio = 1.0;
|
||||||
|
|
||||||
|
# Apply easing curve: ease-out quadratic
|
||||||
|
# Formula: 1 - (1 - x)^2
|
||||||
|
eased_ratio = 1 - ((1 - time_ratio) * (1 - time_ratio));
|
||||||
|
|
||||||
|
# Calculate fake progress based on eased ratio
|
||||||
|
global.fake_progress = eased_ratio * global.fake_progress_limit;
|
||||||
|
|
||||||
|
# Update progress bar with fake progress
|
||||||
|
update_progress_bar(global.fake_progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Plymouth.SetRefreshFunction (refresh_callback);
|
||||||
|
|
||||||
|
#----------------------------------------- Helper Functions --------------------------------
|
||||||
|
|
||||||
|
fun update_progress_bar(progress)
|
||||||
|
{
|
||||||
|
# Only update if progress is moving forward
|
||||||
|
if (progress > global.max_progress)
|
||||||
|
{
|
||||||
|
global.max_progress = progress;
|
||||||
|
width = Math.Int(progress_bar.original_image.GetWidth() * progress);
|
||||||
|
if (width < 1) width = 1; # Ensure minimum width of 1 pixel
|
||||||
|
|
||||||
|
progress_bar.image = progress_bar.original_image.Scale(width, progress_bar.original_image.GetHeight());
|
||||||
|
progress_bar.sprite.SetImage(progress_bar.image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show_progress_bar()
|
||||||
|
{
|
||||||
|
progress_box.sprite.SetOpacity(1);
|
||||||
|
progress_bar.sprite.SetOpacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide_progress_bar()
|
||||||
|
{
|
||||||
|
progress_box.sprite.SetOpacity(0);
|
||||||
|
progress_bar.sprite.SetOpacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show_password_dialog()
|
||||||
|
{
|
||||||
|
lock.sprite.SetOpacity(1);
|
||||||
|
entry.sprite.SetOpacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide_password_dialog()
|
||||||
|
{
|
||||||
|
lock.sprite.SetOpacity(0);
|
||||||
|
entry.sprite.SetOpacity(0);
|
||||||
|
for (index = 0; bullet.sprites[index]; index++)
|
||||||
|
bullet.sprites[index].SetOpacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun start_fake_progress()
|
||||||
|
{
|
||||||
|
# Don't reset if we already have progress
|
||||||
|
if (global.max_progress == 0.0)
|
||||||
|
{
|
||||||
|
global.fake_progress = 0.0;
|
||||||
|
global.real_progress = 0.0;
|
||||||
|
update_progress_bar(0.0);
|
||||||
|
}
|
||||||
|
global.fake_progress_active = 1;
|
||||||
|
global.animation_frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop_fake_progress()
|
||||||
|
{
|
||||||
|
global.fake_progress_active = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#----------------------------------------- Dialogue --------------------------------
|
||||||
|
|
||||||
|
lock.image = Image("lock.png");
|
||||||
|
entry.image = Image("entry.png");
|
||||||
|
bullet.image = Image("bullet.png");
|
||||||
|
|
||||||
|
entry.sprite = Sprite(entry.image);
|
||||||
|
entry.x = Window.GetWidth()/2 - entry.image.GetWidth() / 2;
|
||||||
|
entry.y = logo.sprite.GetY() + logo.image.GetHeight() + 40;
|
||||||
|
entry.sprite.SetPosition(entry.x, entry.y, 10001);
|
||||||
|
entry.sprite.SetOpacity(0);
|
||||||
|
|
||||||
|
# Scale lock to be slightly shorter than entry field height
|
||||||
|
# Original lock is 84x96, entry height determines scale
|
||||||
|
lock_height = entry.image.GetHeight() * 0.8;
|
||||||
|
lock_scale = lock_height / 96;
|
||||||
|
lock_width = 84 * lock_scale;
|
||||||
|
|
||||||
|
scaled_lock = lock.image.Scale(lock_width, lock_height);
|
||||||
|
lock.sprite = Sprite(scaled_lock);
|
||||||
|
lock.x = entry.x - lock_width - 15;
|
||||||
|
lock.y = entry.y + entry.image.GetHeight()/2 - lock_height/2;
|
||||||
|
lock.sprite.SetPosition(lock.x, lock.y, 10001);
|
||||||
|
lock.sprite.SetOpacity(0);
|
||||||
|
|
||||||
|
# Bullet array
|
||||||
|
bullet.sprites = [];
|
||||||
|
|
||||||
|
fun display_normal_callback ()
|
||||||
|
{
|
||||||
|
hide_password_dialog();
|
||||||
|
|
||||||
|
# Get current mode
|
||||||
|
mode = Plymouth.GetMode();
|
||||||
|
|
||||||
|
# Only show progress bar for boot and resume modes
|
||||||
|
if (mode == "boot" || mode == "resume")
|
||||||
|
{
|
||||||
|
show_progress_bar();
|
||||||
|
start_fake_progress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun display_password_callback (prompt, bullets)
|
||||||
|
{
|
||||||
|
global.password_shown = 1; # Mark that password dialog has been shown
|
||||||
|
|
||||||
|
# Reset progress when password dialog appears
|
||||||
|
stop_fake_progress();
|
||||||
|
hide_progress_bar();
|
||||||
|
global.max_progress = 0.0;
|
||||||
|
global.fake_progress = 0.0;
|
||||||
|
global.real_progress = 0.0;
|
||||||
|
show_password_dialog();
|
||||||
|
|
||||||
|
# Clear all bullets first
|
||||||
|
for (index = 0; bullet.sprites[index]; index++)
|
||||||
|
bullet.sprites[index].SetOpacity(0);
|
||||||
|
|
||||||
|
# Create and show bullets for current password (max 21)
|
||||||
|
max_bullets = 21;
|
||||||
|
bullets_to_show = bullets;
|
||||||
|
if (bullets_to_show > max_bullets)
|
||||||
|
bullets_to_show = max_bullets;
|
||||||
|
|
||||||
|
for (index = 0; index < bullets_to_show; index++)
|
||||||
|
{
|
||||||
|
if (!bullet.sprites[index])
|
||||||
|
{
|
||||||
|
# Scale bullet image to 7x7 pixels
|
||||||
|
scaled_bullet = bullet.image.Scale(7, 7);
|
||||||
|
bullet.sprites[index] = Sprite(scaled_bullet);
|
||||||
|
bullet.x = entry.x + 20 + index * (7 + 5);
|
||||||
|
bullet.y = entry.y + entry.image.GetHeight() / 2 - 3.5;
|
||||||
|
bullet.sprites[index].SetPosition(bullet.x, bullet.y, 10002);
|
||||||
|
}
|
||||||
|
bullet.sprites[index].SetOpacity(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Plymouth.SetDisplayNormalFunction(display_normal_callback);
|
||||||
|
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||||
|
|
||||||
|
#----------------------------------------- Progress Bar --------------------------------
|
||||||
|
|
||||||
|
progress_box.image = Image("progress_box.png");
|
||||||
|
progress_box.sprite = Sprite(progress_box.image);
|
||||||
|
|
||||||
|
progress_box.x = Window.GetWidth() / 2 - progress_box.image.GetWidth() / 2;
|
||||||
|
progress_box.y = entry.y + entry.image.GetHeight() / 2 - progress_box.image.GetHeight() / 2;
|
||||||
|
progress_box.sprite.SetPosition(progress_box.x, progress_box.y, 0);
|
||||||
|
progress_box.sprite.SetOpacity(0);
|
||||||
|
|
||||||
|
progress_bar.original_image = Image("progress_bar.png");
|
||||||
|
progress_bar.sprite = Sprite();
|
||||||
|
progress_bar.image = progress_bar.original_image.Scale(1, progress_bar.original_image.GetHeight());
|
||||||
|
|
||||||
|
progress_bar.x = Window.GetWidth() / 2 - progress_bar.original_image.GetWidth() / 2;
|
||||||
|
progress_bar.y = progress_box.y + (progress_box.image.GetHeight() - progress_bar.original_image.GetHeight()) / 2;
|
||||||
|
progress_bar.sprite.SetPosition(progress_bar.x, progress_bar.y, 1);
|
||||||
|
progress_bar.sprite.SetOpacity(0);
|
||||||
|
|
||||||
|
fun progress_callback (duration, progress)
|
||||||
|
{
|
||||||
|
global.real_progress = progress;
|
||||||
|
|
||||||
|
# If real progress is above limit, stop fake progress and use real progress
|
||||||
|
if (progress > global.fake_progress_limit)
|
||||||
|
{
|
||||||
|
stop_fake_progress();
|
||||||
|
update_progress_bar(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Plymouth.SetBootProgressFunction(progress_callback);
|
||||||
|
|
||||||
|
#----------------------------------------- Quit --------------------------------
|
||||||
|
|
||||||
|
fun quit_callback ()
|
||||||
|
{
|
||||||
|
logo.sprite.SetOpacity (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plymouth.SetQuitFunction(quit_callback);
|
||||||
|
|
||||||
|
#----------------------------------------- Message --------------------------------
|
||||||
|
|
||||||
|
message_sprite = Sprite();
|
||||||
|
message_sprite.SetPosition(10, 10, 10000);
|
||||||
|
|
||||||
|
fun display_message_callback (text)
|
||||||
|
{
|
||||||
|
my_image = Image.Text(text, 1, 1, 1);
|
||||||
|
message_sprite.SetImage(my_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide_message_callback (text)
|
||||||
|
{
|
||||||
|
message_sprite.SetOpacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plymouth.SetDisplayMessageFunction (display_message_callback);
|
||||||
|
Plymouth.SetHideMessageFunction (hide_message_callback);
|
||||||
|
|
||||||
|
# Initialize progress bar immediately for normal boots
|
||||||
|
if (Plymouth.GetMode() == "boot" || Plymouth.GetMode() == "resume")
|
||||||
|
{
|
||||||
|
show_progress_bar();
|
||||||
|
start_fake_progress();
|
||||||
|
}
|
||||||
BIN
modules/nixos/plymouth/progress_bar.png
Normal file
BIN
modules/nixos/plymouth/progress_bar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 314 B |
BIN
modules/nixos/plymouth/progress_box.png
Normal file
BIN
modules/nixos/plymouth/progress_box.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 314 B |
@@ -16,6 +16,7 @@
|
|||||||
# NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda NOMARCHY_USERNAME=me \
|
# NOMARCHY_UNATTENDED=1 NOMARCHY_DISK=/dev/vda NOMARCHY_USERNAME=me \
|
||||||
# NOMARCHY_PASSWORD=secret [NOMARCHY_HOSTNAME=nomarchy] \
|
# NOMARCHY_PASSWORD=secret [NOMARCHY_HOSTNAME=nomarchy] \
|
||||||
# [NOMARCHY_TIMEZONE=UTC] [NOMARCHY_LUKS_PASSPHRASE=...] \
|
# [NOMARCHY_TIMEZONE=UTC] [NOMARCHY_LUKS_PASSPHRASE=...] \
|
||||||
|
# [NOMARCHY_LOCALE=en_US.UTF-8] [NOMARCHY_KB_LAYOUT=us] [NOMARCHY_KB_VARIANT=] \
|
||||||
# [NOMARCHY_SWAP_GB=N (default: RAM size; 0 = none)] \
|
# [NOMARCHY_SWAP_GB=N (default: RAM size; 0 = none)] \
|
||||||
# [NOMARCHY_HW="auto"|"none"|"mod1 mod2"] [NOMARCHY_FINISH=none|reboot|poweroff]
|
# [NOMARCHY_HW="auto"|"none"|"mod1 mod2"] [NOMARCHY_FINISH=none|reboot|poweroff]
|
||||||
# nomarchy-install
|
# nomarchy-install
|
||||||
@@ -150,6 +151,9 @@ if [[ "$UNATTENDED" == "1" ]]; then
|
|||||||
PASSWORD="${NOMARCHY_PASSWORD:?}"
|
PASSWORD="${NOMARCHY_PASSWORD:?}"
|
||||||
HOSTNAME_="${NOMARCHY_HOSTNAME:-nomarchy}"
|
HOSTNAME_="${NOMARCHY_HOSTNAME:-nomarchy}"
|
||||||
TIMEZONE="${NOMARCHY_TIMEZONE:-UTC}"
|
TIMEZONE="${NOMARCHY_TIMEZONE:-UTC}"
|
||||||
|
LOCALE="${NOMARCHY_LOCALE:-en_US.UTF-8}"
|
||||||
|
KB_LAYOUT="${NOMARCHY_KB_LAYOUT:-us}"
|
||||||
|
KB_VARIANT="${NOMARCHY_KB_VARIANT:-}"
|
||||||
else
|
else
|
||||||
while true; do
|
while true; do
|
||||||
USERNAME=$(gum input --placeholder "username (lowercase, e.g. ada)")
|
USERNAME=$(gum input --placeholder "username (lowercase, e.g. ada)")
|
||||||
@@ -169,6 +173,26 @@ else
|
|||||||
warn "Invalid hostname."
|
warn "Invalid hostname."
|
||||||
done
|
done
|
||||||
TIMEZONE=$(timedatectl list-timezones | gum filter --placeholder "timezone (type to search)" || echo UTC)
|
TIMEZONE=$(timedatectl list-timezones | gum filter --placeholder "timezone (type to search)" || echo UTC)
|
||||||
|
# Curated UTF-8 locales: the live system only generates en_US, so
|
||||||
|
# `locale -a` can't enumerate what the TARGET could use.
|
||||||
|
LOCALE=$(printf '%s\n' \
|
||||||
|
en_US en_GB de_DE fr_FR es_ES es_MX pt_PT pt_BR it_IT nl_NL \
|
||||||
|
pl_PL ru_RU uk_UA cs_CZ sk_SK sv_SE nb_NO da_DK fi_FI tr_TR \
|
||||||
|
el_GR hu_HU ro_RO bg_BG hr_HR sl_SI lt_LT lv_LV et_EE ja_JP \
|
||||||
|
ko_KR zh_CN zh_TW ar_EG he_IL hi_IN th_TH vi_VN id_ID \
|
||||||
|
| sed 's/$/.UTF-8/' \
|
||||||
|
| gum filter --placeholder "language / locale (type to search)" \
|
||||||
|
|| echo en_US.UTF-8)
|
||||||
|
KB_LAYOUT=$(localectl list-x11-keymap-layouts 2>/dev/null \
|
||||||
|
| gum filter --placeholder "keyboard layout (type to search)" \
|
||||||
|
|| echo us)
|
||||||
|
KB_VARIANT=""
|
||||||
|
if [[ "$KB_LAYOUT" != "us" ]] || gum confirm --default=No "Pick a keyboard variant (intl, nodeadkeys, …)?"; then
|
||||||
|
KB_VARIANT=$( { echo "(none)"; localectl list-x11-keymap-variants "$KB_LAYOUT" 2>/dev/null; } \
|
||||||
|
| gum filter --placeholder "variant for $KB_LAYOUT (pick '(none)' for the default)" \
|
||||||
|
|| echo "(none)")
|
||||||
|
[[ "$KB_VARIANT" == "(none)" ]] && KB_VARIANT=""
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
[[ "$USERNAME" =~ ^[a-z_][a-z0-9_-]*$ ]] || fail "Invalid username '$USERNAME'."
|
[[ "$USERNAME" =~ ^[a-z_][a-z0-9_-]*$ ]] || fail "Invalid username '$USERNAME'."
|
||||||
[[ -f "/usr/share/zoneinfo/$TIMEZONE" || -e "/etc/zoneinfo/$TIMEZONE" ]] \
|
[[ -f "/usr/share/zoneinfo/$TIMEZONE" || -e "/etc/zoneinfo/$TIMEZONE" ]] \
|
||||||
@@ -177,6 +201,7 @@ fi
|
|||||||
HASHED_PASSWORD=$(printf '%s' "$PASSWORD" | mkpasswd -m sha-512 -s)
|
HASHED_PASSWORD=$(printf '%s' "$PASSWORD" | mkpasswd -m sha-512 -s)
|
||||||
unset PASSWORD
|
unset PASSWORD
|
||||||
info "User: $USERNAME @ $HOSTNAME_ ($TIMEZONE)"
|
info "User: $USERNAME @ $HOSTNAME_ ($TIMEZONE)"
|
||||||
|
info "Locale: $LOCALE · keyboard: $KB_LAYOUT${KB_VARIANT:+ ($KB_VARIANT)}"
|
||||||
|
|
||||||
# ─── Hardware profile ───────────────────────────────────────────────────
|
# ─── Hardware profile ───────────────────────────────────────────────────
|
||||||
section "Hardware detection"
|
section "Hardware detection"
|
||||||
@@ -320,9 +345,35 @@ nixos-generate-config --root /mnt
|
|||||||
mv /mnt/etc/nixos/hardware-configuration.nix "$FLAKE_DIR/"
|
mv /mnt/etc/nixos/hardware-configuration.nix "$FLAKE_DIR/"
|
||||||
rm -rf /mnt/etc/nixos
|
rm -rf /mnt/etc/nixos
|
||||||
|
|
||||||
cp "$SHARE/template/home.nix" "$FLAKE_DIR/"
|
|
||||||
cp "$SHARE/template/theme-state.json" "$FLAKE_DIR/"
|
cp "$SHARE/template/theme-state.json" "$FLAKE_DIR/"
|
||||||
|
|
||||||
|
# home.nix is generated (not copied from the template) so the chosen
|
||||||
|
# keyboard layout reaches the Hyprland session — standalone HM cannot
|
||||||
|
# read system.nix.
|
||||||
|
cat > "$FLAKE_DIR/home.nix" <<EOF
|
||||||
|
# Your user environment. The Nomarchy desktop (Hyprland, Waybar,
|
||||||
|
# Ghostty, theming engine, Stylix) comes from homeModules.nomarchy;
|
||||||
|
# tune it via the nomarchy.* options, add your own packages and
|
||||||
|
# programs below.
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Keyboard for the desktop session; console + LUKS prompt get the
|
||||||
|
# same layout from system.nix (xkb + console.useXkbConfig).
|
||||||
|
nomarchy.keyboard.layout = "$KB_LAYOUT";
|
||||||
|
nomarchy.keyboard.variant = "$KB_VARIANT";
|
||||||
|
|
||||||
|
# Examples:
|
||||||
|
# nomarchy.terminal = "kitty"; # swap the default terminal
|
||||||
|
# nomarchy.waybar.enable = false; # bring your own bar
|
||||||
|
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
||||||
|
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
# firefox
|
||||||
|
];
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
hw_nix=""
|
hw_nix=""
|
||||||
for p in "${HW_PROFILES[@]:-}"; do
|
for p in "${HW_PROFILES[@]:-}"; do
|
||||||
[[ -n "$p" ]] && hw_nix+=" \"$p\""
|
[[ -n "$p" ]] && hw_nix+=" \"$p\""
|
||||||
@@ -371,7 +422,17 @@ cat > "$FLAKE_DIR/system.nix" <<EOF
|
|||||||
|
|
||||||
networking.hostName = "$HOSTNAME_";
|
networking.hostName = "$HOSTNAME_";
|
||||||
time.timeZone = "$TIMEZONE";
|
time.timeZone = "$TIMEZONE";
|
||||||
i18n.defaultLocale = "en_US.UTF-8";
|
i18n.defaultLocale = "$LOCALE";
|
||||||
|
|
||||||
|
# One keyboard layout everywhere: xkb is the source of truth, the
|
||||||
|
# virtual console derives from it (greeter/ttys), and the systemd
|
||||||
|
# initrd applies it to the LUKS passphrase prompt too (the classic
|
||||||
|
# script initrd cannot). The Hyprland session reads the same layout
|
||||||
|
# from nomarchy.keyboard.* in home.nix.
|
||||||
|
services.xserver.xkb.layout = "$KB_LAYOUT";
|
||||||
|
services.xserver.xkb.variant = "$KB_VARIANT";
|
||||||
|
console.useXkbConfig = true;
|
||||||
|
boot.initrd.systemd.enable = true;
|
||||||
|
|
||||||
# Your login user — \`username\` flows in from flake.nix automatically.
|
# Your login user — \`username\` flows in from flake.nix automatically.
|
||||||
users.users.\${username} = {
|
users.users.\${username} = {
|
||||||
@@ -410,6 +471,9 @@ fi
|
|||||||
# outright. The first normal NixOS user is always 1000:users(100); the
|
# outright. The first normal NixOS user is always 1000:users(100); the
|
||||||
# account doesn't exist in the target yet, so numeric ids it is.
|
# account doesn't exist in the target yet, so numeric ids it is.
|
||||||
chown -R 1000:100 "$FLAKE_DIR"
|
chown -R 1000:100 "$FLAKE_DIR"
|
||||||
|
# The templates come out of the nix store mode 0444 and cp preserves
|
||||||
|
# that — without this the user owns home.nix but can't edit it.
|
||||||
|
chmod -R u+w "$FLAKE_DIR"
|
||||||
|
|
||||||
# /etc/nixos on the installed system points at the user-owned flake.
|
# /etc/nixos on the installed system points at the user-owned flake.
|
||||||
mkdir -p /mnt/etc
|
mkdir -p /mnt/etc
|
||||||
@@ -464,6 +528,25 @@ success "System installed (bootloader in place)"
|
|||||||
# fully themed desktop, not bare Hyprland. Best-effort: a failure here
|
# fully themed desktop, not bare Hyprland. Best-effort: a failure here
|
||||||
# only costs the user one `home-manager switch` after logging in.
|
# only costs the user one `home-manager switch` after logging in.
|
||||||
section "Baking the desktop"
|
section "Baking the desktop"
|
||||||
|
|
||||||
|
# Build the generation HERE in the live environment, not in the chroot:
|
||||||
|
# the live store always carries the offline pin set, while the target
|
||||||
|
# store only gets the full ISO store on OFFLINE installs — an online
|
||||||
|
# install skips that copy, and the old in-chroot build (substituters
|
||||||
|
# deliberately empty) then tried to compile the world from source.
|
||||||
|
# Building against the live store is the exact path the live session's
|
||||||
|
# own theme switching exercises, online or off.
|
||||||
|
info "Building the desktop generation..."
|
||||||
|
hm_out=""
|
||||||
|
if hm_out=$(nix --extra-experimental-features "nix-command flakes" \
|
||||||
|
build --no-link --print-out-paths \
|
||||||
|
--option substituters "" \
|
||||||
|
"path:$FLAKE_DIR#homeConfigurations.$USERNAME.activationPackage"); then
|
||||||
|
nix --extra-experimental-features "nix-command flakes" \
|
||||||
|
copy --no-check-sigs --to "local?root=/mnt" "$hm_out" \
|
||||||
|
|| hm_out=""
|
||||||
|
fi
|
||||||
|
[[ -n "$hm_out" ]] || warn "live-side desktop build failed — retrying inside the chroot"
|
||||||
# NOT /mnt/tmp: nixos-enter mounts a fresh tmpfs over /tmp inside the
|
# NOT /mnt/tmp: nixos-enter mounts a fresh tmpfs over /tmp inside the
|
||||||
# chroot, which silently vaporizes any script staged there (cost us a
|
# chroot, which silently vaporizes any script staged there (cost us a
|
||||||
# full verification round to find). /root persists into the chroot.
|
# full verification round to find). /root persists into the chroot.
|
||||||
@@ -471,10 +554,15 @@ cat > /mnt/root/nomarchy-hm-activate.sh <<EOF
|
|||||||
set -ex
|
set -ex
|
||||||
exec > /var/log/nomarchy-hm-preactivate.log 2>&1
|
exec > /var/log/nomarchy-hm-preactivate.log 2>&1
|
||||||
export PATH=/run/current-system/sw/bin:\$PATH
|
export PATH=/run/current-system/sw/bin:\$PATH
|
||||||
out=\$(nix --extra-experimental-features "nix-command flakes" \
|
# Normally pre-built in the live env and copied over; the in-chroot
|
||||||
build --no-link --print-out-paths \
|
# build (default substituters — the live-side build already proved the
|
||||||
--option substituters "" \
|
# no-network case) is a last-resort fallback.
|
||||||
"path:/home/$USERNAME/.nomarchy#homeConfigurations.$USERNAME.activationPackage")
|
out="$hm_out"
|
||||||
|
if [ -z "\$out" ]; then
|
||||||
|
out=\$(nix --extra-experimental-features "nix-command flakes" \
|
||||||
|
build --no-link --print-out-paths \
|
||||||
|
"path:/home/$USERNAME/.nomarchy#homeConfigurations.$USERNAME.activationPackage")
|
||||||
|
fi
|
||||||
install -d -o "$USERNAME" -g users /nix/var/nix/profiles/per-user/$USERNAME
|
install -d -o "$USERNAME" -g users /nix/var/nix/profiles/per-user/$USERNAME
|
||||||
install -d -o "$USERNAME" -g users /nix/var/nix/gcroots/per-user/$USERNAME
|
install -d -o "$USERNAME" -g users /nix/var/nix/gcroots/per-user/$USERNAME
|
||||||
# activate's profile ops need store access; as the user that means a
|
# activate's profile ops need store access; as the user that means a
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
# nomarchy.terminal = "kitty"; # swap the default terminal
|
# nomarchy.terminal = "kitty"; # swap the default terminal
|
||||||
# nomarchy.waybar.enable = false; # bring your own bar
|
# nomarchy.waybar.enable = false; # bring your own bar
|
||||||
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
||||||
|
# nomarchy.keyboard.layout = "de"; # session keyboard (pair with
|
||||||
|
# # xkb + console.useXkbConfig in
|
||||||
|
# # system.nix for tty/LUKS)
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
# firefox
|
# firefox
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ window#waybar {
|
|||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
#network,
|
#network,
|
||||||
#battery,
|
#battery,
|
||||||
|
#tray,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
|
|||||||
92
themes/summer-day/waybar.jsonc
Normal file
92
themes/summer-day/waybar.jsonc
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"margin-top": 0,
|
||||||
|
"margin-left": 120,
|
||||||
|
"margin-bottom": 0,
|
||||||
|
"margin-right": 120,
|
||||||
|
"height": 60,
|
||||||
|
"layer": "top",
|
||||||
|
"position": "top",
|
||||||
|
"spacing": 15,
|
||||||
|
"reload_style_on_change": true,
|
||||||
|
|
||||||
|
"modules-left": ["custom/launcher", "clock", "clock#date"],
|
||||||
|
"modules-center": ["hyprland/workspaces"],
|
||||||
|
"modules-right": ["pulseaudio", "network", "battery", "tray", "custom/powermenu"],
|
||||||
|
|
||||||
|
"hyprland/workspaces": {
|
||||||
|
"disable-scroll": true,
|
||||||
|
"all-outputs": true,
|
||||||
|
"on-click": "activate",
|
||||||
|
"on-scroll-up": "hyprctl dispatch workspace e+1",
|
||||||
|
"on-scroll-down": "hyprctl dispatch workspace e-1",
|
||||||
|
"persistent-workspaces": {
|
||||||
|
"1": [], "2": [], "3": [], "4": [], "5": [],
|
||||||
|
"6": [], "7": [], "8": [], "9": [], "10": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"custom/launcher": {
|
||||||
|
"interval": "once",
|
||||||
|
"format": "",
|
||||||
|
"on-click": "nomarchy-menu",
|
||||||
|
"tooltip-format": "Nomarchy menu"
|
||||||
|
},
|
||||||
|
|
||||||
|
"pulseaudio": {
|
||||||
|
"format": "{icon} {volume}%",
|
||||||
|
"format-bluetooth": "{icon} {volume}%",
|
||||||
|
"format-bluetooth-muted": " muted",
|
||||||
|
"format-muted": " muted",
|
||||||
|
"format-icons": {
|
||||||
|
"headphone": "",
|
||||||
|
"hands-free": "",
|
||||||
|
"headset": "",
|
||||||
|
"phone": "",
|
||||||
|
"portable": "",
|
||||||
|
"car": "",
|
||||||
|
"default": ["", "", ""]
|
||||||
|
},
|
||||||
|
"on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
|
||||||
|
"tooltip-format": "Playing at {volume}%"
|
||||||
|
},
|
||||||
|
|
||||||
|
"network": {
|
||||||
|
"format-wifi": " {signalStrength}%",
|
||||||
|
"format-ethernet": "",
|
||||||
|
"format-disconnected": "",
|
||||||
|
"on-click": "sh -c '$TERMINAL -e nmtui'",
|
||||||
|
"tooltip-format": "{ipaddr} via {gwaddr}"
|
||||||
|
},
|
||||||
|
|
||||||
|
"battery": {
|
||||||
|
"interval": 60,
|
||||||
|
"states": { "warning": 30, "critical": 15 },
|
||||||
|
"max-length": 10,
|
||||||
|
"format": "{icon} {capacity}%",
|
||||||
|
"format-charging": " {capacity}%",
|
||||||
|
"format-plugged": " {capacity}%",
|
||||||
|
"format-full": " 100%",
|
||||||
|
"format-icons": ["", "", "", "", ""],
|
||||||
|
"on-click": "nomarchy-menu power",
|
||||||
|
"tooltip-format": "Battery status"
|
||||||
|
},
|
||||||
|
|
||||||
|
"clock": {
|
||||||
|
"format": " {:%H:%M}",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "<tt><small>{calendar}</small></tt>"
|
||||||
|
},
|
||||||
|
|
||||||
|
"clock#date": {
|
||||||
|
"format": " {:%A, %B %d, %Y}",
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"tray": { "spacing": 8 },
|
||||||
|
|
||||||
|
"custom/powermenu": {
|
||||||
|
"format": "",
|
||||||
|
"on-click": "nomarchy-menu power",
|
||||||
|
"tooltip": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,8 +53,9 @@ window#waybar {
|
|||||||
#clock.date,
|
#clock.date,
|
||||||
#workspaces,
|
#workspaces,
|
||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
|
#network,
|
||||||
#idle_inhibitor,
|
#idle_inhibitor,
|
||||||
#custom-battery,
|
#battery,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
@@ -98,7 +99,6 @@ window#waybar {
|
|||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 21px;
|
padding-right: 21px;
|
||||||
font-family: Nomarchy;
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ window#waybar {
|
|||||||
padding-right: 23px;
|
padding-right: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-battery.preservation {
|
#battery.charging {
|
||||||
color: @green;
|
color: @green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
99
themes/summer-night/waybar.jsonc
Normal file
99
themes/summer-night/waybar.jsonc
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
"margin-top": 0,
|
||||||
|
"margin-left": 120,
|
||||||
|
"margin-bottom": 0,
|
||||||
|
"margin-right": 120,
|
||||||
|
"height": 61,
|
||||||
|
"layer": "top",
|
||||||
|
"position": "top",
|
||||||
|
"spacing": 15,
|
||||||
|
"reload_style_on_change": true,
|
||||||
|
|
||||||
|
"modules-left": ["custom/nomarchy", "clock", "clock#date"],
|
||||||
|
"modules-center": ["hyprland/workspaces"],
|
||||||
|
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "battery", "tray", "custom/powermenu"],
|
||||||
|
|
||||||
|
"hyprland/workspaces": {
|
||||||
|
"disable-scroll": true,
|
||||||
|
"all-outputs": true,
|
||||||
|
"on-click": "activate",
|
||||||
|
"on-scroll-up": "hyprctl dispatch workspace r+1",
|
||||||
|
"on-scroll-down": "hyprctl dispatch workspace r-1",
|
||||||
|
"persistent-workspaces": {
|
||||||
|
"1": [], "2": [], "3": [], "4": [], "5": [],
|
||||||
|
"6": [], "7": [], "8": [], "9": [], "10": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"custom/nomarchy": {
|
||||||
|
"interval": "once",
|
||||||
|
"format": "",
|
||||||
|
"on-click": "nomarchy-menu",
|
||||||
|
"tooltip-format": "Nomarchy menu"
|
||||||
|
},
|
||||||
|
|
||||||
|
"idle_inhibitor": {
|
||||||
|
"format": "{icon}",
|
||||||
|
"format-icons": {
|
||||||
|
"activated": " ",
|
||||||
|
"deactivated": " "
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"pulseaudio": {
|
||||||
|
"scroll-step": 5,
|
||||||
|
"format": "{icon} {volume}%",
|
||||||
|
"format-bluetooth": "{icon} {volume}%",
|
||||||
|
"format-bluetooth-muted": " {icon}",
|
||||||
|
"format-muted": " muted",
|
||||||
|
"format-icons": {
|
||||||
|
"headphone": "",
|
||||||
|
"hands-free": "",
|
||||||
|
"headset": "",
|
||||||
|
"phone": "",
|
||||||
|
"portable": "",
|
||||||
|
"car": "",
|
||||||
|
"default": ["", "", ""]
|
||||||
|
},
|
||||||
|
"on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
|
||||||
|
"tooltip-format": "{desc} | {volume}%"
|
||||||
|
},
|
||||||
|
|
||||||
|
"network": {
|
||||||
|
"format-wifi": " {essid}",
|
||||||
|
"format-ethernet": "",
|
||||||
|
"format-disconnected": "",
|
||||||
|
"on-click": "sh -c '$TERMINAL -e nmtui'",
|
||||||
|
"tooltip-format": "{ipaddr} via {gwaddr}"
|
||||||
|
},
|
||||||
|
|
||||||
|
"battery": {
|
||||||
|
"interval": 30,
|
||||||
|
"states": { "warning": 25, "critical": 10 },
|
||||||
|
"format": "{icon} {capacity}%",
|
||||||
|
"format-charging": " {capacity}%",
|
||||||
|
"format-plugged": " {capacity}%",
|
||||||
|
"format-icons": ["", "", "", "", ""],
|
||||||
|
"on-click": "nomarchy-menu power",
|
||||||
|
"tooltip-format": "Battery status"
|
||||||
|
},
|
||||||
|
|
||||||
|
"clock": {
|
||||||
|
"format": " {:%H:%M}",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "<tt><small>{calendar}</small></tt>"
|
||||||
|
},
|
||||||
|
|
||||||
|
"clock#date": {
|
||||||
|
"format": " {:%A, %B %d, %Y}",
|
||||||
|
"tooltip": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"tray": { "spacing": 8 },
|
||||||
|
|
||||||
|
"custom/powermenu": {
|
||||||
|
"format": "",
|
||||||
|
"on-click": "nomarchy-menu power",
|
||||||
|
"tooltip": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,8 +47,8 @@ if df --output=fstype "$TARGET_DIR" | tail -1 | grep -q tmpfs; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OVMF=""
|
OVMF="${NOMARCHY_OVMF:-}"
|
||||||
for c in /run/current-system/sw/share/qemu/edk2-x86_64-code.fd \
|
[ -n "$OVMF" ] || for c in /run/current-system/sw/share/qemu/edk2-x86_64-code.fd \
|
||||||
/run/current-system/sw/share/OVMF/OVMF_CODE.fd \
|
/run/current-system/sw/share/OVMF/OVMF_CODE.fd \
|
||||||
/usr/share/OVMF/OVMF_CODE.fd; do
|
/usr/share/OVMF/OVMF_CODE.fd; do
|
||||||
[ -f "$c" ] && { OVMF="$c"; break; }
|
[ -f "$c" ] && { OVMF="$c"; break; }
|
||||||
|
|||||||
Reference in New Issue
Block a user