feat ✨: Waybar Weekly commit module
This commit is contained in:
parent
43a1dc2442
commit
df780e4c12
5 changed files with 413 additions and 0 deletions
1
waybar/.gitignore
vendored
Normal file
1
waybar/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
scripts/.env
|
|
@ -9,6 +9,7 @@
|
||||||
"modules-right": [
|
"modules-right": [
|
||||||
// "custom/cava",
|
// "custom/cava",
|
||||||
"hyprland/window",
|
"hyprland/window",
|
||||||
|
"custom/gh",
|
||||||
"temperature#gpu",
|
"temperature#gpu",
|
||||||
// "custom/update" ,
|
// "custom/update" ,
|
||||||
"custom/transparency",
|
"custom/transparency",
|
||||||
|
@ -19,6 +20,12 @@
|
||||||
// "bluetooth",
|
// "bluetooth",
|
||||||
"battery"
|
"battery"
|
||||||
],
|
],
|
||||||
|
"custom/gh": {
|
||||||
|
"exec": "~/.config/waybar/scripts/weekly_commits",
|
||||||
|
"return-type": "json",
|
||||||
|
"interval": 3600, // Update every hour
|
||||||
|
"tooltip": true
|
||||||
|
},
|
||||||
"hyprland/window": {
|
"hyprland/window": {
|
||||||
"format": "{initialClass}",
|
"format": "{initialClass}",
|
||||||
"icon": true,
|
"icon": true,
|
||||||
|
|
131
waybar/scripts/weekly_commits
Executable file
131
waybar/scripts/weekly_commits
Executable file
|
@ -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'<span foreground="{color}">●</span>')
|
||||||
|
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))
|
261
waybar/styl.css
Normal file
261
waybar/styl.css
Normal file
|
@ -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 */
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,19 @@
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
background-color: transparent;
|
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 {
|
window#waybar {
|
||||||
/* background: rgba(0, 0, 0, 0.45); */
|
/* background: rgba(0, 0, 0, 0.45); */
|
||||||
/* color: @text; */
|
/* color: @text; */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue