Skip to content
Closed
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
4 changes: 4 additions & 0 deletions app/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ const footerSections = computed<Array<{ label: string; links: FooterLink[] }>>((
name: t('footer.about'),
href: '/about',
},
{
name: t('footer.sponsors'),
href: '/sponsors',
},
{
name: t('footer.brand'),
href: '/brand',
Expand Down
10 changes: 10 additions & 0 deletions app/composables/useCommandPaletteGlobalCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,16 @@ export function useCommandPaletteGlobalCommands() {
),
to: { name: 'noodles' },
},
{
id: 'sponsors',
group: 'npmx',
label: t('sponsors_page.title'),
keywords: [t('sponsors_page.title')],
iconClass: 'i-lucide:heart',
active: route.name === 'sponsors',
activeLabel: activeLabel(route.name === 'sponsors', t('command_palette.here')),
to: { name: 'sponsors' },
},
{
id: 'brand',
group: 'npmx',
Expand Down
5 changes: 5 additions & 0 deletions app/pages/about.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ const communityContributors = computed(
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('about.sponsors.title') }}
</h2>
<p class="text-fg-muted text-sm leading-relaxed mb-4">
<LinkBase to="/sponsors" no-new-tab-icon>
{{ $t('sponsors_page.cta') }}
</LinkBase>
</p>
<h3 class="block text-sm text-fg uppercase tracking-wider mb-3">
{{ $t('about.sponsors.gold') }}
</h3>
Expand Down
31 changes: 10 additions & 21 deletions app/pages/blog/release/rainbow-comet.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors:
title: 'npmx rainbow comet'
tags: ['OpenSource', 'Release']
excerpt: 'npmx 0.16 is out! This period was especially full of good news. And it’s particularly great that, amid the constant search for vulnerabilities and risks, we’ve started celebrating more and taking joy in what we do - and what our favorite maintainers and authors do.'
date: '2026-06-30'
date: '2026-07-03'
slug: 'release/rainbow-comet'
image: 'https://npmx.dev/blog/og/release-rainbow-comet.png'
description: 'npmx 0.16 is out! This period was especially full of good news. And it’s particularly great that, amid the constant search for vulnerabilities and risks, we’ve started celebrating more and taking joy in what we do - and what our favorite maintainers and authors do.'
Expand All @@ -34,15 +34,6 @@ We’d like to start with one of the nicest pieces of news - we’ve welcomed a

![CodeRabbit x npmx](/blog/coderabbit-x-npmx.png)

### Timeline

As you may already know, another place where we celebrate achievements is the package timeline. It’s where we show not only growth and issues, but also optimizations. And of course, we celebrate together with maintainers and users every time you share these results.

<BlueskyPostEmbed
url="https://bsky.app/profile/chenjiahan.bsky.social/post/3mmvj4gq4h22s"
uri="at://did:plc:ymoeg4trisbzfowiaemnu7xz/app.bsky.feed.post/3mmvj4gq4h22s"
/>

### Changelog

Speaking of changes, it’s hard to miss change analysis in packages. And to view those changes, you no longer need third‑party services. Now we show the changelog directly on package pages.
Expand All @@ -52,23 +43,21 @@ Speaking of changes, it’s hard to miss change analysis in packages. And to vie
uri="at://did:plc:nlenimoh4wmif7s22hiw5uzt/app.bsky.feed.post/3mmrihvusqk2b"
/>

### Trusted publishing

But of course the biggest change for packages in this period is trusted publishing. Together with `allowScripts` defaults to off, we suddenly found ourselves in a much safer environment. Incredible work by the npm team to improve the security of packages and our projects.

npmx also shows packages with trusted publishing and tracks changes to this setting.

<BlueskyPostEmbed
url="https://bsky.app/profile/nik.digital/post/3mmettwpgtc24"
uri="at://did:plc:6ctcux7hto6zyi3r7osornur/app.bsky.feed.post/3mmettwpgtc24"
/>

### Stats tab

One of the key metrics when choosing a dependency is statistics. To make that part of your experience more convenient, we added a stats page for every package. All information in one place - and there will be even more soon.

![The Stats tab for the nuxt package](/blog/stats-tab.png)

### Timeline

As you may already know, another place where we celebrate achievements is the package timeline. It’s where we show not only growth and issues, but also optimizations. And of course, we celebrate together with maintainers and users every time you share these results.

<BlueskyPostEmbed
url="https://bsky.app/profile/chenjiahan.bsky.social/post/3mmvj4gq4h22s"
uri="at://did:plc:ymoeg4trisbzfowiaemnu7xz/app.bsky.feed.post/3mmvj4gq4h22s"
/>

### Likes leaderboard

And of course, wherever there are results, a bit of competition and play appears. That’s why we now have a leaderboard page for our likes. Yes, we love everyone, but it seems Svelte will remain the leader from the very first days of npmx (_or do you want to like someone else and change that?_).
Expand Down
250 changes: 250 additions & 0 deletions app/pages/sponsors.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
<script setup lang="ts">
import { SPONSORS } from '~/assets/logos/sponsors'

const SPONSORSHIP_TIER_PRICES = {
silver: 500,
gold: 1000,
} as const

const { t } = useI18n()
const currencyFormatter = useNumberFormatter({
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
})

function formatTierPrice(amount: number) {
return `${currencyFormatter.value.format(amount)}${t('sponsors_page.tiers.per_month')}`
}

useSeoMeta({
title: () => `${$t('sponsors_page.title')} - npmx`,
ogTitle: () => `${$t('sponsors_page.title')} - npmx`,
twitterTitle: () => `${$t('sponsors_page.title')} - npmx`,
description: () => $t('sponsors_page.meta_description'),
ogDescription: () => $t('sponsors_page.meta_description'),
twitterDescription: () => $t('sponsors_page.meta_description'),
})

defineOgImage(
'Page.takumi',
{
title: () => $t('sponsors_page.title'),
description: () => $t('sponsors_page.meta_description'),
},
{ alt: () => `${$t('sponsors_page.title')} — npmx` },
)
</script>

<template>
<main class="container flex-1 py-12 sm:py-16">
<header class="mb-12">
<div class="flex items-baseline justify-between gap-4 mb-4">
<h1 class="font-mono text-3xl sm:text-4xl font-medium">
{{ $t('sponsors_page.heading') }}
</h1>
<BackButton />
</div>
<p class="text-fg-muted text-lg leading-relaxed">
{{ $t('sponsors_page.intro') }}
</p>
</header>

<div class="space-y-12" :class="$style.grid">
<section :class="$style.intro">
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('sponsors_page.what_we_do.title') }}
</h2>
<p class="text-fg-muted leading-relaxed">
{{ $t('sponsors_page.what_we_do.description') }}
</p>
</section>

