Skip to content

Commit 71379ab

Browse files
committed
fix: reduce cls on package page
1 parent 4a6d0b6 commit 71379ab

3 files changed

Lines changed: 107 additions & 142 deletions

File tree

app/components/Package/WeeklyDownloadStats.vue

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ const config = computed(() => {
228228
>
229229
<span class="sr-only">{{ $t('package.downloads.analyze') }}</span>
230230
</ButtonBase>
231+
<span v-else-if="isLoadingWeeklyDownloads" class="min-w-6 min-h-6 -m-1 p-1" />
231232
</template>
232233

233234
<div class="w-full overflow-hidden">
@@ -240,26 +241,21 @@ const config = computed(() => {
240241
</template>
241242
</VueUiSparkline>
242243
<template #fallback>
243-
<!-- Skeleton matching sparkline layout: title row + chart with data label -->
244-
<div class="min-h-[75.195px]">
245-
<!-- Title row: date range (24px height) -->
244+
<!-- Skeleton matching VueUiSparkline layout (title 24px + SVG aspect 500:80) -->
245+
<div class="max-w-xs">
246+
<!-- Title row: fontSize * 2 = 24px -->
246247
<div class="h-6 flex items-center ps-3">
247248
<SkeletonInline class="h-3 w-36" />
248249
</div>
249-
<!-- Chart area: data label left, sparkline right -->
250+
<!-- Chart area: matches SVG viewBox 500:80 -->
250251
<div class="aspect-[500/80] flex items-center">
251-
<!-- Data label (covers ~42% width) -->
252+
<!-- Data label (covers ~42% width, matching dataLabel.offsetX) -->
252253
<div class="w-[42%] flex items-center ps-0.5">
253254
<SkeletonInline class="h-7 w-24" />
254255
</div>
255-
<!-- Sparkline area (~58% width) -->
256-
<div class="flex-1 flex items-end gap-0.5 h-4/5 pe-3">
257-
<SkeletonInline
258-
v-for="i in 16"
259-
:key="i"
260-
class="flex-1 rounded-sm"
261-
:style="{ height: `${25 + ((i * 7) % 50)}%` }"
262-
/>
256+
<!-- Sparkline line placeholder -->
257+
<div class="flex-1 flex items-end pe-3">
258+
<SkeletonInline class="h-px w-full" />
263259
</div>
264260
</div>
265261
</div>

app/pages/about.vue

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@
22
const router = useRouter()
33
const canGoBack = useCanGoBack()
44
5-
interface GitHubContributor {
6-
login: string
7-
id: number
8-
avatar_url: string
9-
html_url: string
10-
contributions: number
11-
}
12-
135
useSeoMeta({
146
title: () => `${$t('about.title')} - npmx`,
157
ogTitle: () => `${$t('about.title')} - npmx`,
@@ -34,12 +26,7 @@ const pmLinks = {
3426
vlt: 'https://www.vlt.sh/',
3527
}
3628
37-
const { data: contributors, status: contributorsStatus } = useFetch<GitHubContributor[]>(
38-
'/api/contributors',
39-
{
40-
lazy: true,
41-
},
42-
)
29+
const { data: contributors, status: contributorsStatus } = useLazyFetch('/api/contributors')
4330
</script>
4431

4532
<template>

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

Lines changed: 97 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { detectPublishSecurityDowngradeForVersion } from '~/utils/publish-securi
1717
import { useModal } from '~/composables/useModal'
1818
import { useAtproto } from '~/composables/atproto/useAtproto'
1919
import { togglePackageLike } from '~/utils/atproto/likes'
20-
import { LinkBase } from '#components'
2120
2221
defineOgImageComponent('Package', {
2322
name: () => packageName.value,
@@ -205,10 +204,7 @@ if (import.meta.client) {
205204
)
206205
}
207206
208-
const provenanceBadgeMounted = shallowRef(false)
209-
onMounted(() => {
210-
provenanceBadgeMounted.value = true
211-
})
207+
const isMounted = useMounted()
212208
213209
// Keep latestVersion for comparison (to show "(latest)" badge)
214210
const latestVersion = computed(() => {
@@ -450,7 +446,7 @@ const { data: likesData, status: likeStatus } = useFetch(
450446
},
451447
)
452448
const isLoadingLikeData = computed(
453-
() => likeStatus.value !== 'error' && likeStatus.value !== 'success',
449+
() => likeStatus.value === 'pending' || likeStatus.value === 'idle',
454450
)
455451
456452
const isLikeActionPending = shallowRef(false)
@@ -617,7 +613,7 @@ onKeyStroke(
617613
>
618614
<span dir="ltr" v-else>v{{ resolvedVersion }}</span>
619615

620-
<template v-if="hasProvenance(displayVersion) && provenanceBadgeMounted">
616+
<template v-if="hasProvenance(displayVersion)">
621617
<TooltipApp
622618
:text="
623619
provenanceData && provenanceStatus !== 'pending'
@@ -680,62 +676,53 @@ onKeyStroke(
680676
</ButtonGroup>
681677

682678
<!-- Package metrics -->
683-
<div class="basis-full flex gap-2 sm:gap-3 flex-wrap">
684-
<ClientOnly>
685-
<PackageMetricsBadges
686-
v-if="resolvedVersion"
687-
:package-name="pkg.name"
688-
:version="resolvedVersion"
689-
:is-binary="isBinaryOnly"
690-
class="self-baseline"
691-
/>
679+
<div class="basis-full flex gap-2 sm:gap-3 flex-wrap items-stretch">
680+
<PackageMetricsBadges
681+
v-if="resolvedVersion"
682+
:package-name="pkg.name"
683+
:version="resolvedVersion"
684+
:is-binary="isBinaryOnly"
685+
class="self-baseline"
686+
/>
692687

693-
<!-- Package likes -->
694-
<TooltipApp
695-
:text="
696-
isLoadingLikeData
697-
? $t('common.loading')
698-
: likesData?.userHasLiked
699-
? $t('package.likes.unlike')
700-
: $t('package.likes.like')
688+
<!-- Package likes -->
689+
<TooltipApp
690+
:text="
691+
isLoadingLikeData
692+
? $t('common.loading')
693+
: likesData?.userHasLiked
694+
? $t('package.likes.unlike')
695+
: $t('package.likes.like')
696+
"
697+
position="bottom"
698+
class="items-center"
699+
>
700+
<ButtonBase
701+
@click="likeAction"
702+
size="small"
703+
:title="
704+
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
705+
"
706+
:aria-label="
707+
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
708+
"
709+
:aria-pressed="likesData?.userHasLiked"
710+
:classicon="
711+
likesData?.userHasLiked
712+
? 'i-lucide-heart-minus text-red-500'
713+
: 'i-lucide-heart-plus'
701714
"
702-
position="bottom"
703-
class="items-center"
704715
>
705716
<span
706717
v-if="isLoadingLikeData"
707-
class="i-carbon-circle-dash w-3 h-3 motion-safe:animate-spin"
718+
class="i-carbon-circle-dash w-3 h-3 motion-safe:animate-spin my-0.5"
708719
aria-hidden="true"
709720
/>
710-
<ButtonBase
711-
v-else
712-
@click="likeAction"
713-
size="small"
714-
:title="
715-
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
716-
"
717-
:aria-label="
718-
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
719-
"
720-
:aria-pressed="likesData?.userHasLiked"
721-
:classicon="
722-
likesData?.userHasLiked
723-
? 'i-lucide-heart-minus text-red-500'
724-
: 'i-lucide-heart-plus'
725-
"
726-
>
721+
<span v-else>
727722
{{ compactNumberFormatter.format(likesData?.totalLikes ?? 0) }}
728-
</ButtonBase>
729-
</TooltipApp>
730-
<template #fallback>
731-
<div class="flex items-center gap-1.5 list-none m-0 p-0 self-baseline">
732-
<SkeletonBlock class="w-16 h-5.5 rounded" />
733-
<SkeletonBlock class="w-13 h-5.5 rounded" />
734-
<SkeletonBlock class="w-13 h-5.5 rounded" />
735-
<SkeletonBlock class="w-13 h-5.5 rounded bg-bg-subtle" />
736-
</div>
737-
</template>
738-
</ClientOnly>
723+
</span>
724+
</ButtonBase>
725+
</TooltipApp>
739726
</div>
740727
</div>
741728
</header>
@@ -744,7 +731,7 @@ onKeyStroke(
744731
<section :class="$style.areaDetails">
745732
<div class="mb-4">
746733
<!-- Description container with min-height to prevent CLS -->
747-
<div class="max-w-2xl min-h-[4.5rem]">
734+
<div class="max-w-2xl">
748735
<p v-if="pkgDescription" class="text-fg-muted text-base m-0">
749736
<span v-html="pkgDescription" />
750737
</p>
@@ -775,6 +762,7 @@ onKeyStroke(
775762
{{ compactNumberFormatter.format(forks) }}
776763
</LinkBase>
777764
</li>
765+
<li class="basis-full sm:hidden" />
778766
<li v-if="homepageUrl">
779767
<LinkBase :to="homepageUrl" classicon="i-carbon:link">
780768
{{ $t('package.links.homepage') }}
@@ -949,42 +937,32 @@ onKeyStroke(
949937
</div>
950938

951939
<!-- Vulnerabilities count -->
952-
<ClientOnly>
953-
<div class="space-y-1 sm:col-span-2">
954-
<dt class="text-xs text-fg-subtle uppercase tracking-wider">
955-
{{ $t('package.stats.vulns') }}
956-
</dt>
957-
<dd class="font-mono text-sm text-fg">
940+
<div class="space-y-1 sm:col-span-2">
941+
<dt class="text-xs text-fg-subtle uppercase tracking-wider">
942+
{{ $t('package.stats.vulns') }}
943+
</dt>
944+
<dd class="font-mono text-sm text-fg">
945+
<span
946+
v-if="vulnTreeStatus === 'pending' || vulnTreeStatus === 'idle'"
947+
class="inline-flex items-center gap-1 text-fg-subtle"
948+
>
958949
<span
959-
v-if="vulnTreeStatus === 'pending' || vulnTreeStatus === 'idle'"
960-
class="inline-flex items-center gap-1 text-fg-subtle"
961-
>
962-
<span
963-
class="i-carbon:circle-dash w-3 h-3 motion-safe:animate-spin"
964-
aria-hidden="true"
965-
/>
950+
class="i-carbon:circle-dash w-3 h-3 motion-safe:animate-spin"
951+
aria-hidden="true"
952+
/>
953+
</span>
954+
<span v-else-if="vulnTreeStatus === 'success'">
955+
<span v-if="hasVulnerabilities" class="text-amber-500">
956+
{{ numberFormatter.format(vulnCount) }}
966957
</span>
967-
<span v-else-if="vulnTreeStatus === 'success'">
968-
<span v-if="hasVulnerabilities" class="text-amber-500">
969-
{{ numberFormatter.format(vulnCount) }}
970-
</span>
971-
<span v-else class="inline-flex items-center gap-1 text-fg-muted">
972-
<span class="i-carbon:checkmark w-3 h-3" aria-hidden="true" />
973-
{{ numberFormatter.format(0) }}
974-
</span>
958+
<span v-else class="inline-flex items-center gap-1 text-fg-muted">
959+
<span class="i-carbon:checkmark w-3 h-3" aria-hidden="true" />
960+
{{ numberFormatter.format(0) }}
975961
</span>
976-
<span v-else class="text-fg-subtle">-</span>
977-
</dd>
978-
</div>
979-
<template #fallback>
980-
<div class="space-y-1 sm:col-span-2">
981-
<dt class="text-xs text-fg-subtle uppercase tracking-wider">
982-
{{ $t('package.stats.vulns') }}
983-
</dt>
984-
<dd class="font-mono text-sm text-fg-subtle">-</dd>
985-
</div>
986-
</template>
987-
</ClientOnly>
962+
</span>
963+
<span v-else class="text-fg-subtle">-</span>
964+
</dd>
965+
</div>
988966

989967
<div
990968
v-if="resolvedVersion && pkg.time?.[resolvedVersion]"
@@ -1183,32 +1161,30 @@ onKeyStroke(
11831161
{{ $t('package.readme.title') }}
11841162
</LinkBase>
11851163
</h2>
1186-
<ClientOnly>
1187-
<div class="flex gap-2">
1188-
<!-- Copy readme as Markdown button -->
1189-
<TooltipApp
1190-
v-if="readmeData?.md"
1191-
:text="$t('package.readme.copy_as_markdown')"
1192-
position="bottom"
1164+
<div class="flex gap-2">
1165+
<!-- Copy readme as Markdown button -->
1166+
<TooltipApp
1167+
v-if="readmeData?.md"
1168+
:text="$t('package.readme.copy_as_markdown')"
1169+
position="bottom"
1170+
>
1171+
<ButtonBase
1172+
@click="copyReadme()"
1173+
:aria-pressed="copiedReadme"
1174+
:aria-label="
1175+
copiedReadme ? $t('common.copied') : $t('package.readme.copy_as_markdown')
1176+
"
1177+
:classicon="copiedReadme ? 'i-carbon:checkmark' : 'i-simple-icons:markdown'"
11931178
>
1194-
<ButtonBase
1195-
@click="copyReadme()"
1196-
:aria-pressed="copiedReadme"
1197-
:aria-label="
1198-
copiedReadme ? $t('common.copied') : $t('package.readme.copy_as_markdown')
1199-
"
1200-
:classicon="copiedReadme ? 'i-carbon:checkmark' : 'i-simple-icons:markdown'"
1201-
>
1202-
{{ copiedReadme ? $t('common.copied') : $t('common.copy') }}
1203-
</ButtonBase>
1204-
</TooltipApp>
1205-
<ReadmeTocDropdown
1206-
v-if="readmeData?.toc && readmeData.toc.length > 1"
1207-
:toc="readmeData.toc"
1208-
:active-id="activeTocId"
1209-
/>
1210-
</div>
1211-
</ClientOnly>
1179+
{{ copiedReadme ? $t('common.copied') : $t('common.copy') }}
1180+
</ButtonBase>
1181+
</TooltipApp>
1182+
<ReadmeTocDropdown
1183+
v-if="readmeData?.toc && readmeData.toc.length > 1"
1184+
:toc="readmeData.toc"
1185+
:active-id="activeTocId"
1186+
/>
1187+
</div>
12121188
</div>
12131189

12141190
<!-- eslint-disable vue/no-v-html -- HTML is sanitized server-side -->
@@ -1226,7 +1202,7 @@ onKeyStroke(
12261202
</p>
12271203

12281204
<section
1229-
v-if="hasProvenance(displayVersion) && provenanceBadgeMounted"
1205+
v-if="hasProvenance(displayVersion) && isMounted"
12301206
id="provenance"
12311207
class="scroll-mt-20"
12321208
>
@@ -1261,6 +1237,9 @@ onKeyStroke(
12611237
<!-- Team access controls (for scoped packages when connected) -->
12621238
<ClientOnly>
12631239
<PackageAccessControls :package-name="pkg.name" />
1240+
<template #fallback>
1241+
<!-- Show skeleton loaders when SSR or access controls are loading -->
1242+
</template>
12641243
</ClientOnly>
12651244

12661245
<!-- Agent Skills -->
@@ -1271,6 +1250,9 @@ onKeyStroke(
12711250
:package-name="pkg.name"
12721251
:version="resolvedVersion || undefined"
12731252
/>
1253+
<template #fallback>
1254+
<!-- Show skeleton loaders when SSR or access controls are loading -->
1255+
</template>
12741256
</ClientOnly>
12751257

12761258
<!-- Download stats -->

0 commit comments

Comments
 (0)