Skip to content

Instantly share code, notes, and snippets.

@kang8
Last active September 18, 2023 00:49
Show Gist options
  • Save kang8/051e9dcc302d87d11d9b510f21e29802 to your computer and use it in GitHub Desktop.
Save kang8/051e9dcc302d87d11d9b510f21e29802 to your computer and use it in GitHub Desktop.
Show all contributions by year
// ==UserScript==
// @name show all contributions by year
// @namespace https://github.com/kang8
// @version 0.0.1
// @description 在 GitHub profile 页面以年份展示自用户创建以来所有的 contributions
// @description Show all contributions by year since the user was created in the GitHub profile page
// @author kang
// @match https://github.com/*
// @grant none
// @run-at document-end
// ==/UserScript==
;(function () {
'use strict'
const pathArr = location.pathname.split('/')
if (pathArr.length === 2 && pathArr[1] !== '') {
const userId = pathArr[1]
const contributionsLastYear = document.querySelector('div.js-yearly-contributions > div:nth-child(1)')
const contributionsAllYearsDiv = document.createElement('div')
contributionsAllYearsDiv.className = 'position-relative border'
contributionsAllYearsDiv.id = 'contributions-all-years'
contributionsLastYear.after(contributionsAllYearsDiv)
const details = document.createElement('details')
details.className = 'py-3'
details.innerHTML = '<summary class="px-3">All contributions by year</summary>'
contributionsAllYearsDiv.append(details)
const totalYearsCreated = document.querySelectorAll('div.js-profile-timeline-year-list > ul > li').length
const thisYear = new Date().getFullYear()
for (let index = 0; index < totalYearsCreated; index++) {
const currentYear = thisYear - index
fetch(`/users/${userId}/contributions?from=${currentYear}-1-01&to=${currentYear}-12-31`, {
method: 'GET',
})
.then((response) => response.text())
.then((data) => {
const contributionsDiv = document.createRange().createContextualFragment(data)
const contributionInfo = contributionsDiv.querySelector('div > div:nth-child(1) > h2').textContent
const svgCalendarGraph = contributionsDiv.querySelector('div > div:nth-child(1) > div > div')
svgCalendarGraph.querySelector('div > div.float-left').innerHTML = contributionInfo
if (currentYear !== thisYear) {
svgCalendarGraph.classList.add('border-top')
}
insertAndOrderToDetails(svgCalendarGraph, details, currentYear)
})
}
}
})()
/**
* @param {Element} graph
* @param {HTMLDetailsElement} details
* @param {number} currentYear
*/
function insertAndOrderToDetails(graph, details, currentYear) {
let contributionsCalendarAllYear = Array.from(details.querySelectorAll('div.js-calendar-graph'))
if (contributionsCalendarAllYear.length === 0) {
details.append(graph)
} else if (contributionsCalendarAllYear.length === 1) {
const firstCalendarYear = getYearByContributionsCalendar(contributionsCalendarAllYear[0])
if (currentYear > firstCalendarYear) {
contributionsCalendarAllYear[0].before(graph)
} else {
contributionsCalendarAllYear[0].after(graph)
}
} else {
for (let index = 0; index < contributionsCalendarAllYear.length - 1; index++) {
const currentYearInCalendar = getYearByContributionsCalendar(contributionsCalendarAllYear[index])
const nextYearInCalendar = getYearByContributionsCalendar(contributionsCalendarAllYear[index + 1])
if (currentYear > currentYearInCalendar) {
contributionsCalendarAllYear[index].before(graph)
break
} else if (currentYear > nextYearInCalendar) {
contributionsCalendarAllYear[index].after(graph)
break
} else if (index === contributionsCalendarAllYear.length - 2 && currentYear < nextYearInCalendar) {
contributionsCalendarAllYear[contributionsCalendarAllYear.length - 1].after(graph)
}
}
}
}
/**
* @param {number|Element} childNode
* @returns {number}
*/
function getYearByContributionsCalendar(childNode) {
return childNode.querySelector('div.float-left').textContent.replace(/\s/g, '').slice(-4)
}
@wey-gu
Copy link

wey-gu commented Sep 11, 2023

Awesome! This work deserves a repo/release in the extension market!

@kang8
Copy link
Author

kang8 commented Sep 18, 2023

Thanks!

I have indeed published this script on Greasy Fork.

In addition, this script has been moved to my .dotfile for maintenance, because I personally prefer github repo rather than gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment