Skip to content

Commit 74b46b1

Browse files
committed
feat: add theme support to badge collection API and update example usage
1 parent b7df26c commit 74b46b1

1 file changed

Lines changed: 21 additions & 6 deletions

File tree

src/controllers/badge-collection.controller.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { badges } from '../db/schema.js';
1010
import { eq } from 'drizzle-orm';
1111
import { GitHubClient } from '../utils/github-client.js';
1212
import { BadgeRenderer } from '../components/badge-renderer.js';
13+
import { badgeThemes } from '../utils/themes.js';
1314
import type { BadgeOptions, UserBadgeType } from '../types/badge.types.js';
1415

1516
/** User badge types that have a corresponding DB column */
@@ -63,7 +64,7 @@ export class BadgeCollectionController {
6364
requiredParams: ['username', 'type'],
6465
optionalParams: ['columns', 'gap', 'theme', 'customLabel', 'labelColor', 'labelBackground', 'iconColor', 'valueColor', 'valueBackground'],
6566
payload: null,
66-
example: '/badge/collection?username=pphatdev&type=visitors,total-stars,repositories&columns=1',
67+
example: '/badge/collection?username=pphatdev&type=visitors,total-stars,repositories&columns=1&theme=galaxy',
6768
},
6869
};
6970

@@ -127,9 +128,8 @@ export class BadgeCollectionController {
127128
}
128129

129130
private static parseSharedOptions(req: Request): Omit<BadgeOptions, 'type'> {
130-
const { theme, customLabel, labelColor, labelBackground, iconColor, valueColor, valueBackground } = req.query;
131+
const { customLabel, labelColor, labelBackground, iconColor, valueColor, valueBackground } = req.query;
131132
return {
132-
theme: typeof theme === 'string' ? theme : undefined,
133133
customLabel: typeof customLabel === 'string' ? customLabel : undefined,
134134
labelColor: typeof labelColor === 'string' ? labelColor : undefined,
135135
labelBackground: typeof labelBackground === 'string' ? labelBackground : undefined,
@@ -279,12 +279,13 @@ export class BadgeCollectionController {
279279
options: Omit<BadgeOptions, 'type'>,
280280
columns: number,
281281
gap: number,
282+
themes: string[],
282283
): string {
283284
return [
284285
'badge-collection',
285286
`user:${username}`,
286287
`types:${types.join(',')}`,
287-
`theme:${options.theme ?? 'default'}`,
288+
`themes:${themes.join(',')}`,
288289
`columns:${columns}`,
289290
`gap:${gap}`,
290291
`labelColor:${options.labelColor ?? ''}`,
@@ -355,8 +356,22 @@ export class BadgeCollectionController {
355356
// 4. Parse display options
356357
const sharedOptions = BadgeCollectionController.parseSharedOptions(req);
357358

359+
// 4a. Parse and validate themes (comma-separated list; cycles across badges)
360+
const rawThemes = BadgeCollectionController.parseQueryList(req.query.theme);
361+
const themes = rawThemes.length > 0 ? rawThemes : ['default'];
362+
const validThemes = Object.keys(badgeThemes);
363+
const invalidThemes = themes.filter((t) => !validThemes.includes(t));
364+
if (invalidThemes.length > 0) {
365+
res.status(400).json({
366+
error: 'Invalid theme',
367+
invalid_themes: invalidThemes,
368+
valid_themes: validThemes,
369+
});
370+
return;
371+
}
372+
358373
// 5. Check in-memory collection cache
359-
const cacheKey = BadgeCollectionController.generateCacheKey(username, types, sharedOptions, columns, gap);
374+
const cacheKey = BadgeCollectionController.generateCacheKey(username, types, sharedOptions, columns, gap, themes);
360375
const cached = BadgeCollectionController.svgCache.get(cacheKey);
361376
if (cached) {
362377
if (req.headers['if-none-match'] === cached.etag) {
@@ -379,7 +394,7 @@ export class BadgeCollectionController {
379394

380395
// Render each badge as a standalone SVG
381396
const badgeSvgs = values.map((value, i) => {
382-
const opts: BadgeOptions = { ...sharedOptions, type: types[i] };
397+
const opts: BadgeOptions = { ...sharedOptions, type: types[i], theme: themes[i % themes.length] };
383398
return BadgeRenderer.generateBadge(value, opts).trim();
384399
});
385400

0 commit comments

Comments
 (0)