diff --git a/.gitignore b/.gitignore index 911ff19cab..38a69c939b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,9 @@ _output /site/.sessions /site/static/svelte-app.json /site/static/contributors.jpg +/site/static/donors.jpg /site/static/workers /site/scripts/svelte-app /site/scripts/community /site/src/routes/_contributors.js +/site/src/routes/_donors.js diff --git a/site/scripts/get_donors.js b/site/scripts/get_donors.js new file mode 100644 index 0000000000..9e26391195 --- /dev/null +++ b/site/scripts/get_donors.js @@ -0,0 +1,63 @@ +import 'dotenv/config'; +import fs from 'fs'; +import fetch from 'node-fetch'; +import Jimp from 'jimp'; +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + + +const force = process.env.FORCE_UPDATE === 'true'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +process.chdir(__dirname); + +const outputFile = `../src/routes/_donors.js`; +if (!force && fs.existsSync(outputFile)) { + console.info(`[update/donors] ${outputFile} exists. Skipping`); + process.exit(0); +} + +const SIZE = 64; + +async function main() { + const res = await fetch('https://opencollective.com/svelte/members/all.json'); + const donors = await res.json(); + + const unique = new Map(); + donors.forEach(d => unique.set(d.profile, d)); + + let backers = [...unique.values()] + .filter(({ role }) => role === 'BACKER') + .sort((a, b) => b.totalAmountDonated - a.totalAmountDonated); + + const included = []; + for (let i = 0; i < backers.length; i += 1) { + const backer = backers[i]; + console.log(`${i} / ${backers.length}: ${backer.name}`); + + try { + const image_data = await fetch(backer.image); + const buffer = await image_data.arrayBuffer(); + const image = await Jimp.read(buffer); + image.resize(SIZE, SIZE); + included.push({ backer, image }); + } catch( err) { + console.log(`Skipping ${backer.name}: no image data`); + } + } + + const sprite = new Jimp(SIZE * included.length, SIZE); + for (let i = 0; i < included.length; i += 1) { + sprite.composite(included[i].image, i * SIZE, 0); + } + + await sprite.quality(80).write(`../static/donors.jpg`); + // TODO: Optimizing the static/donors.jpg image should probably get automated as well + console.log('remember to additionally optimize the resulting /static/donors.jpg image file via e.g. https://squoosh.app '); + + const str = `[\n\t${included.map(a => `${JSON.stringify(a.backer.name)}`).join(',\n\t')}\n]`; + + fs.writeFileSync(outputFile, `export default ${str};`); +} + +main(); diff --git a/site/scripts/update.js b/site/scripts/update.js index 1e8789e67c..724c0d1be8 100644 --- a/site/scripts/update.js +++ b/site/scripts/update.js @@ -4,5 +4,6 @@ sh.env['FORCE_UPDATE'] = process.argv.includes('--force=true'); Promise.all([ sh.exec('node ./scripts/get_contributors.js'), + sh.exec('node ./scripts/get_donors.js'), sh.exec('node ./scripts/update_template.js') ]); diff --git a/site/src/routes/_components/Donors.svelte b/site/src/routes/_components/Donors.svelte new file mode 100644 index 0000000000..dc1f7ffcc8 --- /dev/null +++ b/site/src/routes/_components/Donors.svelte @@ -0,0 +1,27 @@ + + + + +{#each donors as donor, i} + + {donor} + +{/each} diff --git a/site/src/routes/index.svelte b/site/src/routes/index.svelte index 3c84d6ea15..4290c99778 100644 --- a/site/src/routes/index.svelte +++ b/site/src/routes/index.svelte @@ -1,6 +1,7 @@