Skip to content

Commit ed9fe87

Browse files
committed
feat(sponsors): switch to data-driven sponsorships
- Migrates sponsor data from config params to a data-driven structure and updates templates to render sponsors from data - Adds data file for sponsors and a script to fetch active sponsors from Open Collective, plus npm script to run it - Replaces inline sponsor definitions with tiered data-driven rendering (platinum, gold, silver, wood, bronze) and supports blocklists - Updates header, index, blog templates and footer to showcase sponsors using the new data format - Reworks FAQ layout and adds a new dynamic navigation for sections - Removes legacy sponsor definitions from previous config and introduces new config for blocklists
1 parent 895ec30 commit ed9fe87

File tree

9 files changed

+610
-103
lines changed

9 files changed

+610
-103
lines changed

config/_default/params.yaml

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,44 @@
11
sponsors:
22
title: "Open Collective"
33
subtitle: "Proud financial backers of Aurelia."
4-
5-
# gold:
6-
# - name: "Hogia"
7-
# url: "https://www.hogia.com/"
8-
# logo: "sponsors/hogia.svg"
9-
# alt: "Hogia"
10-
# width: 517
11-
# height: 128
12-
13-
# silver:
14-
# - name: "Movavi - Screen Recorder"
15-
# url: "https://www.movavi.com/screen-recorder"
16-
# logo: "sponsors/movavi-screen-recorder.svg"
17-
# alt: "Movavi - Screen Recorder"
18-
# width: 553
19-
# height: 128
4+
5+
# Platinum & Gold sponsors get SEO-friendly follow links (rel="noopener" only)
6+
# Platinum sponsors also get: header banner, footer recognition, extra-large homepage placement
7+
platinum:
8+
blocklist: []
9+
10+
gold:
11+
blocklist: []
12+
13+
silver:
14+
blocklist: []
2015

2116
bronze:
22-
iframe_url: "https://opencollective.com/aurelia/tiers/bronze.svg?avatarHeight=64&button=false&width=1024"
23-
17+
avatar_height: 64
18+
blocklist:
19+
- nzcasinoclub
20+
- trustedcasinos360
21+
- no-deposit-bonuses
22+
- usd200-no-deposit-bonus-200-free-spins-real-money
23+
- https-casinosinlicenciaespana-com-casinos-online-europeos
24+
- novecasino-net
25+
- slovenskecasino-net
26+
- zahranicnicasino-net
27+
- casino-magyar
28+
- betpokies
29+
- bestpayidpokies
30+
- guidebook_betwinner_com
31+
- payid-pokies-sites
32+
- apuetasdeportivases
33+
2434
wood:
25-
iframe_url: "https://opencollective.com/aurelia/tiers/wood.svg?avatarHeight=32&button=false"
35+
avatar_height: 32
36+
blocklist:
37+
- hitcasinobonus
38+
- bonusetu
39+
- bonuspart
40+
- nzcasinoclub
41+
- httpscasinostiger-arcom
2642

2743
cta:
2844
text: "Become a Sponsor!"

