Compare commits
85 Commits
730eff5379
...
features/m
| Author | SHA1 | Date | |
|---|---|---|---|
| e5809efc6a | |||
| d6f79685f0 | |||
| c2c6675f4b | |||
| fcce5f304b | |||
| 4b0b5c72ba | |||
| 3f4e3514a2 | |||
| 622afb2100 | |||
| 3ae5c57303 | |||
| ef06a96757 | |||
| 03ea182c8c | |||
| ba8a565cda | |||
| c8a9c30fc5 | |||
| 185b752393 | |||
| 8515f3f5ce | |||
| 86921f7aab | |||
| cede2a1690 | |||
| 00e4368abe | |||
| 00d7dcb411 | |||
| 4bdb590899 | |||
| 44e73f5a9d | |||
| 3184c61267 | |||
| fb79f0a37e | |||
| 7a1073646a | |||
| 90d068a878 | |||
| 57e5c0c7b3 | |||
| b7a92c9a59 | |||
| d3856ada0d | |||
| 3601f52600 | |||
| 98f9a77b23 | |||
| bc242ae956 | |||
| 4237b2ed9e | |||
| 7b0cf9934b | |||
| 9df5731ee1 | |||
| 3806935316 | |||
| 516f8eed82 | |||
| 369179c057 | |||
| 322804577f | |||
| 0eee14858b | |||
| 461f4c3fff | |||
| 2f9dfda410 | |||
| e35ceb1450 | |||
| 3d0a18866f | |||
| 6c415d6fbb | |||
| c4b4a3bd26 | |||
| 866ee0bb9b | |||
| e77c08a0a2 | |||
| 491509e864 | |||
| c4604f8e0f | |||
| 30d5f4c926 | |||
| 90d7042995 | |||
| b6714cf20b | |||
| 8877835ae0 | |||
| 32dd10c83d | |||
| f3df5e4f3d | |||
| 74953850fb | |||
| 04e50bad3f | |||
| a218026568 | |||
| 7c557bffc8 | |||
| 2eb122960d | |||
| 8c0347ee35 | |||
| 2935fc7cfe | |||
| 6f9651ccb3 | |||
| c88a96406a | |||
| 13c4f95e08 | |||
| c4f220d95a | |||
| f6d69332db | |||
| 1559da170e | |||
| ca18fe26c1 | |||
| cfd6cf2700 | |||
| 5909ed14cb | |||
| 3487732f46 | |||
| 6aff35bd5b | |||
| 176902616b | |||
| 70cda8d08e | |||
| 28c6a0c3d7 | |||
| fa2ae6f4e2 | |||
| 911182628d | |||
| 308e8440bb | |||
| fad66cf071 | |||
| d7cf9e3da3 | |||
| 03d58f73fb | |||
| a35b3b75a3 | |||
| 040cf83811 | |||
| 07c6d57e74 | |||
| d9e3ae2aee |
22
README.md
@@ -26,6 +26,26 @@ My dotfiles, a constantly evolving set of configurations which I arguably spend
|
|||||||
too much time tweaking, but they make the command line feel like home, so here
|
too much time tweaking, but they make the command line feel like home, so here
|
||||||
we are.
|
we are.
|
||||||
|
|
||||||
|
## 🖥️ Installation
|
||||||
|
|
||||||
|
In order to apply these dotfiles, you must have the SSH Key stored in your password manager,
|
||||||
|
then connect the SSH-Agent to your shell. Once that is done, you will need the application
|
||||||
|
**Stow** in order to keep it synced.
|
||||||
|
|
||||||
|
After this, you will need to git clone the repo in the Projects directory
|
||||||
|
|
||||||
|
```console
|
||||||
|
mkdir Projects
|
||||||
|
git clone ssh://git@gitea.thomasleewilliams.co.uk:2222/thomas/dotfiles.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Once that is complete, run this command:
|
||||||
|
```console
|
||||||
|
stow -d ~/Projects/dotfiles/ -t ~/ dotfiles
|
||||||
|
```
|
||||||
|
|
||||||
|
This will sync wallpapers/config files to where they are usually located
|
||||||
|
|
||||||
## 📦 Programs
|
## 📦 Programs
|
||||||
|
|
||||||
List of programs and tools I use.
|
List of programs and tools I use.
|
||||||
@@ -39,7 +59,7 @@ List of programs and tools I use.
|
|||||||
|📁 File Manager | [thunar](https://wiki.archlinux.org/title/Thunar) |
|
|📁 File Manager | [thunar](https://wiki.archlinux.org/title/Thunar) |
|
||||||
|📝 Editor | [vs code](https://github.com/microsoft/vscode) / [neovim (changing to soon)](https://github.com/neovim/neovim) |
|
|📝 Editor | [vs code](https://github.com/microsoft/vscode) / [neovim (changing to soon)](https://github.com/neovim/neovim) |
|
||||||
|🌐 Browser | [zen](https://github.com/zen-browser/desktop) / [firefox](https://github.com/topics/firefox-browser) / [startpage](https://blog-bucket-personal.s3.eu-west-2.amazonaws.com/Screenshot_02-May_08-44-23_6614.png) |
|
|🌐 Browser | [zen](https://github.com/zen-browser/desktop) / [firefox](https://github.com/topics/firefox-browser) / [startpage](https://blog-bucket-personal.s3.eu-west-2.amazonaws.com/Screenshot_02-May_08-44-23_6614.png) |
|
||||||
|📊 Bar | [waybar](https://github.com/Alexays/Waybar) |
|
|📊 Bar | [waybar](https://github.com/Alexays/Waybar) / [quickshell](https://quickshell.org/) |
|
||||||
|🚀 Launcher | [rofi](https://github.com/davatorium/rofi) |
|
|🚀 Launcher | [rofi](https://github.com/davatorium/rofi) |
|
||||||
|🔒 Lockscreen | [hyprlock](https://github.com/hyprwm/hyprlock) |
|
|🔒 Lockscreen | [hyprlock](https://github.com/hyprwm/hyprlock) |
|
||||||
|🚪 Login Menu | [sddm](https://github.com/sddm/sddm) |
|
|🚪 Login Menu | [sddm](https://github.com/sddm/sddm) |
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||||
"logo": {
|
"logo": {
|
||||||
@@ -49,12 +48,12 @@
|
|||||||
{
|
{
|
||||||
"type": "cursor",
|
"type": "cursor",
|
||||||
"key": "│ ├",
|
"key": "│ ├",
|
||||||
"keyColor": "blue",
|
"keyColor": "blue"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "terminalfont",
|
"type": "terminalfont",
|
||||||
"key": "│ ├",
|
"key": "│ ├",
|
||||||
"keyColor": "blue",
|
"keyColor": "blue"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "terminal",
|
"type": "terminal",
|
||||||
@@ -123,6 +122,6 @@
|
|||||||
"type": "custom",
|
"type": "custom",
|
||||||
"format": "\u001b[90m \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[38m \u001b[39m \u001b[39m \u001b[38m \u001b[37m \u001b[36m \u001b[35m \u001b[34m \u001b[33m \u001b[32m \u001b[31m \u001b[90m "
|
"format": "\u001b[90m \u001b[31m \u001b[32m \u001b[33m \u001b[34m \u001b[35m \u001b[36m \u001b[37m \u001b[38m \u001b[39m \u001b[39m \u001b[38m \u001b[37m \u001b[36m \u001b[35m \u001b[34m \u001b[33m \u001b[32m \u001b[31m \u001b[90m "
|
||||||
},
|
},
|
||||||
"break",
|
"break"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
file:///home/thomas/Projects
|
||||||
file:///home/thomas/Documents
|
file:///home/thomas/Documents
|
||||||
file:///home/thomas/Downloads
|
file:///home/thomas/Downloads
|
||||||
file:///home/thomas/Pictures
|
file:///home/thomas/Pictures
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ bind = $mainMod, K, layoutmsg, cycleprev
|
|||||||
bind = $mainMod CTRL, Return, layoutmsg, swapwithmaster
|
bind = $mainMod CTRL, Return, layoutmsg, swapwithmaster
|
||||||
|
|
||||||
# Dwindle Layout
|
# Dwindle Layout
|
||||||
bind = $mainMod SHIFT, I, togglesplit # only works on dwindle layout
|
|
||||||
bind = $mainMod, P, pseudo, # dwindle
|
bind = $mainMod, P, pseudo, # dwindle
|
||||||
|
|
||||||
# Special Keys / Hot Keys
|
# Special Keys / Hot Keys
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
# NOTE: some settings are in ~/.config/hypr/UserConfigs/UserDecorAnimations.conf
|
# NOTE: some settings are in ~/.config/hypr/UserConfigs/UserDecorAnimations.conf
|
||||||
|
|
||||||
dwindle {
|
dwindle {
|
||||||
pseudotile = true
|
|
||||||
preserve_split = true
|
preserve_split = true
|
||||||
#smart_split = true
|
#smart_split = true
|
||||||
special_scale_factor = 1
|
special_scale_factor = 1
|
||||||
@@ -77,7 +76,6 @@ gestures {
|
|||||||
misc {
|
misc {
|
||||||
disable_hyprland_logo = true
|
disable_hyprland_logo = true
|
||||||
disable_splash_rendering = true
|
disable_splash_rendering = true
|
||||||
vfr = true
|
|
||||||
vrr = 2
|
vrr = 2
|
||||||
mouse_move_enables_dpms = true
|
mouse_move_enables_dpms = true
|
||||||
enable_swallow = off
|
enable_swallow = off
|
||||||
|
|||||||
34
dotfiles/.config/hypr/appearance/animations.lua
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Ported from UserConfigs/UserAnimations.conf (the active preset)
|
||||||
|
--
|
||||||
|
-- The 14 alternative presets from animations/*.conf were also ported, flat, as
|
||||||
|
-- anim-*.lua (see the plan) — none of them are wired in. They now live in ../presets/.
|
||||||
|
-- To switch styles, replace the body of this file with `require("presets.anim-<preset>")`,
|
||||||
|
-- e.g. require("presets.anim-ml4w-classic").
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
animations = {
|
||||||
|
enabled = true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("smoothOut", { type = "bezier", points = { { 0.5, 0 }, { 0.99, 0.99 } } })
|
||||||
|
hl.curve("smoothIn", { type = "bezier", points = { { 0.5, -0.5 }, { 0.68, 1.5 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "smoothOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 100, bezier = "liner", style = "loop" }) -- used by rainbow borders and rotating colors; speed clamped from 180 -> Lua hl.animation caps speed at 100
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 3, bezier = "smoothOut" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "overshot" })
|
||||||
|
|
||||||
|
-- animations for -git or version >0.42.0
|
||||||
|
hl.animation({ leaf = "workspacesIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "workspacesOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
26
dotfiles/.config/hypr/appearance/colors.lua
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- HyprFlux static color palette
|
||||||
|
-- Ported from colours/hyprflux-colors.conf
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.background = "rgb(010102)"
|
||||||
|
M.foreground = "rgb(FDF8FE)"
|
||||||
|
M.color0 = "rgb(313131)"
|
||||||
|
M.color1 = "rgb(09050C)"
|
||||||
|
M.color2 = "rgb(221647)"
|
||||||
|
M.color3 = "rgb(2C1A40)"
|
||||||
|
M.color4 = "rgb(5E3887)"
|
||||||
|
M.color5 = "rgb(7344A6)"
|
||||||
|
M.color6 = "rgb(BAB0BD)"
|
||||||
|
M.color7 = "rgb(F3ECF5)"
|
||||||
|
M.color8 = "rgb(AAA5AC)"
|
||||||
|
M.color9 = "rgb(0B0711)"
|
||||||
|
M.color10 = "rgb(2D1D5F)"
|
||||||
|
M.color11 = "rgb(3B2355)"
|
||||||
|
M.color12 = "rgb(7D4AB4)"
|
||||||
|
M.color13 = "rgb(9A5BDD)"
|
||||||
|
M.color14 = "rgb(F8EAFC)"
|
||||||
|
M.color15 = "rgb(F3ECF5)"
|
||||||
|
|
||||||
|
return M
|
||||||
65
dotfiles/.config/hypr/appearance/decorations.lua
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Decoration Settings
|
||||||
|
-- Ported from UserConfigs/UserDecorations.conf
|
||||||
|
--
|
||||||
|
-- Hyprland Wiki Links
|
||||||
|
-- Animation - https://wiki.hyprland.org/Configuring/Animations/
|
||||||
|
-- Decoration - https://wiki.hyprland.org/Configuring/Variables/#decoration
|
||||||
|
|
||||||
|
local colors = require("appearance.colors")
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
general = {
|
||||||
|
border_size = 2,
|
||||||
|
gaps_in = 2,
|
||||||
|
gaps_out = 4,
|
||||||
|
|
||||||
|
col = {
|
||||||
|
active_border = colors.color12,
|
||||||
|
inactive_border = colors.color10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
decoration = {
|
||||||
|
rounding = 10,
|
||||||
|
|
||||||
|
active_opacity = 1.0,
|
||||||
|
inactive_opacity = 0.9,
|
||||||
|
fullscreen_opacity = 1.0,
|
||||||
|
|
||||||
|
dim_inactive = true,
|
||||||
|
dim_strength = 0.1,
|
||||||
|
dim_special = 0.8,
|
||||||
|
|
||||||
|
shadow = {
|
||||||
|
enabled = false,
|
||||||
|
range = 3,
|
||||||
|
render_power = 1,
|
||||||
|
|
||||||
|
color = colors.color12,
|
||||||
|
color_inactive = colors.color10,
|
||||||
|
},
|
||||||
|
|
||||||
|
blur = {
|
||||||
|
enabled = true,
|
||||||
|
size = 6,
|
||||||
|
passes = 2,
|
||||||
|
ignore_opacity = true,
|
||||||
|
new_optimizations = true,
|
||||||
|
special = true,
|
||||||
|
popups = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
group = {
|
||||||
|
col = {
|
||||||
|
border_active = colors.color15,
|
||||||
|
},
|
||||||
|
|
||||||
|
groupbar = {
|
||||||
|
col = {
|
||||||
|
active = colors.color0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
87
dotfiles/.config/hypr/core/env.lua
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Environment variables. See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/
|
||||||
|
-- Ported from UserConfigs/ENVariables.conf
|
||||||
|
|
||||||
|
-- Toolkit Backend Variables
|
||||||
|
hl.env("GDK_BACKEND", "wayland,x11,*")
|
||||||
|
hl.env("QT_QPA_PLATFORM", "wayland;xcb")
|
||||||
|
hl.env("CLUTTER_BACKEND", "wayland")
|
||||||
|
|
||||||
|
-- Run SDL2 applications on Wayland.
|
||||||
|
-- Remove or set to x11 if games that provide older versions of SDL cause compatibility issues
|
||||||
|
-- hl.env("SDL_VIDEODRIVER", "wayland")
|
||||||
|
|
||||||
|
-- xdg Specifications
|
||||||
|
hl.env("XDG_CURRENT_DESKTOP", "Hyprland")
|
||||||
|
hl.env("XDG_SESSION_DESKTOP", "Hyprland")
|
||||||
|
hl.env("XDG_SESSION_TYPE", "wayland")
|
||||||
|
|
||||||
|
-- QT Variables
|
||||||
|
hl.env("QT_AUTO_SCREEN_SCALE_FACTOR", "1")
|
||||||
|
hl.env("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1")
|
||||||
|
hl.env("QT_QPA_PLATFORMTHEME", "qt5ct")
|
||||||
|
hl.env("QT_QPA_PLATFORMTHEME", "qt6ct")
|
||||||
|
|
||||||
|
-- hyprland-qt-support
|
||||||
|
hl.env("QT_QUICK_CONTROLS_STYLE", "org.hyprland.style")
|
||||||
|
|
||||||
|
-- xwayland apps scale fix (useful if you use monitor scaling).
|
||||||
|
-- Set same value if you use scaling in monitors.lua
|
||||||
|
-- 1 is 100% 1.5 is 150%
|
||||||
|
-- see https://wiki.hyprland.org/Configuring/XWayland/
|
||||||
|
hl.env("GDK_SCALE", "1")
|
||||||
|
hl.env("QT_SCALE_FACTOR", "1")
|
||||||
|
|
||||||
|
-- Bibata-Modern-Ice-Cursor
|
||||||
|
-- NOTE! You must have the hyprcursor version to activate this.
|
||||||
|
-- https://wiki.hyprland.org/Hypr-Ecosystem/hyprcursor/
|
||||||
|
hl.env("HYPRCURSOR_THEME", "Bibata-Modern-Classic")
|
||||||
|
hl.env("HYPRCURSOR_SIZE", "24")
|
||||||
|
|
||||||
|
-- firefox
|
||||||
|
hl.env("MOZ_ENABLE_WAYLAND", "1")
|
||||||
|
|
||||||
|
-- electron >28 apps (may help) ##
|
||||||
|
-- https://www.electronjs.org/docs/latest/api/environment-variables
|
||||||
|
hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto") -- auto selects Wayland if possible, X11 otherwise
|
||||||
|
|
||||||
|
-- NVIDIA
|
||||||
|
-- This is from the Hyprland wiki. Uncomment below if an nvidia GPU is detected.
|
||||||
|
-- See hyprland wiki https://wiki.hyprland.org/Nvidia/#environment-variables
|
||||||
|
|
||||||
|
-- hl.env("LIBVA_DRIVER_NAME", "nvidia")
|
||||||
|
-- hl.env("__GLX_VENDOR_LIBRARY_NAME", "nvidia")
|
||||||
|
-- hl.env("NVD_BACKEND", "direct")
|
||||||
|
-- hl.env("GSK_RENDERER", "ngl")
|
||||||
|
|
||||||
|
-- additional ENV's for nvidia. Caution, activate with care
|
||||||
|
-- hl.env("GBM_BACKEND", "nvidia-drm")
|
||||||
|
|
||||||
|
-- hl.env("__GL_GSYNC_ALLOWED", "1") -- adaptive Vsync
|
||||||
|
-- hl.env("__NV_PRIME_RENDER_OFFLOAD", "1")
|
||||||
|
-- hl.env("__VK_LAYER_NV_optimus", "NVIDIA_only")
|
||||||
|
-- hl.env("WLR_DRM_NO_ATOMIC", "1")
|
||||||
|
|
||||||
|
-- FOR VM and POSSIBLY NVIDIA
|
||||||
|
-- LIBGL_ALWAYS_SOFTWARE software mesa rendering
|
||||||
|
-- hl.env("LIBGL_ALWAYS_SOFTWARE", "1") -- Warning. May cause hyprland to crash
|
||||||
|
-- hl.env("WLR_RENDERER_ALLOW_SOFTWARE", "1")
|
||||||
|
|
||||||
|
-- nvidia firefox (for hardware acceleration on FF)?
|
||||||
|
-- check this post https://github.com/elFarto/nvidia-vaapi-driver#configuration
|
||||||
|
-- hl.env("MOZ_DISABLE_RDD_SANDBOX", "1")
|
||||||
|
-- hl.env("EGL_PLATFORM", "wayland")
|
||||||
|
|
||||||
|
---- Aquamarine Environment Variables ---- ( Hyprland > 0.45 )
|
||||||
|
-- https://wiki.hyprland.org/Configuring/Environment-variables/#aquamarine-environment-variables
|
||||||
|
-- hl.env("AQ_TRACE", "1") -- Enables more verbose logging.
|
||||||
|
-- hl.env("AQ_DRM_DEVICES", "/dev/dri/card1:/dev/dri/card0") -- explicit list of DRM devices (GPUs) to use.
|
||||||
|
-- hl.env("AQ_MGPU_NO_EXPLICIT", "1") -- Disables explicit syncing on mgpu buffers
|
||||||
|
-- hl.env("AQ_NO_MODIFIERS", "1") -- Disables modifiers for DRM buffers
|
||||||
|
|
||||||
|
---- Hyprland Environment Variables ----
|
||||||
|
-- https://wiki.hyprland.org/Configuring/Environment-variables/#hyprland-environment-variables
|
||||||
|
-- hl.env("HYPRLAND_TRACE", "1") -- Enables more verbose logging.
|
||||||
|
-- hl.env("HYPRLAND_NO_RT", "1") -- Disables realtime priority setting by Hyprland.
|
||||||
|
-- hl.env("HYPRLAND_NO_SD_NOTIFY", "1") -- If systemd, disables the 'sd_notify' calls.
|
||||||
|
-- hl.env("HYPRLAND_NO_SD_VARS", "1") -- Disables management of variables in systemd and dbus activation environments.
|
||||||
29
dotfiles/.config/hypr/core/hyprmod.lua
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
-- Generated by HyprMod
|
||||||
|
-- Ported from hyprland-gui.conf
|
||||||
|
--
|
||||||
|
-- HyprMod isn't currently installed on this machine, so this is a straight syntax port of
|
||||||
|
-- whatever it last wrote. If you reinstall HyprMod, prefer letting its own "Migrate to Lua…"
|
||||||
|
-- wizard take over managing this file instead of hand-editing it going forward.
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
general = {
|
||||||
|
allow_tearing = true,
|
||||||
|
snap = {
|
||||||
|
enabled = false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
misc = {
|
||||||
|
vrr = 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Monitors
|
||||||
|
hl.monitor({ output = "DP-2", mode = "1920x1080@165.00Hz", position = "0x0", scale = 1, bitdepth = 10, cm = "wide" })
|
||||||
|
|
||||||
|
-- Keybinds
|
||||||
|
-- (unbind = SUPER SHIFT, Print / unbind = SUPER, up from the source .conf have no Lua equivalent needed —
|
||||||
|
-- we just don't define a conflicting bind elsewhere; SUPER + up -> movefocus u below is otherwise identical
|
||||||
|
-- to the one already in keybinds.lua, kept here too for parity with the original file)
|
||||||
|
hl.bind("SUPER + Print", hl.dsp.exec_cmd("hyprshot -o " .. os.getenv("HOME") .. "/Pictures/Screenshots-Linux -m region"))
|
||||||
|
hl.bind("SUPER + up", hl.dsp.focus({ direction = "u" }))
|
||||||
|
hl.bind("SUPER + SHIFT + Print", hl.dsp.exec_cmd("hyprshot -o " .. os.getenv("HOME") .. "/Pictures/Screenshots-Linux -m window"))
|
||||||
120
dotfiles/.config/hypr/core/settings.lua
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- User Settings
|
||||||
|
-- Ported from UserConfigs/UserSettings.conf
|
||||||
|
--
|
||||||
|
-- refer to Hyprland wiki for more info https://wiki.hyprland.org/Configuring/Variables/
|
||||||
|
-- NOTE: some settings are in animations.lua / decorations.lua
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
dwindle = {
|
||||||
|
preserve_split = true,
|
||||||
|
-- smart_split = true,
|
||||||
|
special_scale_factor = 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
master = {
|
||||||
|
new_status = "master",
|
||||||
|
new_on_top = true,
|
||||||
|
mfact = 0.5,
|
||||||
|
},
|
||||||
|
|
||||||
|
general = {
|
||||||
|
resize_on_border = true,
|
||||||
|
layout = "dwindle",
|
||||||
|
},
|
||||||
|
|
||||||
|
input = {
|
||||||
|
kb_layout = "gb",
|
||||||
|
kb_variant = "",
|
||||||
|
kb_model = "",
|
||||||
|
kb_options = "",
|
||||||
|
kb_rules = "",
|
||||||
|
repeat_rate = 50,
|
||||||
|
repeat_delay = 300,
|
||||||
|
sensitivity = 0.6, -- mouse sensitivity
|
||||||
|
-- accel_profile = "", -- flat or adaptive or blank or EMPTY means libinput's default mode
|
||||||
|
numlock_by_default = true,
|
||||||
|
left_handed = false,
|
||||||
|
follow_mouse = 1,
|
||||||
|
float_switch_override_focus = false,
|
||||||
|
|
||||||
|
touchpad = {
|
||||||
|
disable_while_typing = true,
|
||||||
|
natural_scroll = true,
|
||||||
|
clickfinger_behavior = false,
|
||||||
|
middle_button_emulation = false,
|
||||||
|
tap_to_click = true,
|
||||||
|
drag_lock = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- below for devices with touchdevice ie. touchscreen
|
||||||
|
touchdevice = {
|
||||||
|
enabled = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- below is for tablet, see link above for proper variables
|
||||||
|
tablet = {
|
||||||
|
transform = 0,
|
||||||
|
left_handed = false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- "gestures" here only holds the tuning knobs. workspace_swipe/workspace_swipe_fingers
|
||||||
|
-- were removed from this category upstream in favor of hl.gesture() (see below) — and
|
||||||
|
-- were already commented out in the source .conf, so the swipe gesture itself stays
|
||||||
|
-- disabled here too, ported as-is.
|
||||||
|
gestures = {
|
||||||
|
workspace_swipe_distance = 500,
|
||||||
|
workspace_swipe_invert = true,
|
||||||
|
workspace_swipe_min_speed_to_force = 30,
|
||||||
|
workspace_swipe_cancel_ratio = 0.5,
|
||||||
|
workspace_swipe_create_new = true,
|
||||||
|
workspace_swipe_forever = true,
|
||||||
|
-- workspace_swipe_use_r = true, -- uncomment if wanted a forever create a new workspace with swipe right
|
||||||
|
},
|
||||||
|
|
||||||
|
misc = {
|
||||||
|
disable_hyprland_logo = true,
|
||||||
|
disable_splash_rendering = true,
|
||||||
|
vrr = 2,
|
||||||
|
mouse_move_enables_dpms = true,
|
||||||
|
enable_swallow = false,
|
||||||
|
swallow_regex = "^(kitty)$",
|
||||||
|
focus_on_activate = false,
|
||||||
|
initial_workspace_tracking = 0,
|
||||||
|
middle_click_paste = false,
|
||||||
|
enable_anr_dialog = true, -- Application not Responding (ANR)
|
||||||
|
anr_missed_pings = 15, -- ANR Threshold default 1 is too low
|
||||||
|
},
|
||||||
|
|
||||||
|
-- opengl = {
|
||||||
|
-- nvidia_anti_flicker = true,
|
||||||
|
-- },
|
||||||
|
|
||||||
|
binds = {
|
||||||
|
workspace_back_and_forth = true,
|
||||||
|
allow_workspace_cycles = true,
|
||||||
|
pass_mouse_when_bound = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Could help when scaling and not pixelating
|
||||||
|
xwayland = {
|
||||||
|
enabled = true,
|
||||||
|
force_zero_scaling = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
render = {
|
||||||
|
direct_scanout = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
cursor = {
|
||||||
|
sync_gsettings_theme = true,
|
||||||
|
no_hardware_cursors = 2, -- change to 1 if you want to disable
|
||||||
|
enable_hyprcursor = true,
|
||||||
|
warp_on_change_workspace = 2,
|
||||||
|
no_warps = true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Uncomment to actually enable the touchpad workspace-swipe gesture (see the note above):
|
||||||
|
-- hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
|
||||||
52
dotfiles/.config/hypr/core/startup.lua
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Commands and Apps to be executed at launch
|
||||||
|
-- Ported from UserConfigs/Startup_Apps.conf
|
||||||
|
-- See https://wiki.hypr.land/Configuring/Basics/Autostart/
|
||||||
|
|
||||||
|
local scriptsDir = os.getenv("HOME") .. "/.config/hypr/scripts"
|
||||||
|
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
-- wallpaper stuff
|
||||||
|
hl.exec_cmd("awww-daemon --format xrgb")
|
||||||
|
-- hl.exec_cmd("mpvpaper '*' -o \"load-scripts=no no-audio --loop\" $livewallpaper")
|
||||||
|
|
||||||
|
-- Startup
|
||||||
|
hl.exec_cmd("dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP")
|
||||||
|
hl.exec_cmd("systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP")
|
||||||
|
|
||||||
|
-- Polkit (Polkit Gnome / KDE)
|
||||||
|
hl.exec_cmd(scriptsDir .. "/Polkit.sh")
|
||||||
|
|
||||||
|
-- startup apps
|
||||||
|
hl.exec_cmd("nm-applet --indicator")
|
||||||
|
hl.exec_cmd("swaync")
|
||||||
|
-- hl.exec_cmd("ags")
|
||||||
|
-- hl.exec_cmd("blueman-applet")
|
||||||
|
-- hl.exec_cmd("rog-control-center")
|
||||||
|
hl.exec_cmd("waybar")
|
||||||
|
hl.exec_cmd("qs") -- quickshell AGS Desktop Overview alternative
|
||||||
|
|
||||||
|
-- clipboard manager
|
||||||
|
hl.exec_cmd("wl-paste --type text --watch cliphist store")
|
||||||
|
hl.exec_cmd("wl-paste --type image --watch cliphist store")
|
||||||
|
|
||||||
|
-- Starting hypridle to start hyprlock
|
||||||
|
hl.exec_cmd("hypridle")
|
||||||
|
|
||||||
|
-- Float + center the Bitwarden extension pop-out (window rules can't catch it — see the script)
|
||||||
|
hl.exec_cmd(scriptsDir .. "/FloatBitwardenPopup.sh")
|
||||||
|
|
||||||
|
hl.dispatch(hl.dsp.focus({ workspace = 3 }))
|
||||||
|
|
||||||
|
-- NOTE: the trailing "&&" here is a stray leftover from the original .conf (dangling, does nothing) — ported as-is
|
||||||
|
hl.exec_cmd("/usr/bin/Plexamp.AppImage &&")
|
||||||
|
hl.exec_cmd("sleep 3 && vesktop")
|
||||||
|
hl.dispatch(hl.dsp.focus({ workspace = 1 }))
|
||||||
|
hl.exec_cmd("bitwarden-desktop --ozone-platform-hint=auto --silent")
|
||||||
|
|
||||||
|
-- Here are a list of features available but disabled by default
|
||||||
|
-- hl.exec_cmd("awww-daemon --format xrgb && awww img " .. os.getenv("HOME") .. "/Pictures/wallpapers/mecha-nostalgia.png") -- persistent wallpaper
|
||||||
|
|
||||||
|
-- xdg-desktop-portal-hyprland (should be auto starting. However, you can force to start)
|
||||||
|
-- hl.exec_cmd(scriptsDir .. "/PortalHyprland.sh")
|
||||||
|
end)
|
||||||
@@ -10,6 +10,6 @@ monitor = DP-2, 1920x1080@165.00Hz, 0x0, 1, bitdepth, 10, cm, wide
|
|||||||
# Keybinds
|
# Keybinds
|
||||||
unbind = SUPER SHIFT, Print
|
unbind = SUPER SHIFT, Print
|
||||||
unbind = SUPER, up
|
unbind = SUPER, up
|
||||||
bind = SUPER, Print, exec, hyprshot -o $HOME/Pictures/Screenshots -m region
|
bind = SUPER, Print, exec, hyprshot -o $HOME/Pictures/Screenshots-Linux -m region
|
||||||
bind = SUPER, up, movefocus, u
|
bind = SUPER, up, movefocus, u
|
||||||
bind = SUPER SHIFT, Print, exec, hyprshot -o $HOME/Pictures/Screenshots -m window
|
bind = SUPER SHIFT, Print, exec, hyprshot -o $HOME/Pictures/Screenshots-Linux -m window
|
||||||
|
|||||||
42
dotfiles/.config/hypr/hyprland.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Ported from hyprland.conf — see https://wiki.hyprland.org/
|
||||||
|
--
|
||||||
|
-- This mirrors the old source= chain 1:1, just as require()'d Lua modules instead
|
||||||
|
-- of hyprlang includes. See each file for its origin. The presets/ preset library
|
||||||
|
-- (anim-*.lua) is also ported but intentionally not required from here — only the
|
||||||
|
-- currently-active style (appearance/animations.lua) is wired in, exactly like before.
|
||||||
|
--
|
||||||
|
-- Modules live in subfolders sorted by concern (core/, appearance/, layout/, input/,
|
||||||
|
-- presets/) — require() paths below use dotted module names, which Lua resolves to
|
||||||
|
-- the matching subfolder (e.g. require("core.env") -> core/env.lua).
|
||||||
|
|
||||||
|
-- Initial boot script: applies initial wallpapers, theming, new settings etc.
|
||||||
|
-- suggest not changing/deleting this, including the reference file at ~/.config/hypr/.initial_startup_done
|
||||||
|
-- as long as that reference file is present, initial-boot.sh will not execute
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
hl.exec_cmd(os.getenv("HOME") .. "/.config/hypr/initial-boot.sh")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- ## This is where you want to start tinkering
|
||||||
|
require("core.startup") -- put your start-up packages in core/startup.lua
|
||||||
|
require("core.env") -- Environment variables to load
|
||||||
|
require("layout.windowrules") -- all about Hyprland Window Rules and Layer Rules
|
||||||
|
require("appearance.decorations") -- Decorations config
|
||||||
|
require("appearance.animations") -- Animation config
|
||||||
|
require("input.keybinds") -- Put your own keybinds here
|
||||||
|
require("core.settings") -- Main Hyprland Settings
|
||||||
|
|
||||||
|
-- nwg-displays / hyprdynamicmonitors
|
||||||
|
require("layout.monitors")
|
||||||
|
require("layout.workspaces")
|
||||||
|
|
||||||
|
-- NOTE: the original hyprland.conf used a plain `exec` (not `exec-once`) here, so it
|
||||||
|
-- re-ran on every `hyprctl reload`, not just at startup. hl.on("hyprland.start", ...)
|
||||||
|
-- only fires once at actual compositor start — close enough for a one-shot gsettings
|
||||||
|
-- call, but worth knowing if you relied on the reload-time re-apply.
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
hl.exec_cmd("gsettings set org.gnome.desktop.interface cursor-theme Future-black Cursors")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- HyprMod managed settings
|
||||||
|
require("core.hyprmod")
|
||||||
176
dotfiles/.config/hypr/input/keybinds.lua
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Ported from UserConfigs/Keybinds.conf
|
||||||
|
-- See https://wiki.hypr.land/Configuring/Basics/Binds/ and .../Basics/Dispatchers/
|
||||||
|
|
||||||
|
local mainMod = "SUPER"
|
||||||
|
local scriptsDir = os.getenv("HOME") .. "/.config/hypr/scripts"
|
||||||
|
local userScripts = os.getenv("HOME") .. "/.config/hypr/UserScripts"
|
||||||
|
|
||||||
|
-- settings for user default apps
|
||||||
|
local edit = os.getenv("EDITOR") or "nvim"
|
||||||
|
|
||||||
|
-- These two are for UserKeybinds.conf & Waybar Modules
|
||||||
|
local term = "foot" -- Terminal
|
||||||
|
local files = "thunar" -- File Manager
|
||||||
|
|
||||||
|
-- Default Search Engine for ROFI Search (SUPER S)
|
||||||
|
local searchEngine = "https://www.google.com/search?q={}"
|
||||||
|
|
||||||
|
-- common shortcuts
|
||||||
|
hl.bind(mainMod .. " + SPACE", hl.dsp.exec_cmd(".config/rofi/launchers/type-4/launcher.sh")) -- desktop overview (if installed)
|
||||||
|
hl.bind(mainMod .. " + Q", hl.dsp.window.close()) -- close active (not kill)
|
||||||
|
hl.bind(mainMod .. " + SHIFT + Q", hl.dsp.exec_cmd(scriptsDir .. "/KillActiveProcess.sh")) -- Kill active process
|
||||||
|
hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(term)) -- terminal
|
||||||
|
hl.bind(mainMod .. " + F", hl.dsp.exec_cmd(files)) -- file manager
|
||||||
|
hl.bind(mainMod .. " + B", hl.dsp.exec_cmd("zen-browser")) -- Launch Zen Browser New Everytime
|
||||||
|
hl.bind(mainMod .. " + V", hl.dsp.exec_cmd(scriptsDir .. "/ClipManager.sh")) -- Clipboard Manager
|
||||||
|
hl.bind(mainMod .. " + C", hl.dsp.exec_cmd("code --ozone-platform=x11")) -- Visual Studio Code
|
||||||
|
hl.bind(mainMod .. " + O", hl.dsp.exec_cmd("obsidian --ozone-platform=x11")) -- Obsidian
|
||||||
|
hl.bind(mainMod .. " + X", hl.dsp.exec_cmd("vesktop")) -- Vesktop(Discord)
|
||||||
|
hl.bind(mainMod .. " + M", hl.dsp.exec_cmd("fdm")) -- Free Download Manager
|
||||||
|
hl.bind(mainMod .. " + W", hl.dsp.exec_cmd("waypaper")) -- Wayland Wallpaper Setter
|
||||||
|
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd("hyprlock")) -- Screen Locker
|
||||||
|
hl.bind(mainMod .. " + DELETE", hl.dsp.exec_cmd("~/.config/rofi/powermenu/type-2/powermenu.sh")) -- Power Menu
|
||||||
|
hl.bind(mainMod .. " + S", hl.dsp.exec_cmd("cd /home/thomas/hyprmod && uv run hyprmod")) -- Hyprmod - A Hyprland settings manager (if installed)
|
||||||
|
hl.bind(mainMod .. " + SHIFT + R", hl.dsp.exec_cmd(scriptsDir .. "/Refresh.sh")) -- Refresh waybar, swaync, rofirrr
|
||||||
|
hl.bind(mainMod .. " + N", hl.dsp.exec_cmd("swaync-client -t -sw")) -- swayNC notification panel
|
||||||
|
|
||||||
|
-- FEATURES / EXTRAS
|
||||||
|
hl.bind(mainMod .. " + SHIFT + F", hl.dsp.window.fullscreen({ mode = "fullscreen" })) -- whole full screen
|
||||||
|
hl.bind(mainMod .. " + SHIFT + SPACE", hl.dsp.window.float({ action = "toggle" })) -- Float Mode
|
||||||
|
|
||||||
|
-- Desktop zooming or magnifier
|
||||||
|
hl.bind(mainMod .. " + ALT + mouse_down", hl.dsp.exec_cmd([[hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor * 2.0}')"]]))
|
||||||
|
hl.bind(mainMod .. " + ALT + mouse_up", hl.dsp.exec_cmd([[hyprctl keyword cursor:zoom_factor "$(hyprctl getoption cursor:zoom_factor | awk 'NR==1 {factor = $2; if (factor < 1) {factor = 1}; print factor / 2.0}')"]]))
|
||||||
|
|
||||||
|
-- Waybar / Bar related
|
||||||
|
hl.bind(mainMod .. " + CTRL + ALT + B", hl.dsp.exec_cmd("pkill -SIGUSR1 waybar")) -- Toggle hide/show waybar
|
||||||
|
|
||||||
|
-- FEATURES / EXTRAS (UserScripts)
|
||||||
|
hl.bind(mainMod .. " + SHIFT + A", hl.dsp.exec_cmd(scriptsDir .. "/Animations.sh")) -- hyprland animations menu
|
||||||
|
hl.bind(mainMod .. " + SHIFT + Z", hl.dsp.exec_cmd(userScripts .. "/ZshChangeTheme.sh")) -- Change oh-my-zsh theme
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
-- Default Keybinds
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
hl.bind("CTRL + ALT + Delete", hl.dsp.exit()) -- exit Hyprland
|
||||||
|
|
||||||
|
-- Master Layout
|
||||||
|
hl.bind(mainMod .. " + CTRL + D", hl.dsp.layout("removemaster"))
|
||||||
|
hl.bind(mainMod .. " + I", hl.dsp.layout("addmaster"))
|
||||||
|
hl.bind(mainMod .. " + J", hl.dsp.layout("cyclenext"))
|
||||||
|
hl.bind(mainMod .. " + K", hl.dsp.layout("cycleprev"))
|
||||||
|
hl.bind(mainMod .. " + CTRL + Return", hl.dsp.layout("swapwithmaster"))
|
||||||
|
|
||||||
|
-- Dwindle Layout
|
||||||
|
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo()) -- dwindle
|
||||||
|
|
||||||
|
-- Special Keys / Hot Keys
|
||||||
|
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd(scriptsDir .. "/Volume.sh --inc"), { repeating = true, locked = true }) -- volume up
|
||||||
|
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd(scriptsDir .. "/Volume.sh --dec"), { repeating = true, locked = true }) -- volume down
|
||||||
|
hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd(scriptsDir .. "/Volume.sh --toggle-mic"), { locked = true }) -- mic mute
|
||||||
|
hl.bind("XF86AudioMute", hl.dsp.exec_cmd(scriptsDir .. "/Volume.sh --toggle"), { locked = true }) -- mute
|
||||||
|
hl.bind("XF86Sleep", hl.dsp.exec_cmd("systemctl suspend"), { locked = true }) -- sleep button
|
||||||
|
hl.bind("XF86RFKill", hl.dsp.exec_cmd(scriptsDir .. "/AirplaneMode.sh"), { locked = true }) -- Airplane mode
|
||||||
|
|
||||||
|
-- media controls using keyboards
|
||||||
|
hl.bind("XF86MediaPlayPause", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --pause"), { locked = true })
|
||||||
|
hl.bind("XF86AudioPause", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --pause"), { locked = true })
|
||||||
|
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --pause"), { locked = true })
|
||||||
|
hl.bind("XF86AudioNext", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --nxt"), { locked = true })
|
||||||
|
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --prv"), { locked = true })
|
||||||
|
hl.bind("XF86AudioStop", hl.dsp.exec_cmd(scriptsDir .. "/MediaCtrl.sh --stop"), { locked = true })
|
||||||
|
|
||||||
|
-- Resize windows
|
||||||
|
hl.bind(mainMod .. " + SHIFT + left", hl.dsp.window.resize({ x = -50, y = 0, relative = true }), { repeating = true })
|
||||||
|
hl.bind(mainMod .. " + SHIFT + right", hl.dsp.window.resize({ x = 50, y = 0, relative = true }), { repeating = true })
|
||||||
|
hl.bind(mainMod .. " + SHIFT + up", hl.dsp.window.resize({ x = 0, y = -50, relative = true }), { repeating = true })
|
||||||
|
hl.bind(mainMod .. " + SHIFT + down", hl.dsp.window.resize({ x = 0, y = 50, relative = true }), { repeating = true })
|
||||||
|
|
||||||
|
-- Move windows
|
||||||
|
hl.bind(mainMod .. " + CTRL + left", hl.dsp.window.move({ direction = "l" }))
|
||||||
|
hl.bind(mainMod .. " + CTRL + right", hl.dsp.window.move({ direction = "r" }))
|
||||||
|
hl.bind(mainMod .. " + CTRL + up", hl.dsp.window.move({ direction = "u" }))
|
||||||
|
hl.bind(mainMod .. " + CTRL + down", hl.dsp.window.move({ direction = "d" }))
|
||||||
|
|
||||||
|
-- Swap windows
|
||||||
|
hl.bind(mainMod .. " + ALT + left", hl.dsp.window.swap({ direction = "l" }))
|
||||||
|
hl.bind(mainMod .. " + ALT + right", hl.dsp.window.swap({ direction = "r" }))
|
||||||
|
hl.bind(mainMod .. " + ALT + up", hl.dsp.window.swap({ direction = "u" }))
|
||||||
|
hl.bind(mainMod .. " + ALT + down", hl.dsp.window.swap({ direction = "d" }))
|
||||||
|
|
||||||
|
-- Move focus with mainMod + arrow keys
|
||||||
|
hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = "l" }))
|
||||||
|
hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "r" }))
|
||||||
|
hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = "u" }))
|
||||||
|
hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = "d" }))
|
||||||
|
|
||||||
|
-- Workspaces related
|
||||||
|
hl.bind(mainMod .. " + tab", hl.dsp.focus({ workspace = "m+1" }))
|
||||||
|
hl.bind(mainMod .. " + SHIFT + tab", hl.dsp.focus({ workspace = "m-1" }))
|
||||||
|
|
||||||
|
-- Special workspace
|
||||||
|
-- hl.bind(mainMod .. " + SHIFT + U", hl.dsp.window.move({ workspace = "special" }))
|
||||||
|
-- hl.bind(mainMod .. " + U", hl.dsp.workspace.toggle_special())
|
||||||
|
hl.bind(mainMod .. " + U", hl.dsp.workspace.toggle_special("nyx"))
|
||||||
|
hl.bind(mainMod .. " + SHIFT + U", hl.dsp.window.move({ workspace = "special:nyx" }))
|
||||||
|
|
||||||
|
-- The following mappings use key codes to better support various keyboard layouts
|
||||||
|
-- 1 is code:10, 2 is code:11, etc
|
||||||
|
-- Switch workspaces with mainMod + [0-9]
|
||||||
|
for i, code in ipairs({ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }) do
|
||||||
|
hl.bind(mainMod .. " + code:" .. code, hl.dsp.focus({ workspace = i })) -- code:10 = key 1 ... code:19 = key 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move active window and follow to workspace mainMod + SHIFT + [0-9]
|
||||||
|
for i, code in ipairs({ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }) do
|
||||||
|
hl.bind(mainMod .. " + SHIFT + code:" .. code, hl.dsp.window.move({ workspace = i, follow = true }))
|
||||||
|
end
|
||||||
|
hl.bind(mainMod .. " + SHIFT + bracketleft", hl.dsp.window.move({ workspace = -1, follow = true })) -- brackets [
|
||||||
|
hl.bind(mainMod .. " + SHIFT + bracketright", hl.dsp.window.move({ workspace = 1, follow = true })) -- brackets ]
|
||||||
|
|
||||||
|
-- Move active window to a workspace silently mainMod + CTRL + [0-9]
|
||||||
|
for i, code in ipairs({ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }) do
|
||||||
|
hl.bind(mainMod .. " + CTRL + code:" .. code, hl.dsp.window.move({ workspace = i, follow = false }))
|
||||||
|
end
|
||||||
|
hl.bind(mainMod .. " + CTRL + bracketleft", hl.dsp.window.move({ workspace = -1, follow = false })) -- brackets [
|
||||||
|
hl.bind(mainMod .. " + CTRL + bracketright", hl.dsp.window.move({ workspace = 1, follow = false })) -- brackets ]
|
||||||
|
|
||||||
|
-- Scroll through existing workspaces with mainMod + scroll
|
||||||
|
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
|
||||||
|
hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
|
||||||
|
hl.bind(mainMod .. " + period", hl.dsp.focus({ workspace = "e+1" }))
|
||||||
|
hl.bind(mainMod .. " + comma", hl.dsp.focus({ workspace = "e-1" }))
|
||||||
|
|
||||||
|
-- Move/resize windows with mainMod + LMB/RMB and dragging
|
||||||
|
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true }) -- mouse:272 = left click
|
||||||
|
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true }) -- mouse:273 = right click
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
-- Laptop specific keybinds
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- for disabling Touchpad. hyprctl devices to get device name.
|
||||||
|
local touchpadDevice = "asue1209:00-04f3:319f-touchpad"
|
||||||
|
|
||||||
|
hl.bind("XF86KbdBrightnessDown", hl.dsp.exec_cmd(scriptsDir .. "/BrightnessKbd.sh --dec"), { repeating = true }) -- decrease keyboard brightness
|
||||||
|
hl.bind("XF86KbdBrightnessUp", hl.dsp.exec_cmd(scriptsDir .. "/BrightnessKbd.sh --inc"), { repeating = true }) -- increase keyboard brightness
|
||||||
|
hl.bind("XF86Launch1", hl.dsp.exec_cmd("rog-control-center")) -- ASUS Armory crate button
|
||||||
|
hl.bind("XF86Launch3", hl.dsp.exec_cmd("asusctl led-mode -n")) -- FN+F4 Switch keyboard RGB profile
|
||||||
|
hl.bind("XF86Launch4", hl.dsp.exec_cmd("asusctl profile -n")) -- FN+F5 change of fan profiles (Quiet, Balance, Performance)
|
||||||
|
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd(scriptsDir .. "/Brightness.sh --dec"), { repeating = true }) -- decrease monitor brightness
|
||||||
|
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd(scriptsDir .. "/Brightness.sh --inc"), { repeating = true }) -- increase monitor brightness
|
||||||
|
hl.bind("XF86TouchpadToggle", hl.dsp.exec_cmd(scriptsDir .. "/TouchPad.sh")) -- disable touchpad
|
||||||
|
|
||||||
|
-- Screenshot keybindings using F6 (no PrintSrc button)
|
||||||
|
-- hl.bind(mainMod .. " + F6", hl.dsp.exec_cmd(scriptsDir .. "/ScreenShot.sh --now")) -- screenshot
|
||||||
|
-- hl.bind(mainMod .. " + SHIFT + F6", hl.dsp.exec_cmd(scriptsDir .. "/ScreenShot.sh --area")) -- screenshot (area)
|
||||||
|
-- hl.bind(mainMod .. " + CTRL + F6", hl.dsp.exec_cmd(scriptsDir .. "/ScreenShot.sh --in5")) -- screenshot (5 secs delay)
|
||||||
|
-- hl.bind(mainMod .. " + ALT + F6", hl.dsp.exec_cmd(scriptsDir .. "/ScreenShot.sh --in10")) -- screenshot (10 secs delay)
|
||||||
|
-- hl.bind("ALT + F6", hl.dsp.exec_cmd(scriptsDir .. "/ScreenShot.sh --active")) -- screenshot (active window only)
|
||||||
|
|
||||||
|
hl.device({
|
||||||
|
name = touchpadDevice,
|
||||||
|
enabled = true,
|
||||||
|
})
|
||||||
14
dotfiles/.config/hypr/layout/monitors.lua
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-- Generated with hyprdynamicmonitors freeze.
|
||||||
|
-- This is a template that you can edit, it is just a starter that pulled your current monitor setup,
|
||||||
|
-- adjust as needed.
|
||||||
|
-- You can use templates here etc, see https://github.com/fiffeek/hyprdynamicmonitors/blob/main/examples/basic/hyprconfigs/template.go.tmpl.
|
||||||
|
-- Monitors are given arbitrary tags (the "monitor" prefix and the ID coming from hyprland).
|
||||||
|
-- If you are using the TUI to edit, leave this at the end of the file (the last monitor config applies)
|
||||||
|
-- and leave the markers.
|
||||||
|
-- Ported from UserConfigs/monitors.conf — hyprdynamicmonitors already supports writing this file
|
||||||
|
-- directly as monitors.lua once hyprland.lua is active, so re-running it should stay compatible.
|
||||||
|
-- <<<<< TUI AUTO START
|
||||||
|
hl.monitor({ output = "desc:LG Electronics LG ULTRAWIDE 0x0002E68A", mode = "2560x1080@60.00000", position = "1920x-740", scale = 1.00000000, transform = 3, vrr = 0 })
|
||||||
|
hl.monitor({ output = "desc:HP Inc. HP 524pf VNG447017D", mode = "1920x1080@100.00000", position = "-1920x0", scale = 1.00000000, transform = 0, vrr = 0 })
|
||||||
|
hl.monitor({ output = "desc:Acer Technologies VG240Y S 0x126191DE", mode = "1920x1080@165.00301", position = "0x0", scale = 1.00000000, transform = 0, vrr = 1, bitdepth = 10, cm = "wide" })
|
||||||
|
-- <<<<< TUI AUTO END
|
||||||
203
dotfiles/.config/hypr/layout/windowrules.lua
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- For window rules and layer rules
|
||||||
|
-- Ported from UserConfigs/WindowRules.conf
|
||||||
|
-- See https://wiki.hypr.land/Configuring/Basics/Window-Rules/
|
||||||
|
|
||||||
|
-- windowrule - tags - add apps under appropriate tag to use the same settings
|
||||||
|
-- browser tags
|
||||||
|
hl.window_rule({ name = "windowrule-1", tag = "+browser", match = { class = "^([Ff]irefox|org.mozilla.firefox|[Ff]irefox-esr|[Ff]irefox-bin)$" } })
|
||||||
|
hl.window_rule({ name = "rustdesk", tag = "+rustdesk", match = { class = "^(rustdesk)$", xwayland = true } })
|
||||||
|
hl.window_rule({ name = "windowrule-2", tag = "+browser", match = { class = "^([Gg]oogle-chrome(-beta|-dev|-unstable)?)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-3", tag = "+browser", match = { class = "^(chrome-.+-Default)$" } }) -- Chrome PWAs
|
||||||
|
-- hl.window_rule({ name = "browser-chromium", tag = "+browser", match = { class = "^([Cc]hromium)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-4", tag = "+browser", match = { class = "^([Mm]icrosoft-edge(-stable|-beta|-dev|-unstable))$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-5", tag = "+browser", match = { class = "^(Brave-browser(-beta|-dev|-unstable)?)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-6", tag = "+browser", match = { class = "^([Tt]horium-browser|[Cc]achy-browser)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-7", tag = "+browser", match = { class = "^(zen-alpha|zen)$" } })
|
||||||
|
|
||||||
|
-- notif tags
|
||||||
|
hl.window_rule({ name = "windowrule-8", tag = "+notif", match = { class = "^(swaync-control-center|swaync-notification-window|swaync-client|class)$" } })
|
||||||
|
|
||||||
|
-- HyprFlux settings tag
|
||||||
|
hl.window_rule({ name = "windowrule-9", tag = "+HyprFlux_Cheat", match = { title = "^(HyprFlux Quick Cheat Sheet)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-10", tag = "+HyprFlux_Settings", match = { title = "^(HyprFlux Settings)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-11", tag = "+HyprFlux-Settings", match = { class = "^(nwg-displays|nwg-look)$" } })
|
||||||
|
|
||||||
|
-- terminal tags
|
||||||
|
hl.window_rule({ name = "windowrule-12", tag = "+terminal", match = { class = "^(Alacritty|kitty|kitty-dropterm)$" } })
|
||||||
|
|
||||||
|
-- email tags
|
||||||
|
hl.window_rule({ name = "windowrule-13", tag = "+email", match = { class = "^([Tt]hunderbird|org.gnome.Evolution)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-14", tag = "+email", match = { class = "^(eu.betterbird.Betterbird)$" } })
|
||||||
|
|
||||||
|
-- project tags
|
||||||
|
hl.window_rule({ name = "windowrule-15", tag = "+projects", match = { class = "^(codium|codium-url-handler|VSCodium)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-16", tag = "+projects", match = { class = "^(VSCode|code-url-handler)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-17", tag = "+projects", match = { class = "^(jetbrains-.+)$" } }) -- JetBrains IDEs
|
||||||
|
|
||||||
|
-- screenshare tags
|
||||||
|
hl.window_rule({ name = "windowrule-18", tag = "+screenshare", match = { class = "^(com.obsproject.Studio)$" } })
|
||||||
|
|
||||||
|
-- IM tags
|
||||||
|
-- hl.window_rule({ tag = "+im", match = { class = "^([Dd]iscord|[Ww]ebCord|[Vv]esktop)$" } })
|
||||||
|
hl.window_rule({
|
||||||
|
name = "windowrule-19",
|
||||||
|
tag = "+im",
|
||||||
|
center = true,
|
||||||
|
float = true,
|
||||||
|
size = "monitor_w*0.6 monitor_h*0.7",
|
||||||
|
match = { class = "^([Ff]erdium)$" },
|
||||||
|
})
|
||||||
|
hl.window_rule({ name = "windowrule-20", tag = "+im", match = { class = "^([Ww]hatsapp-for-linux)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-21", tag = "+im", match = { class = "^(ZapZap|com.rtosta.zapzap)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-22", tag = "+im", match = { class = "^(org.telegram.desktop|io.github.tdesktop_x64.TDesktop)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-23", tag = "+im", match = { class = "^(teams-for-linux)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-24", tag = "+im", match = { class = "^(im.riot.Riot|Element)$" } }) -- Element Matrix client
|
||||||
|
|
||||||
|
-- game tags
|
||||||
|
hl.window_rule({ name = "windowrule-25", tag = "+games", match = { class = "^(gamescope)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-26", tag = "+games", match = { class = "^(steam_app_\\d+)$" } })
|
||||||
|
|
||||||
|
-- gamestore tags
|
||||||
|
hl.window_rule({ name = "windowrule-27", tag = "+gamestore", match = { class = "^([Ss]team)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-28", tag = "+gamestore", match = { title = "^([Ll]utris)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-29", tag = "+gamestore", match = { class = "^(com.heroicgameslauncher.hgl)$" } })
|
||||||
|
|
||||||
|
-- file-manager tags
|
||||||
|
hl.window_rule({ name = "windowrule-30", tag = "+file-manager", match = { class = "^([Tt]hunar|org.gnome.Nautilus|[Pp]cmanfm-qt)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-31", tag = "+file-manager", match = { class = "^(app.drey.Warp)$" } })
|
||||||
|
|
||||||
|
-- wallpaper tags
|
||||||
|
hl.window_rule({ name = "windowrule-32", tag = "+wallpaper", match = { class = "^([Ww]aytrogen)$" } })
|
||||||
|
|
||||||
|
-- multimedia tags
|
||||||
|
hl.window_rule({ name = "windowrule-33", tag = "+multimedia", match = { class = "^([Aa]udacious)$" } })
|
||||||
|
|
||||||
|
-- multimedia-video tags
|
||||||
|
hl.window_rule({ name = "windowrule-34", tag = "+multimedia_video", match = { class = "^([Mm]pv|vlc)$" } })
|
||||||
|
|
||||||
|
-- settings tags
|
||||||
|
hl.window_rule({ name = "windowrule-35", tag = "+settings", center = true, match = { title = "^(ROG Control)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-36", tag = "+settings", match = { class = "^(wihotspot(-gui)?)$" } }) -- wifi hotspot
|
||||||
|
hl.window_rule({ name = "windowrule-37", tag = "+settings", match = { class = "^([Bb]aobab|org.gnome.[Bb]aobab)$" } }) -- Disk usage analyzer
|
||||||
|
hl.window_rule({ name = "windowrule-38", tag = "+settings", match = { class = "^(gnome-disks|wihotspot(-gui)?)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-39", tag = "+settings", match = { title = "(Kvantum Manager)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-40", tag = "+settings", match = { class = "^(file-roller|org.gnome.FileRoller)$" } }) -- archive manager
|
||||||
|
hl.window_rule({ name = "windowrule-41", tag = "+settings", match = { class = "^(nm-applet|nm-connection-editor|blueman-manager)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-42", tag = "+settings", center = true, match = { class = "^(pavucontrol|org.pulseaudio.pavucontrol|com.saivert.pwvucontrol)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-43", tag = "+settings", match = { class = "^(qt5ct|qt6ct|[Yy]ad)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-44", tag = "+settings", match = { class = "(xdg-desktop-portal-gtk)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-45", tag = "+settings", match = { class = "^(org.kde.polkit-kde-authentication-agent-1)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-46", tag = "+settings", match = { class = "^([Rr]ofi)$" } })
|
||||||
|
|
||||||
|
-- Custom rule
|
||||||
|
hl.window_rule({ name = "windowrule-47", tile = true, match = { class = "^([Cc]hromium)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-48", size = "monitor_w*0.25 monitor_h*0.55", float = true, match = { class = "^(com.network.manager)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-49", workspace = "special:nyx", match = { class = "^([Vv]esktop|[Dd]iscord|[Ss]potify)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-255", size = "monitor_w*0.75 monitor_h*0.80", float = true, match = { class = "^([Bb]itwarden)$" } })
|
||||||
|
|
||||||
|
-- viewer tags
|
||||||
|
hl.window_rule({ name = "windowrule-50", tag = "+viewer", match = { class = "^(gnome-system-monitor|org.gnome.SystemMonitor|io.missioncenter.MissionCenter)$" } }) -- system monitor
|
||||||
|
hl.window_rule({ name = "windowrule-51", tag = "+viewer", match = { class = "^(evince)$" } }) -- document viewer
|
||||||
|
hl.window_rule({ name = "windowrule-52", tag = "+viewer", match = { class = "^(eog|org.gnome.Loupe)$" } }) -- image viewer
|
||||||
|
|
||||||
|
-- Some special override rules
|
||||||
|
hl.window_rule({ name = "windowrule-53", no_blur = true, opacity = "1.0", match = { tag = "multimedia_video*" } })
|
||||||
|
|
||||||
|
-- POSITION
|
||||||
|
-- hl.window_rule({ center = true, match = { float = true } }) -- warning, it cause even the menu to float and center.
|
||||||
|
hl.window_rule({ name = "windowrule-54", center = true, float = true, size = "monitor_w*0.65 monitor_h*0.9", match = { tag = "HyprFlux_Cheat*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-55", center = true, float = true, match = { class = "([Tt]hunar)", title = "negative:(.*[Tt]hunar.*)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-56", center = true, float = true, match = { tag = "HyprFlux-Settings*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-57", center = true, match = { title = "^(Keybindings)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-58", center = true, size = "monitor_w*0.6 monitor_h*0.7", match = { class = "^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$" } })
|
||||||
|
hl.window_rule({
|
||||||
|
name = "windowrule-59",
|
||||||
|
move = "monitor_w*0.61 monitor_h*0.07",
|
||||||
|
float = true,
|
||||||
|
size = "monitor_w*0.38 monitor_h*0.38",
|
||||||
|
pin = true,
|
||||||
|
keep_aspect_ratio = true,
|
||||||
|
match = { title = "^(Picture-in-Picture)$" },
|
||||||
|
})
|
||||||
|
|
||||||
|
-- hl.window_rule({ move = "72% 7%", match = { title = "^(Firefox)$" } })
|
||||||
|
|
||||||
|
-- windowrule to avoid idle for fullscreen apps
|
||||||
|
-- hl.window_rule({ idle_inhibit = "fullscreen", match = { class = "^(*)$" } })
|
||||||
|
-- hl.window_rule({ idle_inhibit = "fullscreen", match = { title = "^(*)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-60", idle_inhibit = "fullscreen", match = { fullscreen = true } })
|
||||||
|
|
||||||
|
-- Discord to workspace 3
|
||||||
|
-- NOTE: these two used the old single-line windowrule syntax in the source .conf (match packed
|
||||||
|
-- oddly with the rule); windowrule-49 above already sends the same apps to special:nyx, so this
|
||||||
|
-- looks like a pre-existing conflict in the original config rather than something introduced here —
|
||||||
|
-- ported literally, last-defined-wins as before.
|
||||||
|
hl.window_rule({ workspace = "3", match = { class = "^([Vv]esktop|[Dd]iscord|[Ss]potify|[Pp]lexamp)$" } })
|
||||||
|
hl.window_rule({ size = "20% 20%", match = { class = "^([Pp]lexamp)" } })
|
||||||
|
|
||||||
|
-- FLOAT
|
||||||
|
hl.window_rule({ name = "windowrule-75", float = true, opacity = "0.9 0.7", size = "monitor_w*0.7 monitor_h*0.7", match = { tag = "wallpaper*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-76", float = true, opacity = "0.8 0.7", size = "monitor_w*0.7 monitor_h*0.7", match = { tag = "settings*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-77", float = true, match = { tag = "viewer*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-78", float = true, match = { class = "([Zz]oom|onedriver|onedriver-launcher)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-79", float = true, match = { class = "(org.gnome.Calculator)", title = "(Calculator)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-80", float = true, match = { class = "^(mpv|com.github.rafostar.Clapper)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-81", float = true, match = { class = "^([Qq]alculate-gtk)$" } })
|
||||||
|
-- hl.window_rule({ float = true, match = { class = "^([Ww]hatsapp-for-linux|ZapZap|com.rtosta.zapzap)$" } })
|
||||||
|
-- hl.window_rule({ float = true, match = { title = "^(Firefox)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-82", float = true, match = { class = "^(fdm|freedownloadmanager)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-83", float = true, match = { class = "^(proton-authenticator)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-84", float = true, match = { class = "^([Ww]indscribe)$" } })
|
||||||
|
|
||||||
|
-- windowrule - ######### float popups and dialogue #######
|
||||||
|
hl.window_rule({ name = "windowrule-85", float = true, center = true, match = { title = "^(Authentication Required)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-86", float = true, match = { class = "(codium|codium-url-handler|VSCodium)", title = "negative:(.*codium.*|.*VSCodium.*)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-87", float = true, match = { class = "^(com.heroicgameslauncher.hgl)$", title = "negative:(Heroic Games Launcher)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-88", float = true, match = { class = "^([Ss]team)$", title = "negative:^([Ss]team)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-89", float = true, size = "monitor_w*0.7 monitor_h*0.6", center = true, match = { title = "^(Add Folder to Workspace)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-90", float = true, size = "monitor_w*0.7 monitor_h*0.6", center = true, match = { title = "^(Save As)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-91", float = true, size = "monitor_w*0.7 monitor_h*0.6", match = { initial_title = "(Open Files)" } })
|
||||||
|
hl.window_rule({ name = "windowrule-92", float = true, center = true, size = "monitor_w*0.16 monitor_h*0.12", match = { title = "^(SDDM Background)$" } }) -- HyprFlux YAD for setting SDDM background
|
||||||
|
-- END of float popups and dialogue #######
|
||||||
|
|
||||||
|
-- OPACITY
|
||||||
|
-- hl.window_rule({ opacity = "0.9 0.7", match = { tag = "browser*" } })
|
||||||
|
-- hl.window_rule({ opacity = "0.9 0.8", match = { tag = "projects*" } })
|
||||||
|
-- hl.window_rule({ opacity = "0.94 0.86", match = { tag = "im*" } })
|
||||||
|
-- hl.window_rule({ opacity = "0.94 0.86", match = { tag = "multimedia*" } })
|
||||||
|
-- hl.window_rule({ opacity = "0.9 0.8", match = { tag = "file-manager*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-93", opacity = "0.8 0.7", match = { tag = "terminal*" } })
|
||||||
|
-- hl.window_rule({ opacity = "0.82 0.75", match = { tag = "viewer*" } })
|
||||||
|
hl.window_rule({ name = "windowrule-94", opacity = "0.8 0.7", match = { class = "^(gedit|org.gnome.TextEditor|mousepad)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-95", opacity = "0.9 0.8", match = { class = "^(deluge)$" } })
|
||||||
|
hl.window_rule({ name = "windowrule-96", opacity = "0.9 0.8", match = { class = "^(seahorse)$" } }) -- gnome-keyring gui
|
||||||
|
-- hl.window_rule({ opacity = "0.95 0.75", match = { title = "^(Picture-in-Picture)$" } })
|
||||||
|
|
||||||
|
-- SIZE
|
||||||
|
-- hl.window_rule({ size = "25% 25%", match = { title = "^(Firefox)$" } })
|
||||||
|
|
||||||
|
-- PINNING
|
||||||
|
-- hl.window_rule({ pin = true, match = { title = "^(Firefox)$" } })
|
||||||
|
|
||||||
|
-- windowrule - extras
|
||||||
|
|
||||||
|
-- BLUR & FULLSCREEN
|
||||||
|
-- hl.window_rule({ active_border_color = "rgb(EE4B55)", inactive_border_color = "rgb(880808)", match = { fullscreen = true } })
|
||||||
|
-- hl.window_rule({ active_border_color = "rgb(282737)", inactive_border_color = "rgb(1E1D2D)", match = { float = true } })
|
||||||
|
-- hl.window_rule({ opacity = "0.8 0.8", match = { pin = true } })
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
-- LAYER RULES
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
hl.layer_rule({ name = "layerrule-1", blur = true, ignore_alpha = 0, match = { namespace = "rofi" } })
|
||||||
|
hl.layer_rule({ name = "layerrule-2", blur = true, ignore_alpha = 0, match = { namespace = "notifications" } })
|
||||||
|
hl.layer_rule({ name = "layerrule-3", blur = true, ignore_alpha = 0.5, match = { namespace = "quickshell:overview" } })
|
||||||
|
|
||||||
|
-- hl.layer_rule({ ignore_alpha = 0.5, match = { tag = "notif*" } })
|
||||||
|
-- hl.layer_rule({ no_anim = true (unset), match = { class = "^([Rr]ofi)$" } })
|
||||||
|
-- hl.layer_rule({ blur = true, match = { class = "^([Rr]ofi)$" } })
|
||||||
|
-- hl.layer_rule({ ignore_alpha = 0, match = { class = "<rofi>" } })
|
||||||
|
-- hl.layer_rule({ ignore_alpha = 0, match = { namespace = "overview" } })
|
||||||
|
-- hl.layer_rule({ blur = true, match = { namespace = "overview" } })
|
||||||
29
dotfiles/.config/hypr/layout/workspaces.lua
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- NOTE: This will be overwritten by NWG-Displays
|
||||||
|
-- once you use it and click apply.
|
||||||
|
-- (nwg-displays already supports writing this file directly as workspaces.lua once
|
||||||
|
-- hyprland.lua is active, so re-running it should stay compatible.)
|
||||||
|
--
|
||||||
|
-- Ported from UserConfigs/workspaces.conf
|
||||||
|
-- You can set workspace rules to achieve workspace-specific behaviors.
|
||||||
|
-- For instance, you can define a workspace where all windows are drawn without borders or gaps.
|
||||||
|
-- https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/
|
||||||
|
|
||||||
|
-- Assigning workspace to a certain monitor. Below are just examples
|
||||||
|
hl.workspace_rule({ workspace = 1, monitor = "DP-2", default = true })
|
||||||
|
hl.workspace_rule({ workspace = 2, monitor = "DP-1", default = true })
|
||||||
|
hl.workspace_rule({ workspace = 3, monitor = "HDMI-A-1", default = true })
|
||||||
|
-- hl.workspace_rule({ workspace = 4, monitor = "eDP-1" })
|
||||||
|
-- hl.workspace_rule({ workspace = 5, monitor = "DP-2" })
|
||||||
|
-- hl.workspace_rule({ workspace = 6, monitor = "DP-2" })
|
||||||
|
-- hl.workspace_rule({ workspace = 7, monitor = "DP-2" })
|
||||||
|
-- hl.workspace_rule({ workspace = 8, monitor = "DP-2" })
|
||||||
|
|
||||||
|
-- example rules (from wiki)
|
||||||
|
-- hl.workspace_rule({ workspace = 3, rounding = false, decorate = false })
|
||||||
|
-- hl.workspace_rule({ workspace = "name:coding", rounding = false, decorate = false, gaps_in = 0, gaps_out = 0, border = false, monitor = "DP-1" })
|
||||||
|
-- hl.workspace_rule({ workspace = 8, border_size = 8 })
|
||||||
|
-- hl.workspace_rule({ workspace = "name:Hello", monitor = "DP-1", default = true })
|
||||||
|
-- hl.workspace_rule({ workspace = "name:gaming", monitor = "desc:Chimei Innolux Corporation 0x150C", default = true })
|
||||||
|
-- hl.workspace_rule({ workspace = 5, on_created_empty = "[float] firefox" })
|
||||||
|
-- hl.workspace_rule({ workspace = "special:scratchpad", on_created_empty = "foot" })
|
||||||
22
dotfiles/.config/hypr/presets/anim-00-default.lua
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Ported from animations/00-default.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "smoothOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 100, bezier = "liner", style = "loop" }) -- used by rainbow borders and rotating colors; speed clamped from 180 -> Lua hl.animation caps speed at 100
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 3, bezier = "smoothOut" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "overshot" })
|
||||||
|
|
||||||
|
-- animations for -git or version >0.42.0
|
||||||
|
hl.animation({ leaf = "workspacesIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "workspacesOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
25
dotfiles/.config/hypr/presets/anim-01-default-v2.lua
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- old animations
|
||||||
|
-- Ported from animations/01-default - v2.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("myBezier", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("linear", { type = "bezier", points = { { 0.0, 0.0 }, { 1.0, 1.0 } } })
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("slow", { type = "bezier", points = { { 0, 0.85 }, { 0.3, 1 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.7, 0.6 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("bounce", { type = "bezier", points = { { 1.1, 1.6 }, { 0.1, 0.85 } } })
|
||||||
|
hl.curve("sligshot", { type = "bezier", points = { { 1, -1 }, { 0.15, 1.25 } } })
|
||||||
|
hl.curve("nice", { type = "bezier", points = { { 0, 6.9 }, { 0.5, -4.20 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 5, bezier = "slow", style = "popin" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "popin" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "linear" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 100, bezier = "linear", style = "loop" }) -- used by rainbow borders and rotating colors; speed clamped from 180 -> Lua hl.animation caps speed at 100
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 5, bezier = "overshot" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 5, bezier = "bounce", style = "popin" })
|
||||||
4
dotfiles/.config/hypr/presets/anim-03-disable.lua
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- Ported from animations/03- Disable Animation.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = false } })
|
||||||
39
dotfiles/.config/hypr/presets/anim-end-4.lua
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "End-4"
|
||||||
|
-- credit https://github.com/end-4/dots-hyprland
|
||||||
|
-- Ported from animations/END-4.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
-- Animation curves
|
||||||
|
hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } })
|
||||||
|
hl.curve("md3_standard", { type = "bezier", points = { { 0.2, 0 }, { 0, 1 } } })
|
||||||
|
hl.curve("md3_decel", { type = "bezier", points = { { 0.05, 0.7 }, { 0.1, 1 } } })
|
||||||
|
hl.curve("md3_accel", { type = "bezier", points = { { 0.3, 0 }, { 0.8, 0.15 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("crazyshot", { type = "bezier", points = { { 0.1, 1.5 }, { 0.76, 0.92 } } })
|
||||||
|
hl.curve("hyprnostretch", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.0 } } })
|
||||||
|
hl.curve("menu_decel", { type = "bezier", points = { { 0.1, 1 }, { 0, 1 } } })
|
||||||
|
hl.curve("menu_accel", { type = "bezier", points = { { 0.38, 0.04 }, { 1, 0.07 } } })
|
||||||
|
hl.curve("easeInOutCirc", { type = "bezier", points = { { 0.85, 0 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("easeOutCirc", { type = "bezier", points = { { 0, 0.55 }, { 0.45, 1 } } })
|
||||||
|
hl.curve("easeOutExpo", { type = "bezier", points = { { 0.16, 1 }, { 0.3, 1 } } })
|
||||||
|
hl.curve("softAcDecel", { type = "bezier", points = { { 0.26, 0.26 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("md2", { type = "bezier", points = { { 0.4, 0 }, { 0.2, 1 } } }) -- use with .2s duration
|
||||||
|
|
||||||
|
-- Animation configs
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 3, bezier = "md3_decel", style = "popin 60%" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 3, bezier = "md3_decel", style = "popin 60%" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "md3_accel", style = "popin 60%" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 3, bezier = "md3_decel" })
|
||||||
|
-- hl.animation({ leaf = "layers", enabled = true, speed = 2, bezier = "md3_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "layersIn", enabled = true, speed = 3, bezier = "menu_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "layersOut", enabled = true, speed = 1.6, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 2, bezier = "menu_decel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 4.5, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 7, bezier = "menu_decel", style = "slide" })
|
||||||
|
-- hl.animation({ leaf = "workspaces", enabled = true, speed = 2.5, bezier = "softAcDecel", style = "slide" })
|
||||||
|
-- hl.animation({ leaf = "workspaces", enabled = true, speed = 7, bezier = "menu_decel", style = "slidefade 15%" })
|
||||||
|
-- hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 3, bezier = "md3_decel", style = "slidefadevert 15%" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 3, bezier = "md3_decel", style = "slidevert" })
|
||||||
21
dotfiles/.config/hypr/presets/anim-hyde-default.lua
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Default"
|
||||||
|
-- credit https://github.com/prasanthrangan/hyprdots
|
||||||
|
-- Ported from animations/HYDE - default.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 6, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 30, bezier = "liner", style = "once" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 5, bezier = "wind", style = "slidevert" })
|
||||||
20
dotfiles/.config/hypr/presets/anim-hyde-minimal-1.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Minimal-1"
|
||||||
|
-- credit https://github.com/prasanthrangan/hyprdots
|
||||||
|
-- Ported from animations/HYDE - minimal-1.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 6, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 30, bezier = "liner", style = "once" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
14
dotfiles/.config/hypr/presets/anim-hyde-minimal-2.lua
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Minimal-2"
|
||||||
|
-- credit https://github.com/prasanthrangan/hyprdots
|
||||||
|
-- Ported from animations/HYDE - minimal-2.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("quart", { type = "bezier", points = { { 0.25, 1 }, { 0.5, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "quart", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 6, bezier = "quart" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 6, bezier = "quart" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 6, bezier = "quart" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 6, bezier = "quart" })
|
||||||
40
dotfiles/.config/hypr/presets/anim-hyde-optimized.lua
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Optimized"
|
||||||
|
-- credit https://github.com/prasanthrangan/hyprdots
|
||||||
|
-- Ported from animations/HYDE - optimized.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.85 }, { 0.03, 0.97 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.07, 0.88 }, { 0.04, 0.99 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.20, -0.15 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
hl.curve("md3_standard", { type = "bezier", points = { { 0.12, 0 }, { 0, 1 } } })
|
||||||
|
hl.curve("md3_decel", { type = "bezier", points = { { 0.05, 0.80 }, { 0.10, 0.97 } } })
|
||||||
|
hl.curve("md3_accel", { type = "bezier", points = { { 0.20, 0 }, { 0.80, 0.08 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.85 }, { 0.07, 1.04 } } })
|
||||||
|
hl.curve("crazyshot", { type = "bezier", points = { { 0.1, 1.22 }, { 0.68, 0.98 } } })
|
||||||
|
hl.curve("hyprnostretch", { type = "bezier", points = { { 0.05, 0.82 }, { 0.03, 0.94 } } })
|
||||||
|
hl.curve("menu_decel", { type = "bezier", points = { { 0.05, 0.82 }, { 0, 1 } } })
|
||||||
|
hl.curve("menu_accel", { type = "bezier", points = { { 0.20, 0 }, { 0.82, 0.10 } } })
|
||||||
|
hl.curve("easeInOutCirc", { type = "bezier", points = { { 0.75, 0 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("easeOutCirc", { type = "bezier", points = { { 0, 0.48 }, { 0.38, 1 } } })
|
||||||
|
hl.curve("easeOutExpo", { type = "bezier", points = { { 0.10, 0.94 }, { 0.23, 0.98 } } })
|
||||||
|
hl.curve("softAcDecel", { type = "bezier", points = { { 0.20, 0.20 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("md2", { type = "bezier", points = { { 0.30, 0 }, { 0.15, 1 } } })
|
||||||
|
|
||||||
|
hl.curve("OutBack", { type = "bezier", points = { { 0.28, 1.40 }, { 0.58, 1 } } })
|
||||||
|
hl.curve("easeInOutCirc", { type = "bezier", points = { { 0.78, 0 }, { 0.15, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1.6, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 82, bezier = "liner", style = "once" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 3.2, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 2.8, bezier = "easeOutCirc" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 3.0, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 1.8, bezier = "md3_decel" })
|
||||||
|
hl.animation({ leaf = "layersIn", enabled = true, speed = 1.8, bezier = "menu_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "layersOut", enabled = true, speed = 1.5, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 1.6, bezier = "menu_decel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.8, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 4.0, bezier = "menu_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 2.3, bezier = "md3_decel", style = "slidefadevert 15%" })
|
||||||
32
dotfiles/.config/hypr/presets/anim-hyde-vertical.lua
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Vertical"
|
||||||
|
-- credit https://github.com/prasanthrangan/hyprdots
|
||||||
|
-- Ported from animations/HYDE - Vertical.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("fluent_decel", { type = "bezier", points = { { 0, 0.2 }, { 0.4, 1 } } })
|
||||||
|
hl.curve("easeOutCirc", { type = "bezier", points = { { 0, 0.55 }, { 0.45, 1 } } })
|
||||||
|
hl.curve("easeOutCubic", { type = "bezier", points = { { 0.33, 1 }, { 0.68, 1 } } })
|
||||||
|
hl.curve("easeinoutsine", { type = "bezier", points = { { 0.37, 0 }, { 0.63, 1 } } })
|
||||||
|
|
||||||
|
-- Windows
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 1.5, bezier = "easeinoutsine", style = "popin 60%" }) -- window open
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.5, bezier = "easeOutCubic", style = "popin 60%" }) -- window close.
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 1.5, bezier = "easeinoutsine", style = "slide" }) -- everything in between, moving, dragging, resizing.
|
||||||
|
|
||||||
|
-- Fading
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 2.5, bezier = "fluent_decel" })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "fadeLayersIn", enabled = false })
|
||||||
|
hl.animation({ leaf = "border", enabled = false })
|
||||||
|
|
||||||
|
-- Layers
|
||||||
|
hl.animation({ leaf = "layers", enabled = true, speed = 1.5, bezier = "easeinoutsine", style = "popin" })
|
||||||
|
|
||||||
|
-- Workspaces
|
||||||
|
-- styles: slide, slidevert, fade, slidefade, slidefadevert
|
||||||
|
-- hl.animation({ leaf = "workspaces", enabled = true, speed = 3, bezier = "fluent_decel", style = "slidefade 30%" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 3, bezier = "fluent_decel", style = "slidefadevert 30%" })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 2, bezier = "fluent_decel", style = "slidefade 10%" })
|
||||||
52
dotfiles/.config/hypr/presets/anim-mahaveer-1.lua
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Me-1"
|
||||||
|
-- credit https://github.com/mahaveergurjar
|
||||||
|
-- Ported from animations/Mahaveer - me-1.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
-- Animation curves
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
-- hl.curve("linear", { type = "bezier", points = { {0,0}, {1,1} } })
|
||||||
|
hl.curve("md3_standard", { type = "bezier", points = { { 0.2, 0 }, { 0, 1 } } })
|
||||||
|
hl.curve("md3_decel", { type = "bezier", points = { { 0.05, 0.7 }, { 0.1, 1 } } })
|
||||||
|
hl.curve("md3_accel", { type = "bezier", points = { { 0.3, 0 }, { 0.8, 0.15 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("crazyshot", { type = "bezier", points = { { 0.1, 1.5 }, { 0.76, 0.92 } } })
|
||||||
|
hl.curve("hyprnostretch", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.0 } } })
|
||||||
|
hl.curve("menu_decel", { type = "bezier", points = { { 0.1, 1 }, { 0, 1 } } })
|
||||||
|
hl.curve("menu_accel", { type = "bezier", points = { { 0.38, 0.04 }, { 1, 0.07 } } })
|
||||||
|
hl.curve("easeInOutCirc", { type = "bezier", points = { { 0.85, 0 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("easeOutCirc", { type = "bezier", points = { { 0, 0.55 }, { 0.45, 1 } } })
|
||||||
|
hl.curve("easeOutExpo", { type = "bezier", points = { { 0.16, 1 }, { 0.3, 1 } } })
|
||||||
|
hl.curve("softAcDecel", { type = "bezier", points = { { 0.26, 0.26 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("md2", { type = "bezier", points = { { 0.4, 0 }, { 0.2, 1 } } }) -- use with .2s duration
|
||||||
|
|
||||||
|
-- Animation configs
|
||||||
|
-- hl.animation({ leaf = "windows", enabled = true, speed = 3, bezier = "md3_decel", style = "popin 60%" })
|
||||||
|
-- hl.animation({ leaf = "windowsIn", enabled = true, speed = 3, bezier = "md3_decel", style = "popin 60%" })
|
||||||
|
-- hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "md3_accel", style = "popin 60%" })
|
||||||
|
-- hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 30, bezier = "liner", style = "once" })
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 6, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
|
||||||
|
-- hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 3, bezier = "md3_decel" })
|
||||||
|
-- hl.animation({ leaf = "layers", enabled = true, speed = 2, bezier = "md3_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "layersIn", enabled = true, speed = 3, bezier = "menu_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "layersOut", enabled = true, speed = 1.6, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 2, bezier = "menu_decel" })
|
||||||
|
hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 4.5, bezier = "menu_accel" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 7, bezier = "menu_decel", style = "slide" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
|
-- hl.animation({ leaf = "workspaces", enabled = true, speed = 2.5, bezier = "softAcDecel", style = "slide" })
|
||||||
|
-- hl.animation({ leaf = "workspaces", enabled = true, speed = 7, bezier = "menu_decel", style = "slidefade 15%" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 3, bezier = "md3_decel", style = "slidefadevert 15%" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 3, bezier = "md3_decel", style = "slidevert" })
|
||||||
27
dotfiles/.config/hypr/presets/anim-mahaveer-2.lua
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Me-2"
|
||||||
|
-- credit https://github.com/mahaveergurjar
|
||||||
|
-- Ported from animations/Mahaveer - me-2.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("smoothOut", { type = "bezier", points = { { 0.5, 0 }, { 0.99, 0.99 } } })
|
||||||
|
hl.curve("smoothIn", { type = "bezier", points = { { 0.5, -0.5 }, { 0.68, 1.5 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "smoothOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 100, bezier = "liner", style = "loop" }) -- used by rainbow borders and rotating colors; speed clamped from 180 -> Lua hl.animation caps speed at 100
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 3, bezier = "smoothOut" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "overshot" })
|
||||||
|
|
||||||
|
-- animations for -git or version >0.42.0
|
||||||
|
hl.animation({ leaf = "workspacesIn", enabled = true, speed = 5, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "workspacesOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
15
dotfiles/.config/hypr/presets/anim-ml4w-classic.lua
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Classic"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - classic.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("myBezier", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 7, bezier = "myBezier" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 7, bezier = "default", style = "popin 80%" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 8, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 7, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 6, bezier = "default" })
|
||||||
20
dotfiles/.config/hypr/presets/anim-ml4w-dynamic.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Dynamic"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - dynamic.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 6, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 30, bezier = "liner", style = "loop" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
24
dotfiles/.config/hypr/presets/anim-ml4w-fast.lua
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Fast"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - fast.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } })
|
||||||
|
hl.curve("md3_standard", { type = "bezier", points = { { 0.2, 0 }, { 0, 1 } } })
|
||||||
|
hl.curve("md3_decel", { type = "bezier", points = { { 0.05, 0.7 }, { 0.1, 1 } } })
|
||||||
|
hl.curve("md3_accel", { type = "bezier", points = { { 0.3, 0 }, { 0.8, 0.15 } } })
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("crazyshot", { type = "bezier", points = { { 0.1, 1.5 }, { 0.76, 0.92 } } })
|
||||||
|
hl.curve("hyprnostretch", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.0 } } })
|
||||||
|
hl.curve("fluent_decel", { type = "bezier", points = { { 0.1, 1 }, { 0, 1 } } })
|
||||||
|
hl.curve("easeInOutCirc", { type = "bezier", points = { { 0.85, 0 }, { 0.15, 1 } } })
|
||||||
|
hl.curve("easeOutCirc", { type = "bezier", points = { { 0, 0.55 }, { 0.45, 1 } } })
|
||||||
|
hl.curve("easeOutExpo", { type = "bezier", points = { { 0.16, 1 }, { 0.3, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 3, bezier = "md3_decel", style = "popin 60%" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 2.5, bezier = "md3_decel" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 3.5, bezier = "easeOutExpo", style = "slide" })
|
||||||
|
hl.animation({ leaf = "specialWorkspace", enabled = true, speed = 3, bezier = "md3_decel", style = "slidevert" })
|
||||||
20
dotfiles/.config/hypr/presets/anim-ml4w-high.lua
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "High"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - high.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("wind", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("winIn", { type = "bezier", points = { { 0.1, 1.1 }, { 0.1, 1.1 } } })
|
||||||
|
hl.curve("winOut", { type = "bezier", points = { { 0.3, -0.3 }, { 0, 1 } } })
|
||||||
|
hl.curve("liner", { type = "bezier", points = { { 1, 1 }, { 1, 1 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 6, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 6, bezier = "winIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 5, bezier = "winOut", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "liner" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 30, bezier = "liner", style = "once" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
||||||
19
dotfiles/.config/hypr/presets/anim-ml4w-moving.lua
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Moving"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - moving.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("overshot", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
hl.curve("smoothOut", { type = "bezier", points = { { 0.5, 0 }, { 0.99, 0.99 } } })
|
||||||
|
hl.curve("smoothIn", { type = "bezier", points = { { 0.5, -0.5 }, { 0.68, 1.5 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 5, bezier = "overshot", style = "slide" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 3, bezier = "smoothOut" })
|
||||||
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 3, bezier = "smoothOut" })
|
||||||
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 4, bezier = "smoothIn", style = "slide" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 5, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 5, bezier = "smoothIn" })
|
||||||
|
hl.animation({ leaf = "fadeDim", enabled = true, speed = 5, bezier = "smoothIn" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 6, bezier = "default" })
|
||||||
15
dotfiles/.config/hypr/presets/anim-ml4w-standard.lua
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- HyprFlux — https://github.com/ahmad9059/HyprFlux
|
||||||
|
-- name "Standard"
|
||||||
|
-- credit https://github.com/mylinuxforwork/dotfiles
|
||||||
|
-- Ported from animations/ML4W - standard.conf (unused preset — not required by anything)
|
||||||
|
|
||||||
|
hl.config({ animations = { enabled = true } })
|
||||||
|
|
||||||
|
hl.curve("myBezier", { type = "bezier", points = { { 0.05, 0.9 }, { 0.1, 1.05 } } })
|
||||||
|
|
||||||
|
hl.animation({ leaf = "windows", enabled = true, speed = 7, bezier = "myBezier" })
|
||||||
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 7, bezier = "default", style = "popin 80%" })
|
||||||
|
hl.animation({ leaf = "border", enabled = true, speed = 10, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "borderangle", enabled = true, speed = 8, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "fade", enabled = true, speed = 7, bezier = "default" })
|
||||||
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 6, bezier = "default" })
|
||||||
73
dotfiles/.config/hypr/scripts/FloatBitwardenPopup.sh
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Float + resize (to 781x702) + center the Bitwarden browser-extension pop-out window.
|
||||||
|
#
|
||||||
|
# Why this exists instead of a window rule: Hyprland's `float`/`center`/`size`
|
||||||
|
# rules are "static" — evaluated exactly once, at the instant a window is
|
||||||
|
# created — and this popup opens with the generic title "Zen Browser" (same
|
||||||
|
# initialTitle/initialClass as the main browser window), only updating to
|
||||||
|
# "Extension: (Bitwarden Password Manager) - Bitwarden..." a moment after
|
||||||
|
# it's already mapped. By then the static rule has already missed its one
|
||||||
|
# chance and there's no field available at creation time to tell the popup
|
||||||
|
# apart from a normal browser window. See layout/windowrules.lua and
|
||||||
|
# https://github.com/hyprwm/Hyprland/issues/7402 for the same problem class.
|
||||||
|
#
|
||||||
|
# No socat/ncat is installed, so instead of an event-driven IPC listener this
|
||||||
|
# just polls `hyprctl clients` at a short interval with jq (already
|
||||||
|
# installed).
|
||||||
|
#
|
||||||
|
# Dispatch syntax note: Hyprland 0.55+'s Lua config changed `hyprctl dispatch`
|
||||||
|
# to take a literal Lua expression calling hl.dsp.* (e.g.
|
||||||
|
# `hyprctl dispatch 'hl.dsp.window.center()'`), not the old
|
||||||
|
# "centerwindow"-style dispatcher strings. Verified live against the real
|
||||||
|
# API in /usr/share/hypr/stubs/hl.meta.lua before wiring this in.
|
||||||
|
#
|
||||||
|
# Why it re-asserts for a few seconds instead of firing once: right after the
|
||||||
|
# popup leaves the tiled layout, Hyprland briefly re-tiles the sibling window
|
||||||
|
# to fill the freed space, and during that reflow this popup was observed
|
||||||
|
# reporting `floating: false` again for one poll tick — snapping it back to
|
||||||
|
# its old tiled geometry. Re-asserting float+center for a short settle window
|
||||||
|
# after first detection rides that out. After the settle window it's left
|
||||||
|
# alone, so a manual re-tile/move by you later isn't fought.
|
||||||
|
|
||||||
|
TITLE_PATTERN='Extension: \(Bitwarden Password Manager\)'
|
||||||
|
POLL_INTERVAL=0.3
|
||||||
|
SETTLE_TICKS=6 # ~2s of re-assertion after first detection, at POLL_INTERVAL
|
||||||
|
TARGET_WIDTH=781
|
||||||
|
TARGET_HEIGHT=702
|
||||||
|
|
||||||
|
declare -A ticks_left # address -> remaining re-assert ticks
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
sleep "$POLL_INTERVAL"
|
||||||
|
|
||||||
|
# Forget any tracked window that's no longer open.
|
||||||
|
open_addresses=$(hyprctl clients -j | jq -r '.[].address')
|
||||||
|
for addr in "${!ticks_left[@]}"; do
|
||||||
|
grep -qF "$addr" <<<"$open_addresses" || unset 'ticks_left[$addr]'
|
||||||
|
done
|
||||||
|
|
||||||
|
# Process substitution (not a pipe) so the while loop runs in this shell
|
||||||
|
# and its writes to ticks_left actually persist across iterations.
|
||||||
|
while IFS= read -r win; do
|
||||||
|
title=$(jq -r '.title' <<<"$win")
|
||||||
|
[[ "$title" =~ $TITLE_PATTERN ]] || continue
|
||||||
|
|
||||||
|
address=$(jq -r '.address' <<<"$win")
|
||||||
|
floating=$(jq -r '.floating' <<<"$win")
|
||||||
|
|
||||||
|
# First time we've seen this window: start its settle window.
|
||||||
|
[[ -v ticks_left[$address] ]] || ticks_left[$address]=$SETTLE_TICKS
|
||||||
|
|
||||||
|
# Already floating and past its settle window: leave it alone.
|
||||||
|
[[ "$floating" == "true" && ${ticks_left[$address]} -le 0 ]] && continue
|
||||||
|
|
||||||
|
hyprctl dispatch "hl.dsp.focus({ window = \"address:$address\" })" >/dev/null
|
||||||
|
hyprctl dispatch 'hl.dsp.window.float({ action = "enable" })' >/dev/null
|
||||||
|
# resize({x=W,y=H}) sets the absolute size (not a delta) — verified live.
|
||||||
|
# Must happen before center(), since resizing shifts what "centered" means.
|
||||||
|
hyprctl dispatch "hl.dsp.window.resize({ x = $TARGET_WIDTH, y = $TARGET_HEIGHT })" >/dev/null
|
||||||
|
hyprctl dispatch 'hl.dsp.window.center()' >/dev/null
|
||||||
|
|
||||||
|
ticks_left[$address]=$((ticks_left[$address] - 1))
|
||||||
|
done < <(hyprctl clients -j | jq -c '.[] | {address, title, floating}')
|
||||||
|
done
|
||||||
93
dotfiles/.config/ohmyposh/zen.toml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#:schema https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json
|
||||||
|
|
||||||
|
version = 2
|
||||||
|
final_space = true
|
||||||
|
console_title_template = '{{ .Shell }} in {{ .Folder }}'
|
||||||
|
|
||||||
|
[[blocks]]
|
||||||
|
type = 'prompt'
|
||||||
|
alignment = 'left'
|
||||||
|
newline = true
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = 'path'
|
||||||
|
style = 'plain'
|
||||||
|
background = 'transparent'
|
||||||
|
foreground = 'blue'
|
||||||
|
template = '{{ .Path }}'
|
||||||
|
|
||||||
|
[blocks.segments.properties]
|
||||||
|
style = 'full'
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = 'git'
|
||||||
|
style = 'plain'
|
||||||
|
foreground = 'p:grey'
|
||||||
|
background = 'transparent'
|
||||||
|
template = ' {{ .HEAD }}{{ if or (.Working.Changed) (.Staging.Changed) }}*{{ end }} <cyan>{{ if gt .Behind 0 }}⇣{{ end }}{{ if gt .Ahead 0 }}⇡{{ end }}</>'
|
||||||
|
|
||||||
|
[blocks.segments.properties]
|
||||||
|
branch_icon = ''
|
||||||
|
commit_icon = '@'
|
||||||
|
fetch_status = true
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = "pnpm"
|
||||||
|
style = "powerline"
|
||||||
|
powerline_symbol = "❯"
|
||||||
|
foreground = "blue"
|
||||||
|
background = "transparent"
|
||||||
|
template = " {{ .Full }} "
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = 'docker'
|
||||||
|
style = 'powerline'
|
||||||
|
foreground = 'blue'
|
||||||
|
background = 'transparent'
|
||||||
|
template = ' {{ .Context }} '
|
||||||
|
|
||||||
|
[blocks.segments.options]
|
||||||
|
display_mode = 'files'
|
||||||
|
|
||||||
|
[[blocks]]
|
||||||
|
type = 'rprompt'
|
||||||
|
overflow = 'hidden'
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = 'executiontime'
|
||||||
|
style = 'plain'
|
||||||
|
foreground = 'yellow'
|
||||||
|
background = 'transparent'
|
||||||
|
template = '{{ .FormattedMs }}'
|
||||||
|
|
||||||
|
[blocks.segments.properties]
|
||||||
|
threshold = 5000
|
||||||
|
|
||||||
|
[[blocks]]
|
||||||
|
type = 'prompt'
|
||||||
|
alignment = 'left'
|
||||||
|
newline = true
|
||||||
|
|
||||||
|
[[blocks.segments]]
|
||||||
|
type = 'text'
|
||||||
|
style = 'plain'
|
||||||
|
foreground_templates = [
|
||||||
|
"{{if gt .Code 0}}red{{end}}",
|
||||||
|
"{{if eq .Code 0}}magenta{{end}}",
|
||||||
|
]
|
||||||
|
background = 'transparent'
|
||||||
|
template = '❯'
|
||||||
|
|
||||||
|
|
||||||
|
[transient_prompt]
|
||||||
|
foreground_templates = [
|
||||||
|
"{{if gt .Code 0}}red{{end}}",
|
||||||
|
"{{if eq .Code 0}}magenta{{end}}",
|
||||||
|
]
|
||||||
|
background = 'transparent'
|
||||||
|
template = '❯ '
|
||||||
|
|
||||||
|
[secondary_prompt]
|
||||||
|
foreground = 'magenta'
|
||||||
|
background = 'transparent'
|
||||||
|
template = '❯❯ '
|
||||||
4
dotfiles/.config/qt5ct/colors/Catppuccin-Latte.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[ColorScheme]
|
||||||
|
active_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff1e66f5, #ffeff1f5, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
|
disabled_colors=#ff6c6f85, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff6c6f85, #ff6c6f85, #ff6c6f85, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff9ca0b0, #ff5c5f77, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
|
inactive_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ffccd0da, #ff6c6f85, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
4
dotfiles/.config/qt5ct/colors/Catppuccin-Mocha.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[ColorScheme]
|
||||||
|
active_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ff1e1e2e, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
|
disabled_colors=#ffa6adc8, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffa6adc8, #ffa6adc8, #ffa6adc8, #ff1e1e2e, #ff11111b, #ff7f849c, #ff89b4fa, #ff45475a, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
|
inactive_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ffa6adc8, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
32
dotfiles/.config/qt5ct/qt5ct.conf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[Appearance]
|
||||||
|
color_scheme_path=
|
||||||
|
custom_palette=true
|
||||||
|
icon_theme=Papirus-Dark
|
||||||
|
standard_dialogs=default
|
||||||
|
style=Fusion
|
||||||
|
|
||||||
|
[Fonts]
|
||||||
|
fixed="Adwaita Sans,10,-1,5,50,0,0,0,0,0,Regular"
|
||||||
|
general="Adwaita Sans,12,-1,5,50,0,0,0,0,0,Regular"
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
activate_item_on_single_click=1
|
||||||
|
buttonbox_layout=0
|
||||||
|
cursor_flash_time=1000
|
||||||
|
dialog_buttons_have_icons=1
|
||||||
|
double_click_interval=400
|
||||||
|
gui_effects=General, AnimateMenu, AnimateCombo, AnimateTooltip, AnimateToolBox
|
||||||
|
keyboard_scheme=2
|
||||||
|
menus_have_icons=true
|
||||||
|
show_shortcuts_in_context_menus=true
|
||||||
|
stylesheets=@Invalid()
|
||||||
|
toolbutton_style=4
|
||||||
|
underline_shortcut=1
|
||||||
|
wheel_scroll_lines=3
|
||||||
|
|
||||||
|
[SettingsWindow]
|
||||||
|
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3\0\0\0\0\x2\0\0\0\a\x80\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3)
|
||||||
|
|
||||||
|
[Troubleshooting]
|
||||||
|
force_raster_widgets=1
|
||||||
|
ignored_applications=@Invalid()
|
||||||
4
dotfiles/.config/qt6ct/colors/Catppuccin-Latte.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[ColorScheme]
|
||||||
|
active_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff1e66f5, #ffeff1f5, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
|
disabled_colors=#ff6c6f85, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff6c6f85, #ff6c6f85, #ff6c6f85, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff9ca0b0, #ff5c5f77, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
|
inactive_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ffccd0da, #ff6c6f85, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1
|
||||||
4
dotfiles/.config/qt6ct/colors/Catppuccin-Mocha.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[ColorScheme]
|
||||||
|
active_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ff1e1e2e, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
|
disabled_colors=#ffa6adc8, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffa6adc8, #ffa6adc8, #ffa6adc8, #ff1e1e2e, #ff11111b, #ff7f849c, #ff89b4fa, #ff45475a, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
|
inactive_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ffa6adc8, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c
|
||||||
32
dotfiles/.config/qt6ct/qt6ct.conf
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[Appearance]
|
||||||
|
color_scheme_path=
|
||||||
|
custom_palette=true
|
||||||
|
icon_theme=Papirus-Dark
|
||||||
|
standard_dialogs=default
|
||||||
|
style=Fusion
|
||||||
|
|
||||||
|
[Fonts]
|
||||||
|
fixed="Adwaita Sans,10,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular"
|
||||||
|
general="Adwaita Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular"
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
activate_item_on_single_click=1
|
||||||
|
buttonbox_layout=0
|
||||||
|
cursor_flash_time=1000
|
||||||
|
dialog_buttons_have_icons=1
|
||||||
|
double_click_interval=400
|
||||||
|
gui_effects=General, AnimateMenu, AnimateCombo, AnimateTooltip, AnimateToolBox
|
||||||
|
keyboard_scheme=2
|
||||||
|
menus_have_icons=true
|
||||||
|
show_shortcuts_in_context_menus=true
|
||||||
|
stylesheets=@Invalid()
|
||||||
|
toolbutton_style=4
|
||||||
|
underline_shortcut=1
|
||||||
|
wheel_scroll_lines=3
|
||||||
|
|
||||||
|
[SettingsWindow]
|
||||||
|
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3\0\0\0\0\x2\0\0\0\a\x80\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x2\xf3)
|
||||||
|
|
||||||
|
[Troubleshooting]
|
||||||
|
force_raster_widgets=1
|
||||||
|
ignored_applications=@Invalid()
|
||||||
29
dotfiles/.config/quickshell/config/Appearance.qml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
readonly property string fontFamily: "CaskaydiaCove Nerd Font Mono"
|
||||||
|
readonly property string iconFontFamily: "Material Symbols Outlined"
|
||||||
|
// Same glyph set, softer/rounded terminals — used where a module wants
|
||||||
|
// a visually distinct icon style from the rest of the bar (currently
|
||||||
|
// just BluetoothIndicator.qml) without switching every icon over.
|
||||||
|
readonly property string iconFontFamilyRounded: "Material Symbols Rounded"
|
||||||
|
// Material Symbols is a variable font. Left unset, glyphs fall back to the
|
||||||
|
// font's default optical size (24px), which is tuned for larger rendering
|
||||||
|
// and makes some icons (e.g. "lock") look heavier/bigger than others when
|
||||||
|
// drawn small — pin "opsz" near the actual render size to keep icons
|
||||||
|
// visually consistent. See Appearance.iconSize for the matching pixelSize.
|
||||||
|
readonly property var iconFontAxes: ({ "FILL": 0, "wght": 400, "GRAD": 0, "opsz": 20 })
|
||||||
|
readonly property int iconSize: 16
|
||||||
|
|
||||||
|
readonly property int fontSize: 13
|
||||||
|
readonly property int fontSizeSmall: 11
|
||||||
|
|
||||||
|
readonly property int radius: 14
|
||||||
|
readonly property int radiusSmall: 8
|
||||||
|
|
||||||
|
readonly property int barHeight: 34
|
||||||
|
readonly property int spacing: 10
|
||||||
|
|
||||||
|
readonly property int animationDuration: 150
|
||||||
|
}
|
||||||
62
dotfiles/.config/quickshell/config/Colors.qml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
// Wallpaper-driven palette, sourced from pywal's ~/.cache/wal/colors.json.
|
||||||
|
// Run `wal -i /path/to/wallpaper.png` to (re)generate it — this file watches
|
||||||
|
// the cache and updates live, no shell restart needed. Until that's been run
|
||||||
|
// once, everything falls back to a hand-picked dark palette below.
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool active: _parsed !== null
|
||||||
|
property var _parsed: null
|
||||||
|
|
||||||
|
// --- Fallback palette (used until pywal has run) ---
|
||||||
|
readonly property color fallbackBg: "#1a1b26"
|
||||||
|
readonly property color fallbackFg: "#c0caf5"
|
||||||
|
readonly property var fallbackPalette: [
|
||||||
|
"#15161e", "#f7768e", "#9ece6a", "#e0af68",
|
||||||
|
"#7aa2f7", "#bb9af7", "#7dcfff", "#a9b1d6",
|
||||||
|
"#414868", "#f7768e", "#9ece6a", "#e0af68",
|
||||||
|
"#7aa2f7", "#bb9af7", "#7dcfff", "#c0caf5"
|
||||||
|
]
|
||||||
|
|
||||||
|
function paletteColor(i) {
|
||||||
|
if (_parsed && _parsed.colors)
|
||||||
|
return _parsed.colors["color" + i] || fallbackPalette[i]
|
||||||
|
return fallbackPalette[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color background: _parsed && _parsed.special ? _parsed.special.background : fallbackBg
|
||||||
|
readonly property color foreground: _parsed && _parsed.special ? _parsed.special.foreground : fallbackFg
|
||||||
|
readonly property color primary: paletteColor(4)
|
||||||
|
// Named primaryText (not "onPrimary") because QML treats any "onXxx"
|
||||||
|
// identifier as a signal handler slot, not a regular property.
|
||||||
|
readonly property color primaryText: background
|
||||||
|
readonly property color urgent: paletteColor(1)
|
||||||
|
// paletteColor(8) alone renders quite dark/low-contrast for text (it's
|
||||||
|
// meant as a muted *background* tone in most wal palettes) — lighten it
|
||||||
|
// so muted labels stay legible against the bar's dark background.
|
||||||
|
readonly property color muted: Qt.lighter(paletteColor(8), 2.2)
|
||||||
|
readonly property color surface: Qt.lighter(background, 1.35)
|
||||||
|
|
||||||
|
// QtObject has no default property, so the FileView is attached via a
|
||||||
|
// property assignment rather than as a plain child element.
|
||||||
|
readonly property FileView _walFile: FileView {
|
||||||
|
path: Quickshell.env("HOME") + "/.cache/wal/colors.json"
|
||||||
|
watchChanges: true
|
||||||
|
onLoaded: {
|
||||||
|
try {
|
||||||
|
root._parsed = JSON.parse(text())
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Colors: failed to parse pywal cache:", e)
|
||||||
|
root._parsed = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onLoadFailed: (error) => {
|
||||||
|
root._parsed = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
dotfiles/.config/quickshell/config/VpnExclusivity.qml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
// Tailscale, Mullvad, and ProtonVPN all fight over the default route/DNS if
|
||||||
|
// more than one is active at once (see VpnIndicator.qml's header comment) —
|
||||||
|
// only one of the three should ever actually be connected. This singleton
|
||||||
|
// is the shared signal between the two widget files: VpnIndicator.qml
|
||||||
|
// writes Mullvad/ProtonVPN's live connection state here as it polls them;
|
||||||
|
// TailscaleIndicator.qml reads it to back off (`tailscale down`) rather
|
||||||
|
// than stay up alongside either one, and to refuse turning Tailscale back
|
||||||
|
// on while one is still connected.
|
||||||
|
QtObject {
|
||||||
|
property bool mullvadConnected: false
|
||||||
|
property bool protonConnected: false
|
||||||
|
readonly property bool commercialVpnActive: mullvadConnected || protonConnected
|
||||||
|
}
|
||||||
4
dotfiles/.config/quickshell/config/qmldir
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module config
|
||||||
|
singleton Colors 1.0 Colors.qml
|
||||||
|
singleton Appearance 1.0 Appearance.qml
|
||||||
|
singleton VpnExclusivity 1.0 VpnExclusivity.qml
|
||||||
13
dotfiles/.config/quickshell/modules/bar/ActiveWindow.qml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.maximumWidth: 320
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
text: Hyprland.activeToplevel ? Hyprland.activeToplevel.title : ""
|
||||||
|
}
|
||||||
58
dotfiles/.config/quickshell/modules/bar/Bar.qml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: bar
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
exclusiveZone: implicitHeight
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Top
|
||||||
|
WlrLayershell.namespace: "quickshell:bar"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.background
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
leftMargin: Appearance.spacing
|
||||||
|
}
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
Workspaces { screen: bar.screen }
|
||||||
|
ActiveWindow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
rightMargin: Appearance.spacing
|
||||||
|
}
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
//Tray {}
|
||||||
|
TailscaleIndicator { barWindow: bar }
|
||||||
|
VpnIndicator { barWindow: bar }
|
||||||
|
NetworkIndicator { barWindow: bar }
|
||||||
|
BluetoothIndicator { barWindow: bar }
|
||||||
|
Volume { barWindow: bar }
|
||||||
|
BatteryIndicator { barWindow: bar }
|
||||||
|
PowerButton { barWindow: bar }
|
||||||
|
}
|
||||||
|
}
|
||||||
422
dotfiles/.config/quickshell/modules/bar/BatteryIndicator.qml
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.UPower
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
// Battery + power-profile panel, ported from omarchy's power panel
|
||||||
|
// (github.com/basecamp/omarchy shell/plugins/panels/power/{Model.js,Panel.qml})
|
||||||
|
// onto this project's own conventions: Quickshell's native UPower/PowerProfiles
|
||||||
|
// bindings instead of omarchy's `omarchy-battery-status` /
|
||||||
|
// `omarchy-powerprofiles-list` / `omarchy-powerprofiles-set` helper scripts
|
||||||
|
// (which don't exist outside omarchy), and Material Symbols glyphs instead of
|
||||||
|
// Nerd Font ones. The charge-threshold ("Holding"/limited-charge) concept from
|
||||||
|
// the original is hardware-specific (vendor charge-limit sysfs knobs) and has
|
||||||
|
// no equivalent in Quickshell's UPower binding, so it's dropped rather than
|
||||||
|
// guessed at; "Battery health" (device.healthPercentage) is shown in its
|
||||||
|
// place, using data UPower actually reports.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property var device: UPower.displayDevice
|
||||||
|
// isLaptopBattery (type === Battery && powerSupply === true) is the
|
||||||
|
// Quickshell-recommended check for "is this actually a battery" — more
|
||||||
|
// precise than isPresent, which the docs note is only meaningful once
|
||||||
|
// you already know the device is of Battery type.
|
||||||
|
readonly property bool batteryPresent: !!(root.device && root.device.ready && root.device.isLaptopBattery)
|
||||||
|
|
||||||
|
// Hidden entirely on a desktop with no battery — RowLayout skips
|
||||||
|
// invisible children for both sizing and spacing, so this just vanishes
|
||||||
|
// from the bar rather than leaving a gap.
|
||||||
|
visible: root.batteryPresent
|
||||||
|
implicitWidth: root.batteryPresent ? label.implicitWidth : 0
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
// The bar's own PanelWindow — passed in from Bar.qml so this popup can
|
||||||
|
// anchor to the bar itself rather than to this icon, keeping it a fixed
|
||||||
|
// distance from the bar and the screen edge regardless of where this
|
||||||
|
// icon sits in the row.
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
readonly property bool onBattery: UPower.onBattery
|
||||||
|
// Named deviceState, not "state" — Item already has a built-in `state`
|
||||||
|
// property (the property-based state-machine one) that this would
|
||||||
|
// otherwise collide with.
|
||||||
|
readonly property int deviceState: root.batteryPresent ? root.device.state : UPowerDeviceState.Unknown
|
||||||
|
readonly property bool fullyCharged: root.deviceState === UPowerDeviceState.FullyCharged
|
||||||
|
readonly property bool charging: root.batteryPresent && !root.onBattery && !root.fullyCharged
|
||||||
|
// device.percentage is a 0..1 fraction despite the name (same convention
|
||||||
|
// Volume.qml relies on for Pipewire's audio.volume).
|
||||||
|
readonly property real fraction: root.batteryPresent ? Math.max(0, Math.min(1, root.device.percentage)) : 0
|
||||||
|
readonly property bool low: root.batteryPresent && root.fraction <= 0.15 && !root.charging
|
||||||
|
|
||||||
|
function batteryIcon() {
|
||||||
|
if (!root.batteryPresent) return "battery_unknown"
|
||||||
|
if (root.fullyCharged) return "battery_full"
|
||||||
|
if (root.charging) return "battery_charging_full"
|
||||||
|
if (root.fraction <= 0.1) return "battery_alert"
|
||||||
|
const bars = ["battery_0_bar", "battery_1_bar", "battery_2_bar", "battery_3_bar", "battery_4_bar", "battery_5_bar", "battery_full"]
|
||||||
|
return bars[Math.max(0, Math.min(bars.length - 1, Math.round(root.fraction * (bars.length - 1))))]
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDuration(seconds) {
|
||||||
|
const s = Math.max(0, Math.round(seconds || 0))
|
||||||
|
if (s <= 0) return "—"
|
||||||
|
const h = Math.floor(s / 3600)
|
||||||
|
const m = Math.round((s % 3600) / 60)
|
||||||
|
return h > 0 ? (h + "h " + m + "m") : (m + "m")
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property string modeLabel: {
|
||||||
|
if (!root.batteryPresent) return ""
|
||||||
|
if (root.fullyCharged) return "Fully charged"
|
||||||
|
return root.onBattery ? "On battery" : "Charging"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cute rotating status phrases while current is actually flowing —
|
||||||
|
// ported as-is from omarchy's power panel, which pairs the same phrase
|
||||||
|
// sets with the same charging/on-battery states.
|
||||||
|
readonly property var chargingPhrases: [
|
||||||
|
"Pumping power", "Injecting electrons", "Pouring juice", "Amassing watts",
|
||||||
|
"Hoarding joules", "Sucking volts", "Topping reserves", "Soaking amps", "Inhaling kilowatts"
|
||||||
|
]
|
||||||
|
readonly property var onBatteryPhrases: [
|
||||||
|
"Slurping power", "Spending joules", "Draining watts", "Burning electrons",
|
||||||
|
"Sipping juice", "Spending coulombs", "Bleeding amps", "Guzzling volts", "Munching reserves"
|
||||||
|
]
|
||||||
|
readonly property var activePhrases: root.fullyCharged ? []
|
||||||
|
: (root.charging ? root.chargingPhrases : (root.onBattery ? root.onBatteryPhrases : []))
|
||||||
|
readonly property bool rotatingPhrases: root.activePhrases.length > 0
|
||||||
|
property int phraseIndex: 0
|
||||||
|
readonly property string heroStatusText: root.rotatingPhrases
|
||||||
|
? root.activePhrases[root.phraseIndex % root.activePhrases.length]
|
||||||
|
: root.modeLabel
|
||||||
|
|
||||||
|
// Only rotates while the panel is open and actually charging/discharging.
|
||||||
|
Timer {
|
||||||
|
id: phraseTimer
|
||||||
|
interval: 2800
|
||||||
|
running: panel.visible && root.rotatingPhrases
|
||||||
|
repeat: true
|
||||||
|
triggeredOnStart: false
|
||||||
|
onTriggered: phraseSwap.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: phraseSwap
|
||||||
|
PropertyAnimation { target: heroStatus; property: "opacity"; to: 0.0; duration: 180; easing.type: Easing.OutQuad }
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
const n = root.activePhrases.length
|
||||||
|
if (n > 0) root.phraseIndex = (root.phraseIndex + 1) % n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropertyAnimation { target: heroStatus; property: "opacity"; to: 1.0; duration: 260; easing.type: Easing.InQuad }
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we leave a rotating state mid-swap (e.g. unplugged mid-fade),
|
||||||
|
// snap back to full opacity so the new state reads immediately.
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onRotatingPhrasesChanged() {
|
||||||
|
if (!root.rotatingPhrases) {
|
||||||
|
phraseSwap.stop()
|
||||||
|
heroStatus.opacity = 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Power profile list ------------------------------------------------
|
||||||
|
// power-profiles-daemon only ever exposes these three fixed profiles;
|
||||||
|
// Performance is conditional on hasPerformanceProfile (e.g. absent on
|
||||||
|
// battery-only/thermally-limited hardware) — same gating omarchy's own
|
||||||
|
// Model.js applies via its profile-list script.
|
||||||
|
readonly property var profileEntries: {
|
||||||
|
const entries = [
|
||||||
|
{ value: PowerProfile.PowerSaver, label: "Saver", icon: "eco" },
|
||||||
|
{ value: PowerProfile.Balanced, label: "Balanced", icon: "balance" }
|
||||||
|
]
|
||||||
|
if (PowerProfiles.hasPerformanceProfile)
|
||||||
|
entries.push({ value: PowerProfile.Performance, label: "Performance", icon: "bolt" })
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: root.low ? Colors.urgent : Colors.foreground
|
||||||
|
text: root.batteryIcon()
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
panel.visible = !panel.visible
|
||||||
|
grab.active = panel.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Reusable pieces -----------------------------------------------
|
||||||
|
|
||||||
|
component ProfileButton: Rectangle {
|
||||||
|
id: profBtn
|
||||||
|
required property string label
|
||||||
|
required property string icon
|
||||||
|
required property bool active
|
||||||
|
signal activate()
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: 44
|
||||||
|
color: mouse.containsMouse ? Colors.primary
|
||||||
|
: (profBtn.active ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent")
|
||||||
|
|
||||||
|
// Hover-only outline, offset outside the button rather than drawn on
|
||||||
|
// its own edge — same treatment as this project's other selectable
|
||||||
|
// rows (e.g. Volume.qml's DeviceRow).
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: mouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 2
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: profBtn.icon
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 18
|
||||||
|
color: mouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
text: profBtn.label
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
font.bold: profBtn.active
|
||||||
|
color: mouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: profBtn.activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component StatRow: RowLayout {
|
||||||
|
id: statRow
|
||||||
|
width: parent.width
|
||||||
|
property string label: ""
|
||||||
|
property string value: ""
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: statRow.label
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: statRow.value
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Panel -----------------------------------------------------------
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: panel
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
readonly property int contentWidth: 244
|
||||||
|
readonly property int contentPadding: 16
|
||||||
|
implicitWidth: contentWidth + contentPadding * 2
|
||||||
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
window: root.barWindow
|
||||||
|
// Unlike anchor.item, anchor.window doesn't default rect to the
|
||||||
|
// window's own bounds — set it explicitly so edges/gravity below
|
||||||
|
// resolve against the full bar (and thus the true screen edges)
|
||||||
|
// instead of a near-zero rect at the window's origin.
|
||||||
|
rect.x: 0
|
||||||
|
rect.y: 0
|
||||||
|
rect.width: root.barWindow.width
|
||||||
|
rect.height: root.barWindow.height
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.bottom: -4
|
||||||
|
margins.right: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [panel]
|
||||||
|
onCleared: panel.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: panel.contentPadding
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// Hero: icon · title/status · percentage
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.batteryIcon()
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 30
|
||||||
|
color: root.low ? Colors.urgent : Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 2
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: "Battery"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: heroStatus
|
||||||
|
width: parent.width
|
||||||
|
text: root.heroStatusText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: Math.round(root.fraction * 100) + "%"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 20
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Charge level bar
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.muted
|
||||||
|
opacity: 0.35
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
radius: 0
|
||||||
|
color: root.low ? Colors.urgent : Colors.primary
|
||||||
|
width: Math.max(height, parent.width * root.fraction)
|
||||||
|
Behavior on width { NumberAnimation { duration: 320; easing.type: Easing.OutCubic } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 4
|
||||||
|
StatRow { label: "STATE"; value: root.modeLabel }
|
||||||
|
StatRow {
|
||||||
|
label: "HEALTH"
|
||||||
|
value: (root.batteryPresent && root.device.healthSupported)
|
||||||
|
? Math.round(root.device.healthPercentage) + "%" : "—"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 4
|
||||||
|
StatRow {
|
||||||
|
label: root.onBattery ? "TIME LEFT" : "TIME TO FULL"
|
||||||
|
value: root.batteryPresent
|
||||||
|
? root.formatDuration(root.onBattery ? root.device.timeToEmpty : root.device.timeToFull)
|
||||||
|
: "—"
|
||||||
|
}
|
||||||
|
StatRow {
|
||||||
|
label: "RATE"
|
||||||
|
value: root.batteryPresent ? Math.abs(root.device.changeRate).toFixed(1) + " W" : "—"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power profile picker
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "POWER PROFILE"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: profileRow
|
||||||
|
width: parent.width
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
readonly property real cellWidth: root.profileEntries.length > 0
|
||||||
|
? (width - spacing * (root.profileEntries.length - 1)) / root.profileEntries.length
|
||||||
|
: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.profileEntries
|
||||||
|
ProfileButton {
|
||||||
|
required property var modelData
|
||||||
|
width: profileRow.cellWidth
|
||||||
|
label: modelData.label
|
||||||
|
icon: modelData.icon
|
||||||
|
active: PowerProfiles.profile === modelData.value
|
||||||
|
onActivate: PowerProfiles.profile = modelData.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
795
dotfiles/.config/quickshell/modules/bar/BluetoothIndicator.qml
Normal file
@@ -0,0 +1,795 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
// Independent left/right breathing room around the glyph. Material
|
||||||
|
// Symbols icons aren't monospaced — each one's font-reported advance
|
||||||
|
// width (label.implicitWidth) bakes in its own side bearings, so the
|
||||||
|
// same "+4, centered" math that every other bar icon uses can still
|
||||||
|
// look tighter/looser icon-to-icon. Tune these two by eye instead of
|
||||||
|
// the icon's own bounding box to even it out against its neighbours.
|
||||||
|
property real iconLeftPadding: 0
|
||||||
|
property real iconRightPadding: 0
|
||||||
|
implicitWidth: root.iconLeftPadding + label.implicitWidth + root.iconRightPadding
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
// The bar's own PanelWindow — passed in from Bar.qml so this popup can
|
||||||
|
// anchor to the bar itself rather than to this icon, keeping it a fixed
|
||||||
|
// distance from the bar and the screen edge regardless of where this
|
||||||
|
// icon sits in the row.
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
readonly property var adapter: Bluetooth.defaultAdapter
|
||||||
|
|
||||||
|
// Scan only while the panel is open — same convention as the WiFi
|
||||||
|
// scannerEnabled binding in NetworkIndicator.qml.
|
||||||
|
Binding {
|
||||||
|
target: root.adapter
|
||||||
|
property: "discovering"
|
||||||
|
value: panel.visible && root.adapter.enabled
|
||||||
|
when: root.adapter !== null
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Device row helpers ----------------------------------------------
|
||||||
|
// Rows are plain objects rather than the live BluetoothDevice QObject —
|
||||||
|
// BlueZ churn (pairing timeouts, a device dropping out of range mid-scan)
|
||||||
|
// can destroy the object while a delegate still holds it, the same
|
||||||
|
// crash risk noted for WiFi networks in NetworkIndicator.qml. The actual
|
||||||
|
// object is re-resolved by address only when an action needs it, via
|
||||||
|
// deviceForAddress().
|
||||||
|
function deviceLabel(d) {
|
||||||
|
return (d.deviceName || d.name || d.address || "").trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlueZ's Icon property is a freedesktop icon-theme name (verified
|
||||||
|
// against a real paired device on this machine: "audio-headset") — map
|
||||||
|
// the common categories to a Material Symbols glyph, falling back to a
|
||||||
|
// generic "devices_other" for anything unrecognized.
|
||||||
|
function deviceIcon(icon) {
|
||||||
|
const i = icon || ""
|
||||||
|
if (i.indexOf("headset") !== -1 || i.indexOf("headphone") !== -1) return "headphones"
|
||||||
|
if (i.indexOf("mouse") !== -1) return "mouse"
|
||||||
|
if (i.indexOf("keyboard") !== -1) return "keyboard"
|
||||||
|
if (i.indexOf("gaming") !== -1 || i.indexOf("joystick") !== -1) return "sports_esports"
|
||||||
|
if (i.indexOf("tablet") !== -1) return "tablet"
|
||||||
|
if (i.indexOf("camera") !== -1) return "videocam"
|
||||||
|
if (i.indexOf("printer") !== -1) return "print"
|
||||||
|
if (i.indexOf("watch") !== -1) return "watch"
|
||||||
|
if (i.indexOf("tv") !== -1) return "tv"
|
||||||
|
if (i.indexOf("computer") !== -1) return "computer"
|
||||||
|
if (i.indexOf("card") !== -1) return "speaker"
|
||||||
|
return "devices_other"
|
||||||
|
}
|
||||||
|
|
||||||
|
function deviceRow(d) {
|
||||||
|
if (!d) return null
|
||||||
|
const label = root.deviceLabel(d)
|
||||||
|
if (!label) return null
|
||||||
|
return {
|
||||||
|
address: d.address || "",
|
||||||
|
label: label,
|
||||||
|
icon: root.deviceIcon(d.icon),
|
||||||
|
connected: !!d.connected,
|
||||||
|
paired: !!d.paired,
|
||||||
|
bonded: !!d.bonded,
|
||||||
|
trusted: !!d.trusted,
|
||||||
|
pairing: !!d.pairing,
|
||||||
|
state: d.state,
|
||||||
|
batteryAvailable: !!d.batteryAvailable,
|
||||||
|
battery: d.battery || 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var deviceRows: root.adapter
|
||||||
|
? root.adapter.devices.values.map(root.deviceRow).filter(function(r) { return r !== null })
|
||||||
|
: []
|
||||||
|
|
||||||
|
readonly property var connectedRows: root.deviceRows.filter(function(r) { return r.connected })
|
||||||
|
readonly property var knownRows: root.deviceRows.filter(function(r) {
|
||||||
|
return !r.connected && (r.paired || r.bonded || r.trusted)
|
||||||
|
})
|
||||||
|
readonly property var discoveredRows: root.deviceRows.filter(function(r) {
|
||||||
|
return !r.connected && !r.paired && !r.bonded && !r.trusted
|
||||||
|
})
|
||||||
|
|
||||||
|
function deviceForAddress(address) {
|
||||||
|
if (!root.adapter) return null
|
||||||
|
const devs = root.adapter.devices.values
|
||||||
|
for (let i = 0; i < devs.length; i++) {
|
||||||
|
if (devs[i].address === address) return devs[i]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Action feedback ---------------------------------------------------
|
||||||
|
// BlueZ operations here are fire-and-forget from QML's side — connect()/
|
||||||
|
// disconnect()/pair()/forget() report failure only via a C++-side log
|
||||||
|
// line (see quickshell's bluetooth/device.cpp), nothing reaches QML. So
|
||||||
|
// "did it work" has to be inferred from the device's own properties
|
||||||
|
// instead of a success/failure callback. Shown as a line right under the
|
||||||
|
// specific row it's about (DeviceRow.statusText below) rather than a
|
||||||
|
// panel-wide banner — actionStatusAddress is how a row knows a message
|
||||||
|
// is meant for it; since it's address-keyed rather than tied to a
|
||||||
|
// particular DeviceRow instance, the message still finds its row even
|
||||||
|
// when the device jumps sections (Paired → Connected on a successful
|
||||||
|
// connect, say), because that's a new DeviceRow for the same address.
|
||||||
|
// - busyStatus is purely reactive — it just reads pairing/state off
|
||||||
|
// whichever row is currently mid-operation, however that operation
|
||||||
|
// was triggered. It's not shown directly (each row already derives
|
||||||
|
// the same "Connecting…"/"Disconnecting…" off its own dev.state);
|
||||||
|
// it only exists here to tell resolvePendingAction when to fire.
|
||||||
|
// - pendingAction+the busyStatus watcher below is how a *specific*
|
||||||
|
// click gets its own outcome message: it snapshots what was asked
|
||||||
|
// for, waits for busyStatus to clear, then checks whether the
|
||||||
|
// expected end state (connected/paired) actually landed.
|
||||||
|
readonly property string busyStatus: {
|
||||||
|
for (const r of root.deviceRows) {
|
||||||
|
if (r.pairing) return "pairing:" + r.address
|
||||||
|
if (r.state === BluetoothDeviceState.Connecting) return "connecting:" + r.address
|
||||||
|
if (r.state === BluetoothDeviceState.Disconnecting) return "disconnecting:" + r.address
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
property var pendingAction: null
|
||||||
|
property string actionStatus: ""
|
||||||
|
property string actionStatusAddress: ""
|
||||||
|
|
||||||
|
// Checks whether pendingAction's expected end state actually landed and
|
||||||
|
// reports it, then clears pendingAction. Called both when busyStatus
|
||||||
|
// clears normally and from pendingTimeoutTimer below — an operation
|
||||||
|
// that resolves inside a single binding re-evaluation (a device already
|
||||||
|
// in range reconnecting near-instantly, say) can flip busyStatus from ""
|
||||||
|
// straight back to "" without ever visibly changing, which would
|
||||||
|
// otherwise leave pendingAction stuck forever and misattribute whatever
|
||||||
|
// busyStatus transition happens to come along next.
|
||||||
|
function resolvePendingAction() {
|
||||||
|
if (!root.pendingAction) return
|
||||||
|
const p = root.pendingAction
|
||||||
|
root.pendingAction = null
|
||||||
|
const d = root.deviceForAddress(p.address)
|
||||||
|
root.actionStatusAddress = p.address
|
||||||
|
if (p.kind === "disconnect") {
|
||||||
|
root.actionStatus = (d && !d.connected) ? "Disconnected" : "Couldn't disconnect"
|
||||||
|
} else if (p.kind === "pair") {
|
||||||
|
root.actionStatus = (d && d.paired) ? "Paired" : "Couldn't pair"
|
||||||
|
} else {
|
||||||
|
root.actionStatus = (d && d.connected) ? "Connected" : "Couldn't connect"
|
||||||
|
}
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
onBusyStatusChanged: if (root.busyStatus === "") root.resolvePendingAction()
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: actionStatusTimer
|
||||||
|
interval: 3500
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.actionStatus = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backstop for the "resolved before busyStatus ever visibly changed"
|
||||||
|
// case above, and a genuine timeout for an operation that's just stuck
|
||||||
|
// (device out of range, etc.) — either way, restarted whenever
|
||||||
|
// pendingAction is (re)set, so it always reflects the latest click.
|
||||||
|
Timer {
|
||||||
|
id: pendingTimeoutTimer
|
||||||
|
interval: 8000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.resolvePendingAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectDevice(row) {
|
||||||
|
const d = root.deviceForAddress(row.address)
|
||||||
|
if (!d) return
|
||||||
|
// Already-paired devices just reconnect; a fresh discovery result
|
||||||
|
// has to pair first (BlueZ's own agent handles the SSP/passkey
|
||||||
|
// handshake — there's no PIN-entry surface exposed by this API).
|
||||||
|
if (row.paired || row.bonded || row.trusted) {
|
||||||
|
root.pendingAction = { address: row.address, kind: "connect" }
|
||||||
|
pendingTimeoutTimer.restart()
|
||||||
|
d.connect()
|
||||||
|
} else {
|
||||||
|
root.pendingAction = { address: row.address, kind: "pair" }
|
||||||
|
pendingTimeoutTimer.restart()
|
||||||
|
d.pair()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectDevice(row) {
|
||||||
|
const d = root.deviceForAddress(row.address)
|
||||||
|
if (!d) return
|
||||||
|
root.pendingAction = { address: row.address, kind: "disconnect" }
|
||||||
|
pendingTimeoutTimer.restart()
|
||||||
|
d.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
function forgetDevice(row) {
|
||||||
|
const d = root.deviceForAddress(row.address)
|
||||||
|
if (!d) return
|
||||||
|
if (d.connected) d.disconnect()
|
||||||
|
d.forget()
|
||||||
|
// No feedback line here — forgetting removes this row from every
|
||||||
|
// list immediately, so there's nothing left to show a message
|
||||||
|
// under. The row vanishing is the confirmation.
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTrusted(row, trusted) {
|
||||||
|
const d = root.deviceForAddress(row.address)
|
||||||
|
if (!d) return
|
||||||
|
d.trusted = trusted
|
||||||
|
root.actionStatusAddress = row.address
|
||||||
|
root.actionStatus = trusted ? "Trusting" : "No longer trusting"
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool anyConnected: root.connectedRows.length > 0
|
||||||
|
|
||||||
|
// Caps how tall the Paired/Available list gets before it scrolls
|
||||||
|
// instead of continuing to grow the popup — same convention as
|
||||||
|
// NetworkIndicator.qml's Known/Other Networks list.
|
||||||
|
readonly property int maxDeviceListHeight: 260
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: root.iconLeftPadding
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: (root.adapter && root.adapter.enabled) ? Colors.foreground : Colors.muted
|
||||||
|
text: {
|
||||||
|
if (!root.adapter || !root.adapter.enabled) return "bluetooth_disabled"
|
||||||
|
return root.anyConnected ? "bluetooth_connected" : "bluetooth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
panel.visible = !panel.visible
|
||||||
|
grab.active = panel.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Reusable pieces ---------------------------------------------------
|
||||||
|
|
||||||
|
component ToggleSwitch: Item {
|
||||||
|
id: toggleRoot
|
||||||
|
property bool checked: false
|
||||||
|
signal toggled()
|
||||||
|
implicitWidth: 34
|
||||||
|
implicitHeight: 18
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: toggleRoot.checked ? Colors.primary : Colors.muted
|
||||||
|
opacity: toggleRoot.checked ? 1 : 0.35
|
||||||
|
}
|
||||||
|
// Hover-only outline, offset outside the switch itself rather than
|
||||||
|
// drawn on its edge — the switch lags behind a click until the
|
||||||
|
// backend confirms it (e.g. the adapter's enabled state), so this
|
||||||
|
// is just a "you can click this" cue, not click feedback.
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -4
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: toggleMouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
width: parent.height - 4
|
||||||
|
height: parent.height - 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.background
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: toggleRoot.checked ? parent.width - width - 2 : 2
|
||||||
|
Behavior on x { NumberAnimation { duration: Appearance.animationDuration } }
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: toggleMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: toggleRoot.toggled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// One device row. `showForget` gates the whole trailing action cluster —
|
||||||
|
// trust toggle, disconnect, forget — for discovered-but-unpaired devices,
|
||||||
|
// which have none of those to act on yet (a plain click there pairs
|
||||||
|
// instead, via activate()). For a paired/connected row, the row body
|
||||||
|
// itself still connects/disconnects (activate()) same as before; the
|
||||||
|
// actions below are the explicit, discoverable versions of that plus
|
||||||
|
// the two this row previously had no way to reach at all.
|
||||||
|
component DeviceRow: Rectangle {
|
||||||
|
id: devRow
|
||||||
|
required property var dev
|
||||||
|
property bool showForget: true
|
||||||
|
signal activate()
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: rowContent.implicitHeight + 12
|
||||||
|
|
||||||
|
// Which action icon (if any) the pointer is currently over — drives
|
||||||
|
// both that icon's own hover color below and rowMouse's click
|
||||||
|
// dispatch. Derived from rowMouse.mouseX/containsMouse rather than a
|
||||||
|
// MouseArea on each icon: those icons live inside rowContent, which
|
||||||
|
// sits underneath rowMouse in stacking order, so a nested MouseArea
|
||||||
|
// there would just be shadowed by it (same reason
|
||||||
|
// NetworkIndicator.qml's NetworkRow dispatches by position too).
|
||||||
|
// Checked right-to-left since that's the order the icons are laid
|
||||||
|
// out in, so an earlier icon's "from here to the row's right edge"
|
||||||
|
// zone doesn't swallow the ones after it.
|
||||||
|
readonly property string hoveredAction: {
|
||||||
|
if (!rowMouse.containsMouse) return ""
|
||||||
|
if (devRow.showForget && forgetIcon.visible
|
||||||
|
&& rowMouse.mouseX >= devRow.mapFromItem(forgetIcon, 0, 0).x - 8) return "forget"
|
||||||
|
if (devRow.showForget && trustIcon.visible
|
||||||
|
&& rowMouse.mouseX >= devRow.mapFromItem(trustIcon, 0, 0).x - 8) return "trust"
|
||||||
|
if (disconnectIcon.visible
|
||||||
|
&& rowMouse.mouseX >= devRow.mapFromItem(disconnectIcon, 0, 0).x - 8) return "disconnect"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// Hover checked first (same ordering as Volume.qml's DeviceRow):
|
||||||
|
// hovering always shows a solid Colors.primary fill, even for an
|
||||||
|
// already-connected row, so the primaryText used below never has to
|
||||||
|
// sit on top of the dimmer translucent tint instead.
|
||||||
|
color: rowMouse.containsMouse ? Colors.primary
|
||||||
|
: (devRow.dev.connected ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent")
|
||||||
|
|
||||||
|
// Hover-only outline, offset outside the row rather than drawn on
|
||||||
|
// its own edge — same treatment as NetworkIndicator.qml's NetworkRow.
|
||||||
|
// The lists this feeds are inset by 3px (see deviceListColumn and
|
||||||
|
// the Connected section below) so this has room without being
|
||||||
|
// cropped by deviceListFlick's clip.
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: rowMouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowContent
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: 6
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.minimumWidth: 20
|
||||||
|
Layout.maximumWidth: 20
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
text: devRow.dev.icon
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: devRow.dev.label
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
font.bold: devRow.dev.connected
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
readonly property string statusText: {
|
||||||
|
if (devRow.dev.pairing) return "Pairing…"
|
||||||
|
if (devRow.dev.state === BluetoothDeviceState.Connecting) return "Connecting…"
|
||||||
|
if (devRow.dev.state === BluetoothDeviceState.Disconnecting) return "Disconnecting…"
|
||||||
|
// The outcome of the last action taken on this
|
||||||
|
// specific device (connect/disconnect/pair/trust) —
|
||||||
|
// see the "Action feedback" comment above
|
||||||
|
// root.busyStatus. Matched by address rather than by
|
||||||
|
// this being "the same row" that was clicked, since
|
||||||
|
// a successful connect/disconnect moves the device
|
||||||
|
// to a different section (a new DeviceRow entirely).
|
||||||
|
if (root.actionStatusAddress === devRow.dev.address && root.actionStatus !== "")
|
||||||
|
return root.actionStatus
|
||||||
|
if (devRow.dev.connected && devRow.dev.batteryAvailable)
|
||||||
|
return Math.round(devRow.dev.battery * 100) + "%"
|
||||||
|
if (devRow.dev.connected) return "Connected"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
visible: statusText !== ""
|
||||||
|
text: statusText
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each action below is a fixed-size slot with its own
|
||||||
|
// hover-halo outline — offset outside the slot rather than drawn
|
||||||
|
// on its own edge, same treatment as devRow's own outline above
|
||||||
|
// and every other hoverable box in this file (ToggleSwitch,
|
||||||
|
// DeviceRow itself, etc.) — instead of just the color swap the
|
||||||
|
// row's own icons get.
|
||||||
|
|
||||||
|
// Disconnect without forgetting — same effect as clicking the
|
||||||
|
// row body on a Connected row (activate() below calls
|
||||||
|
// disconnectDevice too), just given its own explicit, always-
|
||||||
|
// visible icon instead of relying on that being guessed.
|
||||||
|
Item {
|
||||||
|
id: disconnectIcon
|
||||||
|
visible: devRow.showForget && devRow.dev.connected
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.preferredHeight: 20
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: devRow.hoveredAction === "disconnect" ? 1 : 0
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "link_off"
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
// Stays primaryText (dark) rather than switching to
|
||||||
|
// Colors.primary while targeted — devRow's own fill is
|
||||||
|
// already Colors.primary on hover, so that would've put
|
||||||
|
// a primary-colored glyph on a primary-colored
|
||||||
|
// background. The outline Rectangle above is what shows
|
||||||
|
// which slot is targeted.
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trust toggle — full brightness when trusted, dimmed when not,
|
||||||
|
// same "state via opacity" convention PowerButton.qml uses for
|
||||||
|
// its disabled entries.
|
||||||
|
Item {
|
||||||
|
id: trustIcon
|
||||||
|
visible: devRow.showForget
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.preferredHeight: 20
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: devRow.hoveredAction === "trust" ? 1 : 0
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "verified_user"
|
||||||
|
opacity: devRow.dev.trusted ? 1 : 0.4
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: forgetIcon
|
||||||
|
visible: devRow.showForget
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.preferredHeight: 20
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: devRow.hoveredAction === "forget" ? 1 : 0
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "close"
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: rowMouse
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
height: rowContent.height + 12
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
// Dispatches on devRow.hoveredAction rather than its own
|
||||||
|
// MouseArea per icon — see that property's comment above.
|
||||||
|
onClicked: {
|
||||||
|
switch (devRow.hoveredAction) {
|
||||||
|
case "forget": root.forgetDevice(devRow.dev); break
|
||||||
|
case "trust": root.setTrusted(devRow.dev, !devRow.dev.trusted); break
|
||||||
|
case "disconnect": root.disconnectDevice(devRow.dev); break
|
||||||
|
default: devRow.activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Panel -------------------------------------------------------------
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: panel
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
// Wider than the other panels' usual 244 — each device row now ends
|
||||||
|
// in a row of three 20px action slots (disconnect/trust/forget)
|
||||||
|
// instead of a single close icon, and the name column needs room to
|
||||||
|
// not immediately start eliding against that.
|
||||||
|
readonly property int contentWidth: 300
|
||||||
|
readonly property int contentPadding: 16
|
||||||
|
implicitWidth: contentWidth + contentPadding * 2
|
||||||
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||||
|
// Connected/paired/discovered devices come and go while the panel
|
||||||
|
// is open — animate the resize instead of snapping, same as the
|
||||||
|
// network panel's WiFi list.
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
NumberAnimation { duration: Appearance.animationDuration; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
window: root.barWindow
|
||||||
|
rect.x: 0
|
||||||
|
rect.y: 0
|
||||||
|
rect.width: root.barWindow.width
|
||||||
|
rect.height: root.barWindow.height
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.bottom: -4
|
||||||
|
margins.right: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [panel]
|
||||||
|
onCleared: panel.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: panel.contentPadding
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// Header
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: label.text
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 21
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Bluetooth"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spins continuously while root.adapter.discovering is
|
||||||
|
// true — a persistent "still searching" cue independent
|
||||||
|
// of the list itself, unlike the "Scanning for devices…"
|
||||||
|
// text below (which only shows while the device list is
|
||||||
|
// still empty).
|
||||||
|
Text {
|
||||||
|
id: scanSpinner
|
||||||
|
visible: root.adapter !== null && root.adapter.discovering
|
||||||
|
text: "progress_activity"
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: Colors.muted
|
||||||
|
|
||||||
|
RotationAnimation on rotation {
|
||||||
|
running: scanSpinner.visible
|
||||||
|
loops: Animation.Infinite
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 900
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleSwitch {
|
||||||
|
visible: root.adapter !== null
|
||||||
|
checked: root.adapter !== null && root.adapter.enabled
|
||||||
|
onToggled: root.adapter.enabled = !root.adapter.enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
visible: root.adapter === null
|
||||||
|
text: "No Bluetooth adapter"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
visible: root.adapter !== null && !root.adapter.enabled
|
||||||
|
text: "Turn Bluetooth on to see devices"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connected — always shown in full above the scrollable
|
||||||
|
// list, mirroring the network panel's layout.
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
visible: root.connectedRows.length > 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Connected"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
// Inset 3px on each side to match deviceListColumn
|
||||||
|
// below, so DeviceRow's hover halo has room here too.
|
||||||
|
x: 3
|
||||||
|
width: parent.width - 6
|
||||||
|
spacing: 2
|
||||||
|
Repeater {
|
||||||
|
model: root.connectedRows
|
||||||
|
DeviceRow {
|
||||||
|
required property var modelData
|
||||||
|
dev: modelData
|
||||||
|
showForget: true
|
||||||
|
onActivate: root.disconnectDevice(dev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paired — always shown in full, same as Connected above and
|
||||||
|
// for the same reason: these are one click away from
|
||||||
|
// reconnecting (root.connectDevice reconnects rather than
|
||||||
|
// re-pairing whenever a row is already paired/bonded/trusted),
|
||||||
|
// so they shouldn't be buried in the capped-height scroll area
|
||||||
|
// below or hidden behind an active scan turning up other
|
||||||
|
// nearby devices.
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
visible: root.knownRows.length > 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Paired Devices"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
// Inset 3px on each side to match deviceListColumn
|
||||||
|
// below, so DeviceRow's hover halo has room here too.
|
||||||
|
x: 3
|
||||||
|
width: parent.width - 6
|
||||||
|
spacing: 2
|
||||||
|
Repeater {
|
||||||
|
model: root.knownRows
|
||||||
|
DeviceRow {
|
||||||
|
required property var modelData
|
||||||
|
dev: modelData
|
||||||
|
showForget: true
|
||||||
|
onActivate: root.connectDevice(dev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
visible: root.adapter !== null && root.adapter.enabled && root.deviceRows.length === 0
|
||||||
|
text: (root.adapter && root.adapter.discovering) ? "Scanning for devices…" : "No devices found"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
// Available — freshly discovered, unpaired devices only.
|
||||||
|
// Capped height, scrolls once there are more than fit rather
|
||||||
|
// than growing the popup indefinitely.
|
||||||
|
Flickable {
|
||||||
|
id: deviceListFlick
|
||||||
|
width: parent.width
|
||||||
|
height: Math.min(deviceListColumn.implicitHeight, root.maxDeviceListHeight)
|
||||||
|
contentWidth: width
|
||||||
|
contentHeight: deviceListColumn.implicitHeight
|
||||||
|
clip: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
visible: deviceListColumn.implicitHeight > 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: deviceListColumn
|
||||||
|
// Inset 3px on every side so DeviceRow's hover halo
|
||||||
|
// has room without being cropped by deviceListFlick's
|
||||||
|
// clip. Left/right needs the manual x/width shift
|
||||||
|
// (children bind width: parent.width, which ignores
|
||||||
|
// Column's own padding); top/bottom just needs
|
||||||
|
// padding, since that's along Column's own layout
|
||||||
|
// axis and Flickable's contentHeight tracks it.
|
||||||
|
x: 3
|
||||||
|
width: deviceListFlick.width - 6
|
||||||
|
topPadding: 3
|
||||||
|
bottomPadding: 3
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
visible: root.adapter !== null && root.adapter.discovering && root.discoveredRows.length > 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Available Devices"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 2
|
||||||
|
Repeater {
|
||||||
|
model: root.discoveredRows
|
||||||
|
DeviceRow {
|
||||||
|
required property var modelData
|
||||||
|
dev: modelData
|
||||||
|
showForget: false
|
||||||
|
onActivate: root.connectDevice(dev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
dotfiles/.config/quickshell/modules/bar/Clock.qml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import QtQuick
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: root
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
text: Qt.formatDateTime(new Date(), "ddd d MMM hh:mm")
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: root.text = Qt.formatDateTime(new Date(), "ddd d MMM hh:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
1352
dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml
Normal file
200
dotfiles/.config/quickshell/modules/bar/PowerButton.qml
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 2
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
// The bar's own PanelWindow — passed in from Bar.qml so this popup can
|
||||||
|
// anchor to the bar itself rather than to this icon, keeping it a fixed
|
||||||
|
// distance from the bar and the screen edge regardless of where this
|
||||||
|
// icon sits in the row.
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: Colors.foreground
|
||||||
|
text: "settings_power"
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
menu.visible = !menu.visible
|
||||||
|
grab.active = menu.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process { id: proc }
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: menu
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
// Same contentWidth/contentPadding split as the other panels
|
||||||
|
// (Volume.qml, NetworkIndicator.qml, etc.) rather than a single
|
||||||
|
// magic implicitWidth.
|
||||||
|
readonly property int contentWidth: 178
|
||||||
|
readonly property int contentPadding: 16
|
||||||
|
implicitWidth: contentWidth + contentPadding * 2
|
||||||
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
window: root.barWindow
|
||||||
|
// Unlike anchor.item, anchor.window doesn't default rect to the
|
||||||
|
// window's own bounds — set it explicitly so edges/gravity below
|
||||||
|
// resolve against the full bar (and thus the true screen edges)
|
||||||
|
// instead of a near-zero rect at the window's origin.
|
||||||
|
rect.x: 0
|
||||||
|
rect.y: 0
|
||||||
|
rect.width: root.barWindow.width
|
||||||
|
rect.height: root.barWindow.height
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.bottom: -4
|
||||||
|
margins.right: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [menu]
|
||||||
|
onCleared: menu.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: menu.contentPadding
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// Header — same title layout as Volume.qml's panel: the bar
|
||||||
|
// icon large, plus a bold title.
|
||||||
|
RowLayout {
|
||||||
|
id: header
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: label.text
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 23
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Power"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: list
|
||||||
|
model: [
|
||||||
|
{ label: "Lock", icon: "lock", cmd: ["hyprlock"] },
|
||||||
|
{ label: "Suspend", icon: "bedtime", cmd: ["systemctl", "suspend"] },
|
||||||
|
{ label: "Hibernate", icon: "ac_unit", cmd: ["systemctl", "hibernate"] },
|
||||||
|
{ label: "Log out", icon: "logout", cmd: ["hyprctl", "dispatch", "exit"] },
|
||||||
|
{ label: "Reboot", icon: "restart_alt", cmd: ["systemctl", "reboot"] },
|
||||||
|
{ label: "Shut down", icon: "power_settings_new", cmd: ["systemctl", "poweroff"] }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Same shape as this project's other selectable rows
|
||||||
|
// (e.g. VpnIndicator.qml's ProviderRow,
|
||||||
|
// TailscaleIndicator.qml's ExitNodeRow): radius 0, a
|
||||||
|
// fixed-width icon column followed by a fillWidth
|
||||||
|
// label, and an offset hover halo rather than one
|
||||||
|
// drawn on the row's own edge.
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: entry
|
||||||
|
required property var modelData
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: entryContent.implicitHeight + 12
|
||||||
|
color: (!entry.modelData.disabled && entryMouse.containsMouse) ? Colors.primary : "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: entryMouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: entryContent
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: 6
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.minimumWidth: 20
|
||||||
|
Layout.maximumWidth: 20
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
text: entry.modelData.icon
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
opacity: entry.modelData.disabled ? 0.4 : 1
|
||||||
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: entry.modelData.label
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
opacity: entry.modelData.disabled ? 0.4 : 1
|
||||||
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: entryMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !entry.modelData.disabled
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
proc.command = entry.modelData.cmd
|
||||||
|
proc.running = true
|
||||||
|
menu.visible = false
|
||||||
|
grab.active = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1175
dotfiles/.config/quickshell/modules/bar/TailscaleIndicator.qml
Normal file
32
dotfiles/.config/quickshell/modules/bar/Tray.qml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing * 0.6
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
delegate: IconImage {
|
||||||
|
id: trayIcon
|
||||||
|
required property var modelData
|
||||||
|
implicitWidth: 16
|
||||||
|
implicitHeight: 16
|
||||||
|
source: modelData.icon
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
if (mouse.button === Qt.LeftButton)
|
||||||
|
trayIcon.modelData.activate()
|
||||||
|
else
|
||||||
|
trayIcon.modelData.secondaryActivate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
496
dotfiles/.config/quickshell/modules/bar/Volume.qml
Normal file
@@ -0,0 +1,496 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
// The bar's own PanelWindow — passed in from Bar.qml so this popup can
|
||||||
|
// anchor to the bar itself rather than to this icon, keeping it a fixed
|
||||||
|
// distance from the bar and the screen edge regardless of where this
|
||||||
|
// icon sits in the row.
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
readonly property var sink: Pipewire.defaultAudioSink
|
||||||
|
readonly property var source: Pipewire.defaultAudioSource
|
||||||
|
readonly property var nodes: Pipewire.nodes ? Pipewire.nodes.values : []
|
||||||
|
|
||||||
|
readonly property real outputVolume: (root.sink && root.sink.audio) ? root.sink.audio.volume : 0
|
||||||
|
readonly property bool outputMuted: (root.sink && root.sink.audio) ? root.sink.audio.muted : false
|
||||||
|
readonly property real inputVolume: (root.source && root.source.audio) ? root.source.audio.volume : 0
|
||||||
|
readonly property bool inputMuted: (root.source && root.source.audio) ? root.source.audio.muted : false
|
||||||
|
|
||||||
|
readonly property var candidateSinks: root.nodes.filter(function(n) { return n && n.isSink && !n.isStream })
|
||||||
|
readonly property var candidateSources: root.nodes.filter(function(n) { return n && !n.isSink && !n.isStream && n.audio })
|
||||||
|
|
||||||
|
PwObjectTracker { objects: root.candidateSinks }
|
||||||
|
PwObjectTracker { objects: root.candidateSources }
|
||||||
|
|
||||||
|
// Live mic level for the input gauge below — separate from inputVolume
|
||||||
|
// (the configured gain), this tracks the actual incoming signal.
|
||||||
|
// Only runs while the panel is open, to skip metering when unused.
|
||||||
|
PwNodePeakMonitor {
|
||||||
|
id: inputPeak
|
||||||
|
node: root.source
|
||||||
|
enabled: panel.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
PwNodePeakMonitor {
|
||||||
|
id: outputPeak
|
||||||
|
node: root.sink
|
||||||
|
enabled: panel.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Device label/icon heuristics, ported from omarchy's audio panel
|
||||||
|
// Model.js (github.com/basecamp/omarchy shell/plugins/panels/audio/Model.js),
|
||||||
|
// adapted to this project's Material Symbols icon set instead of Nerd Font.
|
||||||
|
function friendlyDeviceLabel(text) {
|
||||||
|
var out = String(text || "").trim()
|
||||||
|
out = out.replace(/^sof-soundwire\s+/i, "")
|
||||||
|
out = out.replace(/^built-?in audio\s+/i, "")
|
||||||
|
out = out.replace(/\s+Output$/i, "")
|
||||||
|
out = out.replace(/\s+Input$/i, "")
|
||||||
|
out = out.replace(/Microphones/gi, "Microphone")
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
function deviceLabel(node) {
|
||||||
|
if (!node) return "Unknown"
|
||||||
|
var nick = friendlyDeviceLabel(node.nickname || "")
|
||||||
|
if (nick) return nick
|
||||||
|
return friendlyDeviceLabel(node.description || node.name || "Unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
function deviceBlob(node) {
|
||||||
|
if (!node) return ""
|
||||||
|
var p = node.properties || {}
|
||||||
|
return [node.name, node.description, node.nickname,
|
||||||
|
p["device.icon-name"] || "", p["device.product.name"] || ""].join(" ").toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quickshell's Pipewire API only exposes a node's own properties, not
|
||||||
|
// its parent Device — so device.api (unlike device.form-factor or the
|
||||||
|
// richer device.icon-name, which only live on the Device object) is the
|
||||||
|
// one reliable Bluetooth signal actually present here: it's set on
|
||||||
|
// every node PipeWire hands off to a bluez5-backed sink/source. Checking
|
||||||
|
// it directly beats sniffing the word "bluetooth" out of node names,
|
||||||
|
// which usually just say "bluez_output..." and never match.
|
||||||
|
function isBluetoothNode(node) {
|
||||||
|
var p = (node && node.properties) || {}
|
||||||
|
return p["device.api"] === "bluez5"
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipeWire's own device.form-factor (which would call ACCENTUM a
|
||||||
|
// "headset" outright) isn't reachable from here for the same reason —
|
||||||
|
// it lives on the Device object, not the node. And some devices (a
|
||||||
|
// generic USB DAC like an EKSA headset) have no form-factor anywhere in
|
||||||
|
// PipeWire at all, headset or not, so no property-based check can catch
|
||||||
|
// them. This override list is the deliberate manual escape hatch for
|
||||||
|
// exactly that case — add a distinctive substring from the product name
|
||||||
|
// (device.product.name/description, matched case-insensitively via
|
||||||
|
// deviceBlob) whenever a new no-metadata device shows up misclassified.
|
||||||
|
readonly property var headphoneNameOverrides: ["e900plus"]
|
||||||
|
|
||||||
|
function isHeadphoneNode(node) {
|
||||||
|
var blob = deviceBlob(node)
|
||||||
|
if (blob.indexOf("headphone") !== -1 || blob.indexOf("headset") !== -1
|
||||||
|
|| blob.indexOf("earbud") !== -1 || blob.indexOf("earphone") !== -1
|
||||||
|
|| blob.indexOf("airpod") !== -1)
|
||||||
|
return true
|
||||||
|
return root.headphoneNameOverrides.some(function(needle) { return blob.indexOf(needle) !== -1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
function sinkIcon(node) {
|
||||||
|
if (!node) return "speaker"
|
||||||
|
if (isHeadphoneNode(node)) return "headphones"
|
||||||
|
if (isBluetoothNode(node)) return "bluetooth_audio"
|
||||||
|
var blob = deviceBlob(node)
|
||||||
|
if (blob.indexOf("hdmi") !== -1 || blob.indexOf("display") !== -1) return "tv"
|
||||||
|
return "speaker"
|
||||||
|
}
|
||||||
|
|
||||||
|
function sourceIcon(node) {
|
||||||
|
if (!node) return "mic"
|
||||||
|
if (isHeadphoneNode(node)) return "headphones"
|
||||||
|
if (isBluetoothNode(node)) return "bluetooth_audio"
|
||||||
|
var blob = deviceBlob(node)
|
||||||
|
if (blob.indexOf("webcam") !== -1 || blob.indexOf("camera") !== -1) return "videocam"
|
||||||
|
return "mic"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 18
|
||||||
|
color: Colors.foreground
|
||||||
|
text: (root.outputMuted || root.outputVolume <= 0) ? "volume_off"
|
||||||
|
: (root.outputVolume < 0.5 ? "volume_down" : "volume_up")
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
panel.visible = !panel.visible
|
||||||
|
grab.active = panel.visible
|
||||||
|
}
|
||||||
|
onWheel: (wheel) => {
|
||||||
|
if (!root.sink || !root.sink.audio) return
|
||||||
|
const step = 0.05
|
||||||
|
const delta = wheel.angleDelta.y > 0 ? step : -step
|
||||||
|
root.sink.audio.volume = Math.max(0, Math.min(1, root.sink.audio.volume + delta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Reusable pieces -----------------------------------------------
|
||||||
|
|
||||||
|
component VolumeSlider: Item {
|
||||||
|
id: sliderRoot
|
||||||
|
property real value: 0
|
||||||
|
property bool enabled: true
|
||||||
|
signal moved(real newValue)
|
||||||
|
implicitHeight: 16
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: track
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.muted
|
||||||
|
opacity: 0.35
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: track.width * Math.max(0, Math.min(1, sliderRoot.value))
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.primary
|
||||||
|
opacity: sliderRoot.enabled ? 1 : 0.4
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
width: 12
|
||||||
|
height: 12
|
||||||
|
radius: 6
|
||||||
|
color: Colors.primary
|
||||||
|
opacity: sliderRoot.enabled ? 1 : 0.4
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: Math.max(0, Math.min(track.width - width, track.width * sliderRoot.value - width / 2))
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: sliderRoot.enabled
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
function updateFromX(mx) {
|
||||||
|
sliderRoot.moved(Math.max(0, Math.min(1, mx / track.width)))
|
||||||
|
}
|
||||||
|
onPressed: (mouse) => updateFromX(mouse.x)
|
||||||
|
onPositionChanged: (mouse) => { if (pressed) updateFromX(mouse.x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-only live level gauge — same track styling as VolumeSlider but no
|
||||||
|
// handle/interaction, filled from an actual signal level instead of a
|
||||||
|
// configured value.
|
||||||
|
component LevelMeter: Item {
|
||||||
|
id: meterRoot
|
||||||
|
property real level: 0
|
||||||
|
implicitHeight: 4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.muted
|
||||||
|
opacity: 0.25
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.paletteColor(2)
|
||||||
|
width: parent.width * Math.max(0, Math.min(1, meterRoot.level))
|
||||||
|
Behavior on width { NumberAnimation { duration: 80 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component ToggleSwitch: Item {
|
||||||
|
id: toggleRoot
|
||||||
|
property bool checked: false
|
||||||
|
signal toggled()
|
||||||
|
implicitWidth: 34
|
||||||
|
implicitHeight: 18
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: toggleRoot.checked ? Colors.primary : Colors.muted
|
||||||
|
opacity: toggleRoot.checked ? 1 : 0.35
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
width: parent.height - 4
|
||||||
|
height: parent.height - 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.background
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: toggleRoot.checked ? parent.width - width - 2 : 2
|
||||||
|
Behavior on x { NumberAnimation { duration: Appearance.animationDuration } }
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: toggleRoot.toggled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component DeviceRow: Rectangle {
|
||||||
|
id: deviceRow
|
||||||
|
required property var node
|
||||||
|
required property string icon
|
||||||
|
required property bool active
|
||||||
|
signal activate()
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
height: 30
|
||||||
|
radius: 0
|
||||||
|
color: rowMouse.containsMouse ? Colors.primary
|
||||||
|
: (deviceRow.active ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent")
|
||||||
|
|
||||||
|
// Hover-only outline, offset outside the row rather than drawn on
|
||||||
|
// its own edge — same treatment as the other bar widgets' selectable
|
||||||
|
// rows (e.g. NetworkIndicator.qml's NetworkRow). Not inside a
|
||||||
|
// clipped Flickable here, so no inset needed on its container.
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -3
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: rowMouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
spacing: 8
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 18
|
||||||
|
Layout.minimumWidth: 18
|
||||||
|
Layout.maximumWidth: 18
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: deviceRow.icon
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.deviceLabel(deviceRow.node)
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
font.bold: deviceRow.active
|
||||||
|
color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: rowMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: deviceRow.activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Panel -----------------------------------------------------------
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: panel
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
// Padding between the panel's border and its content. implicitWidth
|
||||||
|
// is contentWidth + padding on both sides, so the content area
|
||||||
|
// itself stays a fixed size regardless of how much padding surrounds it.
|
||||||
|
readonly property int contentWidth: 244
|
||||||
|
readonly property int contentPadding: 16
|
||||||
|
implicitWidth: contentWidth + contentPadding * 2
|
||||||
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
window: root.barWindow
|
||||||
|
// Unlike anchor.item, anchor.window doesn't default rect to the
|
||||||
|
// window's own bounds — set it explicitly so edges/gravity below
|
||||||
|
// resolve against the full bar (and thus the true screen edges)
|
||||||
|
// instead of a near-zero rect at the window's origin.
|
||||||
|
rect.x: 0
|
||||||
|
rect.y: 0
|
||||||
|
rect.width: root.barWindow.width
|
||||||
|
rect.height: root.barWindow.height
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.bottom: -4
|
||||||
|
margins.right: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [panel]
|
||||||
|
onCleared: panel.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: panel.contentPadding - 2
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// Header
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: label.text
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 30
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "Audio"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleSwitch {
|
||||||
|
checked: !root.outputMuted
|
||||||
|
onToggled: if (root.sink && root.sink.audio) root.sink.audio.muted = !root.sink.audio.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "OUTPUT"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: Math.round(root.outputVolume * 100) + "%"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeSlider {
|
||||||
|
width: parent.width
|
||||||
|
value: root.outputVolume
|
||||||
|
enabled: !!root.sink
|
||||||
|
onMoved: (v) => { if (root.sink && root.sink.audio) root.sink.audio.volume = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelMeter {
|
||||||
|
width: parent.width
|
||||||
|
level: outputPeak.peak
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
Repeater {
|
||||||
|
model: root.candidateSinks
|
||||||
|
DeviceRow {
|
||||||
|
required property var modelData
|
||||||
|
node: modelData
|
||||||
|
icon: root.sinkIcon(modelData)
|
||||||
|
active: !!(root.sink && modelData && root.sink.id === modelData.id)
|
||||||
|
onActivate: Pipewire.preferredDefaultAudioSink = modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "INPUT"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: Math.round(root.inputVolume * 100) + "%"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeSlider {
|
||||||
|
width: parent.width
|
||||||
|
value: root.inputVolume
|
||||||
|
enabled: !!root.source
|
||||||
|
onMoved: (v) => { if (root.source && root.source.audio) root.source.audio.volume = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelMeter {
|
||||||
|
width: parent.width
|
||||||
|
level: inputPeak.peak
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 4
|
||||||
|
Repeater {
|
||||||
|
model: root.candidateSources
|
||||||
|
DeviceRow {
|
||||||
|
required property var modelData
|
||||||
|
node: modelData
|
||||||
|
icon: root.sourceIcon(modelData)
|
||||||
|
active: !!(root.source && modelData && root.source.id === modelData.id)
|
||||||
|
onActivate: Pipewire.preferredDefaultAudioSource = modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
594
dotfiles/.config/quickshell/modules/bar/VpnIndicator.qml
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Io
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
// A switcher between commercial VPN providers, distinct from
|
||||||
|
// TailscaleIndicator.qml — Tailscale is a mesh overlay network you generally
|
||||||
|
// leave running; these are traditional single-tunnel VPN clients where only
|
||||||
|
// one makes sense to have active at a time. Connecting one here disconnects
|
||||||
|
// the other first.
|
||||||
|
//
|
||||||
|
// V1 scope: connect (provider's own "fastest"/default) and disconnect per
|
||||||
|
// provider, live status, no region/server picker yet. Provider CLIs:
|
||||||
|
// - Mullvad: official `mullvad` CLI (mullvad-vpn-daemon package), has
|
||||||
|
// real JSON status output.
|
||||||
|
// - ProtonVPN: official `protonvpn` CLI (proton-vpn-cli package), plain-
|
||||||
|
// text status only — parsed defensively since its exact wording isn't
|
||||||
|
// guaranteed across versions.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 4
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
required property var barWindow
|
||||||
|
|
||||||
|
property int refreshIntervalSec: 20
|
||||||
|
readonly property int _refreshIntervalMs: Math.max(5, Math.min(3600, refreshIntervalSec)) * 1000
|
||||||
|
|
||||||
|
// Whether each CLI is on PATH at all. Starts optimistic so the panel
|
||||||
|
// doesn't flash "not installed" before the first `which` check lands.
|
||||||
|
property bool mullvadInstalled: true
|
||||||
|
property bool protonInstalled: true
|
||||||
|
|
||||||
|
// "disconnected" | "connecting" | "connected" | "disconnecting"
|
||||||
|
property string mullvadState: "disconnected"
|
||||||
|
property string mullvadDetail: ""
|
||||||
|
property string protonState: "disconnected"
|
||||||
|
property string protonDetail: ""
|
||||||
|
|
||||||
|
readonly property bool anyConnected: mullvadState === "connected" || protonState === "connected"
|
||||||
|
|
||||||
|
// Set while switching from one provider to the other: holds which one
|
||||||
|
// to connect once the current one has finished disconnecting.
|
||||||
|
property string pendingConnect: ""
|
||||||
|
|
||||||
|
// Surfaced under the header for a failed connect/disconnect; cleared
|
||||||
|
// automatically after a few seconds.
|
||||||
|
property string actionStatus: ""
|
||||||
|
|
||||||
|
function shortLine(text) {
|
||||||
|
const line = String(text || "").trim().split("\n")[0] || ""
|
||||||
|
return line.length > 80 ? line.substring(0, 77) + "…" : line
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyMullvadStatus(text) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(text)
|
||||||
|
const state = String(data.state || "disconnected")
|
||||||
|
const loc = data.details && data.details.location
|
||||||
|
root.mullvadState = state
|
||||||
|
root.mullvadDetail = loc ? [loc.city, loc.country].filter(Boolean).join(", ") : ""
|
||||||
|
} catch (e) {
|
||||||
|
root.mullvadState = "disconnected"
|
||||||
|
root.mullvadDetail = ""
|
||||||
|
}
|
||||||
|
VpnExclusivity.mullvadConnected = root.mullvadState === "connected"
|
||||||
|
}
|
||||||
|
|
||||||
|
// No --json here — ProtonVPN's CLI only prints plain text, so this
|
||||||
|
// just looks for a "Status: …" line and, best-effort, a following
|
||||||
|
// "Server:"/"Country:" line if the CLI happens to print one.
|
||||||
|
function applyProtonStatus(text) {
|
||||||
|
const body = String(text || "")
|
||||||
|
const statusMatch = body.match(/^Status:\s*(.+)$/mi)
|
||||||
|
const raw = statusMatch ? statusMatch[1].trim().toLowerCase() : ""
|
||||||
|
root.protonState = raw.indexOf("connected") === 0 ? "connected" : "disconnected"
|
||||||
|
const serverMatch = body.match(/^Server:\s*(.+)$/mi)
|
||||||
|
const countryMatch = body.match(/^Country:\s*(.+)$/mi)
|
||||||
|
root.protonDetail = serverMatch ? serverMatch[1].trim() : (countryMatch ? countryMatch[1].trim() : "")
|
||||||
|
VpnExclusivity.protonConnected = root.protonState === "connected"
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshMullvad() {
|
||||||
|
if (!root.mullvadInstalled) {
|
||||||
|
if (!mullvadWhichProc.running) mullvadWhichProc.running = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!mullvadStatusProc.running) {
|
||||||
|
mullvadStatusProc.running = true
|
||||||
|
mullvadPollWatchdog.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshProton() {
|
||||||
|
if (!root.protonInstalled) {
|
||||||
|
if (!protonWhichProc.running) protonWhichProc.running = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!protonStatusProc.running) {
|
||||||
|
protonStatusProc.running = true
|
||||||
|
protonPollWatchdog.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
root.refreshMullvad()
|
||||||
|
root.refreshProton()
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectMullvad() {
|
||||||
|
if (mullvadConnectProc.running || mullvadDisconnectProc.running) return
|
||||||
|
if (root.protonState !== "disconnected") {
|
||||||
|
root.pendingConnect = "mullvad"
|
||||||
|
root.disconnectProton()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root.pendingConnect = ""
|
||||||
|
mullvadConnectProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectProton() {
|
||||||
|
if (protonConnectProc.running || protonDisconnectProc.running) return
|
||||||
|
if (root.mullvadState !== "disconnected") {
|
||||||
|
root.pendingConnect = "protonvpn"
|
||||||
|
root.disconnectMullvad()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root.pendingConnect = ""
|
||||||
|
protonConnectProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectMullvad() {
|
||||||
|
if (mullvadDisconnectProc.running) return
|
||||||
|
mullvadDisconnectProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnectProton() {
|
||||||
|
if (protonDisconnectProc.running) return
|
||||||
|
protonDisconnectProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMullvad() {
|
||||||
|
if (mullvadConnectProc.running || mullvadDisconnectProc.running) return
|
||||||
|
if (root.mullvadState === "connected") root.disconnectMullvad()
|
||||||
|
else root.connectMullvad()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleProton() {
|
||||||
|
if (protonConnectProc.running || protonDisconnectProc.running) return
|
||||||
|
if (root.protonState === "connected") root.disconnectProton()
|
||||||
|
else root.connectProton()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tailscale fights Mullvad/ProtonVPN for the default route/DNS, so fire
|
||||||
|
// this right after either one finishes connecting — a harmless no-op
|
||||||
|
// if Tailscale was already down. TailscaleIndicator.qml also backs
|
||||||
|
// itself off reactively (via VpnExclusivity) as a backstop, but doing
|
||||||
|
// it here too avoids waiting out its poll interval.
|
||||||
|
Process {
|
||||||
|
id: tailscaleDownProc
|
||||||
|
command: ["tailscale", "down"]
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Mullvad ---------------------------------------------------------
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: mullvadWhichProc
|
||||||
|
command: ["which", "mullvad"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
root.mullvadInstalled = exitCode === 0
|
||||||
|
if (root.mullvadInstalled) root.refreshMullvad()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: mullvadStatusProc
|
||||||
|
command: ["mullvad", "status", "--json"]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
id: mullvadStatusCollector
|
||||||
|
onStreamFinished: root.applyMullvadStatus(mullvadStatusCollector.text)
|
||||||
|
}
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0 && !mullvadWhichProc.running) mullvadWhichProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: mullvadConnectProc
|
||||||
|
command: ["mullvad", "connect", "--wait"]
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector { id: mullvadConnectErr }
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.actionStatus = "Mullvad: " + root.shortLine(mullvadConnectErr.text || "connect failed")
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
} else if (!tailscaleDownProc.running) {
|
||||||
|
tailscaleDownProc.running = true
|
||||||
|
}
|
||||||
|
root.refreshMullvad()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: mullvadDisconnectProc
|
||||||
|
command: ["mullvad", "disconnect", "--wait"]
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector { id: mullvadDisconnectErr }
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.actionStatus = "Mullvad: " + root.shortLine(mullvadDisconnectErr.text || "disconnect failed")
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
}
|
||||||
|
root.refreshMullvad()
|
||||||
|
if (root.pendingConnect === "mullvad") { root.pendingConnect = ""; root.connectMullvad() }
|
||||||
|
else if (root.pendingConnect === "protonvpn") { root.pendingConnect = ""; root.connectProton() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: mullvadPollWatchdog
|
||||||
|
interval: 15000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: if (mullvadStatusProc.running) mullvadStatusProc.running = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ProtonVPN ---------------------------------------------------------
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: protonWhichProc
|
||||||
|
command: ["which", "protonvpn"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
root.protonInstalled = exitCode === 0
|
||||||
|
if (root.protonInstalled) root.refreshProton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: protonStatusProc
|
||||||
|
command: ["protonvpn", "status"]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
id: protonStatusCollector
|
||||||
|
onStreamFinished: root.applyProtonStatus(protonStatusCollector.text)
|
||||||
|
}
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0 && !protonWhichProc.running) protonWhichProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: protonConnectProc
|
||||||
|
command: ["protonvpn", "connect"]
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector { id: protonConnectErr }
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.actionStatus = "ProtonVPN: " + root.shortLine(protonConnectErr.text || "connect failed")
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
} else if (!tailscaleDownProc.running) {
|
||||||
|
tailscaleDownProc.running = true
|
||||||
|
}
|
||||||
|
root.refreshProton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: protonDisconnectProc
|
||||||
|
command: ["protonvpn", "disconnect"]
|
||||||
|
stdout: StdioCollector {}
|
||||||
|
stderr: StdioCollector { id: protonDisconnectErr }
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.actionStatus = "ProtonVPN: " + root.shortLine(protonDisconnectErr.text || "disconnect failed")
|
||||||
|
actionStatusTimer.restart()
|
||||||
|
}
|
||||||
|
root.refreshProton()
|
||||||
|
if (root.pendingConnect === "mullvad") { root.pendingConnect = ""; root.connectMullvad() }
|
||||||
|
else if (root.pendingConnect === "protonvpn") { root.pendingConnect = ""; root.connectProton() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: protonPollWatchdog
|
||||||
|
interval: 15000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: if (protonStatusProc.running) protonStatusProc.running = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Shared timers -----------------------------------------------------
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: refreshTimer
|
||||||
|
interval: root._refreshIntervalMs
|
||||||
|
repeat: true
|
||||||
|
running: true
|
||||||
|
triggeredOnStart: true
|
||||||
|
onTriggered: root.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: actionStatusTimer
|
||||||
|
interval: 4000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.actionStatus = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Bar icon ------------------------------------------------------------
|
||||||
|
|
||||||
|
// A fixed, wallpaper-independent green rather than Colors.primary — the
|
||||||
|
// glyph itself doesn't change shape between states (unlike Tailscale's
|
||||||
|
// crossed-out logo), so "connected" needs to read as a shape cue (a
|
||||||
|
// badge appearing) rather than rely on a color swap that can end up
|
||||||
|
// low-contrast depending on the current pywal palette.
|
||||||
|
readonly property color connectedBadgeColor: "#3ddc84"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: Appearance.iconSize
|
||||||
|
color: root.anyConnected ? Colors.primary : Colors.muted
|
||||||
|
text: "vpn_lock"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Small solid dot badge, bottom-right of the glyph, shown only while a
|
||||||
|
// tunnel is actually up — a shape appearing/disappearing reads at a
|
||||||
|
// glance even when the icon tint alone wouldn't stand out.
|
||||||
|
Rectangle {
|
||||||
|
visible: root.anyConnected
|
||||||
|
width: 6
|
||||||
|
height: 6
|
||||||
|
radius: 3
|
||||||
|
color: root.connectedBadgeColor
|
||||||
|
border.color: Colors.background
|
||||||
|
border.width: 1
|
||||||
|
anchors.right: label.right
|
||||||
|
anchors.bottom: label.bottom
|
||||||
|
anchors.rightMargin: 0
|
||||||
|
anchors.bottomMargin: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
panel.visible = !panel.visible
|
||||||
|
grab.active = panel.visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Reusable pieces -----------------------------------------------------
|
||||||
|
|
||||||
|
component ToggleSwitch: Item {
|
||||||
|
id: toggleRoot
|
||||||
|
property bool checked: false
|
||||||
|
property bool busy: false
|
||||||
|
signal toggled()
|
||||||
|
implicitWidth: 34
|
||||||
|
implicitHeight: 18
|
||||||
|
opacity: toggleRoot.enabled ? 1 : 0.4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: toggleRoot.checked ? Colors.primary : Colors.muted
|
||||||
|
opacity: (toggleRoot.checked ? 1 : 0.35) * (toggleRoot.busy ? 0.6 : 1)
|
||||||
|
}
|
||||||
|
// Hover-only outline, offset outside the switch itself rather than
|
||||||
|
// drawn on its edge — the switch lags behind a click until the
|
||||||
|
// connect/disconnect process actually finishes, so this is just a
|
||||||
|
// "you can click this" cue, not click feedback. toggleMouse.containsMouse
|
||||||
|
// is already false while busy, since a disabled MouseArea doesn't
|
||||||
|
// track hover.
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: -4
|
||||||
|
radius: 0
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Colors.foreground
|
||||||
|
border.width: toggleMouse.containsMouse ? 1 : 0
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
width: parent.height - 4
|
||||||
|
height: parent.height - 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.background
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: toggleRoot.checked ? parent.width - width - 2 : 2
|
||||||
|
Behavior on x { NumberAnimation { duration: Appearance.animationDuration } }
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
id: toggleMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !toggleRoot.busy
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: toggleRoot.busy ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||||
|
onClicked: toggleRoot.toggled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A single provider's row — icon, name, live status line, and a toggle
|
||||||
|
// that connects/disconnects it (routed back through root so it can
|
||||||
|
// enforce the one-provider-at-a-time rule).
|
||||||
|
component ProviderRow: Rectangle {
|
||||||
|
id: provRow
|
||||||
|
property string label: ""
|
||||||
|
property string subIcon: "shield"
|
||||||
|
property string detailText: ""
|
||||||
|
property string state: "disconnected"
|
||||||
|
property bool installed: true
|
||||||
|
signal toggle()
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: rowContent.implicitHeight + 12
|
||||||
|
color: provRow.state === "connected"
|
||||||
|
? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18)
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rowContent
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: 6
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
Layout.minimumWidth: 20
|
||||||
|
Layout.maximumWidth: 20
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: provRow.subIcon
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 14
|
||||||
|
color: provRow.state === "connected" ? Colors.primary : Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: provRow.label
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
font.bold: provRow.state === "connected"
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: !provRow.installed ? "Not installed"
|
||||||
|
: provRow.state === "connecting" ? "Connecting…"
|
||||||
|
: provRow.state === "disconnecting" ? "Disconnecting…"
|
||||||
|
: provRow.state === "connected" ? (provRow.detailText || "Connected")
|
||||||
|
: "Disconnected"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleSwitch {
|
||||||
|
enabled: provRow.installed
|
||||||
|
checked: provRow.state === "connected" || provRow.state === "connecting"
|
||||||
|
busy: provRow.state === "connecting" || provRow.state === "disconnecting"
|
||||||
|
onToggled: provRow.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Panel -----------------------------------------------------------
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: panel
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
readonly property int contentWidth: 244
|
||||||
|
readonly property int contentPadding: 16
|
||||||
|
implicitWidth: contentWidth + contentPadding * 2
|
||||||
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
NumberAnimation { duration: Appearance.animationDuration; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChanged: if (visible) root.refresh()
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
window: root.barWindow
|
||||||
|
rect.x: 0
|
||||||
|
rect.y: 0
|
||||||
|
rect.width: root.barWindow.width
|
||||||
|
rect.height: root.barWindow.height
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.bottom: -4
|
||||||
|
margins.right: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [panel]
|
||||||
|
onCleared: panel.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: mainColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: panel.contentPadding
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "vpn_lock"
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 22
|
||||||
|
color: root.anyConnected ? Colors.primary : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "VPN"
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: root.actionStatus !== ""
|
||||||
|
width: parent.width
|
||||||
|
text: root.actionStatus
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
ProviderRow {
|
||||||
|
label: "Mullvad"
|
||||||
|
subIcon: "gpp_good"
|
||||||
|
state: root.mullvadState
|
||||||
|
detailText: root.mullvadDetail
|
||||||
|
installed: root.mullvadInstalled
|
||||||
|
onToggle: root.toggleMullvad()
|
||||||
|
}
|
||||||
|
ProviderRow {
|
||||||
|
label: "ProtonVPN"
|
||||||
|
subIcon: "gpp_good"
|
||||||
|
state: root.protonState
|
||||||
|
detailText: root.protonDetail
|
||||||
|
installed: root.protonInstalled
|
||||||
|
onToggle: root.toggleProton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: "Connecting one disconnects the other — only one VPN tunnel at a time."
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
dotfiles/.config/quickshell/modules/bar/Workspaces.qml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
property var screen
|
||||||
|
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hyprland.workspaces
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: pill
|
||||||
|
required property var modelData
|
||||||
|
visible: modelData.monitor && root.screen && modelData.monitor.name === root.screen.name
|
||||||
|
|
||||||
|
implicitWidth: 26
|
||||||
|
implicitHeight: 22
|
||||||
|
radius: Appearance.radiusSmall
|
||||||
|
color: modelData.urgent ? Colors.urgent
|
||||||
|
: modelData.active ? Colors.primary
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: Appearance.animationDuration } }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: modelData.name
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: modelData.active ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: Hyprland.dispatch("workspace " + modelData.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
125
dotfiles/.config/quickshell/modules/osd/VolumeOsd.qml
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: osd
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
exclusiveZone: 0
|
||||||
|
|
||||||
|
// Top-right, just under the bar — same fixed distance from the bar and
|
||||||
|
// screen edge (Appearance.spacing) that every popup opened from the bar
|
||||||
|
// itself uses, so this lines up with them instead of floating
|
||||||
|
// bottom-center.
|
||||||
|
anchors { top: true; right: true }
|
||||||
|
margins.top: Appearance.spacing
|
||||||
|
margins.right: Appearance.spacing
|
||||||
|
|
||||||
|
implicitWidth: 272
|
||||||
|
implicitHeight: 54
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.namespace: "quickshell:osd"
|
||||||
|
|
||||||
|
readonly property var sink: Pipewire.defaultAudioSink
|
||||||
|
PwObjectTracker { objects: osd.sink ? [osd.sink] : [] }
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hideTimer
|
||||||
|
interval: 1400
|
||||||
|
onTriggered: osd.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: osd.sink ? osd.sink.audio : null
|
||||||
|
function onVolumeChanged() { osd.visible = true; hideTimer.restart() }
|
||||||
|
function onMutedChanged() { osd.visible = true; hideTimer.restart() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.radius
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 14
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
font.family: Appearance.iconFontFamilyRounded
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 18
|
||||||
|
color: Colors.foreground
|
||||||
|
text: {
|
||||||
|
const audio = osd.sink ? osd.sink.audio : null
|
||||||
|
if (!audio || audio.muted || audio.volume <= 0) return "volume_off"
|
||||||
|
return audio.volume < 0.5 ? "volume_down" : "volume_up"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: slider
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: 16
|
||||||
|
|
||||||
|
readonly property real value: osd.sink && osd.sink.audio ? osd.sink.audio.volume : 0
|
||||||
|
readonly property bool enabled: !!osd.sink
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: track
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.muted
|
||||||
|
opacity: 0.35
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: track.width * Math.max(0, Math.min(1, slider.value))
|
||||||
|
height: 4
|
||||||
|
radius: 0
|
||||||
|
color: Colors.primary
|
||||||
|
opacity: slider.enabled ? 1 : 0.4
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
width: 12
|
||||||
|
height: 12
|
||||||
|
radius: 6
|
||||||
|
color: Colors.primary
|
||||||
|
opacity: slider.enabled ? 1 : 0.4
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: Math.max(0, Math.min(track.width - width, track.width * slider.value - width / 2))
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: slider.enabled
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
function updateFromX(mx) {
|
||||||
|
if (!osd.sink || !osd.sink.audio) return
|
||||||
|
osd.sink.audio.volume = Math.max(0, Math.min(1, mx / track.width))
|
||||||
|
}
|
||||||
|
onPressed: (mouse) => updateFromX(mouse.x)
|
||||||
|
onPositionChanged: (mouse) => { if (pressed) updateFromX(mouse.x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 32
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
text: Math.round(slider.value * 100) + "%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
259
dotfiles/.config/quickshell/scripts/CheckQuickshellSetup.sh
Executable file
@@ -0,0 +1,259 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Pre-flight check for everything this quickshell config depends on outside
|
||||||
|
# its own QML — fonts, the compositor, backing D-Bus services, and the
|
||||||
|
# external CLIs individual bar modules shell out to. Run this after
|
||||||
|
# installing/stowing quickshell on a new machine, before assuming the bar
|
||||||
|
# is just going to work.
|
||||||
|
#
|
||||||
|
# Usage: ./CheckQuickshellSetup.sh [path-to-quickshell-config]
|
||||||
|
# Defaults to $XDG_CONFIG_HOME/quickshell or ~/.config/quickshell.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
QS_DIR="${1:-${XDG_CONFIG_HOME:-$HOME/.config}/quickshell}"
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
WARN=0
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
c_green="\033[0;32m"; c_yellow="\033[0;33m"; c_red="\033[0;31m"; c_reset="\033[0m"
|
||||||
|
|
||||||
|
pass() { printf " ${c_green}✓${c_reset} %s\n" "$1"; PASS=$((PASS+1)); }
|
||||||
|
warn() { printf " ${c_yellow}!${c_reset} %s\n" "$1"; WARN=$((WARN+1)); }
|
||||||
|
fail() { printf " ${c_red}✗${c_reset} %s\n" "$1"; FAIL=$((FAIL+1)); }
|
||||||
|
section() { printf "\n%s\n" "$1"; }
|
||||||
|
|
||||||
|
svc_state() {
|
||||||
|
# active / inactive / missing / no-systemctl. $1 = unit, $2 = --user (optional)
|
||||||
|
# NB: capture-then-here-string, not `cmd | grep -q`. Under `set -o
|
||||||
|
# pipefail`, grep -q exits the instant it finds a match, SIGPIPE-ing a
|
||||||
|
# still-writing producer — that producer's non-zero exit (not grep's
|
||||||
|
# success) becomes the pipeline's status, which reads as "not found"
|
||||||
|
# even when it was. Verified this actually happens with fc-list below.
|
||||||
|
if ! command -v systemctl >/dev/null 2>&1; then echo "no-systemctl"; return; fi
|
||||||
|
local unit_files
|
||||||
|
unit_files=$(systemctl ${2:-} list-unit-files "$1" 2>/dev/null)
|
||||||
|
if grep -q "$1" <<< "$unit_files"; then
|
||||||
|
systemctl ${2:-} is-active "$1" 2>/dev/null || echo "inactive"
|
||||||
|
else
|
||||||
|
echo "missing"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 0. Quickshell itself + config files present ----------------------------
|
||||||
|
|
||||||
|
section "Quickshell core"
|
||||||
|
|
||||||
|
if command -v quickshell >/dev/null 2>&1; then
|
||||||
|
ver=$(quickshell --version 2>&1 | head -1)
|
||||||
|
pass "quickshell found ($(command -v quickshell)) — $ver"
|
||||||
|
else
|
||||||
|
fail "quickshell binary not found on PATH — install it before anything else here matters"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for f in "shell.qml" "config/Appearance.qml" "config/Colors.qml" "config/qmldir"; do
|
||||||
|
if [ -f "$QS_DIR/$f" ]; then
|
||||||
|
pass "found $f"
|
||||||
|
else
|
||||||
|
fail "missing $QS_DIR/$f — dotfiles not fully stowed/symlinked here?"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Nearly every module (ActiveWindow, Workspaces, PowerButton, PanelWindow's
|
||||||
|
# layer-shell surfaces, HyprlandFocusGrab) assumes a live Hyprland session.
|
||||||
|
if [ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ] && command -v hyprctl >/dev/null 2>&1 && hyprctl monitors >/dev/null 2>&1; then
|
||||||
|
pass "Hyprland is the running compositor"
|
||||||
|
else
|
||||||
|
fail "Hyprland doesn't appear to be running — Quickshell.Hyprland and the layer-shell bar will not function"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 1. Fonts -----------------------------------------------------------------
|
||||||
|
|
||||||
|
section "Fonts"
|
||||||
|
|
||||||
|
if command -v fc-list >/dev/null 2>&1; then
|
||||||
|
# Captured once, then grepped via here-string — see the pipefail/SIGPIPE
|
||||||
|
# note on svc_state() above; fc-list's output is exactly what triggers it.
|
||||||
|
fc_out=$(fc-list)
|
||||||
|
|
||||||
|
if grep -qi "Material Symbols Outlined" <<< "$fc_out"; then
|
||||||
|
pass "Material Symbols Outlined installed"
|
||||||
|
else
|
||||||
|
fail "Material Symbols Outlined not found — install 'ttf-material-symbols-variable' (AUR); every glyph icon in the bar/panels will render as fallback text without it"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -qi "CaskaydiaCove Nerd Font Mono" <<< "$fc_out"; then
|
||||||
|
pass "CaskaydiaCove Nerd Font Mono installed"
|
||||||
|
else
|
||||||
|
fail "CaskaydiaCove Nerd Font Mono not found — install a Cascadia Code Nerd Font package; clock/labels/window title use it"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "fc-list not found (fontconfig missing?) — can't verify fonts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 2. Backing services for native Quickshell modules ----------------------
|
||||||
|
# These modules talk to system services directly over D-Bus rather than
|
||||||
|
# shelling out — the service being up is the actual dependency, not a CLI.
|
||||||
|
|
||||||
|
section "Backing services (native QML modules)"
|
||||||
|
|
||||||
|
st=$(svc_state NetworkManager.service)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "NetworkManager.service active — Quickshell.Networking (NetworkIndicator)" ;;
|
||||||
|
missing) fail "NetworkManager not installed — required by NetworkIndicator.qml" ;;
|
||||||
|
*) fail "NetworkManager.service is $st — run: sudo systemctl enable --now NetworkManager" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
st=$(svc_state bluetooth.service)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "bluetooth.service active — Quickshell.Bluetooth (BluetoothIndicator)" ;;
|
||||||
|
missing) fail "bluez not installed — required by BluetoothIndicator.qml" ;;
|
||||||
|
*) fail "bluetooth.service is $st — run: sudo systemctl enable --now bluetooth" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Pipewire/wireplumber are user-session services, not system ones.
|
||||||
|
st=$(svc_state pipewire.service --user)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "pipewire.service (user) active — Quickshell.Services.Pipewire (Volume/VolumeOsd)" ;;
|
||||||
|
missing) fail "pipewire not installed — required by Volume.qml/VolumeOsd.qml" ;;
|
||||||
|
*) fail "pipewire.service (user) is $st — run: systemctl --user enable --now pipewire pipewire-pulse wireplumber" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
st=$(svc_state wireplumber.service --user)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "wireplumber.service (user) active" ;;
|
||||||
|
missing) warn "wireplumber not installed — pipewire falls back to pipewire-media-session if present, otherwise volume control may misbehave" ;;
|
||||||
|
*) fail "wireplumber.service (user) is $st — run: systemctl --user enable --now wireplumber" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- 3. External CLIs shelled out to via Process ----------------------------
|
||||||
|
|
||||||
|
section "External CLIs (Quickshell.Io Process calls)"
|
||||||
|
|
||||||
|
check_bin() {
|
||||||
|
# $1 = binary, $2 = which module(s) use it, $3 = fail|warn on missing
|
||||||
|
if command -v "$1" >/dev/null 2>&1; then
|
||||||
|
pass "$1 found — used by $2"
|
||||||
|
elif [ "$3" = "warn" ]; then
|
||||||
|
warn "$1 not found — used by $2 (optional on this machine)"
|
||||||
|
else
|
||||||
|
fail "$1 not found — used by $2"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_bin nmcli "NetworkIndicator.qml (DNS provider panel, connection queries)" fail
|
||||||
|
check_bin ip "NetworkIndicator.qml (gateway/IP lookups)" fail
|
||||||
|
check_bin ping "NetworkIndicator.qml (latency/packet-loss stat)" fail
|
||||||
|
check_bin cat "NetworkIndicator.qml (/sys/class/net throughput counters)" fail
|
||||||
|
check_bin systemctl "PowerButton.qml (suspend/hibernate/reboot/poweroff)" fail
|
||||||
|
check_bin tailscale "TailscaleIndicator.qml / VpnExclusivity" warn
|
||||||
|
check_bin mullvad "VpnIndicator.qml / VpnExclusivity" warn
|
||||||
|
check_bin protonvpn "VpnIndicator.qml / VpnExclusivity" warn
|
||||||
|
|
||||||
|
have_tailscale=0; have_mullvad=0; have_proton=0
|
||||||
|
command -v tailscale >/dev/null 2>&1 && have_tailscale=1
|
||||||
|
command -v mullvad >/dev/null 2>&1 && have_mullvad=1
|
||||||
|
command -v protonvpn >/dev/null 2>&1 && have_proton=1
|
||||||
|
|
||||||
|
if [ $have_mullvad -eq 0 ] && [ $have_proton -eq 0 ]; then
|
||||||
|
warn "neither Mullvad nor ProtonVPN CLI is installed — VpnIndicator.qml will show both as 'Not installed'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 4. VPN daemons + functional status (Mullvad/ProtonVPN/Tailscale) -------
|
||||||
|
# The exclusivity logic (VpnExclusivity.qml backing off Tailscale when a
|
||||||
|
# commercial VPN connects) is pure QML and ships with the dotfiles — it
|
||||||
|
# needs no setup of its own. What varies per machine is whether these three
|
||||||
|
# are actually installed, enabled, and callable without a password prompt.
|
||||||
|
|
||||||
|
section "VPN dual-setup (Mullvad/ProtonVPN + Tailscale)"
|
||||||
|
|
||||||
|
if [ $have_tailscale -eq 1 ]; then
|
||||||
|
st=$(svc_state tailscaled.service)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "tailscaled.service is active" ;;
|
||||||
|
missing) fail "tailscaled.service not found — reinstall tailscale" ;;
|
||||||
|
*) fail "tailscaled.service is $st — run: sudo systemctl enable --now tailscaled" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if out=$(timeout 5 tailscale status --json 2>&1); then
|
||||||
|
if python3 -c "import json,sys; json.load(sys.stdin)" >/dev/null 2>&1 <<< "$out"; then
|
||||||
|
pass "tailscale status --json returns valid JSON"
|
||||||
|
else
|
||||||
|
warn "tailscale status --json returned non-JSON output"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "tailscale status --json failed: $(echo "$out" | head -1)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $have_mullvad -eq 1 ]; then
|
||||||
|
st=$(svc_state mullvad-daemon.service)
|
||||||
|
case "$st" in
|
||||||
|
active) pass "mullvad-daemon.service is active" ;;
|
||||||
|
missing) fail "mullvad-daemon.service not found — reinstall the Mullvad package" ;;
|
||||||
|
*) fail "mullvad-daemon.service is $st — run: sudo systemctl enable --now mullvad-daemon" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if out=$(timeout 5 mullvad status --json 2>&1); then
|
||||||
|
if python3 -c "import json,sys; json.load(sys.stdin)" >/dev/null 2>&1 <<< "$out"; then
|
||||||
|
pass "mullvad status --json returns valid JSON"
|
||||||
|
else
|
||||||
|
warn "mullvad status --json returned non-JSON output"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "mullvad status --json failed: $(echo "$out" | head -1)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $have_proton -eq 1 ]; then
|
||||||
|
# ProtonVPN's CLI drives connections through NetworkManager rather than
|
||||||
|
# its own daemon — already checked above, just re-verified here in context.
|
||||||
|
if out=$(timeout 5 protonvpn status 2>&1); then
|
||||||
|
if grep -qi "^Status:" <<< "$out"; then
|
||||||
|
pass "protonvpn status returns a parseable 'Status:' line"
|
||||||
|
else
|
||||||
|
warn "protonvpn status has no 'Status:' line — applyProtonStatus() in VpnIndicator.qml may misread it: $(echo "$out" | head -1)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "protonvpn status failed: $(echo "$out" | head -1)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ts_up=0; mv_up=0; pv_up=0
|
||||||
|
# Same capture-then-here-string reasoning as above — these outputs are small
|
||||||
|
# enough that the SIGPIPE race is unlikely, but there's no upside to relying
|
||||||
|
# on that instead of just being consistent.
|
||||||
|
[ $have_tailscale -eq 1 ] && grep -q '"BackendState":"Running"' <<< "$(tailscale status --json 2>/dev/null)" && ts_up=1
|
||||||
|
[ $have_mullvad -eq 1 ] && grep -qi "^Connected" <<< "$(mullvad status 2>/dev/null)" && mv_up=1
|
||||||
|
[ $have_proton -eq 1 ] && grep -qi "^Status:\s*Connected" <<< "$(protonvpn status 2>/dev/null)" && pv_up=1
|
||||||
|
|
||||||
|
active_count=$((ts_up + mv_up + pv_up))
|
||||||
|
if [ $active_count -le 1 ]; then
|
||||||
|
pass "at most one tunnel active right now (tailscale=$ts_up mullvad=$mv_up protonvpn=$pv_up)"
|
||||||
|
else
|
||||||
|
warn "more than one tunnel is up right now (tailscale=$ts_up mullvad=$mv_up protonvpn=$pv_up) — bring extras down manually; quickshell only enforces exclusivity when you toggle from its own UI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 5. System tray (currently disabled in Bar.qml) -------------------------
|
||||||
|
|
||||||
|
section "System tray (Tray.qml)"
|
||||||
|
|
||||||
|
if grep -q "^\s*//\s*Tray\s*{}" "$QS_DIR/modules/bar/Bar.qml" 2>/dev/null; then
|
||||||
|
warn "Tray {} is commented out in Bar.qml — skipping icon-theme check (nothing to render)"
|
||||||
|
elif [ -f "$QS_DIR/modules/bar/Bar.qml" ]; then
|
||||||
|
if command -v gtk-update-icon-cache >/dev/null 2>&1 || [ -d /usr/share/icons/hicolor ]; then
|
||||||
|
pass "an icon theme (at least hicolor) is present for Quickshell.Services.SystemTray icon lookups"
|
||||||
|
else
|
||||||
|
warn "no icon theme found — tray icons may render blank"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Summary -----------------------------------------------------------------
|
||||||
|
|
||||||
|
section "Summary"
|
||||||
|
printf " ${c_green}%d passed${c_reset}, ${c_yellow}%d warnings${c_reset}, ${c_red}%d failed${c_reset}\n" "$PASS" "$WARN" "$FAIL"
|
||||||
|
|
||||||
|
if [ $FAIL -gt 0 ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
16
dotfiles/.config/quickshell/shell.qml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Quickshell
|
||||||
|
import "./modules/bar"
|
||||||
|
import "./modules/osd"
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
Bar {
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeOsd {}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "/etc/xdg/swaync/configSchema.json",
|
"$schema": "/etc/xdg/swaync/configSchema.json",
|
||||||
"positionX": "right",
|
"positionX": "left",
|
||||||
"positionY": "top",
|
"positionY": "top",
|
||||||
"layer": "overlay",
|
"layer": "overlay",
|
||||||
"control-center-layer": "top",
|
"control-center-layer": "top",
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"modules-left": ["battery", "clock#date", "clock","custom/updater", "custom/launcher"],
|
"modules-left": ["custom/notification", "battery", "clock#date", "clock","custom/updater", "custom/launcher"],
|
||||||
"modules-center": ["hyprland/workspaces"],
|
"modules-center": ["hyprland/workspaces"],
|
||||||
"modules-right": ["network", "bluetooth", "pulseaudio", "custom/power"],
|
"modules-right": ["network", "bluetooth", "wireplumber", "wireplumber#microphone", "custom/power"],
|
||||||
|
|
||||||
"sway/mode": {
|
"sway/mode": {
|
||||||
"format": "<span style=\"italic\">{}</span>"
|
"format": "<span style=\"italic\">{}</span>"
|
||||||
},
|
},
|
||||||
"network": {
|
"network": {
|
||||||
"format-wifi": "<span color='#962fb5'>{icon} </span>{essid} ({signalStrength}%)",
|
"format-wifi": "<span color='#962fb5'>{icon}<span letter_spacing='500'> </span></span>{essid}({signalStrength}%)",
|
||||||
"format-ethernet": "<span color='#962fb5'> </span>Ethernet",
|
"format-ethernet": "<span color='#962fb5'font='bold'>{icon}<span letter_spacing='500'> </span></span><span rise='1000'>Ethernet</span>",
|
||||||
"format-disconnected": " Not Connected",
|
"format-disconnected": "<span letter_spacing='500'> </span><span rise='1000'>Not Connected</span>",
|
||||||
"tooltip-format": "{ipaddr} via {gwaddr}",
|
"tooltip-format": "{ipaddr} via {gwaddr}",
|
||||||
"tooltip-format-disconnected": "Disconnected",
|
"tooltip-format-disconnected": "Disconnected",
|
||||||
"max-length": 50,
|
"max-length": 50,
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"on-click-right": "kitty -e nmtui",
|
"on-click-right": "kitty -e nmtui",
|
||||||
"format-icons": {
|
"format-icons": {
|
||||||
"wifi": ["", "", "", "", ""],
|
"wifi": ["", "", "", "", ""],
|
||||||
"ethernet": "",
|
"ethernet": "",
|
||||||
"disconnected": ""
|
"disconnected": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -33,10 +33,10 @@
|
|||||||
"spacing": 10
|
"spacing": 10
|
||||||
},
|
},
|
||||||
"clock": {
|
"clock": {
|
||||||
"format": " {:%H:%M}"
|
"format": " <span rise='300'>{:%H:%M}</span>"
|
||||||
},
|
},
|
||||||
"clock#date": {
|
"clock#date": {
|
||||||
"format": " {:%A, %B %d, %Y}",
|
"format": " <span rise='300'>{:%A, %B %d, %Y}</span>",
|
||||||
"tooltip-format": "<tt><small>{calendar}</small></tt>",
|
"tooltip-format": "<tt><small>{calendar}</small></tt>",
|
||||||
"calendar": {
|
"calendar": {
|
||||||
"mode" : "year",
|
"mode" : "year",
|
||||||
@@ -55,27 +55,30 @@
|
|||||||
"on-click-right": "mode"
|
"on-click-right": "mode"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pulseaudio": {
|
"wireplumber": {
|
||||||
"format": "{icon} {volume}% {format_source}",
|
"format": "<span rise='300'>{icon}</span>{volume}%",
|
||||||
"format-muted": " {format_source}",
|
"format-muted": "",
|
||||||
"format-bluetooth": "{icon} {volume}% {format_source}",
|
"format-bluetooth": "{icon}{volume}%",
|
||||||
"format-bluetooth-muted": " {format_source}",
|
"format-bluetooth-muted": "",
|
||||||
"format-source": " {volume}%",
|
"format-icons": [
|
||||||
"format-source-muted": " {volume}%",
|
"<span color='#808080'><span letter_spacing='500'> </span></span>",
|
||||||
"format-icons": {
|
"<span color='#ffff66'><span letter_spacing='500'> </span></span>",
|
||||||
"default": [
|
"<span color='#00ff7f'><span letter_spacing='3000'> </span></span>"
|
||||||
"<span color='#808080'></span>",
|
],
|
||||||
"<span color='#ffff66'></span>",
|
"on-click": "pwvucontrol"
|
||||||
"<span color='#00ff7f'> </span>"]
|
|
||||||
},
|
},
|
||||||
"on-click": "pavucontrol"
|
"wireplumber#microphone": {
|
||||||
|
"node-type": "Audio/Source",
|
||||||
|
"format": "<span letter_spacing='100'> </span><span rise='300'>{volume}%</span>",
|
||||||
|
"format-muted": "<span letter_spacing='2000'> </span>{volume}%",
|
||||||
|
"on-click": "pwvucontrol"
|
||||||
},
|
},
|
||||||
"bluetooth": {
|
"bluetooth": {
|
||||||
"format-on": "<span color='#00ff7f'></span> On",
|
"format-on": "<span color='#00ff7f'><span letter_spacing='500'> </span></span>On",
|
||||||
"format-off": "<span color='#888888'> Off</span>",
|
"format-off": "<span color='#888888'> Off</span>",
|
||||||
"format-disabled": "<span color='#888888'> Off</span>",
|
"format-disabled": "<span color='#888888'> Off</span>",
|
||||||
"format-connected": "<span color='#0478d6'></span> {device_alias}",
|
"format-connected": "<span color='#0478d6'><span letter_spacing='500'> </span></span>{device_alias}",
|
||||||
"format-connected-battery": "<span color='#0478d6'> </span> {device_alias} <span color='#0478d6'> </span> {device_battery_percentage}%",
|
"format-connected-battery": "<span color='#0478d6'><span letter_spacing='500'> </span></span>{device_alias}<span letter_spacing='500'> </span><span color='#0478d6'><span letter_spacing='500'> </span></span>{device_battery_percentage}%",
|
||||||
"tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
|
"tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected",
|
||||||
"tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
|
"tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}",
|
||||||
"tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
|
"tooltip-format-enumerate-connected": "{device_alias}\t{device_address}",
|
||||||
@@ -106,11 +109,11 @@
|
|||||||
"warning": 30,
|
"warning": 30,
|
||||||
"critical": 15
|
"critical": 15
|
||||||
},
|
},
|
||||||
"format": "{icon} {capacity}%",
|
"format": "{icon}<span letter_spacing='1'> </span>{capacity}%",
|
||||||
"format-charging": "{icon} {capacity}%",
|
"format-charging": "{icon}<span letter_spacing='1'> </span>{capacity}%",
|
||||||
"format-plugged": "{icon} {capacity}%",
|
"format-plugged": "{icon}<span letter_spacing='1'> </span>{capacity}%",
|
||||||
"format-alt": "{time} {icon}",
|
"format-alt": "{time}<span letter_spacing='1'> </span>{icon}",
|
||||||
"format-full": " {capacity}%",
|
"format-full": "<span letter_spacing='1'> </span>{capacity}%",
|
||||||
"format-icons": {
|
"format-icons": {
|
||||||
"default": ["", "", "", "", "", "", "", "", ""],
|
"default": ["", "", "", "", "", "", "", "", ""],
|
||||||
"charging": ["", "", "", "", "", "", "", "", ""],
|
"charging": ["", "", "", "", "", "", "", "", ""],
|
||||||
@@ -137,12 +140,33 @@
|
|||||||
"sort-by-number": true
|
"sort-by-number": true
|
||||||
},
|
},
|
||||||
"custom/updater": {
|
"custom/updater": {
|
||||||
"format": " {}",
|
"format": " <span rise='300'>{}</span>",
|
||||||
"exec": "checkupdates | wc -l",
|
"exec": "checkupdates | wc -l",
|
||||||
"exec-if": "[[ $(checkupdates | wc -l) ]]",
|
"exec-if": "[[ $(checkupdates | wc -l) ]]",
|
||||||
"interval": 5,
|
"interval": 1300,
|
||||||
"on-click": "$HOME/.config/waybar/scripts/update-distro.sh",
|
"on-click": "$HOME/.config/waybar/scripts/update-distro.sh",
|
||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
"tooltip-format": "Left Click: Update System\nArch (w/ notification)\nFedora, OpenSuse, Debian/Ubuntu click to update"
|
"tooltip-format": "Left Click: Update System\nRight Click: Update Package Count\nArch (w/ notification)"
|
||||||
|
},
|
||||||
|
|
||||||
|
"custom/notification": {
|
||||||
|
"tooltip": true,
|
||||||
|
"format": "<span>{0} {icon} </span>",
|
||||||
|
"format-icons": {
|
||||||
|
"notification": "",
|
||||||
|
"none": "",
|
||||||
|
"dnd-notification": "",
|
||||||
|
"dnd-none": "",
|
||||||
|
"inhibited-notification": "",
|
||||||
|
"inhibited-none": "",
|
||||||
|
"dnd-inhibited-notification": "",
|
||||||
|
"dnd-inhibited-none": ""
|
||||||
|
},
|
||||||
|
"return-type": "json",
|
||||||
|
"exec-if": "which swaync-client",
|
||||||
|
"exec": "swaync-client -swb",
|
||||||
|
"on-click": "swaync-client -R -t -sw",
|
||||||
|
"on-click-right": "swaync-client -d -sw",
|
||||||
|
"escape": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
# Local Paths
|
# Local Paths
|
||||||
iDIR="$HOME/.config/swaync/images"
|
iDIR="$HOME/.config/swaync/images"
|
||||||
|
|
||||||
# Check for required tools (kitty)
|
# Check for required tools (foot)
|
||||||
if ! command -v kitty &> /dev/null; then
|
if ! command -v foot &> /dev/null; then
|
||||||
notify-send -i "$iDIR/error.png" "Need Kitty:" "Kitty terminal not found. Please install Kitty terminal."
|
notify-send -i "$iDIR/error.png" "Need foot:" "foot terminal not found. Please install foot terminal."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -15,23 +15,23 @@ fi
|
|||||||
if command -v paru &> /dev/null || command -v yay &> /dev/null; then
|
if command -v paru &> /dev/null || command -v yay &> /dev/null; then
|
||||||
# Arch-based
|
# Arch-based
|
||||||
if command -v paru &> /dev/null; then
|
if command -v paru &> /dev/null; then
|
||||||
kitty -T update paru -Syu
|
foot -T update paru -Syu
|
||||||
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Arch-based system' 'has been updated.'
|
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Arch-based system' 'has been updated.'
|
||||||
else
|
else
|
||||||
kitty -T update yay -Syu
|
foot -T update yay -Syu
|
||||||
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Arch-based system' 'has been updated.'
|
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Arch-based system' 'has been updated.'
|
||||||
fi
|
fi
|
||||||
elif command -v dnf &> /dev/null; then
|
elif command -v dnf &> /dev/null; then
|
||||||
# Fedora-based
|
# Fedora-based
|
||||||
kitty -T update sudo dnf update --refresh -y
|
foot -T update sudo dnf update --refresh -y
|
||||||
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Fedora system' 'has been updated.'
|
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Fedora system' 'has been updated.'
|
||||||
elif command -v apt &> /dev/null; then
|
elif command -v apt &> /dev/null; then
|
||||||
# Debian-based (Debian, Ubuntu, etc.)
|
# Debian-based (Debian, Ubuntu, etc.)
|
||||||
kitty -T update sudo apt update && sudo apt upgrade -y
|
foot -T update sudo apt update && sudo apt upgrade -y
|
||||||
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Debian/Ubuntu system' 'has been updated.'
|
notify-send -i "$iDIR/profile-pic.jpg" -u low 'Debian/Ubuntu system' 'has been updated.'
|
||||||
elif command -v zypper &> /dev/null; then
|
elif command -v zypper &> /dev/null; then
|
||||||
# openSUSE-based
|
# openSUSE-based
|
||||||
kitty -T update sudo zypper dup -y
|
foot -T update sudo zypper dup -y
|
||||||
notify-send -i "$iDIR/profile-pic.jpg" -u low 'openSUSE system' 'has been updated.'
|
notify-send -i "$iDIR/profile-pic.jpg" -u low 'openSUSE system' 'has been updated.'
|
||||||
else
|
else
|
||||||
# Unsupported distro
|
# Unsupported distro
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
* {
|
* {
|
||||||
border: none;
|
border: none;
|
||||||
font-family: Font Awesome, Roboto, Arial, sans-serif;
|
font-family:
|
||||||
|
Font Awesome,
|
||||||
|
Roboto,
|
||||||
|
"NotoSansM Nerd Font",
|
||||||
|
"NotoSansMono Nerd Font",
|
||||||
|
"Font Awesome 6 Free",
|
||||||
|
Arial,
|
||||||
|
sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -12,6 +19,16 @@ window#waybar {
|
|||||||
/*-----module groups----*/
|
/*-----module groups----*/
|
||||||
.modules-right {
|
.modules-right {
|
||||||
margin: 2px 10px 0 0;
|
margin: 2px 10px 0 0;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#custom-notification {
|
||||||
|
font-family: "NotoSansM Nerd Font", "NotoSansMono Nerd Font";
|
||||||
|
font-size: 13px;
|
||||||
|
background-color: rgba(0, 43, 51, 0.85);
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 5px 2px 5px 8px;
|
||||||
|
margin: 5px 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-updater {
|
#custom-updater {
|
||||||
@@ -24,6 +41,7 @@ window#waybar {
|
|||||||
|
|
||||||
.modules-left {
|
.modules-left {
|
||||||
margin: 2px 0 0 5px;
|
margin: 2px 0 0 5px;
|
||||||
|
padding-top: 1px;
|
||||||
}
|
}
|
||||||
/*-----modules indv----*/
|
/*-----modules indv----*/
|
||||||
#workspaces button {
|
#workspaces button {
|
||||||
@@ -55,7 +73,8 @@ window#waybar {
|
|||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
margin: 5px 3px;
|
margin: 5px 3px;
|
||||||
}
|
}
|
||||||
#pulseaudio {
|
#wireplumber,
|
||||||
|
#wireplumber-microphone {
|
||||||
padding: 5px 10px 5px 15px;
|
padding: 5px 10px 5px 15px;
|
||||||
background-color: rgba(0, 43, 51, 0.85);
|
background-color: rgba(0, 43, 51, 0.85);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -70,7 +89,7 @@ window#waybar {
|
|||||||
#custom-media,
|
#custom-media,
|
||||||
#custom-launcher {
|
#custom-launcher {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
background-image: url('./bitwarden.svg');
|
background-image: url("./bitwarden.svg");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-color: rgba(0, 43, 51, 0.85);
|
background-color: rgba(0, 43, 51, 0.85);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -105,7 +124,8 @@ window#waybar {
|
|||||||
#idle_inhibitor.activated {
|
#idle_inhibitor.activated {
|
||||||
color: #2dcc36;
|
color: #2dcc36;
|
||||||
}
|
}
|
||||||
#pulseaudio.muted {
|
#wireplumber.muted,
|
||||||
|
#wireplumber-microphone.muted {
|
||||||
color: #cc3436;
|
color: #cc3436;
|
||||||
}
|
}
|
||||||
#battery.charging {
|
#battery.charging {
|
||||||
|
|||||||
674
dotfiles/.themes/HyprFlux-Compact/COPYING
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<svg width="35" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="filter4154" x="-.132" y="-.020842" width="1.264" height="1.0417" color-interpolation-filters="sRGB">
|
||||||
|
<feGaussianBlur stdDeviation="1.65"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(0 -852.36)" shape-rendering="auto">
|
||||||
|
<path d="m7.2 858.36h28v190h-28c-1.108 0-2-0.892-2-2v-186c0-1.108 0.892-2 2-2z" fill="#000000" fill-opacity=".45" filter="url(#filter4154)" opacity=".9"/>
|
||||||
|
<path d="m7 857.36h28v190h-28c-1.108 0-2-0.892-2-2v-186c0-1.108 0.892-2 2-2z" fill="#4DB6AC" />
|
||||||
|
<path transform="translate(0 852.36)" d="m18 94c-0.554 0-1 0.446-1 1v4h-4c-0.554 0-1 0.446-1 1s0.446 1 1 1h4v4c0 0.554 0.446 1 1 1s1-0.446 1-1v-4h4c0.554 0 1-0.446 1-1s-0.446-1-1-1h-4v-4c0-0.554-0.446-1-1-1zm8 6a8 8 0 0 1-8 8 8 8 0 0 1-8-8 8 8 0 0 1 8-8 8 8 0 0 1 8 8z" fill="#ffffff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 883 B |
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="35"
|
||||||
|
height="200"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="add-workspace-hover.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="-81.038405"
|
||||||
|
inkscape:cy="108.58132"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="709"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="false"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:bbox-nodes="true">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3040"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="20,100"
|
||||||
|
id="guide3893"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="18,190"
|
||||||
|
id="guide3895"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-852.36218)">
|
||||||
|
<path
|
||||||
|
id="rect4694"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 7,857.36218 28,0 0,190.00002 -28,0 c -1.108,0 -2,-0.892 -2,-2 L 5,859.36218 c 0,-1.108 0.892,-2 2,-2 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sccssss" />
|
||||||
|
<g
|
||||||
|
transform="translate(0,-0.9999969)"
|
||||||
|
id="g3917-7"
|
||||||
|
style="fill:#eceff1;fill-opacity:1;opacity:0.5;stroke:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="rect4804"
|
||||||
|
transform="translate(0,852.36218)"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 18,94 c -0.554,0 -1,0.446 -1,1 l 0,4 -4,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 4,0 0,4 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 l 0,-4 4,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 l -4,0 0,-4 c 0,-0.554 -0.446,-1 -1,-1 z m 8,6 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="35"
|
||||||
|
height="200"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||||
|
sodipodi:docname="add-workspace.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="-28.526103"
|
||||||
|
inkscape:cy="75.41215"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="709"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="false"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:document-rotation="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3040"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="20,100"
|
||||||
|
id="guide3893"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="18,190"
|
||||||
|
id="guide3895"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-852.36218)">
|
||||||
|
<path
|
||||||
|
id="rect4694"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.35;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 7,857.36218 28,0 0,190.00002 -28,0 c -1.108,0 -2,-0.892 -2,-2 L 5,859.36218 c 0,-1.108 0.892,-2 2,-2 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sccssss" />
|
||||||
|
<g
|
||||||
|
transform="translate(0,-0.9999969)"
|
||||||
|
id="g3917-7"
|
||||||
|
style="fill:#eceff1;fill-opacity:1;opacity:0.5;stroke:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
id="rect4804"
|
||||||
|
transform="translate(0,852.36218)"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.87;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 18,94 c -0.554,0 -1,0.446 -1,1 l 0,4 -4,0 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 4,0 0,4 c 0,0.554 0.446,1 1,1 0.554,0 1,-0.446 1,-1 l 0,-4 4,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 l -4,0 0,-4 c 0,-0.554 -0.446,-1 -1,-1 z m 8,6 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="calendar-arrow-left.svg"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="704"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="29.5"
|
||||||
|
inkscape:cx="13.680381"
|
||||||
|
inkscape:cy="6.1418434"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
d="M10 3v10L5 8z"
|
||||||
|
fill="#000000"
|
||||||
|
opacity="0.54"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#e6e6e6" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="calendar-arrow-right.svg"
|
||||||
|
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="704"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="14.75"
|
||||||
|
inkscape:cx="8"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
d="M6 3v10l5-5z"
|
||||||
|
fill="#000000"
|
||||||
|
opacity="0.54"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#e6e6e6" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24" height="24" fill="#FFFFFF" opacity=".7" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2a10 10 0 0 0-10 10 10 10 0 0 0 10 10 10 10 0 0 0 10-10 10 10 0 0 0-10-10zm0 2a8 8 0 0 1 8 8 8 8 0 0 1-8 8 8 8 0 0 1-8-8 8 8 0 0 1 8-8z" fill="#fff" opacity=".7" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6667"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 419 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24" height="24" fill="#000000" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm5.5898 4.5801 1.4102 1.4199-9 9-5-5 1.4102-1.4102 3.5898 3.5801z" fill="#81c995"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1,10 @@
|
|||||||
|
<svg id="Foreground" width="26" height="26" enable-background="new 0 0 16 16" version="1.0" viewBox="0 0 18.909 18.909" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="filter839" x="-.048" y="-.048" width="1.096" height="1.096" color-interpolation-filters="sRGB">
|
||||||
|
<feGaussianBlur stdDeviation="0.32"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<circle cx="9.4545" cy="10.182" r="8" fill="#000000" filter="url(#filter839)" opacity=".1" stroke-width="0"/>
|
||||||
|
<circle cx="9.4545" cy="9.4545" r="8" fill="#d8354a" stroke-width="0"/>
|
||||||
|
<path d="m6.1115 5.7478c-0.092952 1e-7 -0.18588 0.035309-0.2571 0.10653-0.14245 0.14245-0.14245 0.37175 0 0.5142l3.0852 3.0866-3.0852 3.0852c-0.14245 0.14245-0.14245 0.37175 0 0.5142 0.14245 0.14245 0.37317 0.14245 0.51562 0l3.0852-3.0852 3.0852 3.0852c0.14245 0.14245 0.37175 0.14245 0.5142 0 0.14245-0.14245 0.14245-0.37175 0-0.5142l-3.0852-3.0852 3.0852-3.0866c0.14245-0.14245 0.14245-0.37175 0-0.5142-0.14245-0.14245-0.37175-0.14245-0.5142 0l-3.0852 3.0852-3.0852-3.0852c-0.071224-0.071224-0.16557-0.10653-0.25852-0.10653z" fill="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3606" style="paint-order:markers stroke fill"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
<svg id="Foreground" width="26" height="26" enable-background="new 0 0 16 16" version="1.0" viewBox="0 0 18.909 18.909" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="filter839" x="-.048" y="-.048" width="1.096" height="1.096" color-interpolation-filters="sRGB">
|
||||||
|
<feGaussianBlur stdDeviation="0.32"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<circle cx="9.4545" cy="10.182" r="8" fill="#000000" filter="url(#filter839)" opacity=".1" stroke-width="0"/>
|
||||||
|
<circle cx="9.4545" cy="9.4545" r="8" fill="#ff7a80" stroke-width="0"/>
|
||||||
|
<path d="m6.1115 5.7478c-0.092952 1e-7 -0.18588 0.035309-0.2571 0.10653-0.14245 0.14245-0.14245 0.37175 0 0.5142l3.0852 3.0866-3.0852 3.0852c-0.14245 0.14245-0.14245 0.37175 0 0.5142 0.14245 0.14245 0.37317 0.14245 0.51562 0l3.0852-3.0852 3.0852 3.0852c0.14245 0.14245 0.37175 0.14245 0.5142 0 0.14245-0.14245 0.14245-0.37175 0-0.5142l-3.0852-3.0852 3.0852-3.0866c0.14245-0.14245 0.14245-0.37175 0-0.5142-0.14245-0.14245-0.37175-0.14245-0.5142 0l-3.0852 3.0852-3.0852-3.0852c-0.071224-0.071224-0.16557-0.10653-0.25852-0.10653z" fill="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3606" style="paint-order:markers stroke fill"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
10
dotfiles/.themes/HyprFlux-Compact/cinnamon/assets/close.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<svg id="Foreground" width="26" height="26" enable-background="new 0 0 16 16" version="1.0" viewBox="0 0 18.909 18.909" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="filter879" x="-.048" y="-.048" width="1.096" height="1.096" color-interpolation-filters="sRGB">
|
||||||
|
<feGaussianBlur stdDeviation="0.32"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<circle cx="9.4545" cy="10.182" r="8" fill="#000000" filter="url(#filter879)" opacity=".1" stroke-width="0"/>
|
||||||
|
<circle cx="9.4545" cy="9.4545" r="8" fill="#f75a61" stroke-width="0"/>
|
||||||
|
<path d="m6.1115 5.7478c-0.092952 1e-7 -0.18588 0.035309-0.2571 0.10653-0.14245 0.14245-0.14245 0.37175 0 0.5142l3.0852 3.0866-3.0852 3.0852c-0.14245 0.14245-0.14245 0.37175 0 0.5142 0.14245 0.14245 0.37317 0.14245 0.51562 0l3.0852-3.0852 3.0852 3.0852c0.14245 0.14245 0.37175 0.14245 0.5142 0 0.14245-0.14245 0.14245-0.37175 0-0.5142l-3.0852-3.0852 3.0852-3.0866c0.14245-0.14245 0.14245-0.37175 0-0.5142-0.14245-0.14245-0.37175-0.14245-0.5142 0l-3.0852 3.0852-3.0852-3.0852c-0.071224-0.071224-0.16557-0.10653-0.25852-0.10653z" fill="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.3606" style="paint-order:markers stroke fill"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="104" height="104" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0 -948.36)">
|
||||||
|
<circle id="corner-ripple" cx="52" cy="1000" r="48" fill="#4DB6AC" opacity=".25"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 216 B |
@@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="44"
|
||||||
|
height="26"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
sodipodi:docname="menu-toggle-off.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter932"
|
||||||
|
x="-0.147"
|
||||||
|
y="-0.147"
|
||||||
|
width="1.294"
|
||||||
|
height="1.294">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.225"
|
||||||
|
id="feGaussianBlur934" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#c7c7c7"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="14.364584"
|
||||||
|
inkscape:cx="29.865118"
|
||||||
|
inkscape:cy="15.07179"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1000"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="44"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#ffffff">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2985"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
originx="0"
|
||||||
|
originy="0" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1032.3622)">
|
||||||
|
<g
|
||||||
|
id="g519"
|
||||||
|
transform="matrix(-1,0,0,1,42,0)">
|
||||||
|
<rect
|
||||||
|
x="1"
|
||||||
|
y="1037.3622"
|
||||||
|
width="32"
|
||||||
|
height="14"
|
||||||
|
rx="7"
|
||||||
|
ry="7"
|
||||||
|
id="rect7"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1045.3622"
|
||||||
|
r="10"
|
||||||
|
fill="#1a73e8"
|
||||||
|
id="circle376"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1;stroke-width:1;filter:url(#filter932)" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1044.3622"
|
||||||
|
r="10"
|
||||||
|
id="circle14"
|
||||||
|
style="fill:#f2f2f2;fill-opacity:1;stroke-width:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" fill="#000000" opacity=".54" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" fill="#dfdfdf"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 291 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10c5.52 0 10-4.48 10-10s-4.48-10-10-10zm0 7c1.656 0 3 1.344 3 3s-1.344 3-3 3-3-1.344-3-3 1.344-3 3-3z" fill="#81c995"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 274 B |
126
dotfiles/.themes/HyprFlux-Compact/cinnamon/assets/toggle-off.svg
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="44"
|
||||||
|
height="26"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
sodipodi:docname="toggle-off.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter932"
|
||||||
|
x="-0.147"
|
||||||
|
y="-0.147"
|
||||||
|
width="1.294"
|
||||||
|
height="1.294">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.225"
|
||||||
|
id="feGaussianBlur934" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#212121"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="5.0786474"
|
||||||
|
inkscape:cx="-12.207975"
|
||||||
|
inkscape:cy="5.6117304"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g519"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1000"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="44"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#5a5a5a">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2985"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
originx="0"
|
||||||
|
originy="0" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1032.3622)">
|
||||||
|
<g
|
||||||
|
id="g519"
|
||||||
|
transform="matrix(-1,0,0,1,42,0)">
|
||||||
|
<rect
|
||||||
|
x="1"
|
||||||
|
y="1037.3622"
|
||||||
|
width="32"
|
||||||
|
height="14"
|
||||||
|
rx="7"
|
||||||
|
ry="7"
|
||||||
|
id="rect7"
|
||||||
|
style="opacity:0.15;fill:#ffffff;fill-opacity:1" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1045.3622"
|
||||||
|
r="10"
|
||||||
|
fill="#1a73e8"
|
||||||
|
id="circle376"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1;stroke-width:1;filter:url(#filter932)" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1044.3622"
|
||||||
|
r="10"
|
||||||
|
id="circle14"
|
||||||
|
style="fill:#2f2f2f;fill-opacity:1;stroke-width:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="44"
|
||||||
|
height="26"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 44 26"
|
||||||
|
id="svg176"
|
||||||
|
sodipodi:docname="toggle-on-Dark.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview178"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="8.34386"
|
||||||
|
inkscape:cx="8.7489483"
|
||||||
|
inkscape:cy="24.389192"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1000"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="44"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg176">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3683" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs159">
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter932"
|
||||||
|
x="-0.147"
|
||||||
|
y="-0.147"
|
||||||
|
width="1.294"
|
||||||
|
height="1.294">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.225"
|
||||||
|
id="feGaussianBlur934" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
x="3"
|
||||||
|
y="5"
|
||||||
|
width="32"
|
||||||
|
height="14"
|
||||||
|
rx="7"
|
||||||
|
ry="7"
|
||||||
|
id="rect7"
|
||||||
|
style="opacity:0.35;fill:#4DB6AC" />
|
||||||
|
<circle
|
||||||
|
cx="31"
|
||||||
|
cy="13"
|
||||||
|
r="10"
|
||||||
|
fill="#009688"
|
||||||
|
id="circle376"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1;stroke-width:1;filter:url(#filter932)" />
|
||||||
|
<circle
|
||||||
|
cx="31"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
id="circle14"
|
||||||
|
style="fill:#4DB6AC;fill-opacity:1;stroke-width:1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="400" height="120" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0 -932.36)">
|
||||||
|
<rect x="10" y="942.36" width="380" height="160" rx="18" ry="18" fill="#4d4d4d" stroke-width="0"/>
|
||||||
|
<path class="ColorScheme-Text" d="m200 964.36c-4.4183 0-8 3.5817-8 8h-16v4h48v-4h-16c0-4.4183-3.5817-8-8-8zm0 4c2.2091 1e-5 4 1.7909 4 4h-8c1e-5 -2.2091 1.7909-4 4-4zm-20 12v32c0 4.4321 3.5679 8.0001 8 8.0001h24c4.4321 0 8-3.568 8-8.0001v-32h-38zm4 4h32v28c0 2.2161-1.7839 4.0001-4 4.0001h-24c-2.2161 0-4-1.784-4-4.0001z" fill="#ececec"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 573 B |
2420
dotfiles/.themes/HyprFlux-Compact/cinnamon/cinnamon.css
Normal file
BIN
dotfiles/.themes/HyprFlux-Compact/cinnamon/thumbnail.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="48" height="48" enable-background="new" version="1.0" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0,-276)" fill="#ffffff">
|
||||||
|
<path d="m24 288a12 12 0 0 0-12 12 12 12 0 0 0 12 12 12 12 0 0 0 12-12 12 12 0 0 0-12-12zm0 4a8 8 0 0 1 8 8 8 8 0 0 1-8 8 8 8 0 0 1-8-8 8 8 0 0 1 8-8z" fill="#ffffff" stroke-width="2" style="paint-order:fill markers stroke"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 393 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="#FFFFFF" opacity="0.7">
|
||||||
|
<path d="m10 3v10l-5-5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 149 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="#FFFFFF" opacity="0.7">
|
||||||
|
<path d="m6 3v10l5-5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 147 B |
@@ -0,0 +1,178 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
id="svg10621"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="calendar-today.svg">
|
||||||
|
<defs
|
||||||
|
id="defs10623">
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient99561-1"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient34508-1-3">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop34510-1-9" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop34512-4-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
r="42"
|
||||||
|
fy="30"
|
||||||
|
fx="51"
|
||||||
|
cy="30"
|
||||||
|
cx="51"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="radialGradient10592"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient3770"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient3001"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient3007"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient3067"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient3072"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient34508-1-3"
|
||||||
|
id="radialGradient2997"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||||
|
cx="51"
|
||||||
|
cy="30"
|
||||||
|
fx="51"
|
||||||
|
fy="30"
|
||||||
|
r="42" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="8"
|
||||||
|
inkscape:cx="-23.537329"
|
||||||
|
inkscape:cy="-31.442864"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="2133"
|
||||||
|
inkscape:window-height="1241"
|
||||||
|
inkscape:window-x="238"
|
||||||
|
inkscape:window-y="88"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid3109"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata10626">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-469.08263,-537.99307)">
|
||||||
|
<circle
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.23756906;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
id="path7305"
|
||||||
|
cx="481.57138"
|
||||||
|
cy="559.4649"
|
||||||
|
r="1.5" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24" height="24" fill="#FFFFFF" opacity=".7" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2a10 10 0 0 0-10 10 10 10 0 0 0 10 10 10 10 0 0 0 10-10 10 10 0 0 0-10-10zm0 2a8 8 0 0 1 8 8 8 8 0 0 1-8 8 8 8 0 0 1-8-8 8 8 0 0 1 8-8z" fill="#fff" opacity=".7" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6667"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 419 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24" height="24" fill="#000000" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm5.5898 4.5801 1.4102 1.4199-9 9-5-5 1.4102-1.4102 3.5898 3.5801z" fill="#81c995"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#FFFFFF">
|
||||||
|
<circle cx="12" cy="12" r="12" opacity="0.3"/>
|
||||||
|
<circle cx="12" cy="12" r="4"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 189 B |
@@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="44"
|
||||||
|
height="26"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="menu-toggle-off.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter932"
|
||||||
|
x="-0.147"
|
||||||
|
y="-0.147"
|
||||||
|
width="1.294"
|
||||||
|
height="1.294">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.225"
|
||||||
|
id="feGaussianBlur934" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#c7c7c7"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="14.364584"
|
||||||
|
inkscape:cx="29.83031"
|
||||||
|
inkscape:cy="15.106598"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1006"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#ffffff">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2985"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingy="1"
|
||||||
|
spacingx="1"
|
||||||
|
units="px" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1032.3622)">
|
||||||
|
<rect
|
||||||
|
x="-41"
|
||||||
|
y="1037.3622"
|
||||||
|
width="32"
|
||||||
|
height="14"
|
||||||
|
rx="7"
|
||||||
|
ry="7"
|
||||||
|
id="rect7"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1045.3622"
|
||||||
|
r="10"
|
||||||
|
fill="#1a73e8"
|
||||||
|
id="circle376"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1;stroke-width:1;filter:url(#filter932)"
|
||||||
|
transform="matrix(-1,0,0,1,42,0)" />
|
||||||
|
<circle
|
||||||
|
cx="-13"
|
||||||
|
cy="1044.3622"
|
||||||
|
r="10"
|
||||||
|
id="circle14"
|
||||||
|
style="fill:#f2f2f2;fill-opacity:1;stroke-width:1"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="translate(0 -1036.4)">
|
||||||
|
<circle cx="8" cy="1044.4" r="8" fill="#4DB6AC"/>
|
||||||
|
<path transform="translate(0 1036.4)" d="m7 4v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2z" fill="#ffffff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 298 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="48" height="48" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 0h48v48H0z" fill="none"/>
|
||||||
|
<path d="m38 6h-2v-4h-4v4h-16v-4h-4v4h-2c-2.21 0-3.98 1.79-3.98 4l-0.02 28c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4v-28c0-2.21-1.79-4-4-4zm0 32h-28v-22h28z" fill="#dedede"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 317 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="#dedede" opacity="1">
|
||||||
|
<path d="M24 44c2.21 0 4-1.79 4-4h-8c0 2.21 1.79 4 4 4zm12-12V22c0-6.15-3.27-11.28-9-12.64V8c0-1.66-1.34-3-3-3s-3 1.34-3 3v1.36c-5.73 1.36-9 6.49-9 12.64v10l-4 4v2h32v-2l-4-4zm-4 2H16V22c0-4.97 3.03-9 8-9s8 4.03 8 9v12z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
@@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1600"
|
||||||
|
height="900"
|
||||||
|
viewBox="0 0 1600 900"
|
||||||
|
version="1.1"
|
||||||
|
id="svg13"
|
||||||
|
sodipodi:docname="noise-texture.svg"
|
||||||
|
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
|
||||||
|
<metadata
|
||||||
|
id="metadata17">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:window-height="698"
|
||||||
|
id="namedview15"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.26222222"
|
||||||
|
inkscape:cx="647.80786"
|
||||||
|
inkscape:cy="422.79535"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg13" />
|
||||||
|
<defs
|
||||||
|
id="defs9">
|
||||||
|
<radialGradient
|
||||||
|
id="a"
|
||||||
|
gradientTransform="matrix(1 1 -1 1 0.5 -0.5)">
|
||||||
|
<stop
|
||||||
|
stop-color="#455A64"
|
||||||
|
stop-opacity="0"
|
||||||
|
offset="0.25"
|
||||||
|
id="stop2"
|
||||||
|
style="stop-color:#444444;stop-opacity:0" />
|
||||||
|
<stop
|
||||||
|
stop-color="#455A64"
|
||||||
|
stop-opacity="0.5"
|
||||||
|
offset="0.75"
|
||||||
|
id="stop4"
|
||||||
|
style="stop-color:#444444;stop-opacity:0.50196081" />
|
||||||
|
<stop
|
||||||
|
stop-color="#455A64"
|
||||||
|
stop-opacity="1"
|
||||||
|
offset="1"
|
||||||
|
id="stop6"
|
||||||
|
style="stop-color:#444444;stop-opacity:1" />
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
width="1600"
|
||||||
|
height="900"
|
||||||
|
fill="url(#a)"
|
||||||
|
id="rect11" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,72 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="32" viewBox="0 0 512 32">
|
||||||
|
<defs>
|
||||||
|
<g id="g" fill="#FFFFFF" opacity="0.7">
|
||||||
|
<circle cx="8" cy="8" r="8" fill="none"/>
|
||||||
|
<path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7h-3a4 4 0 0 1 -4 4 4 4 0 0 1 -4 -4 4 4 0 0 1 4 -4v-3z"/>
|
||||||
|
</g>
|
||||||
|
</defs>
|
||||||
|
<use xlink:href="#g" transform="translate(0) rotate(0 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(16) rotate(5.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(32) rotate(11.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(48) rotate(16.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(64) rotate(22.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(80) rotate(28.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(96) rotate(33.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(112) rotate(39.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(128) rotate(45 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(144) rotate(50.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(160) rotate(56.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(176) rotate(61.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(192) rotate(67.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(208) rotate(73.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(224) rotate(78.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(240) rotate(84.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(256) rotate(90 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(272) rotate(95.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(288) rotate(101.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(304) rotate(106.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(320) rotate(112.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(336) rotate(118.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(352) rotate(123.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(368) rotate(129.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(384) rotate(135 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(400) rotate(140.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(416) rotate(146.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(432) rotate(151.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(448) rotate(157.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(464) rotate(163.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(480) rotate(168.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(496) rotate(174.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(0 16) rotate(180 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(16 16) rotate(185.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(32 16) rotate(191.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(48 16) rotate(196.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(64 16) rotate(202.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(80 16) rotate(208.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(96 16) rotate(213.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(112 16) rotate(219.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(128 16) rotate(225 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(144 16) rotate(230.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(160 16) rotate(236.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(176 16) rotate(241.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(192 16) rotate(247.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(208 16) rotate(253.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(224 16) rotate(258.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(240 16) rotate(264.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(256 16) rotate(270 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(272 16) rotate(275.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(288 16) rotate(281.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(304 16) rotate(286.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(320 16) rotate(292.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(336 16) rotate(298.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(352 16) rotate(303.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(368 16) rotate(309.375 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(384 16) rotate(315 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(400 16) rotate(320.625 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(416 16) rotate(326.25 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(432 16) rotate(331.875 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(448 16) rotate(337.5 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(464 16) rotate(343.125 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(480 16) rotate(348.75 8 8)"/>
|
||||||
|
<use xlink:href="#g" transform="translate(496 16) rotate(354.375 8 8)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="44"
|
||||||
|
height="26"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
sodipodi:docname="toggle-off.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter932"
|
||||||
|
x="-0.147"
|
||||||
|
y="-0.147"
|
||||||
|
width="1.294"
|
||||||
|
height="1.294">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.225"
|
||||||
|
id="feGaussianBlur934" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#212121"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="14.364584"
|
||||||
|
inkscape:cx="20.606235"
|
||||||
|
inkscape:cy="14.967367"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1006"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#5a5a5a">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2985"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingy="1"
|
||||||
|
spacingx="1"
|
||||||
|
units="px" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1032.3622)">
|
||||||
|
<rect
|
||||||
|
x="-41"
|
||||||
|
y="1037.3622"
|
||||||
|
width="32"
|
||||||
|
height="14"
|
||||||
|
rx="7"
|
||||||
|
ry="7"
|
||||||
|
id="rect7"
|
||||||
|
style="opacity:0.15;fill:#ffffff;fill-opacity:1"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<circle
|
||||||
|
cx="29"
|
||||||
|
cy="1045.3622"
|
||||||
|
r="10"
|
||||||
|
fill="#1a73e8"
|
||||||
|
id="circle376"
|
||||||
|
style="opacity:0.25;fill:#000000;fill-opacity:1;stroke-width:1;filter:url(#filter932)"
|
||||||
|
transform="matrix(-1,0,0,1,42,0)" />
|
||||||
|
<circle
|
||||||
|
cx="-13"
|
||||||
|
cy="1044.3622"
|
||||||
|
r="10"
|
||||||
|
id="circle14"
|
||||||
|
style="fill:#2f2f2f;fill-opacity:1;stroke-width:1"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |