3 Commits

Author SHA1 Message Date
f578344652 update with our stuff 2026-04-16 16:57:21 +02:00
485b61dd3b update 2026-04-15 23:40:37 +02:00
9108e3be6b update 2026-04-15 21:59:27 +02:00
12 changed files with 207 additions and 777 deletions

51
.bashrc Normal file
View File

@@ -0,0 +1,51 @@
#
# ~/.bashrc
#
# If not running interactively, don't do anything
[[ $- != *i* ]] && return
# -------------------------------------------------------
# Core
# -------------------------------------------------------
alias ls='ls --color=auto'
alias grep='grep --color=auto'
alias c='clear'
# -------------------------------------------------------
# Build
# -------------------------------------------------------
alias make="make -j$(nproc)"
alias ninja="ninja -j$(nproc)"
alias n='ninja'
# -------------------------------------------------------
# Pacman / AUR
# -------------------------------------------------------
alias update='sudo pacman -Syu'
alias rmpkg='sudo pacman -Rsn'
alias cleanch='sudo pacman -Scc'
alias fixpacman='sudo rm /var/lib/pacman/db.lck'
alias cleanup='sudo pacman -Rsn $(pacman -Qtdq)'
# Help people coming from Debian/Ubuntu
alias apt='man pacman'
alias apt-get='man pacman'
# -------------------------------------------------------
# Utilities
# -------------------------------------------------------
alias please='sudo'
alias tb='nc termbin.com 9999'
alias jctl='journalctl -p 3 -xb'
alias rip="expac --timefmt='%Y-%m-%d %T' '%l\t%n %v' | sort | tail -200 | nl"
# -------------------------------------------------------
# Prompt
# -------------------------------------------------------
PS1='[\u@\h \W]\$ '

View File

@@ -1,96 +1,50 @@
[env] [colors.bright]
TERM = "xterm-256color" black = "#4c566a"
blue = "#81a1c1"
[window] cyan = "#8fbcbb"
padding = { x = 10, y = 10 } green = "#a3be8c"
opacity = 1.0 magenta = "#b48ead"
red = "#bf616a"
[font] white = "#eceff4"
size = 11.0 yellow = "#ebcb8b"
[font.normal]
family = "SauceCodePro Nerd Font"
style = "Regular"
[font.bold]
family = "SauceCodePro Nerd Font"
style = "Bold"
[font.italic]
family = "SauceCodePro Nerd Font"
style = "Italic"
[cursor]
style = { shape = "Beam", blinking = "Off" }
unfocused_hollow = true
[selection]
save_to_clipboard = true
[colors.primary]
background = "#2E3440"
foreground = "#D8DEE9"
dim_foreground = "#A5ABB6"
bright_foreground = "#ECEFF4"
[colors.cursor] [colors.cursor]
text = "#2E3440" cursor = "#d8dee9"
cursor = "#D8DEE9" text = "#2e3440"
[colors.vi_mode_cursor]
text = "#2E3440"
cursor = "#88C0D0"
[colors.search.matches]
foreground = "#2E3440"
background = "#EBCB8B"
[colors.search.focused_match]
foreground = "#2E3440"
background = "#A3BE8C"
[colors.footer_bar]
foreground = "#D8DEE9"
background = "#3B4252"
[colors.hints.start]
foreground = "#2E3440"
background = "#EBCB8B"
[colors.hints.end]
foreground = "#2E3440"
background = "#4C566A"
[colors.line_indicator]
foreground = "None"
background = "None"
[colors.normal]
black = "#3B4252"
red = "#BF616A"
green = "#A3BE8C"
yellow = "#EBCB8B"
blue = "#81A1C1"
magenta = "#B48EAD"
cyan = "#88C0D0"
white = "#E5E9F0"
[colors.bright]
black = "#4C566A"
red = "#BF616A"
green = "#A3BE8C"
yellow = "#EBCB8B"
blue = "#81A1C1"
magenta = "#B48EAD"
cyan = "#8FBCBB"
white = "#ECEFF4"
[colors.dim] [colors.dim]
black = "#373E4D" black = "#373e4d"
red = "#94545D" blue = "#68809a"
cyan = "#6d96a5"
green = "#809575" green = "#809575"
yellow = "#B29E75" magenta = "#8c738c"
blue = "#68809A" red = "#94545d"
magenta = "#8C738C" white = "#aeb3bb"
cyan = "#6D96A5" yellow = "#b29e75"
white = "#AEB3BB"
[colors.normal]
black = "#3b4252"
blue = "#81a1c1"
cyan = "#88c0d0"
green = "#a3be8c"
magenta = "#b48ead"
red = "#bf616a"
white = "#e5e9f0"
yellow = "#ebcb8b"
[colors.primary]
background = "#2e3440"
dim_foreground = "#a5abb6"
foreground = "#d8dee9"
[colors.search.matches]
background = "#88c0d0"
foreground = "CellBackground"
[colors.selection]
background = "#4c566a"
text = "CellForeground"
[colors.vi_mode_cursor]
cursor = "#d8dee9"
text = "#2e3440"

