From b2ff5f1ae509211112a1672fe55b8cd032b33071 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Tue, 3 Feb 2026 22:01:14 -0800 Subject: [PATCH] hypr: add hyprspace overview and waybar config --- dotfiles/config/hypr/hyprland.conf | 11 + dotfiles/config/waybar/config.jsonc | 85 ++++++++ dotfiles/config/waybar/style.css | 327 ++++++++++++++++++++++++++++ nixos/flake.lock | 71 ++++-- nixos/flake.nix | 6 + nixos/hyprland.nix | 130 +++-------- 6 files changed, 511 insertions(+), 119 deletions(-) create mode 100644 dotfiles/config/waybar/config.jsonc create mode 100644 dotfiles/config/waybar/style.css diff --git a/dotfiles/config/hypr/hyprland.conf b/dotfiles/config/hypr/hyprland.conf index ad03147f..2cfeeb45 100644 --- a/dotfiles/config/hypr/hyprland.conf +++ b/dotfiles/config/hypr/hyprland.conf @@ -7,6 +7,7 @@ # ============================================================================= # Load the plugin before parsing keybinds/layouts that depend on it plugin = /run/current-system/sw/lib/libhy3.so +plugin = /run/current-system/sw/lib/libHyprspace.so # ============================================================================= # MONITORS @@ -237,6 +238,12 @@ $hyper = SUPER CTRL ALT bind = $mainMod, P, exec, $menu bind = $mainMod SHIFT, P, exec, $runMenu bind = $mainMod SHIFT, Return, exec, $terminal + +# ----------------------------------------------------------------------------- +# Overview (Hyprspace) +# ----------------------------------------------------------------------------- +bind = $mainMod, TAB, overview:toggle +bind = $mainMod SHIFT, TAB, overview:toggle, all bind = $mainMod, Q, killactive, bind = $mainMod SHIFT, C, killactive, bind = $mainMod SHIFT, Q, exit, @@ -514,6 +521,10 @@ bind = $mainMod, mouse_up, workspace, e-1 # AUTOSTART # ============================================================================= +# Start Hyprland session target for systemd user services (e.g., waybar) +exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE +exec-once = systemctl --user start hyprland-session.target + # Scratchpad applications (start in special workspaces) exec-once = [workspace special:element silent] element-desktop exec-once = [workspace special:gmail silent] google-chrome-stable --new-window https://mail.google.com/mail/u/0/#inbox diff --git a/dotfiles/config/waybar/config.jsonc b/dotfiles/config/waybar/config.jsonc new file mode 100644 index 00000000..41613af2 --- /dev/null +++ b/dotfiles/config/waybar/config.jsonc @@ -0,0 +1,85 @@ +// -*- mode: jsonc -*- +{ + "height": 30, + "spacing": 4, + "modules-left": [ + "hyprland/workspaces", + "hyprland/submap" + ], + "modules-center": [ + "hyprland/window" + ], + "modules-right": [ + "idle_inhibitor", + "pulseaudio", + "network", + "power-profiles-daemon", + "cpu", + "memory", + "temperature", + "backlight", + "battery", + "clock", + "tray" + ], + "idle_inhibitor": { + "format": "INHIB {icon}", + "format-icons": { + "activated": "ON", + "deactivated": "OFF" + } + }, + "tray": { + "spacing": 10 + }, + "clock": { + "format": "{:%H:%M}", + "tooltip-format": "{:%Y %B}\n{calendar}", + "format-alt": "{:%Y-%m-%d}" + }, + "cpu": { + "format": "CPU {usage}%", + "tooltip": false + }, + "memory": { + "format": "MEM {}%" + }, + "temperature": { + "critical-threshold": 80, + "format": "TEMP {temperatureC}C" + }, + "backlight": { + "format": "BL {percent}%" + }, + "battery": { + "states": { + "warning": 30, + "critical": 15 + }, + "format": "BAT {capacity}%", + "format-full": "BAT {capacity}%", + "format-charging": "BAT {capacity}% charging", + "format-plugged": "BAT {capacity}% plugged", + "format-alt": "BAT {time}" + }, + "power-profiles-daemon": { + "format": "PWR {profile}", + "tooltip-format": "Power profile: {profile}\nDriver: {driver}", + "tooltip": true + }, + "network": { + "format-wifi": "WIFI {essid} {signalStrength}%", + "format-ethernet": "ETH {ipaddr}/{cidr}", + "tooltip-format": "{ifname} via {gwaddr}", + "format-linked": "{ifname} (No IP)", + "format-disconnected": "NET disconnected", + "format-alt": "{ifname}: {ipaddr}/{cidr}" + }, + "pulseaudio": { + "format": "VOL {volume}%", + "format-muted": "VOL muted", + "format-source": "MIC {volume}%", + "format-source-muted": "MIC muted", + "on-click": "pavucontrol" + } +} diff --git a/dotfiles/config/waybar/style.css b/dotfiles/config/waybar/style.css new file mode 100644 index 00000000..7e830285 --- /dev/null +++ b/dotfiles/config/waybar/style.css @@ -0,0 +1,327 @@ +* { + /* `otf-font-awesome` is required to be installed for icons */ + font-family: FontAwesome, Roboto, Helvetica, Arial, sans-serif; + font-size: 13px; +} + +window#waybar { + background-color: rgba(43, 48, 59, 0.5); + border-bottom: 3px solid rgba(100, 114, 125, 0.5); + color: #ffffff; + transition-property: background-color; + transition-duration: .5s; +} + +window#waybar.hidden { + opacity: 0.2; +} + +/* +window#waybar.empty { + background-color: transparent; +} +window#waybar.solo { + background-color: #FFFFFF; +} +*/ + +window#waybar.termite { + background-color: #3F3F3F; +} + +window#waybar.chromium { + background-color: #000000; + border: none; +} + +button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +button:hover { + background: inherit; + box-shadow: inset 0 -3px #ffffff; +} + +/* you can set a style on hover for any module like this */ +#pulseaudio:hover { + background-color: #a37800; +} + +#workspaces button { + padding: 0 5px; + background-color: transparent; + color: #ffffff; +} + +#workspaces button:hover { + background: rgba(0, 0, 0, 0.2); +} + +#workspaces button.focused { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#workspaces button.urgent { + background-color: #eb4d4b; +} + +#mode { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#clock, +#battery, +#cpu, +#memory, +#disk, +#temperature, +#backlight, +#network, +#pulseaudio, +#wireplumber, +#custom-media, +#tray, +#mode, +#idle_inhibitor, +#scratchpad, +#power-profiles-daemon, +#mpd { + padding: 0 10px; + color: #ffffff; +} + +#window, +#workspaces { + margin: 0 4px; +} + +/* If workspaces is the leftmost module, omit left margin */ +.modules-left > widget:first-child > #workspaces { + margin-left: 0; +} + +/* If workspaces is the rightmost module, omit right margin */ +.modules-right > widget:last-child > #workspaces { + margin-right: 0; +} + +#clock { + background-color: #64727D; +} + +#battery { + background-color: #ffffff; + color: #000000; +} + +#battery.charging, #battery.plugged { + color: #ffffff; + background-color: #26A65B; +} + +@keyframes blink { + to { + background-color: #ffffff; + color: #000000; + } +} + +/* Using steps() instead of linear as a timing function to limit cpu usage */ +#battery.critical:not(.charging) { + background-color: #f53c3c; + color: #ffffff; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: steps(12); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#power-profiles-daemon { + padding-right: 15px; +} + +#power-profiles-daemon.performance { + background-color: #f53c3c; + color: #ffffff; +} + +#power-profiles-daemon.balanced { + background-color: #2980b9; + color: #ffffff; +} + +#power-profiles-daemon.power-saver { + background-color: #2ecc71; + color: #000000; +} + +label:focus { + background-color: #000000; +} + +#cpu { + background-color: #2ecc71; + color: #000000; +} + +#memory { + background-color: #9b59b6; +} + +#disk { + background-color: #964B00; +} + +#backlight { + background-color: #90b1b1; +} + +#network { + background-color: #2980b9; +} + +#network.disconnected { + background-color: #f53c3c; +} + +#pulseaudio { + background-color: #f1c40f; + color: #000000; +} + +#pulseaudio.muted { + background-color: #90b1b1; + color: #2a5c45; +} + +#wireplumber { + background-color: #fff0f5; + color: #000000; +} + +#wireplumber.muted { + background-color: #f53c3c; +} + +#custom-media { + background-color: #66cc99; + color: #2a5c45; + min-width: 100px; +} + +#custom-media.custom-spotify { + background-color: #66cc99; +} + +#custom-media.custom-vlc { + background-color: #ffa000; +} + +#temperature { + background-color: #f0932b; +} + +#temperature.critical { + background-color: #eb4d4b; +} + +#tray { + background-color: #2980b9; +} + +#tray > .passive { + -gtk-icon-effect: dim; +} + +#tray > .needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; +} + +#idle_inhibitor { + background-color: #2d3436; +} + +#idle_inhibitor.activated { + background-color: #ecf0f1; + color: #2d3436; +} + +#mpd { + background-color: #66cc99; + color: #2a5c45; +} + +#mpd.disconnected { + background-color: #f53c3c; +} + +#mpd.stopped { + background-color: #90b1b1; +} + +#mpd.paused { + background-color: #51a37a; +} + +#language { + background: #00b093; + color: #740864; + padding: 0 5px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state { + background: #97e1ad; + color: #000000; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state > label { + padding: 0 5px; +} + +#keyboard-state > label.locked { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad.empty { + background-color: transparent; +} + +#privacy { + padding: 0; +} + +#privacy-item { + padding: 0 5px; + color: white; +} + +#privacy-item.screenshare { + background-color: #cf5700; +} + +#privacy-item.audio-in { + background-color: #1ca000; +} + +#privacy-item.audio-out { + background-color: #0069d4; +} diff --git a/nixos/flake.lock b/nixos/flake.lock index f588dd0a..cbf56863 100644 --- a/nixos/flake.lock +++ b/nixos/flake.lock @@ -29,7 +29,7 @@ "railbird-secrets", "nixpkgs" ], - "systems": "systems_11" + "systems": "systems_12" }, "locked": { "lastModified": 1707830867, @@ -405,7 +405,7 @@ }, "flake-utils_10": { "inputs": { - "systems": "systems_12" + "systems": "systems_13" }, "locked": { "lastModified": 1709126324, @@ -423,7 +423,7 @@ }, "flake-utils_11": { "inputs": { - "systems": "systems_14" + "systems": "systems_15" }, "locked": { "lastModified": 1710146030, @@ -441,7 +441,7 @@ }, "flake-utils_12": { "inputs": { - "systems": "systems_15" + "systems": "systems_16" }, "locked": { "lastModified": 1685518550, @@ -459,7 +459,7 @@ }, "flake-utils_13": { "inputs": { - "systems": "systems_16" + "systems": "systems_17" }, "locked": { "lastModified": 1681202837, @@ -515,7 +515,7 @@ }, "flake-utils_4": { "inputs": { - "systems": "systems_5" + "systems": "systems_6" }, "locked": { "lastModified": 1731533236, @@ -533,7 +533,7 @@ }, "flake-utils_5": { "inputs": { - "systems": "systems_6" + "systems": "systems_7" }, "locked": { "lastModified": 1731533236, @@ -551,7 +551,7 @@ }, "flake-utils_6": { "inputs": { - "systems": "systems_7" + "systems": "systems_8" }, "locked": { "lastModified": 1731533236, @@ -569,7 +569,7 @@ }, "flake-utils_7": { "inputs": { - "systems": "systems_8" + "systems": "systems_9" }, "locked": { "lastModified": 1685518550, @@ -587,7 +587,7 @@ }, "flake-utils_8": { "inputs": { - "systems": "systems_9" + "systems": "systems_10" }, "locked": { "lastModified": 1731533236, @@ -605,7 +605,7 @@ }, "flake-utils_9": { "inputs": { - "systems": "systems_10" + "systems": "systems_11" }, "locked": { "lastModified": 1731533236, @@ -1580,6 +1580,27 @@ "type": "github" } }, + "hyprspace": { + "inputs": { + "hyprland": [ + "hyprland" + ], + "systems": "systems_5" + }, + "locked": { + "lastModified": 1767871242, + "narHash": "sha256-Gge7LY1lrPc2knDnyw8GBQ2sxRPzM7W2T6jNG1HY5bA=", + "owner": "KZDKM", + "repo": "Hyprspace", + "rev": "bcd969224ffeb6266c6618c192949461135eef38", + "type": "github" + }, + "original": { + "owner": "KZDKM", + "repo": "Hyprspace", + "type": "github" + } + }, "hyprtoolkit": { "inputs": { "aquamarine": [ @@ -2484,6 +2505,7 @@ "home-manager": "home-manager_2", "hy3": "hy3", "hyprland": "hyprland", + "hyprspace": "hyprspace", "imalison-taffybar": "imalison-taffybar", "nix": "nix", "nixified-ai": "nixified-ai", @@ -2495,7 +2517,7 @@ "org-agenda-api": "org-agenda-api", "railbird-secrets": "railbird-secrets", "status-notifier-item": "status-notifier-item_2", - "systems": "systems_13", + "systems": "systems_14", "taffybar": "taffybar_2", "vscode-server": "vscode-server", "xmonad": "xmonad_3", @@ -2735,6 +2757,21 @@ "type": "github" } }, + "systems_17": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "systems_2": { "locked": { "lastModified": 1681028828, @@ -2782,16 +2819,16 @@ }, "systems_5": { "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", "type": "github" }, "original": { "owner": "nix-systems", - "repo": "default", + "repo": "default-linux", "type": "github" } }, diff --git a/nixos/flake.nix b/nixos/flake.nix index 87faddc7..67545f95 100644 --- a/nixos/flake.nix +++ b/nixos/flake.nix @@ -42,6 +42,11 @@ inputs.hyprland.follows = "hyprland"; }; + hyprspace = { + url = "github:KZDKM/Hyprspace"; + inputs.hyprland.follows = "hyprland"; + }; + railbird-secrets = { url = "git+ssh://gitea@dev.railbird.ai:1123/railbird/secrets-flake.git"; }; @@ -153,6 +158,7 @@ imalison-taffybar, hyprland, hy3, + hyprspace, org-agenda-api, flake-utils, ... diff --git a/nixos/hyprland.nix b/nixos/hyprland.nix index a3aabb97..47f9c221 100644 --- a/nixos/hyprland.nix +++ b/nixos/hyprland.nix @@ -8,114 +8,37 @@ makeEnable config "myModules.hyprland" true { home-manager.sharedModules = [ { - # Wire the Hyprland config from dotfiles into ~/.config/hypr - xdg.configFile."hypr" = { - source = ../dotfiles/config/hypr; + xdg.configFile."waybar" = { + source = ../dotfiles/config/waybar; recursive = true; force = true; }; - programs.waybar = { - enable = true; - systemd.enable = true; - settings = [ - { - layer = "top"; - position = "top"; - height = 30; - "modules-left" = [ "hyprland/workspaces" ]; - "modules-center" = [ "hyprland/window" ]; - "modules-right" = [ "tray" "clock" ]; + programs.waybar.enable = true; - "hyprland/workspaces" = { - format = "{id}:{windows}"; - "format-window-separator" = " "; - "window-rewrite-default" = ""; - "window-rewrite" = { - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - "class" = ""; - }; - "persistent-workspaces" = { "*" = 10; }; - "all-outputs" = true; - "on-click" = "activate"; - }; - - "hyprland/window" = { - format = "{class}: {title}"; - "separate-outputs" = true; - }; - - tray = { - spacing = 8; - }; - - clock = { - format = "{:%a %b %d %I:%M:%S %p}"; - }; - } - ]; - style = '' - * { - border: none; - border-radius: 0; - font-family: "Roboto", "JetBrainsMono Nerd Font"; - font-size: 11pt; - min-height: 0; - } - - window#waybar { - background: rgba(24, 24, 24, 0.92); - color: #e6e6e6; - } - - #workspaces { - margin-left: 6px; - } - - #workspaces button { - padding: 0 8px; - margin: 4px 4px; - border-radius: 6px; - background: transparent; - color: #bfbfbf; - } - - #workspaces button.active { - background: #e0b45a; - color: #1c1c1c; - } - - #workspaces button.visible { - background: #3a3a3a; - color: #e6e6e6; - } - - #workspaces button.urgent { - background: #e06060; - color: #1c1c1c; - } - - #workspaces button.empty { - color: #777777; - } - - #window { - padding: 0 10px; - } - - #tray, - #clock { - padding: 0 10px; - } - ''; + systemd.user.targets.hyprland-session = { + Unit = { + Description = "Hyprland session"; + }; }; + + systemd.user.services.waybar = { + Unit = { + Description = "Waybar"; + PartOf = [ "hyprland-session.target" ]; + After = [ "hyprland-session.target" ]; + }; + Service = { + ExecStart = "${pkgs.waybar}/bin/waybar"; + Restart = "on-failure"; + RestartSec = 1; + }; + Install = { + WantedBy = [ "hyprland-session.target" ]; + }; + }; + + programs.hyprpanel.enable = false; } ]; @@ -136,6 +59,9 @@ makeEnable config "myModules.hyprland" true { # hy3 plugin from flake (properly built against matching Hyprland) inputs.hy3.packages.${pkgs.stdenv.hostPlatform.system}.hy3 + # Hyprspace plugin from flake (workspace overview) + inputs.hyprspace.packages.${pkgs.stdenv.hostPlatform.system}.Hyprspace + # For scripts jq ];