feat(jade): create modular desktop environment

Rename xmonad/ to jade/ and restructure as a complete desktop environment
with hybrid NixOS and home-manager modules. This establishes jade as a
self-contained, gruvbox-themed DE that can eventually be extracted as a flake.

Changes:
- Create jade/ with NixOS module (WM, system packages, GTK theme)
- Create jade/home.nix for home-manager services (wezterm, picom, dunst)
- Move dmenu with gruvbox patches into jade/dmenu/
- Convert wezterm to pure Lua config with gruvbox-material colors
- Move xinitrc into jade/ directory
- Remove feh/scrot from global env (now in jade)
- Remove dmenu overlay from global overlays
- Simplify home-manager desktop features to just user apps

This follows the pattern of real DEs (GNOME, KDE) where system and user
configs are split across NixOS and home-manager modules.
This commit is contained in:
♥ Minnie ♥ 2025-12-21 12:36:11 +08:00
parent 1a931b76bd
commit 4169045fa4
Signed by: jasmine
GPG key ID: 8563E358D4E8040E
19 changed files with 310 additions and 200 deletions

View file

@ -1,4 +1,8 @@
{pkgs, config, ...}: {
{
pkgs,
config,
...
}: {
imports = [
./direnv.nix
./starship.nix
@ -47,10 +51,25 @@
];
# Extra commands that should be added to '.zshrc'
initContent = ''
initContent = /* sh */ ''
bindkey "^[[1;5C" forward-word
bindkey "^[[1;5D" backward-word
export PATH
# Auto-set wezterm tab title based on directory
chpwd() {
if [[ -d .git ]]; then
# Use git repo name
local repo=$(basename $(git rev-parse --show-toplevel 2>/dev/null))
wezterm cli set-tab-title "$repo" 2>/dev/null
elif [[ $(pwd) =~ "/home/sajenim/.repositories/personal/([^/]+)" ]]; then
# Use directory name for project dirs
wezterm cli set-tab-title "''${match[1]}" 2>/dev/null
fi
}
# Run once on shell startup
chpwd
'';
};
}

View file

@ -1,15 +1,8 @@
{
inputs,
pkgs,
...
}: {
{pkgs, ...}: {
imports = [
./cava
./dunst
./mpv
./obs
./picom
./wezterm
];
# Install some packages for our desktop environment
@ -22,26 +15,4 @@
# KDE Packages
kdePackages.kdenlive
];
home.file = {
# Install patched fonts
".local/share/fonts" = {
recursive = true;
source = "${inputs.self}/pkgs/patched-fonts";
};
# https://www.sainnhe.dev/post/patch-fonts-with-cursive-italic-styles/
# Configure the initialization of xinit
".xinitrc".source = ./xinitrc;
};
# Configure GTK 2/3 applications to use gruvbox-material
gtk = {
enable = true;
theme = {
name = "Gruvbox-Material-Dark";
package = pkgs.unstable.gruvbox-material-gtk-theme;
};
iconTheme.name = "Gruvbox-Material-Dark";
};
}

View file

@ -1,31 +0,0 @@
{...}: {
services.dunst = {
enable = true;
settings = {
global = {
width = 300;
height = 300;
origin = "top-right";
offset = "20x20";
frame_width = 5;
frame_color = "#32302f";
corner_radius = 10;
};
urgency_low = {
background = "#282828";
foreground = "#d4be98";
};
urgency_normal = {
background = "#282828";
foreground = "#d4be98";
};
urgency_critical = {
background = "#282828";
foreground = "#d4be98";
};
};
};
}

View file

@ -1,10 +0,0 @@
{...}: {
services.picom = {
enable = true;
shadow = true;
shadowExclude = [
"class_g = 'dmenu'"
];
backend = "xrender";
};
}

View file

@ -1,50 +0,0 @@
{pkgs, ...}: {
programs.wezterm = {
enable = true;
package = pkgs.unstable.wezterm;
# Enable our shell integrations
enableZshIntegration = true;
# Install our theme
colorSchemes = {
gruvbox_material_dark_medium = {
background = "#282828"; # bg0
foreground = "#D4BE98"; # fg0
selection_bg = "#3C3836"; # bg_current_word
selection_fg = "#A89984"; # grey2
cursor_bg = "#A89984"; # bg_current_word
cursor_fg = "#3C3836"; # grey2
cursor_border = "#A89984"; # grey2
ansi = [
"#282828" # bg0
"#EA6962" # red
"#A9B665" # green
"#D8A657" # yellow
"#7DAEA3" # blue
"#D3869B" # purple
"#89B482" # aqua
"#D4BE98" # fg0
];
brights = [
"#7C6F65" # grey0
"#EA6962" # red
"#A9B665" # green
"#D8A657" # yellow
"#7DAEA3" # blue
"#D3869B" # purple
"#89B482" # aqua
"#DDC7A1" # fg1
];
};
# https://github.com/sainnhe/gruvbox-material
};
# Load our wezterm configuration
extraConfig = builtins.readFile ./wezterm.lua;
};
}

View file

