From 7425b28a750f30d6403ee1ebba2cdfb98ac38a60 Mon Sep 17 00:00:00 2001 From: Felix Schneider <99918022+trueberryless@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:08:43 +0200 Subject: [PATCH 01/63] docs: add link to npmxers site (#2854) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d74939ad29..79d2c4f87f 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,7 @@ We welcome contributions – please do feel free to explore the project and - [npmx-weekly](https://npmx-weekly.trueberryless.org/) – A weekly newsletter for the npmx ecosystem. Add your own content via suggestions in the weekly PR on [GitHub](https://github.com/trueberryless-org/npmx-weekly/pulls?q=is%3Aopen+is%3Apr+label%3A%22%F0%9F%95%94+weekly+post%22). - [npmx-digest](https://npmx-digest.trueberryless.org/) – An automated news aggregation website that summarizes npmx activity from GitHub and Bluesky every 8 hours. - [npmx-badge](https://npmx-badge.vercel.app/) – A playground to help you create custom badges quickly. +- [npmxers](https://npmxers.trueberryless.org/) – Discover the number of contributions you made to npmx and share your npmxer profile. If you're building something cool, let us know! 🙏 From 0d599672ee7a2d48bbc46a6c08eb75b6d62b3709 Mon Sep 17 00:00:00 2001 From: Alex Savelyev <91429106+alexdln@users.noreply.github.com> Date: Fri, 5 Jun 2026 21:14:20 +0100 Subject: [PATCH 02/63] fix(ui): license icon (#2850) --- app/utils/file-icons.ts | 12 ++++++------ assets/media/custom-icons.json | 27 +++++++++++++++++++++++++++ scripts/generate-file-tree-sprite.ts | 17 ++++++++++------- uno.config.ts | 16 ++++------------ 4 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 assets/media/custom-icons.json diff --git a/app/utils/file-icons.ts b/app/utils/file-icons.ts index 6647e43a0e..e0220a0f99 100644 --- a/app/utils/file-icons.ts +++ b/app/utils/file-icons.ts @@ -264,12 +264,12 @@ export const FILENAME_ICONS: Record = { 'CONTRIBUTING.md': 'vscode-icons-file-type-markdown', 'contributing.md': 'vscode-icons-file-type-markdown', 'CODE_OF_CONDUCT.md': 'vscode-icons-file-type-markdown', - 'LICENSE': 'vscode-icons-file-type-license', - 'LICENSE.md': 'vscode-icons-file-type-license', - 'LICENSE.txt': 'vscode-icons-file-type-license', - 'license': 'vscode-icons-file-type-license', - 'license.md': 'vscode-icons-file-type-license', - 'license.txt': 'vscode-icons-file-type-license', + 'LICENSE': 'custom-license-minified', + 'LICENSE.md': 'custom-license-minified', + 'LICENSE.txt': 'custom-license-minified', + 'license': 'custom-license-minified', + 'license.md': 'custom-license-minified', + 'license.txt': 'custom-license-minified', // Node '.npmrc': 'vscode-icons-file-type-npm', diff --git a/assets/media/custom-icons.json b/assets/media/custom-icons.json new file mode 100644 index 0000000000..53f540db9c --- /dev/null +++ b/assets/media/custom-icons.json @@ -0,0 +1,27 @@ +{ + "agent-skills": { + "body": "", + "width": 32, + "height": 32 + }, + "tangled": { + "body": "", + "width": 25, + "height": 25 + }, + "vlt": { + "body": "", + "width": 24, + "height": 24 + }, + "a11y": { + "body": "", + "width": 24, + "height": 24 + }, + "license-minified": { + "body": "", + "width": 32, + "height": 32 + } +} diff --git a/scripts/generate-file-tree-sprite.ts b/scripts/generate-file-tree-sprite.ts index ac691de737..29bf2d615e 100644 --- a/scripts/generate-file-tree-sprite.ts +++ b/scripts/generate-file-tree-sprite.ts @@ -10,19 +10,22 @@ import { COMPOUND_EXTENSIONS, DEFAULT_ICON, } from '../app/utils/file-icons.ts' +import customIcons from '../assets/media/custom-icons.json' with { type: 'json' } const rootDir = process.cwd() -const outputDevPath = path.join(rootDir, 'public', 'file-tree-sprite.svg') -const outputStagePath = path.join(rootDir, 'public-dev', 'file-tree-sprite.svg') -const outputProdPath = path.join(rootDir, 'public-prod', 'file-tree-sprite.svg') +const outputDevPath = path.join(rootDir, 'public-dev', 'file-tree-sprite.svg') +const outputStagePath = path.join(rootDir, 'public-staging', 'file-tree-sprite.svg') +const outputProdPath = path.join(rootDir, 'public', 'file-tree-sprite.svg') -const COLLECTION_NAMES = ['lucide', 'simple-icons', 'svg-spinners', 'vscode-icons'] +const ICONIFY_COLLECTION_NAMES = ['lucide', 'simple-icons', 'svg-spinners', 'vscode-icons'] -const COLLECTION_REGEXP = new RegExp(`^(${COLLECTION_NAMES.join('|')})-(.+)$`) +const COLLECTION_REGEXP = new RegExp(`^(${ICONIFY_COLLECTION_NAMES.join('|')}|custom)-(.+)$`) async function loadCollections() { - const collections: { [key: string]: IconifyJSON } = {} - for (const name of COLLECTION_NAMES) { + const collections: { [key: string]: IconifyJSON } = { + custom: { icons: customIcons, prefix: 'custom' }, + } + for (const name of ICONIFY_COLLECTION_NAMES) { const filePathUrl = import.meta.resolve(`@iconify-json/${name}/icons.json`) const filePath = fileURLToPath(filePathUrl) const raw = await fs.readFile(filePath, 'utf8') diff --git a/uno.config.ts b/uno.config.ts index ddbbafb7a0..665f2fc850 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -10,17 +10,7 @@ import { import { presetRtl } from './uno-preset-rtl' import { presetA11y } from './uno-preset-a11y' import { theme } from './uno.theme' - -const customIcons = { - 'agent-skills': - '', - 'tangled': - '', - 'vlt': - '', - 'a11y': - '', -} +import customIcons from './assets/media/custom-icons.json' export default defineConfig({ // og-image uses hardcoded classes we don't want bundled into main app @@ -45,7 +35,9 @@ export default defineConfig({ warn: true, scale: 1.2, collections: { - custom: customIcons, + custom: Object.fromEntries( + Object.entries(customIcons).map(([key, { body }]) => [key, body]), + ), }, }), presetTypography(), From 28c3a291e17a16e81b47ae4049623c2c35117c5d Mon Sep 17 00:00:00 2001 From: Alex Savelyev <91429106+alexdln@users.noreply.github.com> Date: Fri, 5 Jun 2026 21:25:01 +0100 Subject: [PATCH 03/63] fix: hide mobile search field on blur (#2852) --- app/components/AppHeader.vue | 4 ++-- app/components/Header/SearchBox.vue | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/components/AppHeader.vue b/app/components/AppHeader.vue index 32fc2fb91d..1a2a8393a6 100644 --- a/app/components/AppHeader.vue +++ b/app/components/AppHeader.vue @@ -327,7 +327,7 @@ useShortcuts({ diff --git a/i18n/locales/en.json b/i18n/locales/en.json index 34e9679053..a568f4a81d 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -13,6 +13,7 @@ "trademark_disclaimer": "npm is a registered trademark of npm, Inc. This site is not affiliated with npm, Inc.", "footer": { "about": "about", + "sponsors": "sponsors", "blog": "blog", "docs": "docs", "source": "source", @@ -1268,6 +1269,64 @@ } } }, + "sponsors_page": { + "title": "Sponsors", + "heading": "sponsors", + "meta_description": "Support npmx and help us accelerate ecosystem work around security, trust, optimization, and research.", + "intro": "Support npmx and help us grow the ecosystem work we do for developers and maintainers.", + "what_we_do": { + "title": "What we do", + "description": "We're building an ecosystem that solves problems around security, trust, optimization, and research for the tools we use in everyday development - quickly, conveniently, and with high quality. This project is built by developers for developers. As authors of widely used libraries, we understand team needs and actively study what maintainers and projects need most." + }, + "what_support_means": { + "title": "What support means", + "description": "Our plans and connections keep growing, along with our desire to share what we've built and learn from others. Your support helps fund the project, external talks, conferences, and the broader ecosystem, and, most importantly, enables us to keep growing our community." + }, + "cta": "See sponsorship tiers", + "community_growth_footnote": "* According to {link} Q1 2026 research.", + "what_this_means_for_you": { + "title": "What this means for you", + "description": "npmx is not only about improving developer experience and closing critical everyday gaps. In our first six months, we have already become the default source for thousands of teams and a huge number of developers. You get not only a more stable tool for your teams, but also visibility in front of a constantly growing audience of top-tier engineers.", + "cards": { + "people": { + "contributors": "contributors", + "community_members": "community members" + }, + "visitors": { + "description": "unique monthly visitors" + }, + "stars": { + "title": "stars" + }, + "community": { + "title": "fast-growing", + "description": "We are one of the fastest-growing communities in the ecosystem" + }, + "adoption": { + "title": "adoption", + "description": "charts at conferences, talks, and articles rely on our data" + }, + "default_source": { + "title": "default source", + "description": "pnpm made npmx the default source, many packages have been configured to link to npmx" + } + } + }, + "tiers": { + "title": "Sponsorship tiers", + "per_month": "/month", + "custom": "Custom", + "silver": { + "name": "Silver" + }, + "gold": { + "name": "Gold" + }, + "platinum": { + "name": "Platinum" + } + } + }, "account_menu": { "connect": "connect", "account": "Account", diff --git a/i18n/schema.json b/i18n/schema.json index 78c93bab56..1fe63c4793 100644 --- a/i18n/schema.json +++ b/i18n/schema.json @@ -43,6 +43,9 @@ "about": { "type": "string" }, + "sponsors": { + "type": "string" + }, "blog": { "type": "string" }, @@ -3808,6 +3811,180 @@ }, "additionalProperties": false }, + "sponsors_page": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "heading": { + "type": "string" + }, + "meta_description": { + "type": "string" + }, + "intro": { + "type": "string" + }, + "what_we_do": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, + "what_support_means": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, + "cta": { + "type": "string" + }, + "community_growth_footnote": { + "type": "string" + }, + "what_this_means_for_you": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "cards": { + "type": "object", + "properties": { + "people": { + "type": "object", + "properties": { + "contributors": { + "type": "string" + }, + "community_members": { + "type": "string" + } + }, + "additionalProperties": false + }, + "visitors": { + "type": "object", + "properties": { + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, + "stars": { + "type": "object", + "properties": { + "title": { + "type": "string" + } + }, + "additionalProperties": false + }, + "community": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, + "adoption": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + }, + "default_source": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "tiers": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "per_month": { + "type": "string" + }, + "custom": { + "type": "string" + }, + "silver": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "gold": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "platinum": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, "account_menu": { "type": "object", "properties": { diff --git a/nuxt.config.ts b/nuxt.config.ts index a70b1f5313..401dfd006e 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -220,6 +220,7 @@ export default defineNuxtConfig({ '/pds': { isr: 86400 }, // revalidate daily '/blog/**': { prerender: true }, '/noodles/**': { prerender: true }, + '/sponsors': { prerender: true }, // proxy for insights '/_v/script.js': { proxy: 'https://npmx.dev/_vercel/insights/script.js', diff --git a/server/middleware/canonical-redirects.global.ts b/server/middleware/canonical-redirects.global.ts index 32161fe483..738612c2a7 100644 --- a/server/middleware/canonical-redirects.global.ts +++ b/server/middleware/canonical-redirects.global.ts @@ -22,6 +22,7 @@ const pages = [ '/brand', '/compare', '/noodles', + '/sponsors', '/org', '/package', '/package-code',