{
pkgs,
lib,
config,
...
}:
let
timerScript = pkgs.writeShellScriptBin "timer.sh" ''
#!${pkgs.bash}/bin/bash
CUR_TIME=$(${pkgs.coreutils}/bin/date +%s)
STATUS=$(${pkgs.coreutils}/bin/cat /var/tmp/timer_status || echo "READY")
if [ "$STATUS" = "READY" ]; then
echo ""
elif [ "$STATUS" = "FINISHED" ]; then
${pkgs.pulseaudio}/bin/paplay "${config.home.homeDirectory}/.config/eww/timer.wav" &
echo "READY" > /var/tmp/timer_status
echo ""
elif [ "$STATUS" -gt "$CUR_TIME" ]; then
DIFF=$(( STATUS - CUR_TIME ))
echo $(${pkgs.coreutils}/bin/date -d "@$DIFF" +%M:%S)
else
echo "FINISHED" > /var/tmp/timer_status
echo ""
fi
'';
calendarScript = pkgs.writeShellScriptBin "calendar.sh" ''
#!${pkgs.bash}/bin/bash
${pkgs.coreutils}/bin/date +'%Y %B\n%d %A'
'';
in
{
programs.eww = {
enable = true;
package = pkgs.eww;
};
# Dependencies
home.packages = with pkgs; [
hyprland
brightnessctl
lxqt.pavucontrol-qt
wttrbar
bluetui
wlogout
walker
lm_sensors
pulseaudio
socat
jq
procps
gawk
gnugrep
gnused
systemd
iproute2
dbus
];
home.file.".config/eww/eww.yuck".text = ''
;; Variables and Polls
(defpoll time :interval "1s" "${pkgs.coreutils}/bin/date +'%A, %Y-%m-%d %H:%M:%S'")
(defpoll weather :interval "3600s" "${pkgs.wttrbar}/bin/wttrbar --main-indicator=FeelsLikeC --date-format=%d.%m.%Y --location=Helsinki | ${pkgs.jq}/bin/jq .FeelsLikeC")
(defpoll cpu-usage :interval "2s" "${pkgs.procps}/bin/top -bn1 | ${pkgs.gnugrep}/bin/grep '^%Cpu' | ${pkgs.gawk}/bin/awk '{print 100 - \$8}'")
(defpoll memory :interval "2s" "${pkgs.procps}/bin/free -h | ${pkgs.gnugrep}/bin/grep '^Mem:' | ${pkgs.gawk}/bin/awk '{print \$3 \"/\" \$2}'")
(defpoll load :interval "2s" "${pkgs.coreutils}/bin/cat /proc/loadavg | ${pkgs.gawk}/bin/awk '{print \$1}'")
(defpoll temperature :interval "5s" "${pkgs.lm_sensors}/bin/sensors | ${pkgs.gnugrep}/bin/grep 'Tctl:' | ${pkgs.gawk}/bin/awk '{print \$2}' | ${pkgs.gnused}/bin/sed 's/+//'")
(defpoll volume :interval "2s" "${pkgs.pulseaudio}/bin/pactl get-sink-volume @DEFAULT_SINK@ | ${pkgs.gawk}/bin/awk '{print \$5}' | ${pkgs.gnused}/bin/sed 's/%//'")
(defpoll mute :interval "2s" "${pkgs.pulseaudio}/bin/pactl get-sink-mute @DEFAULT_SINK@ | ${pkgs.gnugrep}/bin/grep -q 'Mute: yes' && echo 'true' || echo 'false'")
(defpoll backlight :interval "2s" "${pkgs.brightnessctl}/bin/brightnessctl g")
(defpoll battery :interval "10s" "${pkgs.coreutils}/bin/cat /sys/class/power_supply/BAT0/capacity 2>/dev/null || echo '0'")
(defpoll battery-status :interval "10s" "${pkgs.coreutils}/bin/cat /sys/class/power_supply/BAT0/status 2>/dev/null || echo 'Unknown'")
(defpoll failed-units :interval "30s" "${pkgs.systemd}/bin/systemctl --failed --no-legend | ${pkgs.coreutils}/bin/wc -l")
(defpoll processes :interval "10s" "${pkgs.procps}/bin/ps -e --no-headers | ${pkgs.coreutils}/bin/wc -l")
(defpoll sockets :interval "10s" "${pkgs.iproute2}/bin/ss -tuln | ${pkgs.coreutils}/bin/tail -n +2 | ${pkgs.coreutils}/bin/wc -l")
(defpoll keyboard-layout :interval "5s" "${pkgs.hyprland}/bin/hyprctl getoption general:kb_layout -j | ${pkgs.jq}/bin/jq -r .str")
;; Hyprland workspace tracking
(defpoll workspaces :interval "1s" "${pkgs.hyprland}/bin/hyprctl workspaces -j")
(defpoll active-workspace :interval "1s" "${pkgs.hyprland}/bin/hyprctl activeworkspace -j | ${pkgs.jq}/bin/jq -r .id")
(defpoll current-window :interval "1s" "${pkgs.hyprland}/bin/hyprctl activewindow -j | ${pkgs.jq}/bin/jq -r .title")
;; Widgets
(defwidget bar []
(box :orientation "h" :class "bar" :space-evenly false
(box :class "left" :halign "start" :spacing 8
;; Start menu with eventbox for hover
(eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &"
(button :class "startmenu" :onclick "${pkgs.walker}/bin/walker" "⚡"))
(box :class "workspaces" :spacing 4
(for ws in workspaces
(button :onclick "${pkgs.hyprland}/bin/hyprctl dispatch workspace ''${ws.id}"
:class { ws.id == active-workspace ? "active" : "" }
"''${ws.name}")))
(label :class "clock" :text time)
(label :class "timer" :text (timer-widget)))
(box :class "center" :halign "center"
(label :text {current-window ? current-window : "No Windows"}))
(box :class "right" :halign "end" :spacing 8
(label :class "cpu" :text " {cpu-usage}%")
(label :class "memory" :text " {memory}")
(label :class "temperature" :text " {temperature}")
;; Pulseaudio with eventbox for hover
(eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.lxqt.pavucontrol-qt}/bin/pavucontrol-qt"
(label :class "pulseaudio" :text {mute ? "" : ""} " {volume}%"))
(label :class "battery" :text {battery-status == "Charging" ? "" : ""} " {battery}%")
;; Bluetooth with eventbox for hover
(eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.bluetui}/bin/bluetui"
(button :class "bluetooth" ""))
;; Exit with eventbox for hover
(eventbox :onhover "${pkgs.pulseaudio}/bin/paplay ${config.home.homeDirectory}/.config/eww/beep.ogg &" :onclick "${pkgs.wlogout}/bin/wlogout"
(button :class "exit" ""))))
;; Timer logic
(defpoll timer-display :interval "1s" "${timerScript}/bin/timer.sh")
(defwidget timer-widget []
(label :text timer-display))
;; Window
(defwindow bar
:monitor 0
:geometry (geometry :x "0%" :y "0%" :width "100%" :height "40px")
:stacking "fg"
:windowtype "dock"
:reserve (struts :distance "40px" :side "top")
(bar))
'';
home.file.".config/eww/eww.css".text = ''
* {
font-family: "JetBrainsMono Nerd Font", monospace;
font-size: 14px;
color: #ff9999;
background-color: transparent;
}
.bar {
background-color: #1a0000;
border-bottom: 1px solid #ff4d4d;
padding: 0 16px;
min-height: 40px;
}
.left, .center, .right {
padding: 8px 0;
}
button, label {
padding: 4px 12px;
border-radius: 4px;
background-color: transparent;
}
button:hover, eventbox:hover > * {
background-color: rgba(255, 77, 77, 0.2);
}
.active {
background-color: rgba(255, 77, 77, 0.3);
box-shadow: 0 0 8px rgba(255, 77, 77, 0.5);
}
.cpu, .memory, .temperature, .pulseaudio, .battery {
padding: 4px 8px;
}
.exit {
background-color: rgba(255, 77, 77, 0.3);
margin-left: 8px;
}
.exit:hover {
background-color: rgba(255, 77, 77, 0.5);
}
.bluetooth {
background-color: rgba(77, 77, 255, 0.2);
}
.bluetooth:hover {
background-color: rgba(77, 77, 255, 0.4);
}
'';
# Ensure EWW starts with Hyprland
wayland.windowManager.hyprland.settings.exec-once = [
"${pkgs.eww}/bin/eww daemon"
"sleep 1 && ${pkgs.eww}/bin/eww open bar"
];
}