Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ Your card lives at a URL. Drop it in your profile README, your portfolio, anywhe
[![My GitFut card](https://gitfut.com/YOUR_USERNAME.png)](https://gitfut.com/YOUR_USERNAME)
```

> **Tip:** some platforms (like GitHub profile READMEs) render SVG more reliably than PNG from external sources. Use `.svg` instead:
> ```md
> [![My GitFut card](https://gitfut.com/YOUR_USERNAME.svg)](https://gitfut.com/YOUR_USERNAME)
> ```

| | |
|---|---|
| **`gitfut.com/<username>.png`** | your card, as a live image |
| **`gitfut.com/<username>.svg`** | same card, SVG format (better for GitHub READMEs) |
| **`gitfut.com/<username>`** | the full scout report |
| **`?country=XX`** | override the flag (e.g. `?country=DZ`) |

Expand Down
42 changes: 42 additions & 0 deletions app/api/card-svg/[username]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SVG wrapper for the embeddable card image.
// gitfut.com/<username>.svg → here (via next.config rewrite).
//
// Returns a minimal SVG that embeds the existing PNG card via an <image> element.
// This lets users embed their card in contexts that only accept SVG (e.g. GitHub
// profile READMEs that block <img src="...png"> from external domains). The SVG
// itself is tiny - the PNG is still served by the card-image route and cached at
// the CDN; this route just wraps it. No rendering, no fonts, no sharp.
//
// Usage: ![card](https://gitfut.com/username.svg)
// ![card](https://gitfut.com/username.svg?country=id)

const W = 810;
const H = 1230;

export async function GET(req: Request, { params }: { params: Promise<{ username: string }> }) {
const { username } = await params;

// Forward the ?country= override to the PNG route so the flag matches.
const { searchParams } = new URL(req.url);
const country = searchParams.get("country");
const pngUrl = country
? `/api/card-image/${username}?country=${encodeURIComponent(country)}`
: `/api/card-image/${username}`;

// Build an absolute URL from the incoming request origin so the <image href>
// works from any host (local dev, preview deployments, production).
const origin = new URL(req.url).origin;
const pngAbsolute = `${origin}${pngUrl}`;

const svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${W}" height="${H}" viewBox="0 0 ${W} ${H}">
<image href="${pngAbsolute}" width="${W}" height="${H}" />
</svg>`;

return new Response(svg, {
headers: {
"Content-Type": "image/svg+xml",
// Match the PNG cache duration so they stay in sync.
"Cache-Control": "public, max-age=300",
},
});
}
3 changes: 3 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const nextConfig: NextConfig = {
// files still win over it regardless.
return [
{ source: "/:username([a-zA-Z0-9-]+).png", destination: "/api/card-image/:username" },
// SVG embed: gitfut.com/<username>.svg → SVG wrapper around the PNG card.
// Useful for GitHub profile READMEs and other contexts that prefer SVG.
{ source: "/:username([a-zA-Z0-9-]+).svg", destination: "/api/card-svg/:username" },
];
},
};
Expand Down