From bee45f21ad557f52d243c37ccc3ed21216a691be Mon Sep 17 00:00:00 2001 From: aibrash Date: Wed, 28 Oct 2026 10:06:04 +0500 Subject: [PATCH] Add swaync control center, wifi/bluetooth/vpn rofi menus, waybar notification button Co-Authored-By: Claude Sonnet 5.5 --- .config/sway/bt-menu.sh | 44 +++++++++ .config/sway/config.d/10-appearance.conf | 2 +- .config/sway/config.d/20-swayfx.conf | 2 + .config/sway/config.d/30-workflow.conf | 3 + .config/sway/vpn-menu.sh | 26 +++++ .config/sway/wifi-menu.sh | 44 +++++++++ .config/swaync/config.json | 98 +++++++++++++++++++ .config/swaync/style.css | 117 +++++++++++++++++++++++ .config/waybar/config.jsonc | 22 ++++- .config/waybar/style.css | 3 +- README.md | 6 +- install.sh | 4 +- 12 files changed, 364 insertions(+), 7 deletions(-) create mode 100755 .config/sway/bt-menu.sh create mode 100755 .config/sway/vpn-menu.sh create mode 100755 .config/sway/wifi-menu.sh create mode 100644 .config/swaync/config.json create mode 100644 .config/swaync/style.css diff --git a/.config/sway/bt-menu.sh b/.config/sway/bt-menu.sh new file mode 100755 index 0000000..6919e13 --- /dev/null +++ b/.config/sway/bt-menu.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Bluetooth menu (rofi): power, connect/disconnect known devices, scan and pair new ones. +THEME=~/.config/rofi/catppuccin.rasi +menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; } + +if ! bluetoothctl show | grep -q "Powered: yes"; then + choice=$(printf '%s\n' "Включить Bluetooth" | menu "Bluetooth") || exit 0 + [[ $choice == "Включить Bluetooth" ]] && bluetoothctl power on >/dev/null && notify-send "Bluetooth" "Включён" + exit 0 +fi + +build() { + local list="" mac name mark + while read -r _ mac name; do + [[ -z $mac ]] && continue + mark="○"; bluetoothctl info "$mac" | grep -q "Connected: yes" && mark="●" + list+="$mark $name [$mac]"$'\n' + done < <(bluetoothctl devices) + printf '%s' "$list" +} + +choice=$(printf '%s%s\n%s\n' "$(build)" "Найти новые устройства" "Выключить Bluetooth" | sed '/^$/d' | menu "Bluetooth") || exit 0 +[[ -z $choice ]] && exit 0 + +case $choice in + "Выключить Bluetooth") bluetoothctl power off >/dev/null; notify-send "Bluetooth" "Выключен"; exit 0 ;; + "Найти новые устройства") + notify-send "Bluetooth" "Поиск устройств (8 с)…" + bluetoothctl --timeout 8 scan on >/dev/null 2>&1 + choice=$(build | menu "Bluetooth: найденные") || exit 0 + [[ -z $choice ]] && exit 0 + mac=${choice##*[}; mac=${mac%]} + bluetoothctl pair "$mac" >/dev/null 2>&1; bluetoothctl trust "$mac" >/dev/null 2>&1 + bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено" || notify-send -u critical "Bluetooth" "Не удалось подключиться" + exit 0 ;; +esac + +mac=${choice##*[}; mac=${mac%]} +name=${choice:2}; name=${name% [*} +if [[ ${choice:0:1} == "●" ]]; then + bluetoothctl disconnect "$mac" >/dev/null && notify-send "Bluetooth" "Отключено: $name" +else + bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено: $name" || notify-send -u critical "Bluetooth" "Не удалось подключиться: $name" +fi diff --git a/.config/sway/config.d/10-appearance.conf b/.config/sway/config.d/10-appearance.conf index a680cdf..127df19 100644 --- a/.config/sway/config.d/10-appearance.conf +++ b/.config/sway/config.d/10-appearance.conf @@ -26,7 +26,7 @@ client.placeholder $base $base $text $base $base client.background $base # Autostart -exec_always sh -c 'pkill -x dunst; exec dunst' +exec_always sh -c 'pkill -x dunst; pkill -x swaync; exec swaync' exec_always sh -c 'pkill -x nm-applet; exec nm-applet --indicator' bindsym --to-code $mod+Shift+x exec ~/.config/sway/lock.sh diff --git a/.config/sway/config.d/20-swayfx.conf b/.config/sway/config.d/20-swayfx.conf index 546fbb7..73836f3 100644 --- a/.config/sway/config.d/20-swayfx.conf +++ b/.config/sway/config.d/20-swayfx.conf @@ -33,6 +33,8 @@ titlebar_separator disable layer_effects "waybar" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable layer_effects "rofi" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable layer_effects "notifications" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable +layer_effects "swaync-control-center" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable +layer_effects "swaync-notification-window" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable layer_effects "swaynag" blur enable; blur_ignore_transparent enable; corner_radius 12 # Translucent terminals, glass shows through diff --git a/.config/sway/config.d/30-workflow.conf b/.config/sway/config.d/30-workflow.conf index dd5b85d..a7dd08f 100644 --- a/.config/sway/config.d/30-workflow.conf +++ b/.config/sway/config.d/30-workflow.conf @@ -32,3 +32,6 @@ bindsym --to-code $mod+Shift+s exec ~/.config/sway/screenshot-menu.sh bindsym --to-code $mod+F1 exec ~/.config/sway/cheatsheet.sh # Performance mode: toggle blur + shadows bindsym --to-code $mod+Shift+b blur toggle; shadows toggle +# Control center (notifications + quick settings) +bindsym --to-code $mod+n exec swaync-client -t -sw +bindsym --to-code $mod+Shift+n exec swaync-client -d -sw diff --git a/.config/sway/vpn-menu.sh b/.config/sway/vpn-menu.sh new file mode 100755 index 0000000..eb1458b --- /dev/null +++ b/.config/sway/vpn-menu.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# VPN menu (rofi): lists NetworkManager vpn/wireguard connections, click to connect/disconnect. +# Secrets are asked by nm-applet (secret agent). +THEME=~/.config/rofi/catppuccin.rasi +menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; } + +active=$(nmcli -t -e no -f NAME,TYPE connection show --active) +list="" +while IFS= read -r line; do + type=${line##*:}; name=${line%:*} + [[ $type == vpn || $type == wireguard ]] || continue + mark="○"; grep -Fxq "$line" <<<"$active" && mark="●" + list+="$mark $name ($type)"$'\n' +done < <(nmcli -t -e no -f NAME,TYPE connection show) + +[[ -z $list ]] && { notify-send "VPN" "Нет настроенных VPN"; exit 0; } +choice=$(printf '%s%s\n' "$list" "Расширенные настройки…" | menu "VPN") || exit 0 +[[ -z $choice ]] && exit 0 +[[ $choice == "Расширенные настройки…" ]] && exec nm-connection-editor + +name=${choice:2}; name=${name% (*} +if [[ ${choice:0:1} == "●" ]]; then + nmcli connection down id "$name" >/dev/null && notify-send "VPN" "Отключено: $name" +else + nmcli connection up id "$name" >/dev/null 2>&1 && notify-send "VPN" "Подключено: $name" || notify-send -u critical "VPN" "Не удалось подключиться: $name" +fi diff --git a/.config/sway/wifi-menu.sh b/.config/sway/wifi-menu.sh new file mode 100755 index 0000000..5772f94 --- /dev/null +++ b/.config/sway/wifi-menu.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Wi-Fi menu (rofi): toggle radio, connect/disconnect, prompt for password on new networks. +THEME=~/.config/rofi/catppuccin.rasi +menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; } + +radio=$(nmcli radio wifi) +if [[ $radio != enabled ]]; then + choice=$(printf '%s\n' "Включить Wi-Fi" | menu "Wi-Fi") + [[ $choice == "Включить Wi-Fi" ]] && nmcli radio wifi on && notify-send "Wi-Fi" "Включён" + exit 0 +fi + +declare -A seen +list="" +while IFS=: read -r use sig sec ssid; do + [[ -z $ssid || -n ${seen[$ssid]} ]] && continue + seen[$ssid]=1 + mark="○"; [[ $use == '*' ]] && mark="●" + lock=""; [[ -n $sec && $sec != "--" ]] && lock=" (защищена)" + list+="$mark $ssid ${sig}%$lock"$'\n' +done < <(nmcli -t -e no -f IN-USE,SIGNAL,SECURITY,SSID dev wifi list --rescan auto | sort -t: -k2 -nr) + +choice=$(printf '%s%s\n%s\n' "$list" "Выключить Wi-Fi" "Расширенные настройки…" | sed '/^$/d' | menu "Wi-Fi") || exit 0 +[[ -z $choice ]] && exit 0 + +case $choice in + "Выключить Wi-Fi") nmcli radio wifi off; notify-send "Wi-Fi" "Выключен"; exit 0 ;; + "Расширенные настройки…") exec nm-connection-editor ;; +esac + +ssid=${choice:2}; ssid=${ssid%% *} +if [[ ${choice:0:1} == "●" ]]; then + nmcli connection down id "$ssid" >/dev/null && notify-send "Wi-Fi" "Отключено от $ssid" +elif nmcli -t -f NAME connection show | grep -Fxq "$ssid"; then + nmcli connection up id "$ssid" >/dev/null 2>&1 && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Не удалось подключиться к $ssid" +else + if [[ $choice == *"(защищена)"* ]]; then + pw=$(menu "Пароль для $ssid" -password -lines 0) || exit 0 + out=$(nmcli dev wifi connect "$ssid" password "$pw" 2>&1) + else + out=$(nmcli dev wifi connect "$ssid" 2>&1) + fi + [[ $? -eq 0 ]] && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Ошибка: $out" +fi diff --git a/.config/swaync/config.json b/.config/swaync/config.json new file mode 100644 index 0000000..786105c --- /dev/null +++ b/.config/swaync/config.json @@ -0,0 +1,98 @@ +{ + "$schema": "/etc/xdg/swaync/configSchema.json", + "ignore-gtk-theme": true, + "positionX": "right", + "positionY": "top", + "layer": "overlay", + "control-center-layer": "top", + "layer-shell": true, + "layer-shell-cover-screen": false, + "cssPriority": "user", + "control-center-margin-top": 6, + "control-center-margin-bottom": 8, + "control-center-margin-right": 8, + "control-center-margin-left": 0, + "control-center-width": 460, + "control-center-height": 620, + "fit-to-screen": false, + "notification-window-width": 380, + "notification-icon-size": 48, + "notification-body-image-height": 100, + "notification-body-image-width": 200, + "timeout": 8, + "timeout-low": 5, + "timeout-critical": 0, + "transition-time": 180, + "hide-on-clear": false, + "hide-on-action": true, + "keyboard-shortcuts": true, + "notification-grouping": true, + "relative-timestamps": true, + "text-empty": "Нет уведомлений", + "widgets": [ + "title", + "buttons-grid", + "volume", + "backlight", + "mpris", + "dnd", + "notifications" + ], + "widget-config": { + "title": { + "text": "Центр управления", + "clear-all-button": true, + "button-text": "Очистить" + }, + "dnd": { + "text": "Не беспокоить" + }, + "buttons-grid": { + "actions": [ + { + "label": " Wi-Fi", + "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/wifi-menu.sh'" + }, + { + "label": " Bluetooth", + "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/bt-menu.sh'" + }, + { + "label": " VPN", + "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/vpn-menu.sh'" + }, + { + "label": " Микрофон", + "type": "toggle", + "active": true, + "command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && wpctl set-mute @DEFAULT_AUDIO_SOURCE@ 0 || wpctl set-mute @DEFAULT_AUDIO_SOURCE@ 1'", + "update-command": "sh -c 'wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED && echo false || echo true'" + }, + { + "label": " Блок", + "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/lock.sh'" + }, + { + "label": " Выкл", + "command": "sh -c 'swaync-client -cp -sw; ~/.config/rofi/powermenu.sh'" + } + ] + }, + "volume": { + "label": "", + "show-per-app": true, + "show-per-app-icon": true, + "show-per-app-label": false + }, + "backlight": { + "label": "", + "device": "intel_backlight" + }, + "mpris": { + "image-size": 64, + "image-radius": 12, + "autohide": true, + "show-album-art": "when-available" + } + } +} \ No newline at end of file diff --git a/.config/swaync/style.css b/.config/swaync/style.css new file mode 100644 index 0000000..827af59 --- /dev/null +++ b/.config/swaync/style.css @@ -0,0 +1,117 @@ +/* swaync glass theme: matches rofi/waybar, purple accent from kitty. + Icons come from FontAwesome (the same glyphs the waybar uses). */ +@define-color text #f2f2f2; +@define-color sub #b4b4b4; +@define-color accent #bb9af7; +@define-color red #f7768e; + +* { + font-family: "JetBrains Mono", "FontAwesome", "Font Awesome 6 Brands", monospace; + font-size: 14px; + color: @text; + text-shadow: none; + box-shadow: none; +} + +/* ---------- Panel ---------- */ +.control-center { + background: rgba(14, 14, 18, 0.80); + border: 1px solid rgba(232, 232, 232, 0.18); + border-radius: 20px; + padding: 16px; +} +.control-center .widget-title { margin: 2px 2px 12px 2px; } +.widget-title > label { font-size: 18px; font-weight: bold; } +.widget-title > button { + background: rgba(255, 255, 255, 0.10); + border: none; border-radius: 12px; padding: 6px 16px; +} +.widget-title > button label { color: @text; } +.widget-title > button:hover { background: rgba(255, 255, 255, 0.22); } + +/* ---------- Toggle tiles ---------- */ +.widget-buttons-grid { background: transparent; margin: 0 0 10px 0; padding: 0; } +.widget-buttons-grid > flowbox > flowboxchild > button { + background: rgba(255, 255, 255, 0.09); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 14px; + min-width: 120px; min-height: 46px; margin: 4px; + font-size: 14px; +} +.widget-buttons-grid > flowbox > flowboxchild > button label { font-weight: bold; } +.widget-buttons-grid > flowbox > flowboxchild > button:hover { background: rgba(255, 255, 255, 0.20); } +.widget-buttons-grid > flowbox > flowboxchild > button:checked { + background: @accent; border-color: @accent; +} +.widget-buttons-grid > flowbox > flowboxchild > button:checked label { color: #11111b; } + +/* ---------- Sliders ---------- */ +.widget-volume, .widget-backlight { + background: rgba(255, 255, 255, 0.09); + border-radius: 14px; padding: 10px 16px; margin: 4px 0; +} +.widget-volume label, .widget-backlight label { font-size: 18px; min-width: 26px; } +scale trough { + min-height: 8px; border-radius: 6px; + background: rgba(255, 255, 255, 0.20); +} +scale highlight { background: @accent; border-radius: 6px; } +scale slider { + min-width: 18px; min-height: 18px; margin: -6px; + background: @text; border-radius: 50%; border: none; +} +.widget-volume button { background: rgba(255, 255, 255, 0.10); border: none; border-radius: 10px; } +.per-app-volume { background: transparent; padding: 4px 0; } + +/* ---------- Player ---------- */ +.widget-mpris { + background: rgba(255, 255, 255, 0.09); + border-radius: 14px; padding: 8px; margin: 4px 0; +} +.widget-mpris-title { font-weight: bold; font-size: 15px; } +.widget-mpris-subtitle { color: @sub; font-size: 13px; } +.widget-mpris button { background: transparent; border: none; border-radius: 12px; } +.widget-mpris button:hover { background: rgba(255, 255, 255, 0.18); } + +/* ---------- Do not disturb ---------- */ +.widget-dnd { margin: 10px 4px; font-size: 14px; } +.widget-dnd > label { font-weight: bold; } +.widget-dnd > switch { + background: rgba(255, 255, 255, 0.20); + border: none; border-radius: 14px; +} +.widget-dnd > switch:checked { background: @accent; } +.widget-dnd > switch slider { background: @text; border-radius: 12px; } + +/* ---------- Notifications (popups + list) ---------- */ +.notification-row { outline: none; } +.notification { + background: rgba(14, 14, 18, 0.85); + border: 1px solid rgba(232, 232, 232, 0.22); + border-radius: 14px; margin: 6px 8px; padding: 0; +} +.control-center .notification { background: rgba(255, 255, 255, 0.09); border: none; } +.notification-content { background: transparent; padding: 10px; } +.notification-default-action, .notification-action { background: transparent; border-radius: 14px; } +.notification-default-action:hover { background: rgba(255, 255, 255, 0.09); } +.summary { font-weight: bold; font-size: 15px; } +.body { color: #d8d8d8; font-size: 14px; } +.time { color: @sub; font-size: 12px; } +.image { border-radius: 10px; } +.close-button { + background: rgba(255, 255, 255, 0.14); + border: none; border-radius: 50%; margin: 6px; padding: 2px; +} +.close-button:hover { background: @red; } +.critical { border: 1px solid @red; } +.notification-group-headers label { color: @sub; font-weight: bold; } +.widget-notifications, .notification-group { background: transparent; } + +/* empty state: text only, no broken icon */ +.notifications-placeholder, .control-center-list placeholder { color: @sub; font-size: 14px; } +.notifications-placeholder image, .control-center-list placeholder image { opacity: 0; min-height: 0; min-width: 0; -gtk-icon-size: 0; } +.notifications-placeholder > *:first-child, +.notifications-placeholder picture, +.notifications-placeholder > box > image, +.control-center-list-placeholder image, +.empty-label image { opacity: 0; min-height: 0; min-width: 0; margin: 0; } diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc index eba2b01..485686f 100644 --- a/.config/waybar/config.jsonc +++ b/.config/waybar/config.jsonc @@ -8,7 +8,7 @@ "spacing": 6, "modules-left": ["sway/workspaces", "sway/mode", "sway/window"], "modules-center": ["clock", "mpris"], - "modules-right": ["idle_inhibitor", "sway/language", "group/hw", "backlight", "pulseaudio", "network", "battery", "tray", "custom/power"], + "modules-right": ["idle_inhibitor", "sway/language", "group/hw", "backlight", "pulseaudio", "network", "battery", "tray", "custom/notification", "custom/power"], "sway/workspaces": { "disable-scroll": true, "all-outputs": true, "format": "{icon}", "format-icons": {"1": "", "2": "", "3": "", "4": "", "5": "", "urgent": "", "default": ""} }, "sway/window": { "max-length": 45, "format": "{title}", "rewrite": { "(.*) — Mozilla Firefox": " $1", "(.*) - Chromium": " $1" } }, @@ -42,5 +42,25 @@ "format-icons": ["", "", "", "", ""] }, "tray": { "spacing": 8 }, + "custom/notification": { + "tooltip": false, + "format": "{icon}", + "format-icons": { + "notification": "\uf0f3\uf111", + "none": "\uf0f3", + "dnd-notification": "\uf1f6\uf111", + "dnd-none": "\uf1f6", + "inhibited-notification": "\uf0f3\uf111", + "inhibited-none": "\uf0f3", + "dnd-inhibited-notification": "\uf1f6\uf111", + "dnd-inhibited-none": "\uf1f6" + }, + "return-type": "json", + "exec-if": "which swaync-client", + "exec": "swaync-client -swb", + "on-click": "swaync-client -t -sw", + "on-click-right": "swaync-client -d -sw", + "escape": true + }, "custom/power": { "format": "", "tooltip": false, "on-click": "~/.config/rofi/powermenu.sh" } } diff --git a/.config/waybar/style.css b/.config/waybar/style.css index 0c13835..266bc73 100644 --- a/.config/waybar/style.css +++ b/.config/waybar/style.css @@ -18,7 +18,7 @@ window#waybar { background: transparent; color: @text; } /* glass pills: translucent so swayfx blur shows through */ #workspaces, #window, #clock, #language, #cpu, #memory, #pulseaudio, #network, #battery, -#tray, #mode, #custom-power, #backlight, #idle_inhibitor, #temperature, #mpris { +#tray, #mode, #custom-power, #custom-notification, #backlight, #idle_inhibitor, #temperature, #mpris { background: alpha(@base, 0.55); border: 1px solid alpha(@text, 0.08); border-radius: 14px; @@ -58,6 +58,7 @@ window#waybar.empty #window { background: transparent; border-color: transparent #battery.warning:not(.charging) { color: @yellow; } #battery.critical:not(.charging) { color: @red; animation: blink 1s steps(2) infinite; } #temperature.critical { color: @red; } +#custom-notification { padding: 0 14px; } #custom-power { padding: 0 14px; } #custom-power:hover { background: @red; color: @base; border-color: @red; } diff --git a/README.md b/README.md index 03c4b15..e32b741 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ | `.config/sway/*.sh` | `wallpaper.sh`, `screenshot-menu.sh`, `screenshot.sh`, `cheatsheet.sh`, `idle.sh`, `mirror.sh` | | `.config/waybar` | стеклянные плашки, выдвижной блок железа, mpris, яркость, idle-inhibitor | | `.config/rofi` | полупрозрачная тема + меню выключения | -| `.config/dunst` | полупрозрачные уведомления со скруглением | +| `.config/swaync` | центр уведомлений и панель управления (`Super+N`): плитки Wi-Fi / Bluetooth / VPN, громкость, яркость, плеер | +| `.config/sway/{wifi,bt,vpn}-menu.sh` | rofi-меню для плиток панели (подключение, пароль, спаривание) | +| `.config/dunst` | старые уведомления (не используются, оставлены для отката) | | `.config/swaylock` | локскрин с обоями | | `.config/kitty/kitty.conf` | прозрачность терминала, чтобы был виден blur | | `.config/sway/config.d/40-bar.conf` | запуск waybar (без `sway-config-fedora`) | @@ -23,7 +25,7 @@ ### Что было добавлено - **Blur 4 прохода** + brightness / contrast / saturation, шум; свечение у фокусного окна, тёмная тень у остальных. - **Waybar:** стеклянные плашки, растягивающийся активный воркспейс, модули mpris, backlight, temperature, idle-inhibitor, выдвижной блок `⚙` (температура / CPU / RAM), мигание при низком заряде. -- **Rofi и dunst** сделаны полупрозрачными, чтобы под ними был виден blur. +- **Rofi и swaync** сделаны полупрозрачными, чтобы под ними был виден blur. - **Выбор обоев** с превью (rofi), 6 обоев в наборе. - **Меню скриншотов** (область / экран, в буфер / в файл). - **Шпаргалка по хоткеям** прямо из конфига. diff --git a/install.sh b/install.sh index 3f5d671..2b320fc 100755 --- a/install.sh +++ b/install.sh @@ -33,7 +33,7 @@ install_packages() { return fi - local want=(waybar rofi dunst swaylock swayidle kitty grim slurp wl-clipboard playerctl + local want=(waybar rofi SwayNotificationCenter swaylock swayidle kitty grim slurp wl-clipboard playerctl brightnessctl ImageMagick libnotify pavucontrol network-manager-applet wireplumber fontawesome-6-free-fonts) fc-list | grep -qi "JetBrains Mono" || want+=(jetbrains-mono-fonts) @@ -88,7 +88,7 @@ install_configs() { say "Backing up existing configs to $BACKUP" mkdir -p "$BACKUP" local d - for d in sway waybar rofi dunst swaylock kitty; do + for d in sway waybar rofi dunst swaync swaylock kitty; do [ -e "$CFG/$d" ] && cp -a "$CFG/$d" "$BACKUP/" done