mirror of
https://github.com/neoromantique/dotfiles.git
synced 2026-03-13 21:53:20 +03:00
sync
This commit is contained in:
93
AGENTS.md
Normal file
93
AGENTS.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# AGENTS Guide: Dotfiles Repository
|
||||||
|
|
||||||
|
Chezmoi-managed dotfiles with device-adaptive templates. Source files in `~/dotfiles/`, deployed to `~/` via `chezmoi apply`.
|
||||||
|
|
||||||
|
## Device Profiles
|
||||||
|
|
||||||
|
| Profile | Hostname | Primary Monitor | Has Touchpad | Has Battery |
|
||||||
|
|---------|----------|-----------------|--------------|-------------|
|
||||||
|
| desktop | box | DP-2 | No | No |
|
||||||
|
| laptop | bluefin | eDP-1 | Yes | Yes |
|
||||||
|
|
||||||
|
## Template Variables
|
||||||
|
|
||||||
|
```go
|
||||||
|
{{ .deviceProfile }} // "desktop" or "laptop"
|
||||||
|
{{ .hostname }} // "box" or "bluefin"
|
||||||
|
{{ .primaryMonitor }} // "DP-2" or "eDP-1"
|
||||||
|
{{ .hasTouchpad }} // boolean
|
||||||
|
{{ .hasBattery }} // boolean
|
||||||
|
{{ .idleTimeout }} // 300 (desktop) or 180 (laptop)
|
||||||
|
{{ .secretsPath }} // "~/secrets"
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Naming Conventions
|
||||||
|
|
||||||
|
| Pattern | Effect |
|
||||||
|
|---------|--------|
|
||||||
|
| `private_dot_*` | Hidden file with 700 permissions |
|
||||||
|
| `dot_*` | Hidden file with 755 permissions |
|
||||||
|
| `executable_*` | Executable (755) |
|
||||||
|
| `*.tmpl` | Processed as Go template |
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
home/
|
||||||
|
├── private_dot_config/ # ~/.config/
|
||||||
|
│ ├── hypr/ # Hyprland configs
|
||||||
|
│ ├── fish/ # Shell
|
||||||
|
│ ├── waybar/ # Status bar
|
||||||
|
│ └── ghostty/ # Terminal
|
||||||
|
├── dot_local/bin/ # ~/.local/bin/ scripts
|
||||||
|
└── .chezmoiscripts/ # One-time setup scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hyprland Config Files
|
||||||
|
|
||||||
|
All in `home/private_dot_config/hypr/`:
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `hyprland.conf.tmpl` | Main config, keybindings, window rules |
|
||||||
|
| `monitors.conf.tmpl` | Monitor setup |
|
||||||
|
| `autostart.conf.tmpl` | Startup applications |
|
||||||
|
| `colors.conf` | Color palette |
|
||||||
|
| `workspaces.conf` | Workspace definitions |
|
||||||
|
| `hyprpaper.conf.tmpl` | Wallpaper |
|
||||||
|
| `hypridle.conf.tmpl` | Idle/power management |
|
||||||
|
| `hyprlock.conf` | Lock screen |
|
||||||
|
|
||||||
|
## Template Conditionals
|
||||||
|
|
||||||
|
```go
|
||||||
|
{{- if eq .deviceProfile "desktop" }}
|
||||||
|
# Desktop only
|
||||||
|
{{- else if eq .deviceProfile "laptop" }}
|
||||||
|
# Laptop only
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .hasBattery }}
|
||||||
|
# Battery-dependent (laptop brightness keys, etc.)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .hasTouchpad }}
|
||||||
|
# Touchpad settings
|
||||||
|
{{- end }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chezmoi apply # Deploy changes
|
||||||
|
chezmoi diff # Preview changes
|
||||||
|
chezmoi edit <file> # Edit managed file
|
||||||
|
chezmoi add <file> # Add new file to management
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standards
|
||||||
|
|
||||||
|
- Scripts: `#!/usr/bin/env bash` with `set -euo pipefail`
|
||||||
|
- Secrets: Store in `~/secrets/`, reference via `{{ .secretsPath }}`
|
||||||
|
- Window rules: Use `windowrulev2` (not deprecated `windowrule`)
|
||||||
|
- Whitespace: Use `{{-` to trim in templates
|
||||||
24
home/dot_local/bin/executable_hypr-debounce
Normal file
24
home/dot_local/bin/executable_hypr-debounce
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ms=${1:-200}
|
||||||
|
shift || true
|
||||||
|
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
echo "usage: hypr-debounce <ms> <command...>" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
key=$(printf '%s\0' "$@" | sha1sum | awk '{print $1}')
|
||||||
|
state="/tmp/hypr-debounce-$key"
|
||||||
|
now=$(date +%s%3N)
|
||||||
|
|
||||||
|
if [ -f "$state" ]; then
|
||||||
|
last=$(cat "$state" 2>/dev/null || echo 0)
|
||||||
|
if [ $((now - last)) -lt "$ms" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "$now" > "$state"
|
||||||
|
exec "$@"
|
||||||
30
home/dot_local/bin/executable_launch-on-workspace
Normal file
30
home/dot_local/bin/executable_launch-on-workspace
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Usage: launch-on-workspace <workspace> <exact_class> <command...>
|
||||||
|
|
||||||
|
target_ws="$1"
|
||||||
|
target_class="$2"
|
||||||
|
shift 2
|
||||||
|
# Use array to preserve argument quoting
|
||||||
|
cmd=("$@")
|
||||||
|
|
||||||
|
echo "$(date) [launch-on-workspace] Launching class='$target_class' to workspace='$target_ws'" >> /tmp/hypr-launch.log
|
||||||
|
|
||||||
|
# Start the application with preserved arguments
|
||||||
|
nohup "${cmd[@]}" >/dev/null 2>&1 &
|
||||||
|
|
||||||
|
# Wait for the window to appear (up to 15 seconds)
|
||||||
|
for i in {1..60}; do
|
||||||
|
# Get address of matching window
|
||||||
|
# We check both class and initialClass for robustness
|
||||||
|
addr=$(hyprctl clients -j | jq -r ".[] | select(.class == \"$target_class\" or .initialClass == \"$target_class\") | .address" | head -1)
|
||||||
|
|
||||||
|
if [ ! -z "$addr" ] && [ "$addr" != "null" ]; then
|
||||||
|
echo "$(date) [launch-on-workspace] Found $target_class at $addr, moving to $target_ws" >> /tmp/hypr-launch.log
|
||||||
|
hyprctl dispatch movetoworkspacesilent "$target_ws,address:$addr"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 0.25
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$(date) [launch-on-workspace] Timeout waiting for $target_class" >> /tmp/hypr-launch.log
|
||||||
|
exit 1
|
||||||
38
home/private_dot_config/alacritty/alacritty.toml
Normal file
38
home/private_dot_config/alacritty/alacritty.toml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Alacritty configuration
|
||||||
|
# Generated from ~/.config/ghostty/config for feature parity where possible.
|
||||||
|
|
||||||
|
[window]
|
||||||
|
opacity = 0.9
|
||||||
|
decorations = "Full"
|
||||||
|
dynamic_padding = true
|
||||||
|
|
||||||
|
[window.padding]
|
||||||
|
x = 12
|
||||||
|
y = 12
|
||||||
|
|
||||||
|
[scrolling]
|
||||||
|
# Alacritty has a finite history buffer; Ghostty unlimited scrollback is not available.
|
||||||
|
history = 100000
|
||||||
|
|
||||||
|
[cursor]
|
||||||
|
style = { shape = "Block", blinking = "Never" }
|
||||||
|
|
||||||
|
[selection]
|
||||||
|
# Approximate Ghostty's copy-on-select behavior.
|
||||||
|
save_to_clipboard = true
|
||||||
|
|
||||||
|
[mouse]
|
||||||
|
hide_when_typing = true
|
||||||
|
|
||||||
|
[font]
|
||||||
|
size = 12.0
|
||||||
|
|
||||||
|
[window.class]
|
||||||
|
# Keep class/app_id compatible with existing Hyprland rules targeting Ghostty.
|
||||||
|
instance = "ghostty"
|
||||||
|
general = "ghostty"
|
||||||
|
|
||||||
|
# Note:
|
||||||
|
# - Background blur is compositor-specific and not a native Alacritty setting.
|
||||||
|
# - Ghostty shell-integration options do not have Alacritty equivalents.
|
||||||
|
# - Quake/quick-terminal toggle is not built into Alacritty.
|
||||||
6
home/private_dot_config/atuin/config.toml
Normal file
6
home/private_dot_config/atuin/config.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Atuin config (managed by chezmoi)
|
||||||
|
#
|
||||||
|
# Keep normal "Up" history scoped to this shell session, while Ctrl-R
|
||||||
|
# search stays global so older/other-session commands are still discoverable.
|
||||||
|
filter_mode = "global"
|
||||||
|
filter_mode_shell_up_key_binding = "session"
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
# Man pages with bat
|
# Man pages with bat
|
||||||
|
set -g fish_greeting
|
||||||
set -x MANROFFOPT "-c"
|
set -x MANROFFOPT "-c"
|
||||||
set -x MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
set -x MANPAGER "sh -c 'col -bx | bat -l man -p'"
|
||||||
|
|
||||||
@@ -8,6 +9,17 @@ fish_add_path -m $HOME/.local/bin
|
|||||||
# LM Studio
|
# LM Studio
|
||||||
fish_add_path $HOME/.lmstudio/bin
|
fish_add_path $HOME/.lmstudio/bin
|
||||||
|
|
||||||
|
# Bun
|
||||||
|
fish_add_path ~/.bun/bin
|
||||||
|
|
||||||
|
# Backblaze B2
|
||||||
|
alias backblaze-b2=bbb2
|
||||||
|
|
||||||
|
# SSHS (optional)
|
||||||
|
if command -q sshs
|
||||||
|
alias ss=sshs
|
||||||
|
end
|
||||||
|
|
||||||
# Scaleway (lazy-load)
|
# Scaleway (lazy-load)
|
||||||
function scw --wraps=scw
|
function scw --wraps=scw
|
||||||
functions -e scw
|
functions -e scw
|
||||||
@@ -26,6 +38,23 @@ function history
|
|||||||
builtin history --show-time='%F %T '
|
builtin history --show-time='%F %T '
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Atuin history (fuzzy search + sync)
|
||||||
|
if status is-interactive; and command -q atuin
|
||||||
|
atuin init fish | source
|
||||||
|
if functions -q _atuin_search
|
||||||
|
bind \cr _atuin_search
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Ctrl+S launches sshs when available
|
||||||
|
if status is-interactive; and command -q sshs
|
||||||
|
function __sshs_launch --description "Launch sshs via keybind"
|
||||||
|
commandline -f cancel
|
||||||
|
sshs
|
||||||
|
end
|
||||||
|
bind \cs __sshs_launch
|
||||||
|
end
|
||||||
|
|
||||||
# Bash-style !! and !$
|
# Bash-style !! and !$
|
||||||
function __history_previous_command
|
function __history_previous_command
|
||||||
switch (commandline -t)
|
switch (commandline -t)
|
||||||
@@ -48,3 +77,218 @@ end
|
|||||||
|
|
||||||
bind ! __history_previous_command
|
bind ! __history_previous_command
|
||||||
bind '$' __history_previous_command_arguments
|
bind '$' __history_previous_command_arguments
|
||||||
|
|
||||||
|
# Terminal SSH background color derived from server IP (Ghostty/Foot)
|
||||||
|
if not set -q TERM_SSH_BG_RESET
|
||||||
|
# Match configured terminal background as the reset target.
|
||||||
|
set -gx TERM_SSH_BG_RESET "#141414"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_supports_osc11 --description "Check if terminal supports OSC 11 bg color"
|
||||||
|
if not status is-interactive
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Ghostty
|
||||||
|
if test "$TERM_PROGRAM" = "ghostty"
|
||||||
|
return 0
|
||||||
|
else if string match -q "*ghostty*" "$TERM"
|
||||||
|
return 0
|
||||||
|
else if set -q GHOSTTY
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Foot
|
||||||
|
if string match -q "foot*" "$TERM"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_bg_set_from_ip --description "Set terminal background derived from IP"
|
||||||
|
if not __term_supports_osc11
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if test (count $argv) -lt 1
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l server_ip $argv[1]
|
||||||
|
if test -z "$server_ip"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l hash (printf '%s' "$server_ip" | cksum | awk '{print $1}')
|
||||||
|
set -l base_r 20
|
||||||
|
set -l base_g 20
|
||||||
|
set -l base_b 20
|
||||||
|
set -l r_delta (math --scale 0 "($hash % 49) - 24")
|
||||||
|
set -l g_delta (math --scale 0 "(($hash / 49) % 49) - 24")
|
||||||
|
set -l b_delta (math --scale 0 "(($hash / 2401) % 49) - 24")
|
||||||
|
set -l r (math --scale 0 "$base_r + $r_delta")
|
||||||
|
set -l g (math --scale 0 "$base_g + $g_delta")
|
||||||
|
set -l b (math --scale 0 "$base_b + $b_delta")
|
||||||
|
|
||||||
|
if test $r -lt 0; set r 0; end
|
||||||
|
if test $g -lt 0; set g 0; end
|
||||||
|
if test $b -lt 0; set b 0; end
|
||||||
|
if test $r -gt 255; set r 255; end
|
||||||
|
if test $g -gt 255; set g 255; end
|
||||||
|
if test $b -gt 255; set b 255; end
|
||||||
|
|
||||||
|
printf '\e]11;#%02x%02x%02x\a' $r $g $b
|
||||||
|
set -g __term_ssh_bg_active 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_ssh_bg --description "Set terminal background for SSH"
|
||||||
|
if not __term_supports_osc11
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not set -q SSH_CONNECTION
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l server_ip (string split " " -- $SSH_CONNECTION)[3]
|
||||||
|
__term_bg_set_from_ip $server_ip
|
||||||
|
end
|
||||||
|
|
||||||
|
set -g __term_ssh_in_progress 0
|
||||||
|
function __term_ssh_postexec_reset --on-event fish_postexec --description "Reset terminal background after SSH command"
|
||||||
|
if test $__term_ssh_in_progress -eq 1
|
||||||
|
__term_ssh_bg_reset --force
|
||||||
|
set -g __term_ssh_in_progress 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_ssh_prompt_reset --on-event fish_prompt --description "Reset terminal background on prompt redraw after SSH"
|
||||||
|
if test $__term_ssh_in_progress -eq 1
|
||||||
|
__term_ssh_bg_reset --force
|
||||||
|
set -g __term_ssh_in_progress 0
|
||||||
|
end
|
||||||
|
if set -q __term_ssh_bg_active; and test $__term_ssh_bg_active -eq 1
|
||||||
|
__term_ssh_bg_reset --force
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_ssh_ctrl_c --description "Reset terminal background before Ctrl+C"
|
||||||
|
if set -q __term_ssh_bg_active; and test $__term_ssh_bg_active -eq 1
|
||||||
|
__term_ssh_bg_reset --force
|
||||||
|
end
|
||||||
|
commandline -f cancel-commandline
|
||||||
|
end
|
||||||
|
|
||||||
|
bind \cc __term_ssh_ctrl_c
|
||||||
|
|
||||||
|
function __term_ssh_bg_reset --on-event fish_exit --description "Reset terminal background after SSH"
|
||||||
|
set -l force 0
|
||||||
|
if test (count $argv) -gt 0; and test "$argv[1]" = "--force"
|
||||||
|
set force 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if not __term_supports_osc11
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $force -ne 1; and not set -q SSH_CONNECTION
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if set -q TERM_SSH_BG_RESET
|
||||||
|
printf '\e]11;%s\a' "$TERM_SSH_BG_RESET"
|
||||||
|
else
|
||||||
|
printf '\e]111\a'
|
||||||
|
end
|
||||||
|
set -g __term_ssh_bg_active 0
|
||||||
|
end
|
||||||
|
|
||||||
|
__term_ssh_bg
|
||||||
|
|
||||||
|
function __term_wrap_ssh --on-event fish_prompt --description "Wrap ssh for terminal bg color"
|
||||||
|
if functions -q __term_ssh_wrapped
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not command -q ssh
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
set -g __term_use_ssh_function 0
|
||||||
|
if functions -q ssh
|
||||||
|
functions -c ssh __term_ssh_orig
|
||||||
|
functions -e ssh
|
||||||
|
set -g __term_use_ssh_function 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function ssh --wraps=__term_ssh_orig --description "SSH with terminal background color per target"
|
||||||
|
set -l host ""
|
||||||
|
set -l skip_next 0
|
||||||
|
set -l after_ddash 0
|
||||||
|
|
||||||
|
for arg in $argv
|
||||||
|
if test $skip_next -eq 1
|
||||||
|
set skip_next 0
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
if test "$arg" = "--"
|
||||||
|
set after_ddash 1
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $after_ddash -eq 0; and string match -q -- "-*" $arg
|
||||||
|
switch $arg
|
||||||
|
case "-b" "-c" "-D" "-E" "-e" "-F" "-I" "-i" "-J" "-L" "-l" "-m" "-O" "-o" "-p" "-Q" "-R" "-S" "-W" "-w"
|
||||||
|
set skip_next 1
|
||||||
|
continue
|
||||||
|
case "-b*" "-c*" "-D*" "-E*" "-e*" "-F*" "-I*" "-i*" "-J*" "-L*" "-l*" "-m*" "-O*" "-o*" "-p*" "-Q*" "-R*" "-S*" "-W*" "-w*"
|
||||||
|
continue
|
||||||
|
case "-B" "-G" "-K" "-M" "-N" "-n" "-T" "-t" "-v" "-V" "-x" "-X" "-Y" "-y" "-q" "-f" "-g" "-k"
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -z "$host"
|
||||||
|
set host $arg
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if __term_supports_osc11; and test -n "$host"
|
||||||
|
set -l host_only (string split "@" -- $host)[-1]
|
||||||
|
set -l resolved ""
|
||||||
|
|
||||||
|
if command -q getent
|
||||||
|
set resolved (getent ahosts $host_only 2>/dev/null | awk 'NR==1 {print $1}')
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -z "$resolved"; and command -q host
|
||||||
|
set resolved (host $host_only 2>/dev/null | awk '/has address/ {print $4; exit}')
|
||||||
|
end
|
||||||
|
|
||||||
|
if test -n "$resolved"
|
||||||
|
__term_bg_set_from_ip $resolved
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set -g __term_ssh_in_progress 1
|
||||||
|
if test $__term_use_ssh_function -eq 1
|
||||||
|
__term_ssh_orig $argv
|
||||||
|
else
|
||||||
|
command ssh $argv
|
||||||
|
end
|
||||||
|
set -l ssh_status $status
|
||||||
|
|
||||||
|
if __term_supports_osc11
|
||||||
|
__term_ssh_bg_reset --force
|
||||||
|
end
|
||||||
|
set -g __term_ssh_in_progress 0
|
||||||
|
|
||||||
|
return $ssh_status
|
||||||
|
end
|
||||||
|
|
||||||
|
function __term_ssh_wrapped --description "Marker for wrapped ssh"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -9,15 +9,16 @@ function gha-cancel-run --description "Cancel a GitHub Actions run using its URL
|
|||||||
|
|
||||||
# Extract owner, repo, and run_id from the URL using regular expressions
|
# Extract owner, repo, and run_id from the URL using regular expressions
|
||||||
# This regex is specifically designed to parse the run URL format
|
# This regex is specifically designed to parse the run URL format
|
||||||
if not string match --regex 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' "$run_url"
|
set -l matches (string match --regex 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' -- "$run_url")
|
||||||
|
if test (count $matches) -eq 0
|
||||||
echo "Error: Invalid GitHub Actions run URL format."
|
echo "Error: Invalid GitHub Actions run URL format."
|
||||||
echo "Expected format: https://github.com/OWNER/REPO/actions/runs/RUN_ID"
|
echo "Expected format: https://github.com/OWNER/REPO/actions/runs/RUN_ID"
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
set -l owner (string match --regex --groups=1 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' "$run_url")[2]
|
set -l owner $matches[2]
|
||||||
set -l repo (string match --regex --groups=2 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' "$run_url")[2]
|
set -l repo $matches[3]
|
||||||
set -l run_id (string match --regex --groups=3 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' "$run_url")[2]
|
set -l run_id $matches[4]
|
||||||
|
|
||||||
echo "Attempting to cancel run ID: $run_id in $owner/$repo..."
|
echo "Attempting to cancel run ID: $run_id in $owner/$repo..."
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
function gha-force-cancel-run --description "Force-cancel a GitHub Actions run using its URL"
|
||||||
|
if test -z "$argv[1]"
|
||||||
|
echo "Usage: gha-force-cancel-run <GitHub Actions run URL>"
|
||||||
|
echo "Example: gha-force-cancel-run https://github.com/OWNER/REPO/actions/runs/123456789"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l run_url $argv[1]
|
||||||
|
set -l matches (string match --regex 'https://github.com/([^/]+)/([^/]+)/actions/runs/([0-9]+)' -- "$run_url")
|
||||||
|
if test (count $matches) -eq 0
|
||||||
|
echo "Error: Invalid GitHub Actions run URL format."
|
||||||
|
echo "Expected format: https://github.com/OWNER/REPO/actions/runs/RUN_ID"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l owner $matches[2]
|
||||||
|
set -l repo $matches[3]
|
||||||
|
set -l run_id $matches[4]
|
||||||
|
|
||||||
|
echo "Attempting to force-cancel run ID: $run_id in $owner/$repo..."
|
||||||
|
|
||||||
|
gh api \
|
||||||
|
--method POST \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
"/repos/$owner/$repo/actions/runs/$run_id/force-cancel"
|
||||||
|
|
||||||
|
if test $status -eq 0
|
||||||
|
echo "Force-cancel request sent successfully for run ID: $run_id"
|
||||||
|
else
|
||||||
|
echo "Failed to send force-cancel request for run ID: $run_id"
|
||||||
|
echo "Check the error message above for details."
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
29
home/private_dot_config/foot/foot.ini
Normal file
29
home/private_dot_config/foot/foot.ini
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[main]
|
||||||
|
font=monospace:size=12
|
||||||
|
pad=12x12 center
|
||||||
|
term=foot
|
||||||
|
selection-target=both
|
||||||
|
|
||||||
|
[scrollback]
|
||||||
|
lines=100000
|
||||||
|
|
||||||
|
[cursor]
|
||||||
|
style=block
|
||||||
|
blink=no
|
||||||
|
unfocused-style=hollow
|
||||||
|
|
||||||
|
[mouse]
|
||||||
|
hide-when-typing=yes
|
||||||
|
|
||||||
|
[colors]
|
||||||
|
background=141414
|
||||||
|
alpha=0.9
|
||||||
|
foreground=e0e0e0
|
||||||
|
|
||||||
|
[csd]
|
||||||
|
preferred=server
|
||||||
|
|
||||||
|
[key-bindings]
|
||||||
|
clipboard-copy=Control+Shift+c
|
||||||
|
clipboard-paste=Control+Shift+v
|
||||||
|
spawn-terminal=Control+Shift+n
|
||||||
@@ -9,7 +9,7 @@ exec-once = xwayland-satellite
|
|||||||
|
|
||||||
# System tray & bar
|
# System tray & bar
|
||||||
exec-once = nm-applet &
|
exec-once = nm-applet &
|
||||||
exec-once = waybar
|
exec-once = qs
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
exec-once = swaync
|
exec-once = swaync
|
||||||
@@ -23,14 +23,14 @@ exec-once = copyq --start-server
|
|||||||
|
|
||||||
# User apps
|
# User apps
|
||||||
exec-once = zen-browser
|
exec-once = zen-browser
|
||||||
exec-once = chromium --profile-directory=work --class=chromium-work
|
exec-once = ~/.local/bin/launch-on-workspace 2 chromium-work chromium --profile-directory=Default --class=chromium-work
|
||||||
exec-once = chromium --profile-directory=llm --class=chromium-llm
|
exec-once = ~/.local/bin/launch-on-workspace "special:llm" chromium-llm chromium --user-data-dir=$HOME/.config/chromium-llm --class=chromium-llm
|
||||||
exec-once = heynote
|
exec-once = ~/.local/bin/launch-on-workspace "special:llm" Heynote heynote
|
||||||
exec-once = telegram-desktop
|
exec-once = ~/.local/bin/launch-on-workspace "name:tg" org.telegram.desktop Telegram
|
||||||
exec-once = slack
|
exec-once = ~/.local/bin/launch-on-workspace "name:tg" Slack slack
|
||||||
exec-once = thunderbird
|
exec-once = ~/.local/bin/launch-on-workspace "name:tg" org.mozilla.Thunderbird thunderbird
|
||||||
exec-once = spotify
|
exec-once = ~/.local/bin/launch-on-workspace "name:media" spotify spotify
|
||||||
exec-once = ticktick
|
exec-once = ~/.local/bin/launch-on-workspace "special:org" ticktick ticktick
|
||||||
|
|
||||||
{{- if eq .deviceProfile "desktop" }}
|
{{- if eq .deviceProfile "desktop" }}
|
||||||
# Desktop: Hyprland plugins
|
# Desktop: Hyprland plugins
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
# Managed by chezmoi - edit source at ~/dotfiles
|
# Managed by chezmoi - edit source at ~/dotfiles
|
||||||
|
|
||||||
source = ~/.config/hypr/colors.conf
|
source = ~/.config/hypr/colors.conf
|
||||||
source = ~/.config/hypr/autostart.conf
|
|
||||||
source = ~/.config/hypr/workspaces.conf
|
source = ~/.config/hypr/workspaces.conf
|
||||||
source = ~/.config/hypr/monitors.conf
|
source = ~/.config/hypr/monitors.conf
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ source = ~/.config/hypr/monitors.conf
|
|||||||
### MY PROGRAMS ###
|
### MY PROGRAMS ###
|
||||||
###################
|
###################
|
||||||
|
|
||||||
$terminal = ghostty
|
$terminal = foot
|
||||||
$fileManager = thunar
|
$fileManager = thunar
|
||||||
$menu = wofi --show drun
|
$menu = wofi --show drun
|
||||||
$run_menu = wofi --show run
|
$run_menu = wofi --show run
|
||||||
@@ -51,14 +50,14 @@ decoration {
|
|||||||
inactive_opacity = 1.0
|
inactive_opacity = 1.0
|
||||||
|
|
||||||
shadow {
|
shadow {
|
||||||
enabled = true
|
enabled = false
|
||||||
range = 4
|
range = 4
|
||||||
render_power = 3
|
render_power = 3
|
||||||
color = rgba(1a1a1aee)
|
color = rgba(1a1a1aee)
|
||||||
}
|
}
|
||||||
|
|
||||||
blur {
|
blur {
|
||||||
enabled = true
|
enabled = false
|
||||||
size = 3
|
size = 3
|
||||||
passes = 1
|
passes = 1
|
||||||
vibrancy = 0.1696
|
vibrancy = 0.1696
|
||||||
@@ -66,7 +65,7 @@ decoration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
animations {
|
animations {
|
||||||
enabled = yes
|
enabled = no
|
||||||
|
|
||||||
bezier = easeOutQuint,0.23,1,0.32,1
|
bezier = easeOutQuint,0.23,1,0.32,1
|
||||||
bezier = easeInOutCubic,0.65,0.05,0.36,1
|
bezier = easeInOutCubic,0.65,0.05,0.36,1
|
||||||
@@ -97,15 +96,15 @@ animations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Smart gaps window rules
|
# Smart gaps window rules
|
||||||
windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
|
windowrule = match:float false, match:workspace w[tv1], border_size 0
|
||||||
windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
|
windowrule = match:float false, match:workspace w[tv1], rounding 0
|
||||||
windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
|
windowrule = match:float false, match:workspace f[1], border_size 0
|
||||||
windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
|
windowrule = match:float false, match:workspace f[1], rounding 0
|
||||||
|
|
||||||
# Quick Memo popup (yad)
|
# Quick Memo popup (yad)
|
||||||
windowrulev2 = float, class:^(yad)$
|
windowrule = match:class ^(yad)$, float on
|
||||||
windowrulev2 = center, class:^(yad)$
|
windowrule = match:class ^(yad)$, center on
|
||||||
windowrulev2 = pin, class:^(yad)$
|
windowrule = match:class ^(yad)$, pin on
|
||||||
|
|
||||||
binds {
|
binds {
|
||||||
hide_special_on_workspace_change = true
|
hide_special_on_workspace_change = true
|
||||||
@@ -251,6 +250,11 @@ bind = , Print, exec, ~/.local/bin/screenshot
|
|||||||
bind = $mainMod, mouse_down, workspace, e+1
|
bind = $mainMod, mouse_down, workspace, e+1
|
||||||
bind = $mainMod, mouse_up, workspace, e-1
|
bind = $mainMod, mouse_up, workspace, e-1
|
||||||
|
|
||||||
|
# Toggle llm workspace
|
||||||
|
bind = , mouse:279, exec, ~/.local/bin/hypr-debounce 125 hyprctl dispatch togglespecialworkspace llm
|
||||||
|
bind = , mouse:278, hyprexpo:expo, toggle
|
||||||
|
bind = , mouse:277, exec, ~/.local/bin/hypr-debounce 125 hyprctl dispatch workspace previous
|
||||||
|
|
||||||
# Move/resize windows with mainMod + LMB/RMB
|
# Move/resize windows with mainMod + LMB/RMB
|
||||||
bindm = $mainMod, mouse:272, movewindow
|
bindm = $mainMod, mouse:272, movewindow
|
||||||
bindm = $mainMod, mouse:273, resizewindow
|
bindm = $mainMod, mouse:273, resizewindow
|
||||||
@@ -274,18 +278,22 @@ bindl = , XF86AudioPrev, exec, playerctl previous
|
|||||||
##############################
|
##############################
|
||||||
|
|
||||||
# Window rules for apps
|
# Window rules for apps
|
||||||
windowrulev2 = workspace 1, class:^zen$
|
windowrule = match:class ^zen$, workspace 1
|
||||||
windowrulev2 = workspace 2, class:^(chromium-work)$
|
windowrule = match:class ^chromium-work$, workspace 2
|
||||||
windowrulev2 = workspace special:llm, class:^(chromium-llm)$
|
windowrule = match:initial_class ^chromium-work$, workspace 2
|
||||||
windowrulev2 = workspace special:llm, class:^(heynote|Heynote)$
|
windowrule = match:class ^chromium-llm$, workspace special:llm
|
||||||
windowrulev2 = workspace name:tg, class:^(org.telegram.desktop)$
|
windowrule = match:initial_class ^chromium-llm$, workspace special:llm
|
||||||
windowrulev2 = workspace name:tg, class:^(discord)$
|
windowrule = match:class ^(heynote|Heynote)$, workspace special:llm
|
||||||
windowrulev2 = workspace name:tg, class:^Slack$
|
windowrule = match:class ^(org.telegram.desktop)$, workspace name:tg
|
||||||
windowrulev2 = workspace name:tg, class:^org.mozilla.Thunderbird$
|
windowrule = match:class ^(discord)$, workspace name:tg
|
||||||
windowrulev2 = workspace name:media, class:^spotify$
|
windowrule = match:class ^Slack$, workspace name:tg
|
||||||
windowrulev2 = workspace special:org, class:^ticktick$
|
windowrule = match:class ^org.mozilla.Thunderbird$, workspace name:tg
|
||||||
windowrulev2 = suppressevent maximize, class:.*
|
windowrule = match:class ^spotify$, workspace name:media
|
||||||
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
windowrule = match:initial_class ^spotify$, workspace name:media
|
||||||
|
windowrule = match:class ^ticktick$, workspace special:org
|
||||||
|
windowrule = match:initial_class ^ticktick$, workspace special:org
|
||||||
|
windowrule = match:class .*, suppress_event maximize
|
||||||
|
windowrule = match:class ^$, match:title ^$, match:xwayland true, match:float true, match:fullscreen false, match:pin false, no_focus on
|
||||||
|
|
||||||
#############
|
#############
|
||||||
### PLUGINS ###
|
### PLUGINS ###
|
||||||
@@ -307,3 +315,6 @@ plugin {
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Autostart (must be at end so windowrule rules are loaded first)
|
||||||
|
source = ~/.config/hypr/autostart.conf
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
# Hyprpaper Configuration
|
# Hyprpaper Configuration
|
||||||
# Device: {{ .deviceProfile }} ({{ .hostname }})
|
# Device: {{ .deviceProfile }} ({{ .hostname }})
|
||||||
|
|
||||||
preload = ~/Pictures/wlpp/wallhaven-9dkeqd.png
|
splash = false
|
||||||
|
|
||||||
{{- if eq .deviceProfile "desktop" }}
|
wallpaper {
|
||||||
wallpaper = {{ .primaryMonitor }}, ~/Pictures/wlpp/wallhaven-9dkeqd.png
|
monitor =
|
||||||
{{- if .secondaryMonitor }}
|
path = ~/Pictures/wlpp/wallhaven-9dkeqd.png
|
||||||
wallpaper = {{ .secondaryMonitor }}, ~/Pictures/wlpp/wallhaven-9dkeqd.png
|
}
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
wallpaper = {{ .primaryMonitor }}, ~/Pictures/wlpp/wallhaven-9dkeqd.png
|
|
||||||
{{- end }}
|
|
||||||
|
|||||||
172
home/private_dot_config/niri/config.kdl.tmpl
Normal file
172
home/private_dot_config/niri/config.kdl.tmpl
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
// Niri configuration
|
||||||
|
// Device: {{ .deviceProfile }} ({{ .hostname }})
|
||||||
|
// Managed by chezmoi - edit source at ~/dotfiles
|
||||||
|
|
||||||
|
input {
|
||||||
|
keyboard {
|
||||||
|
xkb {
|
||||||
|
layout "us,ru"
|
||||||
|
options "caps:escape"
|
||||||
|
}
|
||||||
|
numlock
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if .hasTouchpad }}
|
||||||
|
touchpad {
|
||||||
|
tap
|
||||||
|
dwt
|
||||||
|
natural-scroll
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
focus-follows-mouse
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if eq .deviceProfile "desktop" }}
|
||||||
|
output "{{ .primaryMonitor }}" {
|
||||||
|
mode "{{ .primaryResolution }}"
|
||||||
|
position x=0 y=0
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if .secondaryMonitor }}
|
||||||
|
output "{{ .secondaryMonitor }}" {
|
||||||
|
mode "{{ .secondaryResolution }}"
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
output "{{ .primaryMonitor }}" {
|
||||||
|
mode "{{ .primaryResolution }}"
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
gaps 5
|
||||||
|
center-focused-column "never"
|
||||||
|
|
||||||
|
focus-ring {
|
||||||
|
off
|
||||||
|
}
|
||||||
|
|
||||||
|
border {
|
||||||
|
on
|
||||||
|
width 2
|
||||||
|
// Subtle orange gradient for a muted "Hackers (1995)" look.
|
||||||
|
active-gradient from="#ff9a33" to="#ffad55" angle=90
|
||||||
|
inactive-color "#3a2a12cc"
|
||||||
|
urgent-color "#ff0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
shadow {
|
||||||
|
off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animations {
|
||||||
|
off
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid border/background fill showing through transparent terminals.
|
||||||
|
prefer-no-csd
|
||||||
|
|
||||||
|
// Startup apps (portable subset from Hyprland autostart)
|
||||||
|
spawn-at-startup "nm-applet"
|
||||||
|
spawn-at-startup "qs"
|
||||||
|
spawn-at-startup "swaync"
|
||||||
|
spawn-at-startup "hyprpaper"
|
||||||
|
spawn-at-startup "hypridle"
|
||||||
|
spawn-at-startup "copyq" "--start-server"
|
||||||
|
spawn-at-startup "zen-browser"
|
||||||
|
|
||||||
|
// Keep quick memo popup floating.
|
||||||
|
window-rule {
|
||||||
|
match app-id=r#"^(yad)$"#
|
||||||
|
open-floating true
|
||||||
|
}
|
||||||
|
|
||||||
|
binds {
|
||||||
|
Mod+Shift+Slash { show-hotkey-overlay; }
|
||||||
|
|
||||||
|
// Terminal / launcher
|
||||||
|
Mod+Q { spawn "alacritty"; }
|
||||||
|
Mod+R { spawn-sh "wofi --show drun"; }
|
||||||
|
|
||||||
|
// Core controls
|
||||||
|
Mod+K repeat=false { close-window; }
|
||||||
|
Mod+M { quit; }
|
||||||
|
Mod+V { toggle-window-floating; }
|
||||||
|
Mod+E { toggle-overview; }
|
||||||
|
Mod+F { maximize-column; }
|
||||||
|
Mod+Shift+F { fullscreen-window; }
|
||||||
|
|
||||||
|
// Layout toggle (us/ru)
|
||||||
|
Mod+Space { switch-layout "next"; }
|
||||||
|
|
||||||
|
// Lock
|
||||||
|
Super+Alt+L { spawn-sh "pactl set-sink-mute @DEFAULT_SINK@ 1 && hyprlock"; }
|
||||||
|
|
||||||
|
// VPN and screenshot helpers
|
||||||
|
F6 { spawn-sh "~/.local/bin/vpn-switcher"; }
|
||||||
|
Print { spawn-sh "~/.local/bin/screenshot"; }
|
||||||
|
|
||||||
|
// Snap-like half-screen placement for focused window.
|
||||||
|
// Keep navigation on Mod+H / Mod+L.
|
||||||
|
Mod+Left {
|
||||||
|
spawn-sh "niri msg action move-window-to-floating && niri msg action set-window-width '50%' && niri msg action move-floating-window -x -100000";
|
||||||
|
}
|
||||||
|
Mod+Right {
|
||||||
|
spawn-sh "niri msg action move-window-to-floating && niri msg action set-window-width '50%' && niri msg action move-floating-window -x +100000";
|
||||||
|
}
|
||||||
|
Mod+Up { focus-window-up; }
|
||||||
|
Mod+Down { focus-window-down; }
|
||||||
|
Mod+H { focus-column-left; }
|
||||||
|
Mod+L { focus-column-right; }
|
||||||
|
Mod+J { focus-window-down; }
|
||||||
|
Mod+I { focus-window-up; }
|
||||||
|
|
||||||
|
// Move windows/columns
|
||||||
|
Mod+Ctrl+Left { move-column-left; }
|
||||||
|
Mod+Ctrl+Right { move-column-right; }
|
||||||
|
Mod+Ctrl+Up { move-window-up; }
|
||||||
|
Mod+Ctrl+Down { move-window-down; }
|
||||||
|
|
||||||
|
// Workspace navigation
|
||||||
|
Mod+1 { focus-workspace 1; }
|
||||||
|
Mod+2 { focus-workspace 2; }
|
||||||
|
Mod+3 { focus-workspace 3; }
|
||||||
|
Mod+4 { focus-workspace 4; }
|
||||||
|
Mod+5 { focus-workspace 5; }
|
||||||
|
Mod+6 { focus-workspace 6; }
|
||||||
|
Mod+7 { focus-workspace 7; }
|
||||||
|
Mod+8 { focus-workspace 8; }
|
||||||
|
Mod+9 { focus-workspace 9; }
|
||||||
|
|
||||||
|
Mod+Ctrl+1 { move-column-to-workspace 1; }
|
||||||
|
Mod+Ctrl+2 { move-column-to-workspace 2; }
|
||||||
|
Mod+Ctrl+3 { move-column-to-workspace 3; }
|
||||||
|
Mod+Ctrl+4 { move-column-to-workspace 4; }
|
||||||
|
Mod+Ctrl+5 { move-column-to-workspace 5; }
|
||||||
|
Mod+Ctrl+6 { move-column-to-workspace 6; }
|
||||||
|
Mod+Ctrl+7 { move-column-to-workspace 7; }
|
||||||
|
Mod+Ctrl+8 { move-column-to-workspace 8; }
|
||||||
|
Mod+Ctrl+9 { move-column-to-workspace 9; }
|
||||||
|
|
||||||
|
// Scroll workspaces
|
||||||
|
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
|
||||||
|
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
|
||||||
|
|
||||||
|
// Media keys
|
||||||
|
XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05+ -l 1.0"; }
|
||||||
|
XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05-"; }
|
||||||
|
XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; }
|
||||||
|
XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; }
|
||||||
|
|
||||||
|
{{- if .hasBattery }}
|
||||||
|
XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "set" "+10%"; }
|
||||||
|
XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "set" "10%-"; }
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
XF86AudioNext allow-when-locked=true { spawn-sh "playerctl next"; }
|
||||||
|
XF86AudioPause allow-when-locked=true { spawn-sh "playerctl play-pause"; }
|
||||||
|
XF86AudioPlay allow-when-locked=true { spawn-sh "playerctl play-pause"; }
|
||||||
|
XF86AudioPrev allow-when-locked=true { spawn-sh "playerctl previous"; }
|
||||||
|
}
|
||||||
568
home/private_dot_config/quickshell/shell.qml.tmpl
Normal file
568
home/private_dot_config/quickshell/shell.qml.tmpl
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property color bgColor: "#141414"
|
||||||
|
property color fgColor: "#cccccc"
|
||||||
|
property color dimColor: "#666666"
|
||||||
|
property color okColor: "#00ff00"
|
||||||
|
property color warnColor: "#ffaa00"
|
||||||
|
property color critColor: "#ff0000"
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: shellExec
|
||||||
|
running: false
|
||||||
|
}
|
||||||
|
|
||||||
|
function runShell(cmd) {
|
||||||
|
shellExec.command = ["/usr/bin/env", "bash", "-lc", cmd]
|
||||||
|
shellExec.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim(s) {
|
||||||
|
return (s || "").toString().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function wsLabel(name) {
|
||||||
|
if (name === "1") return "WEB"
|
||||||
|
if (name === "2") return "CODE"
|
||||||
|
if (name === "3") return "TERM"
|
||||||
|
if (name === "4") return "IDE"
|
||||||
|
if (name === "5") return "VM"
|
||||||
|
if (name === "6") return "GFX"
|
||||||
|
if (name === "7") return "DOC"
|
||||||
|
if (name === "8") return "GAME"
|
||||||
|
if (name === "9") return "MISC"
|
||||||
|
if (name === "10") return "TMP"
|
||||||
|
if (name === "special:termius") return "s:term"
|
||||||
|
if (name === "special:org") return "s:org"
|
||||||
|
if (name === "special:llm") return "s:llm"
|
||||||
|
return "WS"
|
||||||
|
}
|
||||||
|
|
||||||
|
function wsIgnored(name) {
|
||||||
|
return name === "chrome-sharing-indicator" || name === "special:chrome-sharing-indicator"
|
||||||
|
}
|
||||||
|
|
||||||
|
component ModuleBox: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.fgColor
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: 22
|
||||||
|
}
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
delegate: PanelWindow {
|
||||||
|
id: panel
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
screen: modelData
|
||||||
|
color: "transparent"
|
||||||
|
exclusionMode: ExclusionMode.Normal
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitHeight: 34
|
||||||
|
|
||||||
|
property var hyprMonitor: Hyprland.monitorFor(modelData)
|
||||||
|
visible: {{- if eq .deviceProfile "desktop" }}hyprMonitor && hyprMonitor.name === "{{ .primaryMonitor }}"{{- else }}true{{- end }}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 4
|
||||||
|
color: root.bgColor
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: mainRow
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 6
|
||||||
|
anchors.rightMargin: 6
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: leftGroup
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: workspacesBox
|
||||||
|
implicitWidth: workspacesRow.implicitWidth + 12
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: workspacesRow
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hyprland.workspaces
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
property bool ignored: root.wsIgnored(modelData.name)
|
||||||
|
|
||||||
|
visible: !ignored
|
||||||
|
color: modelData.urgent
|
||||||
|
? root.critColor
|
||||||
|
: (modelData.active ? root.fgColor : "transparent")
|
||||||
|
border.width: 1
|
||||||
|
border.color: modelData.urgent ? root.critColor : root.fgColor
|
||||||
|
radius: 0
|
||||||
|
implicitHeight: 18
|
||||||
|
implicitWidth: wsText.implicitWidth + 10
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: wsText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.wsLabel(modelData.name)
|
||||||
|
color: modelData.active || modelData.urgent ? "#000000" : root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: modelData.activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
if (wheel.angleDelta.y > 0) {
|
||||||
|
Hyprland.dispatch("workspace e+1")
|
||||||
|
} else if (wheel.angleDelta.y < 0) {
|
||||||
|
Hyprland.dispatch("workspace e-1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: Math.max(0, panel.width - leftGroup.implicitWidth - rightGroup.implicitWidth - 12)
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: rightGroup
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: vpnBox
|
||||||
|
implicitWidth: vpnText.implicitWidth + 12
|
||||||
|
property string vpnClass: "disconnected"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: vpnText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "VPN off"
|
||||||
|
color: vpnBox.vpnClass === "connected"
|
||||||
|
? root.okColor
|
||||||
|
: (vpnBox.vpnClass === "disconnected" ? root.dimColor : root.fgColor)
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: vpnProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "~/.local/bin/vpn-status"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
const raw = root.trim(this.text)
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw)
|
||||||
|
vpnText.text = parsed.text || "VPN off"
|
||||||
|
vpnBox.vpnClass = parsed.class || "disconnected"
|
||||||
|
} catch (_) {
|
||||||
|
vpnText.text = raw || "VPN off"
|
||||||
|
vpnBox.vpnClass = "disconnected"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: vpnProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: root.runShell("~/.local/bin/vpn-switcher")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: spkBox
|
||||||
|
implicitWidth: spkText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: spkText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "VOL --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: spkProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "mute=$(pactl get-sink-mute @DEFAULT_SINK@ 2>/dev/null | awk '{print $2}'); vol=$(pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null | awk 'NR==1{print $5}'); if [ \"${mute}\" = \"yes\" ]; then echo 'VOL muted'; elif [ -n \"${vol}\" ]; then echo \"VOL ${vol}\"; else echo 'VOL --'; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: spkText.text = root.trim(this.text) || "VOL --" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 3000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: spkProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: function(mouse) {
|
||||||
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
root.runShell("pactl set-sink-mute @DEFAULT_SINK@ toggle")
|
||||||
|
} else {
|
||||||
|
root.runShell("pavucontrol -t 3")
|
||||||
|
}
|
||||||
|
spkProc.running = true
|
||||||
|
}
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
if (wheel.angleDelta.y > 0) {
|
||||||
|
root.runShell("~/.local/bin/audio-sink-cycle up")
|
||||||
|
} else if (wheel.angleDelta.y < 0) {
|
||||||
|
root.runShell("~/.local/bin/audio-sink-cycle down")
|
||||||
|
}
|
||||||
|
spkProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: micBox
|
||||||
|
implicitWidth: micText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: micText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "MIC --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: micProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "mute=$(pactl get-source-mute @DEFAULT_SOURCE@ 2>/dev/null | awk '{print $2}'); vol=$(pactl get-source-volume @DEFAULT_SOURCE@ 2>/dev/null | awk 'NR==1{print $5}'); if [ \"${mute}\" = \"yes\" ]; then echo 'MIC muted'; elif [ -n \"${vol}\" ]; then echo \"MIC ${vol}\"; else echo 'MIC --'; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: micText.text = root.trim(this.text) || "MIC --" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 3000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: micProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: function(mouse) {
|
||||||
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
root.runShell("pactl set-source-mute @DEFAULT_SOURCE@ toggle")
|
||||||
|
} else {
|
||||||
|
root.runShell("pavucontrol -t 4")
|
||||||
|
}
|
||||||
|
micProc.running = true
|
||||||
|
}
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
if (wheel.angleDelta.y > 0) {
|
||||||
|
root.runShell("pactl set-source-volume @DEFAULT_SOURCE@ +2%")
|
||||||
|
} else if (wheel.angleDelta.y < 0) {
|
||||||
|
root.runShell("pactl set-source-volume @DEFAULT_SOURCE@ -2%")
|
||||||
|
}
|
||||||
|
micProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: netBox
|
||||||
|
implicitWidth: netText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: netText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "NET down"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: netProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "wifi=$(iwgetid -r 2>/dev/null || true); if [ -n \"$wifi\" ]; then sig=$(awk 'NR==3{gsub(/\./,\"\",$3); q=$3+0; printf \"%d\", int((q/70)*100)}' /proc/net/wireless 2>/dev/null); [ -z \"$sig\" ] && sig=0; echo \"NET wifi $wifi ${sig}%\"; exit; fi; iface=$(ip route | awk '/^default/{print $5; exit}'); if [ -n \"$iface\" ]; then ip4=$(ip -4 addr show dev \"$iface\" | awk '/inet /{print $2; exit}' | cut -d/ -f1); if [ -n \"$ip4\" ]; then echo \"NET eth $ip4\"; else echo 'NET link'; fi; else echo 'NET down'; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: netText.text = root.trim(this.text) || "NET down" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: netProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if .hasBattery }}
|
||||||
|
ModuleBox {
|
||||||
|
id: batteryBox
|
||||||
|
implicitWidth: batteryText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: batteryText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "BAT --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: batteryProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "cap=$(cat /sys/class/power_supply/BAT*/capacity 2>/dev/null | head -n1); stat=$(cat /sys/class/power_supply/BAT*/status 2>/dev/null | head -n1); if [ -z \"$cap\" ]; then echo 'BAT --'; exit; fi; if [ \"$stat\" = 'Charging' ]; then echo \"BAT+ ${cap}%\"; elif [ \"$stat\" = 'Full' ]; then echo 'BAT full'; elif [ \"$stat\" = 'Not charging' ] || [ \"$stat\" = 'Unknown' ]; then echo \"BAT= ${cap}%\"; else echo \"BAT ${cap}%\"; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
const v = root.trim(this.text)
|
||||||
|
batteryText.text = v || "BAT --"
|
||||||
|
const m = v.match(/(\d+)%/)
|
||||||
|
if (v.startsWith("BAT+")) {
|
||||||
|
batteryText.color = root.okColor
|
||||||
|
} else if (m && Number(m[1]) <= 15) {
|
||||||
|
batteryText.color = root.critColor
|
||||||
|
} else if (m && Number(m[1]) <= 30) {
|
||||||
|
batteryText.color = root.warnColor
|
||||||
|
} else {
|
||||||
|
batteryText.color = root.fgColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 10000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: batteryProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: brtBox
|
||||||
|
implicitWidth: brtText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: brtText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "BRT --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: brtProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "pct=$(brightnessctl -m 2>/dev/null | awk -F, '{print $4}' | tr -d '%'); if [ -n \"$pct\" ]; then echo \"BRT ${pct}%\"; else echo 'BRT --'; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: brtText.text = root.trim(this.text) || "BRT --" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: brtProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
if (wheel.angleDelta.y > 0) {
|
||||||
|
root.runShell("brightnessctl s 5%+")
|
||||||
|
} else if (wheel.angleDelta.y < 0) {
|
||||||
|
root.runShell("brightnessctl s 5%-")
|
||||||
|
}
|
||||||
|
brtProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: cpuBox
|
||||||
|
implicitWidth: cpuText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: cpuText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "CPU --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: cpuProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "read -r _ u n s i _ < /proc/stat; used=$((u+n+s)); total=$((u+n+s+i)); if [ \"$total\" -gt 0 ]; then printf 'CPU %d%%\\n' $((used*100/total)); else echo 'CPU --'; fi"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: cpuText.text = root.trim(this.text) || "CPU --" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: cpuProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: memBox
|
||||||
|
implicitWidth: memText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: memText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "MEM --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: memProc
|
||||||
|
command: ["/usr/bin/env", "bash", "-lc", "free | awk '/Mem:/ { if ($2 > 0) printf \"MEM %d%%\\n\", int($3*100/$2); else print \"MEM --\"; }'"]
|
||||||
|
running: true
|
||||||
|
stdout: StdioCollector { onStreamFinished: memText.text = root.trim(this.text) || "MEM --" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 5000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: memProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: clockBox
|
||||||
|
implicitWidth: clockText.implicitWidth + 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: clockText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "TIME --"
|
||||||
|
color: root.fgColor
|
||||||
|
font.family: "Terminus, IBM Plex Mono, JetBrainsMono Nerd Font, monospace"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: {
|
||||||
|
const now = new Date()
|
||||||
|
clockText.text = Qt.formatDateTime(now, "'TIME' yyyy-MM-dd HH:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
const now = new Date()
|
||||||
|
clockText.text = Qt.formatDateTime(now, "'TIME' yyyy-MM-dd HH:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleBox {
|
||||||
|
id: trayBox
|
||||||
|
implicitWidth: trayRow.implicitWidth + 12
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: trayRow
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 0
|
||||||
|
implicitWidth: 18
|
||||||
|
implicitHeight: 18
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: modelData.icon
|
||||||
|
asynchronous: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
onClicked: function(mouse) {
|
||||||
|
if (mouse.button === Qt.RightButton && modelData.hasMenu) {
|
||||||
|
modelData.display(panel, mouse.x, mouse.y)
|
||||||
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
|
modelData.secondaryActivate()
|
||||||
|
} else {
|
||||||
|
modelData.activate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
if (wheel.angleDelta.y > 0) {
|
||||||
|
modelData.scroll(1, false)
|
||||||
|
} else if (wheel.angleDelta.y < 0) {
|
||||||
|
modelData.scroll(-1, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
justfile
Normal file
40
justfile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
set shell := ["bash", "-euo", "pipefail", "-c"]
|
||||||
|
|
||||||
|
# Show available recipes
|
||||||
|
default:
|
||||||
|
@just --list
|
||||||
|
|
||||||
|
# Chezmoi workflows
|
||||||
|
apply:
|
||||||
|
chezmoi apply
|
||||||
|
|
||||||
|
diff:
|
||||||
|
chezmoi diff
|
||||||
|
|
||||||
|
status:
|
||||||
|
chezmoi status
|
||||||
|
|
||||||
|
edit file:
|
||||||
|
chezmoi edit {{file}}
|
||||||
|
|
||||||
|
# Niri workflows
|
||||||
|
niri-reload:
|
||||||
|
niri msg action load-config-file
|
||||||
|
|
||||||
|
niri-validate:
|
||||||
|
chezmoi execute-template < home/private_dot_config/niri/config.kdl.tmpl > /tmp/niri-config.kdl
|
||||||
|
niri validate -c /tmp/niri-config.kdl
|
||||||
|
|
||||||
|
# Quickshell / Hypr helpers
|
||||||
|
qs-reload:
|
||||||
|
pkill -USR2 qs || true
|
||||||
|
|
||||||
|
hypr-reload:
|
||||||
|
hyprctl reload
|
||||||
|
|
||||||
|
# Combined helpers
|
||||||
|
apply-niri: apply niri-validate niri-reload
|
||||||
|
|
||||||
|
apply-qs: apply qs-reload
|
||||||
|
|
||||||
|
check: diff niri-validate
|
||||||
Reference in New Issue
Block a user