Add Omarchy-style Hyprland desktop for straylight
Ports the classic dotfiles Omarchy setup to a no-home-manager NixOS
system module (configs/omarchy.nix), scoped to straylight only so the
other desktop hosts keep i3.
- Hyprland (programs.hyprland) becomes the default lightdm session; i3
stays enabled and selectable as a fallback.
- Omarchy config layout under ~/.config/{hypr,waybar,rofi,wlogout,
swayosd,alacritty} symlinked from the store; mutable theme/wallpaper
state in ~/.config/omarchy/current.
- omarchy-dots generates 8 themes (hyprland/hyprlock/waybar/rofi/
swayosd/wlogout/alacritty/mako colour files) from each theme's
palette, with wallpapers fetched from the Omarchy v3.8.4 tag.
- Helper scripts: omarchy-theme-set/bg-next/bg-set/apply, omarchy-menu
(rofi power/theme/background menus), waybar toggle, screenshot, lock.
- Shared desktop modules (desktop.nix / desktop-light.nix) untouched.
This commit is contained in:
@@ -0,0 +1,344 @@
|
||||
# Omarchy-style Hyprland desktop (classic dotfiles Omarchy, ported to a
|
||||
# no-home-manager NixOS system module). Imported ONLY by hw/straylight, so
|
||||
# the other desktop hosts (imladris, ono-sendai) keep i3.
|
||||
#
|
||||
# Layout mirrors Omarchy v3:
|
||||
# ~/.config/{hypr,waybar,rofi,wlogout,swayosd,alacritty} -> read-only store links
|
||||
# ~/.local/share/omarchy -> store payload (themes/, bin/)
|
||||
# ~/.config/omarchy/current/ -> mutable state
|
||||
# (theme + background)
|
||||
#
|
||||
# Theme colours are generated at build time from each theme's palette
|
||||
# (Omarchy themes/<name>/colors.toml) into themes/<name>/{hyprland.conf,
|
||||
# hyprlock.conf,waybar.css,rofi.rasi,swayosd.css,wlogout.css,alacritty.toml,
|
||||
# mako.ini}. Wallpapers are fetched from the Omarchy v3.8.4 tag.
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
inherit (lib) mkForce mapAttrsToList concatMapStrings;
|
||||
|
||||
user = "kyle";
|
||||
home = "/home/${user}";
|
||||
omarchyPath = "${home}/.local/share/omarchy";
|
||||
current = "${home}/.config/omarchy/current";
|
||||
defaultTheme = "tokyo-night";
|
||||
|
||||
# ---- Omarchy themes/*/colors.toml ----
|
||||
themes = {
|
||||
tokyo-night = {
|
||||
accent = "#7aa2f7"; cursor = "#c0caf5"; foreground = "#a9b1d6"; background = "#1a1b26";
|
||||
selection_foreground = "#c0caf5"; selection_background = "#7aa2f7";
|
||||
color0 = "#32344a"; color1 = "#f7768e"; color2 = "#9ece6a"; color3 = "#e0af68";
|
||||
color4 = "#7aa2f7"; color5 = "#ad8ee6"; color6 = "#449dab"; color7 = "#787c99";
|
||||
color8 = "#444b6a"; color9 = "#ff7a93"; color10 = "#b9f27c"; color11 = "#ff9e64";
|
||||
color12 = "#7da6ff"; color13 = "#bb9af7"; color14 = "#0db9d7"; color15 = "#acb0d0";
|
||||
};
|
||||
catppuccin = {
|
||||
accent = "#89b4fa"; cursor = "#f5e0dc"; foreground = "#cdd6f4"; background = "#1e1e2e";
|
||||
selection_foreground = "#1e1e2e"; selection_background = "#f5e0dc";
|
||||
color0 = "#45475a"; color1 = "#f38ba8"; color2 = "#a6e3a1"; color3 = "#f9e2af";
|
||||
color4 = "#89b4fa"; color5 = "#f5c2e7"; color6 = "#94e2d5"; color7 = "#bac2de";
|
||||
color8 = "#585b70"; color9 = "#f38ba8"; color10 = "#a6e3a1"; color11 = "#f9e2af";
|
||||
color12 = "#89b4fa"; color13 = "#f5c2e7"; color14 = "#94e2d5"; color15 = "#a6adc8";
|
||||
};
|
||||
gruvbox = {
|
||||
accent = "#7daea3"; cursor = "#bdae93"; foreground = "#d4be98"; background = "#282828";
|
||||
selection_foreground = "#ebdbb2"; selection_background = "#d65d0e";
|
||||
color0 = "#3c3836"; color1 = "#ea6962"; color2 = "#a9b665"; color3 = "#d8a657";
|
||||
color4 = "#7daea3"; color5 = "#d3869b"; color6 = "#89b482"; color7 = "#d4be98";
|
||||
color8 = "#3c3836"; color9 = "#ea6962"; color10 = "#a9b665"; color11 = "#d8a657";
|
||||
color12 = "#7daea3"; color13 = "#d3869b"; color14 = "#89b482"; color15 = "#d4be98";
|
||||
};
|
||||
kanagawa = {
|
||||
accent = "#7e9cd8"; cursor = "#c8c093"; foreground = "#dcd7ba"; background = "#1f1f28";
|
||||
selection_foreground = "#c8c093"; selection_background = "#2d4f67";
|
||||
color0 = "#090618"; color1 = "#c34043"; color2 = "#76946a"; color3 = "#c0a36e";
|
||||
color4 = "#7e9cd8"; color5 = "#957fb8"; color6 = "#6a9589"; color7 = "#c8c093";
|
||||
color8 = "#727169"; color9 = "#e82424"; color10 = "#98bb6c"; color11 = "#e6c384";
|
||||
color12 = "#7fb4ca"; color13 = "#938aa9"; color14 = "#7aa89f"; color15 = "#dcd7ba";
|
||||
};
|
||||
everforest = {
|
||||
accent = "#7fbbb3"; cursor = "#d3c6aa"; foreground = "#d3c6aa"; background = "#2d353b";
|
||||
selection_foreground = "#2d353b"; selection_background = "#d3c6aa";
|
||||
color0 = "#475258"; color1 = "#e67e80"; color2 = "#a7c080"; color3 = "#dbbc7f";
|
||||
color4 = "#7fbbb3"; color5 = "#d699b6"; color6 = "#83c092"; color7 = "#d3c6aa";
|
||||
color8 = "#475258"; color9 = "#e67e80"; color10 = "#a7c080"; color11 = "#dbbc7f";
|
||||
color12 = "#7fbbb3"; color13 = "#d699b6"; color14 = "#83c092"; color15 = "#d3c6aa";
|
||||
};
|
||||
nord = {
|
||||
accent = "#81a1c1"; cursor = "#d8dee9"; foreground = "#d8dee9"; background = "#2e3440";
|
||||
selection_foreground = "#d8dee9"; selection_background = "#4c566a";
|
||||
color0 = "#3b4252"; color1 = "#bf616a"; color2 = "#a3be8c"; color3 = "#ebcb8b";
|
||||
color4 = "#81a1c1"; color5 = "#b48ead"; color6 = "#88c0d0"; color7 = "#e5e9f0";
|
||||
color8 = "#4c566a"; color9 = "#bf616a"; color10 = "#a3be8c"; color11 = "#ebcb8b";
|
||||
color12 = "#81a1c1"; color13 = "#b48ead"; color14 = "#8fbcbb"; color15 = "#eceff4";
|
||||
};
|
||||
rose-pine = {
|
||||
accent = "#56949f"; cursor = "#cecacd"; foreground = "#575279"; background = "#faf4ed";
|
||||
selection_foreground = "#575279"; selection_background = "#dfdad9";
|
||||
color0 = "#f2e9e1"; color1 = "#b4637a"; color2 = "#286983"; color3 = "#ea9d34";
|
||||
color4 = "#56949f"; color5 = "#907aa9"; color6 = "#d7827e"; color7 = "#575279";
|
||||
color8 = "#9893a5"; color9 = "#b4637a"; color10 = "#286983"; color11 = "#ea9d34";
|
||||
color12 = "#56949f"; color13 = "#907aa9"; color14 = "#d7827e"; color15 = "#575279";
|
||||
};
|
||||
hackerman = {
|
||||
accent = "#82FB9C"; cursor = "#ddf7ff"; foreground = "#ddf7ff"; background = "#0B0C16";
|
||||
selection_foreground = "#0B0C16"; selection_background = "#ddf7ff";
|
||||
color0 = "#3E4058"; color1 = "#50f872"; color2 = "#4fe88f"; color3 = "#50f7d4";
|
||||
color4 = "#829dd4"; color5 = "#86a7df"; color6 = "#7cf8f7"; color7 = "#85E1FB";
|
||||
color8 = "#6a6e95"; color9 = "#85ff9d"; color10 = "#9cf7c2"; color11 = "#a4ffec";
|
||||
color12 = "#c4d2ed"; color13 = "#cddbf4"; color14 = "#d1fffe"; color15 = "#ddf7ff";
|
||||
};
|
||||
};
|
||||
|
||||
# ---- Omarchy themes/<name>/backgrounds/<file> (v3.8.4) ----
|
||||
wallpapers = {
|
||||
tokyo-night = [
|
||||
{ file = "1-sunset-lake.png"; hash = "sha256-Bt+5/OAp7DWttA6jk5KWd3wrFA0SMrWhaXsVBS1XU2I="; }
|
||||
{ file = "2-pawel-czerwinski.jpg"; hash = "sha256-acxN1KQHwH9VRgD549BP7AKTuMiF3dhR/lg+/C6ty1I="; }
|
||||
{ file = "4-oma-cityscape.jpg"; hash = "sha256-IuHWOXIrM/pvDTrCczRQtLrpYbSB9WZcsWOXvF9xTlw="; }
|
||||
];
|
||||
catppuccin = [
|
||||
{ file = "1-totoro.png"; hash = "sha256-O8+rFOjnsEEwfLd9cAxpWRYP5/bV3mMbFb0C3gz42f8="; }
|
||||
{ file = "2-waves.png"; hash = "sha256-VjGQ35WJvrLVEX1A2wLGSSMqtrw8Py622Xqfs1haDP0="; }
|
||||
];
|
||||
gruvbox = [
|
||||
{ file = "1-the-backwater.jpg"; hash = "sha256-E8/GrjcK+YTAioIP+BtWoP67D7/pcSptsSi5TRTsqsY="; }
|
||||
{ file = "4-idyllic-procession.jpg"; hash = "sha256-vgrnMmOl62lBb7E1R4JqYIBoWaoxuwMQU6/HPeYKVcU="; }
|
||||
{ file = "5-leaves.jpg"; hash = "sha256-zb0817NKLI5+dIGK9RAahTF4aHiwo6/Lj2mFsnOU9m0="; }
|
||||
];
|
||||
kanagawa = [
|
||||
{ file = "1-kanagawa.jpg"; hash = "sha256-m4F9cXaIU58NuHYDtmGZKDnDy7XUkYoCpO/AXJ+Isn0="; }
|
||||
];
|
||||
everforest = [
|
||||
{ file = "1-tree-tops.jpg"; hash = "sha256-DwCl4tD3jV51x6L0gQH23uaRecbZTp9OvG+3wPOUYr8="; }
|
||||
];
|
||||
nord = [
|
||||
{ file = "1-city-view.png"; hash = "sha256-sRhvp+5OnZAIe4aTTE3jGoZ9qkojxAGIUYGwe6Ev/3U="; }
|
||||
{ file = "2-night-hawks.png"; hash = "sha256-YaS8ScE3ERId6H9ffyQH/4I1BRzRf5ze1+IOFbGdVpI="; }
|
||||
];
|
||||
rose-pine = [
|
||||
{ file = "1-funky-shapes.jpg"; hash = "sha256-b1qeo9wiP76RBGfMc5Z7pt2ffoCn2Aa8FemFVj0V/gM="; }
|
||||
];
|
||||
hackerman = [
|
||||
{ file = "1-synth-scape.jpg"; hash = "sha256-x9JZSTXyBODfG0Pf56EjieocHT/Y5XqSqfCEl/J6N34="; }
|
||||
];
|
||||
};
|
||||
|
||||
# ---- helpers ----
|
||||
hexDigits = {
|
||||
"0" = 0; "1" = 1; "2" = 2; "3" = 3; "4" = 4; "5" = 5; "6" = 6; "7" = 7;
|
||||
"8" = 8; "9" = 9; "a" = 10; "b" = 11; "c" = 12; "d" = 13; "e" = 14; "f" = 15;
|
||||
};
|
||||
hexToRgb = hex:
|
||||
let
|
||||
s = lib.toLower (lib.removePrefix "#" hex);
|
||||
dig = i: hexDigits.${builtins.substring i 1 s};
|
||||
byte = i: (dig (i * 2)) * 16 + (dig (i * 2 + 1));
|
||||
in "${toString (byte 0)},${toString (byte 1)},${toString (byte 2)}";
|
||||
strip = hex: lib.removePrefix "#" hex;
|
||||
mkFile = name: text: pkgs.writeText name text;
|
||||
|
||||
themeDir = name: t:
|
||||
let
|
||||
bgs = wallpapers.${name} or [ ];
|
||||
hyprlandConf = mkFile "hyprland.conf" ''
|
||||
$activeBorderColor = rgb(${strip t.accent})
|
||||
|
||||
general {
|
||||
col.active_border = $activeBorderColor
|
||||
}
|
||||
|
||||
group {
|
||||
col.border_active = $activeBorderColor
|
||||
}
|
||||
'';
|
||||
hyprlockConf = mkFile "hyprlock.conf" ''
|
||||
$color = rgba(${hexToRgb t.background}, 1.0)
|
||||
$inner_color = rgba(${hexToRgb t.background}, 0.8)
|
||||
$outer_color = rgba(${hexToRgb t.foreground}, 1.0)
|
||||
$font_color = rgba(${hexToRgb t.foreground}, 1.0)
|
||||
$check_color = rgba(${hexToRgb t.accent}, 1.0)
|
||||
'';
|
||||
waybarCss = mkFile "waybar.css" ''
|
||||
@define-color foreground ${t.foreground};
|
||||
@define-color background ${t.background};
|
||||
'';
|
||||
swayosdCss = mkFile "swayosd.css" ''
|
||||
@define-color background ${t.background};
|
||||
@define-color border-color ${t.foreground};
|
||||
@define-color label ${t.foreground};
|
||||
@define-color image ${t.foreground};
|
||||
@define-color progress ${t.accent};
|
||||
'';
|
||||
wlogoutCss = mkFile "wlogout.css" ''
|
||||
@define-color background ${t.background};
|
||||
@define-color foreground ${t.foreground};
|
||||
@define-color accent ${t.accent};
|
||||
'';
|
||||
rofiRasi = mkFile "rofi.rasi" ''
|
||||
* {
|
||||
bg: ${t.background};
|
||||
fg: ${t.foreground};
|
||||
accent: ${t.accent};
|
||||
|
||||
background-color: @bg;
|
||||
text-color: @fg;
|
||||
border: 2px;
|
||||
border-color: @accent;
|
||||
border-radius: 0;
|
||||
padding: 8px;
|
||||
spacing: 6px;
|
||||
font: "JetBrainsMono Nerd Font 12";
|
||||
}
|
||||
|
||||
window { width: 40%; background-color: @bg; border: 2px; border-color: @accent; }
|
||||
inputbar { background-color: @bg; text-color: @fg; }
|
||||
listview { lines: 10; background-color: @bg; }
|
||||
element { padding: 4px; }
|
||||
element selected { background-color: @accent; text-color: @bg; }
|
||||
'';
|
||||
alacrittyToml = mkFile "alacritty.toml" ''
|
||||
[colors.primary]
|
||||
background = "${t.background}"
|
||||
foreground = "${t.foreground}"
|
||||
|
||||
[colors.cursor]
|
||||
text = "${t.background}"
|
||||
cursor = "${t.cursor}"
|
||||
|
||||
[colors.vi_mode_cursor]
|
||||
text = "${t.background}"
|
||||
cursor = "${t.cursor}"
|
||||
|
||||
[colors.selection]
|
||||
text = "${t.selection_foreground}"
|
||||
background = "${t.selection_background}"
|
||||
|
||||
[colors.normal]
|
||||
black = "${t.color0}"
|
||||
red = "${t.color1}"
|
||||
green = "${t.color2}"
|
||||
yellow = "${t.color3}"
|
||||
blue = "${t.color4}"
|
||||
magenta = "${t.color5}"
|
||||
cyan = "${t.color6}"
|
||||
white = "${t.color7}"
|
||||
|
||||
[colors.bright]
|
||||
black = "${t.color8}"
|
||||
red = "${t.color9}"
|
||||
green = "${t.color10}"
|
||||
yellow = "${t.color11}"
|
||||
blue = "${t.color12}"
|
||||
magenta = "${t.color13}"
|
||||
cyan = "${t.color14}"
|
||||
white = "${t.color15}"
|
||||
'';
|
||||
makoIni = mkFile "mako.ini" ''
|
||||
text-color=${t.foreground}
|
||||
border-color=${t.accent}
|
||||
background-color=${t.background}
|
||||
width=420
|
||||
height=110
|
||||
padding=10
|
||||
margin=10
|
||||
border-size=2
|
||||
border-radius=0
|
||||
anchor=top-right
|
||||
layer=overlay
|
||||
default-timeout=5000
|
||||
max-visible=5
|
||||
font=JetBrainsMono Nerd Font 10
|
||||
'';
|
||||
in
|
||||
pkgs.runCommand "omarchy-theme-${name}" { } ''
|
||||
mkdir -p $out/backgrounds
|
||||
cp ${hyprlandConf} $out/hyprland.conf
|
||||
cp ${hyprlockConf} $out/hyprlock.conf
|
||||
cp ${waybarCss} $out/waybar.css
|
||||
cp ${swayosdCss} $out/swayosd.css
|
||||
cp ${wlogoutCss} $out/wlogout.css
|
||||
cp ${rofiRasi} $out/rofi.rasi
|
||||
cp ${alacrittyToml} $out/alacritty.toml
|
||||
cp ${makoIni} $out/mako.ini
|
||||
${concatMapStrings (b: ''
|
||||
cp ${pkgs.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/omacom/omarchy/v3.8.4/themes/${name}/backgrounds/${b.file}";
|
||||
hash = b.hash;
|
||||
}} $out/backgrounds/${b.file}
|
||||
'') bgs}
|
||||
'';
|
||||
|
||||
themesTree = pkgs.linkFarm "omarchy-themes"
|
||||
(mapAttrsToList (n: t: { name = n; path = themeDir n t; }) themes);
|
||||
|
||||
omarchyDots = pkgs.runCommand "omarchy-dots" { } ''
|
||||
mkdir -p $out
|
||||
cp -r ${./omarchy/hypr} $out/hypr
|
||||
cp -r ${./omarchy/waybar} $out/waybar
|
||||
cp -r ${./omarchy/rofi} $out/rofi
|
||||
cp -r ${./omarchy/wlogout} $out/wlogout
|
||||
cp -r ${./omarchy/swayosd} $out/swayosd
|
||||
cp -r ${./omarchy/alacritty} $out/alacritty
|
||||
cp -r ${themesTree} $out/themes
|
||||
'';
|
||||
|
||||
omarchyBin = pkgs.runCommand "omarchy-bin" { } ''
|
||||
mkdir -p $out/bin
|
||||
cp ${./omarchy/bin}/* $out/bin/
|
||||
chmod +x $out/bin/*
|
||||
'';
|
||||
|
||||
polkitAgent = pkgs.writeShellScriptBin "omarchy-polkit-agent" ''
|
||||
exec ${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1
|
||||
'';
|
||||
in
|
||||
{
|
||||
programs.hyprland = {
|
||||
enable = true;
|
||||
systemd.setPath.enable = true;
|
||||
};
|
||||
|
||||
# Hyprland is the default login session. i3 stays enabled (configs/desktop-light.nix)
|
||||
# and remains selectable in lightdm as a fallback.
|
||||
services.displayManager.defaultSession = "hyprland";
|
||||
|
||||
# Hyprland's own portal should be the default (desktop-light.nix sets gtk).
|
||||
xdg.portal = {
|
||||
config.common.default = mkForce "hyprland";
|
||||
extraPortals = [ pkgs.xdg-desktop-portal-hyprland ];
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
omarchyBin
|
||||
polkitAgent
|
||||
waybar rofi wlogout hyprlock hypridle swayosd mako clipse
|
||||
wl-clipboard wl-clip-persist grim slurp hyprpicker
|
||||
brightnessctl pamixer playerctl alacritty swaybg jq
|
||||
gnome-calculator pavucontrol nautilus
|
||||
nerd-fonts.jetbrains-mono
|
||||
];
|
||||
|
||||
# Link the read-only config into ~/.config, seed the mutable theme state, and
|
||||
# resolve the active theme/background symlinks. Runs on every switch/boot.
|
||||
system.activationScripts.omarchy-dots = {
|
||||
deps = [ "users" ];
|
||||
text = ''
|
||||
set -eu
|
||||
export PATH=${lib.makeBinPath [ pkgs.coreutils pkgs.findutils pkgs.bash ]}:$PATH
|
||||
install -d -m0755 -o ${user} -g users ${home}/.config ${home}/.local/share ${current}
|
||||
ln -sfnT ${omarchyDots}/hypr ${home}/.config/hypr
|
||||
ln -sfnT ${omarchyDots}/waybar ${home}/.config/waybar
|
||||
ln -sfnT ${omarchyDots}/rofi ${home}/.config/rofi
|
||||
ln -sfnT ${omarchyDots}/wlogout ${home}/.config/wlogout
|
||||
ln -sfnT ${omarchyDots}/swayosd ${home}/.config/swayosd
|
||||
ln -sfnT ${omarchyDots}/alacritty ${home}/.config/alacritty
|
||||
ln -sfnT ${omarchyDots} ${omarchyPath}
|
||||
[ -f ${current}/theme.name ] || printf '%s\n' ${defaultTheme} > ${current}/theme.name
|
||||
chown -R ${user}:users ${home}/.config/omarchy
|
||||
HOME=${home} OMARCHY_PATH=${omarchyPath} ${omarchyBin}/bin/omarchy-theme-apply
|
||||
chown -h ${user}:users ${current}/theme ${current}/background 2>/dev/null || true
|
||||
'';
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user