diff --git a/echo b/echo
new file mode 100644
index 0000000..e115f23
--- /dev/null
+++ b/echo
@@ -0,0 +1 @@
+{"text": "\ue312 49\u00b0F", "tooltip": " Overcast 49\u00b0\n .--. Feels like: 49\u00b0\n .-( ). Wind: 2mph \u2199\n (___.__)__) Humidity: 80%\n Moon phase: Waxing Crescent \ud83c\udf12\n\nToday, Mon Nov 24 2025\n\uf2c7 53\u00b0F \uf2ca 38\u00b0F\ue34c 07:23 AM \ue34d 04:36 PM\n03 PM \udb81\udd95 52\u00b0 Partly Cloudy , Overcast 33%, Sunshine 73%\n06 PM \ue313 44\u00b0 Mist, Overcast 83%, Sunshine 8%\n09 PM \ue313 43\u00b0 Fog, Overcast 93%, Sunshine 5%\nTomorrow, Tue Nov 25 2025\n\uf2c7 43\u00b0F \uf2ca 34\u00b0F\ue34c 07:24 AM \ue34d 04:36 PM\n12 AM \ue313 43\u00b0 Fog, Fog 6%, Overcast 81%, Sunshine 19%\n03 AM \ue313 42\u00b0 Fog, Overcast 89%, Sunshine 8%\n06 AM \ue313 41\u00b0 Fog, Fog 6%, Overcast 92%, Sunshine 11%\n09 AM \ue313 40\u00b0 Fog, Fog 6%, Overcast 88%, Sunshine 5%\n12 PM \ue317 39\u00b0 Moderate rain at times, Overcast 90%, Rain 100%\n03 PM \ue308 34\u00b0 Light rain, Overcast 93%, Rain 100%\n06 PM \ue318 31\u00b0 Moderate rain, Overcast 88%, Rain 100%\n09 PM \ue31a 24\u00b0 Moderate snow, Overcast 89%, Rain 100%, Snow 100%\nWed Nov 26 2025\n\uf2c7 36\u00b0F \uf2ca 25\u00b0F\ue34c 07:26 AM \ue34d 04:35 PM\n12 AM \ue312 21\u00b0 Overcast , Overcast 87%, Sunshine 8%\n03 AM \ue312 14\u00b0 Overcast , Frost 25%, Overcast 94%, Sunshine 13%\n06 AM \ue312 11\u00b0 Overcast , Frost 80%, Overcast 89%, Sunshine 8%\n09 AM \ue312 13\u00b0 Overcast , Frost 79%, Overcast 80%, Sunshine 5%\n12 PM \ue33d 18\u00b0 Cloudy , Frost 77%, Overcast 89%, Sunshine 17%\n03 PM \ue30d 24\u00b0 Sunny, Frost 29%, Sunshine 90%\n06 PM \udb81\udd94 22\u00b0 Clear , Frost 78%, Sunshine 94%\n09 PM \udb83\udf31 15\u00b0 Partly Cloudy , Frost 85%, Overcast 39%, Sunshine 83%\n"}
diff --git a/modules/home/programs/waybar/default.nix b/modules/home/programs/waybar/default.nix
index 4c71204..505bfea 100755
--- a/modules/home/programs/waybar/default.nix
+++ b/modules/home/programs/waybar/default.nix
@@ -122,6 +122,23 @@ let
background-color: transparent;
}
+ #custom-power {
+ color: ${palette.colors.primary};
+ background-color: ${palette.colors.bg};
+ ${defaultOpacity}
+ ${defaultCenterOptions}
+ border-radius: 0;
+ }
+
+ menu {
+ border-radius: 15px;
+ background: ${palette.colors.bg};
+ color: ${palette.colors.text};
+ }
+ menuitem {
+ border-radius: 15px;
+ }
+
#custom-weather {
color: ${palette.colors.primary};
background-color: ${palette.colors.bg};
@@ -130,6 +147,25 @@ let
border-radius: 0;
}
+ #custom-notifications {
+ color: ${palette.colors.primary};
+ background-color: ${palette.colors.bg};
+ ${defaultOpacity}
+ ${defaultCenterOptions}
+ border-radius: 0;
+ }
+
+ #custom-notifications.notify {
+ color: ${palette.colors.danger};
+ }
+
+ #custom-notifications.alert {
+ animation-name: blinker;
+ animation-duration: 3s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ }
+
#battery {
color: ${palette.colors.accent};
background-color: ${palette.colors.bg};
@@ -292,6 +328,7 @@ in
./options.nix
./scripts/audio-control.nix
./scripts/hass.nix
+ ./scripts/notifications.nix
./scripts/weather.nix
];
@@ -299,6 +336,39 @@ in
# https://github.com/Alexays/Waybar/wiki/Module:-Hyprland
# https://www.nerdfonts.com/cheat-sheet
+ home.file = {
+ ".config/waybar/power_menu.xml".text = ''
+
+
+
+
+ '';
+ };
+
programs.waybar = {
enable = true;
systemd.enable = true;
@@ -377,15 +447,37 @@ in
};
};
+ "custom/notifications" = {
+ interval = 30;
+ format = { };
+ tooltip = true;
+ exec = "waybar-notifications";
+ return-type = "json";
+ on-click-middle = "makoctl restore && makoctl dismiss --all --no-history"; # todo
+ };
+
"custom/left-end" = {
- format = " ";
+ format = "&nbsp";
tooltip = false;
};
"custom/right-end" = {
- format = " ";
+ format = "&nbsp";
tooltip = false;
};
+
+ "custom/power" = {
+ format = "⏻ ";
+ tooltip = false;
+ menu = "on-click";
+ menu-file = "~/.config/waybar/power_menu.xml";
+ menu-actions = {
+ shutdown = "shutdown";
+ reboot = "reboot";
+ suspend = "systemctl suspend";
+ hibernate = "systemctl hibernate";
+ };
+ };
}
(mkIf cfg.features.tray.enable {
diff --git a/modules/home/programs/waybar/options.nix b/modules/home/programs/waybar/options.nix
index 6b9b28e..c5db66a 100644
--- a/modules/home/programs/waybar/options.nix
+++ b/modules/home/programs/waybar/options.nix
@@ -87,7 +87,9 @@ in
"custom/left-end"
"clock"
"battery"
+ "custom/notifications"
"custom/weather"
+ "custom/power"
"custom/right-end"
];
description = "Modules shown on the right.";
diff --git a/modules/home/programs/waybar/scripts/notifications.nix b/modules/home/programs/waybar/scripts/notifications.nix
new file mode 100644
index 0000000..f34d208
--- /dev/null
+++ b/modules/home/programs/waybar/scripts/notifications.nix
@@ -0,0 +1,95 @@
+{
+ config,
+ lib,
+ namespace,
+ pkgs,
+ ...
+}:
+let
+ cfg = config.${namespace}.programs.waybar;
+
+ waybar-notifications = pkgs.writeScriptBin "waybar-notifications" ''
+ #!/usr/bin/env python
+
+ import subprocess
+ import json
+ import codecs
+ import re
+
+ def check_notifications(args = "history"):
+ notifications = []
+ number = None
+ content = None
+ appname = None
+ urgency = None
+ cmd = "makoctl"
+ temp = subprocess.Popen([cmd, args], stdout = subprocess.PIPE)
+ output = str(temp.communicate()).replace("(b\'", "").replace("\', None)", "")
+ lines = output.split("\\n")
+ for line in lines:
+ if "Notification" in line:
+ number = line.split(":")[0].replace("Notification ", "")
+ content = re.sub(r"[\u2066\u2067\u2068\u2069, \u00e2\u0081\u00a8]", "", codecs.decode(line.split(": ")[-1].encode("latin1").decode("utf-8"), "unicode_escape"))
+ content = re.sub(r"[\u00a9]", " ", content)
+
+ if "App name" in line:
+ appname = line.split(": ")[-1]
+ if "Urgency" in line:
+ urgency = line.split(": ")[-1]
+
+ if number is not None and content is not None and appname is not None and urgency is not None:
+ notifications.append((number, content, appname, urgency))
+ number = None
+ content = None
+ appname = None
+ urgency = None
+
+ return notifications
+
+ def get_icon(notifications):
+ status = ""
+ icon = ""
+
+ for number, content, appname, urgency in notifications:
+ status = "notify"
+ if urgency != "normal":
+ status = "alert"
+ break
+
+ if status == "notify":
+ icon = ""
+ if status == "alert":
+ icon = ""
+
+ return icon, status
+
+ def build_tooltip(notifications):
+ tooltip = ""
+ for number, content, appname, urgency in notifications:
+ tooltip += "{0}: {1}\n".format(appname, content)
+
+ return tooltip
+
+ def main():
+ notifications = check_notifications()
+ data = {}
+
+ icon, status = get_icon(notifications)
+
+ data["text"] = icon
+ data["tooltip"] = build_tooltip(notifications)
+ data["class"] = status
+
+ print(json.dumps(data, ensure_ascii=False))
+
+ main()
+
+ '';
+in
+{
+ imports = [ ../options.nix ];
+
+ config = lib.mkIf cfg.enable {
+ home.packages = [ waybar-notifications ];
+ };
+}
diff --git a/modules/home/programs/waybar/scripts/weather.nix b/modules/home/programs/waybar/scripts/weather.nix
index cb8390d..76e0545 100644
--- a/modules/home/programs/waybar/scripts/weather.nix
+++ b/modules/home/programs/waybar/scripts/weather.nix
@@ -189,100 +189,100 @@ let
' '],
"VeryCloudy": [
' ',
- ' .--. ',
- ' .-( ). ',
- ' (___.__)__) ',
+ ' .--. ',
+ ' .-( ). ',
+ ' (___.__)__) ',
' '],
"LightShowers": [
' _`/\'\'".-. ',
' ,\\_"( ). ',
' /"(___(__) ',
- ' ‘ ‘ ‘ ‘ ',
- ' ‘ ‘ ‘ ‘ '],
+ ' ‘ ‘ ‘ ‘ ',
+ ' ‘ ‘ ‘ ‘ '],
"HeavyShowers": [
- ' _`/\'\'".-. ',
- ' ,\\_"( ). ',
- ' /"(___(__) ',
- ' ‚‘‚‘‚‘‚‘ ',
- ' ‚’‚’‚’‚’ '],
+ ' _`/\'\'".-. ',
+ ' ,\\_"( ). ',
+ ' /"(___(__) ',
+ ' ‚‘‚‘‚‘‚‘ ',
+ ' ‚’‚’‚’‚’ '],
"LightSnowShowers": [
' _`/\'\'".-. ',
' ,\\_"( ). ',
' /"(___(__) ',
- ' * * * ',
- ' * * * '],
+ ' * * * ',
+ ' * * * '],
"HeavySnowShowers": [
- ' _`/\'\'".-. ',
- ' ,\\_"( ). ',
- ' /"(___(__) ',
- ' * * * * ',
- ' * * * * '],
+ ' _`/\'\'".-. ',
+ ' ,\\_"( ). ',
+ ' /"(___(__) ',
+ ' * * * * ',
+ ' * * * * '],
"LightSleetShowers": [
' _`/\'\'".-. ',
' ,\\_"( ). ',
' /"(___(__) ',
- ' ‘ "*" ‘ "* ',
- ' *" ‘ "*" ‘ '],
+ ' ‘ "*" ‘ "* ',
+ ' *" ‘ "*" ‘ '],
"ThunderyShowers": [
' _`/\'\'".-. ',
' ,\\_"( ). ',
' /"(___(__) ',
- ' ⚡\\"‘ ‘"⚡\\"‘ ‘ ',
- ' ‘ ‘ ‘ ‘ '],
+ ' ⚡\\"‘ ‘"⚡\\"‘ ‘ ',
+ ' ‘ ‘ ‘ ‘ '],
"ThunderyHeavyRain": [
- ' .-. ',
- ' ( ). ',
- ' (___(__) ',
- ' ‚‘"⚡\\"‘‚"⚡\\"‚‘ ',
- ' ‚’‚’"⚡\\"’‚’ '],
+ ' .-. ',
+ ' ( ). ',
+ ' (___(__) ',
+ ' ‚‘"⚡\\"‘‚"⚡\\"‚‘ ',
+ ' ‚’‚’"⚡\\"’‚’ '],
"ThunderySnowShowers": [
' _`/\'\'".-. ',
' ,\\_"( ). ',
' /"(___(__) ',
- ' *"⚡\\"*"⚡\\"* ',
- ' * * * '],
+ ' *"⚡\\"*"⚡\\"* ',
+ ' * * * '],
"LightRain": [
' .-. ',
' ( ). ',
' (___(__) ',
- ' ‘ ‘ ‘ ‘ ',
- ' ‘ ‘ ‘ ‘ '],
+ ' ‘ ‘ ‘ ‘ ',
+ ' ‘ ‘ ‘ ‘ '],
"HeavyRain": [
- ' .-. ',
- ' ( ). ',
- ' (___(__) ',
- ' ‚‘‚‘‚‘‚‘ ',
- ' ‚’‚’‚’‚’ '],
+ ' .-. ',
+ ' ( ). ',
+ ' (___(__) ',
+ ' ‚‘‚‘‚‘‚‘ ',
+ ' ‚’‚’‚’‚’ '],
"LightSnow": [
' .-. ',
' ( ). ',
' (___(__) ',
- ' * * * ',
- ' * * * '],
+ ' * * * ',
+ ' * * * '],
"HeavySnow": [
- ' .-. ',
- ' ( ). ',
- ' (___(__) ',
- ' * * * * ',
- ' * * * * '],
+ ' .-. ',
+ ' ( ). ',
+ ' (___(__) ',
+ ' * * * * ',
+ ' * * * * '],
"LightSleet": [
' .-. ',
' ( ). ',
' (___(__) ',
- ' ‘ "*" ‘ "* ',
- ' *" ‘ "*" ‘ '],
+ ' ‘ "*" ‘ "* ',
+ ' *" ‘ "*" ‘ '],
"Fog": [
' ',
- ' _ - _ - _ - ',
- ' _ - _ - _ ',
- ' _ - _ - _ - ',
+ ' _ - _ - _ - ',
+ ' _ - _ - _ ',
+ ' _ - _ - _ - ',
' '],
}
WEATHER_CODES_WEGO = {key: WEATHER_SYMBOL_WEGO[value] for key, value in WWO_CODE.items()}
data = {}
-
+ data["text"] = ""
def format_time(time):
"""get the time formatted"""