Revert "Add map view to leaderboard (#81)" (#89)

This commit is contained in:
guyeisenkot
2025-07-27 17:13:03 +03:00
committed by GitHub
parent 6806e627af
commit 13efbfe567
8 changed files with 23 additions and 422 deletions

View File

@@ -25,17 +25,15 @@ jobs:
with:
python-version: '3.x'
- name: Install Python dependencies
run: pip install pyyaml requests geonamescache
run: pip install pyyaml
- name: Generate leaderboard
run: python generate_leaderboard.py
- name: Build profiles and locations
run: python build_locations.py
- name: Commit leaderboard data
run: |
if [[ `git status --porcelain` ]]; then
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add _data/leaderboard.json assets/data/contributors.json assets/data/locations.json
git add _data/leaderboard.json assets/data/contributors.json
git commit -m "Update leaderboard [skip ci]"
git push
fi

1
.gitignore vendored
View File

@@ -3,4 +3,3 @@ vendor
_site
.jekyll-cache
.claude
assets/data/profiles.json

View File

@@ -34,7 +34,7 @@
* **🚀 One-Click Deployment:** Deploy reviewer agents automatically on your PRs using **[Baz](https://baz.co)**. The site includes a **“🚀 Deploy to baz”** button that lets you spin up the selected reviewer as an AI code review bot in a single click. Baz is a platform for agentic code reviews, and with this integration it can apply the Awesome Reviewers prompts to your PRs without any manual copy-paste. In other words, you get automated code review comments on your GitHub PRs based on the same proven guidelines (with no configuration needed beyond the click). *This is a nod to how Awesome Reviewers works hand-in-hand with Baz to supercharge developer workflows.*
* **🏆 Community Leaderboard:** Check out the new **Leaderboard** page to see the top contributors across all reviewer categories. Contributor stats and GitHub profile metadata are automatically regenerated by a GitHub Action on every deployment. The metadata is cached during the build (not committed) so the leaderboard stays fast without exceeding API limits.
* **🏆 Community Leaderboard:** Check out the new **Leaderboard** page to see the top contributors across all reviewer categories. Contributor stats are automatically regenerated by a GitHub Action on every deployment.
## Getting Started

View File

@@ -30,11 +30,6 @@
<link rel="stylesheet" href="{{ '/assets/prism/prism.css' | relative_url }}">
<link rel="manifest" href="{{ '/manifest.json' | relative_url }}">
<link rel="canonical" href="{{ site.url }}{{ page.url }}">
{% if page.extra_css %}
{% for css in page.extra_css %}
<link rel="stylesheet" href="{{ css }}">
{% endfor %}
{% endif %}
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-2S2LLCMG7N"></script>
@@ -976,10 +971,5 @@
<script src="{{ '/assets/prism/prism.js' | relative_url }}"></script>
<script src="{{ '/assets/js/prism-init.js' | relative_url }}"></script>
<script src="{{ '/assets/js/main.js' | relative_url }}"></script>
{% if page.extra_js %}
{% for js in page.extra_js %}
<script src="{{ js }}"></script>
{% endfor %}
{% endif %}
</body>
</html>

View File

@@ -1939,29 +1939,3 @@ h2 .stat-value {
color: var(--accent);
margin-left: 0.25rem;
}
/* Leaderboard map */
.leaderboard-map {
height: 500px;
margin-top: 1rem;
border: 1px solid var(--border);
}
/* Leaderboard tabs */
.lb-tabs {
margin-bottom: 1rem;
}
.lb-tabs button {
background: none;
border: none;
padding: 0.5rem 1rem;
cursor: pointer;
font-weight: 600;
color: var(--text-light);
}
.lb-tabs button.active {
color: var(--text);
border-bottom: 2px solid var(--accent);
}
.lb-pane { display: none; }
.lb-pane.active { display: block; }

View File

@@ -1,169 +0,0 @@
{
"kimwnasptd": {
"location": "Athens",
"lat": 37.98376,
"lon": 23.72784
},
"Darksonn": {
"location": "Denmark",
"lat": 55.67594,
"lon": 12.56553
},
"louwers": {
"location": "Germany, Europe",
"lat": 52.52437,
"lon": 13.41053
},
"kamilmysliwiec": {
"location": "Poland",
"lat": 52.22977,
"lon": 21.01178
},
"jasnell": {
"location": "Clovis, California",
"lat": 36.82523,
"lon": -119.70292
},
"sapphi-red": {
"location": "Japan",
"lat": 35.6895,
"lon": 139.69171
},
"tannergooding": {
"location": "Lake Stevens, WA",
"lat": 48.0151,
"lon": -122.06374
},
"daniel-lxs": {
"location": "Colombia",
"lat": 20.98812,
"lon": -77.42598
},
"jfagoagas": {
"location": "Madrid, Spain",
"lat": 40.4165,
"lon": -3.70256
},
"Viicos": {
"location": "Amsterdam",
"lat": 52.37403,
"lon": 4.88969
},
"wilkinsona": {
"location": "UK"
},
"MikeMcQuaid": {
"location": "Edinburgh, Scotland",
"lat": 55.95206,
"lon": -3.19648
},
"sydney-runkle": {
"location": "Somerville, MA",
"lat": 42.3876,
"lon": -71.0995
},
"agaudreault": {
"location": "Saguenay",
"lat": 48.41675,
"lon": -71.06573
},
"chris-olszewski": {
"location": "Cleveland",
"lat": 41.4995,
"lon": -81.69541
},
"ololobus": {
"location": "Berlin, Germany",
"lat": 52.52437,
"lon": 13.41053
},
"treo": {
"location": "Mainz, Germany",
"lat": 49.98419,
"lon": 8.2791
},
"jmcdo29": {
"location": "Concrete, WA"
},
"micalevisk": {
"location": "Manaus, Amazonas (Brazil)",
"lat": -3.10194,
"lon": -60.025
},
"VladLazar": {
"location": "London, United Kingdom",
"lat": 51.50853,
"lon": -0.12574
},
"AlexDBlack": {
"location": "Melbourne, Australia",
"lat": -37.814,
"lon": 144.96332
},
"ritchie46": {
"location": "Utrecht",
"lat": 52.09083,
"lon": 5.12222
},
"yottta": {
"location": "Brasov, Romania",
"lat": 44.43225,
"lon": 26.10626
},
"hiltontj": {
"location": "Canada",
"lat": 45.41117,
"lon": -75.69812
},
"SomeoneToIgnore": {
"location": "Turku, Finland",
"lat": 60.45148,
"lon": 22.26869
},
"ZeeshanTamboli": {
"location": "Pune, Maharashtra",
"lat": 18.51957,
"lon": 73.85535
},
"jacoblee93": {
"location": "San Francisco",
"lat": 37.77493,
"lon": -122.41942
},
"thaJeztah": {
"location": "Netherlands",
"lat": 52.37403,
"lon": 4.88969
},
"ndeloof": {
"location": "Rennes, France",
"lat": 48.11198,
"lon": -1.67429
},
"konstin": {
"location": "Munich",
"lat": 48.13743,
"lon": 11.57549
},
"apparentlymart": {
"location": "Portland, OR",
"lat": 45.52345,
"lon": -122.67621
},
"n1t0": {
"location": "New York"
},
"ste93cry": {
"location": "Padova, Italy",
"lat": 45.40797,
"lon": 11.88586
},
"sbrannen": {
"location": "Zurich, Switzerland",
"lat": 46.94809,
"lon": 7.44744
},
"pauldix": {
"location": "New York, NY"
}
}

View File

@@ -1,101 +0,0 @@
import json
import re
from pathlib import Path
import requests
import geonamescache
gc = geonamescache.GeonamesCache()
DATA_DIR = Path('_data')
ASSETS_DIR = Path('assets/data')
LEADERBOARD_PATH = DATA_DIR / 'leaderboard.json'
LOCATIONS_OUT = ASSETS_DIR / 'locations.json'
PROFILES_OUT = ASSETS_DIR / 'profiles.json'
API_URL = 'https://api.github.com/users/'
HEADERS = {'Accept': 'application/vnd.github+json'}
def best_city(name):
results = gc.get_cities_by_name(name)
if not results:
return None
result = max(results, key=lambda d: list(d.values())[0]['population'])
city = list(result.values())[0]
return city['latitude'], city['longitude']
def geocode(location):
if not location:
return None
# split by comma or slash
parts = [p.strip() for p in re.split('[,;/]', location)]
for part in parts:
if not part:
continue
coords = best_city(part)
if coords:
return coords
coords = best_country(part)
if coords:
return coords
return None
def best_country(name):
match = gc.get_countries_by_names().get(name)
if match:
code = match['iso']
info = gc.get_countries()[code]
capital = info['capital']
cities = gc.get_cities_by_name(capital)
if cities:
city = max(cities, key=lambda d: list(d.values())[0]['population'])
data = list(city.values())[0]
return data['latitude'], data['longitude']
return None
def main():
if not LEADERBOARD_PATH.exists():
print('leaderboard not found')
return
users = [u['name'] for u in json.load(open(LEADERBOARD_PATH))]
locations = {}
profiles = {}
for user in users:
print('Fetching', user)
r = requests.get(API_URL + user, headers=HEADERS)
if r.status_code != 200:
print(' failed', r.status_code)
continue
info = r.json()
loc = info.get('location')
coords = geocode(loc)
if coords:
lat, lon = coords
locations[user] = {'location': loc, 'lat': lat, 'lon': lon}
elif loc:
locations[user] = {'location': loc}
profile = {
'location': info.get('location'),
'company': info.get('company'),
'blog': info.get('blog'),
'twitter_username': info.get('twitter_username'),
'email': info.get('email'),
'site_admin': info.get('site_admin'),
'followers': info.get('followers'),
'following': info.get('following'),
}
profiles[user] = {k: v for k, v in profile.items() if v is not None}
ASSETS_DIR.mkdir(parents=True, exist_ok=True)
with open(LOCATIONS_OUT, 'w', encoding='utf-8') as f:
json.dump(locations, f, indent=2)
print('Wrote', len(locations), 'locations to', LOCATIONS_OUT)
with open(PROFILES_OUT, 'w', encoding='utf-8') as f:
json.dump(profiles, f, indent=2)
print('Wrote', len(profiles), 'profiles to', PROFILES_OUT)
if __name__ == '__main__':
main()

View File

@@ -2,10 +2,6 @@
layout: default
title: Leaderboard
description: Top contributors powering Awesome Reviewers
extra_css:
- https://unpkg.com/leaflet@1.9.4/dist/leaflet.css
extra_js:
- https://unpkg.com/leaflet@1.9.4/dist/leaflet.js
---
<section class="hero leaderboard-hero">
@@ -29,11 +25,6 @@ extra_js:
<section class="leaderboard">
<div class="container">
<div class="lb-tabs">
<button class="lb-tab active" data-target="table">Leaderboard</button>
<button class="lb-tab" id="map-tab" data-target="map" style="display:none">Map</button>
</div>
<div id="lb-table-pane" class="lb-pane active">
<table id="leaderboard-table" class="leaderboard-table">
<thead>
<tr>
@@ -66,10 +57,6 @@ extra_js:
{% endfor %}
</tbody>
</table>
</div>
<div id="lb-map-pane" class="lb-pane">
<div id="leader-map" class="leaderboard-map"></div>
</div>
</div>
</section>
@@ -84,25 +71,6 @@ extra_js:
</div>
<script>
let map;
const markers = {};
function initMap() {
map = L.map('leader-map').setView([20, 0], 2);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
}
function addMarker(user, location) {
if (markers[user] || !map) return;
const info = locationData[user];
if (info && info.lat && info.lon) {
const m = L.marker([info.lat, info.lon]).addTo(map);
m.bindPopup(`<a href="https://github.com/${user}" target="_blank">${user}</a><br>${location}`);
markers[user] = m;
}
}
function sortTable(col) {
const table = document.getElementById('leaderboard-table');
const tbody = table.tBodies[0];
@@ -127,38 +95,19 @@ document.querySelectorAll('#leaderboard-table th').forEach((th, i) => {
});
let contributors = {};
let locationData = {};
let profileData = {};
Promise.all([
fetch('/assets/data/contributors.json').then(r => r.json()),
fetch('/assets/data/locations.json').then(r => r.json()),
fetch('/assets/data/profiles.json').then(r => r.json()).catch(() => ({}))
]).then(([cData, lData, pData]) => {
contributors = cData;
locationData = lData;
profileData = pData;
const locUsers = Object.keys(lData);
if (locUsers.length) {
initMap();
locUsers.forEach(u => {
const info = lData[u];
if (info.lat && info.lon) {
const m = L.marker([info.lat, info.lon]).addTo(map);
m.bindPopup(`<a href="https://github.com/${u}" target="_blank">${u}</a><br>${info.location}`);
markers[u] = m;
}
});
document.getElementById('map-tab').style.display = '';
}
const hash = location.hash.slice(1);
if (hash && contributors[hash]) {
openContributorDrawer(hash);
}
loadProfileData();
setupTabs();
}).catch(err => {
console.error('Failed to load datasets', err);
});
fetch('/assets/data/contributors.json')
.then(r => r.json())
.then(data => {
contributors = data;
const hash = location.hash.slice(1);
if (hash && contributors[hash]) {
openContributorDrawer(hash);
}
loadProfileData();
})
.catch(err => {
console.error('Failed to load contributors dataset', err);
});
attachContributorEvents();
@@ -172,30 +121,13 @@ function attachContributorEvents() {
});
}
function setupTabs() {
document.querySelectorAll('.lb-tab').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.lb-tab').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.lb-pane').forEach(p => p.classList.remove('active'));
btn.classList.add('active');
const pane = document.getElementById(`lb-${btn.dataset.target}-pane`);
pane.classList.add('active');
if (btn.dataset.target === 'map' && map) {
setTimeout(() => map.invalidateSize(), 0);
}
});
});
}
function loadProfileData() {
const rows = document.querySelectorAll('tr[data-contributor]');
rows.forEach((row, index) => {
const user = row.dataset.contributor;
const cached = profileData[user];
if (cached) {
if (!contributors[user]) contributors[user] = {};
contributors[user].profile = cached;
applyProfile(row, cached);
const stored = contributors[user] && contributors[user].profile;
if (stored) {
applyProfile(row, stored);
return;
}
setTimeout(() => {
@@ -208,18 +140,8 @@ function loadProfileData() {
.then(r => (r.ok ? r.json() : null))
.then(data => {
if (!data) return;
profileData[user] = {
location: data.location,
company: data.company,
blog: data.blog,
twitter_username: data.twitter_username,
email: data.email,
site_admin: data.site_admin,
followers: data.followers,
following: data.following
};
if (contributors[user]) contributors[user].profile = profileData[user];
applyProfile(row, profileData[user]);
if (contributors[user]) contributors[user].profile = data;
applyProfile(row, data);
})
.catch(() => {});
}, index * 100);
@@ -233,7 +155,6 @@ function applyProfile(row, data) {
if (data.location && locCell) {
locCell.dataset.sort = data.location;
locCell.innerHTML = `<svg class="meta-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg> ${data.location}`;
addMarker(row.dataset.contributor, data.location);
}
if (data.company && compCell) {
compCell.dataset.sort = data.company;
@@ -297,8 +218,7 @@ function openContributorDrawer(user) {
header.appendChild(infoBox);
content.appendChild(header);
const existing = info.profile || profileData[user];
if (existing) info.profile = existing;
const existing = info.profile;
const load = existing ? Promise.resolve(existing) : fetch(`https://api.github.com/users/${user}`, {
headers: {
'Accept': 'application/vnd.github+json',
@@ -307,17 +227,7 @@ function openContributorDrawer(user) {
}).then(r => r.ok ? r.json() : null);
load.then(async data => {
if (!data) return;
profileData[user] = {
location: data.location,
company: data.company,
blog: data.blog,
twitter_username: data.twitter_username,
email: data.email,
site_admin: data.site_admin,
followers: data.followers,
following: data.following
};
if (!existing) info.profile = profileData[user];
if (!existing) info.profile = data;
if (data.site_admin) {
const badge = document.createElement('span');
badge.className = 'verified-badge';