11import type { RequestHandler } from './$types' ;
22import { Resvg } from '@cf-wasm/resvg' ;
33
4+ let fontCache : Uint8Array | null = null ;
5+
6+ async function loadFont ( ) : Promise < Uint8Array > {
7+ if ( fontCache ) return fontCache ;
8+
9+ const css = await fetch (
10+ 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&subset=latin' ,
11+ {
12+ headers : {
13+ 'User-Agent' :
14+ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1'
15+ }
16+ }
17+ ) . then ( ( r ) => r . text ( ) ) ;
18+
19+ const fontUrl = css . match ( / s r c : u r l \( ( .+ ?) \) f o r m a t \( ' ( o p e n t y p e | t r u e t y p e ) ' \) / ) ?. [ 1 ] ;
20+ if ( ! fontUrl ) throw new Error ( 'Could not find font URL' ) ;
21+
22+ const fontBuffer = await fetch ( fontUrl ) . then ( ( r ) => r . arrayBuffer ( ) ) ;
23+ fontCache = new Uint8Array ( fontBuffer ) ;
24+ return fontCache ;
25+ }
26+
427function esc ( s : string ) : string {
528 return s . replace ( / & / g, '&' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) . replace ( / " / g, '"' ) ;
629}
@@ -29,13 +52,13 @@ function buildSvg(
2952
3053 function addGroup ( label : string , count : number , pkgs : { name : string } [ ] , color : string ) {
3154 if ( curY > maxY ) return ;
32- tagsSvg += `<text x="${ pad } " y="${ curY } " fill="#555" font-size="11" font-family="monospace " letter-spacing="1.5">${ label } · ${ count } </text>` ;
55+ tagsSvg += `<text x="${ pad } " y="${ curY } " fill="#555" font-size="11" font-family="Inter " letter-spacing="1.5">${ label } · ${ count } </text>` ;
3356 curY += 20 ;
3457 curX = pad ;
3558
3659 for ( let i = 0 ; i < pkgs . length ; i ++ ) {
3760 if ( curY > maxY ) {
38- tagsSvg += `<text x="${ curX } " y="${ curY + 18 } " fill="#555" font-size="13" font-family="sans-serif ">+${ pkgs . length - i } more</text>` ;
61+ tagsSvg += `<text x="${ curX } " y="${ curY + 18 } " fill="#555" font-size="13" font-family="Inter ">+${ pkgs . length - i } more</text>` ;
3962 curY += tagH + tagGap ;
4063 return ;
4164 }
@@ -47,14 +70,14 @@ function buildSvg(
4770 curX = pad ;
4871 curY += tagH + tagGap ;
4972 if ( curY > maxY ) {
50- tagsSvg += `<text x="${ curX } " y="${ curY + 18 } " fill="#555" font-size="13" font-family="sans-serif ">+${ pkgs . length - i } more</text>` ;
73+ tagsSvg += `<text x="${ curX } " y="${ curY + 18 } " fill="#555" font-size="13" font-family="Inter ">+${ pkgs . length - i } more</text>` ;
5174 curY += tagH + tagGap ;
5275 return ;
5376 }
5477 }
5578
5679 tagsSvg += `<rect x="${ curX } " y="${ curY } " width="${ tw } " height="${ tagH } " rx="6" fill="#141414" stroke="#252525" stroke-width="1"/>` ;
57- tagsSvg += `<text x="${ curX + tagPadX } " y="${ curY + 18 } " fill="${ color } " font-size="13" font-family="monospace ">${ esc ( text ) } </text>` ;
80+ tagsSvg += `<text x="${ curX + tagPadX } " y="${ curY + 18 } " fill="${ color } " font-size="13" font-family="Inter ">${ esc ( text ) } </text>` ;
5881 curX += tw + tagGap ;
5982 }
6083 curY += tagH + tagGap + 8 ;
@@ -65,34 +88,34 @@ function buildSvg(
6588 if ( npm . length > 0 ) addGroup ( 'NPM' , npm . length , npm , '#22c55e' ) ;
6689
6790 const descLine = description
68- ? `<text x="${ pad } " y="138" fill="#888" font-size="16" font-family="sans-serif ">${ esc ( description . slice ( 0 , 80 ) ) } </text>`
91+ ? `<text x="${ pad } " y="138" fill="#888" font-size="16" font-family="Inter ">${ esc ( description . slice ( 0 , 80 ) ) } </text>`
6992 : '' ;
7093
7194 return `<svg xmlns="http://www.w3.org/2000/svg" width="${ W } " height="${ H } " viewBox="0 0 ${ W } ${ H } ">
72- <rect width="${ W } " height="${ H } " fill="#0a0a0a"/>
7395 <defs>
7496 <radialGradient id="glow" cx="0.2" cy="0.15" r="0.55">
7597 <stop offset="0%" stop-color="#22c55e" stop-opacity="0.07"/>
7698 <stop offset="40%" stop-color="#22c55e" stop-opacity="0.03"/>
7799 <stop offset="100%" stop-color="#22c55e" stop-opacity="0"/>
78100 </radialGradient>
79101 </defs>
102+ <rect width="${ W } " height="${ H } " fill="#0a0a0a"/>
80103 <rect width="${ W } " height="${ H } " fill="url(#glow)"/>
81104
82- <text x="${ pad } " y="76" fill="#22c55e" font-size="28" font-weight="bold" font-family="sans-serif ">OpenBoot</text>
83- <text x="${ pad } " y="112" fill="#ffffff" font-size="28" font-weight="bold" font-family="sans-serif ">${ esc ( name ) } </text>
105+ <text x="${ pad } " y="76" fill="#22c55e" font-size="28" font-weight="bold" font-family="Inter ">OpenBoot</text>
106+ <text x="${ pad } " y="112" fill="#ffffff" font-size="28" font-weight="bold" font-family="Inter ">${ esc ( name ) } </text>
84107 ${ descLine }
85108
86- <text x="${ W - pad } " y="68" fill="#666" font-size="15" font-family="sans-serif " text-anchor="end">@${ esc ( username ) } </text>
87- <text x="${ W - pad } " y="90" fill="#22c55e" font-size="15" font-family="sans-serif " text-anchor="end">${ total } packages</text>
109+ <text x="${ W - pad } " y="68" fill="#666" font-size="15" font-family="Inter " text-anchor="end">@${ esc ( username ) } </text>
110+ <text x="${ W - pad } " y="90" fill="#22c55e" font-size="15" font-family="Inter " text-anchor="end">${ total } packages</text>
88111
89112 <line x1="${ pad } " y1="158" x2="${ W - pad } " y2="158" stroke="#1a1a1a" stroke-width="1"/>
90113
91114 ${ tagsSvg }
92115
93116 <line x1="${ pad } " y1="${ H - 56 } " x2="${ W - pad } " y2="${ H - 56 } " stroke="#1a1a1a" stroke-width="1"/>
94- <text x="${ pad } " y="${ H - 28 } " fill="#444" font-size="14" font-family="sans-serif ">openboot.dev</text>
95- <text x="${ W - pad } " y="${ H - 28 } " fill="#444" font-size="13" font-family="sans-serif " text-anchor="end">${ esc ( preset ) } preset</text>
117+ <text x="${ pad } " y="${ H - 28 } " fill="#444" font-size="14" font-family="Inter ">openboot.dev</text>
118+ <text x="${ W - pad } " y="${ H - 28 } " fill="#444" font-size="13" font-family="Inter " text-anchor="end">${ esc ( preset ) } preset</text>
96119 </svg>` ;
97120}
98121
@@ -135,6 +158,8 @@ export const GET: RequestHandler = async ({ params, platform }) => {
135158 const npm = rawPkgs . filter ( ( p ) => p . type === 'npm' ) ;
136159 const total = rawPkgs . length ;
137160
161+ const fontData = await loadFont ( ) ;
162+
138163 const svg = buildSvg (
139164 config . name ,
140165 config . description || '' ,
@@ -146,7 +171,15 @@ export const GET: RequestHandler = async ({ params, platform }) => {
146171 ) ;
147172
148173 try {
149- const resvg = await Resvg . async ( svg , { fitTo : { mode : 'width' as const , value : 1200 } } ) ;
174+ const resvg = await Resvg . async ( svg , {
175+ fitTo : { mode : 'width' as const , value : 1200 } ,
176+ font : {
177+ fontBuffers : [ fontData ] ,
178+ defaultFontFamily : 'Inter' ,
179+ sansSerifFamily : 'Inter' ,
180+ defaultFontSize : 16
181+ }
182+ } ) ;
150183 const pngData = resvg . render ( ) ;
151184 const pngBuffer = pngData . asPng ( ) ;
152185
0 commit comments