From c5caa9e9c5173000f22e5c4fccb36a3be113f79d Mon Sep 17 00:00:00 2001 From: elwrcl Date: Sun, 11 Oct 2026 00:03:10 +0300 Subject: [PATCH] theme --- modules/home/theme/home-theme-kemuri.ulu.nix | 24 + .../home/theme/home-theme-mode-switch.ulu.nix | 42 ++ .../home/theme/home-theme-obsidian.ulu.nix | 63 +++ modules/home/theme/home-theme-qt.ulu.nix | 422 ++++++++++-------- .../home/theme/home-theme-sidechery.ulu.nix | 53 +++ modules/home/theme/home-theme-stylus.ulu.nix | 66 +++ modules/home/theme/home-theme.ulu.nix | 8 + 7 files changed, 480 insertions(+), 198 deletions(-) create mode 100644 modules/home/theme/home-theme-mode-switch.ulu.nix create mode 100644 modules/home/theme/home-theme-obsidian.ulu.nix create mode 100644 modules/home/theme/home-theme-sidechery.ulu.nix create mode 100644 modules/home/theme/home-theme-stylus.ulu.nix diff --git a/modules/home/theme/home-theme-kemuri.ulu.nix b/modules/home/theme/home-theme-kemuri.ulu.nix index ffe060e..98865cd 100644 --- a/modules/home/theme/home-theme-kemuri.ulu.nix +++ b/modules/home/theme/home-theme-kemuri.ulu.nix @@ -27,5 +27,29 @@ accent = "cabaaa"; }; + elars.theme.paletteLight = inputs.themes.custom { + name = "Kemuri Susu Light"; + author = "elars"; + + base00 = "d4c1a8"; # mSurface + base01 = "c5b29a"; # mSurfaceVariant + base02 = "a89682"; # mOutline + base03 = "736c5f"; # mShadow + base04 = "736b5e"; # mSecondary + base05 = "262524"; # mOnSurface + base06 = "3a3734"; + base07 = "1e1d1b"; + + base08 = "b84242"; # red / mError + base09 = "9c7a4a"; # orange + base0A = "8a7140"; # yellow + base0B = "5e7a5c"; # green + base0C = "4f7a70"; # cyan + base0D = "4f6875"; # blue + base0E = "85606b"; # magenta + base0F = "594f46"; # brown + + accent = "262524"; # mPrimary + }; }; } diff --git a/modules/home/theme/home-theme-mode-switch.ulu.nix b/modules/home/theme/home-theme-mode-switch.ulu.nix new file mode 100644 index 0000000..1d0699f --- /dev/null +++ b/modules/home/theme/home-theme-mode-switch.ulu.nix @@ -0,0 +1,42 @@ +{ ... }: +{ + flake.homeModules.home-theme-mode-switch = + { + config, + lib, + pkgs, + ... + }: + let + variants = "${config.xdg.configHome}/elars-theme"; + current = "${config.xdg.stateHome}/elars-theme/current"; + + switch = pkgs.writeShellScript "elars-theme-mode" '' + mode="''${1:-''${NOCTALIA_THEME_MODE:-dark}}" + [ "$mode" = light ] || mode=dark + ${lib.getExe' pkgs.coreutils "mkdir"} -p "$(${lib.getExe' pkgs.coreutils "dirname"} ${lib.escapeShellArg current})" + ${lib.getExe' pkgs.coreutils "ln"} -sfn ${lib.escapeShellArg variants}/"$mode" ${lib.escapeShellArg current} + ''; + in + { + options.elars.theme.currentVariantDir = lib.mkOption { + type = lib.types.str; + readOnly = true; + default = current; + description = '' + Directory holding the active variant's files; point configs here + instead of at a fixed dark/light file. + ''; + }; + + config = { + programs.noctalia.settings.hooks.theme_mode_changed = "${switch}"; + + home.activation.elarsThemeMode = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + if [ ! -e ${lib.escapeShellArg current} ]; then + run ${switch} ${config.programs.noctalia.settings.theme.mode or "dark"} + fi + ''; + }; + }; +} diff --git a/modules/home/theme/home-theme-obsidian.ulu.nix b/modules/home/theme/home-theme-obsidian.ulu.nix new file mode 100644 index 0000000..c4a1d59 --- /dev/null +++ b/modules/home/theme/home-theme-obsidian.ulu.nix @@ -0,0 +1,63 @@ +{ ... }: +{ + flake.homeModules.home-theme-obsidian = + { config, ... }: + let + p = config.elars.theme.palette.withHashtag; + accent = p.accent or p.base06; + in + { + programs.obsidian.defaultSettings = { + appearance = { + theme = "obsidian"; + accentColor = accent; + baseFontSize = 15; + monospaceFontFamily = "JetBrainsMono Nerd Font Mono"; + enabledCssSnippets = [ "kemuri" ]; + }; + cssSnippets = [ + { + name = "kemuri"; + text = '' + /* generated from elars.theme.palette */ + .theme-dark { + --background-primary: ${p.base00}; + --background-primary-alt: ${p.base01}; + --background-secondary: ${p.base01}; + --background-secondary-alt: ${p.base02}; + --background-modifier-border: ${p.base02}; + --background-modifier-hover: ${p.base02}; + --text-normal: ${p.base05}; + --text-muted: ${p.base04}; + --text-faint: ${p.base03}; + --text-accent: ${accent}; + --text-on-accent: ${p.base00}; + --interactive-accent: ${accent}; + --text-selection: ${p.base02}; + --color-red: ${p.base08}; + --color-orange: ${p.base09}; + --color-yellow: ${p.base0A}; + --color-green: ${p.base0B}; + --color-cyan: ${p.base0C}; + --color-blue: ${p.base0D}; + --color-purple: ${p.base0E}; + } + + body { + --radius-s: 0px; + --radius-m: 0px; + --radius-l: 0px; + --radius-xl: 0px; + --input-radius: 0px; + --button-radius: 0px; + --checkbox-radius: 0px; + --tab-radius: 0px; + --shadow-s: none; + --shadow-l: none; + } + ''; + } + ]; + }; + }; +} diff --git a/modules/home/theme/home-theme-qt.ulu.nix b/modules/home/theme/home-theme-qt.ulu.nix index 2516165..8d43f7f 100644 --- a/modules/home/theme/home-theme-qt.ulu.nix +++ b/modules/home/theme/home-theme-qt.ulu.nix @@ -8,109 +8,206 @@ ... }: let - p = config.elars.theme.palette; - h = p.withHashtag; rgb = hex: lib.concatMapStringsSep "," toString (config.elars.theme.hexToRgb hex); - accent = p.accent or p.base06; - foregrounds = { - Normal = p.base05; - Inactive = p.base04; - Active = accent; - Link = p.base0C; - Visited = p.base0E; - Negative = p.base08; - Neutral = p.base0A; - Positive = p.base0B; - }; - - colorSet = - name: - { - background, - alternate, - normal ? foregrounds.Normal, - inactive ? foregrounds.Inactive, - }: - let - fg = foregrounds // { - Normal = normal; - Inactive = inactive; - }; - in - '' - [Colors:${name}] - BackgroundNormal=${rgb background} - BackgroundAlternate=${rgb alternate} - DecorationFocus=${rgb accent} - DecorationHover=${rgb p.base03} - ForegroundActive=${rgb fg.Active} - ForegroundInactive=${rgb fg.Inactive} - ForegroundLink=${rgb fg.Link} - ForegroundNegative=${rgb fg.Negative} - ForegroundNeutral=${rgb fg.Neutral} - ForegroundNormal=${rgb fg.Normal} - ForegroundPositive=${rgb fg.Positive} - ForegroundVisited=${rgb fg.Visited} - ''; - - qtctColors = - { - text, - window, - base, - alternateBase, - button, - buttonText, - bright, - shadow, - }: - builtins.concatStringsSep ", " [ - text # WindowText - button # Button - h.base03 # Light - h.base02 # Midlight - shadow # Dark - h.base03 # Mid - buttonText # Text - bright # BrightText - buttonText # ButtonText - base # Base - window # Window - shadow # Shadow - h.base03 # Highlight - bright # HighlightedText - h.base0C # Link - h.base0E # LinkVisited - alternateBase # AlternateBase - h.base01 # NoRole - h.base01 # ToolTipBase - text # ToolTipText - h.base04 # PlaceholderText - ]; - - active = qtctColors { - text = h.base05; - window = h.base01; - base = h.base00; - alternateBase = h.base01; - button = h.base02; - buttonText = h.base05; - bright = h.base07; - shadow = h.base00; - }; - - disabled = qtctColors { - text = h.base04; - window = h.base01; - base = h.base00; - alternateBase = h.base01; - button = h.base01; - buttonText = h.base04; - bright = h.base06; - shadow = h.base00; - }; - font = "JetBrainsMono Nerd Font,11,-1,5,50,0,0,0,0,0"; + + # qt6ct colour scheme + kdeglobals for one palette. + variant = + p: + let + h = p.withHashtag; + selection = if p.isLight then p.base02 else p.base03; + accent = p.accent or p.base06; + foregrounds = { + Normal = p.base05; + Inactive = p.base04; + Active = accent; + Link = p.base0C; + Visited = p.base0E; + Negative = p.base08; + Neutral = p.base0A; + Positive = p.base0B; + }; + + colorSet = + name: + { + background, + alternate, + normal ? foregrounds.Normal, + inactive ? foregrounds.Inactive, + }: + let + fg = foregrounds // { + Normal = normal; + Inactive = inactive; + }; + in + '' + [Colors:${name}] + BackgroundNormal=${rgb background} + BackgroundAlternate=${rgb alternate} + DecorationFocus=${rgb accent} + DecorationHover=${rgb p.base03} + ForegroundActive=${rgb fg.Active} + ForegroundInactive=${rgb fg.Inactive} + ForegroundLink=${rgb fg.Link} + ForegroundNegative=${rgb fg.Negative} + ForegroundNeutral=${rgb fg.Neutral} + ForegroundNormal=${rgb fg.Normal} + ForegroundPositive=${rgb fg.Positive} + ForegroundVisited=${rgb fg.Visited} + ''; + + qtctColors = + { + text, + window, + base, + alternateBase, + button, + buttonText, + bright, + shadow, + }: + builtins.concatStringsSep ", " [ + text # WindowText + button # Button + h.base03 # Light + h.base02 # Midlight + shadow # Dark + h.base03 # Mid + buttonText # Text + bright # BrightText + buttonText # ButtonText + base # Base + window # Window + shadow # Shadow + "#${selection}" # Highlight + bright # HighlightedText + h.base0C # Link + h.base0E # LinkVisited + alternateBase # AlternateBase + h.base01 # NoRole + h.base01 # ToolTipBase + text # ToolTipText + h.base04 # PlaceholderText + ]; + + active = qtctColors { + text = h.base05; + window = h.base01; + base = h.base00; + alternateBase = h.base01; + button = h.base02; + buttonText = h.base05; + bright = h.base07; + shadow = h.base00; + }; + + disabled = qtctColors { + text = h.base04; + window = h.base01; + base = h.base00; + alternateBase = h.base01; + button = h.base01; + buttonText = h.base04; + bright = h.base06; + shadow = h.base00; + }; + + in + { + qt6ctColors = '' + [ColorScheme] + active_colors=${active} + inactive_colors=${active} + disabled_colors=${disabled} + ''; + + kdeglobals = '' + [General] + ColorScheme=${p.name} + Name=${p.name} + font=${font} + fixed=${font} + menuFont=${font} + toolBarFont=${font} + smallestReadableFont=JetBrainsMono Nerd Font,9,-1,5,50,0,0,0,0,0 + + [Icons] + Theme=int_nord + + [KDE] + widgetStyle=Fusion + contrast=4 + + ${colorSet "Window" { + background = p.base01; + alternate = p.base02; + }} + ${colorSet "View" { + background = p.base00; + alternate = p.base01; + }} + ${colorSet "Button" { + background = p.base02; + alternate = p.base01; + }} + ${colorSet "Header" { + background = p.base01; + alternate = p.base02; + }} + ${colorSet "Header][Inactive" { + background = p.base00; + alternate = p.base01; + normal = p.base04; + }} + ${colorSet "Tooltip" { + background = p.base01; + alternate = p.base02; + }} + ${colorSet "Complementary" { + background = p.base00; + alternate = p.base01; + }} + ${colorSet "Selection" { + background = selection; + alternate = selection; + normal = p.base07; + inactive = p.base06; + }} + + [WM] + activeBackground=${rgb p.base02} + activeBlend=${rgb p.base02} + activeForeground=${rgb p.base05} + inactiveBackground=${rgb p.base01} + inactiveBlend=${rgb p.base01} + inactiveForeground=${rgb p.base04} + + [ColorEffects:Disabled] + Color=${rgb p.base01} + ColorAmount=0 + ColorEffect=0 + ContrastAmount=0.65 + ContrastEffect=1 + IntensityAmount=0.1 + IntensityEffect=2 + + [ColorEffects:Inactive] + ChangeSelectionColor=true + Color=${rgb p.base02} + ColorAmount=0.025 + ColorEffect=2 + ContrastAmount=0.1 + ContrastEffect=2 + IntensityAmount=0 + IntensityEffect=0 + ''; + }; + + dir = config.elars.theme.currentVariantDir; in { qt = { @@ -122,104 +219,33 @@ pkgs.qt6Packages.qt6ct ]; - xdg.configFile."qt6ct/colors/kemuri.conf".text = '' - [ColorScheme] - active_colors=${active} - inactive_colors=${active} - disabled_colors=${disabled} - ''; + # Both variants are generated; home-theme-mode-switch picks one. + xdg.configFile = lib.mkMerge [ + (lib.concatMapAttrs + (mode: palette: { + "elars-theme/${mode}/qt6ct-colors.conf".text = (variant palette).qt6ctColors; + "elars-theme/${mode}/kdeglobals".text = (variant palette).kdeglobals; + }) + { + dark = config.elars.theme.palette; + light = config.elars.theme.paletteLight; + } + ) + { + "kdeglobals".source = config.lib.file.mkOutOfStoreSymlink "${dir}/kdeglobals"; + "qt6ct/qt6ct.conf".text = '' + [Appearance] + style=Fusion + custom_palette=true + color_scheme_path=${dir}/qt6ct-colors.conf + standard_dialogs=default - xdg.configFile."qt6ct/qt6ct.conf".text = '' - [Appearance] - style=Fusion - custom_palette=true - color_scheme_path=${config.xdg.configHome}/qt6ct/colors/kemuri.conf - standard_dialogs=default + [Fonts] + fixed="${font}" + general="${font}" + ''; + } + ]; - [Fonts] - fixed="${font}" - general="${font}" - ''; - - xdg.configFile."kdeglobals".text = '' - [General] - ColorScheme=${p.name} - Name=${p.name} - font=${font} - fixed=${font} - menuFont=${font} - toolBarFont=${font} - smallestReadableFont=JetBrainsMono Nerd Font,9,-1,5,50,0,0,0,0,0 - - [Icons] - Theme=int_nord - - [KDE] - widgetStyle=Fusion - contrast=4 - - ${colorSet "Window" { - background = p.base01; - alternate = p.base02; - }} - ${colorSet "View" { - background = p.base00; - alternate = p.base01; - }} - ${colorSet "Button" { - background = p.base02; - alternate = p.base01; - }} - ${colorSet "Header" { - background = p.base01; - alternate = p.base02; - }} - ${colorSet "Header][Inactive" { - background = p.base00; - alternate = p.base01; - normal = p.base04; - }} - ${colorSet "Tooltip" { - background = p.base01; - alternate = p.base02; - }} - ${colorSet "Complementary" { - background = p.base00; - alternate = p.base01; - }} - ${colorSet "Selection" { - background = p.base03; - alternate = p.base03; - normal = p.base07; - inactive = p.base06; - }} - - [WM] - activeBackground=${rgb p.base02} - activeBlend=${rgb p.base02} - activeForeground=${rgb p.base05} - inactiveBackground=${rgb p.base01} - inactiveBlend=${rgb p.base01} - inactiveForeground=${rgb p.base04} - - [ColorEffects:Disabled] - Color=${rgb p.base01} - ColorAmount=0 - ColorEffect=0 - ContrastAmount=0.65 - ContrastEffect=1 - IntensityAmount=0.1 - IntensityEffect=2 - - [ColorEffects:Inactive] - ChangeSelectionColor=true - Color=${rgb p.base02} - ColorAmount=0.025 - ColorEffect=2 - ContrastAmount=0.1 - ContrastEffect=2 - IntensityAmount=0 - IntensityEffect=0 - ''; }; } diff --git a/modules/home/theme/home-theme-sidechery.ulu.nix b/modules/home/theme/home-theme-sidechery.ulu.nix new file mode 100644 index 0000000..de7f6fd --- /dev/null +++ b/modules/home/theme/home-theme-sidechery.ulu.nix @@ -0,0 +1,53 @@ +{ ... }: +{ + # Baked into the sidechery build (see home-browser-helium-sidechery). + flake.homeModules.home-theme-sidechery = + { config, ... }: + let + p = config.elars.theme.palette.withHashtag; + accent = p.accent or p.base06; + in + { + elars.sidechery.extraCss = '' + /* generated from elars.theme.palette */ + #root.root { + --frame-bg: ${p.base00}; + --toolbar-bg: ${p.base01}; + --s-accent: ${accent}; + + --nav-btn-active-shadow: inset 0 0 0 1px ${accent}; + --nav-btn-len-margin: 2px; + --tabs-border-radius: 0px; + } + + [data-color=red] { --color: ${p.base08}; } + [data-color=orange] { --color: ${p.base09}; } + [data-color=yellow] { --color: ${p.base0A}; } + [data-color=green] { --color: ${p.base0B}; } + [data-color=cyan], + [data-color=turquoise] { --color: ${p.base0C}; } + [data-color=blue] { --color: ${p.base0D}; } + [data-color=purple] { --color: ${p.base0E}; } + [data-color=pink] { --color: color-mix(in oklab, white 25%, ${p.base0E}); } + [data-color=gray] { --color: ${p.base04}; } + + .Tab[data-pin=false] .fav { + margin: 0 var(--tabs-inner-gap) 0 var(--tabs-inner-gap); + } + + .NavigationBar, + .NavigationBar .nav-item { + border-radius: 0px; + } + + .top-horizontal-box { + margin-bottom: 2px; + margin-left: 2px; + } + + .NavigationBar .nav-item .len { + font-size: .5rem; + } + ''; + }; +} diff --git a/modules/home/theme/home-theme-stylus.ulu.nix b/modules/home/theme/home-theme-stylus.ulu.nix new file mode 100644 index 0000000..0248b8d --- /dev/null +++ b/modules/home/theme/home-theme-stylus.ulu.nix @@ -0,0 +1,66 @@ +{ ... }: +{ + flake.homeModules.home-theme-stylus = + { config, ... }: + let + p = config.elars.theme.palette.withHashtag; + accent = p.accent or p.base06; + in + { + xdg.configFile."stylus/kemuri.user.css".text = '' + /* ==UserStyle== + @name Kemuri (square) + @namespace copland + @version 1.0.0 + @description Square corners, no shadows, kemuri palette. Generated from elars.theme.palette. + @author elars + ==/UserStyle== */ + + @-moz-document regexp(".*") { + * { + border-radius: 0px !important; + box-shadow: none !important; + + --dt-black: ${p.base00}; + --dt-gray-0: ${p.base00}; + --dt-gray-1: ${p.base01}; + --dt-gray-2: ${p.base02}; + --dt-gray-3: ${p.base03}; + --dt-gray-4: ${p.base0F}; + --dt-gray-5: ${p.base04}; + --dt-gray-6: ${p.base04}; + --dt-gray-7: ${p.base06}; + --dt-gray-8: ${p.base06}; + --dt-gray-9: ${p.base05}; + --dt-gray-10: ${p.base05}; + --dt-white: ${p.base07}; + --dt-red-6: ${p.base08}; + --dt-red-7: ${p.base08}; + --dt-orange-6: ${p.base09}; + --dt-orange-7: ${p.base09}; + --dt-yellow: ${p.base0A}; + --dt-green-6: ${p.base0B}; + --dt-green-7: ${p.base0B}; + --dt-cyan-6: ${p.base0C}; + --dt-cyan-7: ${p.base0C}; + --dt-blue-6: ${p.base0D}; + --dt-blue-7: ${p.base0D}; + --dt-blue-8: ${p.base0D}; + --dt-magenta-7: ${p.base0E}; + --dt-magenta-8: ${p.base0E}; + } + + html { + accent-color: ${accent}; + caret-color: ${accent}; + scrollbar-color: ${p.base03} transparent; + } + + ::selection { + background: ${accent}; + color: ${p.base00}; + } + } + ''; + }; +} diff --git a/modules/home/theme/home-theme.ulu.nix b/modules/home/theme/home-theme.ulu.nix index 11663a9..1d155bd 100644 --- a/modules/home/theme/home-theme.ulu.nix +++ b/modules/home/theme/home-theme.ulu.nix @@ -39,6 +39,14 @@ ''; }; + options.elars.theme.paletteLight = lib.mkOption { + type = lib.types.raw; + description = '' + Light variant of `elars.theme.palette`, used by consumers that + follow the noctalia light/dark mode (see home-theme-mode-switch). + ''; + }; + options.elars.theme.hexToRgb = lib.mkOption { type = lib.types.raw; default =