Skip to content

Commit c967789

Browse files
boneskullMunter
authored andcommitted
fetch sponsors at build time, show ALL non-skeevy sponsors; closes #4271 (#4272)
* Show all sponsors on site - change ordering: sponsors, then backers - blacklist bad actors - rename `default.html` to `default.liquid`, because it's a Liquid template. - fiddles with the CSS a bit - do not attempt to display a link if there is no website * use smaller imgs for backers * Fetch all open collective sponsor images to save their dimensions * Reworked avatars. LEss reflows due to image dimensions. Smoother loading animation that doesn't wait for all images. Progressive enhanced * Add standardised lazy loading to all images * Set height on badges to avoid page reflows * Add node version specification in .nvmrc to get netlify up to date * Move avatars javascript to external file for better development experience Co-authored-by: Peter Müller <[email protected]>
1 parent 19f1841 commit c967789

13 files changed

+1302
-1152
lines changed

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
12

docs/_data/blacklist.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[
2+
"cheap-writing-service",
3+
"emailmarketingservices-io",
4+
"device-tricks1",
5+
"my-true-media",
6+
"yiannakis-ttafounas-ttafounas",
7+
"writerseperhour",
8+
"casinotop-com",
9+
"casino-topp",
10+
"casinoutanreg",
11+
"supercazino-ro",
12+
"igor-noskov",
13+
"blue-link-seo",
14+
"casino-online",
15+
"domywriting",
16+
"writemypaper4me",
17+
"trust-my-paper",
18+
"seowebsitetraffic-net",
19+
"pfannen-test",
20+
"mochajs"
21+
]

docs/_data/supporters.js

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env node
2+
'use strict';
3+
4+
const debug = require('debug')('mocha:docs:data:supporters');
5+
const needle = require('needle');
6+
const imageSize = require('image-size');
7+
const blacklist = new Set(require('./blacklist.json'));
8+
9+
const API_ENDPOINT = 'https://api.opencollective.com/graphql/v2';
10+
11+
const query = `query account($limit: Int, $offset: Int, $slug: String) {
12+
account(slug: $slug) {
13+
orders(limit: $limit, offset: $offset) {
14+
limit
15+
offset
16+
totalCount
17+
nodes {
18+
fromAccount {
19+
name
20+
slug
21+
website
22+
imgUrlMed: imageUrl(height:64)
23+
imgUrlSmall: imageUrl(height:32)
24+
type
25+
}
26+
totalDonations {
27+
value
28+
}
29+
createdAt
30+
}
31+
}
32+
}
33+
}`;
34+
35+
const graphqlPageSize = 1000;
36+
37+
const nodeToSupporter = node => ({
38+
name: node.fromAccount.name,
39+
slug: node.fromAccount.slug,
40+
website: node.fromAccount.website,
41+
imgUrlMed: node.fromAccount.imgUrlMed,
42+
imgUrlSmall: node.fromAccount.imgUrlSmall,
43+
firstDonation: node.createdAt,
44+
totalDonations: node.totalDonations.value * 100,
45+
type: node.fromAccount.type
46+
});
47+
48+
/**
49+
* Retrieves donation data from OC
50+
*
51+
* Handles pagination
52+
* @param {string} slug - Collective slug to get donation data from
53+
* @returns {Promise<Object[]>} Array of raw donation data
54+
*/
55+
const getAllOrders = async (slug = 'mochajs') => {
56+
let allOrders = [];
57+
const variables = {limit: graphqlPageSize, offset: 0, slug};
58+
59+
// Handling pagination if necessary (2 pages for ~1400 results in May 2019)
60+
while (true) {
61+
const result = await needle(
62+
'post',
63+
API_ENDPOINT,
64+
{query, variables},
65+
{json: true}
66+
);
67+
const orders = result.body.data.account.orders.nodes;
68+
allOrders = [...allOrders, ...orders];
69+
variables.offset += graphqlPageSize;
70+
if (orders.length < graphqlPageSize) {
71+
debug('retrieved %d orders', allOrders.length);
72+
return allOrders;
73+
} else {
74+
debug(
75+
'loading page %d of orders...',
76+
Math.floor(variables.offset / graphqlPageSize)
77+
);
78+
}
79+
}
80+
};
81+
82+
module.exports = async () => {
83+
const orders = await getAllOrders();
84+
// Deduplicating supporters with multiple orders
85+
const uniqueSupporters = new Map();
86+
87+
const supporters = orders
88+
.map(nodeToSupporter)
89+
.filter(supporter => !blacklist.has(supporter.slug))
90+
.reduce((supporters, supporter) => {
91+
if (uniqueSupporters.has(supporter.slug)) {
92+
// aggregate donation totals
93+
uniqueSupporters.get(supporter.slug).totalDonations +=
94+
supporter.totalDonations;
95+
return supporters;
96+
}
97+
uniqueSupporters.set(supporter.slug, supporter);
98+
return [...supporters, supporter];
99+
}, [])
100+
.sort((a, b) => b.totalDonations - a.totalDonations)
101+
.reduce(
102+
(supporters, supporter) => {
103+
if (supporter.type === 'INDIVIDUAL') {
104+
supporters.backers.push({
105+
...supporter,
106+
avatar: supporter.imgUrlSmall
107+
});
108+
} else {
109+
supporters.sponsors.push({...supporter, avatar: supporter.imgUrlMed});
110+
}
111+
return supporters;
112+
},
113+
{sponsors: [], backers: []}
114+
);
115+
116+
// Fetch images for sponsors and save their image dimensions
117+
await Promise.all(
118+
supporters.sponsors.map(async sponsor => {
119+
for await (const chunk of needle.get(sponsor.avatar)) {
120+
sponsor.dimensions = imageSize(chunk);
121+
break;
122+
}
123+
})
124+
);
125+
126+
debug(
127+
'found %d valid backers and %d valid sponsors (%d total)',
128+
supporters.backers.length,
129+
supporters.sponsors.length,
130+
supporters.backers.length + supporters.sponsors.length
131+
);
132+
return supporters;
133+
};

