add quick actions tab

This commit is contained in:
soraefir
2026-06-13 14:04:33 +02:00
parent 43a074f355
commit 6117dca845
10 changed files with 198 additions and 37 deletions

View File

@@ -1,29 +1,20 @@
calendar { calendar {
padding: 5pt; padding: 2pt 1pt;
font-size: 10pt;
:selected { header {
@include color-accent; padding: 2pt 0;
}
.header {
@include color-body; @include color-body;
} }
.highlight { :selected { @include color-accent; }
@include color-accent; .highlight { @include color-accent; font-weight: bold; }
font-weight: bold; :indeterminate { color: $base03; }
}
label {
font-size: 20pt;
@include color-accent;
}
:indeterminate {
color: $base03;
}
} }
.cal-box .sys-section-header { margin-bottom: 4pt; }
.hour, .month { .hour, .month {
font-weight: bolder; font-weight: bolder;
@@ -46,7 +37,36 @@ calendar {
// Clock window accents // Clock window accents
.weather-accent { background-color: $base0A; } .weather-accent { background-color: $base0A; }
.cal-accent { background-color: $base0B; }
.bri-accent { background-color: $base09; }
.vol-accent { background-color: $base0D; } .vol-accent { background-color: $base0D; }
.quick-accent { background-color: $base0E; }
// Quick actions
.quick-grid { margin-top: 2pt; }
.quick-btn {
@include background-base2;
@include border-radius;
padding: 8pt 4pt;
margin: 4px;
min-width: 0;
min-height: 0;
border: none;
&:hover {
@include background-active;
.quick-icon, .quick-label {color: $base01;}
}
}
.quick-btn-active {
.quick-icon { @include color-accent; }
.quick-label { @include color-accent; }
}
.quick-icon { font-size: 1.5em; @include color-body; }
.quick-label { font-size: 0.68em; margin-top: 3pt; @include color-body; }
// Weather section // Weather section
.weather-main { margin-bottom: 8pt; } .weather-main { margin-bottom: 8pt; }
@@ -57,10 +77,18 @@ calendar {
// Volume section // Volume section
.ctrl-row { margin-bottom: 4pt; } .ctrl-row { margin-bottom: 4pt; }
.ctrl-icon { font-size: 1.1em; min-width: 22pt; @include color-body; } .ctrl-icon { font-size: 1.1em; min-width: 22pt; @include border-radius; @include color-body; }
.ctrl-muted { @include color-inactive; } .ctrl-icon:hover { @include background-active; }
.ctrl-muted { @include color-inactive; }
.ctrl-value { font-size: 0.72em; min-width: 28pt; @include color-active; } .ctrl-value { font-size: 0.72em; min-width: 28pt; @include color-active; }
scale.ctrl-slider.ctrl-slider-muted {
trough {
highlight { background-color: $base03; }
slider { background-color: $base03; }
}
}
scale.ctrl-slider { scale.ctrl-slider {
padding: 2pt 4pt; padding: 2pt 4pt;
trough { trough {

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
BACKLIGHT="/sys/class/backlight"
DEV=$(ls "$BACKLIGHT" 2>/dev/null | head -n1)
gen_output() {
if [ -z "$DEV" ]; then
echo '{"percent":0,"available":false}'
return
fi
max=$(cat "$BACKLIGHT/$DEV/max_brightness")
cur=$(cat "$BACKLIGHT/$DEV/actual_brightness" 2>/dev/null || cat "$BACKLIGHT/$DEV/brightness")
percent=$(awk -v c="$cur" -v m="$max" 'BEGIN{print int(c/m*100+0.5)}')
printf '{"percent":%d,"available":true}\n' "$percent"
}
case "$1" in
set)
[ -z "$DEV" ] && exit 0
brightnessctl -d "$DEV" set "${2}%" -q 2>/dev/null
;;
*)
gen_output
[ -z "$DEV" ] && exit 0
# Poll for changes every 2s (sysfs files don't support inotify reliably)
while true; do sleep 2; gen_output; done
;;
esac

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
case "$1" in
status)
pgrep -x wlsunset >/dev/null 2>&1 && echo true || echo false
;;
*)
if pgrep -x wlsunset >/dev/null 2>&1; then
pkill -x wlsunset && echo false
else
wlsunset -T 4500 -t 3200 & echo true
fi
;;
esac

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
current=$(eww state 2>/dev/null | grep '^power-save:' | awk '{print $2}')
if [ "$current" = "true" ]; then
powerprofilesctl set balanced 2>/dev/null || true
echo false
else
powerprofilesctl set power-saver 2>/dev/null || true
echo true
fi

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
DIR="$HOME/Pictures/Screenshots"
mkdir -p "$DIR"
FILE="$DIR/$(date +%Y-%m-%d_%H-%M-%S).png"
grim -g "$(slurp)" "$FILE" && wl-copy < "$FILE"

View File

@@ -12,13 +12,14 @@ gen_output() {
lvl=$(awk -v n="$percent" 'BEGIN{print int(n/34)}') lvl=$(awk -v n="$percent" 'BEGIN{print int(n/34)}')
sink_muted=$(ismuted "SINK") sink_muted=$(ismuted "SINK")
source_muted=$(ismuted "SOURCE") source_muted=$(ismuted "SOURCE")
sink=$(wpctl inspect @DEFAULT_AUDIO_SINK@ 2>/dev/null | grep -m1 'node\.nick' | sed 's/.*= "\(.*\)"/\1/')
[ "$sink_muted" = 0 ] && icon="󰝟" || icon="${volicons[$lvl]}" [ "$sink_muted" = 0 ] && icon="󰝟" || icon="${volicons[$lvl]}"
[ "$source_muted" = 0 ] && mic_icon="󰍭" || mic_icon="󰍬" [ "$source_muted" = 0 ] && mic_icon="󰍭" || mic_icon="󰍬"
printf '{"icon":"%s","percent":%s,"sink_muted":%s,"mic_icon":"%s","microphone":%s,"source_muted":%s}\n' \ printf '{"icon":"%s","percent":%s,"sink_muted":%s,"mic_icon":"%s","microphone":%s,"source_muted":%s,"sink":"%s"}\n' \
"$icon" "$percent" "$([ "$sink_muted" = 0 ] && echo true || echo false)" \ "$icon" "$percent" "$([ "$sink_muted" = 0 ] && echo true || echo false)" \
"$mic_icon" "$(vol SOURCE)" "$([ "$source_muted" = 0 ] && echo true || echo false)" "$mic_icon" "$(vol SOURCE)" "$([ "$source_muted" = 0 ] && echo true || echo false)" "$sink"
} }
case "$1" in case "$1" in
@@ -26,7 +27,18 @@ case "$1" in
setvol) setvol "$2" "$3" ;; setvol) setvol "$2" "$3" ;;
*) *)
gen_output gen_output
pw-cli -m 2>/dev/null | rg --line-buffered "PipeWire:Interface:Client" | while read -r _; do
tmp=$(mktemp -d)
pipe="$tmp/vol-events"
mkfifo "$pipe"
trap 'rm -rf "$tmp"; kill 0 2>/dev/null' EXIT INT TERM
# 1s polling fallback
(while true; do sleep 1; echo poll; done) > "$pipe" &
# PipeWire property-change events (fires on mute/volume change)
(pw-cli -m 2>/dev/null | grep --line-buffered "changed") > "$pipe" &
while IFS= read -r _ < "$pipe"; do
gen_output gen_output
done done
;; ;;