@ -1,262 +0,0 @@
-- Pull in the wezterm API
local wezterm = require("wezterm")
-- Log warnings or generate errors if we define an invalid configuration option
local config = wezterm.config_builder()
--
-- General configuration options.
--
-- Do not check for or show window with update information
config.check_for_updates = false
-- Improve wezterm graphical performance
config.front_end = "OpenGL"
config.max_fps = 144
config.animation_fps = 144
-- Font configuration
config.font = wezterm.font("Fisa Code")
config.font_size = 10.0
-- Enable gruvbox colour scheme
config.color_scheme = "gruvbox_material_dark_medium"
-- Pad window borders
config.window_padding = {
left = 10,
right = 10,
top = 10,
bottom = 10,
}
--
-- Tab bar configuration options.
--
-- Disable modern tab bar
config.use_fancy_tab_bar = false
config.tab_max_width = 32
-- Tab bar colors
config.colors = {
tab_bar = {
background = "#32302f",
active_tab = {
bg_color = "#32302f",
fg_color = "#7daea3",
intensity = "Bold",
italic = true,
},
inactive_tab = {
bg_color = "#32302f",
fg_color = "#a89984",
intensity = "Bold",
italic = true,
},
inactive_tab_hover = {
bg_color = "#32302f",
fg_color = "#a89984",
intensity = "Bold",
italic = true,
},
new_tab = {
bg_color = "#32302f",
fg_color = "#a89984",
intensity = "Bold",
italic = true,
},
new_tab_hover = {
bg_color = "#32302f",
fg_color = "#a89984",
intensity = "Bold",
italic = true,
},
},
}
--
-- Keymaps configuration.
--
-- Disable the default keybindings
config.disable_default_key_bindings = true
-- Setup leader key
config.leader = { key = "a", mods = "ALT", timeout_milliseconds = 2000 }
-- General keymaps
config.keys = {
--
-- Enter key table modes
--
{ -- Enter tab management mode
key = "t",
mods = "LEADER",
action = wezterm.action.ActivateKeyTable({
name = "tab_mode",
one_shot = true,
}),
},
{ -- Enter pane management mode
key = "p",
mods = "LEADER",
action = wezterm.action.ActivateKeyTable({
name = "pane_mode",
one_shot = true,
}),
},
--
-- Navigation
--
{ -- Focus previous tab
key = "LeftArrow",
mods = "ALT",
action = wezterm.action.ActivateTabRelative(-1),
},
{ -- Focus next tab
key = "RightArrow",
mods = "ALT",
action = wezterm.action.ActivateTabRelative(1),
},
{ -- Focus previous pane
key = "UpArrow",
mods = "ALT",
action = wezterm.action.ActivatePaneDirection("Prev"),
},
{ -- Focus next pane
key = "DownArrow",
mods = "ALT",
action = wezterm.action.ActivatePaneDirection("Next"),
},
{ -- Focus largest (master) pane
key = "Delete",
mods = "ALT",
action = wezterm.action_callback(function(window, pane)
local tab = window:active_tab()
local largest = nil
local largest_size = 0
for _, p in ipairs(tab:panes()) do
local dims = p:get_dimensions()
local size = dims.pixel_width * dims.pixel_height
if size > largest_size then
largest_size = size
largest = p
end
end
if largest and largest:pane_id() ~= pane:pane_id() then
largest:activate()
end
end),
},
--
-- Copy / Paste
--
{ -- Enter copy mode
key = "Escape",
mods = "LEADER",
action = wezterm.action.ActivateCopyMode,
},
{ -- Paste from clipboard
key = "v",
mods = "CTRL|SHIFT",
action = wezterm.action.PasteFrom("Clipboard"),
},
--
-- Miscellaneous
--
{ -- This lets us unify delete word across programs
key = "Backspace",
mods = "CTRL",
action = wezterm.action.SendKey({ key = "w", mods = "CTRL" }),
},
}
--
-- Key table definitions for modal keybinding namespaces
--
config.key_tables = {
-- Tab management mode (LEADER + t)
tab_mode = {
{ -- Create new tab
key = "n",
action = wezterm.action.SpawnTab("CurrentPaneDomain"),
},
{ -- Close current tab
key = "q",
action = wezterm.action.CloseCurrentTab({ confirm = false }),
},
{ -- Rename current tab
key = "r",
action = wezterm.action_callback(function(window, pane)
local success, stdout, stderr = wezterm.run_child_process({
"dmenu",
"-fn",
"Fisa Code-10",
"-p",
"Tab name:",
})
if success and stdout then
local name = stdout:gsub("\n", "")
if name ~= "" then
window:active_tab():set_title(name)
end
end
end),
},
},
-- Pane management mode (LEADER + p)
pane_mode = {
{ -- Split pane vertically (bottom, 30%)
key = "s",
action = wezterm.action.SplitPane({
direction = "Down",
size = { Percent = 30 },
}),
},
{ -- Split pane horizontally (left, 28%)
key = "v",
action = wezterm.action.SplitPane({
direction = "Left",
size = { Percent = 28 },
}),
},
{ -- Close current pane
key = "q",
action = wezterm.action.CloseCurrentPane({ confirm = false }),
},
{ -- Maximize/zoom pane
key = "m",
action = wezterm.action.TogglePaneZoomState,
},
},
}
-- Jump to specific tabs by number (ALT + 1-9)
for i = 1, 9 do
table.insert(config.keys, {
key = tostring(i),
mods = "ALT",
action = wezterm.action.ActivateTab(i - 1),
})
end
return config

View file

@ -1,22 +0,0 @@
#/bin/bash
# Setup our monitors
xrandr --output HDMI-A-0 --mode 1920x1080 --output DisplayPort-0 --mode 2560x1440 --right-of HDMI-A-0
# Apply our wallpaper
feh --bg-center ~/.repositories/personal/nix-config/assets/chinatown.png
# Disable screen saver and DPMS features
xset s off -dpms
# Start our notification daemon
dunst &
# Enable our compositor
picom -b
# Fix for pinentry bug on NixOS
gpgconf --reload gpg-agent
# Launch our window manager
exec xmonad

View file

@ -1,6 +1,12 @@
{...}: {
{inputs, ...}: {
imports = [
# Global home-manager configuration
./global
# Desktop environment (wezterm, picom, dunst, xinitrc)
"${inputs.self}/nixos/common/users/sajenim/jade/home.nix"
# Optional user features and applications
./features/cli
./features/desktop
./features/editors