View File

@@ -22,7 +22,7 @@
################ ################
# See https://wiki.hypr.land/Configuring/Monitors/ # See https://wiki.hypr.land/Configuring/Monitors/
source = ~/.config/hypr/monitors.conf monitor=,preferred,auto,auto
################### ###################
@@ -358,11 +358,3 @@ windowrule {
float = yes float = yes
} }
windowrule {
name = float-steam
match:class = ^([Ss]team)$
float = yes
}

View File

@@ -0,0 +1,10 @@
# Hyprland Monitor Configuration
# Generated by hyprmon
# Contains ALL configured monitors from all workspaces
monitor=desc:Microstep MEG 342C OLED,3440x1440@175.00,1920x0,1
monitor=desc:Dell Inc. DELL P2422H CY98FQ3,1920x1080@60.00,5360x0,1
monitor=desc:Dell Inc. DELL P2422HE HFKK5L3,1920x1080@60.00,0x0,1
# Fallback for unknown monitors
monitor=,preferred,auto,1

View File

@@ -1,7 +1,7 @@
{ {
"workspaces": [ "workspaces": [
{ {
"name": "Defaultmon-not-found", "name": "Default",
"monitors": { "monitors": {
"desc:Dell Inc. DELL P2422H CY98FQ3": { "desc:Dell Inc. DELL P2422H CY98FQ3": {
"resolution": "1920x1080", "resolution": "1920x1080",
@@ -12,15 +12,6 @@
"position_y": 0, "position_y": 0,
"is_primary": false "is_primary": false
}, },
"desc:Dell Inc. DELL P2422HE HFKK5L3": {
"resolution": "1920x1080",
"refresh_rate": 60.0,
"scale": 1.0,
"rotation": 0,
"position_x": 0,
"position_y": 0,
"is_primary": false
},
"desc:Microstep MEG 342C OLED": { "desc:Microstep MEG 342C OLED": {
"resolution": "3440x1440", "resolution": "3440x1440",
"refresh_rate": 175.0, "refresh_rate": 175.0,
@@ -29,57 +20,18 @@
"position_x": 1920, "position_x": 1920,
"position_y": 0, "position_y": 0,
"is_primary": true "is_primary": true
},
"desc:Dell Inc. DELL P2422HE HFKK5L3": {
"resolution": "1920x1080",
"refresh_rate": 60.0,
"scale": 1.0,
"rotation": 0,
"position_x": 0,
"position_y": 0,
"is_primary": false
} }
} }
},
{
"name": "l -ba /home/zphinx/.",
"monitors": {}
},
{
"name": "d /home/zphinx/code/",
"monitors": {}
},
{
"name": " echo \"$p :: syml",
"monitors": {}
},
{
"name": " echo \"$p :: file",
"monitors": {}
},
{
"name": "g\" 2>/dev/null || tr",
"monitors": {}
},
{
"name": "x/.config/waybar/scr",
"monitors": {}
},
{
"name": "x/code/mine status -",
"monitors": {}
},
{
"name": "ohup waybar -c /home",
"monitors": {}
},
{
"name": "eline -- dotfiles/.c",
"monitors": {}
},
{
"name": "s-serif' && fc-match",
"monitors": {}
},
{
"name": "eeded ttf-fira-code ",
"monitors": {}
},
{
"name": " /home/zphinx/.confi",
"monitors": {}
} }
], ],
"active_workspace": 12 "active_workspace": 0
} }

View File

@@ -10,8 +10,6 @@
"clock" "clock"
], ],
"modules-right": [ "modules-right": [
"custom/spotify",
"custom/weather",
"custom/screenshot", "custom/screenshot",
"idle_inhibitor", "idle_inhibitor",
"pulseaudio", "pulseaudio",
@@ -22,53 +20,56 @@
"tray" "tray"
], ],
"hyprland/workspaces": { "hyprland/workspaces": {
"format": "{id}" "all-outputs": true,
"format": "{id} {windows}",
"format-window-separator": "",
"window-rewrite-default": "󰘔",
"window-rewrite": {
"class<firefox>": "",
"class<org\\.wezfurlong\\.wezterm>": "",
"class<Alacritty>": "",
"class<code|Code|codium|VSCodium>": "󰨞",
"class<thunar>": "",
"class<org\\.kde\\.dolphin>": "",
"class<discord>": "",
"class<vesktop>": "",
"class<spotify>": "",
"class<steam>": ""
}
}, },
"custom/screenshot": { "custom/screenshot": {
"exec": "printf '{\"text\": \"<span foreground=\\\"#E5E9F0\\\">Shot</span> <span font_desc=\\\"SauceCodePro Nerd Font 17\\\" foreground=\\\"#FFFFFF\\\">󰄀</span>\", \"tooltip\": \"Area screenshot: edit in Swappy, then choose save path and filename; Esc on filename uses screenshot\"}'", "exec": "printf '{\"text\": \"󰄀\", \"tooltip\": \"Area screenshot: edit in Swappy, copy to clipboard, save to NAS pictures if mounted\"}'",
"return-type": "json", "return-type": "json",
"escape": false,
"interval": "once", "interval": "once",
"on-click": "$HOME/.config/waybar/scripts/capture-share-shot.sh" "on-click": "$HOME/.config/waybar/scripts/capture-share-shot.sh"
}, },
"idle_inhibitor": { "idle_inhibitor": {
"escape": false,
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "<span foreground=\"#A3BE8C\">Awake</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#A3BE8C\"></span>", "activated": "",
"deactivated": "<span foreground=\"#D8DEE9\">Idle</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\"></span>" "deactivated": ""
}
},
"hyprland/window": {
"format": "{class}: {title}",
"icon": true,
"icon-size": 16,
"max-length": 80,
"separate-outputs": true,
"rewrite": {
"^(.*)$": "$1"
} }
}, },
"tray": { "tray": {
"spacing": 10 "spacing": 10
}, },
"clock": { "clock": {
"escape": false, "format": " {:%H:%M}",
"format": "<span foreground=\"#D8DEE9\">{:%H:%M}</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#88C0D0\"></span>",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>", "tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
"format-alt": "<span foreground=\"#D8DEE9\">{:%Y-%m-%d}</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\"></span>" "format-alt": " {:%Y-%m-%d}"
},
"custom/spotify": {
"exec": "bash $HOME/.config/waybar/scripts/spotify-waybar.sh",
"return-type": "json",
"interval": 2,
"escape": false,
"on-click": "bash $HOME/.config/waybar/scripts/spotify-waybar.sh --toggle",
"on-click-right": "bash $HOME/.config/waybar/scripts/spotify-waybar.sh --stop",
"on-scroll-up": "bash $HOME/.config/waybar/scripts/spotify-waybar.sh --next",
"on-scroll-down": "bash $HOME/.config/waybar/scripts/spotify-waybar.sh --prev",
"tooltip": false
},
"custom/weather": {
"exec": "bash $HOME/.config/waybar/scripts/weather-norrkoping.sh",
"return-type": "json",
"interval": 600,
"escape": false,
"tooltip": true
}, },
"cpu": { "cpu": {
"escape": false, "format": " {usage}%",
"format": "<span foreground=\"#D8DEE9\">{usage}%</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\"></span>",
"tooltip": false, "tooltip": false,
"on-click": "alacritty -e btop" "on-click": "alacritty -e btop"
}, },
@@ -76,7 +77,6 @@
"custom/mount-data": { "custom/mount-data": {
"exec": "$HOME/.config/waybar/scripts/check-mount.sh /mnt/data data", "exec": "$HOME/.config/waybar/scripts/check-mount.sh /mnt/data data",
"return-type": "json", "return-type": "json",
"escape": false,
"interval": 10, "interval": 10,
"tooltip": true, "tooltip": true,
"on-click": "thunar /mnt/data" "on-click": "thunar /mnt/data"
@@ -84,37 +84,34 @@
"custom/mount-usb1": { "custom/mount-usb1": {
"exec": "$HOME/.config/waybar/scripts/check-mount.sh /mnt/usb1 usb1", "exec": "$HOME/.config/waybar/scripts/check-mount.sh /mnt/usb1 usb1",
"return-type": "json", "return-type": "json",
"escape": false,
"interval": 10, "interval": 10,
"tooltip": true, "tooltip": true,
"on-click": "thunar /mnt/usb1" "on-click": "thunar /mnt/usb1"
}, },
"network": { "network": {
"escape": false, "format-wifi": " {essid} ({signalStrength}%)",
"format-wifi": "<span foreground=\"#D8DEE9\">{essid} ({signalStrength}%)</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#88C0D0\"></span>", "format-ethernet": "󰈀 {ipaddr}/{cidr}",
"format-ethernet": "<span foreground=\"#D8DEE9\">{ipaddr}/{cidr}</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#88C0D0\">󰈀</span>", "tooltip-format": "󰈀 {ifname} via {gwaddr}",
"tooltip-format": "<span foreground=\"#D8DEE9\">{ifname} via {gwaddr}</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#88C0D0\">󰈀</span>", "format-linked": "󰈀 {ifname} (No IP)",
"format-linked": "<span foreground=\"#D8DEE9\">{ifname} (No IP)</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\">󰈀</span>", "format-disconnected": "󰖪 Disconnected",
"format-disconnected": "<span foreground=\"#EBCB8B\">Disconnected</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#BF616A\">󰖪</span>", "format-alt": "󰈀 {ifname}: {ipaddr}/{cidr}",
"format-alt": "<span foreground=\"#D8DEE9\">{ifname}: {ipaddr}/{cidr}</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#88C0D0\">󰈀</span>",
"on-click-right": "nm-connection-editor" "on-click-right": "nm-connection-editor"
}, },
"pulseaudio": { "pulseaudio": {
"escape": false, "format": "{icon} {volume}% {format_source}",
"format": "<span foreground=\"#D8DEE9\">{volume}%</span> {format_source} {icon}", "format-bluetooth": "{icon} {volume}% {format_source}",
"format-bluetooth": "<span foreground=\"#D8DEE9\">{volume}%</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\"></span> {format_source} {icon}", "format-bluetooth-muted": " {icon}  {format_source}",
"format-bluetooth-muted": "{format_source} <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#81A1C1\"></span> {icon} <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#D08770\"></span>", "format-muted": "{format_source}",
"format-muted": "{format_source} <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#D08770\"></span>", "format-source": " {volume}%",
"format-source": "<span foreground=\"#D8DEE9\">{volume}%</span> <span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "format-source-muted": "",
"format-source-muted": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#D08770\"></span>",
"format-icons": { "format-icons": {
"headphone": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "headphone": "",
"hands-free": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "hands-free": "",
"headset": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "headset": "",
"phone": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "phone": "",
"portable": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "portable": "",
"car": "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "car": "",
"default": ["<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>", "<span font_desc=\"SauceCodePro Nerd Font 15\" foreground=\"#B48EAD\"></span>"] "default": ["", "", ""]
}, },
"on-click": "pavucontrol" "on-click": "pavucontrol"
} }

View File

@@ -11,14 +11,7 @@ cleanup() {
} }
trap cleanup EXIT trap cleanup EXIT
trim_whitespace() { choose_subfolder() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s\n' "$value"
}
choose_destination_dir() {
if [[ ! -d "$base_dir" ]] || ! mountpoint -q /mnt/data; then if [[ ! -d "$base_dir" ]] || ! mountpoint -q /mnt/data; then
return 1 return 1
fi fi
@@ -28,7 +21,7 @@ choose_destination_dir() {
find "$base_dir" -mindepth 1 -type d -printf '%P\n' | sort find "$base_dir" -mindepth 1 -type d -printf '%P\n' | sort
} > "$selection_file" } > "$selection_file"
if selected=$(wofi --dmenu --prompt 'Save screenshot path' < "$selection_file"); then if selected=$(wofi --dmenu --prompt 'Save screenshot folder' < "$selection_file"); then
if [[ -z "$selected" || "$selected" == "/" ]]; then if [[ -z "$selected" || "$selected" == "/" ]]; then
printf '%s\n' "$base_dir" printf '%s\n' "$base_dir"
else else
@@ -40,47 +33,6 @@ choose_destination_dir() {
printf '%s\n' "$base_dir" printf '%s\n' "$base_dir"
} }
choose_filename() {
local default_name="screenshot"
local selected=""
if selected=$(printf '%s\n' "$default_name" | wofi --dmenu --prompt 'Save screenshot filename'); then
selected=$(trim_whitespace "$selected")
else
selected="$default_name"
fi
if [[ -z "$selected" ]]; then
selected="$default_name"
fi
selected="${selected%.png}"
if [[ -z "$selected" ]]; then
selected="$default_name"
fi
printf '%s\n' "$selected"
}
build_unique_path() {
local destination_dir="$1"
local file_stem="$2"
local candidate="$destination_dir/$file_stem.png"
local counter=1
if [[ ! -e "$candidate" ]]; then
printf '%s\n' "$candidate"
return
fi
while [[ -e "$destination_dir/$file_stem-$counter.png" ]]; do
counter=$((counter + 1))
done
printf '%s\n' "$destination_dir/$file_stem-$counter.png"
}
if ! region="$(slurp)"; then if ! region="$(slurp)"; then
exit 0 exit 0
fi fi
@@ -91,13 +43,11 @@ fi
wl-copy --type image/png < "$tmp_file" wl-copy --type image/png < "$tmp_file"
if destination_dir="$(choose_destination_dir)"; then if destination_dir="$(choose_subfolder)"; then
mkdir -p "$destination_dir" mkdir -p "$destination_dir"
file_stem="$(choose_filename)" file_name="screenshot-$(date +%Y%m%d-%H%M%S).png"
destination_path="$(build_unique_path "$destination_dir" "$file_stem")" cp "$tmp_file" "$destination_dir/$file_name"
cp "$tmp_file" "$destination_path" notify-send 'Screenshot saved' "$destination_dir/$file_name\nCopied to clipboard"
notify-send 'Screenshot saved' "$destination_path
Copied to clipboard"
else else
notify-send 'Screenshot copied' 'NAS picture share is not available; image copied to clipboard only' notify-send 'Screenshot copied' 'NAS picture share is not available; image copied to clipboard only'
fi fi

