diff --git a/waybar/.gitignore b/waybar/.gitignore new file mode 100644 index 0000000..3cf45bf --- /dev/null +++ b/waybar/.gitignore @@ -0,0 +1 @@ +scripts/.env \ No newline at end of file diff --git a/waybar/config.jsonc b/waybar/config.jsonc index 8a3ad2f..0824d31 100644 --- a/waybar/config.jsonc +++ b/waybar/config.jsonc @@ -9,6 +9,7 @@ "modules-right": [ // "custom/cava", "hyprland/window", + "custom/gh", "temperature#gpu", // "custom/update" , "custom/transparency", @@ -19,6 +20,12 @@ // "bluetooth", "battery" ], + "custom/gh": { + "exec": "~/.config/waybar/scripts/weekly_commits", + "return-type": "json", + "interval": 3600, // Update every hour + "tooltip": true + }, "hyprland/window": { "format": "{initialClass}", "icon": true, diff --git a/waybar/scripts/weekly_commits b/waybar/scripts/weekly_commits new file mode 100755 index 0000000..3c89579 --- /dev/null +++ b/waybar/scripts/weekly_commits @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +import requests +import datetime +import json +from collections import OrderedDict +import os +from dotenv import load_dotenv + +load_dotenv() + +GITHUB_USERNAME = os.getenv("GITHUB_USERNAME") +GITHUB_PAT = os.getenv("GITHUB_PAT") + +today = datetime.date.today() +start_of_week = today - datetime.timedelta(days=today.weekday()) +from_date = start_of_week.isoformat() + "T00:00:00Z" +to_date = today.isoformat() + "T23:59:59Z" + +query = """ +query($user: String!, $from: DateTime!, $to: DateTime!) { + user(login: $user) { + contributionsCollection(from: $from, to: $to) { + contributionCalendar { + weeks { + contributionDays { + date + contributionCount + weekday + } + } + } + } + } +} +""" + +variables = { + "user": GITHUB_USERNAME, + "from": from_date, + "to": to_date +} + +headers = { + "Authorization": f"Bearer {GITHUB_PAT}", + "Accept": "application/vnd.github.v4.idl" +} + +COLOR_SCHEME = { + 0: "#ebedf0", # No contributions (light gray) + 1: "#9be9a8", # 1-3 commits (light green) + 2: "#40c463", # 4-6 commits (medium green) + 3: "#30a14e", # 7-9 commits (dark green) + 4: "#216e39" # 10+ commits (darkest green) +} + +def get_color(count): + """Get GitHub-like color based on contribution count""" + if count == 0: + return COLOR_SCHEME[0] + elif 1 <= count <= 3: + return COLOR_SCHEME[1] + elif 4 <= count <= 6: + return COLOR_SCHEME[2] + elif 7 <= count <= 9: + return COLOR_SCHEME[3] + else: + return COLOR_SCHEME[4] + +def get_weekday_name(weekday): + """Convert weekday number (0-6) to abbreviated name""" + return ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][weekday] + +try: + response = requests.post( + "https://api.github.com/graphql", + json={"query": query, "variables": variables}, + headers=headers, + timeout=10 + ) + response.raise_for_status() + data = response.json() + + weeks = data["data"]["user"]["contributionsCollection"]["contributionCalendar"]["weeks"] + + contributions = OrderedDict() + for i in range(7): + day = start_of_week + datetime.timedelta(days=i) + contributions[day] = 0 + + for week in weeks: + for day in week["contributionDays"]: + date = datetime.date.fromisoformat(day["date"]) + if start_of_week <= date <= today: + contributions[date] = day["contributionCount"] + + dots = [] + tooltip_lines = [] + total_contributions = 0 + + for date, count in contributions.items(): + color = get_color(count) + dots.append(f'') + weekday = get_weekday_name(date.weekday()) + tooltip_lines.append(f"{weekday}: {count} contribution{'s' if count != 1 else ''}") + total_contributions += count + + output = { + "text": " ".join(dots), + "tooltip": "\n".join([f"GitHub Contributions ({start_of_week} to {today})", + f"Total: {total_contributions}"] + tooltip_lines), + "class": "github-contributions", + "alt": "GitHub Contributions" + } + +except requests.exceptions.RequestException as e: + output = { + "text": "⚠", + "tooltip": f"GitHub API error: {str(e)}", + "class": "error", + "alt": "GitHub Error" + } +except Exception as e: + output = { + "text": "⚠", + "tooltip": f"Error: {str(e)}", + "class": "error", + "alt": "Error" + } + +print(json.dumps(output)) \ No newline at end of file diff --git a/waybar/styl.css b/waybar/styl.css new file mode 100644 index 0000000..d0258c5 --- /dev/null +++ b/waybar/styl.css @@ -0,0 +1,261 @@ +@import 'mocha.css'; + +* { + font-family: JetBrains Mono Nerd Font; + min-height: 12px; + font-size: 12px; + border-radius: 6px; + padding: 0; + margin: 0; + box-shadow: none; + text-shadow: none; + background-color: transparent; +} +window#waybar { + background: rgba(0, 0, 0, 0.65); + color: @beige; + border-radius: 6px; + padding: 2px; + box-shadow: none; +} + +#window { + color: @text; + /* background: @raisin-black; */ + padding: 6px; + margin: 0px 2px; +} + +#custom-cava { + color: #cba6f7; + border-left: 0px; + border-right: 0px; + padding: 6px; + font-family: 'bargraph'; + background: @raisin-black; + margin: 0px 2px; +} + +#cpu { + color: @beige; + padding: 0px 8px 0px 15px; + /* background: @raisin-black; */ + margin-left: 2px; + border-radius: 6px 0 0 6px; +} + +#memory { + color: @beige; + padding: 0px 15px 0px 8px; + /* background: @raisin-black; */ + margin-right: 1px; + border-radius: 0 6px 6px 0; +} + +#temperature.gpu { + padding: 0px 12px; + margin-right: 2px; + color: @celadon; + /* background: @raisin-black; */ + border-radius: 6px; +} + +/* General Styling */ +tooltip, +menu, +#workspaces, +#clock, +#pulseaudio, +#backlight, +#bluetooth, +#network, +#battery, +#custom-power { + /* background: @raisin-black; */ + padding: 7px 8px; + margin: 0; + border-radius: 6px; +} + +#workspaces { + /* background: @raisin-black; */ + margin: 0; + margin-left: 3px; + padding: 0; + font-weight: bold; + font-style: normal; + opacity: 1; + font-size: 20px; + color: #1e1; + border-radius: 6px; +} + +#workspaces button { + padding: 0px 5px; + margin: 3px; + border-radius: 6px; + border: none; + transition: all 0.3s ease-in-out; + opacity: 0.4; +} + +#workspaces button.active { + color: #1e1e2e; + background: #cba6f7; + min-width: 20px; + opacity: 1; +} + +#workspaces button:hover { + color: @cerise; + background: #1e1e2e; + opacity: 1; + animation: none; +} + +#workspaces button:not(.active) { + color: #74c7ec; +} + +#workspaces button:nth-child(1):not(.active) { + color: #f38ba8; +} +#workspaces button:nth-child(2):not(.active) { + color: #f9e2af; +} +#workspaces button:nth-child(3):not(.active) { + color: #a6e3a1; +} +#clock { + padding: 0 15px; + color: @beige; + border-radius: 6px; +} + +#custom-launcher { + font-size: 18px; + transition: none; + padding: 0px 10px; + margin-right: 2px; + /* background: @raisin-black; */ + color: rgba(137, 220, 235, 1); + border-radius: 0 6px 6px 0; +} + +#custom-transparency { + font-size: 18px; + /* background: @raisin-black; */ + color: #94e2d5; + padding: 0px 10px; + margin-right: 2px; + border-radius: 6px; + /* border-radius: 6px 0 0 6px; */ + /* border-radius: 0 6px 6px 0; */ +} + +#custom-wallpaper { + font-size: 20px; + font-family: 'Font Awesome 5 Free'; + padding: 0px 8px; + margin-right: 1px; + color: #f38ba8; + /* background: @raisin-black; */ + /* border-radius: 0 6px 6px 0; */ + border-radius: 6px; +} + +#pulseaudio, +#backlight { + padding: 0 8px; + margin: 0 1px; + color: @beige; + border-radius: 6px 6px; +} + +#bluetooth, +#network { + color: #cba6f7; + border-radius: 6px; + margin: 0 1px; +} + +#custom-volume { + padding: 0 8px; + /* color: @beige; */ +} + +#network.speed { + /* background: @raisin-black; */ + padding: 0px 6px; + min-width: 10px; + color: @beige; + border-radius: 6px; +} + +#bluetooth { + min-width: 20px; + padding: 0 10px; + margin: 0 2px; + border-radius: 6px; +} + +#network { + min-width: 30px; + padding: 0 7px 0 2px; + /* margin: 0 2px; */ + border-radius: 6px; + /* border-radius: 0 6px 6px 0; */ +} + +#battery { + color: @mint; + min-width: 30px; + padding-left: 5px; + margin-left: 1px; + margin-right: 3px; + /* margin: 0 1px; */ + padding-right: 5px; + border-radius: 6px; +} + +#battery.charging { + color: #33ae18; /* Text */ + /* background: @raisin-black; */ + border-radius: 6px; +} + +#battery.good:not(.charging) { + color: #f8d589; + /* background: @raisin-black; */ + border-radius: 6px; +} + +#battery.warning:not(.charging) { + color: #e0a858; /* Text */ + /* background: @raisin-black; */ + border-radius: 6px; +} + +#battery.low:not(.charging) { + color: #d20f39; /* Text */ + /* background: @raisin-black; */ + border-radius: 6px; +} + +#battery.critical:not(.charging) { + color: #d20f39; /* Text */ + /* background: @raisin-black; */ + animation-name: blink; + animation-duration: 0.75s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; + border-radius: 6px; +} + +@keyframes blink { + to { + color: #d20f39; /* Red */ + background: #eff1f5; /* Text */ + } +} diff --git a/waybar/style.css b/waybar/style.css index f7345e6..50fbf82 100644 --- a/waybar/style.css +++ b/waybar/style.css @@ -12,6 +12,19 @@ text-shadow: none; background-color: transparent; } + +#custom-gh { + color: #39d353; /* Default color for contributions */ + background: @raisin-black; + border-radius: 6px; + margin-right: 2px; + padding: 6px; +} + +#custom-gh .empty { + color: #161b22; /* Color for no contributions */ +} + window#waybar { /* background: rgba(0, 0, 0, 0.45); */ /* color: @text; */