This commit is contained in:
2026-03-11 13:38:24 +01:00
parent 68302ad3d6
commit 95bd2acda6
6 changed files with 619 additions and 0 deletions

3
.gitignore vendored
View File

@@ -64,6 +64,9 @@ swaylock/*
swayidle/*
!swayidle/config
!waybar
!bin
# flameshot
!flameshot
flameshot/*

71
audit/remaining.md Normal file
View File

@@ -0,0 +1,71 @@
# Remaining Audit Findings
Items already completed: zsh, starship, git, ghostty, tmux config + scripts.
## Sway
### Security
- **[high]** waybar `custom/ssh-login` on-click runs `pkill -9 -t $(who | awk '{ print $2 }')`. Unquoted command substitution causes word-splitting across multiple TTYs. Use `pkill -HUP` instead of `-9`, and quote the substitution or target a specific TTY.
- **[medium]** `80-autostart.conf` starts `protonmail-bridge -n` as bare `exec`. Consider systemd user service for proper lifecycle management.
- **[medium]** swayidle timeout of 300s (5 min) is relatively long for an unattended workstation.
- **[medium]** `swaylock/config` lacks `show-failed-attempts` and `ignore-empty-password` verification.
- **[low]** `wlsunset -l 46.1 -L 14.5` exposes approximate geographic coordinates in public dotfiles.
### Idiomacy
- **[issue]** host.d include is before config.d/* in main sway config. Host files cannot reference `$variables` from `10-variables.conf`. Move host.d include after config.d/*.
- **[issue]** `41-theme-swayfx.conf` uses SwayFX-specific directives that error on stock sway. Gate or document.
- **[issue]** Volume keybindings mix `pactl` (mute toggle) and `pamixer` (volume up/down). Pick one consistently. Mic mute on F16 also uses `pactl` instead of `pamixer`.
- **[issue]** wob FIFO setup has race condition on sway restart. Consider wob 0.14+ `--socket` flag or `$XDG_RUNTIME_DIR/wob.sock` path.
- **[issue]** swayidle missing `lock` event handler (`lock 'swaylock -f'`). `loginctl lock-session` won't lock the screen without it.
- **[issue]** No idle inhibitor configured. Fullscreen video will trigger lock after timeout. Options: waybar `idle_inhibitor` module, `for_window` rule with `inhibit_idle fullscreen`, or `sway-audio-idle-inhibit`.
### Waybar
- **[issue]** `custom/ssh-login` polls every 1 second. Reduce to 10-30s.
- **[issue]** `custom/ssh-login` on-click uses `pkill -9` (SIGKILL). Use SIGHUP.
- **[dead]** `custom/power` module defined but not included in any bar's module list.
- **[issue]** `style.css` references `@define-color` names (`@gray`, `@background-light`, `@foreground`, `@red`, etc.) that are not defined in the file. They must come from an external GTK theme. Define them in `style.css` for self-containment or document the dependency.
- **[issue]** Hardcoded `#1e1e2e` (Catppuccin Mocha) in `#waybar .module` conflicts with gruvbox scheme. Leftover from a template.
- **[note]** `cpu` on-click hardcodes `ghostty -e htop` (waybar JSONC doesn't support sway variables).
### Typos
- `50-keybind.conf` line 13: `# programs'` — trailing apostrophe
- `50-keybind.conf` line 88: `# xf86-brightnes` — missing trailing 's'
- `80-autostart.conf` line 1: `# deamon` — should be "daemon"
## Structure
### .gitignore
- **[dead]** `!alacritty` is tracked but alacritty is no longer used (ghostty replaced it). Remove or keep intentionally.
- **[issue]** `!waybar` and `!bin` un-ignore entire directories with no interior filter. Every other program explicitly whitelists files. Tighten to two-level pattern:
```
!waybar
waybar/*
!waybar/config.jsonc
!waybar/style.css
```
- **[note]** `!ghostty/themes`, `!sway/config.d`, `!sway/host.d` also un-ignore whole subdirectories. Intentional for sway (new drop-in files auto-tracked), worth noting for ghostty themes.
### bin/ directory
- `bin/waybar-custom-cider.sh` is the only script and is waybar-specific. Consider moving to `waybar/cider.sh` and updating the exec path in `waybar/config.jsonc`.
### SSH preview duplication
- `zsh/ssh-menu` defines `_ssh_menu_preview` and `tmux/tmux-ssher` defines `_preview`. Same function with cosmetic differences. Extract to a shared script (e.g. `bin/ssh-preview`) to eliminate drift. The `command -v host` guard is only in ssh-menu, not ssher.
### Paths
- `tmux.conf` hardcodes `~/.config/tmux/...` in run-shell bindings instead of `$XDG_CONFIG_HOME`.
- `flameshot.ini` hardcodes `/home/matej/screens` — breaks on other usernames/machines.
- `swaylock/config` and `sway/config.d/20-output.conf` reference `~/.assets/` — not XDG, but consistent with each other.
### Consistency
- Waybar CSS color variables depend on external GTK theme (see waybar section above).
- Swaylock uses `#000000`/`#ffffff` (black/white) instead of gruvbox. May be intentional for contrast.
- Alacritty config is dead weight if no longer used.

34
bin/waybar-custom-cider.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
url="http://localhost:10767/api/v1/playback"
status_raw=$(curl -s --max-time 2 "$url/is-playing")
# CASE 1: API is totally unreachable (App closed)
if [[ -z "$status_raw" ]]; then
echo '{"text": "offline", "class": "offline", "alt": "offline"}'
exit 0
fi
# Extract playing status, defaulting to false if null
is_playing=$(echo "$status_raw" | jq -r '.is_playing // false')
# 2. Get song info
info_raw=$(curl -s --max-time 2 "$url/now-playing")
# CASE 2 & 3: Handle empty metadata vs. active metadata
echo "$info_raw" | jq -c \
--argjson is_playing "$is_playing" \
'
# Helper function to escape & for Pango
def pango_escape: sub("&"; "&"; "g");
if (.info.name == null or .info.name == "") then
{text: "idle", class: "paused"}
else
{
text: "\(.info.name | pango_escape) - \(.info.artistName | pango_escape)",
tooltip: "\(.info.albumName | pango_escape // "Unknown")",
class: (if $is_playing then "playing" else "paused" end)
}
end'

214
waybar/config.jsonc Normal file
View File

@@ -0,0 +1,214 @@
[
{
"layer": "top",
"position": "top",
"height": 30,
"spacing": 1,
"margin": 0,
"modules-left": [
"sway/workspaces", "sway/mode"
],
"modules-center": [
"privacy",
"custom/ssh-login"
],
"modules-right": [
"custom/cider",
"pulseaudio",
"power-profiles-daemon",
"cpu",
"memory",
"temperature",
"backlight",
"battery",
"tray",
],
//
"sway/workspaces": {
"disable-scroll": true,
"format": "{icon}",
"format-icons": {
"1": "I",
"2": "II",
"3": "III",
"4": "IV",
"5": "V",
"6": "VI",
"7": "VII",
"8": "VIII",
"9": "IX",
"10": "X",
},
},
"sway/mode": {
"format": "{}",
},
"custom/cider": {
"format": "{}",
"return-type": "json",
"max-length": 18,
"interval": 1,
"tooltip": true,
"exec": "~/.config/bin/waybar-custom-cider.sh",
"on-click": "curl -s -X POST http://localhost:10767/api/v1/playback/playpause",
"on-click-right": "curl -s -X POST http://localhost:10767/api/v1/playback/next",
},
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-out",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
],
"ignore-monitor": true,
"ignore": [
{
"type": "audio-in",
"name": "cava"
},
{
"type": "screenshare",
"name": "obs"
}
]
},
"tray": {
"icon-size": 18,
"spacing": 10,
},
"cpu": {
"format": "cpu:{usage}%",
"tooltip": false,
"on-click": "ghostty -e htop",
},
"memory": {
"interval": 10,
"format": "ram:{}%",
"tooltip-format": "total: {total:0.2f}GiB\nused: {used:0.2f}GiB\navailable: {avail:0.2f}GiB\nswap: {swapUsed:0.2f}/{swapTotal:0.2f}GiB",
"on-click": "ghostty -e htop",
},
"temperature": {
// "thermal-zone": 2,
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
"critical-threshold": 80,
// "format-critical": "{temperatureC}°C {icon}",
"format": "{temperatureC}°C {icon}",
"format-icons": ["", "", ""],
"on-click": "ghostty -e s-tui",
"tooltip": false,
},
"backlight": {
// "device": "acpi_video1",
"format": "{percent}% {icon}",
"format-icons": ["", "", "", "", "", "", "", "", ""],
"tooltip": false,
},
"battery": {
"states": {
// "good": 95,
"warning": 30,
"critical": 15,
},
"format": "{capacity}% {icon}",
"format-full": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
"format-alt": "{time} {icon}",
// "format-good": "", // An empty format will hide the module
// "format-full": "",
"format-icons": ["", "", "", "", ""],
},
"power-profiles-daemon": {
"format": "{icon}",
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
"tooltip": true,
"format-icons": {
"default": "",
"performance": "",
"balanced": "",
"power-saver": "",
},
},
"network": {
// "interface": "wlp2*", // (Optional) To force the use of this interface
"format-wifi": "{essid} ({signalStrength}%) ",
"format-ethernet": "ipv4:{ipaddr}/{cidr}",
"tooltip-format": "{ifname} via {gwaddr} ",
"format-linked": "{ifname} (No IP) ",
"format-disconnected": "Disconnected ⚠",
"format-alt": "{ifname}: {ipaddr}/{cidr}",
},
"pulseaudio": {
// "scroll-step": 1, // %, can be a float
"format": "vol:{volume}%/{format_source}",
"format-bluetooth": "{volume}% {icon} {format_source}",
"format-bluetooth-muted": " {icon} {format_source}",
"format-muted": " {format_source}",
"format-source": "{volume}%",
"format-source-muted": "",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", "", ""],
},
"on-click": "pavucontrol",
},
"custom/power": {
"format": "⏻ ",
"tooltip": false,
"menu": "on-click",
"menu-file": "$HOME/.config/waybar/power_menu.xml", // Menu file in resources folder
"menu-actions": {
"shutdown": "shutdown",
"reboot": "reboot",
"suspend": "systemctl suspend",
"hibernate": "systemctl hibernate",
},
},
"custom/ssh-login": {
"format": "{}",
"interval": 1,
// "exec-if": "who",
"exec": "who | awk '{ print $2 }'",
"on-click": "pkill -9 -t $(who | awk '{ print $2 }')",
},
},
{
"layer": "top",
"position": "bottom",
"height": 30,
"spacing": 1,
"margin": 0,
"modules-right": [
"network",
"clock",
],
"network": {
"format-ethernet": "{ipaddr}/{cidr}",
"format-disconnected": "disconnected"
},
"clock": {
"interval": 1,
"format": "{:%Y/%m/%d %H:%M:%S}",
"tooltip-format": "<big><tt>{calendar}</tt></big>",
},
}
]

297
waybar/style.css Normal file
View File

@@ -0,0 +1,297 @@
@define-color workspaces-color @gray;
@define-color workspaces-focused-bg @background-light;
@define-color workspaces-focused-fg @foreground;
@define-color workspaces-urgent-bg @red;
@define-color workspaces-urgent-fg @background;
@define-color cider-color @red;
@define-color clock-color @foreground;
@define-color pulseaudio-color @blue;
@define-color pulseaudio-muted-color @gray;
@define-color network-color @magenta;
@define-color network-disconnected-color @red;
@define-color cpu-color @orange;
@define-color memory-color @cyan;
@define-color temperature-color @yellow;
@define-color temperature-critical-color @red;
@define-color backlight-color @white;
@define-color battery-color @foreground;
@define-color battery-charging-color @green;
@define-color battery-warning-color @yellow;
@define-color battery-critical-color @red;
* {
font-family: "JetBrainsMono Nerd Font";
font-size: 14px;
font-weight: bold;
}
window#waybar {
color: #ffffff;
transition-property: background-color;
transition-duration: .5s;
}
window#waybar.hidden {
opacity: 0.2;
}
/* This targets every module */
#waybar .module {
background-color: #1e1e2e; /* Your desired module color */
}
/* Specific grouping (Optional: if you want modules to stick together in islands) */
.modules-left, .modules-center, .modules-right {}
button {
box-shadow: none;
border: none;
border-radius: 0;
}
button:hover {
background: inherit;
box-shadow: none;
}
/* -----------------------------------------------------------------------------
* Workspaces
* ----------------------------------------------------------------------------- */
#workspaces button {
padding: 0 8px;
background-color: transparent;
color: @workspaces-color;
margin: 0;
}
#workspaces button:hover {
background: @background-light;
color: @foreground;
box-shadow: none;
}
/* The "Neovim Buffer" Look:
Active workspace is lighter background + cream text.
No flashy underlines. */
#workspaces button.focused {
background-color: @background-light;
color: @workspaces-focused-fg;
box-shadow: none;
}
#workspaces button.urgent {
background-color: @workspaces-urgent-bg;
color: @workspaces-urgent-fg;
}
/* -----------------------------------------------------------------------------
* Modules
* ----------------------------------------------------------------------------- */
#mode,
#clock,
#battery,
#cpu,
#memory,
#disk,
#temperature,
#backlight,
#network,
#pulseaudio,
#wireplumber,
#custom-media,
#tray,
#idle_inhibitor,
#scratchpad,
#power-profiles-daemon,
#mpd,
#custom-cider {
color: @clock-color;
font-weight: bold;
padding: 0 10px;
margin: 0 2px;
background-color: transparent;
border: none; /* Removed the underlines for a cleaner look */
}
#window,
#workspaces {
margin: 0 4px;
}
.modules-left > widget:first-child > #workspaces { margin-left: 0; }
.modules-right > widget:last-child > #workspaces { margin-right: 0; }
/* -----------------------------------------------------------------------------
* Module Specifics
* ----------------------------------------------------------------------------- */
#battery {
color: @battery-color;
}
#battery.charging, #battery.plugged {
color: @battery-charging-color;
}
#battery.warning:not(.charging) {
color: @battery-warning-color;
}
@keyframes blink {
to {
background-color: @red;
color: @background;
}
}
#battery.critical:not(.charging) {
color: @battery-critical-color;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: steps(12);
animation-iteration-count: infinite;
animation-direction: alternate;
}
/* #cpu { */
/* color: @cpu-color; */
/* } */
/**/
/* #memory { */
/* color: @memory-color; */
/* } */
/**/
/* #disk { */
/* color: @yellow; */
/* } */
/**/
/* #backlight { */
/* color: @backlight-color; */
/* } */
/**/
/* #network { */
/* color: @network-color; */
/* } */
/**/
/* #network.disconnected { */
/* color: @network-disconnected-color; */
/* } */
/**/
/* #pulseaudio { */
/* color: @pulseaudio-color; */
/* } */
/**/
/* #pulseaudio.muted { */
/* color: @pulseaudio-muted-color; */
/* } */
/**/
/* #wireplumber { */
/* color: @foreground; */
/* } */
/**/
/* #wireplumber.muted { */
/* color: @red; */
/* } */
#custom-media {
color: @green;
min-width: 100px;
}
#temperature {
color: @temperature-color;
}
#temperature.critical {
color: @temperature-critical-color;
}
#tray {
background-color: @background-light;
border-radius: 4px; /* Slight roundness for the tray container */
padding: 0 8px;
}
#tray > .passive {
-gtk-icon-effect: dim;
}
#tray > .needs-attention {
-gtk-icon-effect: highlight;
color: @red;
}
#idle_inhibitor {
color: @gray;
}
#idle_inhibitor.activated {
color: @foreground;
}
#mpd {
color: @green;
}
#mpd.disconnected {
color: @red;
}
#mpd.stopped {
color: @gray;
}
#mpd.paused {
color: @blue;
}
#language {
background: @background-light;
color: @foreground;
padding: 0 5px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state {
color: @foreground;
padding: 0 0px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state > label.locked {
color: @red;
}
#scratchpad {
background: transparent;
color: @gray;
}
#scratchpad.empty {
background-color: transparent;
}
#privacy {
padding: 0;
}
#privacy-item {
padding: 0 5px;
color: @foreground;
}
#privacy-item.screenshare {
color: @orange;
}
#privacy-item.audio-in {
color: @green;
}
#privacy-item.audio-out {
color: @blue;
}