View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bash
nohup bash "$HOME/.config/script/wallpaper.sh" >/dev/null 2>&1 &

View File

@@ -4,9 +4,13 @@
"scripts/weather") "scripts/weather")
(deflisten volume (deflisten volume
:initial '{"icon":"󰕾","percent":50,"sink_muted":false,"mic_icon":"󰍬","microphone":50,"source_muted":false}' :initial '{"icon":"󰕾","percent":50,"sink_muted":false,"mic_icon":"󰍬","microphone":50,"source_muted":false,"sink":""}'
"scripts/volume") "scripts/volume")
(deflisten brightness
:initial '{"percent":0,"available":false}'
"scripts/brightness")
; --- Weather --- ; --- Weather ---
(defwidget weather-section [] (defwidget weather-section []
@@ -14,9 +18,9 @@
(section-header (section-header
:title {weather.city != "" ? "Weather · ${weather.city}" : "Weather"} :title {weather.city != "" ? "Weather · ${weather.city}" : "Weather"}
:accent "weather-accent") :accent "weather-accent")
(box :orientation "h" :space-evenly false :valign "center" :class "weather-main" (box :orientation "h" :space-evenly false :halign "center" :class "weather-main"
(label :class "weather-icon" :text {weather.icon}) (label :class "weather-icon" :valign "center" :text {weather.icon})
(box :orientation "v" :space-evenly false (box :orientation "v" :space-evenly false :valign "center"
(label :class "weather-temp" :text "${weather.temp}°C") (label :class "weather-temp" :text "${weather.temp}°C")
(label :class "weather-desc" :text {weather.desc}))) (label :class "weather-desc" :text {weather.desc})))
(box :orientation "h" :space-evenly true :class "weather-stats" (box :orientation "h" :space-evenly true :class "weather-stats"
@@ -40,13 +44,16 @@
(label :text icon)) (label :text icon))
(scale (scale
:min 0 :max 100 :value value :min 0 :max 100 :value value
:hexpand true :class "ctrl-slider" :hexpand true
:onchange onchange) :class "ctrl-slider ${muted ? 'ctrl-slider-muted' : ''}"
(label :class "ctrl-value" :halign "end" :text "${value}%"))) :onchange {muted ? "true" : onchange})
(label :class "ctrl-value ${muted ? 'ctrl-muted' : ''}" :halign "end" :text "${value}%")))
(defwidget volume-section [] (defwidget volume-section []
(box :orientation "v" :space-evenly false :class "sys-section" (box :orientation "v" :space-evenly false :class "sys-section"
(section-header :title "Volume" :accent "vol-accent") (section-header
:title {volume.sink != "" ? "Volume · ${volume.sink}" : "Volume"}
:accent "vol-accent")
(vol-row (vol-row
:icon {volume.icon} :icon {volume.icon}
:value {volume.percent} :value {volume.percent}
@@ -60,13 +67,68 @@
:onchange "scripts/volume setvol SOURCE {}" :onchange "scripts/volume setvol SOURCE {}"
:onclick "scripts/volume mute SOURCE"))) :onclick "scripts/volume mute SOURCE")))
; --- Quick Actions ---
(defvar power-save false)
(defvar night-light false)
(defwidget quick-btn [icon label onclick active]
(button :class "quick-btn ${active ? 'quick-btn-active' : ''}"
:onclick onclick
(box :orientation "v" :space-evenly false :halign "center" :valign "center"
(label :class "quick-icon" :text icon)
(label :class "quick-label" :text label))))
(defwidget quick-section []
(box :orientation "v" :space-evenly false :class "sys-section"
(section-header :title "Quick Actions" :accent "quick-accent")
(box :orientation "h" :homogeneous true :class "quick-grid"
(quick-btn
:icon "󰸉" :label "Wallpaper"
:onclick "scripts/wallpaper"
:active false)
(quick-btn
:icon "󱐋" :label "Power Save"
:onclick "eww update power-save=$(scripts/power-save)"
:active {power-save})
(quick-btn
:icon "󰌵" :label "Night Light"
:onclick "eww update night-light=$(scripts/nightlight)"
:active {night-light})
(quick-btn
:icon "󰹑" :label "Screenshot"
:onclick "scripts/screenshot"
:active false))))
; --- Brightness ---
(defwidget brightness-section []
(box :orientation "v" :space-evenly false :class "sys-section"
:visible {brightness.available}
(section-header :title "Brightness" :accent "bri-accent")
(box :orientation "h" :space-evenly false :valign "center" :class "ctrl-row"
(label :class "ctrl-icon" :text "󰃠")
(scale
:min 1 :max 100 :value {brightness.percent}
:hexpand true
:class "ctrl-slider"
:onchange "scripts/brightness set {}")
(label :class "ctrl-value" :halign "end" :text "${brightness.percent}%"))))
; --- Root --- ; --- Root ---
(defwidget clock-win [] (defwidget clock-win []
(box :class "sys-win" :orientation "v" :space-evenly false (box :class "sys-win" :orientation "v" :space-evenly false
(volume-section)
(brightness-section)
(box :class "section-sep")
(quick-section)
(box :class "section-sep")
(weather-section) (weather-section)
(box :class "section-sep") (box :class "section-sep")
(calendar) (box :orientation "v" :space-evenly false :class "sys-section cal-box"
(box :class "section-sep") (section-header :title "Calendar" :accent "cal-accent")
(volume-section))) (calendar :show-week-numbers false))
))

View File

@@ -1,4 +1,5 @@
{ ... }: { { lib, ... }: {
services.fwupd.enable = true; services.fwupd.enable = true;
hardware.enableAllFirmware = false; hardware.enableAllFirmware = false;
services.power-profiles-daemon.enable = lib.mkDefault true;
} }

View File

@@ -1,5 +1,6 @@
{ lib, config, pkgs, ... }: { { lib, config, pkgs, ... }: {
config = lib.mkIf (config.syscfg.make.power) { config = lib.mkIf (config.syscfg.make.power) {
services.power-profiles-daemon.enable = false; # conflicts with TLP
services.tlp = { services.tlp = {
enable = true; enable = true;
settings = { settings = {