From a65a1f0764f5c147017c646d1dbb592b0cf5fafa Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 16:18:25 +0300 Subject: [PATCH 1/7] add support for site parameter to fetch stats from different StackExchange sites --- index.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index d1c9e89..7cf079f 100644 --- a/index.js +++ b/index.js @@ -44,6 +44,15 @@ http } const userID = searchParams.get("userID"); + // Get the site parameter and remove .com if it exists + let site = searchParams.has("site") + ? searchParams.get("site") + : "stackoverflow"; + + if (site.endsWith('.com')) { + site = site.substring(0, site.length - 4); + } + const showLogo = searchParams.has("showLogo") ? stringToBoolean(searchParams.get("showLogo")) : true; @@ -64,8 +73,9 @@ http ? stringToBoolean(searchParams.get("showAnimations")) : true; + // Using site in API request const responseArticles = await fetch( - `https://api.stackexchange.com/2.3/users/${userID}?site=stackoverflow` + `https://api.stackexchange.com/2.3/users/${userID}?site=${site}` ); const json = await responseArticles.json(); @@ -75,10 +85,10 @@ http return; } + // Using site to generate URL ratings const res2 = await fetch( - `https://stackoverflow.com/users/rank\?userId\=${userID}` + `https://${site}.com/users/rank?userId=${userID}` ); - // get text, trim, and remove tags const ratingText = (await res2.text()).trim().replace(/(<([^>]+)>)/gi, ""); const result = await StackOverflowCard( @@ -90,7 +100,7 @@ http showAnimations, theme ); - + // res.setHeader( // "Cache-Control", // "private, no-cache, no-store, must-revalidate" @@ -98,10 +108,9 @@ http // res.setHeader("Expires", "-1"); // res.setHeader("Pragma", "no-cache"); res.writeHead(200, { "Content-Type": "image/svg+xml" }); - res.write(result); res.end(); }) .listen(process.env.PORT || 3000, function () { console.log("server start at port 3000"); - }); + }); \ No newline at end of file From d870cd446d3ec67e485b72d481fa7071fed66ec6 Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 16:31:32 +0300 Subject: [PATCH 2/7] updated docs. add info about site parameter --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index f0fdcc0..4901c70 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,17 @@ Get dynamically generated StackOverflow stats on your readmes. src="https://stackoverflow-card.vercel.app/?userID=353337&theme=dracula" /> +You can optionally provide a site parameter to retrieve data from a specific site in the StackExchange ecosystem.
For example: + +```markdown + +``` + + You have to provide a valid `userID`. Apart from that, StackOverflow Card supports several options (with their default values): ``` @@ -19,6 +30,7 @@ theme: [stackoverflow-dark, stackoverflow-light, dracula, ...] showBorder: true showIcons: true showAnimations: true +site: stackoverflow ``` See [here](https://github.com/nschloe/stackoverflow-card/blob/main/src/themes.js) for all available themes. Some examples From acaed80ca0434126818cffc102f5602a99c8b6aa Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 16:36:11 +0300 Subject: [PATCH 3/7] fix userID in askubuntu example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4901c70..c6d8f94 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ You can optionally provide a site parameter to retrieve data from a specific sit ```markdown ``` You have to provide a valid `userID`. Apart from that, StackOverflow Card supports From c9bcef19a5bffec9999142900e38bfd87304823a Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 17:22:01 +0300 Subject: [PATCH 4/7] Updated README.md --- README.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c6d8f94..2831521 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,41 @@ Get dynamically generated StackOverflow stats on your readmes. -```markdown +Use the HTML `img` tag: + +```html ``` +Or use the Markdown image syntax: + +```md +![StackOverflow Card](https://stackoverflow-card-tan.vercel.app/?userID=23095094) +``` + You can optionally provide a site parameter to retrieve data from a specific site in the StackExchange ecosystem.
For example: -```markdown +```html ``` + +```md +![StackOverflow Card](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow) +``` You have to provide a valid `userID`. Apart from that, StackOverflow Card supports several options (with their default values): -``` +```js showLogo: true theme: [stackoverflow-dark, stackoverflow-light, dracula, ...] showBorder: true @@ -32,20 +44,88 @@ showIcons: true showAnimations: true site: stackoverflow ``` -See [here](https://github.com/nschloe/stackoverflow-card/blob/main/src/themes.js) for -all available themes. Some examples -[here](https://github.com/nschloe/stackoverflow-card/blob/main/themes.md). +### Themes +With built-in themes, you can customize the look of the card. + +Use `&theme=THEME_NAME` parameter like so: +```md +![StackOverflow Card](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula) +``` +
+Show example + +![StackOverflow Card](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula) + +
+ +#### All built-in themes +StackOverflow Card comes with several built-in themes (E.g. `dracula`, `stackoverflowdark`, `stackoverflowdark`, `gruvboxdark`, `gruvboxlight`, `solarizeddark`, `solarizedlight`, `tomorrownight`, `tomorrow`). + +See [here](src/themes.js) for all available themes. + +Some card examples can be found [here](themes.md). + +#### Use GitHub's theme context tag + +You can use [GitHub's theme context](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) to make the card match the user's GitHub theme automatically. Just add #gh-dark-mode-only or #gh-light-mode-only at the end of an image link. This tells GitHub how to show the card to users with a light or dark theme preference. + +```md +[![StackOverflow Card Light](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only)](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only) +[![StackOverflow Card Dark](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula#gh-dark-mode-only)](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula#gh-dark-mode-only) +``` +
+Show example + +[![StackOverflow Card Light](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only)](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only) +[![StackOverflow Card Dark](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula#gh-dark-mode-only)](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=dracula#gh-dark-mode-only) + +
+ +#### Use GitHub's new media feature + +You can also use [GitHub's new media feature](https://github.blog/changelog/2022-05-19-specify-theme-context-for-images-in-markdown-beta/) in HTML to control how cards appear in light or dark themes. This is done using the `picture` element in combination with the `prefers-color-scheme` media feature. + +```html + + + + + +``` + +
+Show example + + + + + + + +
### Development Start -``` -nodemon index.js +```sh +nodemon index.js # or npm run start ``` and point a browser to -``` -http://localhost:3000/?userID=353337&theme=stackoverflow-dark -``` + +http://localhost:3000/?userID=536223&site=ru.stackoverflow&theme=stackoverflow-dark + with the desired options. From a06dd849f0f1368a087e9630cde7aa0650f1de39 Mon Sep 17 00:00:00 2001 From: Victor Collins <85904783+QueenDekim@users.noreply.github.com> Date: Wed, 10 Sep 2025 17:23:56 +0300 Subject: [PATCH 5/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2831521..d06fb1d 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Some card examples can be found [here](themes.md). #### Use GitHub's theme context tag -You can use [GitHub's theme context](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) to make the card match the user's GitHub theme automatically. Just add #gh-dark-mode-only or #gh-light-mode-only at the end of an image link. This tells GitHub how to show the card to users with a light or dark theme preference. +You can use [GitHub's theme context](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) to make the card match the user's GitHub theme automatically. Just add `#gh-dark-mode-only` or `#gh-light-mode-only` at the end of an image link. This tells GitHub how to show the card to users with a light or dark theme preference. ```md [![StackOverflow Card Light](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only)](https://stackoverflow-card-tan.vercel.app/?userID=536223&site=ru.stackoverflow&theme=tomorrow#gh-light-mode-only) From 8ab3dfa40fc365524ca5f3d5d4aee0b7a032eb51 Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 18:14:36 +0300 Subject: [PATCH 6/7] add data source to card --- index.js | 2 +- src/artwork.js | 7 +++++++ src/stackoverflow-card.js | 22 ++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 7cf079f..24d766c 100644 --- a/index.js +++ b/index.js @@ -100,7 +100,7 @@ http showAnimations, theme ); - + // res.setHeader( // "Cache-Control", // "private, no-cache, no-store, must-revalidate" diff --git a/src/artwork.js b/src/artwork.js index d199035..5bfc8b2 100644 --- a/src/artwork.js +++ b/src/artwork.js @@ -14,6 +14,13 @@ export const achievementsSm = (size) => export const medal = (size) => ``; +export const source = (size) => + ``; + export function logo(color, height) { const cols = color === "default" diff --git a/src/stackoverflow-card.js b/src/stackoverflow-card.js index 07a238b..1e555c7 100644 --- a/src/stackoverflow-card.js +++ b/src/stackoverflow-card.js @@ -3,6 +3,7 @@ import { reputation, achievementsSm, medal, + source, logo, } from "./artwork.js"; import { themes } from "./themes.js"; @@ -43,6 +44,16 @@ const statLine = (icon, iconColor, label, value) => { `; }; +function getRootUrl(url) { + try { + const parsedUrl = new URL(url.startsWith('http') ? url : `https://${url}`); + return parsedUrl.hostname; + } catch (error) { + console.error('Invalid URL:', error); + return null; + } +} + export const StackOverflowCard = async ( data, ratingText, @@ -64,7 +75,7 @@ export const StackOverflowCard = async ( } const width = 325; - const height = showLogo ? 150 : 105; + const height = showLogo ? 170 : 125; let logoSvg; if (showLogo) { @@ -81,6 +92,13 @@ export const StackOverflowCard = async ( const iconSize = 16; + const lineSrc = statLine( + showIcons ? source(iconSize) : null, + colors.icon, + "Source", + getRootUrl(data.link) + ); + const lineRep = statLine( showIcons ? coinsMono(iconSize) : null, colors.icon, @@ -119,7 +137,7 @@ export const StackOverflowCard = async ( 40 ); - const lines = [lineRep, lineRepYear, lineRating, lineBadges]; + const lines = [lineSrc, lineRep, lineRepYear, lineRating, lineBadges]; let linesStr = ``; const yOffset = showLogo ? 55 : 0; for (let i = 0; i < lines.length; i++) { From 08e22531a988557e966a9bcaf09191023083ec15 Mon Sep 17 00:00:00 2001 From: QueenDekim Date: Wed, 10 Sep 2025 21:15:52 +0300 Subject: [PATCH 7/7] added data source check, if `stackoverflow.com` - the source is not displayed in the card --- src/stackoverflow-card.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/stackoverflow-card.js b/src/stackoverflow-card.js index 1e555c7..30a4f06 100644 --- a/src/stackoverflow-card.js +++ b/src/stackoverflow-card.js @@ -75,7 +75,7 @@ export const StackOverflowCard = async ( } const width = 325; - const height = showLogo ? 170 : 125; + let height = showLogo ? 170 : 125; let logoSvg; if (showLogo) { @@ -137,7 +137,14 @@ export const StackOverflowCard = async ( 40 ); - const lines = [lineSrc, lineRep, lineRepYear, lineRating, lineBadges]; + let lines + if(getRootUrl(data.link) == "stackoverflow.com"){ + lines = [lineRep, lineRepYear, lineRating, lineBadges]; + height = showLogo ? 150 : 125; + } else { + lines = [lineSrc, lineRep, lineRepYear, lineRating, lineBadges]; + } + let linesStr = ``; const yOffset = showLogo ? 55 : 0; for (let i = 0; i < lines.length; i++) {