refactor: implement component-based architecture for enhanced maintainability

- Reorganize directory structure into core/, features/, and themes/
- Colocate application Nix logic, configs, scripts, and theme overrides
- Implement 'Inversion of Control' for theming: apps now pull theme-specific layouts
- Update flake.nix and shared library paths to match the new structure
- Document the new Feature-Centric architecture in README.md
This commit is contained in:
Bernardo Magri
2026-04-12 14:51:15 +01:00
parent a9ee79a5ce
commit bbdf34ced8
535 changed files with 119 additions and 127 deletions

96
lib/default.nix Normal file
View File

@@ -0,0 +1,96 @@
# Nomarchy Shared Library
# Centralized utilities to reduce code duplication across modules
{ lib }:
let
# Import theme palettes once - used by multiple modules
palettes = import ../themes/palettes;
# Unified state reading function
# Handles both JSON and plain text files with graceful fallbacks
readState = { file, default }:
if builtins.pathExists file then
let
content = builtins.readFile file;
cleanContent = lib.removeSuffix "\n" content;
in
if lib.hasSuffix ".json" (toString file) then
builtins.fromJSON cleanContent
else
cleanContent
else
default;
# Read home state from unified location
readHomeState = homeDirectory:
readState {
file = "${homeDirectory}/.config/nomarchy/state.json";
default = {};
};
# Read system state
readSystemState =
readState {
file = /etc/nixos/state.json;
default = {};
};
# Resolve wallpaper path with fallback
# Returns either the user-specified wallpaper or a default from the theme
resolveWallpaper = { wallpaperPath, themeName, assetsPath }:
if wallpaperPath != "" then
wallpaperPath
else
let
themeBackgrounds = assetsPath + "/${themeName}/backgrounds";
defaultBackground = assetsPath + "/catppuccin/backgrounds/1-totoro.png";
in
if builtins.pathExists themeBackgrounds then
let
backgrounds = builtins.attrNames (builtins.readDir themeBackgrounds);
in
if backgrounds != [] then
"${themeBackgrounds}/${builtins.head (builtins.sort (a: b: a < b) backgrounds)}"
else
defaultBackground
else
defaultBackground;
# Get current palette from theme name
getPalette = themeName:
(palettes.${themeName} or palettes.nord).palette;
# Get full color scheme from theme name
getColorScheme = themeName:
palettes.${themeName} or palettes.nord;
# Check if a theme is light mode
isThemeLightMode = { themeName, assetsPath }:
builtins.pathExists (assetsPath + "/${themeName}/light.mode");
# Get icons theme for a given theme
getIconsTheme = { themeName, assetsPath, default ? "Yaru-blue" }:
let
iconsFile = assetsPath + "/${themeName}/icons.theme";
in
if builtins.pathExists iconsFile then
lib.removeSuffix "\n" (builtins.readFile iconsFile)
else
default;
# Get list of available theme names
themeNames = builtins.attrNames palettes;
in {
inherit
palettes
readState
readHomeState
readSystemState
resolveWallpaper
getPalette
getColorScheme
isThemeLightMode
getIconsTheme
themeNames;
}

66
lib/state-schema.nix Normal file
View File

@@ -0,0 +1,66 @@
# Nomarchy State Schema
# Defines the complete state shape with defaults for both home and system state
{ lib }:
{
# Home state defaults (user preferences)
home = {
# Theme and appearance
theme = "nord";
wallpaper = "";
font = "JetBrainsMono Nerd Font";
nightlightTemperature = 4000;
# Feature toggles
suspend = true;
screensaver = true;
idle = true;
nightlight = false;
waybar = true;
skipVsCodeTheme = false;
# Hyprland window manager settings
hyprland = {
gaps_in = 5;
gaps_out = 10;
border_size = 2;
};
};
# System state defaults (system-level configuration)
system = {
# Theme (can differ from home for system-level theming)
theme = "nord";
# Timezone
timezone = "UTC";
# DNS configuration
dns = "DHCP"; # Options: "DHCP", "Cloudflare", "Google", "Custom"
customDns = [];
# Wi-Fi settings
wifi = {
powersave = true;
};
# Optional features
features = {
fingerprint = false;
fido2 = false;
hybridGPU = false;
makima = false;
};
};
# Get a value from state with fallback to default
getWithDefault = state: path: default:
let
pathList = lib.splitString "." path;
getValue = obj: remaining:
if remaining == [] then obj
else if builtins.isAttrs obj && builtins.hasAttr (builtins.head remaining) obj
then getValue obj.${builtins.head remaining} (builtins.tail remaining)
else default;
in getValue state pathList;
}