updated pi, quickshell, and ollama
This commit is contained in:
193
flake.lock
generated
193
flake.lock
generated
@@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1786829626,
|
||||
"narHash": "sha256-Yg4SMZkoln6bEwAUPDhqCU7XWC1REPtHaerrhKf9eew=",
|
||||
"lastModified": 1787879739,
|
||||
"narHash": "sha256-F8R8x75eBMGox1Z9pmLhwEH2bjlZDeUGDIkOtzAOVq0=",
|
||||
"owner": "Hy4ri",
|
||||
"repo": "antigravity-flake",
|
||||
"rev": "bf9c75d727c829794599434cbb29db774dd9ce77",
|
||||
"rev": "d8581e462a2dde4469e056b736b352978ec7db98",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -20,17 +20,45 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"bun2nix": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts_2",
|
||||
"nixpkgs": [
|
||||
"pi",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"pi",
|
||||
"systems"
|
||||
],
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1778446047,
|
||||
"narHash": "sha256-oQvcadh2BCkrog+SGrG6YffKJrveYpjj3TdQJWaKhaM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "bun2nix",
|
||||
"rev": "f2bc12af1a6369648aac41041ceeaa0b866599c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "2.1.0",
|
||||
"repo": "bun2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"comfy-ui": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1786714237,
|
||||
"narHash": "sha256-XnXKBpaidykfCegAqBGI7/F61IFtMSKUibQct/dP2Zw=",
|
||||
"lastModified": 1787851822,
|
||||
"narHash": "sha256-xLLT67dZFyhNTmPTtpQvaruFHrv0ENB5B082C1NvDmA=",
|
||||
"owner": "utensils",
|
||||
"repo": "comfyui-nix",
|
||||
"rev": "4501c5fe8dd93530d856866ba8bc4b585b508d41",
|
||||
"rev": "9c0c693afe7e355b69fdc73dc0b28a628426a814",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -77,6 +105,28 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"pi",
|
||||
"bun2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777988971,
|
||||
"narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"herdr": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -85,11 +135,11 @@
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1787017031,
|
||||
"narHash": "sha256-FeF4eZhxRl4jBbAkMaEzDCmMcaitV6GZapjaeeNZy7A=",
|
||||
"lastModified": 1788211360,
|
||||
"narHash": "sha256-8wrp7NLYPRaZ9hL7QiqSDQFRme/1UrVwoEDs278aOUA=",
|
||||
"owner": "herdrdev",
|
||||
"repo": "herdr",
|
||||
"rev": "2d24950ad9a02096921bc764e2e3dcd8900c3366",
|
||||
"rev": "5158adab10b6dcfea9370782043392f80fa0643c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -105,11 +155,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785119570,
|
||||
"narHash": "sha256-Rgs2xKnGLFWQscxUaXX07oyZeuMDOHEbqDOsgliLFGM=",
|
||||
"lastModified": 1787377438,
|
||||
"narHash": "sha256-Sxu1NLTD/Ern6hFGLlZmtKCSct3YQXZI/lls8RE1XeM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "d4fd24667c8cbef124bb70a20380cab75ec8474d",
|
||||
"rev": "65258d5c65a250189fde2e35f490d15e064c4c62",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -119,16 +169,31 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"jail-nix": {
|
||||
"locked": {
|
||||
"lastModified": 1776230864,
|
||||
"narHash": "sha256-YsEjjdOsGEzTeD+iT7ONh071BqWAOQWpzYVei3okAXE=",
|
||||
"owner": "~alexdavid",
|
||||
"repo": "jail.nix",
|
||||
"rev": "404e7da9da5ab9aa643666682b2ba1312fa5fbe8",
|
||||
"type": "sourcehut"
|
||||
},
|
||||
"original": {
|
||||
"owner": "~alexdavid",
|
||||
"repo": "jail.nix",
|
||||
"type": "sourcehut"
|
||||
}
|
||||
},
|
||||
"nixos-hardware": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1786717298,
|
||||
"narHash": "sha256-asdPlqtM0AweQ5YNLad6eY4tSYW55YNr1uyayf7mOMQ=",
|
||||
"lastModified": 1788044418,
|
||||
"narHash": "sha256-cmOd3iGoE140M2GidgQMQbyxHZ4dT7C0QZq2+CrXQyA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "2dda192987ab6815e44df0130f03d6c907b79134",
|
||||
"rev": "dc3f0cfde2050172abf6c3cdb684f735c15a57c5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -171,11 +236,11 @@
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1786862985,
|
||||
"narHash": "sha256-FBJRXmbGXiSUDvYEbfLYRkckayyZ6SK1UEqhCrIZ2Cs=",
|
||||
"lastModified": 1788179007,
|
||||
"narHash": "sha256-hn1oU2rue2SYK8dAr8+WNZWtbsz1S2W5mnHlSEuh3bo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e5bdc4a41d4c072fe1e3787eaa0320a384741d44",
|
||||
"rev": "34ab99075ac4f7e40cf037eef32cb1c360bb85e9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -200,11 +265,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1786711500,
|
||||
"narHash": "sha256-QvnceIGTBeDvDd9oCn+GvdsnkquliuwbVgpiRH68qaQ=",
|
||||
"lastModified": 1787962033,
|
||||
"narHash": "sha256-u6z9VTZA4Kf3RkHQo9sQI7NI4Ei/uiU9vrMqOiwWP1Y=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "02e08985a27c65ffd33d434eeb2e660a2e4dc84d",
|
||||
"rev": "c5c4a43b0e8056328ec4529f735cabdb8f1942bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -214,24 +279,41 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"quickshell": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1786864924,
|
||||
"narHash": "sha256-9nqIJWuSlAwy4Vs98N9ffoVeU2dmsWcAJ7/DyIDihqM=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "532a0606cafb05851a203e65be22c9a057447ee2",
|
||||
"revCount": 844,
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||
"lastModified": 1773646010,
|
||||
"narHash": "sha256-iYrs97hS7p5u4lQzuNWzuALGIOdkPXvjz7bviiBjUu8=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5b2c2d84341b2afb5647081c1386a80d7a8d8605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pi": {
|
||||
"inputs": {
|
||||
"bun2nix": "bun2nix",
|
||||
"jail-nix": "jail-nix",
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1788173678,
|
||||
"narHash": "sha256-u0YZmQ8Z5luYELFHA6GAQ68HT2Dh5kU3sMFLQ68+2P0=",
|
||||
"owner": "lukasl-dev",
|
||||
"repo": "pi.nix",
|
||||
"rev": "2a11906417b5f2bd9e8f9130da31dfbdfeffecda",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "lukasl-dev",
|
||||
"repo": "pi.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
@@ -244,7 +326,7 @@
|
||||
"nixos-hardware": "nixos-hardware",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"quickshell": "quickshell"
|
||||
"pi": "pi"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
@@ -267,6 +349,43 @@
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pi",
|
||||
"bun2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775636079,
|
||||
"narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
14
flake.nix
14
flake.nix
@@ -25,15 +25,15 @@
|
||||
url = "github:utensils/comfyui-nix";
|
||||
};
|
||||
|
||||
quickshell = {
|
||||
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
herdr = {
|
||||
url = "github:herdrdev/herdr";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
pi = {
|
||||
url = "github:lukasl-dev/pi.nix";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
@@ -48,6 +48,12 @@
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
unstable = import inputs.nixpkgs-unstable {
|
||||
inherit (final) system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
})
|
||||
inputs.antigravity.overlays.default
|
||||
inputs.comfy-ui.overlays.default
|
||||
];
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hypr
|
||||
./foot.nix
|
||||
./brave.nix
|
||||
./zsh.nix
|
||||
./nvim
|
||||
];
|
||||
imports = [
|
||||
./hypr
|
||||
./foot.nix
|
||||
./brave.nix
|
||||
./zsh.nix
|
||||
./nvim
|
||||
|
||||
xdg.portal.config.common.default = "*";
|
||||
./pi.nix
|
||||
];
|
||||
|
||||
home.stateVersion = "26.05";
|
||||
xdg.portal.config.common.default = "*";
|
||||
|
||||
home.stateVersion = "26.05";
|
||||
}
|
||||
|
||||
@@ -47,6 +47,20 @@ QtObject {
|
||||
property bool batteryCharging: false
|
||||
property string batteryStatus: "Full"
|
||||
|
||||
// GPU VRAM Monitoring (NVIDIA)
|
||||
property string gpuVramUsed: "0"
|
||||
property string gpuVramTotal: "0"
|
||||
property int gpuVramPercent: 0
|
||||
|
||||
// System HUD state (replaces individual popup states)
|
||||
property bool systemHudVisible: false
|
||||
property string systemHudActiveSection: "" // "volume", "wifi", "calendar", etc.
|
||||
|
||||
// Workspace tracking
|
||||
property int activeWorkspace: 1
|
||||
property var workspaceList: [1, 2, 3, 4, 5]
|
||||
property var workspaceNames: ({1: "main", 2: "browser", 3: "code", 4: "media", 5: "misc"})
|
||||
|
||||
// Media Player State (MPRIS)
|
||||
property string mediaTitle: ""
|
||||
property string mediaArtist: ""
|
||||
@@ -60,6 +74,7 @@ QtObject {
|
||||
wifiPopupVisible = false;
|
||||
batteryPopupVisible = false;
|
||||
calendarPopupVisible = false;
|
||||
systemHudVisible = false;
|
||||
}
|
||||
|
||||
function toggleSpotlight() {
|
||||
@@ -77,12 +92,25 @@ QtObject {
|
||||
aboutMacVisible = !aboutMacVisible;
|
||||
}
|
||||
|
||||
function toggleSystemHud() {
|
||||
closeAllPopups();
|
||||
systemHudVisible = !systemHudVisible;
|
||||
}
|
||||
|
||||
function switchWorkspace(n) {
|
||||
Hyprland.dispatch("workspace " + n);
|
||||
}
|
||||
|
||||
// Hyprland raw event processing
|
||||
readonly property Connections hyprConn: Connections {
|
||||
target: Hyprland
|
||||
function onRawEvent(event) {
|
||||
function onRawEvent(event) { console.log(JSON.stringify(event), event.name, event.event, event.data);
|
||||
if (!event) return;
|
||||
if (event.startsWith("activewindow>>")) {
|
||||
if (event.startsWith("workspace>>")) {
|
||||
const data = event.substring(11);
|
||||
const wsNum = parseInt(data);
|
||||
if (!isNaN(wsNum)) root.activeWorkspace = wsNum;
|
||||
} else if (event.startsWith("activewindow>>")) {
|
||||
const data = event.substring(14);
|
||||
const parts = data.split(",");
|
||||
const title = parts[1] ? parts[1].trim() : (parts[0] ? parts[0].trim() : "");
|
||||
@@ -127,6 +155,7 @@ QtObject {
|
||||
audioProc.running = true;
|
||||
brightProc.running = true;
|
||||
mprisProc.running = true;
|
||||
gpuProc.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +164,7 @@ QtObject {
|
||||
command: ["bash", "-c", "read -r c u n s i io ir st g gn < /proc/stat; t1=$((u+n+s+i+io+ir+st+g+gn)); i1=$((i+io)); sleep 0.15; read -r c u n s i io ir st g gn < /proc/stat; t2=$((u+n+s+i+io+ir+st+g+gn)); i2=$((i+io)); td=$((t2-t1)); id=$((i2-i1)); [ $td -gt 0 ] && echo $(( (td-id)*100/td )) || echo 0"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = parseInt(data.trim());
|
||||
const val = parseInt(String(data).trim());
|
||||
if (!isNaN(val)) root.cpuPercent = Math.max(0, Math.min(100, val));
|
||||
}
|
||||
}
|
||||
@@ -145,7 +174,7 @@ QtObject {
|
||||
command: ["bash", "-c", "t=$(grep MemTotal /proc/meminfo | awk '{print $2}'); a=$(grep MemAvailable /proc/meminfo | awk '{print $2}'); if [ -n \"$t\" ] && [ -n \"$a\" ] && [ \"$t\" -gt 0 ]; then u=$((t-a)); p=$((u*100/t)); ug=$(awk \"BEGIN {printf \\\"%.1f\\\", $u/1048576}\"); tg=$(awk \"BEGIN {printf \\\"%.1f\\\", $t/1048576}\"); echo \"$p $ug $tg\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 3) {
|
||||
root.memPercent = parseInt(parts[0]) || 0;
|
||||
root.memUsedGb = parts[1];
|
||||
@@ -159,7 +188,7 @@ QtObject {
|
||||
command: ["bash", "-c", "b=$(find /sys/class/power_supply/ -name 'BAT*' 2>/dev/null | head -n 1); if [ -n \"$b\" ]; then cap=$(cat $b/capacity 2>/dev/null || echo 100); st=$(cat $b/status 2>/dev/null || echo Full); echo \"1 $cap $st\"; else echo \"0 100 AC\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 3) {
|
||||
root.batteryPresent = parts[0] === "1";
|
||||
root.batteryPercent = parseInt(parts[1]) || 100;
|
||||
@@ -174,7 +203,7 @@ QtObject {
|
||||
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}\""]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const str = data.trim();
|
||||
const str = String(data).trim();
|
||||
const parts = str.split(" ");
|
||||
if (parts.length >= 2) {
|
||||
root.wifiSsid = parts[0];
|
||||
@@ -189,7 +218,7 @@ QtObject {
|
||||
command: ["bash", "-c", "if command -v pactl &>/dev/null; then v=$(pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | grep -Po '[0-9]+(?=%)' | head -n 1); m=$(pactl get-sink-mute @DEFAULT_SINK@ 2>/dev/null | grep -q yes && echo 1 || echo 0); echo \"${v:-50} $m\"; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split(" ");
|
||||
const parts = String(data).trim().split(" ");
|
||||
if (parts.length >= 2) {
|
||||
root.volume = parseInt(parts[0]) || 50;
|
||||
root.volumeMuted = parts[1] === "1";
|
||||
@@ -202,7 +231,7 @@ QtObject {
|
||||
command: ["bash", "-c", "if command -v brightnessctl &>/dev/null; then b=$(brightnessctl -m 2>/dev/null | cut -d, -f4 | tr -d '%'); echo \"${b:-100}\"; else echo 100; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = parseInt(data.trim());
|
||||
const val = parseInt(String(data).trim());
|
||||
if (!isNaN(val)) root.brightness = val;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +241,7 @@ QtObject {
|
||||
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 {
|
||||
onDataChanged: {
|
||||
const parts = data.trim().split("|");
|
||||
const parts = String(data).trim().split("|");
|
||||
if (parts.length >= 3) {
|
||||
root.mediaPlaying = parts[0] === "Playing";
|
||||
root.mediaTitle = parts[1] || "";
|
||||
@@ -226,12 +255,30 @@ QtObject {
|
||||
}
|
||||
}
|
||||
|
||||
readonly property Process gpuProc: Process {
|
||||
command: ["bash", "-c", "nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits 2>/dev/null || echo '0, 0'"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const parts = String(data).trim().split(",");
|
||||
if (parts.length >= 2) {
|
||||
const usedMiB = parseInt(parts[0].trim());
|
||||
const totalMiB = parseInt(parts[1].trim());
|
||||
if (!isNaN(usedMiB) && !isNaN(totalMiB) && totalMiB > 0) {
|
||||
root.gpuVramUsed = (usedMiB / 1024).toFixed(1);
|
||||
root.gpuVramTotal = (totalMiB / 1024).toFixed(1);
|
||||
root.gpuVramPercent = Math.round((usedMiB / totalMiB) * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property Process clientsProc: Process {
|
||||
command: ["bash", "-c", "if command -v hyprctl &>/dev/null; then hyprctl -j clients 2>/dev/null; else echo '[]'; fi"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim());
|
||||
const parsed = JSON.parse(String(data).trim());
|
||||
if (Array.isArray(parsed)) {
|
||||
root.runningApps = parsed;
|
||||
}
|
||||
|
||||
190
home/hypr/quickshell/components/QuickMenu.qml
Normal file
190
home/hypr/quickshell/components/QuickMenu.qml
Normal file
@@ -0,0 +1,190 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: quickMenu
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
}
|
||||
|
||||
margins {
|
||||
top: 0
|
||||
left: Theme.sidebarWidth
|
||||
}
|
||||
|
||||
visible: GlobalState.appleMenuVisible
|
||||
|
||||
implicitWidth: 220
|
||||
implicitHeight: menuContainer.implicitHeight
|
||||
|
||||
color: "transparent"
|
||||
|
||||
// Close on escape
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
Keys.onEscapePressed: GlobalState.appleMenuVisible = false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: menuContainer
|
||||
anchors.fill: parent
|
||||
color: Theme.glassBg
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
padding: 8
|
||||
|
||||
component MenuItem: Item {
|
||||
id: menuItem
|
||||
width: parent.width
|
||||
height: 28
|
||||
|
||||
property string text: ""
|
||||
property string shortcut: ""
|
||||
signal triggered()
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: menuItemMouseArea.containsMouse ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.1) : "transparent"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: Theme.accentVolt
|
||||
visible: menuItemMouseArea.containsMouse
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: menuItem.text
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
color: menuItemMouseArea.containsMouse ? Theme.textPrimary : Theme.textSecondary
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: menuItem.shortcut
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
visible: text !== ""
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: menuItemMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
menuItem.triggered()
|
||||
GlobalState.appleMenuVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component MenuSeparator: Item {
|
||||
width: parent.width
|
||||
height: 17
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "System Info..."
|
||||
onTriggered: GlobalState.aboutMacVisible = true
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "System Preferences..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["pavucontrol"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Activity Monitor"
|
||||
shortcut: "btop"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["foot", "-e", "btop"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Sleep"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "suspend"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Restart..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "reboot"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Shut Down..."
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["systemctl", "poweroff"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuSeparator {}
|
||||
|
||||
MenuItem {
|
||||
text: "Lock Screen"
|
||||
shortcut: "Super+L"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["hyprlock"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Log Out"
|
||||
shortcut: "Super+Shift+Q"
|
||||
onTriggered: {
|
||||
let p = Qt.createQmlObject('import Quickshell.Io; Process { command: ["hyprctl", "dispatch", "exit"] }', quickMenu)
|
||||
p.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
531
home/hypr/quickshell/components/SidePanel.qml
Normal file
531
home/hypr/quickshell/components/SidePanel.qml
Normal file
@@ -0,0 +1,531 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
property var screen
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-sidepanel"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: false
|
||||
}
|
||||
|
||||
exclusiveZone: Theme.sidebarWidth
|
||||
implicitWidth: Theme.sidebarWidth
|
||||
color: Theme.bgPrimary
|
||||
|
||||
// Right edge hairline border
|
||||
Rectangle {
|
||||
width: 1
|
||||
color: Theme.glassBorder
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
component Separator: Rectangle {
|
||||
width: 36
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
component DockIcon: Item {
|
||||
id: dockIconRoot
|
||||
width: 36
|
||||
height: 36
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
property string appClass: ""
|
||||
property string execCmd: ""
|
||||
property string iconSource: ""
|
||||
property string tooltipText: ""
|
||||
|
||||
property bool isRunning: (appClass !== "" && GlobalState.activeWindowClass === appClass) || (GlobalState.runningApps && GlobalState.runningApps.indexOf(appClass) !== -1)
|
||||
|
||||
Image {
|
||||
id: img
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
source: iconSource ? Qt.resolvedUrl("../assets/" + iconSource) : ""
|
||||
sourceSize: Qt.size(24, 24)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
opacity: mouseArea.containsMouse ? 1.0 : 0.8
|
||||
|
||||
scale: mouseArea.containsMouse ? 1.15 : 1.0
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: runningDot
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.accentVolt
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: isRunning
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (execCmd !== "") {
|
||||
GlobalState.launchApp(execCmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
Rectangle {
|
||||
id: tooltip
|
||||
visible: mouseArea.containsMouse && tooltipText !== ""
|
||||
color: Theme.glassBg
|
||||
radius: 4
|
||||
width: tooltipLabel.implicitWidth + 16
|
||||
height: tooltipLabel.implicitHeight + 8
|
||||
|
||||
anchors.left: parent.right
|
||||
anchors.leftMargin: 24
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Text {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: tooltipText
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
// Top spacer
|
||||
Item { height: 4; Layout.fillWidth: true }
|
||||
|
||||
// 1. AG Logo Button
|
||||
Rectangle {
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 4
|
||||
color: logoMouse.containsMouse ? Qt.rgba(1,1,1,0.05) : "transparent"
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "AG"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 16
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: logoMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.appleMenuVisible = !GlobalState.appleMenuVisible
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 3. Workspace Indicators
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: GlobalState.workspaceList
|
||||
delegate: Rectangle {
|
||||
width: 52
|
||||
height: 36
|
||||
color: wsMouse.containsMouse ? Qt.rgba(1,1,1,0.04) : "transparent"
|
||||
|
||||
property bool isActive: GlobalState.activeWorkspace === modelData
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 2
|
||||
height: 20
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.accentVolt
|
||||
visible: isActive
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (modelData < 10 ? "0" : "") + modelData
|
||||
color: isActive ? Theme.accentVolt : Theme.textMuted
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (GlobalState.workspaceNames && GlobalState.workspaceNames[modelData]) ? GlobalState.workspaceNames[modelData] : ""
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 8
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wsMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.switchWorkspace(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 5. Spotlight trigger
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "⌕"
|
||||
font.pixelSize: 20
|
||||
color: spotlightMouse.containsMouse ? Theme.accentVolt : Theme.textMuted
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: spotlightMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.toggleSpotlight()
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 7. Pinned Apps
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
DockIcon {
|
||||
appClass: ""
|
||||
execCmd: "nautilus"
|
||||
iconSource: "finder.svg"
|
||||
tooltipText: "Finder"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "brave-browser"
|
||||
execCmd: "brave"
|
||||
iconSource: "browser.svg"
|
||||
tooltipText: "Brave Browser"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "foot"
|
||||
execCmd: "foot"
|
||||
iconSource: "terminal.svg"
|
||||
tooltipText: "Terminal"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "nvim"
|
||||
execCmd: "foot -e nvim"
|
||||
iconSource: "code.svg"
|
||||
tooltipText: "Code"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: "pavucontrol"
|
||||
execCmd: "pavucontrol"
|
||||
iconSource: "preferences.svg"
|
||||
tooltipText: "Settings"
|
||||
}
|
||||
DockIcon {
|
||||
appClass: ""
|
||||
execCmd: "spotify"
|
||||
iconSource: "music.svg"
|
||||
tooltipText: "Music"
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 9. Running Apps (non-pinned)
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
var pinned = ["foot", "brave-browser", "pavucontrol", "nvim", "nautilus", "spotify", ""]
|
||||
var running = []
|
||||
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]) {
|
||||
seen[cls] = true
|
||||
running.push(cls)
|
||||
}
|
||||
}
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: 36
|
||||
height: 36
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: Qt.rgba(1, 1, 1, 0.1)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: modelData.charAt(0).toUpperCase()
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 4
|
||||
height: 4
|
||||
radius: 2
|
||||
color: Theme.accentVolt
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
// Focus app logic here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Flexible spacer
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
Separator {}
|
||||
|
||||
// 12. Telemetry mini-readouts
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "CPU" + (GlobalState.cpuPercent !== undefined ? GlobalState.cpuPercent : "0") + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: (GlobalState.cpuPercent !== undefined && GlobalState.cpuPercent > 80) ? Theme.accentCoral : Theme.textMuted
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "RAM" + (GlobalState.memUsedGb !== undefined ? GlobalState.memUsedGb : "0") + "G"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: (GlobalState.memPercent !== undefined && GlobalState.memPercent > 85) ? Theme.accentCoral : Theme.textMuted
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "VRM" + (GlobalState.gpuVramUsed !== undefined ? GlobalState.gpuVramUsed : "0") + "G"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 14. System tray icons
|
||||
Column {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 8
|
||||
|
||||
// Volume
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/volume.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: volMouse.containsMouse ? 1.0 : 0.7
|
||||
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
MouseArea {
|
||||
id: volMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "volume"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WiFi
|
||||
Item {
|
||||
width: 36
|
||||
height: 36
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/wifi.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: GlobalState.wifiConnected ? 0.7 : 0.3
|
||||
Behavior on opacity { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "network"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Battery
|
||||
Item {
|
||||
width: 36
|
||||
height: 44
|
||||
visible: GlobalState.batteryPresent !== undefined ? GlobalState.batteryPresent : false
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 16
|
||||
height: 16
|
||||
source: Qt.resolvedUrl("../assets/battery.svg")
|
||||
sourceSize: Qt.size(16, 16)
|
||||
opacity: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? 1.0 : 0.7
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: (GlobalState.batteryPercent !== undefined ? GlobalState.batteryPercent : "100") + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 9
|
||||
color: (GlobalState.batteryPercent !== undefined && GlobalState.batteryPercent < 20) ? Theme.accentCoral : Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "battery"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Separator {}
|
||||
|
||||
// 16. Clock
|
||||
Item {
|
||||
width: 36
|
||||
height: 44
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: GlobalState.timeString !== undefined ? GlobalState.timeString : "00:00"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: GlobalState.dateString !== undefined ? GlobalState.dateString : "Jan 01"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 9
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
GlobalState.systemHudActiveSection = "calendar"
|
||||
GlobalState.systemHudVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom spacer
|
||||
Item { height: 4; Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ PanelWindow {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
color: Qt.rgba(0, 0, 0, 0.45)
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-spotlight"
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
@@ -35,7 +35,7 @@ PanelWindow {
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim());
|
||||
const parsed = JSON.parse(String(data).trim());
|
||||
if (Array.isArray(parsed)) {
|
||||
spotWindow.allApps = parsed;
|
||||
}
|
||||
@@ -67,223 +67,246 @@ PanelWindow {
|
||||
}
|
||||
|
||||
// Centered Spotlight Search Modal
|
||||
Rectangle {
|
||||
id: modalBox
|
||||
Item {
|
||||
id: modalContainer
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: 140
|
||||
width: 640
|
||||
implicitHeight: searchBarRow.height + (resultsListView.count > 0 || mathResultText !== "" ? 340 : 0)
|
||||
radius: Theme.radiusModal
|
||||
color: Theme.windowBg
|
||||
border.color: Theme.windowBorder
|
||||
border.width: 1
|
||||
height: modalBox.implicitHeight
|
||||
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutQuad }
|
||||
scale: spotWindow.visible ? 1.0 : 0.96
|
||||
opacity: spotWindow.visible ? 1.0 : 0.0
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: Theme.animSmooth; easing.type: Easing.OutQuint }
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.animSmooth; easing.type: Easing.OutQuint }
|
||||
}
|
||||
|
||||
// Prevent clicking inside from closing modal
|
||||
MouseArea {
|
||||
Rectangle {
|
||||
id: modalBox
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
implicitHeight: searchBarRowContainer.height + (resultsListView.count > 0 || mathResultText !== "" ? 340 : 0)
|
||||
radius: 0
|
||||
color: Theme.bgPrimary
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
Behavior on implicitHeight {
|
||||
NumberAnimation { duration: 180; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
// Top Search Bar
|
||||
RowLayout {
|
||||
id: searchBarRow
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 44
|
||||
spacing: 12
|
||||
// Prevent clicking inside from closing modal
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {}
|
||||
}
|
||||
|
||||
Image {
|
||||
width: 24
|
||||
height: 24
|
||||
source: "../assets/spotlight.svg"
|
||||
sourceSize: Qt.size(24, 24)
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
// Top Search Bar Area
|
||||
Item {
|
||||
id: searchBarRowContainer
|
||||
Layout.fillWidth: true
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textPrimary
|
||||
focus: true
|
||||
clip: true
|
||||
Layout.preferredHeight: 64
|
||||
|
||||
Text {
|
||||
RowLayout {
|
||||
id: searchBarRow
|
||||
anchors.fill: parent
|
||||
visible: searchInput.text === ""
|
||||
text: "Spotlight Search"
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSpotlight
|
||||
font.weight: Font.Light
|
||||
color: Theme.textTertiary
|
||||
anchors.margins: 14
|
||||
spacing: 12
|
||||
|
||||
Text {
|
||||
text: "⌕"
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 24
|
||||
color: Theme.accentVolt
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 20
|
||||
color: Theme.textPrimary
|
||||
focus: true
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
visible: searchInput.text === ""
|
||||
text: "Spotlight Search"
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 20
|
||||
color: Theme.textMuted
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: GlobalState.spotlightVisible = false
|
||||
Keys.onDownPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.min(resultsListView.count - 1, spotWindow.selectedIndex + 1);
|
||||
}
|
||||
}
|
||||
Keys.onUpPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.max(0, spotWindow.selectedIndex - 1);
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
if (filteredModel.count > 0 && spotWindow.selectedIndex < filteredModel.count) {
|
||||
const item = filteredModel.get(spotWindow.selectedIndex);
|
||||
GlobalState.launchApp(item.exec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear button
|
||||
Rectangle {
|
||||
visible: searchInput.text !== ""
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
font.pixelSize: 16
|
||||
color: clearMouseArea.containsMouse ? Theme.textPrimary : Theme.textMuted
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clearMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: searchInput.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: GlobalState.spotlightVisible = false
|
||||
Keys.onDownPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.min(resultsListView.count - 1, spotWindow.selectedIndex + 1);
|
||||
}
|
||||
}
|
||||
Keys.onUpPressed: {
|
||||
if (resultsListView.count > 0) {
|
||||
spotWindow.selectedIndex = Math.max(0, spotWindow.selectedIndex - 1);
|
||||
}
|
||||
}
|
||||
Keys.onReturnPressed: {
|
||||
if (filteredModel.count > 0 && spotWindow.selectedIndex < filteredModel.count) {
|
||||
const item = filteredModel.get(spotWindow.selectedIndex);
|
||||
GlobalState.launchApp(item.exec);
|
||||
}
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
}
|
||||
|
||||
// Clear button
|
||||
// Math Calculation Result Banner (if valid formula)
|
||||
Rectangle {
|
||||
visible: searchInput.text !== ""
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 10
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.2)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
font.pixelSize: 11
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: searchInput.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Math Calculation Result Banner (if valid formula)
|
||||
Rectangle {
|
||||
visible: mathResultText !== ""
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
radius: Theme.radiusSmall
|
||||
color: Qt.rgba(0.04, 0.52, 1.0, 0.2)
|
||||
border.color: Theme.accentBlue
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "="
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
color: Theme.accentBlue
|
||||
}
|
||||
Text {
|
||||
text: mathResultText
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.DemiBold
|
||||
color: "#FFFFFF"
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divider Line
|
||||
Rectangle {
|
||||
visible: resultsListView.count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
}
|
||||
|
||||
// Search Results List View
|
||||
ListView {
|
||||
id: resultsListView
|
||||
visible: count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.min(270, count * 42)
|
||||
clip: true
|
||||
spacing: 2
|
||||
model: filteredModel
|
||||
|
||||
delegate: Rectangle {
|
||||
id: itemDelegate
|
||||
required property int index
|
||||
required property string name
|
||||
required property string exec
|
||||
required property string comment
|
||||
|
||||
width: resultsListView.width
|
||||
height: 40
|
||||
radius: Theme.radiusSmall
|
||||
color: spotWindow.selectedIndex === index ? Theme.menuHoverBlue : "transparent"
|
||||
visible: mathResultText !== ""
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
Layout.margins: 14
|
||||
radius: 0
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
spacing: 10
|
||||
|
||||
Image {
|
||||
width: 22
|
||||
height: 22
|
||||
source: "../assets/terminal.svg"
|
||||
sourceSize: Qt.size(22, 22)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 1
|
||||
|
||||
Text {
|
||||
text: itemDelegate.name
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeNormal
|
||||
font.weight: Font.Medium
|
||||
color: "#FFFFFF"
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: itemDelegate.comment || itemDelegate.exec
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? Qt.rgba(1,1,1,0.85) : Theme.textTertiary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
anchors.margins: 8
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "↩"
|
||||
font.pixelSize: 14
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? "#FFFFFF" : "transparent"
|
||||
text: "="
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: mathResultText
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 16
|
||||
color: Theme.accentVolt
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: spotWindow.selectedIndex = itemDelegate.index
|
||||
onClicked: GlobalState.launchApp(itemDelegate.exec)
|
||||
// Search Results List View
|
||||
ListView {
|
||||
id: resultsListView
|
||||
visible: count > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.min(270, count * 40)
|
||||
Layout.topMargin: 8
|
||||
Layout.bottomMargin: 8
|
||||
clip: true
|
||||
spacing: 0
|
||||
model: filteredModel
|
||||
|
||||
delegate: Rectangle {
|
||||
id: itemDelegate
|
||||
required property int index
|
||||
required property string name
|
||||
required property string exec
|
||||
required property string comment
|
||||
|
||||
width: resultsListView.width
|
||||
height: 40
|
||||
radius: 0
|
||||
color: spotWindow.selectedIndex === index ? Qt.rgba(0.812, 0.988, 0.0, 0.08) : "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 2
|
||||
color: Theme.accentVolt
|
||||
visible: spotWindow.selectedIndex === index
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 14
|
||||
anchors.rightMargin: 14
|
||||
spacing: 12
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: itemDelegate.name
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
color: Theme.textPrimary
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: itemDelegate.comment || itemDelegate.exec
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "↩"
|
||||
font.pixelSize: 14
|
||||
color: spotWindow.selectedIndex === itemDelegate.index
|
||||
? Theme.textPrimary : "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: spotWindow.selectedIndex = itemDelegate.index
|
||||
onClicked: GlobalState.launchApp(itemDelegate.exec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
685
home/hypr/quickshell/components/SystemHUD.qml
Normal file
685
home/hypr/quickshell/components/SystemHUD.qml
Normal file
@@ -0,0 +1,685 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
}
|
||||
|
||||
margins {
|
||||
left: Theme.sidebarWidth
|
||||
top: Theme.topStripHeight
|
||||
}
|
||||
|
||||
implicitWidth: Theme.hudWidth
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-systemhud"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
|
||||
visible: GlobalState.systemHudVisible
|
||||
|
||||
color: "transparent"
|
||||
|
||||
property real slideOffset: GlobalState.systemHudVisible ? 0 : -Theme.hudWidth
|
||||
Behavior on slideOffset {
|
||||
NumberAnimation {
|
||||
duration: Theme.animSmooth
|
||||
easing.type: Easing.OutQuint
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Escape"
|
||||
onActivated: GlobalState.systemHudVisible = false
|
||||
}
|
||||
|
||||
component SectionHeader: Item {
|
||||
property string sectionNum: "00"
|
||||
property string title: "Section"
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 24
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
Text {
|
||||
text: sectionNum + " //"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: title
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 16
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ToggleCard: Rectangle {
|
||||
property string title: ""
|
||||
property string icon: ""
|
||||
property bool active: false
|
||||
signal clicked()
|
||||
|
||||
Layout.preferredWidth: 160
|
||||
Layout.preferredHeight: 56
|
||||
color: Theme.bgPrimary
|
||||
border.color: active ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.3) : Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 4
|
||||
|
||||
Behavior on border.color { ColorAnimation { duration: Theme.animFast } }
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: clicked()
|
||||
onEntered: if (!active) border.color = Theme.glassBorderHover
|
||||
onExited: if (!active) border.color = Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 12
|
||||
Image {
|
||||
source: icon ? Qt.resolvedUrl("../" + icon) : ""
|
||||
Layout.preferredWidth: 24
|
||||
Layout.preferredHeight: 24
|
||||
sourceSize: Qt.size(24, 24)
|
||||
visible: parent.icon !== ""
|
||||
}
|
||||
Text {
|
||||
text: title
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component CustomSlider: Item {
|
||||
property real value: 0
|
||||
signal valueChangedUser(real newVal)
|
||||
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: 24
|
||||
|
||||
Rectangle {
|
||||
id: track
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - 40
|
||||
height: 6
|
||||
color: Theme.bgSecondary
|
||||
radius: 3
|
||||
|
||||
Rectangle {
|
||||
id: fill
|
||||
width: track.width * (parent.parent.value / 100)
|
||||
height: track.height
|
||||
color: Theme.accentVolt
|
||||
radius: 3
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 14
|
||||
height: 14
|
||||
radius: 7
|
||||
color: Theme.textPrimary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: Math.max(0, fill.width - 7)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
function updateValue(mouseX) {
|
||||
let p = Math.max(0, Math.min(1, mouseX / track.width))
|
||||
parent.parent.valueChangedUser(p * 100)
|
||||
}
|
||||
onPressed: (mouse) => updateValue(mouse.x)
|
||||
onPositionChanged: (mouse) => updateValue(mouse.x)
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: Math.round(parent.value) + "%"
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
component ProgressBarItem: ColumnLayout {
|
||||
property string label: ""
|
||||
property real percent: 0
|
||||
property string valueText: ""
|
||||
property color barColor: Theme.accentVolt
|
||||
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: parent.parent.label
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Text {
|
||||
text: parent.parent.valueText
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 8
|
||||
color: Theme.bgSecondary
|
||||
radius: 4
|
||||
|
||||
Rectangle {
|
||||
width: parent.width * (parent.parent.percent / 100)
|
||||
height: parent.height
|
||||
color: parent.parent.barColor
|
||||
radius: 4
|
||||
Behavior on width { NumberAnimation { duration: Theme.animFast; easing.type: Easing.OutCubic } }
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFast } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: panelContent
|
||||
anchors.fill: parent
|
||||
color: Theme.glassBg
|
||||
opacity: GlobalState.systemHudVisible ? 1 : 0
|
||||
|
||||
transform: Translate { x: slideOffset }
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.animSmooth
|
||||
easing.type: Easing.OutQuint
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
Item {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 60
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 20
|
||||
anchors.rightMargin: 20
|
||||
|
||||
Text {
|
||||
text: "System HUD"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 19
|
||||
color: Theme.textPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "✕"
|
||||
color: Theme.textMuted
|
||||
font.pixelSize: 16
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: GlobalState.systemHudVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
anchors.top: header.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
contentWidth: availableWidth
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
id: contentLayout
|
||||
width: parent.width - 40
|
||||
x: 20
|
||||
spacing: 32
|
||||
|
||||
Item { Layout.preferredHeight: 16 } // Top padding
|
||||
|
||||
// Section 1: Toggles
|
||||
ColumnLayout {
|
||||
id: sectionToggles
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "01"; title: "Toggles" }
|
||||
GridLayout {
|
||||
columns: 2
|
||||
columnSpacing: 12
|
||||
rowSpacing: 12
|
||||
Layout.fillWidth: true
|
||||
|
||||
ToggleCard {
|
||||
title: GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "Wi-Fi"
|
||||
icon: "assets/wifi.svg"
|
||||
active: GlobalState.wifiConnected
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
title: "Bluetooth"
|
||||
icon: "assets/bluetooth.svg"
|
||||
active: false // Adjust if there's a bluetooth state
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "foot -e bluetoothctl"])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
property bool dndActive: false
|
||||
title: "Do Not Disturb"
|
||||
icon: "" // Optional DND icon
|
||||
active: dndActive
|
||||
onClicked: dndActive = !dndActive
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
title: GlobalState.volumeMuted ? "Muted" : "Sound"
|
||||
icon: "" // Optional sound icon
|
||||
active: !GlobalState.volumeMuted
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 2: Volume
|
||||
ColumnLayout {
|
||||
id: sectionVolume
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "02"; title: "Volume" }
|
||||
|
||||
CustomSlider {
|
||||
Layout.fillWidth: true
|
||||
value: GlobalState.volume
|
||||
onValueChangedUser: (val) => GlobalState.volume = val // Adjust to actual volume setter if needed
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: GlobalState.volumeMuted ? "Unmute" : "Mute"
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Text {
|
||||
text: "Sound Preferences..."
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("pavucontrol", [])
|
||||
proc.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 3: Brightness
|
||||
ColumnLayout {
|
||||
id: sectionBrightness
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "03"; title: "Brightness" }
|
||||
|
||||
CustomSlider {
|
||||
Layout.fillWidth: true
|
||||
value: GlobalState.brightness
|
||||
onValueChangedUser: (val) => GlobalState.setBrightness(val)
|
||||
}
|
||||
}
|
||||
|
||||
// Section 4: Performance
|
||||
ColumnLayout {
|
||||
id: sectionPerformance
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "04"; title: "Performance" }
|
||||
|
||||
ProgressBarItem {
|
||||
label: "CPU"
|
||||
percent: GlobalState.cpuPercent
|
||||
valueText: GlobalState.cpuPercent + "%"
|
||||
barColor: GlobalState.cpuPercent > 80 ? Theme.accentCoral : Theme.accentVolt
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "RAM"
|
||||
percent: (GlobalState.memUsedGb / Math.max(1, GlobalState.memTotalGb)) * 100
|
||||
valueText: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "VRAM"
|
||||
percent: (GlobalState.gpuVramUsed / Math.max(1, GlobalState.gpuVramTotal)) * 100
|
||||
valueText: GlobalState.gpuVramUsed + " / " + GlobalState.gpuVramTotal + " GB"
|
||||
}
|
||||
}
|
||||
|
||||
// Section 5: Network
|
||||
ColumnLayout {
|
||||
id: sectionNetwork
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "05"; title: "Network" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 8
|
||||
Rectangle {
|
||||
width: 8
|
||||
height: 8
|
||||
radius: 4
|
||||
color: GlobalState.wifiConnected ? Theme.accentVolt : Theme.accentCoral
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.wifiConnected ? "Connected" : "Disconnected"
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "SSID: " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "None")
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "IP: " + GlobalState.ipAddress
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Network Preferences..."
|
||||
color: Theme.textMuted
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 6: Battery
|
||||
ColumnLayout {
|
||||
id: sectionBattery
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
visible: GlobalState.batteryPresent
|
||||
SectionHeader { sectionNum: "06"; title: "Battery" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 16
|
||||
Text {
|
||||
text: GlobalState.batteryPercent + "%"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 24
|
||||
color: GlobalState.batteryStatus === "Charging" ? Theme.accentVolt :
|
||||
(GlobalState.batteryPercent < 20 ? Theme.accentCoral : Theme.textPrimary)
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.batteryStatus
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 7: Now Playing
|
||||
ColumnLayout {
|
||||
id: sectionNowPlaying
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
visible: GlobalState.mediaTitle !== ""
|
||||
SectionHeader { sectionNum: "07"; title: "Now Playing" }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 4
|
||||
Text {
|
||||
text: GlobalState.mediaTitle
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.bold: true
|
||||
font.pixelSize: 14
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaArtist
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: "⏮"
|
||||
font.pixelSize: 20
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaPrevious()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaStatus === "Playing" ? "⏸" : "▶"
|
||||
font.pixelSize: 24
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaPlayPause()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: "⏭"
|
||||
font.pixelSize: 20
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -10
|
||||
hoverEnabled: true
|
||||
onEntered: parent.color = Theme.accentVolt
|
||||
onExited: parent.color = Theme.textSecondary
|
||||
onClicked: GlobalState.mediaNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section 8: Calendar
|
||||
ColumnLayout {
|
||||
id: sectionCalendar
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
SectionHeader { sectionNum: "08"; title: "Calendar" }
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
Text {
|
||||
text: GlobalState.timeString
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 22
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.fullDateString
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
color: Theme.textSecondary
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 7
|
||||
columnSpacing: 4
|
||||
rowSpacing: 4
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Repeater {
|
||||
model: ["S", "M", "T", "W", "T", "F", "S"]
|
||||
Text {
|
||||
text: modelData
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 11
|
||||
color: Theme.textMuted
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: 32
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 31
|
||||
Rectangle {
|
||||
property bool isToday: (index + 1) === new Date().getDate()
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
color: isToday ? Theme.accentVolt : "transparent"
|
||||
radius: isToday ? 0 : 4
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: index + 1
|
||||
color: parent.isToday ? "#ffffff" : Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: if (!parent.isToday) parent.color = Qt.rgba(1, 1, 1, 0.04)
|
||||
onExited: if (!parent.isToday) parent.color = "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 20 } // Bottom padding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-scroll to active section when changed
|
||||
Connections {
|
||||
target: GlobalState
|
||||
function onSystemHudActiveSectionChanged() {
|
||||
if (!GlobalState.systemHudVisible) return;
|
||||
|
||||
let targetY = 0;
|
||||
if (GlobalState.systemHudActiveSection === "volume") targetY = sectionVolume.y;
|
||||
else if (GlobalState.systemHudActiveSection === "brightness") targetY = sectionBrightness.y;
|
||||
else if (GlobalState.systemHudActiveSection === "performance") targetY = sectionPerformance.y;
|
||||
else if (GlobalState.systemHudActiveSection === "network") targetY = sectionNetwork.y;
|
||||
else if (GlobalState.systemHudActiveSection === "battery") targetY = sectionBattery.y;
|
||||
else if (GlobalState.systemHudActiveSection === "nowplaying") targetY = sectionNowPlaying.y;
|
||||
else if (GlobalState.systemHudActiveSection === "calendar") targetY = sectionCalendar.y;
|
||||
|
||||
if (targetY > 0) {
|
||||
// Ensure targetY doesn't scroll past max possible scroll
|
||||
let maxY = Math.max(0, contentLayout.height - scrollView.height);
|
||||
scrollView.ScrollBar.vertical.position = Math.min(targetY, maxY) / contentLayout.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
257
home/hypr/quickshell/components/SystemInfo.qml
Normal file
257
home/hypr/quickshell/components/SystemInfo.qml
Normal file
@@ -0,0 +1,257 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: systemInfoDialog
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
visible: GlobalState.aboutMacVisible
|
||||
color: Qt.rgba(0, 0, 0, 0.35)
|
||||
|
||||
// Close on click outside or Escape
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
Keys.onEscapePressed: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
|
||||
property string cpuName: ""
|
||||
property string gpuName: ""
|
||||
|
||||
// Process to get CPU info
|
||||
Process {
|
||||
id: cpuProcess
|
||||
command: ["sh", "-c", "grep 'model name' /proc/cpuinfo | head -n1 | cut -d':' -f2 | xargs"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = String(data).trim();
|
||||
if (val.length > 0) systemInfoDialog.cpuName = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process to get GPU info
|
||||
Process {
|
||||
id: gpuProcess
|
||||
command: ["sh", "-c", "nvidia-smi --query-gpu=name --format=csv,noheader | head -n1"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
const val = String(data).trim();
|
||||
if (val.length > 0) systemInfoDialog.gpuName = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: dialogBox
|
||||
width: 480
|
||||
height: 320
|
||||
anchors.centerIn: parent
|
||||
color: Theme.glassBg
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 0
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
// Eat clicks so they don't close the dialog
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Header bar
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeBtn
|
||||
width: 40
|
||||
height: 40
|
||||
anchors.left: parent.left
|
||||
color: closeMouseArea.containsMouse ? Theme.accentCoral : "transparent"
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: closeMouseArea.containsMouse ? Theme.textPrimary : Theme.textSecondary
|
||||
font.pixelSize: 14
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: GlobalState.aboutMacVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "System Info"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 15
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "Silicon Volt"
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: 24
|
||||
color: Theme.accentVolt
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "NixOS // Hyprland"
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textMuted
|
||||
bottomPadding: 16
|
||||
}
|
||||
|
||||
Grid {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
columns: 2
|
||||
spacing: 12
|
||||
rowSpacing: 8
|
||||
|
||||
// HOST
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "HOST"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "hades"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// CPU
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "CPU"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { id: cpuText; text: systemInfoDialog.cpuName || "Loading..."; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// MEMORY
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "MEMORY"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// GPU
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "GPU"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { id: gpuText; text: systemInfoDialog.gpuName || "Loading..."; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// VRAM
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "VRAM"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: GlobalState.gpuVramUsed + " / " + GlobalState.gpuVramTotal + " GB"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// WM
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "WM"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "Hyprland"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
|
||||
// OS
|
||||
Text { width: 100; horizontalAlignment: Text.AlignRight; text: "OS"; font.family: Theme.fontMono; font.pixelSize: 11; color: Theme.textMuted }
|
||||
Text { text: "NixOS"; font.family: Theme.fontSans; font.pixelSize: 13; color: Theme.textSecondary }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Footer bar
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 44
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
component FooterButton: Rectangle {
|
||||
id: btn
|
||||
property string text: ""
|
||||
property alias command: proc.command
|
||||
|
||||
width: btnText.width + 24
|
||||
height: 28
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: btnMouse.containsMouse ? Qt.rgba(Theme.accentVolt.r, Theme.accentVolt.g, Theme.accentVolt.b, 0.1) : "transparent"
|
||||
border.color: Theme.glassBorder
|
||||
border.width: 1
|
||||
radius: 0
|
||||
|
||||
Text {
|
||||
id: btnText
|
||||
anchors.centerIn: parent
|
||||
text: btn.text
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
color: btnMouse.containsMouse ? Theme.accentVolt : Theme.textMuted
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: btnMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: proc.running = true
|
||||
}
|
||||
|
||||
Process {
|
||||
id: proc
|
||||
}
|
||||
}
|
||||
|
||||
FooterButton {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
text: "System Report..."
|
||||
command: ["foot", "-e", "btop"]
|
||||
}
|
||||
|
||||
FooterButton {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 16
|
||||
text: "Software Update..."
|
||||
command: ["foot", "-e", "sudo", "nixos-rebuild", "dry-activate"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
home/hypr/quickshell/components/TopStrip.qml
Normal file
101
home/hypr/quickshell/components/TopStrip.qml
Normal file
@@ -0,0 +1,101 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
property var modelData
|
||||
screen: modelData
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
margins.left: Theme.sidebarWidth
|
||||
|
||||
implicitHeight: Theme.topStripHeight
|
||||
color: Qt.rgba(Theme.bgPrimary.r, Theme.bgPrimary.g, Theme.bgPrimary.b, 0.92)
|
||||
exclusiveZone: Theme.topStripHeight
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "quickshell-topstrip"
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
Rectangle {
|
||||
id: bottomBorder
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: 1
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
spacing: 16
|
||||
|
||||
// Left Section
|
||||
Text {
|
||||
id: workspaceIndicator
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
// Center Section
|
||||
Text {
|
||||
id: windowTitle
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.family: Theme.fontSerif
|
||||
font.italic: true
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.textSecondary
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
|
||||
text: GlobalState.activeWindowTitle
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
// Right Section
|
||||
Text {
|
||||
id: clock
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
text: GlobalState.timeString
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,55 +25,60 @@ Scope {
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "controlCenter"
|
||||
target: "systemHud"
|
||||
function toggle() {
|
||||
GlobalState.toggleControlCenter();
|
||||
GlobalState.toggleSystemHud();
|
||||
}
|
||||
function open() {
|
||||
GlobalState.controlCenterVisible = true;
|
||||
GlobalState.systemHudVisible = true;
|
||||
}
|
||||
function close() {
|
||||
GlobalState.controlCenterVisible = false;
|
||||
GlobalState.systemHudVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "aboutMac"
|
||||
target: "systemInfo"
|
||||
function toggle() {
|
||||
GlobalState.toggleAboutMac();
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// MULTI-MONITOR BARS & DOCKS
|
||||
// LEFT SIDEBAR (Primary monitor only)
|
||||
// =========================================================================
|
||||
// 1. macOS Catalina Top Menu Bar (Spawned per monitor)
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
MenuBar {}
|
||||
SidePanel {
|
||||
screen: Quickshell.screens[0]
|
||||
}
|
||||
|
||||
// 2. macOS Catalina Floating Dock (Spawned per monitor)
|
||||
// =========================================================================
|
||||
// TOP STATUS STRIP (All monitors)
|
||||
// =========================================================================
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
Dock {}
|
||||
TopStrip {}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// GLOBAL MODAL OVERLAYS
|
||||
// =========================================================================
|
||||
// 3. Spotlight Search Overlay
|
||||
// Spotlight Search Overlay
|
||||
Spotlight {
|
||||
id: spotlightOverlay
|
||||
}
|
||||
|
||||
// 4. Control Center & Notification Center Sidebar
|
||||
ControlCenter {
|
||||
id: controlCenterSidebar
|
||||
// System HUD Flyout Panel
|
||||
SystemHUD {
|
||||
id: systemHudPanel
|
||||
}
|
||||
|
||||
// 5. About This Mac Dialog
|
||||
AboutMac {
|
||||
id: aboutMacDialog
|
||||
// Quick Menu (Power/Session Menu)
|
||||
QuickMenu {
|
||||
id: quickMenuOverlay
|
||||
}
|
||||
|
||||
// System Info Dialog
|
||||
SystemInfo {
|
||||
id: systemInfoDialog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,56 +2,45 @@ pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
// macOS Catalina Color Palette
|
||||
readonly property color menuBarBg: Qt.rgba(0.12, 0.12, 0.14, 0.88)
|
||||
readonly property color menuBarBorder: Qt.rgba(1.0, 1.0, 1.0, 0.12)
|
||||
|
||||
readonly property color dockBg: Qt.rgba(0.15, 0.16, 0.18, 0.72)
|
||||
readonly property color dockBorder: Qt.rgba(1.0, 1.0, 1.0, 0.22)
|
||||
readonly property color dockHighlight: Qt.rgba(1.0, 1.0, 1.0, 0.35)
|
||||
readonly property color dockShadow: Qt.rgba(0.0, 0.0, 0.0, 0.45)
|
||||
readonly property color dockDot: Qt.rgba(1.0, 1.0, 1.0, 0.95)
|
||||
|
||||
readonly property color windowBg: Qt.rgba(0.14, 0.14, 0.16, 0.94)
|
||||
readonly property color windowBorder: Qt.rgba(1.0, 1.0, 1.0, 0.15)
|
||||
readonly property color cardBg: Qt.rgba(0.22, 0.22, 0.26, 0.65)
|
||||
readonly property color cardBorder: Qt.rgba(1.0, 1.0, 1.0, 0.10)
|
||||
|
||||
readonly property color menuDropdownBg: Qt.rgba(0.16, 0.16, 0.18, 0.96)
|
||||
readonly property color menuDropdownBorder: Qt.rgba(1.0, 1.0, 1.0, 0.18)
|
||||
readonly property color menuHoverBlue: "#0062E3"
|
||||
readonly property color menuTextHover: "#FFFFFF"
|
||||
|
||||
readonly property color accentBlue: "#0A84FF"
|
||||
readonly property color accentGreen: "#30D158"
|
||||
readonly property color accentRed: "#FF453A"
|
||||
readonly property color accentYellow: "#FFD60A"
|
||||
readonly property color accentOrange: "#FF9F0A"
|
||||
|
||||
// Colors
|
||||
readonly property color bgPrimary: "#131313"
|
||||
readonly property color bgSecondary: "#0e0e0e"
|
||||
readonly property color glassBg: "#1c1b1b"
|
||||
readonly property color glassBorder: Qt.rgba(1.0, 1.0, 1.0, 0.08)
|
||||
readonly property color glassBorderHover: Qt.rgba(1.0, 1.0, 1.0, 0.18)
|
||||
readonly property color accentVolt: "#CFFC00"
|
||||
readonly property color accentVoltGlow: Qt.rgba(0.812, 0.988, 0.0, 0.25)
|
||||
readonly property color accentVoltLight: "#e3ff66"
|
||||
readonly property color accentBlue: "#00BFFF"
|
||||
readonly property color accentCoral: "#FF7A59"
|
||||
readonly property color textPrimary: "#FFFFFF"
|
||||
readonly property color textSecondary: Qt.rgba(1.0, 1.0, 1.0, 0.72)
|
||||
readonly property color textTertiary: Qt.rgba(1.0, 1.0, 1.0, 0.45)
|
||||
readonly property color textSecondary: "#e5e2e1"
|
||||
readonly property color textMuted: "#ADAAAA"
|
||||
readonly property color textDisabled: Qt.rgba(1.0, 1.0, 1.0, 0.25)
|
||||
|
||||
// Typography
|
||||
readonly property string fontFamily: "SF Pro Display, SF Pro Text, Helvetica Neue, Cantarell, Liberation Sans, sans-serif"
|
||||
readonly property int fontSizeMenuBar: 13
|
||||
readonly property string fontSerif: "Instrument Serif, Georgia, serif"
|
||||
readonly property string fontSans: "IBM Plex Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif"
|
||||
readonly property string fontMono: "Nanum Gothic Coding, JetBrains Mono, monospace"
|
||||
|
||||
readonly property int fontSizeSmall: 11
|
||||
readonly property int fontSizeNormal: 13
|
||||
readonly property int fontSizeLarge: 15
|
||||
readonly property int fontSizeTitle: 19
|
||||
readonly property int fontSizeSpotlight: 20
|
||||
readonly property int fontSizeDisplay: 24
|
||||
readonly property int fontSizeWorkspace: 12
|
||||
|
||||
// Geometry & Radii
|
||||
readonly property int menuBarHeight: 26
|
||||
readonly property int radiusSmall: 4
|
||||
readonly property int radiusMedium: 8
|
||||
readonly property int radiusLarge: 14
|
||||
readonly property int radiusDock: 18
|
||||
readonly property int radiusModal: 16
|
||||
// Geometry
|
||||
readonly property int radiusNone: 0
|
||||
readonly property int sidebarWidth: 52
|
||||
readonly property int topStripHeight: 28
|
||||
readonly property int hudWidth: 360
|
||||
readonly property int iconSize: 36
|
||||
readonly property int iconSizeSmall: 20
|
||||
readonly property int workspaceIndicatorWidth: 2
|
||||
|
||||
// Animation Durations
|
||||
readonly property int animFast: 120
|
||||
readonly property int animNormal: 220
|
||||
readonly property int animSmooth: 320
|
||||
readonly property int animSmooth: 400
|
||||
readonly property int animFast: 200
|
||||
readonly property int animBounce: 600
|
||||
}
|
||||
|
||||
7
home/pi.nix
Normal file
7
home/pi.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ inputs, config, ... }:
|
||||
{
|
||||
imports = [ inputs.pi.homeModules.default ];
|
||||
programs.pi.coding-agent = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
# Core Editors & AI Agents
|
||||
neovim
|
||||
antigravity-cli
|
||||
pi-coding-agent
|
||||
|
||||
# Languages & Toolchains
|
||||
uv
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
comfy-ui-cuda
|
||||
unstable.ollama-cuda
|
||||
];
|
||||
}
|
||||
|
||||
@@ -8,8 +8,23 @@
|
||||
"flakes"
|
||||
];
|
||||
auto-optimise-store = true;
|
||||
substituters = [ "https://cache.nixos-cuda.org" ];
|
||||
trusted-public-keys = [ "cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M=" ];
|
||||
extra-substituters = [
|
||||
"https://cache.nixos-cuda.org"
|
||||
"https://pi.cachix.org"
|
||||
"https://comfyui.cachix.org"
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
extra-trusted-public-keys = [
|
||||
"cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M="
|
||||
"pi.cachix.org-1:lGeoGJaZ5ZDabuRzkcD5EBTNnDM4HJ1vqeOxlWk1Flk="
|
||||
"comfyui.cachix.org-1:33mf9VzoIjzVbp0zwj+fT51HG0y31ZTK3nzYZAX0rec="
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
trusted-users = [
|
||||
"root"
|
||||
"@wheel"
|
||||
"anish"
|
||||
];
|
||||
};
|
||||
|
||||
gc = {
|
||||
|
||||
Reference in New Issue
Block a user