<aside :class="$style.sponsors">
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('about.sponsors.title') }}
</h2>
<h3 class="block text-sm text-fg uppercase tracking-wider mb-3">
{{ $t('about.sponsors.gold') }}
</h3>
<AboutLogoList
:list="SPONSORS.gold"
class="grid gap-3 grid-cols-[repeat(auto-fill,minmax(160px,1fr))] lg:grid-cols-1"
/>
<h3 class="block text-sm text-fg uppercase tracking-wider mb-3 mt-6">
{{ $t('about.sponsors.silver') }}
</h3>
<AboutLogoList
:list="SPONSORS.silver"
class="grid gap-3 grid-cols-[repeat(auto-fill,minmax(160px,1fr))] lg:grid-cols-1"
/>
</aside>

<section :class="$style.content">
<div>
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('sponsors_page.what_this_means_for_you.title') }}
</h2>
<p class="text-fg-muted leading-relaxed mb-4">
{{ $t('sponsors_page.what_this_means_for_you.description') }}
</p>
<div class="grid gap-4 sm:grid-cols-12">
<section class="border border-border bg-bg-elevated rounded-lg p-5 sm:col-span-7">
<div class="grid grid-cols-2 gap-4">
<div>
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">250+</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.people.contributors') }}
</p>
</div>
<div>
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">700+</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.people.community_members') }}
</p>
</div>
</div>
</section>
<section class="border border-border rounded-lg p-5 bg-bg-subtle sm:col-span-5">
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">200000+</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.visitors.description') }}
</p>
</section>
<section class="border border-border rounded-lg p-5 bg-bg-subtle sm:col-span-4">
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">3400+</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.stars.title') }}
</p>
</section>
<section class="border border-border rounded-lg p-5 bg-bg-subtle sm:col-span-8">
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">
{{ $t('sponsors_page.what_this_means_for_you.cards.community.title') }}
</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.community.description')
}}<sup>*</sup>
</p>
</section>
<section class="border border-border rounded-lg p-5 bg-bg-subtle sm:col-span-6">
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">
{{ $t('sponsors_page.what_this_means_for_you.cards.adoption.title') }}
</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.adoption.description') }}
</p>
</section>
<section class="border border-border rounded-lg p-5 bg-bg-subtle sm:col-span-6">
<p class="font-mono text-2xl text-fg uppercase tracking-wider mb-2">
{{ $t('sponsors_page.what_this_means_for_you.cards.default_source.title') }}
</p>
<p class="text-fg-muted text-sm leading-relaxed m-0">
{{ $t('sponsors_page.what_this_means_for_you.cards.default_source.description') }}
</p>
</section>
</div>
</div>

<div class="mt-6">
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('sponsors_page.what_support_means.title') }}
</h2>
<p class="text-fg-muted leading-relaxed">
{{ $t('sponsors_page.what_support_means.description') }}
</p>
</div>

<div class="mt-6">
<h2 class="text-lg text-fg uppercase tracking-wider mb-4">
{{ $t('sponsors_page.tiers.title') }}
</h2>

<div class="border border-fg/80 rounded-xl p-5 bg-bg-muted">
<div class="flex items-center justify-between gap-3 mb-2">
<h3 class="font-mono text-base text-fg uppercase tracking-wider">
{{ $t('sponsors_page.tiers.silver.name') }}
</h3>
<span class="i-lucide:coins size-4 text-fg-subtle" aria-hidden="true" />
</div>
<p class="text-sm text-fg-subtle font-mono">
{{ formatTierPrice(SPONSORSHIP_TIER_PRICES.silver) }}
</p>
</div>

<div
class="border border-badge-yellow/80 rounded-xl p-5 bg-linear-to-br from-badge-yellow/8 to-bg-subtle/40 relative overflow-hidden mt-4"
>
<div class="flex items-center justify-between gap-3 mb-2 relative">
<h3 class="font-mono text-base text-fg uppercase tracking-wider">
{{ $t('sponsors_page.tiers.gold.name') }}
</h3>
<span class="i-lucide:medal size-4 text-badge-yellow" aria-hidden="true" />
</div>
<p class="text-sm text-fg-subtle font-mono">
{{ formatTierPrice(SPONSORSHIP_TIER_PRICES.gold) }}
</p>
</div>

<div
class="border border-badge-blue/80 rounded-xl p-5 bg-linear-to-br from-badge-blue/8 to-bg-subtle/40 relative overflow-hidden mt-4"
>
<div class="flex items-center justify-between gap-3 mb-2">
<h3 class="font-mono text-base text-fg uppercase tracking-wider">
{{ $t('sponsors_page.tiers.platinum.name') }}
</h3>
<span class="i-lucide:crown size-4 text-badge-blue" aria-hidden="true" />
</div>
<p class="text-sm text-fg-subtle font-mono">
{{ $t('sponsors_page.tiers.custom') }}
</p>
</div>
</div>
</section>
</div>

<p class="text-fg-subtle text-xs leading-relaxed mt-12">
<i18n-t keypath="sponsors_page.community_growth_footnote" tag="span" scope="global">
<template #link>
<LinkBase to="https://osscar.dev/"> OSSCAR </LinkBase>
</template>
</i18n-t>
</p>
</main>
</template>

<style module>
.grid {
display: grid;
column-gap: 2rem;
row-gap: 1rem;
grid-template-columns: minmax(0, 1fr);
grid-template-areas:
'intro'
'sponsors'
'content';
}

@media (min-width: 64rem) {
.grid {
grid-template-columns: 1fr 20rem;
grid-template-areas: 'intro sponsors' 'content sponsors';
}
}

.grid > * {
min-width: 0;
}

.intro {
grid-area: intro;
}

.sponsors {
grid-area: sponsors;
align-self: start;
}

.content {
grid-area: content;
}
</style>
3 changes: 1 addition & 2 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
".": "./dist/index.mjs"
},
"scripts": {
"build": "tsdown",
"build": "vp pack",
"dev": "NPMX_CLI_DEV=true node src/cli.ts",
"dev:debug": "DEBUG=npmx-connector NPMX_CLI_DEV=true node src/cli.ts",
"dev:mock": "NPMX_CLI_DEV=true node src/mock-server.ts",
Expand All @@ -42,7 +42,6 @@
"devDependencies": {
"@types/node": "24.12.2",
"@types/validate-npm-package-name": "4.0.2",
"tsdown": "0.21.7",
"typescript": "6.0.2"
},
"engines": {
Expand Down
2 changes: 1 addition & 1 deletion cli/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineConfig } from 'tsdown'
import { defineConfig } from 'vite-plus/pack'

export default defineConfig({
entry: ['src/index.ts', 'src/cli.ts'],
Expand Down
Loading
Loading