View File

@@ -7,37 +7,10 @@ LABEL="$2"
ICON_MOUNT="󰋊" ICON_MOUNT="󰋊"
ICON_DOWN="" ICON_DOWN=""
json_escape() {
local s="$1"
s=${s//\\/\\\\}
s=${s//\"/\\\"}
s=${s//$'\n'/\\n}
printf '%s' "$s"
}
markup_escape() {
local s="$1"
s=${s//&/&amp;}
s=${s//</&lt;}
s=${s//>/&gt;}
printf '%s' "$s"
}
icon_markup() {
local icon="$1"
local color="$2"
printf '<span font_desc="SauceCodePro Nerd Font 15" foreground="%s">%s</span>' "$color" "$icon"
}
if mountpoint -q "$MOUNT"; then if mountpoint -q "$MOUNT"; then
read -r used avail pcent <<< "$(df -h --output=used,avail,pcent "$MOUNT" | tail -1)" read -r used avail pcent <<< "$(df -h --output=used,avail,pcent "$MOUNT" | tail -1)"
text="<span foreground=\"#D8DEE9\">$(markup_escape "$LABEL $used/$avail ($pcent)")</span> $(icon_markup "$ICON_MOUNT" "#A3BE8C")" printf '{"text": "%s %s %s/%s (%s)", "tooltip": "%s mounted — used: %s, free: %s (%s)", "class": "mounted"}\n' \
tooltip="$(markup_escape "$MOUNT mounted - used: $used, free: $avail ($pcent)")" "$ICON_MOUNT" "$LABEL" "$used" "$avail" "$pcent" "$MOUNT" "$used" "$avail" "$pcent"
printf '{"text":"%s","tooltip":"%s","class":"mounted"}\n' \
"$(json_escape "$text")" "$(json_escape "$tooltip")"
else else
text="<span foreground=\"#EBCB8B\">$(markup_escape "$LABEL N/A")</span> $(icon_markup "$ICON_DOWN" "#BF616A")" printf '{"text": "%s %s N/A", "tooltip": "%s is NOT mounted", "class": "unmounted"}\n' "$ICON_DOWN" "$LABEL" "$MOUNT"
tooltip="$(markup_escape "$MOUNT is NOT mounted")"
printf '{"text":"%s","tooltip":"%s","class":"unmounted"}\n' \
"$(json_escape "$text")" "$(json_escape "$tooltip")"
fi fi

View File

@@ -1,218 +0,0 @@
#!/usr/bin/env bash
set -u
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/waybar-spotify"
ART_URL_FILE="$CACHE_DIR/art_url"
ART_FILE="$CACHE_DIR/cover.jpg"
PLAYER=""
mkdir -p "$CACHE_DIR"
json_escape() {
local s="$1"
s=${s//\\/\\\\}
s=${s//\"/\\\"}
s=${s//$'\n'/\\n}
printf '%s' "$s"
}
markup_escape() {
local s="$1"
s=${s//&/&amp;}
s=${s//</&lt;}
s=${s//>/&gt;}
printf '%s' "$s"
}
icon_markup() {
local icon="$1"
local color="$2"
printf '<span font_desc="SauceCodePro Nerd Font 15" foreground="%s">%s</span>' "$color" "$icon"
}
truncate_text() {
local text="$1"
local max_len="$2"
if (( ${#text} <= max_len )); then
printf '%s' "$text"
return
fi
printf '%s...' "${text:0:max_len-3}"
}
pick_player() {
local candidates
local p
local c
mapfile -t candidates < <(playerctl -l 2>/dev/null)
if (( ${#candidates[@]} == 0 )); then
return 1
fi
for c in spotify spotifyd ncspot nspot; do
for p in "${candidates[@]}"; do
if [[ "$p" == "$c" || "$p" == "$c."* ]]; then
PLAYER="$p"
return 0
fi
done
done
PLAYER="${candidates[0]}"
return 0
}
download_cover_if_needed() {
local art_url="$1"
if [[ -z "$art_url" ]]; then
return
fi
local old_url=""
if [[ -f "$ART_URL_FILE" ]]; then
old_url=$(cat "$ART_URL_FILE" 2>/dev/null)
fi
if [[ "$art_url" == "$old_url" ]]; then
return
fi
printf '%s' "$art_url" > "$ART_URL_FILE"
if [[ "$art_url" == file://* ]]; then
local local_path="${art_url#file://}"
if [[ -f "$local_path" ]]; then
cp -f "$local_path" "$ART_FILE" 2>/dev/null || true
fi
return
fi
if command -v curl >/dev/null 2>&1; then
curl -LfsS --max-time 4 "$art_url" -o "$ART_FILE" 2>/dev/null || true
fi
}
open_cover() {
if [[ -f "$ART_FILE" ]]; then
xdg-open "$ART_FILE" >/dev/null 2>&1 &
fi
}
control_player() {
local action="$1"
case "$action" in
--toggle)
playerctl -p "$PLAYER" play-pause >/dev/null 2>&1 || true
;;
--next)
playerctl -p "$PLAYER" next >/dev/null 2>&1 || true
;;
--prev)
playerctl -p "$PLAYER" previous >/dev/null 2>&1 || true
;;
--stop)
playerctl -p "$PLAYER" stop >/dev/null 2>&1 || true
;;
--open-art)
open_cover
;;
esac
}
if [[ $# -gt 0 ]]; then
control_player "$1"
exit 0
fi
if ! command -v playerctl >/dev/null 2>&1; then
printf '{"text":"%s","tooltip":"playerctl missing: install playerctl for media controls","class":"idle","alt":"idle"}\n' "$(json_escape "$(icon_markup "" "#A3BE8C")")"
exit 0
fi
if ! pick_player; then
printf '{"text":"%s","tooltip":"No active player","class":"idle","alt":"idle"}\n' "$(json_escape "$(icon_markup "" "#A3BE8C")")"
exit 0
fi
status=$(playerctl -p "$PLAYER" status 2>/dev/null || true)
if [[ -z "$status" ]]; then
printf '{"text":"%s","tooltip":"No active player status","class":"idle","alt":"idle"}\n' "$(json_escape "$(icon_markup "" "#A3BE8C")")"
exit 0
fi
title=$(playerctl -p "$PLAYER" metadata xesam:title 2>/dev/null || true)
artist=$(playerctl -p "$PLAYER" metadata xesam:artist 2>/dev/null || true)
album=$(playerctl -p "$PLAYER" metadata xesam:album 2>/dev/null || true)
art_url=$(playerctl -p "$PLAYER" metadata mpris:artUrl 2>/dev/null || true)
state_class=$(printf '%s' "$status" | tr '[:upper:]' '[:lower:]')
if [[ "$state_class" == "stopped" ]]; then
text_markup="<span foreground=\"#D8DEE9\">Stopped</span> $(icon_markup "" "#D08770") $(icon_markup "" "#A3BE8C")"
printf '{"text":"%s","class":"stopped","alt":"stopped"}\n' "$(json_escape "$text_markup")"
exit 0
fi
if [[ -z "$artist" && -z "$title" ]]; then
printf '{"text":"%s","class":"idle","alt":"idle"}\n' "$(json_escape "$(icon_markup "" "#A3BE8C")")"
exit 0
fi
if [[ -z "$title" ]]; then
title="Unknown title"
fi
if [[ -z "$artist" ]]; then
artist="Unknown artist"
fi
if [[ -z "$album" ]]; then
album="Unknown album"
fi
download_cover_if_needed "$art_url"
display_track="$(truncate_text "$artist - $title" 52)"
state_icon=""
if [[ "$state_class" == "paused" ]]; then
state_icon=""
fi
app_icon=""
if [[ "$PLAYER" == spotify* || "$PLAYER" == spotifyd* || "$PLAYER" == *ncspot* || "$PLAYER" == *nspot* ]]; then
app_icon=""
fi
track_color="#ECEFF4"
state_color="#88C0D0"
app_color="#A3BE8C"
if [[ "$state_class" == "paused" ]]; then
track_color="#E5E9F0"
state_color="#EBCB8B"
fi
cover_line="Cover art: unavailable"
if [[ -f "$ART_FILE" ]]; then
cover_line="Cover art: cached (right-click opens image)"
fi
tooltip=$(cat <<EOF
$artist
$title
$album
$status
Player: $PLAYER
$cover_line
Left click: play/pause | Scroll: next/prev
EOF
)
text_markup="<span foreground=\"$track_color\">$(markup_escape "$display_track")</span> $(icon_markup "$state_icon" "$state_color") $(icon_markup "$app_icon" "$app_color")"
printf '{"text":"%s","tooltip":"%s","class":"%s","alt":"%s"}\n' \
"$(json_escape "$text_markup")" \
"$(json_escape "$tooltip")" \
"$(json_escape "$state_class")" \
"$(json_escape "$state_class")"

View File

@@ -1,88 +0,0 @@
#!/usr/bin/env bash
set -u
LOCATION="Norrkoping"
URL="https://wttr.in/${LOCATION}?format=%t|%C"
json_escape() {
local s="$1"
s=${s//\\/\\\\}
s=${s//\"/\\\"}
s=${s//$'\n'/\\n}
printf '%s' "$s"
}
markup_escape() {
local s="$1"
s=${s//&/&amp;}
s=${s//</&lt;}
s=${s//>/&gt;}
printf '%s' "$s"
}
icon_markup() {
local icon="$1"
local color="$2"
printf '<span font_desc="SauceCodePro Nerd Font 15" foreground="%s">%s</span>' "$color" "$icon"
}
icon_for_condition() {
local c
c=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')
case "$c" in
*thunder*|*storm*)
printf '󰖓'
;;
*snow*|*sleet*|*blizzard*|*ice*)
printf '󰼶'
;;
*rain*|*drizzle*|*shower*)
printf '󰖗'
;;
*fog*|*mist*|*haze*|*smoke*)
printf '󰖑'
;;
*partly*)
printf '󰖕'
;;
*clear*|*sunny*)
printf '󰖙'
;;
*cloud*|*overcast*)
printf '󰖐'
;;
*)
printf '󰖐'
;;
esac
}
if ! command -v curl >/dev/null 2>&1; then
text="<span foreground=\"#EBCB8B\">--°C Unavailable</span> $(icon_markup "󰖐" "#D08770")"
printf '{"text":"%s","tooltip":"curl is required for weather","class":"weather-unavailable"}\n' "$(json_escape "$text")"
exit 0
fi
raw=$(curl -fsS --max-time 6 "$URL" 2>/dev/null || true)
if [[ -z "$raw" || "$raw" != *"|"* ]]; then
text="<span foreground=\"#EBCB8B\">--°C Unavailable</span> $(icon_markup "󰖐" "#D08770")"
printf '{"text":"%s","tooltip":"Weather unavailable for Norrkoping","class":"weather-unavailable"}\n' "$(json_escape "$text")"
exit 0
fi
temp=${raw%%|*}
condition=${raw#*|}
icon=$(icon_for_condition "$condition")
updated=$(date '+%H:%M')
text="<span foreground=\"#D8DEE9\">$(markup_escape "$temp $condition")</span> $(icon_markup "$icon" "#88C0D0")"
tooltip=$(cat <<EOF
Norrkoping, Sweden
$temp - $condition
Updated: $updated
EOF
)
printf '{"text":"%s","tooltip":"%s","class":"weather"}\n' \
"$(json_escape "$text")" \
"$(json_escape "$tooltip")"

View File

@@ -1,15 +1,15 @@
* { * {
border: none; border: none;
border-radius: 10px; border-radius: 8px;
font-family: "Ubuntu", "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "Symbols Nerd Font Mono", "Symbols Nerd Font", "Font Awesome 7 Free", sans-serif; font-family: "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "Symbols Nerd Font Mono", "Symbols Nerd Font", "Font Awesome 7 Free", sans-serif;
font-size: 14px; font-size: 14px;
min-height: 0; min-height: 0;
} }
window#waybar { window#waybar {
background: #2e3440; background: alpha(#2e3440, 0.92);
color: #eceff4; color: #eceff4;
border-bottom: 2px solid #5e81ac; border-bottom: 2px solid alpha(#5e81ac, 0.55);
} }
tooltip { tooltip {
@@ -19,10 +19,8 @@ tooltip {
} }
#workspaces { #workspaces {
background: #3b4252; background: alpha(#3b4252, 0.88);
padding: 2px 6px; padding: 2px 6px;
margin: 4px 3px;
border: 1px solid #4c566a;
} }
#workspaces button { #workspaces button {
@@ -32,8 +30,12 @@ tooltip {
margin: 0 2px; margin: 0 2px;
} }
#workspaces button label {
font-weight: 600;
}
#workspaces button:hover { #workspaces button:hover {
background: #434c5e; background: alpha(#4c566a, 0.55);
} }
#workspaces button.active { #workspaces button.active {
@@ -41,14 +43,17 @@ tooltip {
background: #88c0d0; background: #88c0d0;
} }
#workspaces button.visible {
color: #eceff4;
background: alpha(#5e81ac, 0.28);
}
#workspaces button.urgent { #workspaces button.urgent {
color: #eceff4; color: #eceff4;
background: #bf616a; background: #bf616a;
} }
#window, #window,
#custom-spotify,
#custom-weather,
#clock, #clock,
#custom-screenshot, #custom-screenshot,
#idle_inhibitor, #idle_inhibitor,
@@ -59,94 +64,40 @@ tooltip {
#tray, #tray,
#custom-mount-data, #custom-mount-data,
#custom-mount-usb1 { #custom-mount-usb1 {
background: #3b4252; background: alpha(#3b4252, 0.88);
color: #e5e9f0; color: #eceff4;
padding: 0 10px; padding: 0 10px;
margin: 4px 3px; margin: 4px 3px;
border: 1px solid #4c566a;
} }
#clock { #clock {
background: #34425a; background: alpha(#5e81ac, 0.35);
color: #eceff4;
border-color: #81a1c1;
}
#custom-spotify {
background: #3a4a3f;
color: #eceff4;
font-weight: 600;
border-color: #a3be8c;
}
#custom-spotify.paused {
background: #5b4f3b;
color: #eceff4;
border-color: #d08770;
}
#custom-spotify.stopped,
#custom-spotify.idle {
background: #4c566a;
color: #d8dee9;
border-color: #616e88;
}
#custom-weather {
background: #34504f;
color: #eceff4;
font-weight: 600;
border-color: #88c0d0;
}
#custom-screenshot {
background: #34425a;
color: #eceff4;
font-weight: 700;
border-color: #88c0d0;
} }
#cpu, #cpu,
#memory { #memory {
background: #384b5e; background: alpha(#81a1c1, 0.25);
color: #eceff4;
border-color: #5e81ac;
} }
#network { #network {
background: #2f4f5a; background: alpha(#88c0d0, 0.22);
color: #eceff4;
border-color: #81a1c1;
} }
#network.disconnected { #network.disconnected {
color: #eceff4; color: #bf616a;
background: #5a3942; background: alpha(#bf616a, 0.18);
border-color: #d08770;
}
#pulseaudio {
background: #4b4256;
color: #eceff4;
border-color: #b48ead;
} }
#pulseaudio.muted { #pulseaudio.muted {
color: #eceff4; color: #ebcb8b;
background: #5a433f;
border-color: #d08770;
} }
#idle_inhibitor.activated { #idle_inhibitor.activated {
color: #eceff4; color: #a3be8c;
background: #3a4a3f;
border-color: #a3be8c;
} }
#idle_inhibitor.deactivated { #idle_inhibitor.deactivated {
color: #eceff4; color: #bf616a;
background: #34425a;
border-color: #81a1c1;
} }
#custom-mount-data, #custom-mount-data,
@@ -156,14 +107,12 @@ tooltip {
#custom-mount-data.mounted, #custom-mount-data.mounted,
#custom-mount-usb1.mounted { #custom-mount-usb1.mounted {
color: #eceff4; color: #a3be8c;
background: #3a4a3f; background: alpha(#a3be8c, 0.12);
border-color: #a3be8c;
} }
#custom-mount-data.unmounted, #custom-mount-data.unmounted,
#custom-mount-usb1.unmounted { #custom-mount-usb1.unmounted {
color: #eceff4; color: #bf616a;
background: #5a3942; background: alpha(#bf616a, 0.16);
border-color: #d08770;
} }

