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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@iconify-json/vscode-icons": "1.2.40",
"@intlify/shared": "11.2.8",
"@lunariajs/core": "https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@f07e1a3",
"@napi-rs/canvas": "0.1.92",
"@nuxt/a11y": "1.0.0-alpha.1",
"@nuxt/fonts": "0.13.0",
"@nuxt/scripts": "0.13.2",
Expand Down
125 changes: 125 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 41 additions & 11 deletions server/api/registry/badge/[type]/[...pkg].get.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as v from 'valibot'
import { createCanvas, type SKRSContext2D } from '@napi-rs/canvas'
import { hash } from 'ohash'
import { createError, getRouterParam, getQuery, setHeader } from 'h3'
import { PackageRouteParamsSchema } from '#shared/schemas/package'
Expand Down Expand Up @@ -34,15 +35,47 @@ const COLORS = {
white: '#ffffff',
}

const DEFAULT_CHAR_WIDTH = 7
const CHARS_WIDTH = {
engines: 5.5,
const CHAR_WIDTH = 7

const BADGE_PADDING_X = 8
const MIN_BADGE_TEXT_WIDTH = 40

const BADGE_FONT_SHORTHAND = 'normal normal 400 11px Geist, system-ui, -apple-system, sans-serif'

let cachedCanvasContext: SKRSContext2D | null | undefined

function getCanvasContext(): SKRSContext2D | null {
if (cachedCanvasContext !== undefined) {
return cachedCanvasContext
}

try {
cachedCanvasContext = createCanvas(1, 1).getContext('2d')
} catch {
cachedCanvasContext = null
}

return cachedCanvasContext
}
Comment on lines +47 to 59
Copy link
Contributor

Choose a reason for hiding this comment

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

is reusing canvas context safe? like we're not going to run into issues with methods mutating the context and causing weird behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, were not drawing anything, we're just using a method you call "what IF you drew on that canvas"?


function measureTextWidth(text: string, charWidth?: number): number {
charWidth ??= DEFAULT_CHAR_WIDTH
const paddingX = 8
return Math.max(40, Math.round(text.length * charWidth) + paddingX * 2)
function fallbackMeasureTextWidth(text: string): number {
return Math.max(MIN_BADGE_TEXT_WIDTH, Math.round(text.length * CHAR_WIDTH) + BADGE_PADDING_X * 2)
}

function measureTextWidth(text: string): number {
const context = getCanvasContext()

if (context) {
context.font = BADGE_FONT_SHORTHAND

const measuredWidth = context.measureText(text).width

if (!Number.isNaN(measuredWidth)) {
return Math.max(MIN_BADGE_TEXT_WIDTH, Math.ceil(measuredWidth) + BADGE_PADDING_X * 2)
}
}

return fallbackMeasureTextWidth(text)
}

function formatBytes(bytes: number): string {
Expand Down Expand Up @@ -296,10 +329,7 @@ export default defineCachedEventHandler(
const finalLabelColor = rawLabelColor?.startsWith('#') ? rawLabelColor : `#${rawLabelColor}`

const leftWidth = finalLabel.trim().length === 0 ? 0 : measureTextWidth(finalLabel)
const rightWidth = measureTextWidth(
finalValue,
CHARS_WIDTH[strategyKey as keyof typeof CHARS_WIDTH],
)
const rightWidth = measureTextWidth(finalValue)
const totalWidth = leftWidth + rightWidth
const height = 20

Expand Down
Loading