Theme Eclipse desktop with Miku Frost palette and glass surfaces

This commit is contained in:
Chest authored and Sweetbread committed 2026-11-13 00:06:31 +03:00
1 parent d414b3fe6a
commit 72c85c59ff
4 files changed
+296 -29

No files matched your search

+17
View File
@@ -8,6 +8,23 @@ let
}; };
in { in {
wayland.windowManager.hyprland.settings = { wayland.windowManager.hyprland.settings = {
# Keep the animated wallpaper visible through the panel's translucent surface.
layer_rule = [
{
match.namespace = "^waybar$";
blur = true;
# Blur the glass, but exclude its low-alpha CSS shadow from the mask.
ignore_alpha = 0.2;
xray = true;
}
{
match.namespace = "^walker$";
blur = true;
ignore_alpha = 0.08;
xray = true;
}
];
monitor = [ monitor = [
{ {
output = "DP-3"; output = "DP-3";
+35 -1
View File
@@ -1,4 +1,4 @@
{ config, lib, ... }: let { config, lib, osConfig, ... }: let
hyprLua = import ./hyprland/lua.nix { inherit lib; }; hyprLua = import ./hyprland/lua.nix { inherit lib; };
colors = config.lib.stylix.colors.withHashtag; colors = config.lib.stylix.colors.withHashtag;
accent = colors.${config.stylix.accent}; accent = colors.${config.stylix.accent};
@@ -141,6 +141,40 @@ in {
.preview-content.aptpackages { .preview-content.aptpackages {
font-family: "${config.stylix.fonts.monospace.name}"; font-family: "${config.stylix.fonts.monospace.name}";
} }
'' + lib.optionalString (config.home.username == "chest" && osConfig.networking.hostName == "Eclipse") ''
/* Keep the existing layout; let the compositor blur the wallpaper. */
window { background: transparent; }
.box-wrapper {
background: alpha(@surface_color, 0.62);
border: 2px solid alpha(@accent_bg_color, 0.38);
padding: 19px;
box-shadow: none;
}
.input {
background: alpha(${colors.base02}, 0.42);
border-radius: 10px;
}
popover {
background: alpha(@surface_color, 0.86);
border: 2px solid alpha(@accent_bg_color, 0.38);
padding: 9px;
}
/* Paint only the rounded item, never both its row and child. */
child, row,
child:hover, row:hover,
child:selected, row:selected {
background: transparent;
border-radius: 10px;
}
child:hover .item-box,
row:hover .item-box {
background: alpha(@accent_bg_color, 0.12);
}
child:selected .item-box,
row:selected .item-box {
background: alpha(@accent_bg_color, 0.25);
}
''; '';
}; };
}; };
+117 -3
View File
@@ -1,4 +1,29 @@
{ pkgs, config, lib, ... }: let { pkgs, config, lib, osConfig, inputs, ... }: let
mikuFrost = osConfig.networking.hostName == "Eclipse";
colors = config.lib.stylix.colors.withHashtag;
accent = colors.${config.stylix.accent};
# Render the same Stylix templates, changing only native translucency and accent.
kvantumConfig = config.lib.stylix.colors {
template = builtins.readFile "${inputs.stylix}/modules/qt/kvconfig.mustache";
extension = ".kvconfig";
};
kvantumSvg = config.lib.stylix.colors {
template = builtins.readFile "${inputs.stylix}/modules/qt/kvantum.svg.mustache";
extension = ".svg";
};
frostKvantum = pkgs.runCommandLocal "miku-frost-kvantum" {} ''
directory="$out/share/Kvantum/Base16Kvantum"
mkdir -p "$directory"
cp ${kvantumConfig} "$directory/Base16Kvantum.kvconfig"
cp ${kvantumSvg} "$directory/Base16Kvantum.svg"
substituteInPlace "$directory/Base16Kvantum.kvconfig" \
--replace-fail 'translucent_windows=false' 'translucent_windows=true' \
--replace-fail 'blurring=false' 'blurring=true' \
--replace-fail 'reduce_window_opacity=10' 'reduce_window_opacity=18' \
--replace-fail 'highlight.color=${colors.base0E}' 'highlight.color=${accent}'
substituteInPlace "$directory/Base16Kvantum.svg" \
--replace-fail '${colors.base0D}' '${accent}'
'';
miku-cursor = pkgs.stdenv.mkDerivation { miku-cursor = pkgs.stdenv.mkDerivation {
name = "Miku cursor"; name = "Miku cursor";
@@ -86,10 +111,46 @@ in {
hyprland.enable = false; hyprland.enable = false;
waybar.enable = false; waybar.enable = false;
kitty.variant256Colors = true; kitty.variant256Colors = true;
gtk.extraCss = lib.mkIf mikuFrost ''
/* Native background alpha keeps text and controls fully opaque. */
@define-color accent_color ${accent};
@define-color accent_bg_color ${accent};
@define-color theme_selected_bg_color ${accent};
@define-color window_bg_color alpha(${colors.base01}, 0.78);
@define-color view_bg_color alpha(${colors.base00}, 0.48);
@define-color headerbar_bg_color alpha(${colors.base01}, 0.76);
@define-color headerbar_backdrop_color @window_bg_color;
@define-color sidebar_bg_color alpha(${colors.base01}, 0.72);
@define-color sidebar_backdrop_color @window_bg_color;
@define-color dialog_bg_color alpha(${colors.base01}, 0.84);
@define-color popover_bg_color alpha(${colors.base01}, 0.90);
@define-color theme_bg_color @window_bg_color;
@define-color theme_base_color @view_bg_color;
'';
}; };
base16Scheme = "${pkgs.base16-schemes}/share/themes/eris.yaml"; # Keep a file-backed scheme for consumers such as Neofetch.
accent = "base0E"; base16Scheme = if mikuFrost then toString (pkgs.writeText "miku-frost.yaml" ''
scheme: "Miku Frost"
author: "chest"
base00: "101724"
base01: "192534"
base02: "253247"
base03: "47586B"
base04: "93A8BA"
base05: "E1EFF2"
base06: "F1F8F8"
base07: "F9FFFF"
base08: "EF829A"
base09: "F5AB82"
base0A: "EED69A"
base0B: "69DCC7"
base0C: "43D6CD"
base0D: "7BB9E8"
base0E: "B29DF4"
base0F: "E3A8D8"
'') else "${pkgs.base16-schemes}/share/themes/eris.yaml";
accent = if mikuFrost then "base0C" else "base0E";
polarity = "dark"; polarity = "dark";
image = pkgs.fetchurl { image = pkgs.fetchurl {
@@ -132,6 +193,59 @@ in {
}; };
}; };
qt.kvantum.themes = lib.mkIf mikuFrost (lib.mkForce [ frostKvantum ]);
# Notifications share the island's surface and rounded, borderless silhouette.
services.mako.settings = lib.mkIf mikuFrost {
background-color = lib.mkForce "${colors.base01}D9";
text-color = lib.mkForce colors.base05;
border-size = lib.mkForce 0;
border-radius = 22;
padding = "12";
progress-color = lib.mkForce "over ${accent}33";
"urgency=low".background-color = lib.mkForce "${colors.base01}D9";
"urgency=critical" = {
background-color = lib.mkForce "${colors.base01}F0";
text-color = lib.mkForce colors.base08;
};
};
# Yazi uses its own true-colour theme rather than the terminal ANSI palette.
programs.yazi.theme = lib.mkIf mikuFrost {
filetype.rules = lib.mkBefore [
{ url = "*/"; fg = colors.base05; bold = false; }
];
icon.conds = lib.mkBefore [
{ "if" = "dir"; text = ""; fg = accent; }
];
mgr.border_style.fg = lib.mkForce colors.base03;
indicator = {
current = { fg = colors.base05; bg = lib.mkForce colors.base02; };
preview = { fg = colors.base05; bg = lib.mkForce colors.base02; };
};
tabs = {
active = { fg = lib.mkForce colors.base00; bg = lib.mkForce accent; };
inactive = { fg = lib.mkForce colors.base04; bg = lib.mkForce colors.base01; };
};
mode = {
normal_main = { fg = lib.mkForce colors.base00; bg = lib.mkForce accent; };
normal_alt = { fg = lib.mkForce accent; bg = lib.mkForce colors.base01; };
};
input = {
border.fg = lib.mkForce accent;
selected.bg = lib.mkForce colors.base02;
};
pick.border.fg = lib.mkForce accent;
completion.border.fg = lib.mkForce accent;
tasks.border.fg = lib.mkForce accent;
};
# Keep the original terminal glass, with colours inherited from Stylix.
programs.ghostty.themes.stylix = lib.mkIf mikuFrost {
background = lib.mkForce config.lib.stylix.colors.base00;
cursor-color = lib.mkForce config.lib.stylix.colors.base0C;
};
dconf.settings = { dconf.settings = {
"org/gnome/desktop/interface".color-scheme = "prefer-dark"; "org/gnome/desktop/interface".color-scheme = "prefer-dark";
}; };
+127 -25
View File
@@ -5,7 +5,9 @@
pkgs, pkgs,
lib, lib,
... ...
}: { }: let
mikuFrost = osConfig.networking.hostName == "Eclipse";
in {
home.packages = with pkgs; [ home.packages = with pkgs; [
font-awesome font-awesome
nerd-fonts.symbols-only nerd-fonts.symbols-only
@@ -59,11 +61,20 @@
"pulseaudio" "pulseaudio"
"custom/sep-left" "custom/sep-left"
"battery" "battery"
] ++ lib.optional mikuFrost "custom/sep-battery" ++ [
"clock" "clock"
]; ];
}; };
"hyprland/workspaces" = lib.optionalAttrs mikuFrost {
tooltip = false;
};
tray = lib.optionalAttrs mikuFrost {
tooltip = false;
};
cava = { cava = {
bars = 9; bars = 9;
bar_delimiter = 0; bar_delimiter = 0;
@@ -79,6 +90,7 @@
}; };
pulseaudio = { pulseaudio = {
tooltip = !mikuFrost;
format = "{icon} {volume}%"; format = "{icon} {volume}%";
format-icons = { format-icons = {
headphone = ""; headphone = "";
@@ -94,18 +106,20 @@
}; };
mpris = { mpris = {
tooltip = !mikuFrost;
format = "{dynamic}"; format = "{dynamic}";
dynamic-len = if osConfig.host.laptop then 16 else 32; dynamic-len = if osConfig.host.laptop then 16 else 32;
dynamic-order = [ "title" "artist" "album" ]; dynamic-order = [ "title" "artist" "album" ];
}; };
battery = { battery = {
tooltip = !mikuFrost;
interval = 5; interval = 5;
states = { states = {
warning = 30; warning = 30;
critical = 15; critical = 15;
}; };
format = "{icon} {capacity}% | "; format = if mikuFrost then "{icon} {capacity}%" else "{icon} {capacity}% | ";
format-icons = { format-icons = {
default = ["󰂎" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹"]; default = ["󰂎" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹"];
charging = ["󰢟" "󰢜" "󰂆" "󰂇" "󰂈" "󰢝" "󰂉" "󰢞" "󰂊" "󰂋" "󰂅"]; charging = ["󰢟" "󰢜" "󰂆" "󰂇" "󰂈" "󰢝" "󰂉" "󰢞" "󰂊" "󰂋" "󰂅"];
@@ -117,7 +131,17 @@
tooltip = false; tooltip = false;
}; };
# Follow battery visibility; the divider has no hover or click target.
"custom/sep-battery" = {
format = " {} ";
exec = "printf '|'";
tooltip = false;
exec-if = "for battery in /sys/class/power_supply/*; do test \"$(cat \"$battery/type\" 2>/dev/null)\" = Battery && exit 0; done; exit 1";
interval = 5;
};
"keyboard-state" = { "keyboard-state" = {
tooltip = !mikuFrost;
capslock = true; capslock = true;
format = "{icon}"; format = "{icon}";
format-icons = { format-icons = {
@@ -127,6 +151,7 @@
}; };
"hyprland/language" = { "hyprland/language" = {
tooltip = !mikuFrost;
format-en = "en"; format-en = "en";
format-ru = "ru"; format-ru = "ru";
}; };
@@ -146,6 +171,7 @@
}; };
network = { network = {
tooltip = !mikuFrost;
format = "{ifname}"; format = "{ifname}";
format-wifi = " {essid} ({signalStrength}%)"; format-wifi = " {essid} ({signalStrength}%)";
format-ethernet = "{ifname}"; format-ethernet = "{ifname}";
@@ -171,6 +197,7 @@
}; };
cpu = { cpu = {
tooltip = !mikuFrost;
interval = 2; interval = 2;
format = "{usage}% "; format = "{usage}% ";
min-length = 6; min-length = 6;
@@ -188,47 +215,97 @@
style = let style = let
colors = config.lib.stylix.colors.withHashtag; colors = config.lib.stylix.colors.withHashtag;
accent = colors.${config.stylix.accent}; accent = colors.${config.stylix.accent};
themed = frost: original: if mikuFrost then frost else original;
scssFile = pkgs.writeText "waybar.scss" /*scss*/ '' scssFile = pkgs.writeText "waybar.scss" /*scss*/ ''
window#waybar { window#waybar {
background: transparent; background: transparent;
color: ${colors.base05}; color: ${colors.base05};
font-weight: bold; font-weight: bold;
font-size: .85em; font-size: .85em;
& > * { padding: 0 0 6px 0; } & > * { padding: ${themed "0 12px 14px" "0 0 6px 0"}; }
} }
${lib.optionalString mikuFrost /*scss*/ ''
// Only the centered island paints a surface or a shadow.
window#waybar,
window#waybar > box {
background: transparent;
background-image: none;
border: none;
box-shadow: none;
}
''}
.modules-center { .modules-center {
background: ${colors.base01}CC; background: ${themed "rgba(${colors.base01}, 0.58)" "${colors.base01}CC"};
border-radius: 12px; border: none;
border-radius: ${themed "22px" "12px"};
padding: 10px; padding: 10px;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.4); box-shadow: ${themed "0 3px 8px rgba(0, 0, 0, 0.18)" "5px 5px 10px rgba(0, 0, 0, 0.4)"};
} }
#left, #left,
#right, #right,
#center { #center {
background: ${colors.base02}; background: ${themed "rgba(40, 59, 79, 0.68)" colors.base02};
padding: 0 2px; padding: 0 2px;
margin: 0 8px; margin: 0 8px;
border-radius: 8px; border-radius: ${themed "12px" "8px"};
} }
#left { margin-left: 0; } #left { margin-left: 0; }
#right { margin-right: 0; } #right { margin-right: 0; }
#clock { padding-right: 10px; } ${lib.optionalString mikuFrost /*scss*/ ''
// Keep hover surfaces inside the rounded groups.
#language, #keyboard-state, #keyboard-state label,
#cava, #mpris, #tray widget, #tray widget > image,
#network, #custom-mem, #cpu, #temperature,
#pulseaudio, #battery, #clock {
border-radius: 10px;
}
#cava { padding: 0 10px; } #network, #custom-mem, #cpu, #temperature,
#pulseaudio, #battery, #clock {
padding-left: 6px;
padding-right: 6px;
}
// Reserve the same width in active, inactive and hover states.
#workspaces button {
box-shadow: none;
text-shadow: none;
background-image: none;
}
tooltip {
color: ${colors.base05};
background: rgba(25, 37, 52, 0.94);
border: 2px solid rgba(67, 214, 205, 0.38);
border-radius: ${themed "12px" "8px"};
}
tooltip label { padding: 6px; }
''}
#clock { padding-right: ${themed "6px" "10px"}; }
#cava { padding: 0 10px; color: ${themed accent colors.base05}; }
#custom-sep-left,
#custom-sep-battery {
color: ${themed "rgba(147, 168, 186, 0.38)" colors.base05};
background: transparent;
}
#language { padding: 8px; } #language { padding: 8px; }
#workspaces button { #workspaces button {
color: ${colors.base05}; color: ${themed colors.base04 colors.base05};
padding: 0 2px; padding: 0 2px;
border-radius: 999px; border-radius: 999px;
border: 1pt solid transparent; border: 1pt solid transparent;
min-width: 20px; min-width: ${themed "25px" "20px"};
&:hover { background: ${colors.base03}; } &:hover { background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03}; }
&.active { &.active {
background: ${accent}; background: ${accent};
@@ -236,27 +313,50 @@
min-width: 25px; min-width: 25px;
&:hover { &:hover {
border-color: ${accent}; border-color: ${themed "transparent" accent};
background: ${colors.base03}; background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03};
color: ${accent}; color: ${accent};
} }
} }
} }
#mpris { #mpris {
border-radius: 8px; border-radius: ${themed "10px" "8px"};
padding: 4px; // Do not leave a styled placeholder when the player has no text.
&:hover { background: ${colors.base03}; } padding: ${themed "0" "4px"};
border: none;
&:hover { background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03}; }
&.playing { &.playing {
border: 2px solid ${accent}; border: ${themed "none" "2px solid ${accent}"};
padding: 2px; padding: ${themed "0" "2px"};
color: ${themed colors.base0E colors.base05};
} }
} }
${if mikuFrost then /*scss*/ ''
// Each SNI item is one event box containing one image. Paint it once.
#tray > widget {
border: none;
border-radius: 10px;
padding: 0;
background: transparent;
}
#tray > widget:hover {
background: rgba(67, 214, 205, 0.12);
}
#tray > widget > image {
padding: 8px;
margin: 0;
background: transparent;
}
#tray > widget.needs-attention {
background: rgba(245, 171, 130, 0.16);
}
'' else /*scss*/ ''
#tray { #tray {
widget { widget {
border: 1pt solid transparent; border: 1pt solid transparent;
&:hover { background: ${colors.base03}; } &:hover { background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03}; }
& > image { padding: 8px; } & > image { padding: 8px; }
} }
@@ -264,21 +364,23 @@
& > .needs-attention { border-color: ${colors.base09}; } & > .needs-attention { border-color: ${colors.base09}; }
} }
''}
#pulseaudio { #pulseaudio {
&:hover { background: ${colors.base03}; } &:hover { background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03}; }
&.muted { &.muted {
background: ${colors.base08}; background: ${colors.base08};
color: ${colors.base01}; color: ${colors.base01};
&:hover { &:hover {
color: ${colors.base08}; color: ${colors.base08};
background: ${colors.base03}; background: ${themed "rgba(67, 214, 205, 0.12)" colors.base03};
} }
} }
} }
#network { #network {
&:hover { background: ${colors.base02}; } &:hover { background: ${themed "rgba(67, 214, 205, 0.12)" colors.base02}; }
&.disconnected { &.disconnected {
color: ${colors.base00}; color: ${colors.base00};
background: ${colors.base08}; background: ${colors.base08};
@@ -286,7 +388,7 @@
} }
#system .drawer-child > * { #system .drawer-child > * {
margin-right: 4px margin-right: 4px;
} }
#keyboard-state label.locked { #keyboard-state label.locked {