92
install.sh Normal file → Executable file
View File

@@ -1,96 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
# Arch Linux bootstrap for this dotfiles setup.
# Installs the packages required by configs in this repository.
if ! command -v pacman >/dev/null 2>&1; then
echo "This installer currently supports Arch Linux (pacman) only."
exit 1
fi
PACKAGES=(
# Core desktop/session
hyprland
hyprpaper
waybar
xdg-desktop-portal
xdg-desktop-portal-hyprland
# Terminal + launcher + file manager
alacritty
wofi
thunar
# Audio/network/system controls used by config
pipewire
wireplumber
pavucontrol
playerctl
brightnessctl
networkmanager
network-manager-applet
# Wayland screenshot stack + notifications
grim
slurp
swappy
wl-clipboard
libnotify
# Utilities used by scripts/config
curl
btop
tmux
fzf
xclip
kdeconnect
)
REQUIRED_COMMANDS=(
hyprland
hyprpaper
waybar
alacritty
wofi
thunar
wpctl
playerctl
brightnessctl
grim
slurp
swappy
wl-copy
notify-send
curl
btop
)
echo "Installing packages for dotfiles setup..."
sudo pacman -S --needed --noconfirm "${PACKAGES[@]}"
missing=()
for cmd in "${REQUIRED_COMMANDS[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
missing+=("$cmd")
fi
done
if (( ${#missing[@]} > 0 )); then
echo
echo "Install completed, but these commands are still missing:"
printf ' - %s\n' "${missing[@]}"
echo "Check package names/repos on your system and install them manually."
exit 2
fi
echo
echo "Install complete."
echo "Next steps:"
echo "1) Symlink/copy dotfiles into ~/.config and ~/.tmux.conf"
echo "2) Enable/start NetworkManager if needed: sudo systemctl enable --now NetworkManager"
echo "3) Start Hyprland"
#!/usr/bin/env bash
# install.sh — bootstrap dotfiles on a fresh Arch/CachyOS install # install.sh — bootstrap dotfiles on a fresh Arch/CachyOS install
# Usage: ./install.sh [--dry-run] # Usage: ./install.sh [--dry-run]
set -euo pipefail set -euo pipefail