@@ -58,10 +58,10 @@ const { repoRef, stars, refresh: refreshRepoMeta } = useRepoMeta(repositoryUrl)
5858
5959const formattedStars = computed (() => (stars .value > 0 ? compactFormat .format (stars .value ) : ' ' ))
6060
61- const weeklyDownloads = shallowRef ( 0 )
62- const formattedDownloads = computed (() =>
63- weeklyDownloads . value ? compactFormat .format (weeklyDownloads . value ) : ' ' ,
64- )
61+ const formattedDownloads = computed (() => {
62+ const last = weeklyValues . value . at ( - 1 )
63+ return last ? compactFormat .format (last ) : ' '
64+ } )
6565
6666const totalLikes = shallowRef (0 )
6767const formattedLikes = computed (() =>
@@ -177,34 +177,25 @@ async function fetchFunctionTree() {
177177 symbolRows .value = rows
178178}
179179
180- function fetchVariantData() {
181- if (variant === ' code-tree' ) return fetchCodeTree ()
182- if (variant === ' function-tree' ) return fetchFunctionTree ()
183- return fetchWeeklyEvolution ()
184- }
185-
186- const fetchLikes = $fetch <{ totalLikes: number }>(` /api/social/likes/${name } ` )
187- .then (d => {
188- totalLikes .value = d ?.totalLikes ?? 0
189- })
190- .catch (() => {})
191-
192- const downloadUrl = ` https://api.npmjs.org/downloads/point/last-week/${encodePackageName (name )} `
193- const fetchDownloads = $fetch <{ downloads: number }>(downloadUrl )
194- .then (d => {
195- console .error (' [og-image-package] downloads response:' , JSON .stringify (d ))
196- weeklyDownloads .value = d ?.downloads ?? 0
197- })
198- .catch (err => {
199- console .error (' [og-image-package] downloads fetch failed:' , downloadUrl , err ?.message || err )
200- })
180+ const fetchLikes = import .meta .test
181+ ? // need deterministic likes for testing
182+ Promise .resolve ().then (() => {
183+ totalLikes .value = 83
184+ })
185+ : $fetch <{ totalLikes: number }>(` /api/social/likes/${name } ` ).then (d => {
186+ totalLikes .value = d ?.totalLikes ?? 0
187+ })
201188
202189try {
203190 await Promise .all ([
204191 refreshPkg ().then (() => refreshRepoMeta ()),
205- fetchVariantData (),
192+ variant === ' code-tree'
193+ ? fetchCodeTree ()
194+ : variant === ' function-tree'
195+ ? fetchFunctionTree ()
196+ : undefined ,
197+ fetchWeeklyEvolution (),
206198 fetchLikes ,
207- fetchDownloads ,
208199 ])
209200} catch (err ) {
210201 console .warn (' [og-image-package] Failed to load data server-side:' , err )
@@ -238,11 +229,11 @@ const sparklineSrc = computed(() => {
238229 const svg = [
239230 ` <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width } ${height }" fill="none" preserveAspectRatio="none"> ` ,
240231 ` <defs><linearGradient id="af" x1="0" y1="0" x2="0" y2="1"> ` ,
241- ` <stop offset="0%" stop-color="white" stop-opacity="0.07 "/> ` ,
242- ` <stop offset="100%" stop-color="white" stop-opacity="0.005 "/> ` ,
232+ ` <stop offset="0%" stop-color="white" stop-opacity="0.018 "/> ` ,
233+ ` <stop offset="100%" stop-color="white" stop-opacity="0.001 "/> ` ,
243234 ` </linearGradient></defs> ` ,
244235 ` <path d="M ${firstX },${height } L ${pathData } L ${lastX },${height } Z" fill="url(#af)"/> ` ,
245- ` <path d="M ${pathData }" stroke="rgba(255,255,255,0.18 )" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> ` ,
236+ ` <path d="M ${pathData }" stroke="rgba(255,255,255,0.045 )" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/> ` ,
246237 ` </svg> ` ,
247238 ].join (' ' )
248239
@@ -251,15 +242,15 @@ const sparklineSrc = computed(() => {
251242 </script >
252243
253244<template >
254- <OgLayout >
245+ <OgLayout data-theme = " dark " >
255246 <div class =" px-15 py-12 flex flex-col justify-center gap-12 h-full" >
256247 <OgBrand :height =" 48" />
257248
258249 <div class =" flex flex-col max-w-full gap-3" >
259250 <div
260251 v-if =" pkgNameParts.org"
261- class =" lg:text-5xl text-3xl opacity-50 font-mono tracking-tight leading-none"
262- : style =" { textOverflow: ' ellipsis', lineClamp : 1 } "
252+ class =" lg:text-5xl text-3xl font-mono tracking-tight leading-none"
253+ style =" opacity : 0.5 ; text-overflow : ellipsis ; line-clamp : 1 "
263254 >
264255 {{ pkgNameParts.org }}
265256 </div >
@@ -268,65 +259,67 @@ const sparklineSrc = computed(() => {
268259 :class ="
269260 (pkgNameParts.short?.length ?? 0) > 20 ? 'lg:text-6xl text-4xl' : 'lg:text-7xl text-5xl'
270261 "
271- : style =" { textOverflow: ' ellipsis', lineClamp : 1, wordBreak: ' break-all' } "
262+ style =" text-overflow : ellipsis ; line-clamp : 1 ; word-break : break-all "
272263 >
273264 {{ pkgNameParts.short }}
274265 </div >
275266 <div
276267 v-if =" version"
277- class =" pt-3 lg:text-4xl text-3xl opacity-70 font-mono tracking-tight leading-none"
278- : style =" { textOverflow: ' ellipsis', lineClamp : 1 } "
268+ class =" pt-3 lg:text-4xl text-3xl font-mono tracking-tight leading-none"
269+ style =" opacity : 0.7 ; text-overflow : ellipsis ; line-clamp : 1 "
279270 >
280271 v{{ version }}
281272 </div >
282273 </div >
283274
284- <div class =" flex items-center gap-5 text-4xl text-fg-muted" >
275+ <div class =" flex flex-col gap-3 text-4xl text-fg-muted" >
285276 <div v-if =" repositoryUrl" class =" flex items-center gap-2" >
286277 <div
287278 class =" i-simple-icons:github shrink-0 text-fg-muted"
288- : style =" { width: '32px', height: '32px' } "
279+ style =" width : 24 px ; height : 24 px "
289280 />
290- <span v-if =" repoRef" class =" max-w-[500px]" : style =" { textOverflow: ' ellipsis' } " >
281+ <span v-if =" repoRef" class =" max-w-[500px]" style =" text-overflow : ellipsis " >
291282 {{ repoRef.owner }}<span class =" opacity-50" >/</span >{{ repoRef.repo }}
292283 </span >
293284 <span v-else >{{ $t('package.links.repo') }}</span >
294285 </div >
295286
296- <span v-if =" formattedDownloads" class =" flex items-center gap-2" data-testid =" downloads" >
297- <div
298- class =" i-lucide:download shrink-0 text-fg-muted"
299- :style =" { width: '32px', height: '32px' }"
300- />
301- <span >{{ formattedDownloads }}/wk</span >
302- </span >
287+ <div class =" flex items-center gap-5" >
288+ <span v-if =" formattedDownloads" class =" flex items-center gap-2" data-testid =" downloads" >
289+ <div
290+ class =" i-lucide:download shrink-0 text-fg-muted"
291+ style =" width : 24px ; height : 24px "
292+ />
293+ <span >{{ formattedDownloads }}/wk</span >
294+ </span >
303295
304- <span v-if =" formattedStars" class =" flex items-center gap-2" data-testid =" stars" >
305- <div
306- class =" i-lucide:star shrink-0 text-fg-muted"
307- : style =" { width: '32px', height: '32px', fill: ' white' } "
308- />
309- <span >{{ formattedStars }}</span >
310- </span >
296+ <span v-if =" formattedStars" class =" flex items-center gap-2" data-testid =" stars" >
297+ <div
298+ class =" i-lucide:star shrink-0 text-fg-muted"
299+ style =" width : 24 px ; height : 24 px ; fill : white "
300+ />
301+ <span >{{ formattedStars }}</span >
302+ </span >
311303
312- <span v-if =" formattedLikes" class =" flex items-center gap-2" data-testid =" likes" >
313- <div
314- class =" i-lucide:heart shrink-0 text-fg-muted"
315- : style =" { width: '32px', height: '32px', fill: ' white' } "
316- />
317- <span >{{ formattedLikes }}</span >
318- </span >
304+ <span v-if =" formattedLikes" class =" flex items-center gap-2" data-testid =" likes" >
305+ <div
306+ class =" i-lucide:heart shrink-0 text-fg-muted"
307+ style =" width : 24 px ; height : 24 px ; fill : white "
308+ />
309+ <span >{{ formattedLikes }}</span >
310+ </span >
319311
320- <div
321- v-if =" pkg?.license && !pkg.license.includes(' ')"
322- class =" flex items-center gap-2"
323- data-testid =" license"
324- >
325312 <div
326- class =" i-lucide:scale shrink-0 text-fg-subtle self-center"
327- :style =" { width: '32px', height: '32px' }"
328- />
329- <span >{{ pkg.license }}</span >
313+ v-if =" pkg?.license && !pkg.license.includes(' ')"
314+ class =" flex items-center gap-2"
315+ data-testid =" license"
316+ >
317+ <div
318+ class =" i-lucide:scale shrink-0 text-fg-subtle self-center"
319+ style =" width : 24px ; height : 24px "
320+ />
321+ <span >{{ pkg.license }}</span >
322+ </div >
330323 </div >
331324 </div >
332325 </div >
@@ -335,71 +328,84 @@ const sparklineSrc = computed(() => {
335328 <img
336329 v-if =" variant === 'download-chart' && sparklineSrc"
337330 :src =" sparklineSrc"
338- class =" absolute force-left-0 bottom-0 w-full h-[65%] opacity-30 "
331+ class =" absolute force-left-0 bottom-0 w-full h-[65%]"
339332 />
340333
341334 <!-- Code tree variant -->
342335 <div
343336 v-else-if =" variant === 'code-tree' && treeRows.length"
344- class =" text-fg-muted absolute force-right-8 top-8 bottom-8 w-[340px] flex flex-col gap-0 opacity-30 overflow-hidden font-mono text-4.5 leading-7 "
337+ class =" text-fg-muted absolute force-right-8 top-8 bottom-8 w-[340px] flex flex-col gap-0 opacity-30 overflow-hidden font-mono text-4.5 leading-8 "
345338 >
346339 <div
347340 v-for =" (row, i) in treeRows"
348341 :key =" i"
349- class =" flex items-center whitespace-nowrap text-fg"
342+ class =" flex items-center gap-3 whitespace-nowrap text-fg"
350343 :style =" { paddingLeft: `${row.depth * 20}px` }"
351344 >
352- <span
345+ <div
353346 v-if =" row.isDir"
354- class =" w-5 h-5 text-fg-muted shrink-0 force-mr-1.5 i-lucide:folder"
347+ class =" text-fg-muted shrink-0 i-lucide:folder"
348+ style =" width : 20px ; height : 20px "
349+ />
350+ <div
351+ v-else
352+ class =" text-fg-muted shrink-0 i-lucide:file"
353+ style =" width : 20px ; height : 20px "
355354 />
356- <span v-else class =" w-5 h-5 text-fg-muted shrink-0 force-mr-1.5 i-lucide:file" />
357355 <span class =" text-fg-muted" >{{ row.name }}</span >
358356 </div >
359357 </div >
360358
361359 <!-- Function tree variant (API symbols) -->
362360 <div
363361 v-else-if =" variant === 'function-tree' && symbolRows.length"
364- class =" absolute force-right-8 top-8 bottom-8 w-[340px] flex flex-col gap-0 opacity-30 overflow-hidden font-mono text-4.5 leading-7 "
362+ class =" absolute force-right-8 top-8 bottom-8 w-[340px] flex flex-col gap-0 opacity-30 overflow-hidden font-mono text-4.5 leading-8 "
365363 >
366364 <div
367365 v-for =" (row, i) in symbolRows"
368366 :key =" i"
369- class =" flex items-center whitespace-nowrap text-fg"
367+ class =" flex items-center gap-3 whitespace-nowrap text-fg"
370368 :style =" { paddingLeft: row.kind === 'symbol' ? '20px' : '0' }"
371369 >
372- <span
370+ <div
373371 v-if =" row.icon === 'i-lucide:parentheses'"
374- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:parentheses"
372+ class =" shrink-0 text-fg-muted i-lucide:parentheses"
373+ style =" width : 20px ; height : 20px "
375374 />
376- <span
375+ <div
377376 v-else-if =" row.icon === 'i-lucide:box'"
378- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:box"
377+ class =" shrink-0 text-fg-muted i-lucide:box"
378+ style =" width : 20px ; height : 20px "
379379 />
380- <span
380+ <div
381381 v-else-if =" row.icon === 'i-lucide:puzzle'"
382- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:puzzle"
382+ class =" shrink-0 text-fg-muted i-lucide:puzzle"
383+ style =" width : 20px ; height : 20px "
383384 />
384- <span
385+ <div
385386 v-else-if =" row.icon === 'i-lucide:type'"
386- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:type"
387+ class =" shrink-0 text-fg-muted i-lucide:type"
388+ style =" width : 20px ; height : 20px "
387389 />
388- <span
390+ <div
389391 v-else-if =" row.icon === 'i-lucide:variable'"
390- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:variable"
392+ class =" shrink-0 text-fg-muted i-lucide:variable"
393+ style =" width : 20px ; height : 20px "
391394 />
392- <span
395+ <div
393396 v-else-if =" row.icon === 'i-lucide:list'"
394- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:list"
397+ class =" shrink-0 text-fg-muted i-lucide:list"
398+ style =" width : 20px ; height : 20px "
395399 />
396- <span
400+ <div
397401 v-else-if =" row.icon === 'i-lucide:package'"
398- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:package"
402+ class =" shrink-0 text-fg-muted i-lucide:package"
403+ style =" width : 20px ; height : 20px "
399404 />
400- <span
401- v-else-if =" row.kind === 'symbol'"
402- class =" w-5 h-5 shrink-0 text-fg-muted force-mr-1.5 i-lucide:code"
405+ <div
406+ v-else
407+ class =" shrink-0 text-fg-muted i-lucide:code"
408+ style =" width : 20px ; height : 20px "
403409 />
404410 <span class =" text-fg-muted" :class =" row.kind === 'section' ? 'text-4 mt-1' : ''" >{{
405411 row.name
0 commit comments