Skip to content

feat(ui): add badges ?style=compact variant#2640

Open
OrbisK wants to merge 2 commits intonpmx-dev:mainfrom
OrbisK:feat/badges-compact
Open

feat(ui): add badges ?style=compact variant#2640
OrbisK wants to merge 2 commits intonpmx-dev:mainfrom
OrbisK:feat/badges-compact

Conversation

@OrbisK
Copy link
Copy Markdown
Contributor

@OrbisK OrbisK commented Apr 27, 2026

🔗 Linked issue

fixes #2509

🧭 Context

Working on https://github.com/OrbisK/renovate-config-npmx i wanted to use the npmx styled badges, but they were to big.

📚 Description

This PR add a third style (compact) to the badges. compact has less x padding and "trimmed" labels

?style=default

image

?style=compact

image

Alternative naming: ?style=slim


Funfact: fff5849 commit hash is tomato color in hex

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Apr 27, 2026 10:09am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Apr 27, 2026 10:09am
npmx-lunaria Ignored Ignored Apr 27, 2026 10:09am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

Introduces a new compact badge style alongside default and shieldsio. The compact style uses reduced horizontal padding, dynamic text-width measurement, and abbreviated built-in labels. Changes span the UI selector, documentation, API renderer selection and implementation, and end-to-end tests.

Changes

Cohort / File(s) Summary
Badge UI
docs/app/components/BadgeGeneratorParameters.vue
Added compact option to the Badge Style <select>.
Documentation
docs/content/2.guide/6.badges.md
Documented compact style details and added ?style=compact examples; clarified three style options.
Badge API & Renderers
server/api/registry/badge/[type]/[...pkg].get.ts
Added compact support: text-measure utilities, renderCompactBadgeSvg, COMPACT_LABEL_MAP for built-in label abbreviations, refactored Geist renderer into renderGeistBadgeSvg, introduced BADGE_RENDERERS dispatch and extended BadgeStyleSchema.
End-to-End Tests
test/e2e/badge.spec.ts
Added tests for style=compact: verifies renderer selection, 20px height, label trimming/abbreviations, width regression vs default, and behaviour with explicit label and name=true.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as Badge API Handler
    participant Renderer as Badge Renderer (default/shieldsio/compact)
    participant Response as SVG Response

    Client->>API: GET /badge/... ?style=compact
    API->>API: validate style, compute strategyLabel (apply COMPACT_LABEL_MAP if compact)
    API->>Renderer: render SVG with measured widths & padding
    Renderer-->>API: SVG (width,height,content)
    API-->>Client: 200 OK + SVG
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature addition: a new compact badge style variant, directly matching the primary changeset objective.
Linked Issues check ✅ Passed The pull request fully implements issue #2509 requirements: introduces a third badge style named 'compact' with reduced padding and trimmed labels as requested.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the compact badge style feature. Documentation updates, component changes, API implementation, and e2e tests are all within scope.
Description check ✅ Passed The pull request description clearly relates to the changeset, detailing the addition of a compact badge style with reduced padding and trimmed labels, supported by comparative images.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
server/api/registry/badge/[type]/[...pkg].get.ts (1)

248-280: Consider sharing the SVG template between the default and compact renderers.

renderCompactBadgeSvg is byte-identical to renderDefaultBadgeSvg except for the width-measurement helper (and the absence of FALLBACK_VALUE_EXTRA_PADDING_X). Future tweaks to the modern Geist template (e.g. corner radius, accessibility attributes, font-family) will need to be applied in two places, which is easy to miss. A small parameterisation removes the duplication.

