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.
This commit is contained in:
@@ -267,11 +267,7 @@ decide.
|
|||||||
would flatten the aligned hand-formatting of ~33 files. Adopt or
|
would flatten the aligned hand-formatting of ~33 files. Adopt or
|
||||||
declare never?
|
declare never?
|
||||||
- **Docs site vs Markdown-in-repo** (from the docs-review item).
|
- **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
|
- **zram swap:** faster under pressure and pairs with NOW#3, but it
|
||||||
interacts with the hibernation-swapfile story (resume device/priority
|
interacts with the hibernation-swapfile story (resume device/priority
|
||||||
ordering) — adopt, adopt-with-hibernation-guard, or skip?
|
ordering) — adopt, adopt-with-hibernation-guard, or skip?
|
||||||
|
|||||||
@@ -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)
|
## 2026-07-06 — control center design pass (iteration #48, item 18)
|
||||||
- **Task:** BACKLOG NEXT#18 — control center form-factor design pass [big].
|
- **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).
|
- **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).
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
themesDir = ./themes;
|
themesDir = ./themes;
|
||||||
};
|
};
|
||||||
nomarchy-doctor = final.callPackage ./pkgs/nomarchy-doctor { };
|
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 { };
|
nomarchy-battery-notify = final.callPackage ./pkgs/nomarchy-battery-notify { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -557,6 +557,10 @@ ${themeRows}
|
|||||||
exec ${cfg.terminal} -e sh -c "nomarchy-doctor
|
exec ${cfg.terminal} -e sh -c "nomarchy-doctor
|
||||||
printf '\nEnter to close.'; read -r _" ;;
|
printf '\nEnter to close.'; read -r _" ;;
|
||||||
|
|
||||||
|
controlcenter)
|
||||||
|
# Nomarchy TUI Control Center.
|
||||||
|
exec ${cfg.terminal} -e nomarchy-control-center ;;
|
||||||
|
|
||||||
rollback)
|
rollback)
|
||||||
# Undo, one menu away (informative + rock-stable). Desktop =
|
# Undo, one menu away (informative + rock-stable). Desktop =
|
||||||
# Home Manager generations: theme/config history is already one
|
# 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
|
command -v nomarchy-snapshots >/dev/null 2>&1 && row "Snapshots" timeshift
|
||||||
row "Rollback" edit-undo
|
row "Rollback" edit-undo
|
||||||
command -v nomarchy-doctor >/dev/null 2>&1 && row "Doctor" utilities-system-monitor
|
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
|
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
||||||
row "Power profile" preferences-system-power
|
row "Power profile" preferences-system-power
|
||||||
fi
|
fi
|
||||||
@@ -669,6 +674,7 @@ ${themeRows}
|
|||||||
*Snapshots*) exec "$0" snapshot ;;
|
*Snapshots*) exec "$0" snapshot ;;
|
||||||
*Rollback*) exec "$0" rollback ;;
|
*Rollback*) exec "$0" rollback ;;
|
||||||
*Doctor*) exec "$0" doctor ;;
|
*Doctor*) exec "$0" doctor ;;
|
||||||
|
*"Control Center"*) exec "$0" controlcenter ;;
|
||||||
*"Power profile"*) exec "$0" power-profile ;;
|
*"Power profile"*) exec "$0" power-profile ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
|
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ in
|
|||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
nomarchy-theme-sync # provided by overlays.default
|
nomarchy-theme-sync # provided by overlays.default
|
||||||
nomarchy-doctor # read-only health check (System › Doctor)
|
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
|
# Friendly wrappers for the two rebuild paths (README §3). Run as
|
||||||
# your user: `nix flake update` must NOT run as root (libgit2
|
# your user: `nix flake update` must NOT run as root (libgit2
|
||||||
|
|||||||
7
pkgs/nomarchy-control-center/default.nix
Normal file
7
pkgs/nomarchy-control-center/default.nix
Normal file
@@ -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;
|
||||||
|
}
|
||||||
167
pkgs/nomarchy-control-center/nomarchy-control-center.sh
Normal file
167
pkgs/nomarchy-control-center/nomarchy-control-center.sh
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user