updated quickshell

This commit is contained in:
2026-08-31 21:20:26 -07:00
parent e09304b0b6
commit 47c0c9c719
25 changed files with 763 additions and 219 deletions

View File

@@ -1,5 +1,12 @@
{ pkgs, ... }:
{ pkgs, lib, config, ... }:
let
# Deterministic Silicon Volt wallpaper: rendered from SVG at build time,
# so the same source always produces a byte-identical image.
wallpaper = pkgs.runCommand "silicon-volt-wallpaper.png" { } ''
${pkgs.librsvg}/bin/rsvg-convert -w 3840 -h 2160 ${./wallpaper.svg} > $out
'';
in
{
imports = [
./hyprland.nix
@@ -15,10 +22,51 @@
wl-clipboard
cliphist
brightnessctl
jq
# Desktop Environment / Hyprland ecosystem
hyprpaper
rofi
hyprpolkitagent
];
# Build-time rendered wallpaper
xdg.dataFile."backgrounds/silicon-volt.png".source = wallpaper;
# hyprpaper: load the Silicon Volt wallpaper on every output
xdg.configFile."hypr/hyprpaper.conf".text = ''
preload = ${config.home.homeDirectory}/.local/share/backgrounds/silicon-volt.png
wallpaper = ,${config.home.homeDirectory}/.local/share/backgrounds/silicon-volt.png
splash = false
'';
# Notifications: flat brutalist-glass cards with volt accents
services.mako = {
enable = true;
settings = {
background-color = "#1c1b1bee";
text-color = "#e5e2e1";
border-color = "#cffc00";
border-size = 1;
border-radius = 0;
width = 420;
margin = "12";
padding = "14";
default-timeout = 6000;
font = "JetBrainsMono Nerd Font 11";
format = "<b>%s</b>\\n%b";
"icon-location" = "left";
max-icon-size = 48;
"urgency=critical" = {
border-color = "#ff7a59";
text-color = "#ffffff";
default-timeout = 0;
};
"urgency=low" = {
border-color = "#2a2929";
text-color = "#adaaaa";
};
};
};
}

View File

