my over complex system configurations dotfiles.isabelroses.com/
nixos nix flake dotfiles linux

Compare changes

Choose any two refs to compare.

+20 -1
README.md
··· 10 10 11 11 <br /> 12 12 13 - ![Preview image](./docs/src/images/main.webp) 13 + ![Preview image](./docs/src/images/main.png) 14 + 15 + <details> 16 + <summary>more previews</summary> 17 + 18 + <p align="center"> 19 + light mode 20 + <img src="./docs/src/images/lightmode.png" width="800px" /> 21 + </p> 22 + 23 + <p align="center"> 24 + wezterm + chromium 25 + <img src="./docs/src/images/blur.png" width="800px" /> 26 + </p> 27 + 28 + <p align="center"> 29 + neovim 30 + <img src="./docs/src/images/nvim.png" width="800px" /> 31 + </p> 32 + </details> 14 33 15 34 ![image of my flakes topology](./docs/src/images/topology.png) 16 35
-8
docs/src/README.md
··· 8 8 <img alt="nixos-unstable" src="https://img.shields.io/badge/NixOS-unstable-blue.svg?style=for-the-badge&labelColor=303446&logo=NixOS&logoColor=white&color=91D7E3" /> 9 9 </div> 10 10 11 - <br /> 12 - 13 - ![Preview image](./docs/src/images/main.webp) 14 - 15 - ![image of my flakes topology](./docs/src/images/topology.png) 16 - 17 11 ### Foreword 18 12 19 13 This repository contains my **personal** configuration for my systems, so its really important that you know it's **personal** and not everything will fit your needs. ··· 28 22 - Sensible defaults, so you can get started quickly 29 23 - Docs kind of 30 24 - [Catppuccin](https://github.com/catppuccin/catppuccin) everywhere. 31 - 32 - [![Star History Chart](https://api.star-history.com/svg?repos=isabelroses/dotfiles&type=Date)](https://star-history.com/#isabelroses/dotfiles&Date)
+1
docs/src/SUMMARY.md
··· 35 35 # Misc 36 36 37 37 - [mirrors](misc/mirrors.md) 38 + - [previews](misc/previews.md)
docs/src/images/blur.png

This is a binary file and will not be displayed.

docs/src/images/blur.webp

This is a binary file and will not be displayed.

docs/src/images/lightmode.png

This is a binary file and will not be displayed.

docs/src/images/lightmode.webp

This is a binary file and will not be displayed.

docs/src/images/main.png

This is a binary file and will not be displayed.

docs/src/images/main.webp

This is a binary file and will not be displayed.

docs/src/images/nvim.png

This is a binary file and will not be displayed.

docs/src/images/nvim.webp

This is a binary file and will not be displayed.

