diff --git a/hypr/rules.conf b/hypr/rules.conf index 09acb16..233afe9 100644 --- a/hypr/rules.conf +++ b/hypr/rules.conf @@ -5,6 +5,8 @@ # 文件对话框 windowrule = float, class:^(thunar|google-chrome|chromium)$, title:^(.*文件.*|.*保存.*|.*打开.*) +windowrule = float, class:^(Alacritty)$, title:^(alacritty -e \./system-update\.sh.*) + # Ignore maximize requests from apps. You'll probably like this. windowrule = suppressevent maximize, class:.* diff --git a/waybar/LICENSE b/waybar/LICENSE new file mode 100644 index 0000000..355f2ba --- /dev/null +++ b/waybar/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Jesse Mirabel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/waybar/config.jsonc b/waybar/config.jsonc new file mode 100644 index 0000000..97a2845 --- /dev/null +++ b/waybar/config.jsonc @@ -0,0 +1,119 @@ +{ + /* + "include": [ + "~/.config/waybar/modules/*.jsonc", + "~/.config/waybar/modules/custom/*.jsonc", + "~/.config/waybar/modules/hyprland/*.jsonc" + + // modules that are not included by default: + // "~/.config/waybar/modules/extras/*.jsonc" + ], + */ + + "include": [ + // modules-left + "~/.config/waybar/modules/custom/user.jsonc", + "~/.config/waybar/modules/hyprland/workspaces.jsonc", + "~/.config/waybar/modules/hyprland/window.jsonc", + + // modules-center + "~/.config/waybar/modules/hyprland/windowcount.jsonc", + "~/.config/waybar/modules/temperature.jsonc", + "~/.config/waybar/modules/memory.jsonc", + "~/.config/waybar/modules/cpu.jsonc", + "~/.config/waybar/modules/custom/distro.jsonc", + "~/.config/waybar/modules/idle_inhibitor.jsonc", + "~/.config/waybar/modules/clock.jsonc", + "~/.config/waybar/modules/custom/system_update.jsonc", + + // modules-right + "~/.config/waybar/modules/mpris.jsonc", + "~/.config/waybar/modules/pulseaudio.jsonc", + "~/.config/waybar/modules/backlight.jsonc", + "~/.config/waybar/modules/battery.jsonc", + "~/.config/waybar/modules/custom/power_menu.jsonc", + + "~/.config/waybar/modules/custom/dividers.jsonc" + + // modules that are not included by default: + // "~/.config/waybar/modules/extras/taskbar.jsonc", + // "~/.config/waybar/modules/extras/tray.jsonc", + // "~/.config/waybar/modules/extras/wireplumber.jsonc" + ], + + /*------------ + layout + ------------*/ + + "modules-left": [ + "group/user", + "custom/left_div#1", + "hyprland/workspaces", + "custom/right_div#1", + "hyprland/window" + ], + "modules-center": [ + "hyprland/windowcount", + "custom/left_div#2", + "temperature", + "custom/left_div#3", + "memory", + "custom/left_div#4", + "cpu", + "custom/left_inv#1", + "custom/left_div#5", + "custom/distro", + "custom/right_div#2", + "custom/right_inv#1", + "idle_inhibitor", + "clock#time", + "custom/right_div#3", + "clock#date", + "custom/right_div#4", + "custom/system_update", + "custom/right_div#5" + ], + "modules-right": [ + "mpris", + "custom/left_div#6", + "group/pulseaudio", + "custom/left_div#7", + "backlight", + "custom/left_div#8", + "battery", + "custom/left_inv#2", + "custom/power_menu" + ], + + /*------------- + options + -------------*/ + + // "expand-center": + // "expand-left": + // "expand-right": + "layer": "top", + // "output": + // "position": + "height": 0, + "width": 0, + "margin": 0, + // "margin-top": + // "margin-left": + // "margin-bottom": + // "margin-right": + // "no-center": + "spacing": 0, + // "name": + "mode": "dock", + // "start_hidden": + // "modifier-reset": + // "exclusive": + // "fixed-center": + // "passthrough": + // "ipc": + // "id": + "reload_style_on_change": true + // "on-sigusr1": + // "on-sigusr2": +} diff --git a/waybar/current-theme.css b/waybar/current-theme.css new file mode 100644 index 0000000..ea025b2 --- /dev/null +++ b/waybar/current-theme.css @@ -0,0 +1,63 @@ +/* catppuccin mocha */ + +@define-color rosewater #f5e0dc; +@define-color flamingo #f2cdcd; +@define-color pink #f5c2e7; +@define-color mauve #cba6f7; +@define-color red #f38ba8; +@define-color maroon #eba0ac; +@define-color peach #fab387; +@define-color yellow #f9e2af; +@define-color green #a6e3a1; +@define-color teal #94e2d5; +@define-color sky #89dceb; +@define-color sapphire #74c7ec; +@define-color blue #89b4fa; +@define-color lavender #b4befe; +@define-color text #cdd6f4; +@define-color subtext1 #bac2de; +@define-color subtext0 #a6adc8; +@define-color overlay2 #9399b2; +@define-color overlay1 #7f849c; +@define-color overlay0 #6c7086; +@define-color surface2 #585b70; +@define-color surface1 #45475a; +@define-color surface0 #313244; +@define-color base #1e1e2e; +@define-color mantle #181825; +@define-color crust #11111b; + +/* + br - border + bg - background + fg - foreground +*/ + +/* main colors */ + +@define-color accent @lavender; +@define-color main-br @subtext0; +@define-color main-bg @crust; +@define-color main-fg @text; +@define-color hover-bg @base; +@define-color hover-fg alpha(@main-fg, 0.75); +@define-color outline shade(@main-bg, 0.5); + +/* module colors */ + +@define-color workspaces @mantle; +@define-color temperature @mantle; +@define-color memory @base; +@define-color cpu @surface0; +@define-color time @surface0; +@define-color date @base; +@define-color tray @mantle; +@define-color volume @mantle; +@define-color backlight @base; +@define-color battery @surface0; + +/* state colors */ + +@define-color warning @yellow; +@define-color critical @red; +@define-color charging @green; diff --git a/waybar/install.sh b/waybar/install.sh new file mode 100755 index 0000000..1f98a40 --- /dev/null +++ b/waybar/install.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +RED='\033[1;31m' +GRN='\033[1;32m' +BLU='\033[1;34m' +RST='\033[0m' + +DEPS=( + bluez + bluez-utils # bluetoothctl + brightnessctl + fzf + networkmanager # nmcli + pacman-contrib # checkupdates + pipewire-pulse + otf-commit-mono-nerd +) + +main() { + printf '%bInstalling dependencies...%b\n' "$BLU" "$RST" + + local package + local error=0 + for package in "${DEPS[@]}"; do + if pacman -Qi "$package" > /dev/null; then + printf '[%b/%b] %s\n' "$GRN" "$RST" "$package" + else + printf '[ ] %s...\n' "$package" + if sudo pacman -S --noconfirm "$package"; then + printf '[%b+%b] %s\n' "$GRN" "$RST" "$package" + else + printf '[%bx%b] %s\n' "$RED" "$RST" "$package" + ((error++)) + fi + fi + done + + printf '\n%bMaking scripts executable...%b\n' "$BLU" "$RST" + chmod +x ~/.config/waybar/scripts/*.sh --verbose + + pkill waybar + waybar &> /dev/null & + disown + + if ((error > 0)); then + printf '\nInstallation completed with %b%d errors%b\n' \ + "$RED" "$error" "$RST" + else + printf '\n%bInstallation complete!%b\n' "$GRN" "$RST" + fi +} + +main diff --git a/waybar/modules/backlight.jsonc b/waybar/modules/backlight.jsonc new file mode 100644 index 0000000..d5b53fc --- /dev/null +++ b/waybar/modules/backlight.jsonc @@ -0,0 +1,32 @@ +{ + "backlight": { + // "interval": + "format": "{icon} {percent}%", + "format-icons": [ + "", "", "", "", "", "", "", "", "" + ], + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "rotate": + // "states": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + "on-scroll-up": "~/.config/waybar/scripts/backlight.sh up", + "on-scroll-down": "~/.config/waybar/scripts/backlight.sh down", + // "smooth-scrolling-threshold": + // "reverse-scrolling": + // "reverse-mouse-scrolling": + // "scroll-step": + // "min-brightness": + "tooltip": false + // "tooltip-format": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/battery.jsonc b/waybar/modules/battery.jsonc new file mode 100644 index 0000000..f1aacca --- /dev/null +++ b/waybar/modules/battery.jsonc @@ -0,0 +1,45 @@ +{ + "battery": { + // "bat": + // "adapter": + // "design-capacity": + // "full-at": + // "interval": + "states": { + "warning": 20, + "critical": 10 + }, + "format": "{icon} {capacity}%", + "format-time": "{H}h {M}min", + "format-icons": [ + "󰂎", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹" + ], + "format-charging": "󰉁 {capacity}%", + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "rotate": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Discharging: {time}", + "tooltip-format-charging": "Charging: {time}", + // "weighted-average": + // "bat-compatibility": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + "events": { + "on-discharging-warning": "notify-send 'Battery Low (20%)' -u critical -i 'battery-020' -r 1525", + "on-discharging-critical": "notify-send 'Battery Critical (10%)' -u critical -i 'battery-010' -r 1525", + "on-charging-100": "notify-send 'Battery Full (100%)' -i 'battery-100-charged'" + } + } +} diff --git a/waybar/modules/bluetooth.jsonc b/waybar/modules/bluetooth.jsonc new file mode 100644 index 0000000..3113870 --- /dev/null +++ b/waybar/modules/bluetooth.jsonc @@ -0,0 +1,38 @@ +{ + "bluetooth": { + // "controller": + // "format-device-preference": + "format": "󰂯", + "format-disabled": "󰂲", + "format-off": "󰂲", + "format-on": "󰂰", + "format-connected": "󰂱", + // "format-connected-battery": + // "format-no-controller": + // "format-icons": + // "rotate": + "min-length": 2, + "max-length": 2, + // "align": + // "justify": + "on-click": "kitty -e ~/.config/waybar/scripts/bluetooth.sh", + // "on-click-middle": + "on-click-right": "bluetoothctl power off && notify-send 'Bluetooth Off' -i 'network-bluetooth-inactive' -r 1925", + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Device Addr: {device_address}", + "tooltip-format-disabled": "Bluetooth Disabled", + "tooltip-format-off": "Bluetooth Off", + "tooltip-format-on": "Bluetooth Disconnected", + "tooltip-format-connected": "Device: {device_alias}", + "tooltip-format-enumerate-connected": "Device: {device_alias}", + "tooltip-format-connected-battery": "Device: {device_alias}\nBattery: {device_battery_percentage}%", + "tooltip-format-enumerate-connected-battery": "Device: {device_alias}\nBattery: {device_battery_percentage}%" + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/clock.jsonc b/waybar/modules/clock.jsonc new file mode 100644 index 0000000..9bcbfb8 --- /dev/null +++ b/waybar/modules/clock.jsonc @@ -0,0 +1,71 @@ +{ + "clock#time": { + // "interval": + "format": "{:%H:%M}", + // "timezone": + // "timezones": + // "locale": + "min-length": 5, + "max-length": 5, + // "rotate": 0, + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Standard Time: {:%I:%M %p}" + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + }, + + /*-------------- + calendar + --------------*/ + + "clock#date": { + // "interval": + "format": "󰸗 {:%d-%m}", + // "timezone": + // "timezones": + // "locale": + "min-length": 8, + "max-length": 8, + // "rotate": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "{calendar}", + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + "calendar": { + "mode": "month", + "mode-mon-col": 6, + // "week-pos": + // "on-scroll": + "format": { + "months": "{}", + "days": "{}", + // "weeks": + "weekdays": "{}", + "today": "{}" + } + }, + "actions": { + "on-click": "mode" + // "on-click-middle": + // "on-click-right": + // "on-scroll-up": + // "on-scroll-down": + } + } +} diff --git a/waybar/modules/cpu.jsonc b/waybar/modules/cpu.jsonc new file mode 100644 index 0000000..67ac8a5 --- /dev/null +++ b/waybar/modules/cpu.jsonc @@ -0,0 +1,27 @@ +{ + "cpu": { + "interval": 10, + "format": "󰍛 {usage}%", + "format-warning": "󰀨 {usage}%", + "format-critical": "󰀨 {usage}%", + // "format-icons": + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "rotate": + "states": { + "warning": 75, + "critical": 90 + }, + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + "tooltip": false + // "expand": + } +} diff --git a/waybar/modules/custom/distro.jsonc b/waybar/modules/custom/distro.jsonc new file mode 100644 index 0000000..62c86ea --- /dev/null +++ b/waybar/modules/custom/distro.jsonc @@ -0,0 +1,33 @@ +{ + "custom/distro": { + // "exec": + // "exec-if": + // "exec-on-event": + // "hide-empty-text": + // "return-type": + // "interval": + // "restart-interval": + // "signal": + "format": "󰣇", + // "format-icons": + // "rotate": + // "min-length": + // "max-length": + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + "tooltip": false + // "tooltip-format": + // "escape": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/custom/dividers.jsonc b/waybar/modules/custom/dividers.jsonc new file mode 100644 index 0000000..b1944a0 --- /dev/null +++ b/waybar/modules/custom/dividers.jsonc @@ -0,0 +1,79 @@ +{ + /*------------------- + left dividers + -------------------*/ + + "custom/left_div#1": { + "format": "", + "tooltip": false + }, + "custom/left_div#2": { + "format": "", + "tooltip": false + }, + "custom/left_div#3": { + "format": "", + "tooltip": false + }, + "custom/left_div#4": { + "format": "", + "tooltip": false + }, + "custom/left_div#5": { + "format": "", + "tooltip": false + }, + "custom/left_div#6": { + "format": "", + "tooltip": false + }, + "custom/left_div#7": { + "format": "", + "tooltip": false + }, + "custom/left_div#8": { + "format": "", + "tooltip": false + }, + + // inverse + "custom/left_inv#1": { + "format": "", + "tooltip": false + }, + "custom/left_inv#2": { + "format": "", + "tooltip": false + }, + + /*-------------------- + right dividers + --------------------*/ + + "custom/right_div#1": { + "format": "", + "tooltip": false + }, + "custom/right_div#2": { + "format": "", + "tooltip": false + }, + "custom/right_div#3": { + "format": "", + "tooltip": false + }, + "custom/right_div#4": { + "format": "", + "tooltip": false + }, + "custom/right_div#5": { + "format": "", + "tooltip": false + }, + + // inverse + "custom/right_inv#1": { + "format": "", + "tooltip": false + } +} diff --git a/waybar/modules/custom/power_menu.jsonc b/waybar/modules/custom/power_menu.jsonc new file mode 100644 index 0000000..c438735 --- /dev/null +++ b/waybar/modules/custom/power_menu.jsonc @@ -0,0 +1,33 @@ +{ + "custom/power_menu": { + // "exec": + // "exec-if": + // "exec-on-event": + // "hide-empty-text": + // "return-type": + // "interval": + // "restart-interval": + // "signal": + "format": "󰤄", + // "format-icons": + // "rotate": + // "min-length": + // "max-length": + // "align": + // "justify": + "on-click": "kitty -e ~/.config/waybar/scripts/power-menu.sh", + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Power Menu" + // "escape": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/custom/system_update.jsonc b/waybar/modules/custom/system_update.jsonc new file mode 100644 index 0000000..d8bd085 --- /dev/null +++ b/waybar/modules/custom/system_update.jsonc @@ -0,0 +1,33 @@ +{ + "custom/system_update": { + "exec": "~/.config/waybar/scripts/system-update.sh module", + // "exec-if": + // "exec-on-event": + // "hide-empty-text": + "return-type": "json", + "interval": 3600, + // "restart-interval": + "signal": 1, + "format": "{}", + // "format-icons": + // "rotate": + // "align": + // "justify": + "min-length": 2, + "max-length": 2, + "on-click": "alacritty -e ~/.config/waybar/scripts/system-update.sh", + // "on-click-middle": + "on-click-right": "pkill -RTMIN+1 waybar" + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + // "tooltip-format": + // "escape": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/custom/user.jsonc b/waybar/modules/custom/user.jsonc new file mode 100644 index 0000000..9046dfe --- /dev/null +++ b/waybar/modules/custom/user.jsonc @@ -0,0 +1,83 @@ +{ + "group/user": { + "orientation": "horizontal", + "modules": [ + "custom/trigger", + "custom/user" + ], + "drawer": { + // "transition-duration": + // "transition-left-to-right": + // "children-class": + // "click-to-reveal": + } + }, + + "custom/trigger": { + // "exec": + // "exec-if": + // "exec-on-event": + // "hide-empty-text": + // "return-type": + // "interval": + // "restart-interval": + // "signal": + "format": "󰍜", + // "format-icons": + // "rotate": + "min-length": 4, + "max-length": 4, + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + "tooltip": false + // "tooltip-format": + // "escape": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + }, + + /*-------------- + username + --------------*/ + + "custom/user": { + "exec": "id -un", + // "exec-if": + // "exec-on-event": + // "hide-empty-text": + // "return-type": + // "interval": + // "restart-interval": + // "signal": + "format": "{}", + // "format-icons": + // "rotate": + // "min-length": + // "max-length": + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + "tooltip": false + // "tooltip-format": + // "escape": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/extras/taskbar.jsonc b/waybar/modules/extras/taskbar.jsonc new file mode 100644 index 0000000..245ca32 --- /dev/null +++ b/waybar/modules/extras/taskbar.jsonc @@ -0,0 +1,21 @@ +{ + "wlr/taskbar": { + // "all-outputs": + // "format": + // "icon-theme": + // "icon-size": + // "markup": + // "tooltip": + // "tooltip-format": + // "active-first": + // "sort-by-app-id": + "on-click": "activate", + // "on-click-middle": + // "on-click-right": + // "on-update": + "ignore-list": [ "kitty" ], + // "app_ids-mapping": + // "rewrite": + "cursor": true + } +} diff --git a/waybar/modules/extras/tray.jsonc b/waybar/modules/extras/tray.jsonc new file mode 100644 index 0000000..c576fdb --- /dev/null +++ b/waybar/modules/extras/tray.jsonc @@ -0,0 +1,13 @@ +{ + "tray": { + "icon-size": 16, + // "show-passive-items": + // "smooth-scrolling-threshold": + "spacing": 12, + // "reverse-direction": + // "on-update": + // "expand": + // "icons": + "cursor": true + } +} diff --git a/waybar/modules/extras/wireplumber.jsonc b/waybar/modules/extras/wireplumber.jsonc new file mode 100644 index 0000000..7bfc14e --- /dev/null +++ b/waybar/modules/extras/wireplumber.jsonc @@ -0,0 +1,82 @@ +{ + "group/wireplumber": { + "orientation": "horizontal", + "modules": [ + "wireplumber#output", + "wireplumber#input" + ], + "drawer": { + // "transition-duration": + "transition-left-to-right": false + // "children-class": + // "click-to-reveal": + } + }, + + /*------------------- + output device + -------------------*/ + + "wireplumber#output": { + "format": "{icon} {volume}%", + "format-muted": "󰝟 {volume}%", + // "format-source": + // "format-source-muted": + "format-icons": [ + "󰕿", "󰖀", "󰕾" + ], + // "rotate": + // "states": + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "scroll-step": + "on-click": "~/.config/waybar/scripts/volume.sh output mute", + // "on-click-middle": + // "on-click-right": + // "on-update": + "on-scroll-up": "~/.config/waybar/scripts/volume.sh output raise", + "on-scroll-down": "~/.config/waybar/scripts/volume.sh output lower", + // "tooltip": + "tooltip-format": "Device: {node_name}", + // "max-volume": + // "reverse-scrolling": + "node-type": "Audio/Sink" + // "menu": + // "menu-file": + // "menu-actions": + }, + + /*---------------- + microphone + ----------------*/ + + "wireplumber#input": { + "format": "󰍬 {volume}%", + "format-muted": "󰍭 {volume}%", + // "format-source": + // "format-source-muted": + // "rotate": + // "states": + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "scroll-step": + "on-click": "~/.config/waybar/scripts/volume.sh input mute", + // "on-click-middle": + // "on-click-right": + // "on-update": + "on-scroll-up": "~/.config/waybar/scripts/volume.sh input raise", + "on-scroll-down": "~/.config/waybar/scripts/volume.sh input lower", + // "tooltip": + "tooltip-format": "Device: {node_name}", + // "max-volume": + // "reverse-scrolling": + "node-type": "Audio/Source" + // "menu": + // "menu-file": + // "menu-actions": + } +} diff --git a/waybar/modules/hyprland/window.jsonc b/waybar/modules/hyprland/window.jsonc new file mode 100644 index 0000000..caca1cd --- /dev/null +++ b/waybar/modules/hyprland/window.jsonc @@ -0,0 +1,19 @@ +{ + "hyprland/window": { + "format": "{}", + "rewrite": { + "": "Desktop", + "kitty": "Terminal", + "zsh": "Terminal", + "~": "Terminal" + }, + // "separate-outputs": + // "icon": + // "icon-size": + // "min-length": + // "max-length": + // "tooltip": + "swap-icon-label": false + // "expand": + } +} diff --git a/waybar/modules/hyprland/windowcount.jsonc b/waybar/modules/hyprland/windowcount.jsonc new file mode 100644 index 0000000..65e959d --- /dev/null +++ b/waybar/modules/hyprland/windowcount.jsonc @@ -0,0 +1,12 @@ +{ + "hyprland/windowcount": { + "format": "[{}]", + // "format-empty": + // "format-windowed": + // "format-fullscreen": + // "separate-outputs": + // "min-length": + // "max-length": + "swap-icon-label": false + } +} diff --git a/waybar/modules/hyprland/workspaces.jsonc b/waybar/modules/hyprland/workspaces.jsonc new file mode 100644 index 0000000..864fcac --- /dev/null +++ b/waybar/modules/hyprland/workspaces.jsonc @@ -0,0 +1,38 @@ +{ + "hyprland/workspaces": { + // "active-only": + // "hide-active": + // "all-outputs": + "format": "{icon}", + "format-icons": { + "active": "", + "default": "" + }, + "persistent-workspaces": { + "*": 5 + }, + // "persistent-only": + // "show-special": + // "special-visible-only": + // "sort-by": + // "window-rewrite": + // "window-rewrite-default": + // "format-window-separator": + "workspace-taskbar": { + // "enable": + // "update-active-window": + // "format": + // "icon-size": + // "icon-theme": + // "orientation": + // "ignore-list": + // "on-click-window": + }, + // "move-to-monitor": + // "ignore-workspaces": + "on-scroll-up": "hyprctl dispatch workspace +1", + "on-scroll-down": "hyprctl dispatch workspace -1", + // "expand": + "cursor": true + } +} diff --git a/waybar/modules/idle_inhibitor.jsonc b/waybar/modules/idle_inhibitor.jsonc new file mode 100644 index 0000000..c05e5a2 --- /dev/null +++ b/waybar/modules/idle_inhibitor.jsonc @@ -0,0 +1,30 @@ +{ + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "󰈈", + "deactivated": "󰈉" + }, + // "rotate": + "min-length": 3, + "max-length": 3, + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format-activated": "Idle Inhibitor: Activated", + "tooltip-format-deactivated": "Idle Inhibitor: Deactivated", + "start-activated": false + // "timeout": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/memory.jsonc b/waybar/modules/memory.jsonc new file mode 100644 index 0000000..dba44bc --- /dev/null +++ b/waybar/modules/memory.jsonc @@ -0,0 +1,31 @@ +{ + "memory": { + "interval": 10, + "format": "󰘚 {percentage}%", + "format-warning": "󰀧 {percentage}%", + "format-critical": "󰀧 {percentage}%", + // "format-icons": + // "rotate": + "states": { + "warning": 75, + "critical": 90 + }, + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Memory Used: {used:0.0f}/{total:0.0f} GB" + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/mpris.jsonc b/waybar/modules/mpris.jsonc new file mode 100644 index 0000000..51218b4 --- /dev/null +++ b/waybar/modules/mpris.jsonc @@ -0,0 +1,36 @@ +{ + "mpris": { + // "player": + // "ignored-players": + // "interval": + "format": "{player_icon} {title} - {artist}", + "format-paused": "{status_icon} {title} - {artist}", + "tooltip-format": "Playing: {title} - {artist}", + "tooltip-format-paused": "Paused: {title} - {artist}", + // "enable-tooltip-len-limits": + // "on-click": + // "on-click-middle": + // "on-click-right": + "player-icons": { + "default": "󰐊" + }, + "status-icons": { + "paused": "󰏤" + }, + // "artist-len": + // "album-len": + // "title-len": + // "dynamic-len": + // "dynamic-order": + // "dynamic-separator": + // "dynamic-importance-order": + // "truncate-hours": + // "ellipsis": + // "rotate": + // "min-length": + "max-length": 1000 + // "align": + // "justify": + // "expand": + } +} diff --git a/waybar/modules/network.jsonc b/waybar/modules/network.jsonc new file mode 100644 index 0000000..e4c6df0 --- /dev/null +++ b/waybar/modules/network.jsonc @@ -0,0 +1,40 @@ +{ + "network": { + // "interface": + // "rfkill": + "interval": 10, + // "family": + "format": "󰤨", + "format-ethernet": "󰈀", + "format-wifi": "{icon}", + // "format-linked": + "format-disconnected": "󰤯", + "format-disabled": "󰤮", + // "format-alt": + "format-icons": [ + "󰤟", "󰤢", "󰤥", "󰤨" + ], + // "rotate": + "min-length": 2, + "max-length": 2, + // "align": + // "justify": + "on-click": "kitty -e ~/.config/waybar/scripts/network.sh", + // "on-click-middle": + "on-click-right": "nmcli radio wifi off && notify-send 'Wi-Fi Disabled' -i 'network-wireless-off' -r 1125", + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Gateway: {gwaddr}", + "tooltip-format-ethernet": "Interface: {ifname}", + "tooltip-format-wifi": "Network: {essid}\nIP Addr: {ipaddr}/{cidr}\nStrength: {signalStrength}%\nFrequency: {frequency} GHz", + "tooltip-format-disconnected": "Wi-Fi Disconnected", + "tooltip-format-disabled": "Wi-Fi Disabled" + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/pulseaudio.jsonc b/waybar/modules/pulseaudio.jsonc new file mode 100644 index 0000000..97ac12a --- /dev/null +++ b/waybar/modules/pulseaudio.jsonc @@ -0,0 +1,96 @@ +{ + "group/pulseaudio": { + "orientation": "horizontal", + "modules": [ + "pulseaudio#output", + "pulseaudio#input" + ], + "drawer": { + // "transition-duration": + "transition-left-to-right": false + // "children-class": + // "click-to-reveal": + } + }, + + /*------------------- + output device + -------------------*/ + + "pulseaudio#output": { + "format": "{icon} {volume}%", + // "format-bluetooth": + "format-muted": "{icon} {volume}%", + // "format-source": + // "format-source-muted": + "format-icons": { + "default": [ "󰕿", "󰖀", "󰕾" ], + "default-muted": "󰝟", + "headphone": "󰋋", + "headphone-muted": "󰟎", + "headset": "󰋎", + "headset-muted": "󰋐" + }, + // "rotate": + // "states": + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "scroll-step": + "on-click": "~/.config/waybar/scripts/volume.sh output mute", + // "on-click-middle": + // "on-click-right": + // "on-update": + "on-scroll-up": "~/.config/waybar/scripts/volume.sh output raise", + "on-scroll-down": "~/.config/waybar/scripts/volume.sh output lower", + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Output Device: {desc}" + // "max-volume": + // "ignored-sinks": + // "reverse-scrolling": + // "reverse-mouse-scrolling": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + }, + + /*---------------- + microphone + ----------------*/ + + "pulseaudio#input": { + "format": "{format_source}", + // "format-bluetooth": + // "format-muted": + "format-source": "󰍬 {volume}%", + "format-source-muted": "󰍭 {volume}%", + // "format-icons": + // "rotate": + // "states": + "min-length": 7, + "max-length": 7, + // "align": + // "justify": + // "scroll-step": + "on-click": "~/.config/waybar/scripts/volume.sh input mute", + // "on-click-middle": + // "on-click-right": + // "on-update": + "on-scroll-up": "~/.config/waybar/scripts/volume.sh input raise", + "on-scroll-down": "~/.config/waybar/scripts/volume.sh input lower", + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Input Device: {desc}" + // "max-volume": + // "ignored-sinks": + // "reverse-scrolling": + // "reverse-mouse-scrolling": + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/modules/temperature.jsonc b/waybar/modules/temperature.jsonc new file mode 100644 index 0000000..6c2dc25 --- /dev/null +++ b/waybar/modules/temperature.jsonc @@ -0,0 +1,35 @@ +{ + "temperature": { + "thermal-zone": 1, + // "hwmon-path": + // "hwmon-path-abs": + // "input-filename": + // "warning-threshold": + "critical-threshold": 90, + "interval": 10, + // "format-warning": + "format-critical": "󰀦 {temperatureC}°C", + "format": "{icon} {temperatureC}°C", + "format-icons": [ + "󱃃", "󰔏", "󱃂" + ], + // "rotate": + "min-length": 8, + "max-length": 8, + // "align": + // "justify": + // "on-click": + // "on-click-middle": + // "on-click-right": + // "on-update": + // "on-scroll-up": + // "on-scroll-down": + // "smooth-scrolling-threshold": + // "tooltip": + "tooltip-format": "Fahrenheit: {temperatureF}°F" + // "menu": + // "menu-file": + // "menu-actions": + // "expand": + } +} diff --git a/waybar/scripts/_fzf_colorizer.sh b/waybar/scripts/_fzf_colorizer.sh new file mode 100755 index 0000000..2efa0bf --- /dev/null +++ b/waybar/scripts/_fzf_colorizer.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# A helper script that syncs fzf colors with the current Waybar theme +# + +main() { + local wcss="$HOME/.config/waybar/current-theme.css" + + local wtheme fcolors + wtheme=$(sed 1q "$wcss" | awk '{print $2}') + fcolors="$HOME/.config/waybar/themes/fzf/$wtheme.txt" + + # Extract theme colors starting from line 3 up to (but not including) the + # first blank line + local wcolors + wcolors=$(sed -n '3,${/^ *$/Q;p}' "$wcss") + + local element color hex + fcconf=() + while read -r element color; do + read -r _ _ hex < <(grep " $color " <<< "$wcolors") + hex=${hex%;} + fcconf+=("--color=$element:$hex") + done < "$fcolors" +} + +main diff --git a/waybar/scripts/backlight.sh b/waybar/scripts/backlight.sh new file mode 100755 index 0000000..ed44dad --- /dev/null +++ b/waybar/scripts/backlight.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# Adjust screen brightness and send a notification with the current level +# +# Requirements: +# - brightnessctl +# - notify-send (libnotify) +# +# Author: Jesse Mirabel +# Created: August 28, 2025 +# License: MIT + +VALUE=1 + +print-usage() { + local script=${0##*/} + cat <<- EOF + USAGE: $script [OPTIONS] + + Adjust screen brightness and send a notification with the current level + + OPTIONS: + up Increase brightness by + down Decrease brightness by + Default value: $VALUE + + EXAMPLES: + Increase brightness: + $ $script up + + Decrease brightness by 5: + $ $script down 5 + EOF + exit 1 +} + +set-brightness() { + local op + case $action in + 'up') op='+' ;; + 'down') op='-' ;; + esac + + brightnessctl -n set "${value}%${op}" > /dev/null + + local level + level=$(brightnessctl -m | awk -F ',' '{print $4}') + + notify-send "Brightness: $level" -h int:value:"$level" -i 'contrast' -r 2825 +} + +main() { + action=$1 + value=${2:-$VALUE} + + ! ((value > 0)) && print-usage + + case $action in + 'up' | 'down') set-brightness ;; + *) print-usage ;; + esac +} + +main "$@" diff --git a/waybar/scripts/bluetooth.sh b/waybar/scripts/bluetooth.sh new file mode 100755 index 0000000..d05b9fc --- /dev/null +++ b/waybar/scripts/bluetooth.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +# +# Scan, select, pair, and connect to Bluetooth devices +# +# Requirements: +# - bluetoothctl (bluez-utils) +# - fzf +# - notify-send (libnotify) +# +# Author: Jesse Mirabel +# Created: August 19, 2025 +# License: MIT + +fcconf=() +# Get fzf color config +# shellcheck disable=SC1090,SC2154 +. ~/.config/waybar/scripts/_fzf_colorizer.sh 2> /dev/null || true +# If the file is missing, fzf will fall back to its default colors + +RED='\033[1;31m' +RST='\033[0m' + +TIMEOUT=10 + +ensure-on() { + local status + status=$(bluetoothctl show | awk '/PowerState/ {print $2}') + + case $status in + 'off') bluetoothctl power on > /dev/null ;; + 'off-blocked') + rfkill unblock bluetooth + + local i new_status + for ((i = 1; i <= TIMEOUT; i++)); do + printf '\rUnblocking Bluetooth... (%d/%d)' $i $TIMEOUT + + new_status=$(bluetoothctl show | awk '/PowerState/ {print $2}') + if [[ $new_status == 'on' ]]; then + break + fi + sleep 1 + done + + # Bluetooth could be hard blocked + if [[ $new_status != 'on' ]]; then + notify-send 'Bluetooth' 'Failed to unblock' -i 'package-purge' + return 1 + fi + ;; + *) return 0 ;; + esac + + notify-send 'Bluetooth On' -i 'network-bluetooth-activated' -r 1925 +} + +get-device-list() { + bluetoothctl --timeout $TIMEOUT scan on > /dev/null & + + local i num + for ((i = 1; i <= TIMEOUT; i++)); do + printf '\rScanning for devices... (%d/%d)' $i $TIMEOUT + printf '\n%bPress [q] to stop%b\n\n' "$RED" "$RST" + + num=$(bluetoothctl devices | grep -c 'Device') + printf '\rDevices: %s' "$num" + printf '\033[3A' + + read -rs -n 1 -t 1 + if [[ $REPLY == [Qq] ]]; then + break + fi + done + printf '\n%bScanning stopped.%b\n\n' "$RED" "$RST" + + list=$(bluetoothctl devices | sed 's/^Device //') + if [[ -z $list ]]; then + notify-send 'Bluetooth' 'No devices found' -i 'package-broken' + return 1 + fi +} + +select-device() { + local header + header=$(printf '%-17s %s' 'Address' 'Name') + local opts=( + '--border=sharp' + '--border-label= Bluetooth Devices ' + '--ghost=Search' + "--header=$header" + '--height=~100%' + '--highlight-line' + '--info=inline-right' + '--pointer=' + '--reverse' + "${fcconf[@]}" + ) + + address=$(fzf "${opts[@]}" <<< "$list" | awk '{print $1}') + if [[ -z $address ]]; then + return 1 + fi + + local connected + connected=$(bluetoothctl info "$address" | awk '/Connected/ {print $2}') + if [[ $connected == 'yes' ]]; then + notify-send 'Bluetooth' 'Already connected to this device' \ + -i 'package-install' + return 1 + fi +} + +pair-and-connect() { + local paired + paired=$(bluetoothctl info "$address" | awk '/Paired/ {print $2}') + if [[ $paired == 'no' ]]; then + printf 'Pairing...' + if ! timeout $TIMEOUT bluetoothctl pair "$address" > /dev/null; then + notify-send 'Bluetooth' 'Failed to pair' -i 'package-purge' + return 1 + fi + fi + + printf '\nConnecting...' + if ! timeout $TIMEOUT bluetoothctl connect "$address" > /dev/null; then + notify-send 'Bluetooth' 'Failed to connect' -i 'package-purge' + return 1 + fi + notify-send 'Bluetooth' 'Successfully connected' -i 'package-install' +} + +main() { + tput civis + ensure-on || exit 1 + get-device-list || exit 1 + tput cnorm + select-device || exit 1 + pair-and-connect || exit 1 +} + +main diff --git a/waybar/scripts/network.sh b/waybar/scripts/network.sh new file mode 100755 index 0000000..6c61a5a --- /dev/null +++ b/waybar/scripts/network.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# +# Scan, select, and connect to Wi-Fi networks +# +# Requirements: +# - nmcli (networkmanager) +# - fzf +# - notify-send (libnotify) +# +# Author: Jesse Mirabel +# Created: August 11, 2025 +# License: MIT + +fcconf=() +# Get fzf color config +# shellcheck disable=SC1090,SC2154 +. ~/.config/waybar/scripts/_fzf_colorizer.sh 2> /dev/null || true +# If the file is missing, fzf will fall back to its default colors + +RED='\033[1;31m' +RST='\033[0m' + +TIMEOUT=5 + +ensure-enabled() { + local radio + radio=$(nmcli radio wifi) + if [[ $radio == 'enabled' ]]; then + return 0 + fi + nmcli radio wifi on + + local i state + for ((i = 1; i <= TIMEOUT; i++)); do + printf '\rEnabling Wi-Fi... (%d/%d)' $i $TIMEOUT + + state=$(nmcli -t -f STATE general) + # If STATE returns anything other than this, we assume that Wi-Fi is + # fully enabled + if [[ $state != 'connected (local only)' ]]; then + break + fi + sleep 1 + done + notify-send 'Wi-Fi Enabled' -i 'network-wireless-on' -r 1125 +} + +get-network-list() { + nmcli device wifi rescan + + local i + for ((i = 1; i <= TIMEOUT; i++)); do + printf '\rScanning for networks... (%d/%d)' $i $TIMEOUT + + list=$(timeout 1 nmcli device wifi list) + networks=$(tail -n +2 <<< "$list" | awk '$2 != "--"') + if [[ -n $networks ]]; then + break + fi + done + printf '\n%bScanning stopped.%b\n\n' "$RED" "$RST" + + if [[ -z $networks ]]; then + notify-send 'Wi-Fi' 'No networks found' -i 'package-broken' + return 1 + fi +} + +select-network() { + local header + header=$(head -n 1 <<< "$list") + local opts=( + '--border=sharp' + '--border-label= Wi-Fi Networks ' + '--ghost=Search' + "--header=$header" + '--height=~100%' + '--highlight-line' + '--info=inline-right' + '--pointer=' + '--reverse' + "${fcconf[@]}" + ) + + bssid=$(fzf "${opts[@]}" <<< "$networks" | awk '{print $1}') + if [[ -z $bssid ]]; then + return 1 + fi + if [[ $bssid == '*' ]]; then + notify-send 'Wi-Fi' 'Already connected to this network' \ + -i 'package-install' + return 1 + fi +} + +connect-to-network() { + printf 'Connecting...\n' + if ! nmcli --ask device wifi connect "$bssid"; then + notify-send 'Wi-Fi' 'Failed to connect' -i 'package-purge' + return 1 + fi + notify-send 'Wi-Fi' 'Successfully connected' -i 'package-install' +} + +main() { + tput civis + ensure-enabled || exit 1 + get-network-list || exit 1 + tput cnorm + select-network || exit 1 + connect-to-network || exit 1 +} + +main diff --git a/waybar/scripts/power-menu.sh b/waybar/scripts/power-menu.sh new file mode 100755 index 0000000..2d4323f --- /dev/null +++ b/waybar/scripts/power-menu.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# +# Launch a power menu +# +# Requirements: +# - fzf +# +# Author: Jesse Mirabel +# Created: August 19, 2025 +# License: MIT + +fcconf=() +# Get fzf color config +# shellcheck disable=SC1090,SC2154 +. ~/.config/waybar/scripts/_fzf_colorizer.sh 2> /dev/null || true +# If the file is missing, fzf will fall back to its default colors + +main() { + local list=( + 'Lock' + 'Shutdown' + 'Reboot' + 'Logout' + 'Hibernate' + 'Suspend' + ) + local opts=( + '--border=sharp' + '--border-label= Power Menu ' + '--height=~100%' + '--highlight-line' + '--no-input' + '--pointer=' + '--reverse' + "${fcconf[@]}" + ) + + local selected + selected=$(printf '%s\n' "${list[@]}" | fzf "${opts[@]}") + case $selected in + 'Lock') loginctl lock-session ;; + 'Shutdown') systemctl poweroff ;; + 'Reboot') systemctl reboot ;; + 'Logout') loginctl terminate-session "$XDG_SESSION_ID" ;; + 'Hibernate') systemctl hibernate ;; + 'Suspend') systemctl suspend ;; + *) exit 1 ;; + esac +} + +main diff --git a/waybar/scripts/system-update.sh b/waybar/scripts/system-update.sh new file mode 100755 index 0000000..43cbbe8 --- /dev/null +++ b/waybar/scripts/system-update.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# +# Check for official and AUR package updates and upgrade them. When run with the +# 'module' argument, output the status icon and update counts in JSON format for +# Waybar +# +# Requirements: +# - checkupdates (pacman-contrib) +# - notify-send (libnotify) +# - optional: an AUR helper +# +# Author: Jesse Mirabel +# Created: August 16, 2025 +# License: MIT + +GRN='\033[1;32m' +BLU='\033[1;34m' +RST='\033[0m' + +TIMEOUT=10 +HELPERS=('aura' 'paru' 'pikaur' 'trizen' 'yay') + +detect-helper() { + local h + for h in "${HELPERS[@]}"; do + if command -v "$h" > /dev/null; then + helper=$h + break + fi + done +} + +check-updates() { + is_online=true + repo=0 + aur=0 + + local rout rstat + rout=$(timeout $TIMEOUT checkupdates) + rstat=$? + # 2 means no updates are available + if ((rstat != 0 && rstat != 2)); then + is_online=false + return 1 + fi + repo=$(grep -cve '^\s*$' <<< "$rout") + + if [[ -z $helper ]]; then + return 0 + fi + + local aout astat + aout=$(timeout $TIMEOUT "$helper" -Quaq) + astat=$? + # Return only if the exit status is non-zero and there is an error + # message + if ((${#aout} > 0 && astat != 0)); then + is_online=false + return 1 + fi + aur=$(grep -cve '^\s*$' <<< "$aout") +} + +update-packages() { + printf '\n%bUpdating pacman packages...%b\n' "$BLU" "$RST" + sudo pacman -Syu + + if [[ -n $helper ]]; then + printf '\n%bUpdating AUR packages...%b\n' "$BLU" "$RST" + "$helper" -Syu + fi + + notify-send 'Update Complete' -i 'package-install' + printf '\n%bUpdate Complete!%b\n' "$GRN" "$RST" + read -rs -n 1 -p 'Press any key to exit...' +} + +display-module() { + if [[ $is_online == false ]]; then + echo "{ \"text\": \"󰒑\", \"tooltip\": \"Cannot fetch updates. Right-click to retry.\" }" + return 0 + fi + + local tooltip="Official: $repo" + if [[ -n $helper ]]; then + tooltip+="\nAUR($helper): $aur" + fi + + local total=$((repo + aur)) + if ((total == 0)); then + echo "{ \"text\": \"󰸟\", \"tooltip\": \"No updates available\" }" + else + echo "{ \"text\": \"󰄠\", \"tooltip\": \"$tooltip\" }" + fi +} + +main() { + detect-helper + + case $1 in + 'module') + check-updates + display-module + ;; + *) + printf '%bChecking for updates...%b' "$BLU" "$RST" + check-updates + update-packages + # use signal to update the module + pkill -RTMIN+1 waybar + ;; + esac +} + +main "$@" diff --git a/waybar/scripts/volume.sh b/waybar/scripts/volume.sh new file mode 100755 index 0000000..e6d571f --- /dev/null +++ b/waybar/scripts/volume.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# +# Adjust default device volume and send a notification with the current level +# +# Requirements: +# - pactl (libpulse) +# - notify-send (libnotify) +# +# Author: Jesse Mirabel +# Created: September 07, 2025 +# License: MIT + +VALUE=1 +MIN=0 +MAX=100 + +print-usage() { + local script=${0##*/} + cat <<- EOF + USAGE: $script [OPTIONS] + + Adjust default device volume and send a notification with the current level + + OPTIONS: + input Set device as '@DEFAULT_SOURCE@' + output Set device as '@DEFAULT_SINK@' + + mute Toggle device mute + + raise Raise volume by + lower Lower volume by + Default value: $VALUE + + EXAMPLES: + Toggle microphone mute: + $ $script input mute + + Raise speaker volume: + $ $script output raise + + Lower speaker volume by 5: + $ $script output lower 5 + EOF + exit 1 +} + +check-muted() { + local muted + muted=$(pactl "get-$dev_mute" "$dev" | awk '{print $2}') + local state + case $muted in + 'yes') state='Muted' ;; + 'no') state='Unmuted' ;; + esac + + echo "$state" +} + +get-volume() { + pactl "get-$dev_vol" "$dev" | awk '{print $5}' | tr -d '%' +} + +get-icon() { + local icon + local new_vol=${1:-$(get-volume)} + + if [[ $(check-muted) == 'Muted' ]]; then + icon="$dev_icon-muted" + else + if ((new_vol < ((MAX * 33) / 100))); then + icon="$dev_icon-low" + elif ((new_vol < ((MAX * 66) / 100))); then + icon="$dev_icon-medium" + else + icon="$dev_icon-high" + fi + fi + + echo "$icon" +} + +toggle-mute() { + pactl "set-$dev_mute" "$dev" toggle + notify-send "$title: $(check-muted)" -i "$(get-icon)" -r 2425 +} + +set-volume() { + local vol + vol=$(get-volume) + local new_vol + + case $action in + 'raise') + new_vol=$((vol + value)) + ((new_vol > MAX)) && new_vol=$MAX + ;; + 'lower') + new_vol=$((vol - value)) + ((new_vol < MIN)) && new_vol=$MIN + ;; + esac + + pactl "set-$dev_vol" "$dev" "${new_vol}%" + + local icon + icon=$(get-icon "$new_vol") + + notify-send "$title: ${new_vol}%" -h int:value:$new_vol -i "$icon" -r 2425 +} + +main() { + device=$1 + action=$2 + value=${3:-$VALUE} + + ! ((value > 0)) && print-usage + + case $device in + 'input') + dev='@DEFAULT_SOURCE@' + dev_mute='source-mute' + dev_vol='source-volume' + dev_icon='mic-volume' + title='Microphone' + ;; + 'output') + dev='@DEFAULT_SINK@' + dev_mute='sink-mute' + dev_vol='sink-volume' + dev_icon='audio-volume' + title='Volume' + ;; + *) print-usage ;; + esac + + case $action in + 'mute') toggle-mute ;; + 'raise' | 'lower') set-volume ;; + *) print-usage ;; + esac +} + +main "$@" diff --git a/waybar/style.css b/waybar/style.css new file mode 100644 index 0000000..6bee011 --- /dev/null +++ b/waybar/style.css @@ -0,0 +1,12 @@ +/* ignore GTK theme */ +* { + all: initial; +} + +@import "current-theme.css"; +@import "styles/fonts.css"; +@import "styles/global.css"; +@import "styles/modules-center.css"; +@import "styles/modules-left.css"; +@import "styles/modules-right.css"; +@import "styles/states.css"; diff --git a/waybar/styles/fonts.css b/waybar/styles/fonts.css new file mode 100644 index 0000000..8a7b96a --- /dev/null +++ b/waybar/styles/fonts.css @@ -0,0 +1,29 @@ +* { + font-family: "Commit Mono Nerd Font"; + font-weight: bold; + font-size: 16px; +} + +#custom-user, +#window label, +#mpris, +tooltip label { + font-weight: normal; +} + +#workspaces button.active label, +#workspaces button.focused label, +#custom-distro { + font-size: 20px; +} + +#custom-power_menu { + font-size: 18px; +} + +#custom-left_div, +#custom-left_inv, +#custom-right_div, +#custom-right_inv { + font-size: 22px; +} diff --git a/waybar/styles/global.css b/waybar/styles/global.css new file mode 100644 index 0000000..9db99a0 --- /dev/null +++ b/waybar/styles/global.css @@ -0,0 +1,34 @@ +* { + color: @main-fg; +} + +.module { + margin-bottom: -1px; +} + +#waybar { + background-color: @outline; +} +#waybar > box { + margin: 4px; + background-color: @main-bg; +} + +button { + border-radius: 16px; + min-width: 16px; + padding: 0 10px; +} +button:hover { + background-color: @hover-bg; + color: @hover-fg; +} + +tooltip { + border: 2px solid @main-br; + border-radius: 10px; + background-color: @main-bg; +} +tooltip > box { + padding: 0 6px; +} diff --git a/waybar/styles/modules-center.css b/waybar/styles/modules-center.css new file mode 100644 index 0000000..8647310 --- /dev/null +++ b/waybar/styles/modules-center.css @@ -0,0 +1,119 @@ +/*------------------ + window count +------------------*/ + +#windowcount { + margin-right: 12px; +} +#windowcount label { + color: @hover-fg; +} + +/*----------------- + temperature +-----------------*/ + +#custom-left_div.2 { + color: @temperature; +} +#temperature { + background-color: @temperature; +} + +/*------------ + memory +------------*/ + +#custom-left_div.3 { + background-color: @temperature; + color: @memory; +} +#memory { + background-color: @memory; +} + +/*--------- + cpu +---------*/ + +#custom-left_div.4 { + background-color: @memory; + color: @cpu; +} +#cpu { + background-color: @cpu; +} +#custom-left_inv.1 { + color: @cpu; +} + +/*----------------- + distro icon +-----------------*/ + +#custom-left_div.5, +#custom-right_div.2 { + color: @accent; +} +#custom-distro { + padding: 0 10px 0 5px; + background-color: @accent; + color: @main-bg; +} + +/*-------------------- + idle inhibitor +--------------------*/ + +#custom-right_inv.1 { + color: @time; +} +#idle_inhibitor { + background-color: @time; +} + +/*---------- + time +----------*/ + +#clock.time { + padding-right: 6px; + background-color: @time; +} +#custom-right_div.3 { + background-color: @date; + color: @time; +} + +/*---------- + date +----------*/ + +#clock.date { + padding-left: 6px; + background-color: @date; +} +#custom-right_div.4 { + background-color: @tray; + color: @date; +} + +/*----------------- + system tray +-----------------*/ + +#network { + background-color: @tray; + padding: 0 6px 0 4px; +} +#bluetooth { + background-color: @tray; + padding: 0 5px; +} +#custom-system_update { + background-color: @tray; + padding: 0 8px 0 2px; +} +#custom-right_div.5 { + color: @tray; +} diff --git a/waybar/styles/modules-left.css b/waybar/styles/modules-left.css new file mode 100644 index 0000000..6756e8d --- /dev/null +++ b/waybar/styles/modules-left.css @@ -0,0 +1,32 @@ +/*-------------- + username +--------------*/ + +#custom-user { + padding-right: 12px; +} + +/*---------------- + workspaces +----------------*/ + +#custom-left_div.1, +#custom-right_div.1 { + color: @workspaces; +} +#workspaces { + padding: 0 1px; + background-color: @workspaces; +} +#workspaces button.active label, +#workspaces button.focused label { + color: @accent; +} + +/*------------------ + window title +------------------*/ + +#window { + margin-left: 12px; +} diff --git a/waybar/styles/modules-right.css b/waybar/styles/modules-right.css new file mode 100644 index 0000000..50f2598 --- /dev/null +++ b/waybar/styles/modules-right.css @@ -0,0 +1,59 @@ +/*---------------- + media info +----------------*/ + +#mpris { + padding: 0 12px; +} + +/*------------ + volume +------------*/ + +#custom-left_div.6 { + color: @volume; +} +#pulseaudio, +#wireplumber { + background-color: @volume; +} + +/*---------------- + brightness +----------------*/ + +#custom-left_div.7 { + background-color: @volume; + color: @backlight; +} +#backlight { + background-color: @backlight; +} + +/*------------- + battery +-------------*/ + +#custom-left_div.8 { + background-color: @backlight; + color: @battery; +} +#battery { + background-color: @battery; +} +#custom-left_inv.2 { + color: @battery; +} + +/*---------------- + power menu +----------------*/ + +#custom-power_menu { + border-radius: 16px; + padding: 0 19px 0 16px; + color: @accent; +} +#custom-power_menu:hover { + background-color: @hover-bg; +} diff --git a/waybar/styles/states.css b/waybar/styles/states.css new file mode 100644 index 0000000..a1c52f8 --- /dev/null +++ b/waybar/styles/states.css @@ -0,0 +1,37 @@ +#custom-trigger:hover, +#idle_inhibitor:hover, +#clock.date:hover, +#network:hover, +#bluetooth:hover, +#custom-system_update:hover, +#mpris:hover, +#pulseaudio:hover, +#wireplumber:hover { + color: @hover-fg; +} + +/* inactive state */ +#idle_inhibitor.deactivated, +#mpris.paused, +#pulseaudio.output.muted, +#pulseaudio.input.source-muted, +#wireplumber.muted { + color: @hover-fg; +} + +#memory.warning, +#cpu.warning, +#battery.warning { + color: @warning; +} + +#temperature.critical, +#memory.critical, +#cpu.critical, +#battery.critical { + color: @critical; +} + +#battery.charging { + color: @charging; +} diff --git a/waybar/themes/catppuccin-frappe.css b/waybar/themes/catppuccin-frappe.css new file mode 100644 index 0000000..be98dd1 --- /dev/null +++ b/waybar/themes/catppuccin-frappe.css @@ -0,0 +1,63 @@ +/* catppuccin frappe */ + +@define-color rosewater #f2d5cf; +@define-color flamingo #eebebe; +@define-color pink #f4b8e4; +@define-color mauve #ca9ee6; +@define-color red #e78284; +@define-color maroon #ea999c; +@define-color peach #ef9f76; +@define-color yellow #e5c890; +@define-color green #a6d189; +@define-color teal #81c8be; +@define-color sky #99d1db; +@define-color sapphire #85c1dc; +@define-color blue #8caaee; +@define-color lavender #babbf1; +@define-color text #c6d0f5; +@define-color subtext1 #b5bfe2; +@define-color subtext0 #a5adce; +@define-color overlay2 #949cbb; +@define-color overlay1 #838ba7; +@define-color overlay0 #737994; +@define-color surface2 #626880; +@define-color surface1 #51576d; +@define-color surface0 #414559; +@define-color base #303446; +@define-color mantle #292c3c; +@define-color crust #232634; + +/* + br - border + bg - background + fg - foreground +*/ + +/* main colors */ + +@define-color accent @lavender; +@define-color main-br @subtext0; +@define-color main-bg @crust; +@define-color main-fg @text; +@define-color hover-bg @base; +@define-color hover-fg alpha(@main-fg, 0.75); +@define-color outline shade(@main-bg, 0.5); + +/* module colors */ + +@define-color workspaces @mantle; +@define-color temperature @mantle; +@define-color memory @base; +@define-color cpu @surface0; +@define-color time @surface0; +@define-color date @base; +@define-color tray @mantle; +@define-color volume @mantle; +@define-color backlight @base; +@define-color battery @surface0; + +/* state colors */ + +@define-color warning @yellow; +@define-color critical @red; +@define-color charging @green; diff --git a/waybar/themes/catppuccin-latte.css b/waybar/themes/catppuccin-latte.css new file mode 100644 index 0000000..26d9499 --- /dev/null +++ b/waybar/themes/catppuccin-latte.css @@ -0,0 +1,63 @@ +/* catppuccin latte */ + +@define-color rosewater #dc8a78; +@define-color flamingo #dd7878; +@define-color pink #ea76cb; +@define-color mauve #8839ef; +@define-color red #d20f39; +@define-color maroon #e64553; +@define-color peach #fe640b; +@define-color yellow #df8e1d; +@define-color green #40a02b; +@define-color teal #179299; +@define-color sky #04a5e5; +@define-color sapphire #209fb5; +@define-color blue #1e66f5; +@define-color lavender #7287fd; +@define-color text #4c4f69; +@define-color subtext1 #5c5f77; +@define-color subtext0 #6c6f85; +@define-color overlay2 #7c7f93; +@define-color overlay1 #8c8fa1; +@define-color overlay0 #9ca0b0; +@define-color surface2 #acb0be; +@define-color surface1 #bcc0cc; +@define-color surface0 #ccd0da; +@define-color base #eff1f5; +@define-color mantle #e6e9ef; +@define-color crust #dce0e8; + +/* + br - border + bg - background + fg - foreground +*/ + +/* main colors */ + +@define-color accent @lavender; +@define-color main-br @subtext0; +@define-color main-bg @crust; +@define-color main-fg @text; +@define-color hover-bg @base; +@define-color hover-fg alpha(@main-fg, 0.75); +@define-color outline shade(@main-bg, 0.5); + +/* module colors */ + +@define-color workspaces @mantle; +@define-color temperature @mantle; +@define-color memory @base; +@define-color cpu @surface0; +@define-color time @surface0; +@define-color date @base; +@define-color tray @mantle; +@define-color volume @mantle; +@define-color backlight @base; +@define-color battery @surface0; + +/* state colors */ + +@define-color warning @yellow; +@define-color critical @red; +@define-color charging @green; diff --git a/waybar/themes/catppuccin-macchiato.css b/waybar/themes/catppuccin-macchiato.css new file mode 100644 index 0000000..d98b1cc --- /dev/null +++ b/waybar/themes/catppuccin-macchiato.css @@ -0,0 +1,63 @@ +/* catppuccin macchiato */ + +@define-color rosewater #f4dbd6; +@define-color flamingo #f0c6c6; +@define-color pink #f5bde6; +@define-color mauve #c6a0f6; +@define-color red #ed8796; +@define-color maroon #ee99a0; +@define-color peach #f5a97f; +@define-color yellow #eed49f; +@define-color green #a6da95; +@define-color teal #8bd5ca; +@define-color sky #91d7e3; +@define-color sapphire #7dc4e4; +@define-color blue #8aadf4; +@define-color lavender #b7bdf8; +@define-color text #cad3f5; +@define-color subtext1 #b8c0e0; +@define-color subtext0 #a5adcb; +@define-color overlay2 #939ab7; +@define-color overlay1 #8087a2; +@define-color overlay0 #6e738d; +@define-color surface2 #5b6078; +@define-color surface1 #494d64; +@define-color surface0 #363a4f; +@define-color base #24273a; +@define-color mantle #1e2030; +@define-color crust #181926; + +/* + br - border + bg - background + fg - foreground +*/ + +/* main colors */ + +@define-color accent @lavender; +@define-color main-br @subtext0; +@define-color main-bg @crust; +@define-color main-fg @text; +@define-color hover-bg @base; +@define-color hover-fg alpha(@main-fg, 0.75); +@define-color outline shade(@main-bg, 0.5); + +/* module colors */ + +@define-color workspaces @mantle; +@define-color temperature @mantle; +@define-color memory @base; +@define-color cpu @surface0; +@define-color time @surface0; +@define-color date @base; +@define-color tray @mantle; +@define-color volume @mantle; +@define-color backlight @base; +@define-color battery @surface0; + +/* state colors */ + +@define-color warning @yellow; +@define-color critical @red; +@define-color charging @green; diff --git a/waybar/themes/catppuccin-mocha.css b/waybar/themes/catppuccin-mocha.css new file mode 100644 index 0000000..ea025b2 --- /dev/null +++ b/waybar/themes/catppuccin-mocha.css @@ -0,0 +1,63 @@ +/* catppuccin mocha */ + +@define-color rosewater #f5e0dc; +@define-color flamingo #f2cdcd; +@define-color pink #f5c2e7; +@define-color mauve #cba6f7; +@define-color red #f38ba8; +@define-color maroon #eba0ac; +@define-color peach #fab387; +@define-color yellow #f9e2af; +@define-color green #a6e3a1; +@define-color teal #94e2d5; +@define-color sky #89dceb; +@define-color sapphire #74c7ec; +@define-color blue #89b4fa; +@define-color lavender #b4befe; +@define-color text #cdd6f4; +@define-color subtext1 #bac2de; +@define-color subtext0 #a6adc8; +@define-color overlay2 #9399b2; +@define-color overlay1 #7f849c; +@define-color overlay0 #6c7086; +@define-color surface2 #585b70; +@define-color surface1 #45475a; +@define-color surface0 #313244; +@define-color base #1e1e2e; +@define-color mantle #181825; +@define-color crust #11111b; + +/* + br - border + bg - background + fg - foreground +*/ + +/* main colors */ + +@define-color accent @lavender; +@define-color main-br @subtext0; +@define-color main-bg @crust; +@define-color main-fg @text; +@define-color hover-bg @base; +@define-color hover-fg alpha(@main-fg, 0.75); +@define-color outline shade(@main-bg, 0.5); + +/* module colors */ + +@define-color workspaces @mantle; +@define-color temperature @mantle; +@define-color memory @base; +@define-color cpu @surface0; +@define-color time @surface0; +@define-color date @base; +@define-color tray @mantle; +@define-color volume @mantle; +@define-color backlight @base; +@define-color battery @surface0; + +/* state colors */ + +@define-color warning @yellow; +@define-color critical @red; +@define-color charging @green; diff --git a/waybar/themes/fzf/catppuccin.txt b/waybar/themes/fzf/catppuccin.txt new file mode 100644 index 0000000..77d1a72 --- /dev/null +++ b/waybar/themes/fzf/catppuccin.txt @@ -0,0 +1,15 @@ +current-bg surface0 +bg base +spinner rosewater +hl red +fg text +header red +info mauve +pointer rosewater +marker lavender +current-fg text +prompt mauve +current-hl red +selected-bg surface1 +border overlay0 +label text