Skip to content
Merged
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
66 changes: 48 additions & 18 deletions app/components/Package/MetricsBadges.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ const props = defineProps<{
version?: string
}>()

const { data: analysis } = usePackageAnalysis(
const { data: analysis, status } = usePackageAnalysis(
() => props.packageName,
() => props.version,
)

const isLoading = computed(() => status.value !== 'error' && !analysis.value)

// ESM support
const hasEsm = computed(() => {
if (!analysis.value) return false
Expand Down Expand Up @@ -52,25 +54,33 @@ const typesHref = computed(() => {
</script>

<template>
<ul v-if="analysis" class="flex items-center gap-1.5 list-none m-0 p-0">
<ul class="flex items-center gap-1.5 list-none m-0 p-0">
<!-- TypeScript types badge -->
<li v-if="!props.isBinary">
<li v-if="!props.isBinary" class="contents">
<TooltipApp :text="typesTooltip">
<component
:is="typesHref ? NuxtLink : 'span'"
:to="typesHref"
:tabindex="!typesHref ? 0 : undefined"
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
class="flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
:class="[
hasTypes
? 'text-fg-muted bg-bg-muted border border-border'
: 'text-fg-subtle bg-bg-subtle border border-border-subtle',
isLoading
? 'text-fg-subtle bg-bg-subtle border border-border-subtle'
: hasTypes
? 'text-fg-muted bg-bg-muted border border-border'
: 'text-fg-subtle bg-bg-subtle border border-border-subtle',
typesHref
? 'hover:text-fg hover:border-border-hover focus-visible:outline-accent/70'
: '',
]"
>
<span
v-if="isLoading"
class="i-carbon-circle-dash w-3 h-3 motion-safe:animate-spin"
aria-hidden="true"
/>
<span
v-else
class="w-3 h-3"
:class="hasTypes ? 'i-carbon-checkmark' : 'i-carbon-close'"
aria-hidden="true"
Expand All @@ -81,18 +91,28 @@ const typesHref = computed(() => {
</li>

<!-- ESM badge (show with X if missing) -->
<li>
<TooltipApp :text="hasEsm ? $t('package.metrics.esm') : $t('package.metrics.no_esm')">
<li class="contents">
<TooltipApp
:text="isLoading ? '' : hasEsm ? $t('package.metrics.esm') : $t('package.metrics.no_esm')"
>
<span
tabindex="0"
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
class="flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
:class="
hasEsm
? 'text-fg-muted bg-bg-muted border border-border'
: 'text-fg-subtle bg-bg-subtle border border-border-subtle'
isLoading
? 'text-fg-subtle bg-bg-subtle border border-border-subtle'
: hasEsm
? 'text-fg-muted bg-bg-muted border border-border'
: 'text-fg-subtle bg-bg-subtle border border-border-subtle'
"
>
<span
v-if="isLoading"
class="i-carbon-circle-dash w-3 h-3 motion-safe:animate-spin"
aria-hidden="true"
/>
<span
v-else
class="w-3 h-3"
:class="hasEsm ? 'i-carbon-checkmark' : 'i-carbon-close'"
aria-hidden="true"
Expand All @@ -102,14 +122,24 @@ const typesHref = computed(() => {
</TooltipApp>
</li>

<!-- CJS badge (only show if present) -->
<li v-if="hasCjs">
<TooltipApp :text="$t('package.metrics.cjs')">
<!-- CJS badge -->
<li v-if="isLoading || hasCjs" class="contents">
<TooltipApp :text="isLoading ? '' : $t('package.metrics.cjs')">
<span
tabindex="0"
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs text-fg-muted bg-bg-muted border border-border rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
class="flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)"
:class="
isLoading
? 'text-fg-subtle bg-bg-subtle border border-border-subtle'
: 'text-fg-muted bg-bg-muted border border-border'
"
>
<span class="i-carbon-checkmark w-3 h-3" aria-hidden="true" />
<span
v-if="isLoading"
class="i-carbon-circle-dash w-3 h-3 motion-safe:animate-spin"
aria-hidden="true"
/>
<span v-else class="i-carbon-checkmark w-3 h-3" aria-hidden="true" />
CJS
</span>
</TooltipApp>
Expand Down
26 changes: 14 additions & 12 deletions app/pages/package/[...package].vue
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,8 @@ defineOgImageComponent('Package', {
</span>

<!-- Package metrics (module format, types) -->
<ClientOnly>
<div class="flex gap-2 sm:gap-3 flex-wrap">
<div class="flex gap-2 sm:gap-3 flex-wrap">
<ClientOnly>
<PackageMetricsBadges
v-if="resolvedVersion"
:package-name="pkg.name"
Expand All @@ -613,16 +613,18 @@ defineOgImageComponent('Package', {
/>
<span>{{ formatCompactNumber(likesData?.totalLikes ?? 0, { decimals: 1 }) }}</span>
</button>
</div>

<template #fallback>
<div class="flex items-center gap-1.5 self-baseline ms-1 sm:ms-2">
<SkeletonBlock class="w-8 h-5 rounded" />
<SkeletonBlock class="w-12 h-5 rounded" />
<SkeletonBlock class="w-5 h-5 rounded" />
</div>
</template>
</ClientOnly>
<template #fallback>
<div
class="flex items-center gap-1.5 list-none m-0 p-0 relative top-[5px] self-baseline ms-1 sm:ms-2"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The relative top-[5px] sucks a bit, but gets the job done. Honestly, I have no better idea how to fix it while keeping baseline alignment.

Copy link
Member

Choose a reason for hiding this comment

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

what about having the text visible so it's just the icon that loads? we could even replace it with a spinner to give better feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's probably a good idea, but if I may have a say, I'd do it as a next iterative improvement. It's likely not going to be such an easy fix as this was.

Copy link
Member

Choose a reason for hiding this comment

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

pushed a first stab - what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sweet!

>
<SkeletonBlock class="w-16 h-5.5 rounded" />
<SkeletonBlock class="w-13 h-5.5 rounded" />
<SkeletonBlock class="w-13 h-5.5 rounded" />
<SkeletonBlock class="w-13 h-5.5 rounded bg-bg-subtle" />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I intentionally used a white div as the like button is itself white, but I'm okay with this.

</div>
</template>
</ClientOnly>
</div>

<!-- Internal navigation: Docs + Code + Compare (hidden on mobile, shown in external links instead) -->
<nav
Expand Down
Loading