Skip to content

Commit f2d5f2b

Browse files
authored
Merge branch 'npmx-dev:main' into feat/changelog-1
2 parents 9f9195d + 63d5d59 commit f2d5f2b

32 files changed

Lines changed: 1630 additions & 339 deletions

app/components/CallToAction.vue

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ const socialLinks = computed(() => [
2525
ctaKey: $t('about.get_involved.follow.cta'),
2626
},
2727
])
28+
29+
function handleCardClick(event: MouseEvent) {
30+
if ((event.target as HTMLElement).closest(':any-link')) return
31+
if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return
32+
33+
const selection = window.getSelection()
34+
if (selection && selection.type === 'Range') return
35+
36+
const card = event.currentTarget as HTMLElement
37+
const link = card.querySelector('a')
38+
link?.click()
39+
}
2840
</script>
2941

3042
<template>
@@ -37,15 +49,16 @@ const socialLinks = computed(() => [
3749
<div
3850
v-for="link in socialLinks"
3951
:key="link.id"
40-
class="group relative grid gap-3 p-4 rounded-lg bg-bg-subtle hover:bg-bg-elevated border border-border hover:border-border-hover transition-all duration-200 sm:grid-rows-subgrid sm:row-span-3 focus-within:ring-2 focus-within:ring-accent/50"
52+
@click="handleCardClick"
53+
class="cursor-pointer group relative grid gap-3 p-4 rounded-lg bg-bg-subtle hover:bg-bg-elevated border border-border hover:border-border-hover transition-all duration-200 sm:grid-rows-subgrid sm:row-span-3 focus-within:ring-2 focus-within:ring-accent/50"
4154
>
42-
<h3 class="z-1 flex gap-2">
55+
<h3 class="flex gap-2">
4356
<span :class="link.icon" class="shrink-0 mt-1 w-5 h-5 text-fg" aria-hidden="true" />
4457
<span class="font-medium text-fg">
4558
{{ link.titleKey }}
4659
</span>
4760
</h3>
48-
<p class="z-1 text-sm text-fg-muted leading-relaxed">
61+
<p class="text-sm text-fg-muted leading-relaxed">
4962
{{ link.descriptionKey }}
5063
</p>
5164
<a
@@ -56,7 +69,6 @@ const socialLinks = computed(() => [
5669
>
5770
{{ link.ctaKey }}
5871
<span class="i-lucide:arrow-right rtl-flip w-3 h-3" aria-hidden="true" />
59-
<span class="absolute z-0 inset-0" aria-hidden="true" />
6072
</a>
6173
</div>
6274
</div>

app/components/Code/DirectoryListing.vue

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,7 @@ const bytesFormatter = useBytesFormatter()
120120
</svg>
121121
<span class="w-full flex justify-self-stretch items-center gap-2">
122122
<span class="flex-1">{{ node.name }}</span>
123-
<span
124-
v-if="node.type === 'file' && node.size"
125-
class="text-end text-xs text-fg-subtle"
126-
>
123+
<span v-if="typeof node.size === 'number'" class="text-end text-xs text-fg-subtle">
127124
{{ bytesFormatter.format(node.size) }}
128125
</span>
129126
</span>

app/components/Compare/PackageSelector.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ function handleKeydown(e: KeyboardEvent) {
105105
case 'ArrowDown':
106106
e.preventDefault()
107107
if (count === 0) return
108-
highlightedIndex.value = Math.min(highlightedIndex.value + 1, count - 1)
108+
if (highlightedIndex.value < count - 1) {
109+
highlightedIndex.value++
110+
} else {
111+
highlightedIndex.value = 0
112+
}
109113
break
110114
111115
case 'ArrowUp':
112116
e.preventDefault()
113117
if (count === 0) return
114118
if (highlightedIndex.value > 0) {
115119
highlightedIndex.value--
120+
} else {
121+
highlightedIndex.value = count - 1
116122
}
117123
break
118124

app/components/Package/ClaimPackageModal.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { checkPackageName } from '~/utils/package-name'
33
44
const props = defineProps<{
55
packageName: string
6+
packageScope?: string | null
7+
canPublishToScope: boolean
68
}>()
79
810
const {
@@ -221,9 +223,19 @@ const previewPackageJson = computed(() => {
221223
</div>
222224

223225
<!-- Availability status -->
224-
<div v-if="checkResult.valid">
226+
<template v-if="checkResult.valid">
225227
<div
226-
v-if="checkResult.available"
228+
v-if="isConnected && !canPublishToScope"
229+
class="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/20 rounded-lg"
230+
>
231+
<span class="i-lucide:x text-red-500 w-5 h-5" aria-hidden="true" />
232+
<p class="font-mono text-sm text-fg">
233+
{{ $t('claim.modal.missing_permission', { scope: packageScope }) }}
234+
</p>
235+
</div>
236+
237+
<div
238+
v-else-if="checkResult.available"
227239
class="flex items-center gap-3 p-4 bg-green-500/10 border border-green-500/20 rounded-lg"
228240
>
229241
<span class="i-lucide:check text-green-500 w-5 h-5" aria-hidden="true" />
@@ -237,10 +249,10 @@ const previewPackageJson = computed(() => {
237249
<span class="i-lucide:x text-red-500 w-5 h-5" aria-hidden="true" />
238250
<p class="font-mono text-sm text-fg">{{ $t('claim.modal.taken') }}</p>
239251
</div>
240-
</div>
252+
</template>
241253

242254
<!-- Similar packages warning -->
243-
<div v-if="checkResult.similarPackages?.length && checkResult.available">
255+
<template v-if="checkResult.similarPackages?.length && checkResult.available">
244256
<div
245257
:class="
246258
hasDangerousSimilarPackages
@@ -290,7 +302,7 @@ const previewPackageJson = computed(() => {
290302
</li>
291303
</ul>
292304
</div>
293-
</div>
305+
</template>
294306

295307
<!-- Error message -->
296308
<div
@@ -336,7 +348,7 @@ const previewPackageJson = computed(() => {
336348
</div>
337349

338350
<!-- Claim button -->
339-
<div v-else class="space-y-3">
351+
<div v-else-if="isConnected && canPublishToScope" class="space-y-3">
340352
<p class="text-sm text-fg-muted">
341353
{{ $t('claim.modal.publish_hint') }}
342354
</p>

app/components/Package/Table.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ function getColumnLabel(id: ColumnId): string {
193193
<template v-if="isSortable('downloads')">
194194
<span
195195
v-if="isColumnSorted('downloads')"
196-
class="i-lucide:caret-down w-3 h-3"
196+
class="i-lucide:chevron-down w-3 h-3"
197197
:class="getSortDirection('downloads') === 'asc' ? 'rotate-180' : ''"
198198
aria-hidden="true"
199199
/>
@@ -231,7 +231,7 @@ function getColumnLabel(id: ColumnId): string {
231231
<template v-if="isSortable('updated')">
232232
<span
233233
v-if="isColumnSorted('updated')"
234-
class="i-lucide:caret-down w-3 h-3"
234+
class="i-lucide:chevron-down w-3 h-3"
235235
:class="getSortDirection('updated') === 'asc' ? 'rotate-180' : ''"
236236
aria-hidden="true"
237237
/>

app/components/Package/WeeklyDownloadStats.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ const config = computed(() => {
362362
.vue-ui-sparkline-title span {
363363
padding: 0 !important;
364364
letter-spacing: 0.04rem;
365+
@apply font-mono;
365366
}
366367
367368
.vue-ui-sparkline text {

app/components/ReadmeTocDropdown.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import type { TocItem } from '#shared/types/readme'
33
import { onClickOutside, useEventListener } from '@vueuse/core'
4+
import { decodeHtmlEntities } from '~/utils/formatters'
45
56
const props = defineProps<{
67
toc: TocItem[]
@@ -201,7 +202,7 @@ function handleKeydown(event: KeyboardEvent) {
201202
@click="select()"
202203
@mouseenter="highlightedIndex = getIndex(node.id)"
203204
>
204-
<span class="truncate">{{ node.text }}</span>
205+
<span class="truncate">{{ decodeHtmlEntities(node.text) }}</span>
205206
</NuxtLink>
206207

207208
<template v-for="child in node.children" :key="child.id">
@@ -219,7 +220,7 @@ function handleKeydown(event: KeyboardEvent) {
219220
@click="select()"
220221
@mouseenter="highlightedIndex = getIndex(child.id)"
221222
>
222-
<span class="truncate">{{ child.text }}</span>
223+
<span class="truncate">{{ decodeHtmlEntities(child.text) }}</span>
223224
</NuxtLink>
224225

225226
<NuxtLink
@@ -240,7 +241,7 @@ function handleKeydown(event: KeyboardEvent) {
240241
@click="select()"
241242
@mouseenter="highlightedIndex = getIndex(grandchild.id)"
242243
>
243-
<span class="truncate">{{ grandchild.text }}</span>
244+
<span class="truncate">{{ decodeHtmlEntities(grandchild.text) }}</span>
244245
</NuxtLink>
245246
</template>
246247
</template>

app/composables/useNumberFormatter.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,21 @@ export const useBytesFormatter = () => {
1616
const decimalNumberFormatter = useNumberFormatter({
1717
maximumFractionDigits: 1,
1818
})
19+
const KB = 1000
20+
const MB = 1000 * 1000
1921

2022
return {
2123
format: (bytes: number) => {
22-
if (bytes < 1024)
24+
if (bytes < KB)
2325
return t('package.size.b', {
2426
size: decimalNumberFormatter.value.format(bytes),
2527
})
26-
if (bytes < 1024 * 1024)
28+
if (bytes < MB)
2729
return t('package.size.kb', {
28-
size: decimalNumberFormatter.value.format(bytes / 1024),
30+
size: decimalNumberFormatter.value.format(bytes / KB),
2931
})
3032
return t('package.size.mb', {
31-
size: decimalNumberFormatter.value.format(bytes / (1024 * 1024)),
33+
size: decimalNumberFormatter.value.format(bytes / MB),
3234
})
3335
},
3436
}

app/pages/search.vue

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,14 +332,13 @@ const canPublishToScope = computed(() => {
332332
return orgMembership.value[scope] === true
333333
})
334334
335-
// Show claim prompt when valid name, available, connected, and has permission
335+
// Show claim prompt when valid name, available, either not connected or connected and has permission
336336
const showClaimPrompt = computed(() => {
337337
return (
338-
isConnected.value &&
339338
isValidPackageName.value &&
340339
packageAvailability.value?.available === true &&
341340
packageAvailability.value.name === query.value.trim() &&
342-
canPublishToScope.value &&
341+
(!isConnected.value || (isConnected.value && canPublishToScope.value)) &&
343342
status.value !== 'pending'
344343
)
345344
})
@@ -569,7 +568,7 @@ defineOgImageComponent('Default', {
569568
<!-- Claim prompt - shown at top when valid name but no exact match -->
570569
<div
571570
v-if="showClaimPrompt && visibleResults.total > 0"
572-
class="mb-6 p-4 bg-bg-subtle border border-border rounded-lg flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"
571+
class="mb-6 p-4 bg-bg-subtle border border-border rounded-lg sm:flex hidden flex-row sm:items-center gap-3 sm:gap-4"
573572
>
574573
<div class="flex-1 min-w-0">
575574
<p class="font-mono text-sm text-fg">
@@ -687,7 +686,7 @@ defineOgImageComponent('Default', {
687686
</div>
688687

689688
<!-- Offer to claim the package name if it's valid -->
690-
<div v-if="showClaimPrompt" class="max-w-md mx-auto text-center">
689+
<div v-if="showClaimPrompt" class="max-w-md mx-auto text-center hidden sm:block">
691690
<div class="p-4 bg-bg-subtle border border-border rounded-lg">
692691
<p class="text-sm text-fg-muted mb-3">{{ $t('search.want_to_claim') }}</p>
693692
<button
@@ -741,6 +740,11 @@ defineOgImageComponent('Default', {
741740
</div>
742741

743742
<!-- Claim package modal -->
744-
<PackageClaimPackageModal ref="claimPackageModalRef" :package-name="query" />
743+
<PackageClaimPackageModal
744+
ref="claimPackageModalRef"
745+
:package-name="query"
746+
:package-scope="packageScope"
747+
:can-publish-to-scope="canPublishToScope"
748+
/>
745749
</main>
746750
</template>

0 commit comments

Comments
 (0)