Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: thanking contributor (#2632) #2635

Merged
merged 10 commits into from
Jan 31, 2020
4 changes: 4 additions & 0 deletions layouts/css/_utils.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@
white-space: nowrap;
border: none;
}

.hidden {
display: none;
}
32 changes: 32 additions & 0 deletions layouts/css/page-modules/_contributor-card.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.contributor-card {
display: flex;
align-items: center;
min-height: 42px;
width: 300px;
padding: 1.5em 1em;
margin: 1em auto;
border: 1px solid $white;
border-radius: 3px;

> a {
height: 40px;
width: 40px;
flex: 0 0 auto;
}

p {
padding-left: 1em;
margin: 0;
flex: 1 1 1px;
}

.spinner-border {
margin: 5px;
}
}

@media (max-width: 350px) {
.contributor-card {
width: auto;
}
}
4 changes: 0 additions & 4 deletions layouts/css/page-modules/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ header {
margin: 0;
padding: 0;

&.hidden {
display: none;
}

a {
color: $light-gray2;
}
Expand Down
15 changes: 15 additions & 0 deletions layouts/css/page-modules/_jsfoundation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@
margin-left: auto;
}

.thanking-contributor {
max-width: 300px;
display: flex;
align-items: center;
padding: .5em 1em;
margin-top: 1em;
border: 1px solid $white;
border-radius: 3px;

img {
border-radius: 50%;
margin-right: 1em;
}
}

@media screen and (max-width: 700px) {
.issue-link-container {
flex-wrap: wrap;
Expand Down
18 changes: 18 additions & 0 deletions layouts/css/page-modules/spinner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// borrowed from Bootstrap
@keyframes spinner-border {
to {
transform: rotate(360deg);
}
}

.spinner-border {
box-sizing: border-box;
display: inline-block;
width: 2rem;
height: 2rem;
vertical-align: text-bottom;
border: .25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: spinner-border .75s linear infinite;
}
2 changes: 2 additions & 0 deletions layouts/css/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
@import "page-modules/prev-next-navigation";
@import "page-modules/release-schedule";
@import "page-modules/resources";
@import "page-modules/contributor-card";
@import "page-modules/spinner";
@import "vendor/prism-tomorrow";

article a {
Expand Down
15 changes: 15 additions & 0 deletions layouts/partials/contributor-card.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="contributor-card">
<a href="#" rel="nofollow noopener noreferrer">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
<img id="contributor-avatar" class="hidden" src="/static/images/logos/js-green.svg" alt="Avatar of a Node.js contributor" width="40" height="40">
</a>

<p>
Thank you <a href="#" id="contributor-username" rel="nofollow noopener noreferrer">username</a> for being a <a href="https://github.com/nodejs/node/graphs/contributors" rel="nofollow noopener noreferrer" title="List of all Node.js contributors">Node.js contributor</a>
<a href="https://github.com/nodejs/node/graphs/contributors" rel="nofollow noopener noreferrer">
<strong id="contributor-contributions">0 contributions</strong>
</a>
</p>
</div>
3 changes: 3 additions & 0 deletions layouts/partials/footer.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<p>
<a href="https://raw.githubusercontent.com/nodejs/node/master/LICENSE">Node.js Project Licensing Information</a>.
</p>

{{> contributor-card }}

</div>
</div>

Expand Down
1 change: 1 addition & 0 deletions layouts/partials/html-head.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
<link rel="dns-prefetch" href="https://api.github.com">

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600&display=fallback">
<link rel="stylesheet" href="/static/css/styles.css">
Expand Down
129 changes: 129 additions & 0 deletions static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,135 @@
})
})()

;(function () {
var contributorCard = document.querySelector('.contributor-card')

if (!contributorCard) {
return
}

var contributorAvatar = contributorCard.querySelector('#contributor-avatar')
var contributorUsername = contributorCard.querySelector('#contributor-username')
var contributorContributions = contributorCard.querySelector('#contributor-contributions')
var loadingSpinner = contributorCard.querySelector('.spinner-border')

if (window.IntersectionObserver) {
var observer = new window.IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.intersectionRatio > 0.5) {
// In viewport, fetch a random contributor
fetchRandomContributor()

observer.unobserve(entry.target)
}
})
},
{ threshold: 0.5 }
)

observer.observe(document.querySelector('footer'))
} else {
// Does not support IntersectionObserver
fetchRandomContributor()
}

function fetchRandomContributor () {
var maxContributors
var fetchDate
var needToRefetch = false

if (window.localStorage) {
maxContributors = window.localStorage.getItem('max_contributors')
fetchDate = parseInt(window.localStorage.getItem('fetch_date'), 10)
}

// If fetch date is a month old (2592000000 ms === 30 days)
if (Date.now() - fetchDate >= 2592000000) {
needToRefetch = true
}

// If localStorage and data is less than 1 month old, fetch 1 time
if (maxContributors && !needToRefetch) {
getContributor(Math.floor(Math.random() * Math.floor(parseInt(maxContributors))) + 1)
} else {
getMaxContributors(function (randomPage, lastPage) {
getContributor(randomPage)

if (window.localStorage) {
window.localStorage.setItem('max_contributors', lastPage)
}
})
}
}

function getMaxContributors (callback) {
var xhr = new window.XMLHttpRequest()
xhr.open('GET', 'https://api.github.com/repos/nodejs/node/contributors?per_page=1', true)

xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// Get Headers Links last page to generate a random contributor
var links = linkParser(xhr.getResponseHeader('Link'))
var randomPage = Math.floor(Math.random() * Math.floor(parseInt(links.last.page, 10))) + 1

if (window.localStorage) {
window.localStorage.setItem('fetch_date', Date.now())
}
callback(randomPage, links.last.page)
} else {
return contributorCard.parentNode.removeChild(contributorCard)
}
}
}

xhr.send()
}

function getContributor (randomPage) {
var xhr = new window.XMLHttpRequest()
xhr.open('GET', 'https://api.github.com/repos/nodejs/node/contributors?per_page=1&page=' + randomPage, true)

xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var contributor = JSON.parse(xhr.responseText)[0]

// Remove loading spinner and show avatar
loadingSpinner.parentNode.removeChild(loadingSpinner)
contributorAvatar.classList.remove('hidden')
// Set new values
contributorAvatar.src = contributor.avatar_url + '&s=80'
contributorAvatar.parentElement.href = contributor.html_url
contributorUsername.textContent = contributor.login
contributorUsername.href = contributor.html_url
contributorContributions.textContent = contributor.contributions + ' contributions'
contributorContributions.parentElement.href = 'https://github.com/nodejs/node/commits?author=' + contributor.login
} else {
return contributorCard.parentNode.removeChild(contributorCard)
}
}
}

xhr.send()
}

function linkParser (linkHeader) {
var regex = /<([^?]+\?per_page=1&[a-z]+=([\d]+))>;[\s]*rel="([a-z]+)"/g
var array = []
var object = {}

while ((array = regex.exec(linkHeader)) !== null) {
object[array[3]] = {
url: array[1],
page: array[2]
}
}

return object
}
})()

;(function (d, n) {
'use strict'

Expand Down