Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2539086
feat(i18n): add romanian locale (#2809)
mihaizaurus May 28, 2026
ef982d8
fix(ui): keep compare header links inside their grid column (#2805)
rohitg00 May 28, 2026
46dab0e
feat: support npmjs versions redirect (#2800)
johnnyreilly May 28, 2026
7c53128
refactor: switch to packumeta for trust levels (#2804)
43081j May 28, 2026
2859119
chore: bump vue-data-ui from 3.20.10 to 3.20.11 (#2812)
graphieros May 28, 2026
bdd17b8
fix: noodle date check (#2808)
alexdln May 29, 2026
f868fd1
fix(i18n): add missing turkish translations (#2813)
tinas May 29, 2026
da29a90
fix(i18n): add missing bangla translations (#2807)
shomriddho May 29, 2026
2ce2d05
feat: update versions page download count tooltip/title (#2695)
btea May 29, 2026
b3ba515
chore(deps): bump packumeta (#2814)
43081j May 29, 2026
79f7f78
fix: do not fetch metadata for self-hosted Gitea/Forgejo (#2788)
serhalp May 30, 2026
6909832
test: re-work some brittle atproto mocks (#2798)
serhalp May 31, 2026
3958786
fix: don't flag a license change when there is no previous version (#…
jp-knj May 31, 2026
10e11f5
refactor: use normalizeLicense util consistently (#2816)
charpeni May 31, 2026
04f46b6
fix: skip emoji conversion inside code blocks (#2694)
gameroman May 31, 2026
9ad4695
fix: improve proxy for images without content-type (#2740)
alexdln May 31, 2026
26091b2
chore(deps): update knip ✂️ and add enable treatTagHintsAsErrors (#2824)
cylewaitforit May 31, 2026
d76e272
feat: update team list and design on about page (#2756)
alexdln May 31, 2026
0a36394
feat: add compact badge style variant (#2640)
OrbisK May 31, 2026
719cb3d
fix(i18n): update Japanese translations (#2825)
shuuji3 May 31, 2026
f0bdd20
fix(i18n): add singular forms to en strings (#2827)
trueberryless May 31, 2026
98be51d
feat(ui): improve package description cleaning and search result card…
Adebesin-Cell May 31, 2026
9246e07
chore(deps): update all non-major dependencies (#2219)
renovate[bot] May 31, 2026
082a321
feat: pride noodle (#2826)
alexdln May 31, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/chromatic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
run: vp install -g pnpm

- name: 🧪 Run Chromatic Visual and Accessibility Tests
uses: chromaui/action@f191a0224b10e1a38b2091cefb7b7a2337009116 # v16.0.0
uses: chromaui/action@8a2b82547aef5a3efc8ec3c7905f4ab09a76ed0b # v16.1.0
env:
CHROMATIC_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }}
CHROMATIC_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
Expand Down
61 changes: 61 additions & 0 deletions app/components/About/GovernanceList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup lang="ts">
import type { Role, GitHubContributor } from '~~/server/api/contributors.get'

const props = defineProps<{
members: GitHubContributor[]
}>()

const roleLabels = computed(
() =>
({
steward: $t('about.team.role_steward'),
core: $t('about.team.role_core'),
maintainer: $t('about.team.role_maintainer'),
}) as Partial<Record<Role, string>>,
)
</script>

<template>
<ul class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3 list-none p-0">
<li
v-for="person in props.members"
:key="person.id"
class="relative p-3 bg-bg-muted border border-border rounded-xl hover:border-border-hover hover:bg-bg-subtle transition-[border-color,background-color] duration-200 cursor-pointer focus-within:ring-2 focus-within:ring-offset-bg focus-within:ring-offset-2 focus-within:ring-fg/50"
>
<div class="flex gap-3">
<img
:src="`${person.avatar_url}&s=80`"
:alt="`${person.login}'s avatar`"
class="block w-15 h-15 rounded-md ring-1 ring-bg shrink-0"
loading="lazy"
/>
<div class="min-w-0 flex-1">
<div class="font-mono text-sm text-fg truncate">
<NuxtLink
:to="person.html_url"
target="_blank"
class="decoration-none after:content-[''] after:absolute after:inset-0"
:aria-label="$t('about.contributors.view_profile', { name: person.login })"
>
@{{ person.login }}
</NuxtLink>
</div>
<div class="text-sm text-fg-muted tracking-tight">
{{ roleLabels[person.role] ?? person.role }}
</div>
<LinkBase
v-if="person.sponsors_url"
:to="person.sponsors_url"
no-underline
no-external-icon
classicon="i-lucide:heart"
class="flex! relative z-10 text-xs text-fg-muted hover:text-pink-400 mt-1"
:aria-label="$t('about.team.sponsor_aria', { name: person.login })"
>
{{ $t('about.team.sponsor') }}
</LinkBase>
</div>
</div>
</li>
</ul>
</template>
4 changes: 2 additions & 2 deletions app/components/About/LogoList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const props = defineProps<{
:href="item.url"
target="_blank"
rel="noopener noreferrer"
class="relative flex items-center justify-center h-16 rounded-md bg-bg-muted hover:bg-bg-subtle border border-border transition-colors py-1 px-3"
class="relative flex items-center justify-center h-16 rounded-md bg-bg-muted hover:bg-bg-subtle border border-border hover:border-border-hover transition-colors py-1 px-3"
:style="{ paddingBlock: item.normalisingIndent }"
:aria-label="item.name"
>
Expand Down Expand Up @@ -65,7 +65,7 @@ const props = defineProps<{
:href="groupItem.url"
target="_blank"
rel="noopener noreferrer"
class="relative flex items-center justify-center h-full aspect-square rounded-md hover:bg-bg-subtle border border-transparent hover:border-border transition-colors p-1.5"
class="relative flex items-center justify-center h-full aspect-square rounded-md hover:bg-bg-subtle border border-transparent hover:border-border-hover transition-colors p-1.5"
:style="{ paddingBlock: groupItem.normalisingIndent }"
:aria-label="groupItem.name"
>
Expand Down
6 changes: 3 additions & 3 deletions app/components/Compare/ComparisonGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ function getReplacementTooltip(col: ComparisonGridColumn): string {
<div class="flex items-start justify-center gap-1.5 min-w-0">
<LinkBase
:to="packageRoute(col.name, col.version)"
class="flex min-w-0 flex-col items-center text-center text-sm"
class="flex min-w-0 flex-1 flex-col items-center text-center text-sm"
:title="col.version ? `${col.name}@${col.version}` : col.name"
>
<span class="min-w-0 break-words line-clamp-1">
<span class="w-full truncate">
{{ col.name }}
</span>
<span v-if="col.version" class="text-fg-muted line-clamp-1">
<span v-if="col.version" class="w-full truncate text-fg-muted">
@{{ col.version }}
</span>
</LinkBase>
Expand Down
27 changes: 9 additions & 18 deletions app/components/Landing/IntroHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,17 @@ onPrehydrate(el => {
}

const currentActiveNoodles = activeNoodles.filter(noodle => {
const todayDate = new Date()
const todayDateRaw = new Intl.DateTimeFormat('en-US', {
timeZone: noodle.timezone === 'auto' ? undefined : noodle.timezone,
if (!noodle.date) return false

const today = new Intl.DateTimeFormat('en-CA', {
timeZone: noodle.timezone !== 'auto' ? noodle.timezone : undefined,
year: 'numeric',
month: '2-digit',
day: '2-digit',
year: 'numeric',
}).format(todayDate)

const noodleDateFrom = new Date(noodle.date!)
if (!noodle.dateTo) {
const noodleDateFromRaw = new Intl.DateTimeFormat('en-US', {
timeZone: noodle.timezone === 'auto' ? undefined : noodle.timezone,
month: '2-digit',
day: '2-digit',
year: 'numeric',
}).format(noodleDateFrom)
return todayDateRaw === noodleDateFromRaw
}
const noodleDateTo = new Date(noodle.dateTo!)
return todayDate >= noodleDateFrom && todayDate <= noodleDateTo
}).format(new Date())

if (!noodle.dateTo) return today === noodle.date
return today >= noodle.date && today <= noodle.dateTo
})

if (!currentActiveNoodles.length) return
Expand Down
13 changes: 13 additions & 0 deletions app/components/Noodle/Pride1/Logo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<template>
<TooltipApp interactive position="top">
<template #content>
<p class="text-sm font-medium text-fg mb-1">Happy Pride Month!</p>
</template>
<img
width="400"
class="mb-6 w-80 sm:w-140 max-w-full"
src="/extra/pride-1.svg"
:alt="$t('alt_logo')"
/>
</TooltipApp>
</template>
17 changes: 9 additions & 8 deletions app/components/Noodle/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import NoodleKawaiiLogo from './Kawaii/Logo.vue'
import NoodleNodejsLogo from './Nodejs/Logo.vue'
import NoodlePride1Logo from './Pride1/Logo.vue'

export type Noodle = {
// Unique identifier for the noodle
key: string
// Timezone for the noodle (default is auto, i.e. user's timezone)
timezone?: string
// Date for the noodle
date?: string
// `Date to` for the noodle
dateTo?: string
// Date for the noodle (YYYY-MM-DD)
date?: `${number}-${number}-${number}`
// `Date to` for the noodle (YYYY-MM-DD)
dateTo?: `${number}-${number}-${number}`
// Logo for the noodle - could be any component. Relative parent - intro section
logo: Component
// Show npmx tagline or not (default is true)
Expand All @@ -28,9 +28,10 @@ export const PERMANENT_NOODLES: Noodle[] = [
// Active noodles - shown based on date and timezone
export const ACTIVE_NOODLES: Noodle[] = [
{
key: 'nodejs',
logo: NoodleNodejsLogo,
date: '2026-05-27',
key: 'pride-1',
logo: NoodlePride1Logo,
date: '2026-06-01',
dateTo: '2026-06-30',
timezone: 'auto',
},
]
114 changes: 41 additions & 73 deletions app/components/Package/Card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,84 +74,52 @@ const numberFormatter = useNumberFormatter()
/>
</header>

<div class="flex flex-col sm:flex-row sm:justify-start sm:items-start gap-6 sm:gap-8">
<div class="min-w-0 w-full">
<p v-if="pkgDescription" class="text-fg-muted text-xs sm:text-sm line-clamp-2 mb-2 sm:mb-3">
<span v-html="pkgDescription" />
</p>
<div class="flex flex-wrap items-center gap-x-3 sm:gap-x-4 gap-y-2 text-xs text-fg-muted">
<dl v-if="showPublisher || result.package.date" class="flex items-center gap-4 m-0">
<div
v-if="showPublisher && result.package.publisher?.username"
class="flex items-center gap-1.5"
>
<dt class="sr-only">{{ $t('package.card.publisher') }}</dt>
<dd class="font-mono">{{ result.package.publisher.username }}</dd>
</div>
<div v-if="result.package.date" class="flex items-center gap-1.5">
<dt class="sr-only">{{ $t('package.card.published') }}</dt>
<dd>
<DateTime
:datetime="result.package.date"
year="numeric"
month="short"
day="numeric"
/>
</dd>
</div>
<div v-if="result.package.license" class="flex items-center gap-1.5">
<dt class="sr-only">{{ $t('package.card.license') }}</dt>
<dd>{{ result.package.license }}</dd>
</div>
</dl>
</div>
<!-- Mobile: downloads on separate row -->
<dl
v-if="result.downloads?.weekly"
class="sm:hidden flex items-center gap-4 mt-2 text-xs text-fg-muted m-0"
>
<div class="flex items-center gap-1.5">
<dt class="sr-only">{{ $t('package.card.weekly_downloads') }}</dt>
<dd class="flex items-center gap-1.5">
<span class="i-lucide:chart-line w-3.5 h-3.5" aria-hidden="true" />
<span class="font-mono">{{ $n(result.downloads.weekly) }}/w</span>
</dd>
</div>
</dl>
</div>

<div class="flex flex-col gap-2 shrink-0">
<div class="text-fg-subtle flex items-start gap-2 sm:justify-end">
<span
v-if="result.package.version"
class="font-mono text-xs truncate max-w-32"
:title="result.package.version"
>
<p v-if="pkgDescription" class="text-fg-muted text-xs sm:text-sm line-clamp-2 mb-2 sm:mb-3">
<span v-html="pkgDescription" />
</p>
<div class="flex flex-wrap items-center gap-x-3 sm:gap-x-4 gap-y-2 text-xs text-fg-muted">
<ProvenanceBadge
v-if="result.package.publisher?.trustedPublisher"
:provider="result.package.publisher.trustedPublisher.id"
:package-name="result.package.name"
:version="result.package.version"
:linked="false"
compact
/>
<dl class="contents m-0">
<div v-if="result.package.version" class="flex items-center gap-1.5 min-w-0">
<dt class="sr-only">{{ $t('package.card.version') }}</dt>
<dd class="font-mono truncate max-w-32" :title="result.package.version">
v{{ result.package.version }}
</span>
<div
v-if="result.package.publisher?.trustedPublisher"
class="flex items-center gap-1.5 shrink-0 max-w-32"
>
<ProvenanceBadge
:provider="result.package.publisher.trustedPublisher.id"
:package-name="result.package.name"
:version="result.package.version"
:linked="false"
compact
/>
</div>
</dd>
</div>
<div v-if="result.package.date" class="flex items-center gap-1.5">
<dt class="sr-only">{{ $t('package.card.published') }}</dt>
<dd>
<DateTime :datetime="result.package.date" year="numeric" month="short" day="numeric" />
</dd>
</div>
<div
v-if="result.downloads?.weekly"
class="text-fg-subtle gap-2 flex items-center sm:justify-end"
v-if="showPublisher && result.package.publisher?.username"
class="flex items-center gap-1.5"
>
<span class="i-lucide:chart-line w-3.5 h-3.5" aria-hidden="true" />
<span class="font-mono text-xs">
{{ $n(result.downloads.weekly) }} {{ $t('common.per_week') }}
</span>
<dt class="sr-only">{{ $t('package.card.publisher') }}</dt>
<dd class="font-mono">{{ result.package.publisher.username }}</dd>
</div>
<div v-if="result.package.license" class="flex items-center gap-1.5">
<dt class="sr-only">{{ $t('package.card.license') }}</dt>
<dd>{{ result.package.license }}</dd>
</div>
<div v-if="result.downloads?.weekly != null" class="flex items-center gap-1.5 sm:ms-auto">
<dt class="sr-only">{{ $t('package.card.weekly_downloads') }}</dt>
<dd class="flex items-center gap-1.5">
<span class="i-lucide:chart-line w-3.5 h-3.5" aria-hidden="true" />
<span class="font-mono">
{{ $n(result.downloads.weekly) }} {{ $t('common.per_week') }}
</span>
</dd>
</div>
</div>
</dl>
</div>

<ul
Expand Down
11 changes: 7 additions & 4 deletions app/components/Package/TimelineChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ const tooltipPosition = useChartTooltipPosition(chartRef)
const config = computed<VueUiXyConfig>(() => {
return {
theme: isDarkMode.value ? 'dark' : '',
downsample: {
threshold: 5000,
},
line: {
useGradient: false,
radius: 2,
Expand Down Expand Up @@ -711,7 +714,7 @@ const indexSelection = computed(() => {
class="pointer-events-none"
>
<path
:d="`M ${plot.x - 5} ${plot.y - 20} l 4 6 l 10 -12`"
:d="`M ${plot.x - 4} ${plot.y - 20} l 4 6 l 10 -12`"
fill="none"
:stroke="colors.bg"
stroke-width="6"
Expand All @@ -720,7 +723,7 @@ const indexSelection = computed(() => {
class="svg-element-transition"
/>
<path
:d="`M ${plot.x - 5} ${plot.y - 20} l 4 6 l 10 -12`"
:d="`M ${plot.x - 4} ${plot.y - 20} l 4 6 l 10 -12`"
fill="none"
:stroke="e18eGradientColors.at(-1)"
stroke-width="2"
Expand All @@ -737,7 +740,7 @@ const indexSelection = computed(() => {
class="pointer-events-none"
>
<path
:d="`M ${plot.x - 1} ${plot.y - 20 - (plot.offsetY ?? 0)} l -6 10 l 12 0 l -6 -10 m 0 5 l 0 2`"
:d="`M ${plot.x} ${plot.y - 20 - (plot.offsetY ?? 0)} l -6 10 l 12 0 l -6 -10 m 0 5 l 0 2`"
fill="none"
:stroke="colors.bg"
stroke-width="6"
Expand All @@ -746,7 +749,7 @@ const indexSelection = computed(() => {
class="svg-element-transition"
/>
<path
:d="`M ${plot.x - 1} ${plot.y - 20 - (plot.offsetY ?? 0)} l -6 10 l 12 0 l -6 -10 m 0 5 l 0 2`"
:d="`M ${plot.x} ${plot.y - 20 - (plot.offsetY ?? 0)} l -6 10 l 12 0 l -6 -10 m 0 5 l 0 2`"
fill="none"
:stroke="e18eGradientColors[0]"
stroke-width="2"
Expand Down
3 changes: 3 additions & 0 deletions app/components/Package/TrendsChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,9 @@ const keepZoomState = shallowRef(true)
const chartConfig = computed<VueUiXyConfig>(() => {
return {
theme: isDarkMode.value ? 'dark' : ('' as VueDataUiTheme),
downsample: {
threshold: 5000,
},
a11y: {
translations: {
keyboardNavigation: $t(
Expand Down
Loading
Loading