docs/_includes/backers.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs/_includes/default.html renamed to docs/_includes/default.liquid

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
66
<title>{{ title }}</title>
7-
<link
8-
rel="preload"
9-
href="https://opencollective.com/static/images/user.svg"
10-
as="image"
11-
crossorigin="anonymous"
12-
/>
137
<link rel="stylesheet" href="css/normalize.css" />
148
<link rel="stylesheet" href="css/style.css" />
159
<link rel="stylesheet" href="css/prism.css" />
@@ -22,7 +16,7 @@
2216
<header id="_header">
2317
<h1>
2418
<a href="/">
25-
<img id="mocha-logo" src="/images/mocha-logo.svg" alt="Mocha logo" />
19+
<img id="mocha-logo" loading="eager" src="/images/mocha-logo.svg" alt="Mocha logo" />
2620
</a>
2721
</h1>
2822
<p id="tag"><em>simple</em>, <em>flexible</em>, <em>fun</em></p>
@@ -36,7 +30,7 @@ <h1>
3630
rel="external noopener"
3731
title="Mocha is sponsored by Matomo"
3832
>
39-
<img src="images/matomo-logo.png?trim" alt="Matomo logo" />
33+
<img src="images/matomo-logo.png?trim" loading="lazy" alt="Matomo logo" />
4034
</a>
4135
<a
4236
title="Mocha is an OpenJS Foundation Project"
@@ -45,6 +39,7 @@ <h1>
4539
>
4640
<img
4741
src="/images/openjsf-logo.svg"
42+
loading="lazy"
4843
width="300"
4944
height="94"
5045
alt="OpenJS Foundation Logo"
@@ -56,7 +51,7 @@ <h1>
5651
title="Mocha is sponsored by Wallaby"
5752
>
5853
<figure id="wallaby-logo">
59-
<img src="images/wallaby-logo.png?trim" alt="Wallaby logo" />
54+
<img src="images/wallaby-logo.png?trim" loading="lazy" alt="Wallaby logo" />
6055
<figcaption>Wallaby</figcaption>
6156
</figure>
6257
</a>
@@ -153,7 +148,7 @@ <h1>
153148
<div class="netlify-badge">
154149
<a href="https://www.netlify.com">
155150
<img
156-
src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
151+
src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" loading="lazy"
157152
/>
158153
</a>
159154
</div>