♻️ Suggested consolidation
-function renderDefaultBadgeSvg(params: {
+type ModernBadgeParams = {
   finalColor: string
   finalLabel: string
   finalLabelColor: string
   finalValue: string
   labelTextColor: string
   valueTextColor: string
-}): string {
-  const { finalColor, finalLabel, finalLabelColor, finalValue, labelTextColor, valueTextColor } =
-    params
-  const leftWidth = finalLabel.trim().length === 0 ? 0 : measureDefaultTextWidth(finalLabel)
-  const rightWidth = measureDefaultTextWidth(finalValue, FALLBACK_VALUE_EXTRA_PADDING_X)
+}
+
+function renderModernBadgeSvg(
+  params: ModernBadgeParams,
+  measureLabel: (text: string) => number,
+  measureValue: (text: string) => number,
+): string {
+  const { finalColor, finalLabel, finalLabelColor, finalValue, labelTextColor, valueTextColor } =
+    params
+  const leftWidth = finalLabel.trim().length === 0 ? 0 : measureLabel(finalLabel)
+  const rightWidth = measureValue(finalValue)
   const totalWidth = leftWidth + rightWidth
   const height = 20
   /* ...existing SVG template... */
 }

-function renderCompactBadgeSvg(params: { ... }): string { ... duplicated template ... }
+const renderDefaultBadgeSvg = (params: ModernBadgeParams) =>
+  renderModernBadgeSvg(
+    params,
+    text => measureDefaultTextWidth(text),
+    text => measureDefaultTextWidth(text, FALLBACK_VALUE_EXTRA_PADDING_X),
+  )
+
+const renderCompactBadgeSvg = (params: ModernBadgeParams) =>
+  renderModernBadgeSvg(params, measureCompactTextWidth, measureCompactTextWidth)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/registry/badge/`[type]/[...pkg].get.ts around lines 248 - 280,
renderCompactBadgeSvg duplicates renderDefaultBadgeSvg; extract the shared SVG
template into a single helper (e.g., renderBadgeSvgTemplate or renderBadgeSvg)
that accepts parameters for leftWidth/rightWidth (or a measurement strategy),
finalColor/finalLabelColor, label/value text/colors, height, corner radius and
any padding (FALLBACK_VALUE_EXTRA_PADDING_X) and accessibility attributes, then
have renderDefaultBadgeSvg and renderCompactBadgeSvg compute their widths using
measureTextWidth and measureCompactTextWidth respectively and call the new
shared renderer with those computed widths and any extra padding; update callers
to use the two small adapters and remove the duplicated SVG string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/api/registry/badge/`[type]/[...pkg].get.ts:
- Around line 248-280: renderCompactBadgeSvg duplicates renderDefaultBadgeSvg;
extract the shared SVG template into a single helper (e.g.,
renderBadgeSvgTemplate or renderBadgeSvg) that accepts parameters for
leftWidth/rightWidth (or a measurement strategy), finalColor/finalLabelColor,
label/value text/colors, height, corner radius and any padding
(FALLBACK_VALUE_EXTRA_PADDING_X) and accessibility attributes, then have
renderDefaultBadgeSvg and renderCompactBadgeSvg compute their widths using
measureTextWidth and measureCompactTextWidth respectively and call the new
shared renderer with those computed widths and any extra padding; update callers
to use the two small adapters and remove the duplicated SVG string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b6925d5e-36aa-4b37-8324-ab978a187b15

📥 Commits

Reviewing files that changed from the base of the PR and between b1684b0 and fff5849.

📒 Files selected for processing (4)
  • docs/app/components/BadgeGeneratorParameters.vue
  • docs/content/2.guide/6.badges.md
  • server/api/registry/badge/[type]/[...pkg].get.ts
  • test/e2e/badge.spec.ts

@OrbisK OrbisK changed the title feat(badges): add ?style=compact variant feat(ui): add badges ?style=compact variant Apr 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
server/api/registry/badge/[type]/[...pkg].get.ts (2)

543-560: Dispatch table + compact label map: tidy. One maintenance caveat.

The BADGE_RENDERERS lookup paired with the picklist schema gives a fully typed dispatch — much cleaner than the previous inline conditional. The COMPACT_LABEL_MAP is also straightforward, and verified consistent: both the downloads and downloads-month strategies emit 'downloads/mo', so they both abbreviate to 'dl/mo' as expected.

One nit worth flagging for future maintenance: COMPACT_LABEL_MAP keys are stringly-coupled to label strings declared inside badgeStrategies (e.g. 'install size', 'dependencies'). A future rename there would silently fall through to the original label rather than break a build. Not a bug today, but worth a brief comment near the map (or co-locating compact labels with each strategy) to prevent drift.

♻️ Minimal hardening — narrow the key type
-const COMPACT_LABEL_MAP: Record<string, string> = {
+// Keys must match labels returned by `badgeStrategies` entries.
+const COMPACT_LABEL_MAP: Record<string, string> = {
   'install size': 'size',
   'downloads/day': 'dl/day',
   'downloads/wk': 'dl/wk',
   'downloads/mo': 'dl/mo',
   'downloads/yr': 'dl/yr',
   'dependencies': 'deps',
   'maintainers': 'maint',
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/registry/badge/`[type]/[...pkg].get.ts around lines 543 - 560,
COMPACT_LABEL_MAP keys are stringly-coupled to label strings in badgeStrategies
which can drift silently; to fix, narrow the key type and/or co-locate the
compact labels with each strategy: either export a LabelKey union (e.g., type
BadgeLabel = 'install size' | 'downloads/day' | ... used by badgeStrategies) and
type COMPACT_LABEL_MAP as Record<BadgeLabel,string>, or move the compact label
into each entry in badgeStrategies and build COMPACT_LABEL_MAP from those
entries; update usages to rely on the new BadgeLabel type or the
strategy-provided compact label and add a short comment by COMPACT_LABEL_MAP
referencing badgeStrategies to avoid future divergence.

272-281: Optional: reuse BadgeRenderParams for the shieldsio renderer.

renderShieldsBadgeSvg re-declares the same six fields inline. Now that BadgeRenderParams exists, switching to it removes duplication and keeps the three renderers structurally aligned, which also makes the BADGE_RENDERERS dispatch table’s shared input contract obvious.

♻️ Proposed refactor
-function renderShieldsBadgeSvg(params: {
-  finalColor: string
-  finalLabel: string
-  finalLabelColor: string
-  finalValue: string
-  labelTextColor: string
-  valueTextColor: string
-}): string {
+function renderShieldsBadgeSvg(params: BadgeRenderParams): string {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/api/registry/badge/`[type]/[...pkg].get.ts around lines 272 - 281,
renderShieldsBadgeSvg currently re-declares the same six fields instead of using
the existing BadgeRenderParams type; update the function signature of
renderShieldsBadgeSvg to accept params: BadgeRenderParams and remove the
redundant local destructuring that duplicates those fields, ensuring its
parameter shape matches the other renderers and keeping the BADGE_RENDERERS
dispatch table’s shared input contract consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/api/registry/badge/`[type]/[...pkg].get.ts:
- Around line 543-560: COMPACT_LABEL_MAP keys are stringly-coupled to label
strings in badgeStrategies which can drift silently; to fix, narrow the key type
and/or co-locate the compact labels with each strategy: either export a LabelKey
union (e.g., type BadgeLabel = 'install size' | 'downloads/day' | ... used by
badgeStrategies) and type COMPACT_LABEL_MAP as Record<BadgeLabel,string>, or
move the compact label into each entry in badgeStrategies and build
COMPACT_LABEL_MAP from those entries; update usages to rely on the new
BadgeLabel type or the strategy-provided compact label and add a short comment
by COMPACT_LABEL_MAP referencing badgeStrategies to avoid future divergence.
- Around line 272-281: renderShieldsBadgeSvg currently re-declares the same six
fields instead of using the existing BadgeRenderParams type; update the function
signature of renderShieldsBadgeSvg to accept params: BadgeRenderParams and
remove the redundant local destructuring that duplicates those fields, ensuring
its parameter shape matches the other renderers and keeping the BADGE_RENDERERS
dispatch table’s shared input contract consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: be32817b-9eee-453e-917b-b1dbd25ba4d1

📥 Commits

Reviewing files that changed from the base of the PR and between fff5849 and fa4b550.

📒 Files selected for processing (1)
  • server/api/registry/badge/[type]/[...pkg].get.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New badge style compact

1 participant