diff --git a/modules/home-manager/default.nix b/modules/home-manager/default.nix
index 1b9e596..cbca9df 100644
--- a/modules/home-manager/default.nix
+++ b/modules/home-manager/default.nix
@@ -14,6 +14,7 @@
../rice/hyprland
../rice/gtk.nix
../rice/kitty.nix
+ ../rice/waybar
../shell
];
diff --git a/modules/rice/waybar/crypto.py b/modules/rice/waybar/crypto.py
new file mode 100644
index 0000000..bd7467c
--- /dev/null
+++ b/modules/rice/waybar/crypto.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+import requests
+import json
+
+
+url = "https://api.coingecko.com/api/v3/coins/markets"
+params = {
+ "vs_currency": "usd",
+ "order": "market_cap_desc",
+ "per_page": 10,
+ "price_change_percentage": "24h",
+ "page": 1,
+}
+
+response = requests.get(url, params=params)
+
+if response.status_code == 200:
+ top_cryptos = response.json()
+ tooltip = 'Crypto\n'
+ for crypto in top_cryptos:
+ name = crypto["name"]
+ symbol = crypto["symbol"]
+ price = crypto["current_price"]
+ change = crypto["price_change_percentage_24h"]
+ tooltip += str(f" {name}: ${price} | {change:.2f}%\n")
+
+ out_data = {
+ "text": f"",
+ "alt": f"",
+ "tooltip": tooltip,
+ "class": "weather",
+ }
+ print(json.dumps(out_data))
+else:
+ exit(1)
diff --git a/modules/rice/waybar/default.nix b/modules/rice/waybar/default.nix
new file mode 100644
index 0000000..05ec5c3
--- /dev/null
+++ b/modules/rice/waybar/default.nix
@@ -0,0 +1,133 @@
+{
+ pkgs,
+ lib,
+ ...
+}:
+with lib; let
+ waybar-wttr = pkgs.stdenv.mkDerivation {
+ name = "waybar-wttr";
+ buildInputs = [
+ (pkgs.python39.withPackages
+ (pythonPackages: with pythonPackages; [requests]))
+ ];
+ unpackPhase = "true";
+ installPhase = ''
+ mkdir -p $out/bin
+ cp ${./waybar-wttr.py} $out/bin/waybar-wttr
+ chmod +x $out/bin/waybar-wttr
+ '';
+ };
+in {
+ home.packages = [waybar-wttr];
+ programs.waybar = {
+ enable = true;
+ style = import ./style.nix;
+ systemd = {
+ enable = true;
+ target = "hyprland-session.target";
+ };
+ settings = {
+ mainBar = {
+ layer = "top";
+ position = "left";
+ width = 57;
+ spacing = 7;
+ modules-left = [
+ "custom/search"
+ "hyprland/workspaces"
+ "custom/lock"
+ "custom/weather"
+ "backlight"
+ "battery"
+ ];
+ modules-center = [];
+ modules-right = ["pulseaudio" "network" "clock" "custom/power"];
+ "hyprland/workspaces" = {
+ on-click = "activate";
+ format = "{icon}";
+ active-only = false;
+ format-icons = {
+ "1" = "一";
+ "2" = "二";
+ "3" = "三";
+ "4" = "四";
+ "5" = "五";
+ "6" = "六";
+ "7" = "七";
+ "8" = "八";
+ "9" = "九";
+ "10" = "十";
+ };
+
+ persistent_workspaces = {
+ "*" = 5;
+ };
+ };
+ "custom/search" = {
+ format = " ";
+ tooltip = false;
+ on-click = "${pkgs.tofi}/bin/tofi-drun";
+ };
+
+ "custom/weather" = {
+ format = "{}";
+ tooltip = true;
+ interval = 3600;
+ exec = "waybar-wttr";
+ return-type = "json";
+ };
+ "custom/lock" = {
+ tooltip = false;
+ on-click = "sh -c '(sleep 0.5s; swaylock)' & disown";
+ format = "";
+ };
+ "custom/power" = {
+ tooltip = false;
+ on-click = "wlogout &";
+ format = "";
+ };
+ clock = {
+ format = ''
+ {:%H
+ %M}'';
+ tooltip-format = ''
+ {:%Y %B}
+ {calendar}'';
+ };
+ backlight = {
+ format = "{icon}";
+ format-icons = ["" "" "" "" "" "" "" "" ""];
+ };
+ battery = {
+ states = {
+ warning = 30;
+ critical = 15;
+ };
+ format = "{icon}";
+ format-charging = "{icon}\n";
+ tooltip-format = "{timeTo} {capacity}% {power}";
+ format-icons = ["" "" "" "" "" "" "" "" "" "" ""];
+ };
+ network = {
+ format-wifi = "";
+ format-ethernet = "";
+ format-alt = "";
+ format-disconnected = "";
+ tooltip-format = "{ipaddr}/{ifname} via {gwaddr} ({signalStrength}%)";
+ };
+ pulseaudio = {
+ scroll-step = 5;
+ tooltip = true;
+ tooltip-format = "{volume}% {format_source}";
+ on-click = "${pkgs.killall}/bin/killall pavucontrol || ${pkgs.pavucontrol}/bin/pavucontrol";
+ format = " {icon}\n{volume}%";
+ format-bluetooth = " {icon} {volume}%";
+ format-muted = " ";
+ format-icons = {
+ default = ["" "" " "];
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/modules/rice/waybar/sakura.png b/modules/rice/waybar/sakura.png
new file mode 100644
index 0000000..21e463c
Binary files /dev/null and b/modules/rice/waybar/sakura.png differ
diff --git a/modules/rice/waybar/style.nix b/modules/rice/waybar/style.nix
new file mode 100644
index 0000000..27e5798
--- /dev/null
+++ b/modules/rice/waybar/style.nix
@@ -0,0 +1,129 @@
+''
+ * {
+ /* `otf-font-awesome` is required to be installed for icons */
+ font-family: Material Design Icons, Iosevka Nerd Font;
+ }
+
+ window#waybar {
+ background-color: rgba(48, 52, 70, 0.88);
+ border-radius: 0px;
+ color: #c6d0f5;
+ font-size: 20px;
+ /* transition-property: background-color; */
+ transition-duration: 0.5s;
+ }
+
+ window#waybar.hidden {
+ opacity: 0.2;
+ }
+
+ #workspaces {
+ font-size: 15px;
+ background-color: #414559;
+ }
+
+ #pulseaudio {
+ color: #a6d189;
+ }
+ #network {
+ color: #8caaee;
+ }
+
+ #custom-search,
+ #clock {
+ background-color: #414559;
+ }
+
+ #workspaces button {
+ background-color: transparent;
+ color: #8caaee;
+ /* Use box-shadow instead of border so the text isn't offset */
+ box-shadow: inset 0 -3px transparent;
+ }
+
+ /* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
+ #workspaces button:hover {
+ color: #85c1dc;
+ }
+
+ #custom-power {
+ color: #e78284;
+ }
+
+ #custom-lock {
+ color: #8caaee;
+ }
+
+ #workspaces button.active {
+ color: #e5c890;
+ }
+
+ #workspaces button.urgent {
+ background-color: #e78284;
+ }
+
+ #clock,
+ #network,
+ #cpu,
+ #battery,
+ #backlight,
+ #memory,
+ #workspaces,
+ #custom-search,
+ #custom-power,
+ #custom-todo,
+ #custom-lock,
+ #custom-weather,
+ #custom-btc,
+ #custom-eth,
+ #volume,
+ #pulseaudio {
+ border-radius: 15px;
+ margin: 0px 7px 0px 7px;
+ background-color: rgba(65, 69, 89, 0.9);
+ padding: 10px 0px 10px 0px;
+ }
+
+ #custom-power {
+ margin-bottom: 7px;
+ padding-right: 6px;
+ }
+ #custom-search {
+ background-image: url("${./sakura.png}");
+ background-size: 60%;
+ background-position: center;
+ background-repeat: no-repeat;
+ margin-top: 7px;
+ }
+ #clock {
+ font-weight: 700;
+ font-size: 20px;
+ padding: 5px 0px 5px 0px;
+ font-family: "Iosevka Term";
+ }
+ #backlight {
+ padding-right: 2px;
+ color: #e5c890;
+ }
+ #battery {
+ color: #a6d189;
+ }
+
+ #battery.warning {
+ color: #ef9f76;
+ }
+
+ #battery.critical:not(.charging) {
+ color: #e78284;
+ }
+ tooltip {
+ font-family: 'Lato', sans-serif;
+ border-radius: 15px;
+ padding: 20px;
+ margin: 30px;
+ }
+ tooltip label {
+ font-family: 'Lato', sans-serif;
+ padding: 20px;
+ }
+''
diff --git a/modules/rice/waybar/waybar-wttr.py b/modules/rice/waybar/waybar-wttr.py
new file mode 100644
index 0000000..bc3a7ae
--- /dev/null
+++ b/modules/rice/waybar/waybar-wttr.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+import json
+import requests
+from datetime import datetime
+
+WEATHER_CODES = {
+ '113': '☀️ ',
+ '116': '⛅ ',
+ '119': '☁️ ',
+ '122': '☁️ ',
+ '143': '☁️ ',
+ '176': '🌧️',
+ '179': '🌧️',
+ '182': '🌧️',
+ '185': '🌧️',
+ '200': '⛈️ ',
+ '227': '🌨️',
+ '230': '🌨️',
+ '248': '☁️ ',
+ '260': '☁️ ',
+ '263': '🌧️',
+ '266': '🌧️',
+ '281': '🌧️',
+ '284': '🌧️',
+ '293': '🌧️',
+ '296': '🌧️',
+ '299': '🌧️',
+ '302': '🌧️',
+ '305': '🌧️',
+ '308': '🌧️',
+ '311': '🌧️',
+ '314': '🌧️',
+ '317': '🌧️',
+ '320': '🌨️',
+ '323': '🌨️',
+ '326': '🌨️',
+ '329': '❄️ ',
+ '332': '❄️ ',
+ '335': '❄️ ',
+ '338': '❄️ ',
+ '350': '🌧️',
+ '353': '🌧️',
+ '356': '🌧️',
+ '359': '🌧️',
+ '362': '🌧️',
+ '365': '🌧️',
+ '368': '🌧️',
+ '371': '❄️',
+ '374': '🌨️',
+ '377': '🌨️',
+ '386': '🌨️',
+ '389': '🌨️',
+ '392': '🌧️',
+ '395': '❄️ '
+}
+
+data = {}
+
+
+weather = requests.get("https://wttr.in/?format=j1").json()
+
+
+def format_time(time):
+ return time.replace("00", "").zfill(2)
+
+
+def format_temp(temp):
+ return (hour['FeelsLikeC']+"°").ljust(3)
+
+
+def format_chances(hour):
+ chances = {
+ "chanceoffog": "Fog",
+ "chanceoffrost": "Frost",
+ "chanceofovercast": "Overcast",
+ "chanceofrain": "Rain",
+ "chanceofsnow": "Snow",
+ "chanceofsunshine": "Sunshine",
+ "chanceofthunder": "Thunder",
+ "chanceofwindy": "Wind"
+ }
+
+ conditions = []
+ for event in chances.keys():
+ if int(hour[event]) > 0:
+ conditions.append(chances[event]+" "+hour[event]+"%")
+ return ", ".join(conditions)
+
+tempint = int(weather['current_condition'][0]['FeelsLikeC'])
+extrachar = ''
+if tempint >= 0 and tempint < 10:
+ extrachar = '+'
+
+
+data['text'] = ' '+WEATHER_CODES[weather['current_condition'][0]['weatherCode']] + \
+ "\n "+extrachar+weather['current_condition'][0]['FeelsLikeC']+"°"
+
+data['tooltip'] = f"{weather['current_condition'][0]['weatherDesc'][0]['value']} {weather['current_condition'][0]['temp_C']}°\n"
+data['tooltip'] += f"Feels like: {weather['current_condition'][0]['FeelsLikeC']}°\n"
+data['tooltip'] += f"Wind: {weather['current_condition'][0]['windspeedKmph']}Km/h\n"
+data['tooltip'] += f"Humidity: {weather['current_condition'][0]['humidity']}%\n"
+for i, day in enumerate(weather['weather']):
+ data['tooltip'] += f"\n"
+ if i == 0:
+ data['tooltip'] += "Today, "
+ if i == 1:
+ data['tooltip'] += "Tomorrow, "
+ data['tooltip'] += f"{day['date']}\n"
+ data['tooltip'] += f"⬆️ {day['maxtempC']}° ⬇️ {day['mintempC']}° "
+ data['tooltip'] += f"🌅 {day['astronomy'][0]['sunrise']} 🌇 {day['astronomy'][0]['sunset']}\n"
+ for hour in day['hourly']:
+ if i == 0:
+ if int(format_time(hour['time'])) < datetime.now().hour-2:
+ continue
+ data['tooltip'] += f"{format_time(hour['time'])} {WEATHER_CODES[hour['weatherCode']]} {format_temp(hour['FeelsLikeC'])} {hour['weatherDesc'][0]['value']}, {format_chances(hour)}\n"
+
+
+print(json.dumps(data))