docs/_includes/sponsors.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

docs/_includes/supporters.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## Sponsors
2+
3+
Use Mocha at Work? Ask your manager or marketing team if they'd help [support](https://opencollective.com/mochajs#support) our project. Your company's logo will also be displayed on [npmjs.com](http://npmjs.com/package/mocha) and our [GitHub repository](https://github.com/mochajs/mocha#sponsors).
4+
5+
<ul class="image-list" id="sponsors">
6+
{%- for supporter in supporters.sponsors -%}
7+
<li>
8+
{%- if supporter.website -%}
9+
<a href="{{ supporter.website }}" target="_blank" rel="noopener" title="{{ supporter.name }}">
10+
{%- endif -%}
11+
<img src="{{ supporter.avatar }}" width="{{ supporter.dimensions.width }}" height="{{ supporter.dimensions.height }}" alt="{{ supporter.name }}" />
12+
{%- if supporter.website -%}
13+
</a>
14+
{%- endif -%}
15+
</li>
16+
{%- endfor -%}
17+
</ul>
18+
19+
## Backers
20+
21+
Find Mocha helpful? Become a [backer](https://opencollective.com/mochajs#support) and support Mocha with a monthly donation.
22+
23+
<ul class="image-list faded-images" id="backers">
24+
{%- for supporter in supporters.backers -%}
25+
<li>
26+
{%- if supporter.website -%}
27+
<a href="{{ supporter.website }}" target="_blank" rel="noopener" title="{{ supporter.name }}">
28+
{%- endif -%}
29+
<img src="{{ supporter.avatar }}" alt="{{ supporter.name }}" />
30+
{%- if supporter.website -%}
31+
</a>
32+
{%- endif -%}
33+
</li>
34+
{%- endfor -%}
35+
</ul>
36+
37+
<script src="/js/avatars.js"></script>

docs/css/style.css

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,42 +74,57 @@ nav.badges a + a {
7474
margin-left: 3px;
7575
}
7676

77-
.image-list {
77+
ul.image-list {
7878
overflow: hidden;
7979
text-align: center;
80+
list-style: none;
81+
column-count: 1;
82+
padding: 0;
83+
margin: 0;
8084
}
8185

82-
.image-list a {
86+
ul.image-list li {
87+
border-bottom: none;
8388
display: inline-block;
84-
margin: 6px;
89+
margin: 0 4px 0 4px;
90+
max-height: 64px;
91+
padding: 0;
92+
line-height: 0;
8593
}
8694

87-
.image-list a img {
95+
ul.image-list li a {
96+
display: inline-block;
97+
}
98+
99+
ul.image-list li img {
100+
margin: 0;
101+
padding: 0;
88102
display: block;
89-
height: 64px;
103+
max-height: 64px;
90104
}
91105

92-
.faded-images {
93-
background-color: #ddd;
94-
border: 1px solid;
95-
border-color: #ddd #ddd #ccc;
96-
border-radius: 3px;
97-
padding: 1em;
98-
box-shadow: inset 0 0 10px #ccc;
106+
ul#backers.image-list li img {
107+
width: 32px;
108+
height: 32px;
109+
overflow: hidden;
99110
}
100111

101-
.faded-images img {
102-
opacity: 0;
103-
transition: opacity 0.3s;
112+
.faded-image {
113+
background-color: rgba(0, 0, 0, 0.05);
104114
}
105115

106-
.faded-images.is-loaded img {
107-
opacity: 1;
116+
.faded-image.is-loaded {
117+
background-color: rgba(0, 0, 0, 0);
118+
transition: background-color 0.3s;
108119
}
109120

110-
#_backers a img {
111-
background: url(/images/backer-background.svg?inline) center center no-repeat;
112-
width: 64px;
121+
.faded-image img {
122+
opacity: 0;
123+
transition: opacity 0.1s;
124+
}
125+
126+
.faded-image.is-loaded img {
127+
opacity: 1;
113128
}
114129

115130
h2 {

docs/images/backer-background.svg

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)