+5
docs/src/misc/previews.md
··· 1 + ![Preview image](/images/main.png) 2 + ![images/lightmode.png](/images/lightmode.png) 3 + ![images/blur](/images/blur.png) 4 + ![images/nvim](/images/nvim.png) 5 + ![image of my flakes topology](/images/topology.png)
+45 -45
flake.lock
··· 24 24 ] 25 25 }, 26 26 "locked": { 27 - "lastModified": 1767967164, 28 - "narHash": "sha256-Cx4VETh9dGoQYDtWhre7g66d7SAr+h1h6f+SSHxVrck=", 27 + "lastModified": 1767720192, 28 + "narHash": "sha256-gA2dpQr/REM9D4SUdMwioAATnXmOZz/eVIladxEISRA=", 29 29 "owner": "catppuccin", 30 30 "repo": "nix", 31 - "rev": "e973584280e3b0e1d5b5a1a5e9948dc222c54af7", 31 + "rev": "bbda4b492ba33c1ca04385792c93dda1a3a28f64", 32 32 "type": "github" 33 33 }, 34 34 "original": { ··· 39 39 }, 40 40 "crane": { 41 41 "locked": { 42 - "lastModified": 1767461147, 43 - "narHash": "sha256-TH/xTeq/RI+DOzo+c+4F431eVuBpYVwQwBxzURe7kcI=", 42 + "lastModified": 1766774972, 43 + "narHash": "sha256-8qxEFpj4dVmIuPn9j9z6NTbU+hrcGjBOvaxTzre5HmM=", 44 44 "owner": "ipetkov", 45 45 "repo": "crane", 46 - "rev": "7d59256814085fd9666a2ae3e774dc5ee216b630", 46 + "rev": "01bc1d404a51a0a07e9d8759cd50a7903e218c82", 47 47 "type": "github" 48 48 }, 49 49 "original": { ··· 91 91 "flake-compat": { 92 92 "flake": false, 93 93 "locked": { 94 - "lastModified": 1767039857, 95 - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", 96 - "owner": "NixOS", 94 + "lastModified": 1761588595, 95 + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", 96 + "owner": "edolstra", 97 97 "repo": "flake-compat", 98 - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", 98 + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", 99 99 "type": "github" 100 100 }, 101 101 "original": { 102 - "owner": "NixOS", 102 + "owner": "edolstra", 103 103 "repo": "flake-compat", 104 104 "type": "github" 105 105 } ··· 111 111 ] 112 112 }, 113 113 "locked": { 114 - "lastModified": 1767609335, 115 - "narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", 114 + "lastModified": 1765835352, 115 + "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=", 116 116 "owner": "hercules-ci", 117 117 "repo": "flake-parts", 118 - "rev": "250481aafeb741edfe23d29195671c19b36b6dca", 118 + "rev": "a34fae9c08a15ad73f295041fec82323541400a9", 119 119 "type": "github" 120 120 }, 121 121 "original": { ··· 174 174 ] 175 175 }, 176 176 "locked": { 177 - "lastModified": 1767971841, 178 - "narHash": "sha256-TwDXF4MkmjI9c3Sly9FOWXf4sPbre6ZujG87v39G1Ig=", 177 + "lastModified": 1767048910, 178 + "narHash": "sha256-KLFTeA/xquN+F3XHLAXcserk0L0nijbhzuldxNDF1eE=", 179 179 "owner": "nix-community", 180 180 "repo": "home-manager", 181 - "rev": "0e4217b2c4827e71e2e612accccb01981c16afda", 181 + "rev": "d99b4ca5debaa082c7d76015aa2b7f3fc7e8b5f7", 182 182 "type": "github" 183 183 }, 184 184 "original": { ··· 212 212 ] 213 213 }, 214 214 "locked": { 215 - "lastModified": 1768007596, 216 - "narHash": "sha256-8es5mAWk+UMlo9O3pEbdLhXVk5CTs3yE7S1531aD1ZQ=", 215 + "lastModified": 1767057212, 216 + "narHash": "sha256-zmCTjuCxfA/iMWoM3dlqI6Jr7IxfdhxPQKps05mRH/4=", 217 217 "owner": "isabelroses", 218 218 "repo": "izlix", 219 - "rev": "450899c93ac2b101b1db2061f3bddbd369728815", 219 + "rev": "5ef2fec7c95c61c67337164df84bf89b50d862b8", 220 220 "type": "github" 221 221 }, 222 222 "original": { ··· 233 233 ] 234 234 }, 235 235 "locked": { 236 - "lastModified": 1767756498, 237 - "narHash": "sha256-a7SYG/6uUeeyfg1Xiq/sXpRb2RXs+kQ0GKrKMVlMw+4=", 236 + "lastModified": 1766546564, 237 + "narHash": "sha256-JShJrgMHSssMX425ubPK4hS5d4I9tqcb8+oB9qRnO/4=", 238 238 "owner": "isabelroses", 239 239 "repo": "nvim", 240 - "rev": "725ef38a0ea9b5bd8218aad272bd7458d430b2be", 240 + "rev": "790c8cb2ce8e8b51515b1bbc16226d445a8e2d4d", 241 241 "type": "github" 242 242 }, 243 243 "original": { ··· 256 256 "rust-overlay": "rust-overlay" 257 257 }, 258 258 "locked": { 259 - "lastModified": 1767697030, 260 - "narHash": "sha256-0iVZ99H3kR5h6Lhw8kDDuUc5C/k6iismeWgCS1qWTQ4=", 259 + "lastModified": 1767013031, 260 + "narHash": "sha256-p8ANXBakAtfX/aEhLbU6w0tuQe3nrBvLdHbKirJP7ug=", 261 261 "owner": "nix-community", 262 262 "repo": "lanzaboote", 263 - "rev": "657469e8f036334db768daaf7732b1174676054b", 263 + "rev": "c2a82339373daee8cbbcad5f51f22ae6b71069e0", 264 264 "type": "github" 265 265 }, 266 266 "original": { ··· 292 292 }, 293 293 "nixpkgs": { 294 294 "locked": { 295 - "lastModified": 1767966113, 296 - "narHash": "sha256-mb9aE5Y/wRCZz0cTB9EOe4BEKWpXAAl5Yai4TFrEf1E=", 297 - "rev": "5f02c91314c8ba4afe83b256b023756412218535", 295 + "lastModified": 1766996594, 296 + "narHash": "sha256-Ot0xSLsfRXy6IlMvnc8hSLHKNn/7R8yFDc7uI5Cjpr4=", 297 + "rev": "0744ef1b047f07d31d9962d757ffe38ec14a4d41", 298 298 "type": "tarball", 299 - "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre924980.5f02c91314c8/nixexprs.tar.xz?lastModified=1767966113&rev=5f02c91314c8ba4afe83b256b023756412218535" 299 + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre918100.0744ef1b047f/nixexprs.tar.xz?lastModified=1766996594&rev=0744ef1b047f07d31d9962d757ffe38ec14a4d41" 300 300 }, 301 301 "original": { 302 302 "type": "tarball", ··· 313 313 ] 314 314 }, 315 315 "locked": { 316 - "lastModified": 1767281941, 317 - "narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=", 316 + "lastModified": 1765911976, 317 + "narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=", 318 318 "owner": "cachix", 319 319 "repo": "pre-commit-hooks.nix", 320 - "rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa", 320 + "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", 321 321 "type": "github" 322 322 }, 323 323 "original": { ··· 353 353 ] 354 354 }, 355 355 "locked": { 356 - "lastModified": 1767495280, 357 - "narHash": "sha256-hEEgtE/RSRigw8xscchGymf/t1nluZwTfru4QF6O1CQ=", 356 + "lastModified": 1766976750, 357 + "narHash": "sha256-w+o3AIBI56tzfMJRqRXg9tSXnpQRN5hAT15o2t9rxYw=", 358 358 "owner": "oxalica", 359 359 "repo": "rust-overlay", 360 - "rev": "cb24c5cc207ba8e9a4ce245eedd2d37c3a988bc1", 360 + "rev": "9fe44e7f05b734a64a01f92fc51ad064fb0a884f", 361 361 "type": "github" 362 362 }, 363 363 "original": { ··· 396 396 ] 397 397 }, 398 398 "locked": { 399 - "lastModified": 1767848616, 400 - "narHash": "sha256-rAVR2ucz5vn9TOjvj5hVyEl0MnXrwIJo3ee12+p0EZE=", 399 + "lastModified": 1766896955, 400 + "narHash": "sha256-BbAUnNjaBmfR7Mvho9BN0RfvDi5fpP19wd/Hs6DMX8k=", 401 401 "owner": "Mic92", 402 402 "repo": "sops-nix", 403 - "rev": "994c9f014e5ce073de4bca7ebe21cf1cf90f2b0a", 403 + "rev": "861c32b27cce26c4bb828dfd21bd23df0dba7df2", 404 404 "type": "github" 405 405 }, 406 406 "original": { ··· 418 418 "systems": "systems" 419 419 }, 420 420 "locked": { 421 - "lastModified": 1767502559, 422 - "narHash": "sha256-om0IPjW850vhhIrNZ5tiXjsYuqyoI44IdE+I9AwZ96I=", 421 + "lastModified": 1767117828, 422 + "narHash": "sha256-K9sL2WwDQOltBiT111uU5pmfFjB6VmApaaHgTdXZqpg=", 423 423 "owner": "Gerg-L", 424 424 "repo": "spicetify-nix", 425 - "rev": "806c1fdeb7af3e013215d14f5d9f06685fa6650f", 425 + "rev": "b164eb4d18bed0f4be47c1033b477d3e81646752", 426 426 "type": "github" 427 427 }, 428 428 "original": { ··· 453 453 ] 454 454 }, 455 455 "locked": { 456 - "lastModified": 1768006445, 457 - "narHash": "sha256-WQ1yhsbYQM+EvhaWPSuS4UZPD4SjsskMWNG6azbEAgM=", 456 + "lastModified": 1767055973, 457 + "narHash": "sha256-sXhH2gl0SfcUVIhPvyBqhLOd4R20SrRypLl5EjzW3OI=", 458 458 "owner": "tgirlcloud", 459 459 "repo": "pkgs", 460 - "rev": "ae2de15f76978b6564c3eecdbe68d5ed0d0d2500", 460 + "rev": "ba3f5e451bd5fb41c147e62802c68e7729ac1d63", 461 461 "type": "github" 462 462 }, 463 463 "original": {
+1 -2
home/isabel/gui/chromium.nix
··· 1 1 { 2 2 lib, 3 3 pkgs, 4 - config, 5 4 ... 6 5 }: 7 6 let ··· 188 187 }; 189 188 }; 190 189 191 - xdg.configFile = mkIf (pkgs.stdenv.hostPlatform.isLinux && config.programs.chromium.enable) { 190 + xdg.configFile = mkIf pkgs.stdenv.hostPlatform.isLinux { 192 191 "chromium/NativeMessagingHosts/ff2mpv.json".source = 193 192 "${pkgs.ff2mpv-rust}/etc/chromium/native-messaging-hosts/ff2mpv.json"; 194 193 };
+31 -17
home/isabel/gui/hyprland.nix
··· 215 215 }; 216 216 217 217 layerrule = [ 218 - "blur on, ignore_alpha 0, match:namespace vicinae" 219 - "no_anim on, match:namespace vicinae" 218 + "blur,vicinae" 219 + "ignorealpha 0, vicinae" 220 + "noanim, vicinae" 220 221 ]; 221 222 222 223 general = { ··· 224 225 gaps_out = 8; 225 226 gaps_workspaces = 0; 226 227 border_size = 2; 228 + no_border_on_floating = true; 227 229 228 230 "col.active_border" = "$pink"; 229 231 "col.inactive_border" = "$surface1"; ··· 292 294 disable_autoreload = true; # autoreload is unnecessary on nixos, because the config is readonly anyway 293 295 }; 294 296 295 - windowrule = [ 296 - "float on, match:title ^(nm-connection-editor)$" 297 - "float on, match:title ^(Network)$" 298 - "float on, match:title ^(xdg-desktop-portal-gtk)$" 299 - "float on, match:class gay.vaskel.soteria" 300 - "float on, match:title ^(Picture-in-Picture)$" 301 - "float on, match:class ^(download)$" 297 + windowrulev2 = [ 298 + "float, title:^(nm-connection-editor)$" 299 + "float, title:^(Network)$" 300 + "float, title:^(xdg-desktop-portal-gtk)$" 301 + "float, class:gay.vaskel.soteria" 302 + "float, title:^(Picture-in-Picture)$" 303 + "float, class:^(download)$" 302 304 303 - "center on, float on, size (monitor_w*0.4) (monitor_h*0.6), match:initial_title (Open Files)" 304 - "center on, float on, size (monitor_w*0.4) (monitor_h*0.6), match:class .blueman-manager-wrapped" 305 - "center on, float on, size (monitor_w*0.4) (monitor_h*0.6), match:class com.saivert.pwvucontrol" 306 - "float on, size 800 600, match:title Bitwarden" 305 + "center(1), initialTitle:(Open Files)" 306 + "float, initialTitle:(Open Files)" 307 + "size 40% 60%, initialTitle:(Open Files)" 307 308 308 - "workspace 6, match:class discord" # move discord to workspace 6 309 - "workspace 7, match:class spotify" # move spotify to workspace 7 309 + "center(1), class:.blueman-manager-wrapped" 310 + "float, class:.blueman-manager-wrapped" 311 + "size 40% 60%, class:.blueman-manager-wrapped" 312 + 313 + "center(1), class:com.saivert.pwvucontrol" 314 + "float, class:com.saivert.pwvucontrol" 315 + "size 40% 60%, class:com.saivert.pwvucontrol" 316 + 317 + # we can't just use the tag because we want to capture the popup window 318 + "float, title:Bitwarden" 319 + "size 800 600, title:Bitwarden" 320 + # "no_screenshare on, tag:bitwarden" 321 + 322 + "workspace 6, class:discord" # move discord to workspace 6 323 + "workspace 7, class:spotify" # move spotify to workspace 7 310 324 311 325 # throw sharing indicators away 312 - "workspace special silent, match:title ^(Firefox โ€” Sharing Indicator)$" 313 - "workspace special silent, match:title ^(.*is sharing (your screen|a window).)$" 326 + "workspace special silent, title:^(Firefox โ€” Sharing Indicator)$" 327 + "workspace special silent, title:^(.*is sharing (your screen|a window)\.)$" 314 328 ]; 315 329 }; 316 330
-186
home/isabel/gui/quickshell/components/MediaPlayers.qml
··· 1 - import QtQuick 2 - import QtQuick.Layouts 3 - import Quickshell.Widgets 4 - import Quickshell.Services.Mpris 5 - import "root:/data" 6 - import "root:/services" 7 - 8 - ColumnLayout { 9 - id: root 10 - 11 - Layout.fillWidth: true 12 - spacing: 8 13 - visible: Media.players.length > 0 14 - 15 - RowLayout { 16 - Layout.fillWidth: true 17 - spacing: 8 18 - 19 - Text { 20 - text: "Now Playing" 21 - color: Settings.colors.foreground 22 - font { 23 - pixelSize: 14 24 - weight: Font.Bold 25 - } 26 - } 27 - 28 - Item { Layout.fillWidth: true } 29 - 30 - // Player selector (if multiple players) 31 - Row { 32 - spacing: 4 33 - visible: Media.players.length > 1 34 - 35 - Repeater { 36 - model: Media.players 37 - 38 - Rectangle { 39 - required property MprisPlayer modelData 40 - required property int index 41 - width: 8 42 - height: 8 43 - radius: 4 44 - color: Media.selectedPlayer === modelData ? Settings.colors.accent : Settings.colors.backgroundLightest 45 - 46 - MouseArea { 47 - anchors.fill: parent 48 - cursorShape: Qt.PointingHandCursor 49 - onClicked: Media.selectedPlayer = modelData 50 - } 51 - } 52 - } 53 - } 54 - } 55 - 56 - // Current Player 57 - ListView { 58 - id: mediaPlayerList 59 - Layout.fillWidth: true 60 - Layout.preferredHeight: contentHeight 61 - model: Media.players 62 - spacing: 8 63 - clip: true 64 - interactive: false 65 - 66 - delegate: Rectangle { 67 - required property MprisPlayer modelData 68 - required property int index 69 - width: ListView.view.width 70 - height: 90 71 - radius: 8 72 - color: Settings.colors.backgroundLighter 73 - opacity: Media.selectedPlayer === modelData ? 1.0 : 0.6 74 - 75 - MouseArea { 76 - anchors.fill: parent 77 - onClicked: Media.selectedPlayer = modelData 78 - } 79 - 80 - RowLayout { 81 - anchors { 82 - fill: parent 83 - margins: 10 84 - } 85 - spacing: 10 86 - 87 - // Album Art 88 - ClippingWrapperRectangle { 89 - radius: 6 90 - Layout.preferredWidth: 70 91 - Layout.preferredHeight: 70 92 - 93 - Image { 94 - anchors.fill: parent 95 - source: modelData.trackArtUrl 96 - fillMode: Image.PreserveAspectCrop 97 - } 98 - } 99 - 100 - // Track Info & Controls 101 - ColumnLayout { 102 - Layout.fillWidth: true 103 - Layout.fillHeight: true 104 - spacing: 2 105 - 106 - RowLayout { 107 - Layout.fillWidth: true 108 - spacing: 4 109 - 110 - Text { 111 - text: modelData.trackTitle ?? "Unknown" 112 - color: Settings.colors.foreground 113 - font { 114 - pixelSize: 13 115 - weight: Font.Medium 116 - } 117 - elide: Text.ElideRight 118 - Layout.fillWidth: true 119 - } 120 - 121 - // Player app name badge 122 - Rectangle { 123 - visible: Media.players.length > 1 124 - Layout.preferredHeight: 16 125 - Layout.preferredWidth: appNameText.width + 8 126 - radius: 4 127 - color: Settings.colors.backgroundLightest 128 - 129 - Text { 130 - id: appNameText 131 - anchors.centerIn: parent 132 - text: modelData.identity ?? "" 133 - color: Settings.colors.foreground 134 - opacity: 0.7 135 - font.pixelSize: 9 136 - } 137 - } 138 - } 139 - 140 - Text { 141 - text: modelData.trackArtist ?? "" 142 - color: Settings.colors.foreground 143 - opacity: 0.7 144 - font.pixelSize: 11 145 - elide: Text.ElideRight 146 - Layout.fillWidth: true 147 - } 148 - 149 - Item { Layout.fillHeight: true } 150 - 151 - // Playback Controls 152 - RowLayout { 153 - spacing: 14 154 - Layout.alignment: Qt.AlignLeft 155 - 156 - IconButton { 157 - icon: "media-skip-backward-symbolic" 158 - size: 14 159 - onClicked: modelData.previous() 160 - } 161 - 162 - IconButton { 163 - icon: modelData.playbackState === MprisPlaybackState.Playing 164 - ? "media-playback-pause-symbolic" 165 - : "media-playback-start-symbolic" 166 - size: 18 167 - onClicked: { 168 - if (modelData.playbackState === MprisPlaybackState.Playing) { 169 - modelData.pause(); 170 - } else { 171 - modelData.play(); 172 - } 173 - } 174 - } 175 - 176 - IconButton { 177 - icon: "media-skip-forward-symbolic" 178 - size: 14 179 - onClicked: modelData.next() 180 - } 181 - } 182 - } 183 - } 184 - } 185 - } 186 - }
+528 -5
home/isabel/gui/quickshell/components/Noti.qml
··· 1 1 import QtQuick 2 2 import QtQuick.Layouts 3 3 import QtQuick.Controls 4 + import QtQuick.Controls.Basic 4 5 import Quickshell 5 6 import Quickshell.Widgets 6 - import Quickshell.Services.Notifications as QsNotifications 7 + import Quickshell.Io 8 + import Quickshell.Services.Notifications 9 + import Quickshell.Services.Mpris 10 + import Quickshell.Services.Pipewire 7 11 import "root:/data" 8 12 import "root:/services" 9 13 ··· 98 102 } 99 103 100 104 delegate: Rectangle { 101 - required property QsNotifications.Notification modelData 105 + required property Notification modelData 102 106 width: ListView.view.width 103 107 height: 72 104 108 radius: 8 ··· 168 172 visible: Media.players.length > 0 169 173 } 170 174 171 - // Media Players Section 172 - MediaPlayers {} 175 + // Media Players Section (Multiple Players) 176 + ColumnLayout { 177 + Layout.fillWidth: true 178 + spacing: 8 179 + visible: Media.players.length > 0 180 + 181 + RowLayout { 182 + Layout.fillWidth: true 183 + spacing: 8 184 + 185 + Text { 186 + text: "Now Playing" 187 + color: Settings.colors.foreground 188 + font { 189 + pixelSize: 14 190 + weight: Font.Bold 191 + } 192 + } 193 + 194 + Item { Layout.fillWidth: true } 195 + 196 + // Player selector (if multiple players) 197 + Row { 198 + spacing: 4 199 + visible: Media.players.length > 1 200 + 201 + Repeater { 202 + model: Media.players 203 + 204 + Rectangle { 205 + required property MprisPlayer modelData 206 + required property int index 207 + width: 8 208 + height: 8 209 + radius: 4 210 + color: Media.selectedPlayer === modelData ? Settings.colors.accent : Settings.colors.backgroundLightest 211 + 212 + MouseArea { 213 + anchors.fill: parent 214 + cursorShape: Qt.PointingHandCursor 215 + onClicked: Media.selectedPlayer = modelData 216 + } 217 + } 218 + } 219 + } 220 + } 221 + 222 + // Current Player 223 + ListView { 224 + id: mediaPlayerList 225 + Layout.fillWidth: true 226 + Layout.preferredHeight: contentHeight 227 + model: Media.players 228 + spacing: 8 229 + clip: true 230 + interactive: false 231 + 232 + delegate: Rectangle { 233 + required property MprisPlayer modelData 234 + required property int index 235 + width: ListView.view.width 236 + height: 90 237 + radius: 8 238 + color: Settings.colors.backgroundLighter 239 + opacity: Media.selectedPlayer === modelData ? 1.0 : 0.6 240 + 241 + MouseArea { 242 + anchors.fill: parent 243 + onClicked: Media.selectedPlayer = modelData 244 + } 245 + 246 + RowLayout { 247 + anchors { 248 + fill: parent 249 + margins: 10 250 + } 251 + spacing: 10 252 + 253 + // Album Art 254 + ClippingWrapperRectangle { 255 + radius: 6 256 + Layout.preferredWidth: 70 257 + Layout.preferredHeight: 70 258 + 259 + Image { 260 + anchors.fill: parent 261 + source: modelData.trackArtUrl 262 + fillMode: Image.PreserveAspectCrop 263 + } 264 + } 265 + 266 + // Track Info & Controls 267 + ColumnLayout { 268 + Layout.fillWidth: true 269 + Layout.fillHeight: true 270 + spacing: 2 271 + 272 + RowLayout { 273 + Layout.fillWidth: true 274 + spacing: 4 275 + 276 + Text { 277 + text: modelData.trackTitle ?? "Unknown" 278 + color: Settings.colors.foreground 279 + font { 280 + pixelSize: 13 281 + weight: Font.Medium 282 + } 283 + elide: Text.ElideRight 284 + Layout.fillWidth: true 285 + } 286 + 287 + // Player app name badge 288 + Rectangle { 289 + visible: Media.players.length > 1 290 + Layout.preferredHeight: 16 291 + Layout.preferredWidth: appNameText.width + 8 292 + radius: 4 293 + color: Settings.colors.backgroundLightest 294 + 295 + Text { 296 + id: appNameText 297 + anchors.centerIn: parent 298 + text: modelData.identity ?? "" 299 + color: Settings.colors.foreground 300 + opacity: 0.7 301 + font.pixelSize: 9 302 + } 303 + } 304 + } 305 + 306 + Text { 307 + text: modelData.trackArtist ?? "" 308 + color: Settings.colors.foreground 309 + opacity: 0.7 310 + font.pixelSize: 11 311 + elide: Text.ElideRight 312 + Layout.fillWidth: true 313 + } 314 + 315 + Item { Layout.fillHeight: true } 316 + 317 + // Playback Controls 318 + RowLayout { 319 + spacing: 14 320 + Layout.alignment: Qt.AlignLeft 321 + 322 + IconButton { 323 + icon: "media-skip-backward-symbolic" 324 + size: 14 325 + onClicked: modelData.previous() 326 + } 327 + 328 + IconButton { 329 + icon: modelData.playbackState === MprisPlaybackState.Playing 330 + ? "media-playback-pause-symbolic" 331 + : "media-playback-start-symbolic" 332 + size: 18 333 + onClicked: { 334 + if (modelData.playbackState === MprisPlaybackState.Playing) { 335 + modelData.pause(); 336 + } else { 337 + modelData.play(); 338 + } 339 + } 340 + } 341 + 342 + IconButton { 343 + icon: "media-skip-forward-symbolic" 344 + size: 14 345 + onClicked: modelData.next() 346 + } 347 + } 348 + } 349 + } 350 + } 351 + } 352 + } 173 353 174 354 // Separator 175 355 Rectangle { ··· 179 359 } 180 360 181 361 // Quick Settings Section 182 - QuickSettings {} 362 + ColumnLayout { 363 + Layout.fillWidth: true 364 + spacing: 12 365 + 366 + Text { 367 + text: "Quick Settings" 368 + color: Settings.colors.foreground 369 + font { 370 + pixelSize: 14 371 + weight: Font.Bold 372 + } 373 + } 374 + 375 + // Connection Status Row (Ethernet indicator) 376 + RowLayout { 377 + Layout.fillWidth: true 378 + spacing: 8 379 + visible: Networking.ethernetConnected 380 + 381 + MyIcon { 382 + icon: "network-wired-symbolic" 383 + size: 16 384 + } 385 + 386 + Text { 387 + text: "Ethernet: " + Networking.ethernetDevice 388 + color: Settings.colors.foreground 389 + font.pixelSize: 12 390 + } 391 + 392 + Item { Layout.fillWidth: true } 393 + 394 + Rectangle { 395 + width: 8 396 + height: 8 397 + radius: 4 398 + color: Settings.colors.success 399 + } 400 + } 401 + 402 + // Toggle Buttons Row 403 + RowLayout { 404 + Layout.fillWidth: true 405 + spacing: 8 406 + 407 + // WiFi Toggle 408 + QuickSettingButton { 409 + icon: Networking.wifiEnabled 410 + ? (Networking.activeWifi?.icon ?? "network-wireless-acquiring-symbolic") 411 + : "network-wireless-disabled-symbolic" 412 + label: "WiFi" 413 + active: Networking.wifiEnabled 414 + onClicked: Networking.toggleWifi() 415 + onPressAndHold: networkPanel.visible = !networkPanel.visible 416 + } 417 + 418 + // Bluetooth Toggle 419 + QuickSettingButton { 420 + icon: Bluetooth.icon 421 + label: "Bluetooth" 422 + active: Bluetooth.powered 423 + onClicked: Bluetooth.toggle() 424 + onPressAndHold: bluetoothPanel.visible = !bluetoothPanel.visible 425 + } 426 + 427 + // Do Not Disturb Toggle 428 + QuickSettingButton { 429 + id: dndButton 430 + property bool dndEnabled: false 431 + icon: dndEnabled ? "notifications-disabled-symbolic" : "preferences-system-notifications-symbolic" 432 + label: "DND" 433 + active: dndEnabled 434 + onClicked: dndEnabled = !dndEnabled 435 + } 436 + } 437 + 438 + // Volume Slider 439 + PwObjectTracker { 440 + objects: [Pipewire.defaultAudioSink] 441 + } 442 + 443 + StyledSlider { 444 + icon: { 445 + const muted = Pipewire.defaultAudioSink?.audio?.muted ?? false; 446 + const vol = Pipewire.defaultAudioSink?.audio?.volume ?? 0; 447 + if (muted) return "audio-volume-muted-symbolic"; 448 + if (vol > 0.66) return "audio-volume-high-symbolic"; 449 + if (vol > 0.33) return "audio-volume-medium-symbolic"; 450 + if (vol > 0) return "audio-volume-low-symbolic"; 451 + return "audio-volume-muted-symbolic"; 452 + } 453 + value: Pipewire.defaultAudioSink?.audio?.volume ?? 0 454 + iconClickable: true 455 + onIconClicked: { 456 + if (Pipewire.defaultAudioSink?.audio) { 457 + Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted; 458 + } 459 + } 460 + onMoved: (val) => { 461 + if (Pipewire.defaultAudioSink?.audio) { 462 + Pipewire.defaultAudioSink.audio.volume = val; 463 + } 464 + } 465 + } 466 + 467 + // Brightness Slider 468 + BrightnessHelper { id: brightnessHelper } 469 + 470 + StyledSlider { 471 + visible: brightnessHelper.available 472 + icon: "display-brightness-symbolic" 473 + value: brightnessHelper.brightness 474 + from: 0.05 475 + accentColor: Settings.colors.warning 476 + onMoved: (val) => brightnessHelper.setBrightness(val) 477 + } 478 + 479 + // Network Panel (expandable) 480 + Rectangle { 481 + id: networkPanel 482 + Layout.fillWidth: true 483 + Layout.preferredHeight: visible ? networkListView.contentHeight + 48 : 0 484 + visible: false 485 + radius: 8 486 + color: Settings.colors.backgroundLighter 487 + clip: true 488 + 489 + Behavior on Layout.preferredHeight { 490 + NumberAnimation { duration: 150; easing.type: Easing.OutCubic } 491 + } 492 + 493 + ColumnLayout { 494 + anchors.fill: parent 495 + anchors.margins: 12 496 + spacing: 8 497 + 498 + RowLayout { 499 + Layout.fillWidth: true 500 + 501 + Text { 502 + text: "Networks" 503 + color: Settings.colors.foreground 504 + font { 505 + pixelSize: 13 506 + weight: Font.Medium 507 + } 508 + } 509 + 510 + Item { Layout.fillWidth: true } 511 + 512 + IconButton { 513 + icon: "view-refresh-symbolic" 514 + size: 14 515 + onClicked: Networking.reload() 516 + } 517 + } 518 + 519 + ListView { 520 + id: networkListView 521 + Layout.fillWidth: true 522 + Layout.preferredHeight: Math.min(contentHeight, 150) 523 + model: Networking.networks 524 + spacing: 4 525 + clip: true 526 + 527 + delegate: PanelListItem { 528 + required property var modelData 529 + icon: modelData.icon 530 + text: modelData.ssid || "Unknown" 531 + badge: modelData.strength + "%" 532 + active: modelData.active 533 + } 534 + } 535 + } 536 + } 537 + 538 + // Bluetooth Panel (expandable) 539 + Rectangle { 540 + id: bluetoothPanel 541 + Layout.fillWidth: true 542 + Layout.preferredHeight: visible ? bluetoothListView.contentHeight + 64 : 0 543 + visible: false 544 + radius: 8 545 + color: Settings.colors.backgroundLighter 546 + clip: true 547 + 548 + Behavior on Layout.preferredHeight { 549 + NumberAnimation { duration: 150; easing.type: Easing.OutCubic } 550 + } 551 + 552 + ColumnLayout { 553 + anchors.fill: parent 554 + anchors.margins: 12 555 + spacing: 8 556 + 557 + RowLayout { 558 + Layout.fillWidth: true 559 + 560 + Text { 561 + text: "Bluetooth Devices" 562 + color: Settings.colors.foreground 563 + font { 564 + pixelSize: 13 565 + weight: Font.Medium 566 + } 567 + } 568 + 569 + Item { Layout.fillWidth: true } 570 + 571 + // Scan button 572 + IconButton { 573 + icon: Bluetooth.adapter?.discovering ? "process-stop-symbolic" : "view-refresh-symbolic" 574 + size: 14 575 + onClicked: { 576 + if (Bluetooth.adapter?.discovering) { 577 + Bluetooth.stopDiscovery(); 578 + } else { 579 + Bluetooth.startDiscovery(); 580 + } 581 + } 582 + } 583 + 584 + Text { 585 + text: Bluetooth.connected ? Bluetooth.connectedDevice?.name ?? "" : "" 586 + color: Settings.colors.accent 587 + font.pixelSize: 11 588 + visible: Bluetooth.connected 589 + } 590 + } 591 + 592 + ListView { 593 + id: bluetoothListView 594 + Layout.fillWidth: true 595 + Layout.preferredHeight: Math.min(contentHeight, 150) 596 + model: Bluetooth.devices 597 + spacing: 4 598 + clip: true 599 + 600 + delegate: PanelListItem { 601 + required property var modelData 602 + icon: modelData.icon || "bluetooth-symbolic" 603 + text: modelData.name 604 + badge: modelData.connected ? "Connected" : (modelData.paired ? "Paired" : "") 605 + active: modelData.connected 606 + onClicked: { 607 + if (modelData.connected) { 608 + modelData.disconnect(); 609 + } else { 610 + modelData.connect(); 611 + } 612 + } 613 + } 614 + } 615 + 616 + Text { 617 + text: { 618 + if (!Bluetooth.adapter) return "No Bluetooth adapter"; 619 + if (Bluetooth.devices?.count === 0) return "No devices found"; 620 + return ""; 621 + } 622 + color: Settings.colors.foreground 623 + opacity: 0.5 624 + font.pixelSize: 12 625 + visible: !Bluetooth.adapter || Bluetooth.devices?.count === 0 626 + Layout.alignment: Qt.AlignHCenter 627 + } 628 + } 629 + } 630 + } 183 631 } 184 632 } 633 + } 634 + } 635 + 636 + // Quick Setting Button Component 637 + component QuickSettingButton: Rectangle { 638 + id: qsButton 639 + Layout.fillWidth: true 640 + Layout.preferredHeight: 64 641 + radius: 8 642 + color: active ? Settings.colors.accent : Settings.colors.backgroundLighter 643 + 644 + property string icon: "" 645 + property string label: "" 646 + property bool active: false 647 + 648 + signal clicked() 649 + signal pressAndHold() 650 + 651 + ColumnLayout { 652 + anchors.centerIn: parent 653 + spacing: 6 654 + 655 + MyIcon { 656 + icon: qsButton.icon 657 + size: 20 658 + Layout.alignment: Qt.AlignHCenter 659 + invert: active 660 + } 661 + 662 + Text { 663 + text: qsButton.label 664 + color: qsButton.active ? Settings.colors.background : Settings.colors.foreground 665 + font.pixelSize: 11 666 + Layout.alignment: Qt.AlignHCenter 667 + } 668 + } 669 + 670 + MouseArea { 671 + anchors.fill: parent 672 + cursorShape: Qt.PointingHandCursor 673 + onClicked: qsButton.clicked() 674 + onPressAndHold: qsButton.pressAndHold() 675 + } 676 + } 677 + 678 + // Brightness Helper Component 679 + component BrightnessHelper: QtObject { 680 + id: brightnessObj 681 + property real brightness: 1.0 682 + property bool available: false 683 + 684 + function setBrightness(value) { 685 + brightness = value; 686 + setBrightnessProc.command = ["brightnessctl", "set", Math.round(value * 100) + "%"]; 687 + setBrightnessProc.running = true; 688 + } 689 + 690 + Component.onCompleted: getBrightness.running = true 691 + 692 + property Process getBrightness: Process { 693 + id: getBrightness 694 + command: ["bash", "-c", "brightnessctl -m 2>/dev/null | cut -d, -f4 | tr -d '%'"] 695 + stdout: SplitParser { 696 + onRead: { 697 + const val = parseInt(data.trim()); 698 + if (!isNaN(val)) { 699 + brightnessObj.brightness = val / 100; 700 + brightnessObj.available = true; 701 + } 702 + } 703 + } 704 + } 705 + 706 + property Process setBrightnessProc: Process { 707 + id: setBrightnessProc 185 708 } 186 709 } 187 710 }
-387
home/isabel/gui/quickshell/components/QuickSettings.qml
··· 1 - import QtQuick 2 - import QtQuick.Layouts 3 - import QtQuick.Controls.Basic 4 - import Quickshell.Io 5 - import Quickshell.Services.Pipewire 6 - import "root:/data" 7 - import "root:/services" 8 - 9 - ColumnLayout { 10 - id: root 11 - 12 - Layout.fillWidth: true 13 - spacing: 12 14 - 15 - Text { 16 - text: "Quick Settings" 17 - color: Settings.colors.foreground 18 - font { 19 - pixelSize: 14 20 - weight: Font.Bold 21 - } 22 - } 23 - 24 - // Connection Status Row (Ethernet indicator) 25 - RowLayout { 26 - Layout.fillWidth: true 27 - spacing: 8 28 - visible: Networking.ethernetConnected 29 - 30 - MyIcon { 31 - icon: "network-wired-symbolic" 32 - size: 16 33 - } 34 - 35 - Text { 36 - text: "Ethernet: " + Networking.ethernetDevice 37 - color: Settings.colors.foreground 38 - font.pixelSize: 12 39 - } 40 - 41 - Item { Layout.fillWidth: true } 42 - 43 - Rectangle { 44 - width: 8 45 - height: 8 46 - radius: 4 47 - color: Settings.colors.success 48 - } 49 - } 50 - 51 - // Network Panel (expandable) 52 - Rectangle { 53 - id: networkPanel 54 - Layout.fillWidth: true 55 - Layout.preferredHeight: visible ? Math.min(networkColumn.implicitHeight + 20, 350) : 0 56 - visible: false 57 - radius: 8 58 - color: Settings.colors.backgroundLighter 59 - clip: true 60 - 61 - Behavior on Layout.preferredHeight { 62 - NumberAnimation { duration: 150; easing.type: Easing.OutCubic } 63 - } 64 - 65 - ColumnLayout { 66 - id: networkColumn 67 - anchors.fill: parent 68 - anchors.margins: 12 69 - spacing: 8 70 - 71 - RowLayout { 72 - Layout.fillWidth: true 73 - 74 - Text { 75 - text: "Networks" 76 - color: Settings.colors.foreground 77 - font { 78 - pixelSize: 13 79 - weight: Font.Medium 80 - } 81 - } 82 - 83 - Item { Layout.fillWidth: true } 84 - 85 - IconButton { 86 - icon: "view-refresh-symbolic" 87 - size: 14 88 - onClicked: Networking.reload() 89 - } 90 - } 91 - 92 - ScrollView { 93 - Layout.fillWidth: true 94 - Layout.preferredHeight: Math.min(networkListView.contentHeight, 280) 95 - clip: true 96 - 97 - ListView { 98 - id: networkListView 99 - width: parent.width 100 - model: Networking.networks 101 - spacing: 4 102 - 103 - delegate: PanelListItem { 104 - required property var modelData 105 - width: ListView.view.width 106 - icon: modelData.icon 107 - text: modelData.ssid || "Unknown" 108 - badge: modelData.strength + "%" 109 - active: modelData.active 110 - onClicked: { 111 - if (!modelData.active) { 112 - Networking.connectToNetwork(modelData.ssid); 113 - } 114 - } 115 - } 116 - } 117 - } 118 - 119 - Text { 120 - text: Networking.networks?.count === 0 ? "No networks found" : "" 121 - color: Settings.colors.foreground 122 - opacity: 0.5 123 - font.pixelSize: 12 124 - visible: Networking.networks?.count === 0 125 - Layout.alignment: Qt.AlignHCenter 126 - } 127 - 128 - Item { Layout.fillHeight: true } 129 - } 130 - } 131 - 132 - // Bluetooth Panel (expandable) 133 - Rectangle { 134 - id: bluetoothPanel 135 - Layout.fillWidth: true 136 - Layout.preferredHeight: visible ? Math.min(bluetoothColumn.implicitHeight + 20, 350) : 0 137 - visible: false 138 - radius: 8 139 - color: Settings.colors.backgroundLighter 140 - clip: true 141 - 142 - Behavior on Layout.preferredHeight { 143 - NumberAnimation { duration: 150; easing.type: Easing.OutCubic } 144 - } 145 - 146 - ColumnLayout { 147 - id: bluetoothColumn 148 - anchors.fill: parent 149 - anchors.margins: 12 150 - spacing: 8 151 - 152 - RowLayout { 153 - Layout.fillWidth: true 154 - 155 - Text { 156 - text: "Bluetooth Devices" 157 - color: Settings.colors.foreground 158 - font { 159 - pixelSize: 13 160 - weight: Font.Medium 161 - } 162 - } 163 - 164 - Item { Layout.fillWidth: true } 165 - 166 - // Scan button 167 - IconButton { 168 - icon: Bluetooth.adapter?.discovering ? "process-stop-symbolic" : "view-refresh-symbolic" 169 - size: 14 170 - onClicked: { 171 - if (Bluetooth.adapter?.discovering) { 172 - Bluetooth.stopDiscovery(); 173 - } else { 174 - Bluetooth.startDiscovery(); 175 - } 176 - } 177 - } 178 - 179 - Text { 180 - text: Bluetooth.connected ? Bluetooth.connectedDevice?.name ?? "" : "" 181 - color: Settings.colors.accent 182 - font.pixelSize: 11 183 - visible: Bluetooth.connected 184 - } 185 - } 186 - 187 - ScrollView { 188 - Layout.fillWidth: true 189 - Layout.preferredHeight: Math.min(bluetoothListView.contentHeight, 280) 190 - clip: true 191 - 192 - ListView { 193 - id: bluetoothListView 194 - width: parent.width 195 - model: Bluetooth.devices 196 - spacing: 8 197 - clip: true 198 - 199 - delegate: PanelListItem { 200 - required property var modelData 201 - width: ListView.view.width 202 - icon: modelData.icon || "bluetooth-symbolic" 203 - text: modelData.name 204 - badge: modelData.connected ? "Connected" : (modelData.paired ? "Paired" : "") 205 - active: modelData.connected 206 - onClicked: { 207 - if (modelData.connected) { 208 - modelData.disconnect(); 209 - } else if (modelData.paired) { 210 - modelData.connect(); 211 - } else { 212 - // Pair and connect 213 - modelData.pair(); 214 - } 215 - } 216 - } 217 - } 218 - } 219 - 220 - Text { 221 - text: { 222 - if (!Bluetooth.adapter) return "No Bluetooth adapter"; 223 - if (Bluetooth.devices?.count === 0) return "No devices found"; 224 - return ""; 225 - } 226 - color: Settings.colors.foreground 227 - opacity: 0.5 228 - font.pixelSize: 12 229 - visible: !Bluetooth.adapter || Bluetooth.devices?.count === 0 230 - Layout.alignment: Qt.AlignHCenter 231 - } 232 - 233 - Item { Layout.fillHeight: true } 234 - } 235 - } 236 - 237 - // Toggle Buttons Row 238 - RowLayout { 239 - Layout.fillWidth: true 240 - spacing: 8 241 - 242 - // WiFi Toggle 243 - QuickSettingButton { 244 - icon: Networking.wifiEnabled 245 - ? (Networking.activeWifi?.icon ?? "network-wireless-acquiring-symbolic") 246 - : "network-wireless-disabled-symbolic" 247 - label: "WiFi" 248 - active: Networking.wifiEnabled 249 - onClicked: Networking.toggleWifi() 250 - onPressAndHold: networkPanel.visible = !networkPanel.visible 251 - } 252 - 253 - // Bluetooth Toggle 254 - QuickSettingButton { 255 - icon: Bluetooth.icon 256 - label: "Bluetooth" 257 - active: Bluetooth.powered 258 - onClicked: Bluetooth.toggle() 259 - onPressAndHold: bluetoothPanel.visible = !bluetoothPanel.visible 260 - } 261 - 262 - // Do Not Disturb Toggle 263 - QuickSettingButton { 264 - icon: Notifications.dndEnabled ? "notifications-disabled-symbolic" : "preferences-system-notifications-symbolic" 265 - label: "DND" 266 - active: Notifications.dndEnabled 267 - onClicked: Notifications.dndEnabled = !Notifications.dndEnabled 268 - } 269 - } 270 - 271 - // Volume Slider 272 - PwObjectTracker { 273 - objects: [Pipewire.defaultAudioSink] 274 - } 275 - 276 - StyledSlider { 277 - icon: { 278 - const muted = Pipewire.defaultAudioSink?.audio?.muted ?? false; 279 - const vol = Pipewire.defaultAudioSink?.audio?.volume ?? 0; 280 - if (muted) return "audio-volume-muted-symbolic"; 281 - if (vol > 0.66) return "audio-volume-high-symbolic"; 282 - if (vol > 0.33) return "audio-volume-medium-symbolic"; 283 - if (vol > 0) return "audio-volume-low-symbolic"; 284 - return "audio-volume-muted-symbolic"; 285 - } 286 - value: Pipewire.defaultAudioSink?.audio?.volume ?? 0 287 - iconClickable: true 288 - onIconClicked: { 289 - if (Pipewire.defaultAudioSink?.audio) { 290 - Pipewire.defaultAudioSink.audio.muted = !Pipewire.defaultAudioSink.audio.muted; 291 - } 292 - } 293 - onMoved: (val) => { 294 - if (Pipewire.defaultAudioSink?.audio) { 295 - Pipewire.defaultAudioSink.audio.volume = val; 296 - } 297 - } 298 - } 299 - 300 - // Brightness Slider 301 - BrightnessHelper { id: brightnessHelper } 302 - 303 - StyledSlider { 304 - visible: brightnessHelper.available 305 - icon: "display-brightness-symbolic" 306 - value: brightnessHelper.brightness 307 - from: 0.05 308 - accentColor: Settings.colors.warning 309 - onMoved: (val) => brightnessHelper.setBrightness(val) 310 - } 311 - 312 - // Quick Setting Button Component 313 - component QuickSettingButton: Rectangle { 314 - id: qsButton 315 - Layout.fillWidth: true 316 - Layout.preferredHeight: 64 317 - radius: 8 318 - color: active ? Settings.colors.accent : Settings.colors.backgroundLighter 319 - 320 - property string icon: "" 321 - property string label: "" 322 - property bool active: false 323 - 324 - signal clicked() 325 - signal pressAndHold() 326 - 327 - ColumnLayout { 328 - anchors.centerIn: parent 329 - spacing: 6 330 - 331 - MyIcon { 332 - icon: qsButton.icon 333 - size: 20 334 - Layout.alignment: Qt.AlignHCenter 335 - invert: active 336 - } 337 - 338 - Text { 339 - text: qsButton.label 340 - color: qsButton.active ? Settings.colors.background : Settings.colors.foreground 341 - font.pixelSize: 11 342 - Layout.alignment: Qt.AlignHCenter 343 - } 344 - } 345 - 346 - MouseArea { 347 - anchors.fill: parent 348 - cursorShape: Qt.PointingHandCursor 349 - onClicked: qsButton.clicked() 350 - onPressAndHold: qsButton.pressAndHold() 351 - } 352 - } 353 - 354 - // Brightness Helper Component 355 - component BrightnessHelper: QtObject { 356 - id: brightnessObj 357 - property real brightness: 1.0 358 - property bool available: false 359 - 360 - function setBrightness(value) { 361 - brightness = value; 362 - setBrightnessProc.command = ["brightnessctl", "set", Math.round(value * 100) + "%"]; 363 - setBrightnessProc.running = true; 364 - } 365 - 366 - Component.onCompleted: getBrightness.running = true 367 - 368 - property Process getBrightness: Process { 369 - id: getBrightness 370 - command: ["bash", "-c", "brightnessctl -m 2>/dev/null | cut -d, -f4 | tr -d '%'"] 371 - stdout: SplitParser { 372 - onRead: { 373 - const val = parseInt(data.trim()); 374 - if (!isNaN(val)) { 375 - brightnessObj.brightness = val / 100; 376 - brightnessObj.available = true; 377 - } 378 - } 379 - } 380 - } 381 - 382 - property Process setBrightnessProc: Process { 383 - id: setBrightnessProc 384 - } 385 - } 386 - } 387 -
-5
home/isabel/gui/quickshell/data/Settings.qml
··· 23 23 } 24 24 25 25 property string wallpaper: "/home/isabel/media/pictures/wallpapers/flowers.jpg"; 26 - 27 - // Notification settings 28 - property list<string> notificationBlacklist: [ 29 - "Spotify" 30 - ] 31 26 }
+8 -8
home/isabel/gui/quickshell/modules/Osd.qml
··· 4 4 import Quickshell.Widgets 5 5 import Quickshell.Wayland 6 6 import Quickshell.Services.Pipewire 7 - import Quickshell.Services.Notifications as QsNotifications 7 + import Quickshell.Services.Notifications 8 8 import "root:/data" 9 9 import "root:/components" 10 - import "root:/services" 11 10 12 11 Scope { 13 12 id: root ··· 54 53 osdHideTimer.restart(); 55 54 } 56 55 57 - function showNotification(notification: QsNotifications.Notification): void { 56 + function showNotification(notification: Notification): void { 58 57 root.currentNotification = notification; 59 58 root.notificationVisible = true; 60 59 notificationHideTimer.restart(); ··· 72 71 onTriggered: root.notificationVisible = false 73 72 } 74 73 75 - // Connect to the shared notification service 76 - Connections { 77 - target: Notifications 78 - function onNewNotification(notification) { 74 + // Notification Server 75 + NotificationServer { 76 + id: notificationServer 77 + onNotification: (notification) => { 78 + notification.tracked = true; 79 79 root.showNotification(notification); 80 80 } 81 + actionsSupported: true 81 82 } 82 83 83 84 Variants { ··· 273 274 } 274 275 } 275 276 } 276 -
-10
home/isabel/gui/quickshell/services/Networking.qml
··· 45 45 checkStatus.running = true; 46 46 } 47 47 48 - function connectToNetwork(ssid) { 49 - connectProc.command = ["nmcli", "d", "wifi", "connect", ssid]; 50 - connectProc.running = true; 51 - } 52 - 53 48 QtObject { 54 49 id: internal 55 50 property bool wifiEnabled: true ··· 107 102 Process { 108 103 id: toggleWifiProc 109 104 command: ["nmcli", "radio", "wifi", internal.wifiEnabled ? "off" : "on"] 110 - onExited: checkStatus.running = true 111 - } 112 - 113 - Process { 114 - id: connectProc 115 105 onExited: checkStatus.running = true 116 106 } 117 107
+1 -12
home/isabel/gui/quickshell/services/Notifications.qml
··· 3 3 import Quickshell 4 4 import Quickshell.Io 5 5 import Quickshell.Services.Notifications 6 - import "root:/data" 7 6 8 7 Singleton { 9 8 id: root 10 9 11 - property bool dndEnabled: false 12 - property list<Notification> list: notifactionServer.trackedNotifications.values.filter( 13 - notification => notification.tracked && !root.dndEnabled && !Settings.notificationBlacklist.includes(notification.appName) 14 - ) 15 - 16 - signal newNotification(Notification notification) 10 + property list<Notification> list: notifactionServer.trackedNotifications.values.filter(notification => notification.tracked) 17 11 18 12 NotificationServer { 19 13 id: notifactionServer 20 14 onNotification: (notification) => { 21 15 notification.tracked = true 22 - // Only emit signal if not in DND and not blacklisted 23 - if (!root.dndEnabled && !Settings.notificationBlacklist.includes(notification.appName)) { 24 - root.newNotification(notification) 25 - } 26 16 } 27 17 28 18 actionsSupported: true ··· 38 28 } 39 29 } 40 30 } 41 -
+3 -3
justfile
··· 29 29 deploy host *args: 30 30 #!/usr/bin/env bash 31 31 set -euo pipefail 32 - before=$(ssh -q {{ host }} 'readlink /run/current-system') 32 + before=$(ssh {{ host }} 'readlink /run/current-system') 33 33 just builder switch --target-host {{ host }} --use-substitutes {{ args }} 34 34 35 35 if [[ -n "${DEPLOY_SUMMARY:-}" ]]; then 36 36 { 37 37 echo "===== {{ host }} =====" 38 - ssh -q {{ host }} lix diff "$before" 38 + ssh {{ host }} lix diff "$before" 39 39 echo 40 40 } >> "$DEPLOY_SUMMARY" 41 41 else ··· 60 60 echo 61 61 echo "===== DEPLOYMENT SUMMARY =====" 62 62 cat "$DEPLOY_SUMMARY" 63 - rm "$DEPLOY_SUMMARY" 63 + @rm "$DEPLOY_SUMMARY" 64 64 65 65 # rebuild the boot 66 66 [group('rebuild')]
-2
modules/nixos/hardware/gpu/nvidia.nix
··· 1 - # A worthy read before attempting to change anything here: 2 - # <https://discourse.nixos.org/t/can-we-solve-the-nvidia-situation/73198> 3 1 { 4 2 lib, 5 3 pkgs,
+29
modules/nixos/networking/default.nix
··· 50 50 "2620:fe::fe" 51 51 ]; 52 52 53 + # hosts = { 54 + # "2a01:4f8:c010:d56::2" = [ "github.com" ]; 55 + # "2a01:4f8:c010:d56::3" = [ "api.github.com" ]; 56 + # "2a01:4f8:c010:d56::4" = [ "codeload.github.com" ]; 57 + # "2a01:4f8:c010:d56::8" = [ "uploads.github.com" ]; 58 + # "2606:50c0:8000::133" = [ 59 + # "objects.githubusercontent.com" 60 + # "www.objects.githubusercontent.com" 61 + # "release-assets.githubusercontent.com" 62 + # "gist.githubusercontent.com" 63 + # "repository-images.githubusercontent.com" 64 + # "camo.githubusercontent.com" 65 + # "private-user-images.githubusercontent.com" 66 + # "avatars0.githubusercontent.com" 67 + # "avatars1.githubusercontent.com" 68 + # "avatars2.githubusercontent.com" 69 + # "avatars3.githubusercontent.com" 70 + # "cloud.githubusercontent.com" 71 + # "desktop.githubusercontent.com" 72 + # ]; 73 + # "2606:50c0:8000::154" = [ 74 + # "support-assets.githubassets.com" 75 + # "github.githubassets.com" 76 + # "opengraph.githubassets.com" 77 + # "github-registry-files.githubusercontent.com" 78 + # "github-cloud.githubusercontent.com" 79 + # ]; 80 + # }; 81 + 53 82 enableIPv6 = true; 54 83 }; 55 84 }
+1 -1
modules/nixos/system/scheduler.nix
··· 1 - { pkgs, ... }: 1 + { pkgs, config, ... }: 2 2 { 3 3 services.scx = { 4 4 # inherit (config.garden.profiles.workstation) enable;
+3 -3
secrets/services/piper.yaml
··· 1 - env: ENC[AES256_GCM,data:/bJSpMnpO/P5pen9RKdsRF47veCmkRstBFUwbdyu+fp3UDayUrL2u+/397XQQxBQYl266wJOQB7sjJ5lsOI/yRiM/89yv4zow7Qh/akPnsYyhxiLAjdIdJHFzh6tQMBZiHEHNF16edhejKMgIz0qOIvIQZu0yHX6ozvWfc7KKzYH3CUohbhIjgjqbJfzP/YMFNnqu6Aa4mlksprCeVPg/ZX3vf4z/DS9vIhmUbkc91064gjytMq3EFZvVt01aD3Wror/ApBCtCZ1Pt8zAbH/mrQd2Dsx9pOKueqYhTGcF6nsU5fxkKG62K0nK3xGOS2vOpl4k9m220k5BF1CbSKbWXFBafvtvorYbBBK+N4caBKI6DQz66/eA75D0DwA0KbBKadboqzRZOWFsvqQwIuiqnkzJottJZ2swGbyVjhLsAQEmZI/b6Ie0I0=,iv:Z1gnEHoJ8eBDWn1IorUn/pT+ghxrB7+nk9boHx7efWg=,tag:zNJRN/JeWP98TDxfFDdElw==,type:str] 1 + env: ENC[AES256_GCM,data:scYfFEXl6esjrYaTLbFbeqQVnOw6h2ZzZVQ2EUsCxnYzaI+rhCTVqkrqXgowFAILWwQOiYM7B5ukgqTytiB5h6C2Bh/xa/VdMOPdY3EXqRed7NzZC96LZt3+dKDKKDbkw1wyddWvX/phQFk/cHq6BR5CQZfQ7nPXRr2ofZGoK/3m+GhouyJq2I4RHHRGxv0WXYniHkR9zgdc+myg1KsFphu9XaoR4WN/uaGACv59pguMJWRcBzr+wKPxdWtrzb4vTIVQiF8wpTSdWBmnwmKq29y/pBSNivDdhWB5N1/VHGFDRge5RzxXCg98Hv4fegebx4+YPiVlwoC2peGSi/q8EeNLFES+waywaKmbQ1r54AAFqGnXIIp16Ib5lCUa+VwY2jQl9c+QZOcNEJkVZ6jWmuoUguO1q2y4WbLvcaWksjRXJHs/NOsQoF4=,iv:b8O+3GksPP4hTuH57IxgAeYe6MAiYGO83nJKn7MVn6Q=,tag:V1dFrgABjL6SXN7af1DtgA==,type:str] 2 2 sops: 3 3 age: 4 4 - recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMQDiHbMSinj8twL9cTgPOfI6OMexrTZyHX27T8gnMj2 ··· 71 71 lm9UxzoNda1OtptX52t1sWVYkx1pwvlTbTmuNy/8uVufZVekdPBz+pywuJbSJlh2 72 72 bH8K6Q== 73 73 -----END AGE ENCRYPTED FILE----- 74 - lastmodified: "2026-01-07T01:01:47Z" 75 - mac: ENC[AES256_GCM,data:ThIfvJcDdWqprQ0i66bTy29QOcPzWjIYCB8aYhdeEIPzBOjQDKgVh3YNXVaMC7/2tBJmC/IQbxvJ/pIPP/UICSxFvqS+Ta6wipRlTs2A23gaoaVXwj7nY8oMwUH4w04NbWuNFavQ/gnKYBEOmqDBsLrZ6+v5IPxfxx/fRapMKMM=,iv:OYGE7Ja0X6WNHswwYwQ8VsDSlb3U/sm47tsTnJ5wspc=,tag:5Pcfd0/eSL36rFNp8sH6qA==,type:str] 74 + lastmodified: "2025-11-14T16:08:46Z" 75 + mac: ENC[AES256_GCM,data:jd968uS+JcdIg1eDyo1ssHSVw/cxXVwuIDE6YdJrZCHpCf/XSHIWvlu6+L3LILixhV45eMdI81GKCMR3uBnXaXf6SOEPWZ2BJc9cT+p1seAPR1surmVA8d2GGKSWuGmi7mFW30kLsDJhRk1pybKpIHf/Jxdgx0cuh95DEoOtoPg=,iv:+XUddLha4hj68zCcnHiH5aEJU6buzKV+FNUO8ZXQofY=,tag:wlmooDkxQJyPD883cwRdSA==,type:str] 76 76 unencrypted_suffix: _unencrypted 77 77 version: 3.11.0