@@ -8,7 +8,7 @@
general = {
lock_cmd = "pidof hyprlock || hyprlock";
before_sleep_cmd = "loginctl lock-session";
after_sleep_cmd = "hyprctl dispatch dpms on";
after_sleep_cmd = "hyprctl dispatch \"hl.dsp.dpms({off = false})\"";
};
listener = [
@@ -24,10 +24,12 @@
on-timeout = "loginctl lock-session";
}
# 3. Turn off displays (DPMS) after 10 minutes
# NOTE: Hyprland's Lua config bridge requires typed dispatcher calls;
# `hyprctl dispatch dpms off` is mangled into invalid Lua.
{
timeout = 600;
on-timeout = "hyprctl dispatch dpms off";
on-resume = "hyprctl dispatch dpms on";
on-timeout = "hyprctl dispatch \"hl.dsp.dpms({off = true})\"";
on-resume = "hyprctl dispatch \"hl.dsp.dpms({off = false})\"";
}
# 4. Suspend system after 30 minutes
{

View File

@@ -1,10 +1,58 @@
{ pkgs, lib, ... }:
{ pkgs, lib, config, ... }:
let
mkLua = lib.generators.mkLuaInline;
in
{
wayland.windowManager.hyprland = {
# -------------------------------------------------------------------------
# Per-host monitor configuration.
#
# Hosts declare their displays once, in hosts/<host>/default.nix, via:
# home-manager.users.anish.volt.monitors = [ { ... } ];
# and the setting flows into Hyprland here. The default (empty output +
# preferred mode) works on any machine with any display.
# -------------------------------------------------------------------------
options.volt.monitors = lib.mkOption {
description = "Hyprland monitor rules for this host";
type = lib.types.listOf (lib.types.submodule {
options = {
output = lib.mkOption {
type = lib.types.str;
default = "";
description = "Output name or desc: match. Empty string matches every output.";
};
mode = lib.mkOption {
type = lib.types.str;
default = "preferred";
description = "Resolution@refresh, e.g. \"3840x2160@164.99Hz\" or \"preferred\".";
};
position = lib.mkOption {
type = lib.types.str;
default = "auto";
};
scale = lib.mkOption {
type = lib.types.either lib.types.number lib.types.str;
default = "auto";
};
vrr = lib.mkOption {
type = lib.types.nullOr (lib.types.either lib.types.number lib.types.str);
default = null;
description = "Optional per-monitor VRR setting (0/1/on-demand).";
};
};
});
default = [
{ output = ""; mode = "preferred"; position = "auto"; scale = "auto"; }
];
};
config = {
wayland.windowManager.hyprland.settings.monitor = map (m:
{ inherit (m) output mode position scale; }
// (lib.optionalAttrs (m.vrr != null) { inherit (m) vrr; })
) config.volt.monitors;
wayland.windowManager.hyprland = {
enable = true;
configType = "lua";
package = null; # Hyprland package is managed system-wide via NixOS programs.hyprland
@@ -18,45 +66,16 @@ in
browser = { _var = "brave"; };
# -----------------------------------------------------------------------
# 2. Monitors (hl.monitor)
# 2. Monitors (hl.monitor) - declared per-host via volt.monitors
# (see hosts/<host>/default.nix); defaults to any display @ preferred.
# -----------------------------------------------------------------------
monitor = [
{
output = "eDP-2";
mode = "3840x2160@144";
position = "0x0";
scale = 2;
}
{
output = "desc:Dell Inc. DELL U3419W 28DQ5T2";
mode = "3440x1440@60";
position = "0x-1440";
scale = 1;
}
{
output = "desc:Samsung Electric Company Odyssey Ark H1AK500000";
mode = "3840x2160@144";
position = "3840x0";
scale = 1;
}
{
output = "";
mode = "preferred";
position = "auto";
scale = "auto";
}
];
# -----------------------------------------------------------------------
# 3. Environment Variables (hl.env)
# -----------------------------------------------------------------------
env = [
{ _args = [ "XCURSOR_SIZE" "24" ]; }
{ _args = [ "LIBVA_DRIVE_NAME" "nvidia" ]; }
{ _args = [ "XDG_SESSION_TYPE" "wayland" ]; }
{ _args = [ "GBM_BACKEND" "nvidia-drm" ]; }
{ _args = [ "WLR_NO_HARDWARE_CURSORS" "1" ]; }
{ _args = [ "WLR_DRM_DEVICES" "/dev/dri/card1:/dev/dri/card0" ]; }
];
# -----------------------------------------------------------------------
@@ -76,6 +95,9 @@ in
cursor = {
inactive_timeout = 3;
# Hardware cursors ON (explicit). Note: this replaces the old
# WLR_NO_HARDWARE_CURSORS=1, which forced software rendering.
no_hardware_cursors = false;
};
general = {
@@ -83,11 +105,12 @@ in
gaps_out = 10;
border_size = 2;
col = {
# Silicon Volt: electric lime gradient on focus, glass gray at rest
active_border = {
colors = [ "rgba(33ccffee)" "rgba(00ff99ee)" ];
colors = [ "rgba(cffc00ee)" "rgba(e3ff66ee)" ];
angle = 45;
};
inactive_border = "rgba(595959aa)";
inactive_border = "rgba(ffffff14)";
};
layout = "dwindle";
};
@@ -95,19 +118,19 @@ in
group = {
groupbar = {
font_size = 14;
font_family = "SF Pro Display";
font_family = "JetBrainsMono Nerd Font";
col = {
active = "rgba(33ccff00)";
inactive = "rgba(59595900)";
active = "rgba(cffc0022)";
inactive = "rgba(ffffff08)";
};
};
col = {
border_active = {
colors = [ "rgba(33ccffee)" "rgba(00ff99ee)" ];
colors = [ "rgba(cffc00ee)" "rgba(e3ff66ee)" ];
angle = 45;
};
border_inactive = "rgba(595959aa)";
border_inactive = "rgba(ffffff14)";
};
};
@@ -117,19 +140,25 @@ in
};
decoration = {
rounding = 10;
rounding = 4;
# Subtle glass blur to match the brutalist-glass aesthetic
blur = {
enabled = false;
size = 3;
passes = 1;
enabled = true;
size = 4;
passes = 2;
new_optimizations = true;
ignore_opacity = true;
contrast = 1.1;
brightness = 0.9;
vibrancy = 0.1;
};
shadow = {
enabled = false;
range = 4;
enabled = true;
range = 12;
render_power = 3;
color = "rgba(1a1a1aee)";
color = "rgba(00000066)";
};
};
@@ -180,6 +209,9 @@ in
(mkLua ''function()
hl.exec_cmd("quickshell")
hl.exec_cmd("hyprpaper")
hl.exec_cmd("mako")
hl.exec_cmd("wl-paste --type text --watch cliphist store")
hl.exec_cmd("wl-paste --type image --watch cliphist store")
hl.exec_cmd("${pkgs.hyprpolkitagent}/libexec/hyprpolkitagent")
end'')
];
@@ -196,7 +228,7 @@ in
{ _args = [ (mkLua "mainMod .. \" + SPACE\"") (mkLua "hl.dsp.exec_cmd(\"quickshell ipc call spotlight toggle || rofi -show combi -show-icons\")") ]; }
{ _args = [ (mkLua "mainMod .. \" + N\"") (mkLua "hl.dsp.exec_cmd(\"quickshell ipc call controlCenter toggle || swaync-client -t -sw\")") ]; }
{ _args = [ (mkLua "mainMod .. \" + V\"") (mkLua "hl.dsp.window.float({ action = \"toggle\" })") ]; }
{ _args = [ (mkLua "mainMod .. \" + R\"") (mkLua "hl.dsp.exec_cmd(\"quickshell ipc call spotlight toggle || rofi -show combi -show-icons\")") ]; }
{ _args = [ (mkLua "mainMod .. \" + R\"") (mkLua "hl.dsp.exec_cmd(\"rofi -show combi\")") ]; }
{ _args = [ (mkLua "mainMod .. \" + G\"") (mkLua "hl.dsp.group.toggle()") ]; }
{ _args = [ (mkLua "mainMod .. \" + F\"") (mkLua "hl.dsp.window.fullscreen({ fullscreen = 0 })") ]; }
@@ -274,30 +306,30 @@ in
{
_args = [
"XF86MonBrightnessUp"
(mkLua "hl.dsp.exec_cmd(\"brightnessctl -d acpi_video0 set 5%+\")")
(mkLua "hl.dsp.exec_cmd(\"brightnessctl set 5%+\")")
{ repeating = true; locked = true; }
];
}
{
_args = [
"XF86MonBrightnessDown"
(mkLua "hl.dsp.exec_cmd(\"brightnessctl -d acpi_video0 set 5%-\")")
(mkLua "hl.dsp.exec_cmd(\"brightnessctl set 5%-\")")
{ repeating = true; locked = true; }
];
}
# Lid switch
# Lid switch - generically detects the embedded (eDP*) panel on any laptop
{
_args = [
"switch:off:Lid Switch"
(mkLua "hl.dsp.exec_cmd(\"hyprctl keyword monitor \\\"eDP-2,3840x2160@144,0x0,2\\\"\")")
(mkLua "hl.dsp.exec_cmd(\"m=$(hyprctl monitors | awk '$1==\\\"Monitor\\\"{print $2; exit}'); [ -n \\\"$m\\\" ] && hyprctl keyword monitor \\\"$m, preferred, auto, auto\\\"\")")
{ locked = true; }
];
}
{
_args = [
"switch:on:Lid Switch"
(mkLua "hl.dsp.exec_cmd(\"hyprctl keyword monitor \\\"eDP-2, disable\\\"\")")
(mkLua "hl.dsp.exec_cmd(\"m=$(hyprctl monitors | awk '$1==\\\"Monitor\\\"{print $2; exit}'); [ -n \\\"$m\\\" ] && hyprctl keyword monitor \\\"$m, disable\\\"\")")
{ locked = true; }
];
}
@@ -364,5 +396,6 @@ in
}
];
};
};
};
}