data/sponsors.json

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
{
2+
"lastUpdated": "2026-01-03T23:37:33.258Z",
3+
"tiers": {
4+
"bronze": [
5+
{
6+
"slug": "payid-pokies-sites",
7+
"name": "PayID Pokies Sites",
8+
"imageUrl": "https://images.opencollective.com/payid-pokies-sites/c9cd78a/logo.png",
9+
"website": "https://au.trustpilot.com/review/payid-casino.net",
10+
"amount": 100
11+
},
12+
{
13+
"slug": "apuetasdeportivases",
14+
"name": "Apuetasdeportivas",
15+
"imageUrl": "https://images.opencollective.com/apuetasdeportivases/4453657/avatar.png",
16+
"website": "https://apuetasdeportivas.es/",
17+
"amount": 100
18+
},
19+
{
20+
"slug": "bestpayidpokies",
21+
"name": "PayID Pokies",
22+
"imageUrl": "https://images.opencollective.com/bestpayidpokies/07fc9d6/logo.png",
23+
"website": "https://au.trustpilot.com/review/bestpayidpokies.net",
24+
"amount": 100
25+
},
26+
{
27+
"slug": "betpokies",
28+
"name": "Online Pokies in Australia",
29+
"imageUrl": "https://images.opencollective.com/betpokies/147f64c/avatar.png",
30+
"website": "https://au.trustpilot.com/review/betpokies.com",
31+
"amount": 100
32+
},
33+
{
34+
"slug": "dashtickets-new-zealand-gambling-magazine",
35+
"name": "DashTickets New Zealand gambling magazine",
36+
"imageUrl": "https://images.opencollective.com/dashtickets-new-zealand-gambling-magazine/275e4d0/logo.png",
37+
"website": "https://dashtickets.nz/",
38+
"amount": 100
39+
},
40+
{
41+
"slug": "igutech",
42+
"name": "igutech",
43+
"imageUrl": "https://images.opencollective.com/igutech/f182ca2/avatar.png",
44+
"website": "https://www.igutech.com/",
45+
"amount": 100
46+
},
47+
{
48+
"slug": "bubbleshooter",
49+
"name": "Bubble Shooter",
50+
"imageUrl": "https://images.opencollective.com/bubbleshooter/15b856c/avatar.png",
51+
"website": "https://www.bubbleshooter.net/",
52+
"amount": 100
53+
},
54+
{
55+
"slug": "drive",
56+
"name": "Drive",
57+
"imageUrl": "https://images.opencollective.com/drive/3437d63/logo.png",
58+
"website": "https://drive.software",
59+
"amount": 100
60+
}
61+
],
62+
"wood": [
63+
{
64+
"slug": "mymoneycomparison",
65+
"name": "Mymoneycomparison.com",
66+
"imageUrl": "https://images.opencollective.com/mymoneycomparison/93c0e0e/avatar.png",
67+
"website": "https://www.mymoneycomparison.com",
68+
"amount": 2
69+
},
70+
{
71+
"slug": "horoskopi",
72+
"name": "Horoskopi",
73+
"imageUrl": "https://images.opencollective.com/horoskopi/02f7c79/logo.png",
74+
"website": "https://horoskopishqip.com/",
75+
"amount": 2
76+
},
77+
{
78+
"slug": "bileta-avioni",
79+
"name": "Bileta Avioni",
80+
"imageUrl": "https://images.opencollective.com/bileta-avioni/6ff12cb/logo.png",
81+
"website": "https://biletaavioni.al/",
82+
"amount": 2
83+
},
84+
{
85+
"slug": "guest-95ee8b43",
86+
"name": "Michele",
87+
"imageUrl": "https://images.opencollective.com/guest-95ee8b43/avatar.png",
88+
"website": null,
89+
"amount": 5
90+
},
91+
{
92+
"slug": "socialwick",
93+
"name": "SocialWick",
94+
"imageUrl": "https://images.opencollective.com/socialwick/e244614/logo.png",
95+
"website": "https://www.socialwick.com/instagram/followers",
96+
"amount": 2
97+
},
98+
{
99+
"slug": "roemhildtg",
100+
"name": "Gregg Roemhildt",
101+
"imageUrl": "https://images.opencollective.com/roemhildtg/5e656d7/avatar.png",
102+
"website": null,
103+
"amount": 2
104+
},
105+
{
106+
"slug": "guest-ba66dc1f",
107+
"name": "Artur Erotschkin",
108+
"imageUrl": "https://images.opencollective.com/guest-ba66dc1f/avatar.png",
109+
"website": null,
110+
"amount": 5
111+
},
112+
{
113+
"slug": "david-morris",
114+
"name": "David Morris",
115+
"imageUrl": "https://images.opencollective.com/david-morris/avatar.png",
116+
"website": null,
117+
"amount": 20
118+
},
119+
{
120+
"slug": "ivan-dolgintsev",
121+
"name": "Ivan Dolgintsev",
122+
"imageUrl": "https://images.opencollective.com/ivan-dolgintsev/cc1f51d/avatar.png",
123+
"website": null,
124+
"amount": 5
125+
},
126+
{
127+
"slug": "sayan751",
128+
"name": "Sayan",
129+
"imageUrl": "https://images.opencollective.com/sayan751/8d46263/avatar.png",
130+
"website": "https://scattered-notes.netlify.com/",
131+
"amount": 5
132+
},
133+
{
134+
"slug": "brandonwittwer",
135+
"name": "Brandon Wittwer",
136+
"imageUrl": "https://images.opencollective.com/brandonwittwer/60f05fc/avatar.png",
137+
"website": "https://www.brandonwittwer.com",
138+
"amount": 2
139+
},
140+
{
141+
"slug": "steven_pena",
142+
"name": "Steven Pena",
143+
"imageUrl": "https://images.opencollective.com/steven_pena/8d98a38/avatar.png",
144+
"website": "https://twitter.com/steven_pena",
145+
"amount": 3
146+
},
147+
{
148+
"slug": "graycrow",
149+
"name": "Dimitry Panchenko",
150+
"imageUrl": "https://images.opencollective.com/graycrow/avatar.png",
151+
"website": null,
152+
"amount": 10
153+
},
154+
{
155+
"slug": "rokadias",
156+
"name": "Saqib Rokadia",
157+
"imageUrl": "https://images.opencollective.com/rokadias/e521d81/avatar.png",
158+
"website": "https://invioinc.com/",
159+
"amount": 2
160+
},
161+
{
162+
"slug": "dwaynecharrington",
163+
"name": "Dwayne Charrington",
164+
"imageUrl": "https://images.opencollective.com/dwaynecharrington/dcffa44/avatar.png",
165+
"website": "https://ilikekillnerds.com",
166+
"amount": 2
167+
}
168+
],
169+
"stone": [
170+
{
171+
"slug": "guest-b92d79c1",
172+
"name": "cavalix",
173+
"imageUrl": "https://images.opencollective.com/guest-b92d79c1/avatar.png",
174+
"website": null,
175+
"amount": 20
176+
}
177+
]
178+
}
179+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"scripts": {
66
"dev": "hugo serve -D -F --ignoreCache",
77
"build": "hugo --minify",
8-
"start": "hugo serve -D -F --ignoreCache"
8+
"start": "hugo serve -D -F --ignoreCache",
9+
"fetch-sponsors": "node scripts/fetch-sponsors.js"
910
},
1011
"devDependencies": {
1112
"@tailwindcss/cli": "^4.0.0-beta.7",

scripts/fetch-sponsors.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
const OPENCOLLECTIVE_API = 'https://api.opencollective.com/graphql/v2';
7+
const COLLECTIVE_SLUG = 'aurelia';
8+
const OUTPUT_PATH = path.join(__dirname, '..', 'data', 'sponsors.json');
9+
10+
const QUERY = `
11+
query {
12+
collective(slug: "${COLLECTIVE_SLUG}") {
13+
orders(status: ACTIVE, limit: 500) {
14+
nodes {
15+
status
16+
frequency
17+
amount { value }
18+
fromAccount {
19+
slug
20+
name
21+
imageUrl
22+
website
23+
}
24+
tier {
25+
slug
26+
}
27+
}
28+
}
29+
}
30+
}
31+
`;
32+
33+
async function fetchActiveSponsors() {
34+
const response = await fetch(OPENCOLLECTIVE_API, {
35+
method: 'POST',
36+
headers: {
37+
'Content-Type': 'application/json',
38+
},
39+
body: JSON.stringify({ query: QUERY }),
40+
});
41+
42+
if (!response.ok) {
43+
throw new Error(`HTTP error! status: ${response.status}`);
44+
}
45+
46+
const data = await response.json();
47+
48+
if (data.errors) {
49+
throw new Error(data.errors[0].message);
50+
}
51+
52+
return data.data.collective.orders.nodes;
53+
}
54+
55+
function groupByTier(orders) {
56+
const tiers = {};
57+
const seen = new Set();
58+
59+
for (const order of orders) {
60+
const tierSlug = order.tier?.slug || 'unknown';
61+
const accountSlug = order.fromAccount.slug;
62+
63+
// Dedupe sponsors who may have multiple active orders
64+
const key = `${tierSlug}:${accountSlug}`;
65+
if (seen.has(key)) continue;
66+
seen.add(key);
67+
68+
if (!tiers[tierSlug]) {
69+
tiers[tierSlug] = [];
70+
}
71+
tiers[tierSlug].push({
72+
slug: order.fromAccount.slug,
73+
name: order.fromAccount.name,
74+
imageUrl: order.fromAccount.imageUrl,
75+
website: order.fromAccount.website,
76+
amount: order.amount.value,
77+
});
78+
}
79+
80+
return tiers;
81+
}
82+
83+
async function main() {
84+
console.log('Fetching active sponsors from OpenCollective...');
85+
86+
const orders = await fetchActiveSponsors();
87+
console.log(` Found ${orders.length} active subscriptions`);
88+
89+
const tiers = groupByTier(orders);
90+
91+
for (const [tier, sponsors] of Object.entries(tiers)) {
92+
console.log(` ${tier}: ${sponsors.length} sponsors`);
93+
}
94+
95+
const output = {
96+
lastUpdated: new Date().toISOString(),
97+
tiers,
98+
};
99+
100+
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2));
101+
console.log(`Sponsors saved to ${OUTPUT_PATH}`);
102+
}
103+
104+
main().catch((error) => {
105+
console.error('Failed to fetch sponsors:', error);
106+
process.exit(1);
107+
});

0 commit comments

Comments
 (0)