This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon-website.git
The following commit(s) were added to refs/heads/master by this push:
new 3d3eaae5 feat: download github avatars (#28)
3d3eaae5 is described below
commit 3d3eaae5cd9eeef609c655f0b730d62cf9f7c170
Author: Laffery <[email protected]>
AuthorDate: Fri Jan 16 09:59:58 2026 +0800
feat: download github avatars (#28)
---
.gitignore | 1 +
README.md | 2 +
package.json | 4 +-
pnpm-lock.yaml | 303 ++++++++++++++++++++-
.../home/components/team/team.component.html | 2 +-
src/app/routers/team/team.component.html | 4 +-
src/load-avatars.ts | 95 +++++++
7 files changed, 403 insertions(+), 8 deletions(-)
diff --git a/.gitignore b/.gitignore
index 6e3ac072..eca1e73f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
# See
https://docs.github.com/get-started/getting-started-with-git/ignoring-files for
more about ignoring files.
# Compiled output
+/src/assets/avatars/
/src/assets/metadata/
/src/assets/docs/
/src/sitemap.xml
diff --git a/README.md b/README.md
index 6721aef9..e56f6fd8 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ Run `pnpm install` to install all dependencies.
Run `pnpm start` for a dev server. Navigate to `http://localhost:8801/`. The
application will automatically reload if you change any of the source files.
+> Before starting the dev server, make sure you have run `pnpm avatar` to load
the avatars of the team members.
+
### Build
Run `pnpm build` to build the project. The build artifacts will be stored in
the `dist/` directory.
diff --git a/package.json b/package.json
index 9b83cc2b..702d61de 100644
--- a/package.json
+++ b/package.json
@@ -2,10 +2,11 @@
"name": "paimon-next-website",
"version": "0.0.0",
"scripts": {
+ "avatar": "tsx ./src/load-avatars.ts",
"parse": "cd library/markdown-parser && npm run parse",
"prestart": "npm run parse",
"start": "ng serve --port 8801",
- "prebuild": "npm run parse",
+ "prebuild": "npm run avatar && npm run parse",
"build": "ng build",
"serve:ssr": "node dist/server/server.mjs",
"i18n:extract": "ngx-translate-extract --input ./src --output
./src/assets/i18n/{en,zh}.json -ss -k --clean --format json",
@@ -60,6 +61,7 @@
"prettier-plugin-tailwindcss": "^0.6.6",
"tailwindcss": "^3.4.10",
"tailwindcss-animation-delay": "^2.0.1",
+ "tsx": "^4.21.0",
"typescript": "~5.5.2",
"typescript-eslint": "8.2.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 87bf102a..de756f7d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -62,7 +62,7 @@ importers:
devDependencies:
'@angular-devkit/build-angular':
specifier: ^18.2.2
- version: 18.2.6(5ez4bdpgzwqrz4i7y6zlfrwqqy)
+ version: 18.2.6(af889e1f26053a970339fafa7663b129)
'@angular/cli':
specifier: ^18.2.2
version: 18.2.6([email protected])
@@ -138,6 +138,9 @@ importers:
tailwindcss-animation-delay:
specifier: ^2.0.1
version:
2.0.1([email protected]([email protected](@types/[email protected])([email protected])))
+ tsx:
+ specifier: ^4.21.0
+ version: 4.21.0
typescript:
specifier: ~5.5.2
version: 5.5.4
@@ -1152,6 +1155,12 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
@@ -1164,6 +1173,12 @@ packages:
cpu: [arm64]
os: [android]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
@@ -1176,6 +1191,12 @@ packages:
cpu: [arm]
os: [android]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
@@ -1188,6 +1209,12 @@ packages:
cpu: [x64]
os: [android]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
@@ -1200,6 +1227,12 @@ packages:
cpu: [arm64]
os: [darwin]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
@@ -1212,6 +1245,12 @@ packages:
cpu: [x64]
os: [darwin]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
@@ -1224,6 +1263,12 @@ packages:
cpu: [arm64]
os: [freebsd]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
@@ -1236,6 +1281,12 @@ packages:
cpu: [x64]
os: [freebsd]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
@@ -1248,6 +1299,12 @@ packages:
cpu: [arm64]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
@@ -1260,6 +1317,12 @@ packages:
cpu: [arm]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
@@ -1272,6 +1335,12 @@ packages:
cpu: [ia32]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
@@ -1284,6 +1353,12 @@ packages:
cpu: [loong64]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
@@ -1296,6 +1371,12 @@ packages:
cpu: [mips64el]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
@@ -1308,6 +1389,12 @@ packages:
cpu: [ppc64]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
@@ -1320,6 +1407,12 @@ packages:
cpu: [riscv64]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
@@ -1332,6 +1425,12 @@ packages:
cpu: [s390x]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
@@ -1344,6 +1443,18 @@ packages:
cpu: [x64]
os: [linux]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
@@ -1356,12 +1467,24 @@ packages:
cpu: [x64]
os: [netbsd]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
@@ -1374,6 +1497,18 @@ packages:
cpu: [x64]
os: [openbsd]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
@@ -1386,6 +1521,12 @@ packages:
cpu: [x64]
os: [sunos]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
@@ -1398,6 +1539,12 @@ packages:
cpu: [arm64]
os: [win32]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
@@ -1410,6 +1557,12 @@ packages:
cpu: [ia32]
os: [win32]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/[email protected]':
resolution: {integrity:
sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
@@ -1422,6 +1575,12 @@ packages:
cpu: [x64]
os: [win32]
+ '@esbuild/[email protected]':
+ resolution: {integrity:
sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/[email protected]':
resolution: {integrity:
sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3001,6 +3160,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ [email protected]:
+ resolution: {integrity:
sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
[email protected]:
resolution: {integrity:
sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -3340,6 +3504,9 @@ packages:
resolution: {integrity:
sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
engines: {node: '>= 0.4'}
+ [email protected]:
+ resolution: {integrity:
sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
+
[email protected]:
resolution: {integrity:
sha512-aMgPyjC9W5Mz9tbFU8DcQ7GYMXoFWq633kaWGt4imlcpBWzDIWk7HY7nCSZTCJxyjRaLq9L/NEjMKkZ9gR630Q==}
@@ -4769,6 +4936,9 @@ packages:
resolution: {integrity:
sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
+ [email protected]:
+ resolution: {integrity:
sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
[email protected]:
resolution: {integrity:
sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==}
engines: {node: '>=12'}
@@ -5299,6 +5469,11 @@ packages:
[email protected]:
resolution: {integrity:
sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
+ [email protected]:
+ resolution: {integrity:
sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
[email protected]:
resolution: {integrity:
sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==}
engines: {node: ^16.14.0 || >=18.0.0}
@@ -5680,13 +5855,13 @@ snapshots:
transitivePeerDependencies:
- chokidar
- '@angular-devkit/[email protected](5ez4bdpgzwqrz4i7y6zlfrwqqy)':
+ '@angular-devkit/[email protected](af889e1f26053a970339fafa7663b129)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.6([email protected])
'@angular-devkit/build-webpack':
0.1802.6([email protected])([email protected]([email protected]))([email protected]([email protected]))
'@angular-devkit/core': 18.2.6([email protected])
- '@angular/build': 18.2.6(stdzbpsd2y76kkjxukjo2bjzki)
+ '@angular/build': 18.2.6(38d3034695d993a4a3411ce8e26edddb)
'@angular/compiler-cli':
18.2.6(@angular/[email protected](@angular/[email protected]([email protected])([email protected])))([email protected])
'@babel/core': 7.25.2
'@babel/generator': 7.25.0
@@ -5858,7 +6033,7 @@ snapshots:
'@angular/core': 18.2.6([email protected])([email protected])
tslib: 2.7.0
- '@angular/[email protected](stdzbpsd2y76kkjxukjo2bjzki)':
+ '@angular/[email protected](38d3034695d993a4a3411ce8e26edddb)':
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1802.6([email protected])
@@ -6942,141 +7117,219 @@ snapshots:
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@esbuild/[email protected]':
optional: true
'@esbuild/[email protected]':
optional: true
+ '@esbuild/[email protected]':
+ optional: true
+
'@eslint-community/[email protected]([email protected]([email protected]))':
dependencies:
eslint: 9.11.1([email protected])
@@ -8965,6 +9218,35 @@ snapshots:
'@esbuild/win32-ia32': 0.23.0
'@esbuild/win32-x64': 0.23.0
+ [email protected]:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.2
+ '@esbuild/android-arm': 0.27.2
+ '@esbuild/android-arm64': 0.27.2
+ '@esbuild/android-x64': 0.27.2
+ '@esbuild/darwin-arm64': 0.27.2
+ '@esbuild/darwin-x64': 0.27.2
+ '@esbuild/freebsd-arm64': 0.27.2
+ '@esbuild/freebsd-x64': 0.27.2
+ '@esbuild/linux-arm': 0.27.2
+ '@esbuild/linux-arm64': 0.27.2
+ '@esbuild/linux-ia32': 0.27.2
+ '@esbuild/linux-loong64': 0.27.2
+ '@esbuild/linux-mips64el': 0.27.2
+ '@esbuild/linux-ppc64': 0.27.2
+ '@esbuild/linux-riscv64': 0.27.2
+ '@esbuild/linux-s390x': 0.27.2
+ '@esbuild/linux-x64': 0.27.2
+ '@esbuild/netbsd-arm64': 0.27.2
+ '@esbuild/netbsd-x64': 0.27.2
+ '@esbuild/openbsd-arm64': 0.27.2
+ '@esbuild/openbsd-x64': 0.27.2
+ '@esbuild/openharmony-arm64': 0.27.2
+ '@esbuild/sunos-x64': 0.27.2
+ '@esbuild/win32-arm64': 0.27.2
+ '@esbuild/win32-ia32': 0.27.2
+ '@esbuild/win32-x64': 0.27.2
+
[email protected]: {}
[email protected]: {}
@@ -9385,6 +9667,10 @@ snapshots:
es-errors: 1.3.0
get-intrinsic: 1.2.4
+ [email protected]:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
[email protected]:
dependencies:
content-type: 1.0.5
@@ -10785,6 +11071,8 @@ snapshots:
[email protected]: {}
+ [email protected]: {}
+
[email protected]:
dependencies:
adjust-sourcemap-loader: 4.0.0
@@ -11437,6 +11725,13 @@ snapshots:
[email protected]: {}
+ [email protected]:
+ dependencies:
+ esbuild: 0.27.2
+ get-tsconfig: 4.13.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
[email protected]:
dependencies:
'@tufjs/models': 2.0.1
diff --git a/src/app/routers/home/components/team/team.component.html
b/src/app/routers/home/components/team/team.component.html
index 558c73c6..df20e17d 100644
--- a/src/app/routers/home/components/team/team.component.html
+++ b/src/app/routers/home/components/team/team.component.html
@@ -31,7 +31,7 @@
<div class="h-full w-full rounded bg-paimon-gray-2">
<img
class="rounded"
- [ngSrc]="'https://avatars.githubusercontent.com/u/' +
item.avatarId"
+ ngSrc="assets/avatars/{{ item.avatarId }}.png"
[width]="92"
[height]="92"
[alt]="item.name"
diff --git a/src/app/routers/team/team.component.html
b/src/app/routers/team/team.component.html
index 856c5e45..b7a86c71 100644
--- a/src/app/routers/team/team.component.html
+++ b/src/app/routers/team/team.component.html
@@ -13,7 +13,7 @@
class="flex w-[156px] flex-col items-center justify-between
gap-4 rounded-lg bg-paimon-gray-1 p-1.5 pb-6"
>
<img
- [ngSrc]="'https://avatars.githubusercontent.com/u/' +
item.avatarId"
+ ngSrc="assets/avatars/{{ item.avatarId }}.png"
[width]="144"
[height]="144"
[alt]="item.name"
@@ -47,7 +47,7 @@
class="flex w-[156px] flex-col items-center justify-between
gap-4 rounded-lg bg-paimon-gray-1 p-1.5 pb-6"
>
<img
- [ngSrc]="'https://avatars.githubusercontent.com/u/' +
item.avatarId"
+ ngSrc="assets/avatars/{{ item.avatarId }}.png"
[width]="144"
[height]="144"
[alt]="item.name"
diff --git a/src/load-avatars.ts b/src/load-avatars.ts
new file mode 100644
index 00000000..2e836e75
--- /dev/null
+++ b/src/load-avatars.ts
@@ -0,0 +1,95 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import fs from 'node:fs';
+import { get } from 'node:https';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { listOfPMCs, listOfCommitters } from './app/tokens/member';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const OUTPUT_DIR = path.resolve(__dirname, 'assets', 'avatars');
+const AVATAR_SIZE = 256;
+
+const avatars = new Set<string>([
+ ...listOfPMCs.map(member => member.avatarId),
+ ...listOfCommitters.map(member => member.avatarId)
+]);
+
+function fetchBuffer(url: string): Promise<Buffer> {
+ return new Promise((resolve, reject) => {
+ get(
+ url,
+ {
+ headers: {
+ // GitHub requires a user agent for avatar fetches.
+ 'User-Agent': 'paimon-website-avatar-downloader'
+ }
+ },
+ res => {
+ if (res.statusCode && res.statusCode >= 400) {
+ return reject(new Error(`Failed to fetch ${url}:
${res.statusCode}`));
+ }
+
+ const data: Uint8Array[] = [];
+ res.on('data', chunk => data.push(chunk));
+ res.on('end', () => resolve(Buffer.concat(data)));
+ }
+ ).on('error', err => reject(err));
+ });
+}
+
+async function downloadAvatar(avatarId: string): Promise<void> {
+ const url =
`https://avatars.githubusercontent.com/u/${avatarId}?s=${AVATAR_SIZE}`;
+ const targetPath = path.join(OUTPUT_DIR, `${avatarId}.png`);
+
+ if (fs.existsSync(targetPath)) {
+ return;
+ }
+
+ const buffer = await fetchBuffer(url);
+ await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });
+ await fs.promises.writeFile(targetPath, buffer);
+}
+
+// Download avatars from GitHub if not already present, and save them to
/src/assets/avatars/
+export async function loadAvatars(): Promise<void> {
+ const ids = Array.from(avatars.values());
+
+ const results = await Promise.allSettled(ids.map(id => downloadAvatar(id)));
+ const failures = results
+ .map((result, index) => ({ result, id: ids[index] }))
+ .filter(({ result }) => result.status === 'rejected');
+
+ if (failures.length > 0) {
+ const message = failures.map(({ id, result }) => `${id}: ${(result as
PromiseRejectedResult).reason}`).join('\n');
+ throw new Error(`Failed to download ${failures.length}
avatar(s):\n${message}`);
+ }
+}
+
+if (process.argv[1] === __filename) {
+ loadAvatars()
+ .then(() => console.log('Avatar download complete.'))
+ .catch(err => {
+ console.error(err);
+ process.exitCode = 1;
+ });
+}