View File

@@ -10,41 +10,65 @@
grace = 0;
hide_cursor = true;
no_fade_in = false;
ignore_empty_input = true;
};
# Background with screenshot blur effect
# Background: screenshot darkened into the site's #0e0e0e glass tone
background = [
{
path = "screenshot";
blur_passes = 3;
blur_size = 8;
blur_passes = 4;
blur_size = 12;
noise = 0.0117;
contrast = 0.8916;
brightness = 0.8172;
vibrancy = 0.1696;
vibrancy_darkness = 0.0;
contrast = 0.9;
brightness = 0.55;
vibrancy = 0.1;
vibrancy_darkness = 0.4;
}
];
# Clock display
label = [
# Big clock
{
monitor = "";
text = "$TIME";
color = "rgba(242, 243, 244, 0.75)";
font_size = 95;
font_family = "JetBrainsMono Nerd Font Bold";
position = "0, 200";
color = "rgba(ffffffdd)";
font_size = 90;
font_family = "JetBrainsMono Nerd Font";
position = "0, 220";
halign = "center";
valign = "center";
}
# Date
{
monitor = "";
text = "cmd[update:1000] echo \"$(date +'%A, %B %d')\"";
color = "rgba(242, 243, 244, 0.6)";
font_size = 22;
text = "cmd[update:1000] echo \" $(date +'%A, %B %d') \"";
color = "rgba(adaaaaff)";
font_size = 20;
font_family = "JetBrainsMono Nerd Font";
position = "0, 100";
position = "0, 120";
halign = "center";
valign = "center";
}
# Session banner
{
monitor = "";
text = "NIXOS // SILICON VOLT";
color = "rgba(cffc00ee)";
font_size = 14;
font_family = "JetBrainsMono Nerd Font";
position = "0, 60";
halign = "center";
valign = "center";
}
# User + hostname line
{
monitor = "";
text = "cmd[update:3600000] echo \" $USER @ $(hostname) \"";
color = "rgba(adaaaa99)";
font_size = 13;
font_family = "JetBrainsMono Nerd Font";
position = "0, -160";
halign = "center";
valign = "center";
}
@@ -54,18 +78,22 @@
input-field = [
{
monitor = "";
size = "250, 50";
size = "300, 50";
outline_thickness = 2;
dots_size = 0.2;
dots_spacing = 0.2;
dots_center = true;
outer_color = "rgba(33ccffee)";
inner_color = "rgba(15, 23, 42, 0.85)";
font_color = "rgb(242, 243, 244)";
# Volt lime outline, dark glass interior
outer_color = "rgba(cffc00ee)";
inner_color = "rgba(1c1b1b, 0.9)";
check_color = "rgba(e3ff66ee)";
fail_color = "rgba(ff7a59ee)";
font_color = "rgba(e5e2e1ff)";
fail_text = "$FAIL (<b>attempts: $ATTEMPTS</b>)";
fade_on_empty = false;
placeholder_text = "<i>Enter Password...</i>";
placeholder_text = "<i> Enter Password...</i>";
hide_input = false;
position = "0, -50";
position = "0, -80";
halign = "center";
valign = "center";
}

View File

@@ -39,6 +39,7 @@ QtObject {
property int brightness: 100
property bool wifiConnected: true
property string connectionType: "off" // "wifi" | "eth" | "off"
property string wifiSsid: "Wi-Fi"
property string ipAddress: ""
@@ -47,6 +48,11 @@ QtObject {
property bool batteryCharging: false
property string batteryStatus: "Full"
// Disk Monitoring (root filesystem)
property int diskPercent: 0
property string diskUsedGb: "0"
property string diskTotalGb: "0"
// GPU VRAM Monitoring (NVIDIA)
property string gpuVramUsed: "0"
property string gpuVramTotal: "0"
@@ -98,31 +104,32 @@ QtObject {
}
function switchWorkspace(n) {
Hyprland.dispatch("workspace " + n);
// NOTE: Hyprland's Lua config bridge requires typed dispatcher calls
// (plain `hyprctl dispatch workspace 2` is mangled into invalid Lua).
Hyprland.dispatch("hl.dsp.focus({workspace = " + n + "})");
}
// Hyprland raw event processing
readonly property Connections hyprConn: Connections {
target: Hyprland
function onRawEvent(event) { console.log(JSON.stringify(event), event.name, event.event, event.data);
if (!event) return;
if (event.startsWith("workspace>>")) {
const data = event.substring(11);
function onRawEvent(event) {
if (!event || !event.name) return;
const name = event.name;
const data = event.data !== undefined ? String(event.data) : "";
if (name === "workspace") {
const wsNum = parseInt(data);
if (!isNaN(wsNum)) root.activeWorkspace = wsNum;
} else if (event.startsWith("activewindow>>")) {
const data = event.substring(14);
} else if (name === "activewindow") {
const parts = data.split(",");
const title = parts[1] ? parts[1].trim() : (parts[0] ? parts[0].trim() : "");
const cls = parts[0] ? parts[0].trim() : "Finder";
root.activeWindowClass = cls && cls.length > 0 ? cls : "Finder";
const cls = parts[0] ? parts[0].trim() : "";
const title = parts[1] ? parts[1].trim() : (cls || "");
root.activeWindowClass = cls && cls.length > 0 ? cls : "Desktop";
root.activeWindowTitle = title && title.length > 0 ? title : root.activeWindowClass;
} else if (event.startsWith("activewindowv2>>")) {
} else if (name === "activewindowv2" || name === "openwindow" || name === "closewindow") {
// Update running clients
clientsProc.running = true;
} else if (event.startsWith("openwindow>>") || event.startsWith("closewindow>>")) {
clientsProc.running = true;
}
}
}
@@ -156,6 +163,7 @@ QtObject {
brightProc.running = true;
mprisProc.running = true;
gpuProc.running = true;
diskProc.running = true;
}
}
@@ -200,15 +208,16 @@ QtObject {
}
readonly property Process wifiProc: Process {
command: ["bash", "-c", "ssid=\"\"; if command -v nmcli &>/dev/null; then ssid=$(nmcli -t -f active,ssid dev wifi 2>/dev/null | grep '^yes:' | cut -d':' -f2); fi; [ -z \"$ssid\" ] && [ -f /proc/net/wireless ] && ssid=$(iwgetid -r 2>/dev/null); ip=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}'); echo \"${ssid:-Ethernet} ${ip:-Offline}\""]
// Emits: connectionType|ssid|ip ("wifi" | "eth" | "off")
command: ["bash", "-c", "route=$(ip -4 route get 1.1.1.1 2>/dev/null); ip=$(echo \"$route\" | awk '{for(i=1;i<=NF;i++) if($i==\"src\") print $(i+1)}'); dev=$(echo \"$route\" | awk '{for(i=1;i<=NF;i++) if($i==\"dev\") print $(i+1)}'); type=\"off\"; ssid=\"\"; if [ -n \"$dev\" ]; then if [ -d \"/sys/class/net/$dev/wireless\" ]; then type=\"wifi\"; ssid=$(iwgetid -r 2>/dev/null); if [ -z \"$ssid\" ] && command -v nmcli &>/dev/null; then ssid=$(nmcli -t -f active,ssid dev wifi 2>/dev/null | grep '^yes:' | cut -d':' -f2); fi; else type=\"eth\"; fi; fi; echo \"$type|$ssid|$ip\""]
stdout: StdioCollector {
onDataChanged: {
const str = String(data).trim();
const parts = str.split(" ");
if (parts.length >= 2) {
root.wifiSsid = parts[0];
root.ipAddress = parts[1];
root.wifiConnected = parts[1] !== "Offline";
const parts = String(data).trim().split("|");
if (parts.length >= 3) {
root.connectionType = parts[0] !== "" ? parts[0] : "off";
root.wifiSsid = parts[1];
root.ipAddress = parts[2];
root.wifiConnected = parts[2] !== "" && parts[2] !== "Offline";
}
}
}
@@ -237,6 +246,21 @@ QtObject {
}
}
readonly property Process diskProc: Process {
// Emits: usedGB totalGB percent for the root filesystem
command: ["bash", "-c", "df -BG / 2>/dev/null | awk 'NR==2 {u=$3; t=$2; gsub(/G/,\"\",u); gsub(/G/,\"\",t); if (t+0 > 0) print u, t, int(u*100/t)}'"]
stdout: StdioCollector {
onDataChanged: {
const parts = String(data).trim().split(" ");
if (parts.length >= 3) {
root.diskUsedGb = parts[0];
root.diskTotalGb = parts[1];
root.diskPercent = parseInt(parts[2]) || 0;
}
}
}
}
readonly property Process mprisProc: Process {
command: ["bash", "-c", "if command -v playerctl &>/dev/null; then t=$(playerctl metadata title 2>/dev/null); a=$(playerctl metadata artist 2>/dev/null); s=$(playerctl status 2>/dev/null); echo \"$s|$t|$a\"; fi"]
stdout: StdioCollector {
@@ -287,40 +311,40 @@ QtObject {
}
}
// Helper functions to control system
// Helper functions to control system (execDetached: fire-and-forget)
function setVolume(val) {
root.volume = Math.max(0, Math.min(100, val));
Process.exec(["pactl", "set-sink-volume", "@DEFAULT_SINK@", `${root.volume}%`]);
Quickshell.execDetached(["pactl", "set-sink-volume", "@DEFAULT_SINK@", `${root.volume}%`]);
}
function toggleVolumeMute() {
Process.exec(["pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle"]);
Quickshell.execDetached(["pactl", "set-sink-mute", "@DEFAULT_SINK@", "toggle"]);
root.volumeMuted = !root.volumeMuted;
}
function setBrightness(val) {
root.brightness = Math.max(1, Math.min(100, val));
Process.exec(["brightnessctl", "set", `${root.brightness}%`]);
Quickshell.execDetached(["brightnessctl", "set", `${root.brightness}%`]);
}
function mediaPlayPause() {
Process.exec(["playerctl", "play-pause"]);
Quickshell.execDetached(["playerctl", "play-pause"]);
mprisProc.running = true;
}
function mediaNext() {
Process.exec(["playerctl", "next"]);
Quickshell.execDetached(["playerctl", "next"]);
mprisProc.running = true;
}
function mediaPrevious() {
Process.exec(["playerctl", "previous"]);
Quickshell.execDetached(["playerctl", "previous"]);
mprisProc.running = true;
}
function launchApp(execCmd) {
if (!execCmd) return;
Process.exec(["bash", "-c", `${execCmd} &`]);
Quickshell.execDetached(["sh", "-c", execCmd]);
closeAllPopups();
spotlightVisible = false;
}

View File

@@ -25,7 +25,7 @@ Rectangle {
model: root.menuName === "File" ? [
{ text: "New Window", shortcut: "⌘N", cmd: "foot &" },
{ text: "New Incognito Window", shortcut: "⇧⌘N", cmd: "brave --incognito &" },
{ text: "Close Window", shortcut: "⌘W", cmd: "hyprctl dispatch killactive" },
{ text: "Close Window", shortcut: "⌘W", cmd: "hyprctl dispatch \"hl.dsp.window.close()\"" },
{ text: "---", shortcut: "", cmd: "" },
{ text: "Take Screenshot", shortcut: "⇧⌘5", cmd: "grim -g \"$(slurp)\" ~/screenshot.png" }
] : []
@@ -49,9 +49,9 @@ Rectangle {
// VIEW MENU
Repeater {
model: root.menuName === "View" ? [
{ text: "Toggle Fullscreen", shortcut: "⌃⌘F", cmd: "hyprctl dispatch fullscreen 0" },
{ text: "Toggle Floating", shortcut: "⌘V", cmd: "hyprctl dispatch togglefloating" },
{ text: "Toggle Group", shortcut: "⌘G", cmd: "hyprctl dispatch togglegroup" },
{ text: "Toggle Fullscreen", shortcut: "⌃⌘F", cmd: "hyprctl dispatch \"hl.dsp.window.fullscreen({fullscreen = 0})\"" },
{ text: "Toggle Floating", shortcut: "⌘V", cmd: "hyprctl dispatch \"hl.dsp.window.float({action = \"toggle\"})\"" },
{ text: "Toggle Group", shortcut: "⌘G", cmd: "hyprctl dispatch \"hl.dsp.group.toggle()\"" },
{ text: "---", shortcut: "", cmd: "" },
{ text: "Zoom In", shortcut: "⌘+", cmd: "" },
{ text: "Zoom Out", shortcut: "⌘-", cmd: "" }
@@ -62,12 +62,12 @@ Rectangle {
// WINDOW MENU
Repeater {
model: root.menuName === "Window" ? [
{ text: "Minimize Window", shortcut: "⌘M", cmd: "hyprctl dispatch movetoworkspacesilent special:scratch" },
{ text: "Tile Left", shortcut: "⌃⌥←", cmd: "hyprctl dispatch movewindow l" },
{ text: "Tile Right", shortcut: "⌃⌥→", cmd: "hyprctl dispatch movewindow r" },
{ text: "Minimize Window", shortcut: "⌘M", cmd: "hyprctl dispatch \"hl.dsp.window.move({workspace = \"special:scratch\"})\"" },
{ text: "Tile Left", shortcut: "⌃⌥←", cmd: "hyprctl dispatch \"hl.dsp.window.move({direction = \"left\"})\"" },
{ text: "Tile Right", shortcut: "⌃⌥→", cmd: "hyprctl dispatch \"hl.dsp.window.move({direction = \"right\"})\"" },
{ text: "---", shortcut: "", cmd: "" },
{ text: "Show Scratchpad", shortcut: "⌘↩", cmd: "hyprctl dispatch togglespecialworkspace scratch" },
{ text: "Show Messaging", shortcut: "⌘M", cmd: "hyprctl dispatch togglespecialworkspace messaging" }
{ text: "Show Scratchpad", shortcut: "⌘↩", cmd: "hyprctl dispatch \"hl.dsp.workspace.toggle_special(\"scratch\")\"" },
{ text: "Show Messaging", shortcut: "⌘M", cmd: "hyprctl dispatch \"hl.dsp.workspace.toggle_special(\"messaging\")\"" }
] : []
delegate: MenuEntryDelegate {}
}

View File

@@ -99,7 +99,7 @@ Rectangle {
shortcut: "⇧⌘Q"
onTriggered: {
GlobalState.appleMenuVisible = false;
GlobalState.launchApp("hyprctl dispatch exit");
GlobalState.launchApp("loginctl terminate-session");
}
}
}

View File

@@ -170,7 +170,7 @@ PanelWindow {
isPinned: false
onCustomClicked: {
if (modelData.address) {
Hyprland.dispatch(`focuswindow address:${modelData.address}`);
Hyprland.dispatch(`hl.dsp.focus({window = "address:${modelData.address}"})`);
}
}
}

View File

@@ -308,8 +308,9 @@ PanelWindow {
var seen = {}
if (GlobalState.runningApps) {
for (var i = 0; i < GlobalState.runningApps.length; i++) {
var cls = GlobalState.runningApps[i]
if (cls && pinned.indexOf(cls) === -1 && !seen[cls]) {
// hyprctl clients entries are objects; extract the class string
var cls = GlobalState.runningApps[i] && GlobalState.runningApps[i].class
if (cls && cls.length > 0 && pinned.indexOf(cls) === -1 && !seen[cls]) {
seen[cls] = true
running.push(cls)
}
@@ -331,7 +332,7 @@ PanelWindow {
Text {
anchors.centerIn: parent
text: modelData.charAt(0).toUpperCase()
text: modelData && modelData.length > 0 ? modelData.charAt(0).toUpperCase() : "?"
color: Theme.textPrimary
font.family: Theme.fontSans
font.pixelSize: 12

View File

@@ -31,7 +31,9 @@ PanelWindow {
// App Database Loader Process
readonly property Process appScanProc: Process {
command: ["bash", "-c", "dirs=(\"/run/current-system/sw/share/applications\" \"$HOME/.nix-profile/share/applications\" \"$HOME/.local/share/applications\"); echo '['; first=1; for d in \"${dirs[@]}\"; do [ -d \"$d\" ] && for f in \"$d\"/*.desktop; do [ -e \"$f\" ] || continue; grep -q \"^NoDisplay=true\" \"$f\" 2>/dev/null && continue; n=$(grep -m 1 \"^Name=\" \"$f\" 2>/dev/null | cut -d= -f2-); e=$(grep -m 1 \"^Exec=\" \"$f\" 2>/dev/null | cut -d= -f2- | sed -E 's/%[fFuUdDnNickvm]//g'); if [ -n \"$n\" ] && [ -n \"$e\" ]; then [ $first -eq 0 ] && echo ','; first=0; echo \"{\\\"name\\\":\\\"$n\\\",\\\"exec\\\":\\\"$e\\\"}\"; fi; done; done; echo ']'"]
// Indexes .desktop applications AND executable user scripts so the
// launcher finds "everything" without depending on an external service.
command: ["bash", "-c", "dirs=(\"/run/current-system/sw/share/applications\" \"$HOME/.nix-profile/share/applications\" \"$HOME/.local/share/applications\"); bdirs=(\"$HOME/.local/bin\" \"$HOME/bin\" \"$HOME/.cargo/bin\"); echo '['; first=1; for d in \"${dirs[@]}\"; do [ -d \"$d\" ] && for f in \"$d\"/*.desktop; do [ -e \"$f\" ] || continue; grep -q \"^NoDisplay=true\" \"$f\" 2>/dev/null && continue; n=$(grep -m 1 \"^Name=\" \"$f\" 2>/dev/null | cut -d= -f2-); e=$(grep -m 1 \"^Exec=\" \"$f\" 2>/dev/null | cut -d= -f2- | sed -E 's/%[fFuUdDnNickvm]//g'); if [ -n \"$n\" ] && [ -n \"$e\" ]; then [ $first -eq 0 ] && echo ','; first=0; echo \"{\\\"name\\\":\\\"$n\\\",\\\"exec\\\":\\\"$e\\\"}\"; fi; done; done; for d in \"${bdirs[@]}\"; do [ -d \"$d\" ] || continue; for f in \"$d\"/*; do [ -f \"$f\" ] && [ -x \"$f\" ] || continue; n=$(basename \"$f\"); [ $first -eq 0 ] && echo ','; first=0; printf '{\\\"name\\\":\\\"%s\\\",\\\"exec\\\":\\\"%s\\\",\\\"comment\\\":\\\"script\\\"}\\n' \"$n\" \"$f\"; done; done; echo ']'"]
stdout: StdioCollector {
onDataChanged: {
try {

View File

@@ -73,6 +73,7 @@ PanelWindow {
component ToggleCard: Rectangle {
property string title: ""
property string icon: ""
property string glyph: "" // Nerd Font glyph alternative to icon file
property bool active: false
signal clicked()
@@ -97,15 +98,22 @@ PanelWindow {
anchors.fill: parent
anchors.margins: 12
spacing: 12
Text {
visible: parent.parent.glyph !== ""
text: parent.parent.glyph
font.family: "JetBrainsMono Nerd Font"
font.pixelSize: 20
color: parent.parent.active ? Theme.accentVolt : Theme.textMuted
}
Image {
source: icon ? Qt.resolvedUrl("../" + icon) : ""
source: parent.parent.icon && parent.parent.glyph === "" ? Qt.resolvedUrl("../" + parent.parent.icon) : ""
Layout.preferredWidth: 24
Layout.preferredHeight: 24
sourceSize: Qt.size(24, 24)
visible: parent.icon !== ""
visible: parent.parent.icon !== "" && parent.parent.glyph === ""
}
Text {
text: title
text: parent.parent.title
color: Theme.textPrimary
font.family: Theme.fontSans
font.pixelSize: 13
@@ -312,8 +320,7 @@ PanelWindow {
icon: "assets/wifi.svg"
active: GlobalState.wifiConnected
onClicked: {
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
proc.start()
Quickshell.execDetached(["sh", "-c", "nm-connection-editor || foot -e nmtui"])
}
}
@@ -330,14 +337,14 @@ PanelWindow {
ToggleCard {
property bool dndActive: false
title: "Do Not Disturb"
icon: "" // Optional DND icon
glyph: "\uF186"
active: dndActive
onClicked: dndActive = !dndActive
}
ToggleCard {
title: GlobalState.volumeMuted ? "Muted" : "Sound"
icon: "" // Optional sound icon
glyph: GlobalState.volumeMuted ? "\uF026" : "\uF028"
active: !GlobalState.volumeMuted
onClicked: GlobalState.toggleVolumeMute()
}
@@ -423,6 +430,13 @@ PanelWindow {
valueText: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"
}
ProgressBarItem {
label: "DISK"
percent: GlobalState.diskPercent
valueText: GlobalState.diskUsedGb + " / " + GlobalState.diskTotalGb + " GB"
barColor: GlobalState.diskPercent > 90 ? Theme.accentCoral : Theme.accentVolt
}
ProgressBarItem {
label: "VRAM"
percent: (GlobalState.gpuVramUsed / Math.max(1, GlobalState.gpuVramTotal)) * 100
@@ -446,7 +460,12 @@ PanelWindow {
color: GlobalState.wifiConnected ? Theme.accentVolt : Theme.accentCoral
}
Text {
text: GlobalState.wifiConnected ? "Connected" : "Disconnected"
text: {
if (!GlobalState.wifiConnected) return "Disconnected";
if (GlobalState.connectionType === "wifi") return "Wi-Fi — " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "unknown");
if (GlobalState.connectionType === "eth") return "Ethernet";
return "Connected";
}
color: Theme.textPrimary
font.family: Theme.fontSans
font.pixelSize: 14
@@ -454,14 +473,8 @@ PanelWindow {
}
Text {
text: "SSID: " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "None")
color: Theme.textSecondary
font.family: Theme.fontSans
font.pixelSize: 13
}
Text {
text: "IP: " + GlobalState.ipAddress
visible: GlobalState.wifiConnected
text: "IP: " + (GlobalState.ipAddress !== "" ? GlobalState.ipAddress : "—")
color: Theme.textSecondary
font.family: Theme.fontMono
font.pixelSize: 13
@@ -478,8 +491,7 @@ PanelWindow {
onEntered: parent.color = Theme.textPrimary
onExited: parent.color = Theme.textMuted
onClicked: {
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
proc.start()
Quickshell.execDetached(["sh", "-c", "nm-connection-editor || foot -e nmtui"])
}
}
}
@@ -558,7 +570,7 @@ PanelWindow {
}
}
Text {
text: GlobalState.mediaStatus === "Playing" ? "⏸" : "▶"
text: GlobalState.mediaPlaying ? "⏸" : "▶"
font.pixelSize: 24
color: Theme.textSecondary
MouseArea {

View File

@@ -5,6 +5,11 @@ import Quickshell.Wayland
import "../theme"
import ".."
// Nerd Font glyphs (JetBrainsMono Nerd Font, installed system-wide)
// \uF1EB wifi \uF796 ethernet \uF538 memory \uF1C0 disk
// \uF028 volume \uF185 brightness \uF240 battery \uF0E7 charging
// \uF017 clock \uF2DB cpu
PanelWindow {
id: root
@@ -38,33 +43,87 @@ PanelWindow {
color: Theme.glassBorder
}
// --------------------------------------------------------------------
// Helpers to compose rich-text status segments
// --------------------------------------------------------------------
function pad(num) {
if (num === undefined || num === null) return "00";
return num < 10 ? "0" + num : num.toString();
}
function seg(icon, value, iconColor, valueColor) {
return "<font color=\"" + iconColor + "\">" + icon + "</font><font color=\"" + valueColor + "\"> " + value + "</font>";
}
function buildStats() {
const c = "#e5e2e1";
const dim = "#adaaaa";
const volt = "#CFFC00";
const coral = "#FF7A59";
const sep = "<font color=\"#2a2929\"> // </font>";
const parts = [];
// Network: type icon + SSID (wifi) + IP
if (GlobalState.wifiConnected) {
const icon = GlobalState.connectionType === "wifi" ? "\uF1EB" : "\uF796";
const label = (GlobalState.connectionType === "wifi" && GlobalState.wifiSsid !== "") ? GlobalState.wifiSsid : "eth";
parts.push(seg(icon, label + " " + (GlobalState.ipAddress !== "" ? GlobalState.ipAddress : "\u2014"), volt, c));
} else {
parts.push(seg("\uF1EB", "offline", coral, dim));
}
// Memory (used GB / total GB)
parts.push(seg("\uF538", GlobalState.memUsedGb + "G / " + GlobalState.memTotalGb + "G",
GlobalState.memPercent > 85 ? coral : dim, c));
// Disk (root filesystem percent)
parts.push(seg("\uF1C0", GlobalState.diskPercent + "%",
GlobalState.diskPercent > 90 ? coral : dim, c));
// Audio (mute state flips icon + color)
if (GlobalState.volumeMuted) {
parts.push(seg("\uF026", "mute", coral, dim));
} else {
parts.push(seg("\uF028", GlobalState.volume + "%", dim, c));
}
// Display brightness
parts.push(seg("\uF185", GlobalState.brightness + "%", dim, c));
// Battery (only when present, e.g. laptops)
if (GlobalState.batteryPresent) {
const icon = GlobalState.batteryCharging ? "\uF0E7" : "\uF240";
parts.push(seg(icon, GlobalState.batteryPercent + "%",
GlobalState.batteryPercent < 20 ? coral : dim, c));
}
return parts.join(sep);
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16
// Left Section
// Left Section: workspace indicator
Text {
id: workspaceIndicator
Layout.alignment: Qt.AlignVCenter
font.family: Theme.fontMono
textFormat: Text.RichText
font.family: "JetBrainsMono Nerd Font"
font.pixelSize: 12
color: Theme.textMuted
function pad(num) {
if (num === undefined || num === null) return "00";
return num < 10 ? "0" + num : num.toString();
}
text: pad(GlobalState.activeWorkspace) + " // " + (GlobalState.workspaceNames[GlobalState.activeWorkspace] !== undefined ? GlobalState.workspaceNames[GlobalState.activeWorkspace] : "main")
Behavior on color {
ColorAnimation { duration: 150 }
text: {
const name = GlobalState.workspaceNames[GlobalState.activeWorkspace] !== undefined
? GlobalState.workspaceNames[GlobalState.activeWorkspace] : "main";
return "<font color=\"#CFFC00\">" + pad(GlobalState.activeWorkspace) + "</font>"
+ "<font color=\"#2a2929\"> // </font>"
+ "<font color=\"#adaaaa\">" + name + "</font>";
}
}
// Center Section
// Center Section: focused window title
Text {
id: windowTitle
Layout.fillWidth: true
@@ -84,18 +143,35 @@ PanelWindow {
}
}
// Right Section
// Right Section: live system stats (click to open the System HUD)
Text {
id: stats
Layout.alignment: Qt.AlignVCenter
textFormat: Text.RichText
font.family: "JetBrainsMono Nerd Font"
font.pixelSize: 11
text: buildStats()
MouseArea {
id: statsMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: GlobalState.toggleSystemHud()
}
}
// Clock
Text {
id: clock
Layout.alignment: Qt.AlignVCenter
font.family: Theme.fontMono
textFormat: Text.RichText
font.family: "JetBrainsMono Nerd Font"
font.pixelSize: 12
color: Theme.textPrimary
text: GlobalState.timeString
Behavior on color {
ColorAnimation { duration: 150 }
}
text: "<font color=\"#adaaaa\">\uF017</font>"
+ "<font color=\"#ffffff\"> " + GlobalState.timeString + "</font>"
}
}
}

53
home/hypr/wallpaper.svg Normal file
View File

@@ -0,0 +1,53 @@
<svg xmlns="http://www.w3.org/2000/svg" width="3840" height="2160" viewBox="0 0 3840 2160">
<defs>
<radialGradient id="voltGlow" cx="72%" cy="88%" r="55%">
<stop offset="0%" stop-color="#CFFC00" stop-opacity="0.07"/>
<stop offset="60%" stop-color="#CFFC00" stop-opacity="0.015"/>
<stop offset="100%" stop-color="#CFFC00" stop-opacity="0"/>
</radialGradient>
<radialGradient id="coralGlow" cx="12%" cy="8%" r="45%">
<stop offset="0%" stop-color="#FF7A59" stop-opacity="0.05"/>
<stop offset="100%" stop-color="#FF7A59" stop-opacity="0"/>
</radialGradient>
<pattern id="grid" width="160" height="160" patternUnits="userSpaceOnUse">
<path d="M 160 0 L 0 0 0 160" fill="none" stroke="#FFFFFF" stroke-opacity="0.028" stroke-width="1"/>
</pattern>
<pattern id="gridFine" width="32" height="32" patternUnits="userSpaceOnUse">
<path d="M 32 0 L 0 0 0 32" fill="none" stroke="#FFFFFF" stroke-opacity="0.012" stroke-width="1"/>
</pattern>
</defs>
<!-- Base: site bg-secondary -->
<rect width="3840" height="2160" fill="#0e0e0e"/>
<rect width="3840" height="2160" fill="url(#gridFine)"/>
<rect width="3840" height="2160" fill="url(#grid)"/>
<!-- Ambient glows -->
<rect width="3840" height="2160" fill="url(#voltGlow)"/>
<rect width="3840" height="2160" fill="url(#coralGlow)"/>
<!-- Horizon lines: subtle glass borders -->
<line x1="0" y1="1750" x2="3840" y2="1750" stroke="#FFFFFF" stroke-opacity="0.05" stroke-width="2"/>
<line x1="0" y1="1770" x2="3840" y2="1770" stroke="#CFFC00" stroke-opacity="0.10" stroke-width="1"/>
<!-- Top-left coral bracket (site accent) -->
<rect x="140" y="140" width="180" height="10" fill="#FF7A59" opacity="0.55"/>
<rect x="140" y="140" width="10" height="180" fill="#FF7A59" opacity="0.55"/>
<!-- Bottom-right volt corner assembly -->
<rect x="3420" y="2020" width="280" height="12" fill="#CFFC00" opacity="0.9"/>
<rect x="3688" y="1820" width="12" height="212" fill="#CFFC00" opacity="0.9"/>
<circle cx="3694" cy="2026" r="26" fill="#CFFC00"/>
<circle cx="3694" cy="2026" r="52" fill="none" stroke="#CFFC00" stroke-opacity="0.35" stroke-width="3"/>
<!-- Volt tick marks along the horizon -->
<rect x="300" y="1762" width="60" height="8" fill="#CFFC00" opacity="0.5"/>
<rect x="420" y="1762" width="24" height="8" fill="#CFFC00" opacity="0.3"/>
<rect x="3600" y="1762" width="120" height="8" fill="#CFFC00" opacity="0.5"/>
<!-- Faint "//" motif, mono-grid aligned -->
<g fill="#FFFFFF" fill-opacity="0.04">
<polygon points="1900,700 2000,700 1780,1460 1680,1460"/>
<polygon points="2080,700 2180,700 1960,1460 1860,1460"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB