Skip to content

Commit ebdbf0c

Browse files
authored
feat: versions page improvements (#2844)
1 parent 4aed48b commit ebdbf0c

1 file changed

Lines changed: 89 additions & 71 deletions

File tree

app/pages/package/[[org]]/[name]/versions.vue

Lines changed: 89 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ const flatItems = computed<FlatItem[]>(() => {
269269
<main class="flex-1 flex flex-col">
270270
<!-- Header -->
271271
<header class="border-b border-border bg-bg sticky top-14 z-20">
272-
<div class="container py-3 flex items-center justify-between gap-4">
272+
<div class="container py-3 flex items-center justify-between gap-2 sm:gap-4">
273273
<div class="flex items-center gap-2 min-w-0">
274274
<NuxtLink
275275
:to="packageRoute(packageName)"
@@ -283,73 +283,43 @@ const flatItems = computed<FlatItem[]>(() => {
283283
<span class="text-fg-subtle shrink-0">/</span>
284284
<h1 class="text-sm text-fg-muted shrink-0">{{ $t('package.versions.page_title') }}</h1>
285285
</div>
286-
<div class="relative">
287-
<InputBase
288-
v-model="versionFilterInput"
289-
type="text"
290-
:placeholder="$t('package.versions.filter_placeholder')"
291-
:aria-label="$t('package.versions.filter_placeholder')"
292-
:aria-invalid="isInvalidRange ? 'true' : undefined"
293-
:aria-describedby="isInvalidRange ? 'version-filter-error' : undefined"
294-
autocomplete="off"
295-
size="sm"
296-
class="w-36 sm:w-64"
297-
:class="isInvalidRange ? 'pe-7 !border-red-500' : ''"
298-
/>
299-
<Transition
300-
enter-active-class="transition-all duration-150"
301-
enter-from-class="opacity-0 scale-60"
302-
leave-active-class="transition-all duration-150"
303-
leave-to-class="opacity-0 scale-60"
304-
>
305-
<TooltipApp
306-
v-if="isInvalidRange"
307-
:text="$t('package.versions.filter_invalid')"
308-
position="bottom"
309-
class="absolute end-0 inset-y-0 flex items-center pe-2"
310-
>
311-
<span
312-
id="version-filter-error"
313-
class="i-lucide:circle-alert w-3.5 h-3.5 text-red-500 block"
314-
role="img"
315-
:aria-label="$t('package.versions.filter_invalid')"
316-
/>
317-
</TooltipApp>
318-
</Transition>
319-
</div>
320286
</div>
321287
</header>
322288

323289
<!-- Content -->
324290
<div class="container w-full py-8 space-y-8">
325291
<!-- ── Current Tags ───────────────────────────────────────────────────── -->
326292
<section class="space-y-3">
327-
<h2 class="text-xs text-fg-subtle uppercase tracking-wider px-4 sm:px-6 ps-1">
293+
<h2 class="text-sm text-fg-subtle uppercase">
328294
{{ $t('package.versions.current_tags') }}
329295
</h2>
330296

331297
<!-- Latest — featured card -->
332298
<div
333299
v-if="latestTagRow"
334-
class="border-y sm:rounded-lg sm:border border-accent/40 bg-accent/5 px-4 py-4 relative flex items-center justify-between gap-4 hover:bg-accent/8 transition-colors"
300+
class="border-y sm:rounded-lg sm:border border-accent/40 bg-accent/5 px-4 py-4 relative flex max-sm:flex-col sm:items-center justify-between gap-2 sm:gap-4 hover:bg-accent/8 transition-colors"
335301
>
336302
<!-- Left: tags + version + deprecated -->
337303
<div>
338304
<div class="flex items-center gap-2 mb-1.5 flex-wrap">
339-
<span class="text-3xs font-bold uppercase tracking-widest text-accent">latest</span>
305+
<span class="text-xs font-bold uppercase tracking-wider text-accent">latest</span>
340306
<span
341307
v-for="tag in latestTagRow!.tags.filter(t => t !== 'latest')"
342308
:key="tag"
343-
class="text-3xs font-semibold uppercase tracking-wide text-fg-subtle"
309+
class="text-xs font-semibold uppercase tracking-wider text-fg-subtle"
344310
:title="tag"
345311
>{{ tag }}</span
346312
>
347313
<span
348314
v-if="fullVersionMap?.get(latestTagRow!.version)?.deprecated"
349-
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
315+
class="text-xs font-medium text-red-700 dark:text-red-400 relative z-10"
350316
:title="fullVersionMap!.get(latestTagRow!.version)!.deprecated"
351-
>deprecated</span
352317
>
318+
<span class="sm:hidden i-lucide:octagon-alert" aria-hidden="true"></span>
319+
<span class="max-sm:sr-only bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
320+
>deprecated</span
321+
>
322+
</span>
353323
</div>
354324
<div class="flex items-center gap-2">
355325
<LinkBase
@@ -370,10 +340,10 @@ const flatItems = computed<FlatItem[]>(() => {
370340
</div>
371341
</div>
372342
<!-- Right: downloads + date -->
373-
<div class="flex items-center gap-4 shrink-0 relative z-10">
343+
<div class="flex sm:items-center gap-2 sm:gap-4 shrink-0 relative z-10">
374344
<span
375345
v-if="getVersionDownloads(latestTagRow!.version)"
376-
class="w-28 grid grid-flow-col auto-cols-max items-center gap-1 text-xs text-fg-muted tabular-nums justify-end"
346+
class="max-w-32 md:w-32 grid grid-flow-col auto-cols-max items-center gap-1 text-xs text-fg-muted tabular-nums sm:justify-end"
377347
:aria-label="
378348
getDownloadsAriaLabel(
379349
getVersionDownloads(latestTagRow!.version)!,
@@ -394,7 +364,7 @@ const flatItems = computed<FlatItem[]>(() => {
394364
<DateTime
395365
v-if="getVersionTime(latestTagRow!.version)"
396366
:datetime="getVersionTime(latestTagRow!.version)!"
397-
class="text-xs text-fg-subtle whitespace-nowrap w-24 text-end"
367+
class="text-xs text-fg-subtle whitespace-nowrap w-24 sm:text-end"
398368
year="numeric"
399369
month="short"
400370
day="numeric"
@@ -410,24 +380,24 @@ const flatItems = computed<FlatItem[]>(() => {
410380
<div
411381
v-for="row in otherTagRows"
412382
:key="row.id"
413-
class="flex items-center gap-4 px-4 py-2.5 border-b border-border last:border-0 hover:bg-bg-subtle transition-colors relative"
383+
class="flex items-center gap-2 sm:gap-4 px-4 py-2.5 border-b border-border last:border-0 hover:bg-bg-subtle transition-colors relative"
414384
>
415385
<!-- Tag labels -->
416-
<div class="w-28 shrink-0 flex flex-wrap gap-x-1.5 gap-y-0.5">
386+
<div class="max-w-[max(32px,32vw)] md:w-32 shrink-0 flex flex-wrap gap-x-1.5 gap-y-0.5">
417387
<span
418388
v-for="tag in row.tags"
419389
:key="tag"
420-
class="text-3xs font-semibold uppercase tracking-wide text-fg-subtle"
390+
class="text-xs font-semibold uppercase tracking-wider text-fg-subtle"
421391
:title="tag"
422392
>{{ tag }}</span
423393
>
424394
</div>
425395

426396
<!-- Version + Provenance + Deprecated -->
427-
<div class="flex-1 min-w-0 flex items-center gap-2">
397+
<div class="flex-1 flex items-center gap-2">
428398
<LinkBase
429399
:to="packageRoute(packageName, row.version)"
430-
class="text-sm after:absolute after:inset-0 after:content-['']"
400+
class="block! min-w-16 max-sm:max-w-40 text-sm after:absolute after:inset-0 after:content-[''] truncate"
431401
:title="row.version"
432402
dir="ltr"
433403
>
@@ -443,24 +413,28 @@ const flatItems = computed<FlatItem[]>(() => {
443413
/>
444414
<span
445415
v-if="fullVersionMap?.get(row.version)?.deprecated"
446-
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded relative z-10"
416+
class="text-xs font-medium text-red-700 dark:text-red-400 relative z-10"
447417
:title="fullVersionMap!.get(row.version)!.deprecated"
448-
>deprecated</span
449418
>
419+
<span class="sm:hidden i-lucide:octagon-alert" aria-hidden="true"></span>
420+
<span class="max-sm:sr-only bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
421+
>deprecated</span
422+
>
423+
</span>
450424
</div>
451425

452426
<!-- Downloads -->
453427
<span
454428
v-if="getVersionDownloads(row.version)"
455-
class="w-28 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0 relative z-10"
429+
class="max-w-32 md:w-32 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0 relative z-10"
456430
:aria-label="getDownloadsAriaLabel(getVersionDownloads(row.version)!, row.version)"
457431
dir="ltr"
458432
:title="getDownloadsAriaLabel(getVersionDownloads(row.version)!, row.version)"
459433
>
460434
<span>{{ numberFormatter.format(getVersionDownloads(row.version)!) }}</span>
461435
<span class="i-lucide:chart-line" aria-hidden="true"></span>
462436
</span>
463-
<span v-else class="w-28 shrink-0" />
437+
<span v-else class="max-w-32 md:w-32 shrink-0" />
464438

465439
<!-- Date -->
466440
<div class="flex items-center gap-2 shrink-0 relative z-10">
@@ -479,12 +453,47 @@ const flatItems = computed<FlatItem[]>(() => {
479453

480454
<!-- ── Version History ───────────────────────────────────────────────── -->
481455
<section v-if="versionGroups.length > 0">
482-
<h2 class="text-xs text-fg-subtle uppercase tracking-wider mb-3 px-4 sm:px-6 ps-1">
483-
{{ $t('package.versions.page_title') }}
484-
<span class="ms-1 normal-case font-normal tracking-normal">
485-
({{ versionStrings.length }})
486-
</span>
487-
</h2>
456+
<div class="flex max-sm:flex-col sm:items-center justify-between gap-2 mb-3">
457+
<h2 class="text-sm text-fg-subtle uppercase">
458+
{{ $t('package.versions.page_title') }}
459+
<span class="ms-1 normal-case font-normal"> ({{ versionStrings.length }}) </span>
460+
</h2>
461+
462+
<div class="relative">
463+
<InputBase
464+
v-model="versionFilterInput"
465+
type="text"
466+
:placeholder="$t('package.versions.filter_placeholder')"
467+
:aria-label="$t('package.versions.filter_placeholder')"
468+
:aria-invalid="isInvalidRange ? 'true' : undefined"
469+
:aria-describedby="isInvalidRange ? 'version-filter-error' : undefined"
470+
autocomplete="off"
471+
size="sm"
472+
class="w-36 sm:w-64 max-sm:w-full"
473+
:class="isInvalidRange ? 'pe-7 !border-red-500' : ''"
474+
/>
475+
<Transition
476+
enter-active-class="transition-all duration-150"
477+
enter-from-class="opacity-0 scale-60"
478+
leave-active-class="transition-all duration-150"
479+
leave-to-class="opacity-0 scale-60"
480+
>
481+
<TooltipApp
482+
v-if="isInvalidRange"
483+
:text="$t('package.versions.filter_invalid')"
484+
position="bottom"
485+
class="absolute end-0 inset-y-0 flex items-center pe-2"
486+
>
487+
<span
488+
id="version-filter-error"
489+
class="i-lucide:circle-alert w-3.5 h-3.5 text-red-500 block"
490+
role="img"
491+
:aria-label="$t('package.versions.filter_invalid')"
492+
/>
493+
</TooltipApp>
494+
</Transition>
495+
</div>
496+
</div>
488497

489498
<!-- No filter matches -->
490499
<div
@@ -533,16 +542,21 @@ const flatItems = computed<FlatItem[]>(() => {
533542
<span class="text-sm font-medium">{{ item.label }}</span>
534543
<span
535544
v-if="deprecatedGroupKeys.has(item.groupKey)"
536-
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
537-
>deprecated</span
545+
class="text-xs font-medium text-red-700 dark:text-red-400 relative z-10"
538546
>
547+
<span class="sm:hidden i-lucide:octagon-alert" aria-hidden="true"></span>
548+
<span
549+
class="max-sm:sr-only bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
550+
>deprecated</span
551+
>
552+
</span>
539553
<span class="text-xs text-fg-subtle">({{ item.versions.length }})</span>
540-
<span class="text-xs text-fg-muted" :title="item.versions[0]" dir="ltr"
554+
<span class="text-xs text-fg-muted truncate" :title="item.versions[0]" dir="ltr"
541555
>v{{ item.versions[0] }}</span
542556
>
543557
<span
544558
v-if="groupDownloadsMap.has(item.groupKey)"
545-
class="ms-auto w-28 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0"
559+
class="ms-auto max-w-32 md:w-32 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0"
546560
:aria-label="
547561
getDownloadsAriaLabel(groupDownloadsMap.get(item.groupKey)!, item.label)
548562
"
@@ -556,7 +570,7 @@ const flatItems = computed<FlatItem[]>(() => {
556570
}}</span>
557571
<span class="i-lucide:chart-line" aria-hidden="true"></span>
558572
</span>
559-
<span v-else class="ms-auto w-28 shrink-0" />
573+
<span v-else class="ms-auto max-w-32 md:w-32 shrink-0" />
560574
<span class="flex items-center gap-3 shrink-0">
561575
<DateTime
562576
v-if="getVersionTime(item.versions[0]!)"
@@ -618,7 +632,7 @@ const flatItems = computed<FlatItem[]>(() => {
618632
<span
619633
v-for="tag in versionToTagsMap.get(item.version)"
620634
:key="tag"
621-
class="text-4xs font-semibold uppercase tracking-wide"
635+
class="text-2xs font-semibold uppercase tracking-wide"
622636
:class="tag === 'latest' ? 'text-accent' : 'text-fg-subtle'"
623637
:title="tag"
624638
>
@@ -627,17 +641,21 @@ const flatItems = computed<FlatItem[]>(() => {
627641
</div>
628642
<span
629643
v-if="fullVersionMap?.get(item.version)?.deprecated"
630-
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded relative z-10"
644+
class="text-xs font-medium text-red-700 dark:text-red-400 relative z-10"
631645
:title="fullVersionMap.get(item.version)!.deprecated"
632646
>
633-
deprecated
647+
<span class="sm:hidden i-lucide:octagon-alert" aria-hidden="true"></span>
648+
<span
649+
class="max-sm:sr-only bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded"
650+
>deprecated</span
651+
>
634652
</span>
635653
</div>
636654

637655
<!-- Downloads -->
638656
<span
639657
v-if="getVersionDownloads(item.version)"
640-
class="w-28 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0 relative z-10"
658+
class="max-w-32 md:w-32 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0 relative z-10"
641659
:aria-label="
642660
getDownloadsAriaLabel(getVersionDownloads(item.version)!, item.version)
643661
"
@@ -651,7 +669,7 @@ const flatItems = computed<FlatItem[]>(() => {
651669
}}</span>
652670
<span class="i-lucide:chart-line" aria-hidden="true"></span>
653671
</span>
654-
<span v-else class="w-28 shrink-0" />
672+
<span v-else class="max-w-32 md:w-32 shrink-0" />
655673

656674
<!-- Date -->
657675
<div class="flex items-center gap-2 shrink-0 relative z-10">
@@ -690,7 +708,7 @@ const flatItems = computed<FlatItem[]>(() => {
690708
>
691709
<span
692710
v-if="groupDownloadsMap.has(item.groupKey)"
693-
class="ms-auto w-28 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0"
711+
class="ms-auto max-w-32 md:w-32 grid grid-flow-col auto-cols-max items-center justify-end gap-1 text-xs text-fg-muted tabular-nums shrink-0"
694712
:aria-label="
695713
getDownloadsAriaLabel(groupDownloadsMap.get(item.groupKey)!, item.label)
696714
"
@@ -702,7 +720,7 @@ const flatItems = computed<FlatItem[]>(() => {
702720
<span>{{ numberFormatter.format(groupDownloadsMap.get(item.groupKey)!) }}</span>
703721
<span class="i-lucide:chart-line" aria-hidden="true"></span>
704722
</span>
705-
<span v-else class="ms-auto w-28 shrink-0" />
723+
<span v-else class="ms-auto max-w-32 md:w-32 shrink-0" />
706724
<span class="flex items-center gap-3 shrink-0">
707725
<DateTime
708726
v-if="getVersionTime(item.versions[0] ?? '')"

0 commit comments

Comments
 (0)