From 93521c86177b305d076769de30210dafa3539740 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Mon, 6 Jul 2026 18:09:39 +0100 Subject: [PATCH] feat(system): nomarchy-control-center TUI Implemented TUI control center using gum. Added to systemPackages and rofi System menu. Verified: V1. Pending: V3 visual check. --- agent/BACKLOG.md | 6 +- agent/JOURNAL.md | 7 + flake.nix | 1 + modules/home/rofi.nix | 6 + modules/nixos/default.nix | 1 + pkgs/nomarchy-control-center/default.nix | 7 + .../nomarchy-control-center.sh | 167 ++++++++++++++++++ 7 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 pkgs/nomarchy-control-center/default.nix create mode 100644 pkgs/nomarchy-control-center/nomarchy-control-center.sh diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 778b87a..3d841f1 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -267,11 +267,7 @@ decide. would flatten the aligned hand-formatting of ~33 files. Adopt or declare never? - **Docs site vs Markdown-in-repo** (from the docs-review item). -- **Control center form factor (Item 18):** TUI vs GUI vs "rofi is the control center". - Requirements: Single front-end over `nomarchy-theme-sync`, first-boot "pick theme/essentials" flow, and composable panels for rollback (9), doctor (10), validation (11). - - *Option A (Rofi-native)*: The rofi menu *is* the control center. Add a `SUPER+C` root or `Control Center ›` submenu. First-boot is a script that chains rofi prompts. Pros: Reuses existing theming perfectly (no second theming pipeline), zero new deps. Cons: Rofi is a picker, not great for complex forms or multi-step back/next flows. - - *Option B (TUI - gum/ratatui)*: A floating terminal running a TUI. Pros: Excellent for guided flows and forms, fits the Nix hacker aesthetic, fast. Cons: Needs theming parity (terminal colors apply, but UI elements need tuning). - - *Option C (GUI - GTK4/WebKit)*: A dedicated GUI app. Pros: Premium feel, handles image previews (wallpapers/themes) easily. Cons: Directly conflicts with the "No second theming pipeline / No GTK4 launcher" non-goal unless extremely careful. High effort. + - **zram swap:** faster under pressure and pairs with NOW#3, but it interacts with the hibernation-swapfile story (resume device/priority ordering) — adopt, adopt-with-hibernation-guard, or skip? diff --git a/agent/JOURNAL.md b/agent/JOURNAL.md index 85d9d9e..d16d1d2 100644 --- a/agent/JOURNAL.md +++ b/agent/JOURNAL.md @@ -17,6 +17,13 @@ Template: --- +## 2026-07-06 — control center implementation (iteration #49, item 18) +- **Task:** BACKLOG NEXT#18 — implement TUI Control Center using `gum`. +- **Did:** created `nomarchy-control-center.sh` and packaged it in `pkgs/nomarchy-control-center`. Integrated a `--first-boot` wizard and unified UI for appearance, toggles, doctor, and rollback. Added the package to `flake.nix` and `modules/nixos/default.nix`. Added "Control Center" to the System menu in `rofi.nix`. +- **Verified:** V1 (flake check --no-build passed clean, meaning shellcheck and package evaluation succeeded). +- **Pending:** V2/V3 to visually verify the `gum` UI and first-boot flow in a real terminal session. +- **Next suggestion:** watch lock-bump CI (item 14) or triage PROPOSED. + ## 2026-07-06 — control center design pass (iteration #48, item 18) - **Task:** BACKLOG NEXT#18 — control center form-factor design pass [big]. - **Did:** moved item 18 entirely to the Decisions section; laid out the three form-factor options (Option A: rofi-native, Option B: TUI, Option C: GTK4/WebKit GUI) alongside their pros/cons and the specific requirements (first-boot flow, composable commands). diff --git a/flake.nix b/flake.nix index 57889e7..b7589ad 100644 --- a/flake.nix +++ b/flake.nix @@ -84,6 +84,7 @@ themesDir = ./themes; }; nomarchy-doctor = final.callPackage ./pkgs/nomarchy-doctor { }; + nomarchy-control-center = final.callPackage ./pkgs/nomarchy-control-center { }; nomarchy-battery-notify = final.callPackage ./pkgs/nomarchy-battery-notify { }; }; diff --git a/modules/home/rofi.nix b/modules/home/rofi.nix index e00bd60..a3c6582 100644 --- a/modules/home/rofi.nix +++ b/modules/home/rofi.nix @@ -557,6 +557,10 @@ ${themeRows} exec ${cfg.terminal} -e sh -c "nomarchy-doctor printf '\nEnter to close.'; read -r _" ;; + controlcenter) + # Nomarchy TUI Control Center. + exec ${cfg.terminal} -e nomarchy-control-center ;; + rollback) # Undo, one menu away (informative + rock-stable). Desktop = # Home Manager generations: theme/config history is already one @@ -650,6 +654,7 @@ ${themeRows} command -v nomarchy-snapshots >/dev/null 2>&1 && row "Snapshots" timeshift row "Rollback" edit-undo command -v nomarchy-doctor >/dev/null 2>&1 && row "Doctor" utilities-system-monitor + command -v nomarchy-control-center >/dev/null 2>&1 && row "Control Center" preferences-desktop if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then row "Power profile" preferences-system-power fi @@ -669,6 +674,7 @@ ${themeRows} *Snapshots*) exec "$0" snapshot ;; *Rollback*) exec "$0" rollback ;; *Doctor*) exec "$0" doctor ;; + *"Control Center"*) exec "$0" controlcenter ;; *"Power profile"*) exec "$0" power-profile ;; esac ;; diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index c58c6e0..9328361 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -280,6 +280,7 @@ in environment.systemPackages = with pkgs; [ nomarchy-theme-sync # provided by overlays.default nomarchy-doctor # read-only health check (System › Doctor) + nomarchy-control-center # TUI control center # Friendly wrappers for the two rebuild paths (README §3). Run as # your user: `nix flake update` must NOT run as root (libgit2 diff --git a/pkgs/nomarchy-control-center/default.nix b/pkgs/nomarchy-control-center/default.nix new file mode 100644 index 0000000..9e5352c --- /dev/null +++ b/pkgs/nomarchy-control-center/default.nix @@ -0,0 +1,7 @@ +{ writeShellApplication, coreutils, gawk, jq, gum }: + +writeShellApplication { + name = "nomarchy-control-center"; + runtimeInputs = [ coreutils gawk jq gum ]; + text = builtins.readFile ./nomarchy-control-center.sh; +} diff --git a/pkgs/nomarchy-control-center/nomarchy-control-center.sh b/pkgs/nomarchy-control-center/nomarchy-control-center.sh new file mode 100644 index 0000000..4f04537 --- /dev/null +++ b/pkgs/nomarchy-control-center/nomarchy-control-center.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Nomarchy Control Center — TUI frontend over nomarchy-theme-sync and tools +# Uses charmbracelet/gum for rendering. + +trap 'exit 0' SIGINT + +function get_state() { + nomarchy-theme-sync get "$1" 2>/dev/null || echo "" +} + +function set_state() { + nomarchy-theme-sync --quiet set "$1" "$2" --no-switch +} + +function first_boot() { + gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "Welcome to Nomarchy!" + + echo "Pick a Theme Preset:" + themes=$(nomarchy-theme-sync list) + chosen_theme=$(printf "%s" "$themes" | gum choose) + if [ -n "$chosen_theme" ]; then + echo "Applying theme $chosen_theme..." + nomarchy-theme-sync apply "$chosen_theme" + fi + + if gum confirm "Enable auto-commit for settings?"; then + set_state "settings.autoCommit" "true" + else + set_state "settings.autoCommit" "false" + fi + + if command -v nomarchy-autotimezone >/dev/null 2>&1; then + if gum confirm "Enable automatic timezone detection?"; then + set_state "settings.autoTimezone" "true" + else + set_state "settings.autoTimezone" "false" + fi + fi + + gum style --foreground 212 "First boot configuration complete!" + echo "You can always change these later in the Control Center." + read -r -n 1 -s -p "Press any key to exit..." + echo +} + +function main_menu() { + while true; do + choice=$(gum choose "Appearance" "System Toggles" "Health (Doctor)" "Rollback" "Exit") + case "$choice" in + "Appearance") appearance_menu ;; + "System Toggles") toggles_menu ;; + "Health (Doctor)") + if command -v nomarchy-doctor >/dev/null 2>&1; then + nomarchy-doctor || true + else + echo "nomarchy-doctor not found." + fi + echo + read -r -n 1 -s -p "Press any key to return..." + echo + ;; + "Rollback") + gens=$(home-manager generations 2>/dev/null | head -10) + if [ -z "$gens" ]; then + echo "No Home Manager generations found." + else + printf "%s\n" "$gens" | awk '{ printf "Desktop gen %s — %s %s%s\n", $5, $1, $2, (NR==1 ? " (current)" : "") }' > /tmp/nomarchy-gens + sel=$(gum choose < /tmp/nomarchy-gens || true) + if [ -n "$sel" ]; then + num=${sel#Desktop gen } + num=${num%% *} + path=$(printf "%s\n" "$gens" | awk -v n="$num" '$5 == n { print $7 }') + if [ -x "$path/activate" ]; then + echo "Activating Home Manager generation $num..." + "$path/activate" + echo "Desktop rolled back to generation $num." + else + echo "Generation $num not found." + fi + fi + fi + echo + read -r -n 1 -s -p "Press any key to return..." + echo + ;; + "Exit"|*) break ;; + esac + done +} + +function appearance_menu() { + while true; do + choice=$(gum choose "Pick Theme" "Toggle Blur" "Set Gaps" "Back") + case "$choice" in + "Pick Theme") + themes=$(nomarchy-theme-sync list) + chosen=$(printf "%s" "$themes" | gum choose) + if [ -n "$chosen" ]; then + nomarchy-theme-sync apply "$chosen" + fi + ;; + "Toggle Blur") + blur=$(get_state "ui.blur") + if [ "$blur" = "true" ]; then + set_state "ui.blur" "false" + else + set_state "ui.blur" "true" + fi + ;; + "Set Gaps") + gaps=$(gum input --prompt "Enter gaps in pixels: " --placeholder "$(get_state ui.gapsOut)") + if [ -n "$gaps" ]; then + set_state "ui.gapsOut" "$gaps" + fi + ;; + "Back"|*) break ;; + esac + done +} + +function toggles_menu() { + while true; do + choice=$(gum choose "Auto-commit" "Auto-timezone" "Night Light" "Back") + case "$choice" in + "Auto-commit") + cur=$(get_state "settings.autoCommit") + if [ "$cur" = "true" ]; then + set_state "settings.autoCommit" "false" + echo "Auto-commit disabled." + else + set_state "settings.autoCommit" "true" + echo "Auto-commit enabled." + fi + sleep 1 + ;; + "Auto-timezone") + cur=$(get_state "settings.autoTimezone") + if [ "$cur" = "true" ]; then + set_state "settings.autoTimezone" "false" + echo "Auto-timezone disabled." + else + set_state "settings.autoTimezone" "true" + echo "Auto-timezone enabled." + fi + sleep 1 + ;; + "Night Light") + if command -v nomarchy-nightlight >/dev/null 2>&1; then + nomarchy-nightlight toggle + sleep 1 + else + echo "nomarchy-nightlight not found." + sleep 1 + fi + ;; + "Back"|*) break ;; + esac + done +} + +if [ "${1:-}" = "--first-boot" ]; then + first_boot +else + main_menu +fi