From 96bcc96023cd21e65bdb4f63f2d8d6970ae8a0b0 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Mon, 2 Feb 2026 22:51:45 +0800
Subject: [PATCH 1/6] feat: badge support colorLeft
---
docs/content/2.guide/1.features.md | 7 +++++++
server/api/registry/badge/[type]/[...pkg].get.ts | 7 ++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/docs/content/2.guide/1.features.md b/docs/content/2.guide/1.features.md
index 81eee0564a..5a12199f28 100644
--- a/docs/content/2.guide/1.features.md
+++ b/docs/content/2.guide/1.features.md
@@ -167,6 +167,13 @@ Overrides the default strategy color. You can pass a standard hex code (with or
| **Pure Black** | `.../badge/version/nuxt?color=000000` |
| **Brand Blue** | `.../badge/version/nuxt?color=3b82f6` |
+#### `colorLeft`
+
+Overrides the default label color. You can pass a standard hex code (with or without the `#` prefix).
+
+- **Default**: `#0a0a0a`
+- **Usage**: `?colorLeft=HEX_CODE`
+
##### `name`
When set to `true`, this parameter replaces the static category label (like "version" or "downloads/mo") with the actual name of the package. This is useful for brand-focused READMEs.
diff --git a/server/api/registry/badge/[type]/[...pkg].get.ts b/server/api/registry/badge/[type]/[...pkg].get.ts
index 8f6a56d45c..bafbeecb2b 100644
--- a/server/api/registry/badge/[type]/[...pkg].get.ts
+++ b/server/api/registry/badge/[type]/[...pkg].get.ts
@@ -14,6 +14,7 @@ const NPMS_API = 'https://api.npms.io/v2/package'
const QUERY_SCHEMA = v.object({
color: v.optional(v.string()),
name: v.optional(v.string()),
+ colorLeft: v.optional(v.string()),
})
const COLORS = {
@@ -263,6 +264,7 @@ export default defineCachedEventHandler(
const queryParams = v.safeParse(QUERY_SCHEMA, query)
const userColor = queryParams.success ? queryParams.output.color : undefined
+ const userColorLeft = queryParams.success ? queryParams.output.colorLeft : undefined
const showName = queryParams.success && queryParams.output.name === 'true'
const badgeTypeResult = v.safeParse(BadgeTypeSchema, typeParam)
@@ -280,6 +282,9 @@ export default defineCachedEventHandler(
const rawColor = userColor ?? strategyResult.color
const finalColor = rawColor?.startsWith('#') ? rawColor : `#${rawColor}`
+ const rawLeftColor = userColorLeft ?? '#0a0a0a'
+ const finalLeftColor = rawLeftColor?.startsWith('#') ? rawLeftColor : `#${rawLeftColor}`
+
const leftWidth = measureTextWidth(finalLabel)
const rightWidth = measureTextWidth(finalValue)
const totalWidth = leftWidth + rightWidth
@@ -291,7 +296,7 @@ export default defineCachedEventHandler(
-
+
From 51fcd1beb73e8352be608c986c52db34309a759f Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 3 Feb 2026 11:27:03 +0800
Subject: [PATCH 2/6] feat: update
---
docs/content/2.guide/1.features.md | 26 +++++++++----------
.../api/registry/badge/[type]/[...pkg].get.ts | 8 +++---
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/docs/content/2.guide/1.features.md b/docs/content/2.guide/1.features.md
index 81b675f40d..3e6294a76c 100644
--- a/docs/content/2.guide/1.features.md
+++ b/docs/content/2.guide/1.features.md
@@ -154,25 +154,25 @@ You can add custom npmx badges to your markdown files using the following syntax
You can further customize your badges by appending query parameters to the badge URL.
-##### `color`
+#### `colorA`
-Overrides the default strategy color. You can pass a standard hex code (with or without the `#` prefix).
+Overrides the default label color. You can pass a standard hex code (with or without the `#` prefix).
-- **Default**: Depends on the badge type (e.g., version is blue, downloads are orange).
-- **Usage**: `?color=HEX_CODE`
+- **Default**: `#0a0a0a`
+- **Usage**: `?colorA=HEX_CODE`
-| Example | URL |
-| :------------- | :------------------------------------ |
-| **Hot Pink** | `.../badge/version/nuxt?color=ff69b4` |
-| **Pure Black** | `.../badge/version/nuxt?color=000000` |
-| **Brand Blue** | `.../badge/version/nuxt?color=3b82f6` |
+##### `colorB`
-#### `colorLeft`
+Overrides the default strategy color. You can pass a standard hex code (with or without the `#` prefix).
-Overrides the default label color. You can pass a standard hex code (with or without the `#` prefix).
+- **Default**: Depends on the badge type (e.g., version is blue, downloads are orange).
+- **Usage**: `?colorB=HEX_CODE`
-- **Default**: `#0a0a0a`
-- **Usage**: `?colorLeft=HEX_CODE`
+| Example | URL |
+| :------------- | :------------------------------------- |
+| **Hot Pink** | `.../badge/version/nuxt?colorB=ff69b4` |
+| **Pure Black** | `.../badge/version/nuxt?colorB=000000` |
+| **Brand Blue** | `.../badge/version/nuxt?colorB=3b82f6` |
##### `name`
diff --git a/server/api/registry/badge/[type]/[...pkg].get.ts b/server/api/registry/badge/[type]/[...pkg].get.ts
index bafbeecb2b..74e8d47c7c 100644
--- a/server/api/registry/badge/[type]/[...pkg].get.ts
+++ b/server/api/registry/badge/[type]/[...pkg].get.ts
@@ -12,9 +12,9 @@ const BUNDLEPHOBIA_API = 'https://bundlephobia.com/api/size'
const NPMS_API = 'https://api.npms.io/v2/package'
const QUERY_SCHEMA = v.object({
- color: v.optional(v.string()),
+ colorA: v.optional(v.string()),
name: v.optional(v.string()),
- colorLeft: v.optional(v.string()),
+ colorB: v.optional(v.string()),
})
const COLORS = {
@@ -263,8 +263,8 @@ export default defineCachedEventHandler(
})
const queryParams = v.safeParse(QUERY_SCHEMA, query)
- const userColor = queryParams.success ? queryParams.output.color : undefined
- const userColorLeft = queryParams.success ? queryParams.output.colorLeft : undefined
+ const userColor = queryParams.success ? queryParams.output.colorB : undefined
+ const userColorLeft = queryParams.success ? queryParams.output.colorA : undefined
const showName = queryParams.success && queryParams.output.name === 'true'
const badgeTypeResult = v.safeParse(BadgeTypeSchema, typeParam)
From f15e3aa72a4043af590b10601fa8d1f67f3d64e5 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 3 Feb 2026 14:19:52 +0800
Subject: [PATCH 3/6] test: update
---
test/e2e/badge.spec.ts | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/test/e2e/badge.spec.ts b/test/e2e/badge.spec.ts
index 9254ec910d..c7dbb74c6c 100644
--- a/test/e2e/badge.spec.ts
+++ b/test/e2e/badge.spec.ts
@@ -102,9 +102,17 @@ test.describe('badge API', () => {
})
})
- test('custom color parameter is applied to SVG', async ({ page, baseURL }) => {
+ test('custom colorA parameter is applied to SVG', async ({ page, baseURL }) => {
+ const customColor = '00ff00'
+ const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?colorA=${customColor}`)
+ const { body } = await fetchBadge(page, url)
+
+ expect(body).toContain(`fill="#${customColor}"`)
+ })
+
+ test('custom colorB parameter is applied to SVG', async ({ page, baseURL }) => {
const customColor = 'ff69b4'
- const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?color=${customColor}`)
+ const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?colorB=${customColor}`)
const { body } = await fetchBadge(page, url)
expect(body).toContain(`fill="#${customColor}"`)
From 9a04a24c23ef13b516c6cf375e5cb094160f0075 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 3 Feb 2026 20:59:27 +0800
Subject: [PATCH 4/6] docs: update
---
docs/content/2.guide/1.features.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/content/2.guide/1.features.md b/docs/content/2.guide/1.features.md
index 3e6294a76c..4b13cb7f25 100644
--- a/docs/content/2.guide/1.features.md
+++ b/docs/content/2.guide/1.features.md
@@ -154,7 +154,7 @@ You can add custom npmx badges to your markdown files using the following syntax
You can further customize your badges by appending query parameters to the badge URL.
-#### `colorA`
+##### `colorA`
Overrides the default label color. You can pass a standard hex code (with or without the `#` prefix).
From 6af07393aa54455e98ecbdbdbb84ff5029d81586 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Wed, 4 Feb 2026 14:03:23 +0800
Subject: [PATCH 5/6] feat: update
---
docs/content/2.guide/1.features.md | 15 +++++++++++----
server/api/registry/badge/[type]/[...pkg].get.ts | 14 ++++++++------
test/e2e/badge.spec.ts | 16 ++++++++++++----
3 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/docs/content/2.guide/1.features.md b/docs/content/2.guide/1.features.md
index 03599ad275..ee37f2350b 100644
--- a/docs/content/2.guide/1.features.md
+++ b/docs/content/2.guide/1.features.md
@@ -158,19 +158,26 @@ Make sure to replace `TYPE` with one of the options listed below and `YOUR_PACKA
You can further customize your badges by appending query parameters to the badge URL.
-##### `colorA`
+##### `labelColor`
Overrides the default label color. You can pass a standard hex code (with or without the `#` prefix).
- **Default**: `#0a0a0a`
-- **Usage**: `?colorA=HEX_CODE`
+- **Usage**: `?labelColor=HEX_CODE`
-##### `colorB`
+##### `label`
+
+Overrides the default label text. You can pass any string to customize the label displayed on the badge.
+
+- **Default**: Depends on the badge type (e.g., "version", "downloads/mo").
+- **Usage**: `?label=YOUR_LABEL`
+
+##### `color`
Overrides the default strategy color. You can pass a standard hex code (with or without the `#` prefix).
- **Default**: Depends on the badge type (e.g., version is blue, downloads are orange).
-- **Usage**: `?colorB=HEX_CODE`
+- **Usage**: `?color=HEX_CODE`
| Example | URL |
| :------------- | :------------------------------------- |
diff --git a/server/api/registry/badge/[type]/[...pkg].get.ts b/server/api/registry/badge/[type]/[...pkg].get.ts
index 74e8d47c7c..9a53afa9b4 100644
--- a/server/api/registry/badge/[type]/[...pkg].get.ts
+++ b/server/api/registry/badge/[type]/[...pkg].get.ts
@@ -12,9 +12,10 @@ const BUNDLEPHOBIA_API = 'https://bundlephobia.com/api/size'
const NPMS_API = 'https://api.npms.io/v2/package'
const QUERY_SCHEMA = v.object({
- colorA: v.optional(v.string()),
+ color: v.optional(v.string()),
name: v.optional(v.string()),
- colorB: v.optional(v.string()),
+ labelColor: v.optional(v.string()),
+ label: v.optional(v.string()),
})
const COLORS = {
@@ -263,9 +264,10 @@ export default defineCachedEventHandler(
})
const queryParams = v.safeParse(QUERY_SCHEMA, query)
- const userColor = queryParams.success ? queryParams.output.colorB : undefined
- const userColorLeft = queryParams.success ? queryParams.output.colorA : undefined
+ const userColor = queryParams.success ? queryParams.output.color : undefined
+ const labelColor = queryParams.success ? queryParams.output.labelColor : undefined
const showName = queryParams.success && queryParams.output.name === 'true'
+ const userLabel = queryParams.success ? queryParams.output.label : undefined
const badgeTypeResult = v.safeParse(BadgeTypeSchema, typeParam)
const strategyKey = badgeTypeResult.success ? badgeTypeResult.output : 'version'
@@ -276,13 +278,13 @@ export default defineCachedEventHandler(
const pkgData = await fetchNpmPackage(packageName)
const strategyResult = await strategy(pkgData, requestedVersion)
- const finalLabel = showName ? packageName : strategyResult.label
+ const finalLabel = userLabel ? userLabel : showName ? packageName : strategyResult.label
const finalValue = strategyResult.value
const rawColor = userColor ?? strategyResult.color
const finalColor = rawColor?.startsWith('#') ? rawColor : `#${rawColor}`
- const rawLeftColor = userColorLeft ?? '#0a0a0a'
+ const rawLeftColor = labelColor ?? '#0a0a0a'
const finalLeftColor = rawLeftColor?.startsWith('#') ? rawLeftColor : `#${rawLeftColor}`
const leftWidth = measureTextWidth(finalLabel)
diff --git a/test/e2e/badge.spec.ts b/test/e2e/badge.spec.ts
index dfda3c9f7e..ff6f972d4e 100644
--- a/test/e2e/badge.spec.ts
+++ b/test/e2e/badge.spec.ts
@@ -102,22 +102,30 @@ test.describe('badge API', () => {
})
})
- test('custom colorA parameter is applied to SVG', async ({ page, baseURL }) => {
+ test('custom labelColor parameter is applied to SVG', async ({ page, baseURL }) => {
const customColor = '00ff00'
- const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?colorA=${customColor}`)
+ const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?labelColor=${customColor}`)
const { body } = await fetchBadge(page, url)
expect(body).toContain(`fill="#${customColor}"`)
})
- test('custom colorB parameter is applied to SVG', async ({ page, baseURL }) => {
+ test('custom color parameter is applied to SVG', async ({ page, baseURL }) => {
const customColor = 'ff69b4'
- const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?colorB=${customColor}`)
+ const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?color=${customColor}`)
const { body } = await fetchBadge(page, url)
expect(body).toContain(`fill="#${customColor}"`)
})
+ test('custom label parameter is applied to SVG', async ({ page, baseURL }) => {
+ const customLabel = 'my-label'
+ const url = toLocalUrl(baseURL, `/api/registry/badge/version/nuxt?label=${customLabel}`)
+ const { body } = await fetchBadge(page, url)
+
+ expect(body).toContain(customLabel)
+ })
+
test('invalid badge type defaults to version strategy', async ({ page, baseURL }) => {
const url = toLocalUrl(baseURL, '/api/registry/badge/invalid-type/nuxt')
const { body } = await fetchBadge(page, url)
From 812b28c44ca9a36a73c413959498169cee9d9e9f Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Wed, 4 Feb 2026 14:05:21 +0800
Subject: [PATCH 6/6] refactor: rename
---
server/api/registry/badge/[type]/[...pkg].get.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/api/registry/badge/[type]/[...pkg].get.ts b/server/api/registry/badge/[type]/[...pkg].get.ts
index 9a53afa9b4..f41149f30a 100644
--- a/server/api/registry/badge/[type]/[...pkg].get.ts
+++ b/server/api/registry/badge/[type]/[...pkg].get.ts
@@ -284,8 +284,8 @@ export default defineCachedEventHandler(
const rawColor = userColor ?? strategyResult.color
const finalColor = rawColor?.startsWith('#') ? rawColor : `#${rawColor}`
- const rawLeftColor = labelColor ?? '#0a0a0a'
- const finalLeftColor = rawLeftColor?.startsWith('#') ? rawLeftColor : `#${rawLeftColor}`
+ const rawLabelColor = labelColor ?? '#0a0a0a'
+ const finalLabelColor = rawLabelColor?.startsWith('#') ? rawLabelColor : `#${rawLabelColor}`
const leftWidth = measureTextWidth(finalLabel)
const rightWidth = measureTextWidth(finalValue)
@@ -298,7 +298,7 @@ export default defineCachedEventHandler(
-
+