Skip to content

Commit 780b545

Browse files
patak-catalexdlncoderabbitai[bot]autofix-ci[bot]serhalp
authored
feat: npmx 0.8 release blog post (#2422)
Co-authored-by: Vordgi <sasha2822222@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Philippe Serhal <philippe.serhal@gmail.com>
1 parent e5fafc1 commit 780b545

File tree

15 files changed

+170
-10
lines changed

15 files changed

+170
-10
lines changed

app/components/global/BlogPostWrapper.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ useSeoMeta({
1515
ogTitle: props.frontmatter.title,
1616
ogDescription: props.frontmatter.description || props.frontmatter.excerpt,
1717
ogType: 'article',
18+
ogImage: props.frontmatter.image,
1819
...(props.frontmatter.draft ? { robots: 'noindex, nofollow' } : {}),
1920
})
2021
@@ -27,11 +28,13 @@ useHead({
2728
],
2829
})
2930
30-
defineOgImageComponent('BlogPost', {
31-
title: props.frontmatter.title,
32-
authors: post.value?.authors ?? [],
33-
date: props.frontmatter.date,
34-
})
31+
if (!props.frontmatter.image) {
32+
defineOgImageComponent('BlogPost', {
33+
title: props.frontmatter.title,
34+
authors: post.value?.authors ?? [],
35+
date: props.frontmatter.date,
36+
})
37+
}
3538
3639
const slug = computed(() => props.frontmatter.slug)
3740

app/components/global/BlueskyPostEmbed.client.vue

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,18 @@ interface EmbedImage {
2626
aspectRatio?: { width: number; height: number }
2727
}
2828
29+
interface EmbedExternal {
30+
description?: string
31+
thumb?: string
32+
title?: string
33+
uri: string
34+
}
35+
2936
interface BlueskyPost {
3037
uri: string
3138
author: PostAuthor
3239
record: { text: string; createdAt: string }
33-
embed?: { $type: string; images?: EmbedImage[] }
40+
embed?: { $type: string; images?: EmbedImage[]; external?: EmbedExternal }
3441
likeCount?: number
3542
replyCount?: number
3643
repostCount?: number
@@ -107,7 +114,7 @@ const postUrl = computed(() => {
107114
:href="postUrl ?? '#'"
108115
target="_blank"
109116
rel="noopener noreferrer"
110-
class="not-prose block rounded-lg border border-border bg-bg-subtle p-4 sm:p-5 no-underline hover:border-border-hover transition-colors duration-200 relative group"
117+
class="not-prose block my-4 rounded-lg border border-border bg-bg-subtle p-4 sm:p-5 no-underline hover:border-border-hover transition-colors duration-200 relative group"
111118
>
112119
<!-- Bluesky icon -->
113120
<span
@@ -154,6 +161,27 @@ const postUrl = computed(() => {
154161
/>
155162
</template>
156163

164+
<!-- Embedded external embed -->
165+
<template v-if="post.embed?.external && post.embed.external.uri">
166+
<div class="block mb-3 p-0.5 bg-bg-muted rounded-lg">
167+
<img
168+
v-if="post.embed.external.thumb"
169+
:src="post.embed.external.thumb"
170+
alt=""
171+
class="w-full rounded-lg object-cover"
172+
loading="lazy"
173+
/>
174+
<div class="text-fg-muted text-sm p-2">
175+
<p class="font-medium truncate">
176+
{{ post.embed.external.title || post.embed.external.uri }}
177+
</p>
178+
<p v-if="post.embed.external.description" class="text-sm line-clamp-2 mt-1">
179+
{{ post.embed.external.description }}
180+
</p>
181+
</div>
182+
</div>
183+
</template>
184+
157185
<!-- Timestamp + engagement -->
158186
<div class="flex items-center gap-4 text-sm text-fg-subtle">
159187
<DateTime :datetime="post.record.createdAt" date-style="medium" />

app/pages/blog/release/0.8.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
authors:
3+
- name: Alex Savelyev
4+
blueskyHandle: alexdln.com
5+
- name: Philippe Serhal
6+
blueskyHandle: philippeserhal.com
7+
- name: Matias Capeletto
8+
blueskyHandle: patak.cat
9+
title: 'npmx 0.8: npm at your fingertips'
10+
tags: ['OpenSource', 'Release']
11+
excerpt: "Today we're releasing npmx 0.8 – including a new command palette and a lot of other features."
12+
date: '2026-04-08'
13+
slug: 'release/0.8'
14+
image: 'https://npmx.dev/blog/og/release-0_8.png'
15+
description: "Today we're releasing npmx 0.8 – including a new command palette and a lot of other features."
16+
draft: false
17+
---
18+
19+
# npmx 0.8: npm at your fingertips
20+
21+
Today we continue to improve [npmx.dev](https://npmx.dev). npmx 0.8 includes new features to help our users navigate the npm registry and chose great dependencies to build their projects. Our [repository](https://repo.npmx.dev) has more than 3K stars and we're 240+ contributors working together to craft a modern browser for our packages.
22+
23+
## Unleash your mechanical keyboard with ⌘ K
24+
25+
npmx now has a rich command palette for efficient, keyboard-driven access to every page, toggle, and action across the website. Open it by hitting ⌘ K on macOS or Ctrl+K on Windows/Linux, or by clicking the new “jump to…” item in the header.
26+
27+
<figure>
28+
<video
29+
poster="/blog/release/0.8/cmd-palette-demo-cover.png"
30+
controls
31+
loop
32+
muted
33+
playsinline
34+
preload="metadata"
35+
aria-label="Screen recording of npmx's command palette in action: opening it with Cmd+K, toggling dark/light theme, switching languages, navigating to a package page, browsing source files, switching package versions, and searching for a new package, all without leaving the keyboard."
36+
>
37+
<source src="/blog/release/0.8/cmd-palette-demo.mp4" type="video/mp4" />
38+
</video>
39+
<figcaption class="sr-only">
40+
A screen recording demonstrating npmx's command palette. The video shows: the npmx home page in dark mode; opening the command palette with Cmd+K to reveal navigation, connections, and settings sections; using the palette to toggle to light mode, then back to dark mode; using the palette to switch the interface language to Vietnamese and back to English; navigating to the Vue package page and using the palette to access package actions like "download tarball" and "copy package name"; browsing into the package's source files in the built-in code viewer; using the palette to switch between Vue versions from a list filtered by a semantic versioning specifier; and finally typing "tinyexec" into the palette to search for a different package. Throughout, individual key presses are shown in an on-screen overlay.
41+
</figcaption>
42+
</figure>
43+
44+
There are already 68 total commands across the website, but you’ll always see just what’s relevant to your current view:
45+
46+
- On [a package page](https://npmx.dev/package/@clack/prompts), quickly download its tarball, copy its install command to your clipboard, open its repo, jump to its `@types/` package, and more
47+
- On the [compare page](https://npmx.dev/compare/), toggle between the table and charts views, copy the table to your clipboard, and more
48+
- When viewing [a package’s code](https://npmx.dev/package-code/unenv/v/2.0.0-rc.24/dist%2Findex.d.mts#L58), copy a link or the raw file contents to your clipboard, toggle between raw and preview mode, and more
49+
- From anywhere, jump to another page, toggle dark/light mode, change your language, get help by showing all keyboard shortcuts, jumping to the docs or to the npmx Discord server.
50+
51+
You’ll always see a fallback option to submit your input as a search:
52+
53+
![Light-themed command palette interface with a title ‘command palette’ and subtitle about
54+
navigating npm packages. A focused input field contains ‘tinylibs’. Below it, a single option
55+
appears with a magnifying glass icon and the text ‘search for “tinylibs”](/blog/release/0.8/cmd-palette-search-fallback.png)
56+
57+
Oh, and one more thing.
58+
59+
On a package page, type or paste any version or [SemVer range specifier](https://docs.npmx.dev/guide/semver-ranges) and you’ll immediately see matching versions of that package.
60+
61+
![Dark-themed command palette modal titled ‘command palette’ with a subtitle about navigating npm packages. A search input contains ‘~1.0.1’. Below, a list labeled ‘Versions of tinyexec’ shows selectable versions: 1.0.4, 1.0.3, 1.0.2, and 1.0.1.](/blog/release/0.8/cmd-palette-semver.png)
62+
63+
The command palette is intended to be accessible to everyone, with a full, rich experience on mobile and desktop, keyboard, mouse, touch screens, and screen readers.
64+
65+
## New package comparison view: quadrant graphs
66+
67+
The [compare page](https://npmx.dev/compare/) graph mode now shows an additional view of the same
68+
data: a quadrant graph. This is a scatter plot of all selected packages (up to 10 now, up from
69+
four!), with an aggregate measure of traction (downloads, freshness, likes) on the x-axis and developer ergonomics (install size, dependencies, vulnerabilities, type support) on the y-axis.
70+
71+
<figure>
72+
<img src="/blog/release/0.8/quadrant-graph-example.png" alt="Scatter plot of package traction vs. ergonomics, with delineated quadrants, showing seven UI component packages" />
73+
<figcaption class="sr-only">
74+
Dark-themed scatter plot titled ‘Package traction vs ergonomics.’ The vertical axis is labeled ‘Ergonomics’ (increasing upward), and the horizontal axis is labeled ‘Traction’ (increasing to the right). The chart is divided into four labeled regions: top left ‘Hidden gems,’ top right ‘Solid picks,’ bottom right ‘Popular with tradeoffs,’ and bottom left ‘Avoid.’ Several UI component libraries are plotted as colored dots:
75+
76+
- ‘emotion’ appears near the top center, indicating high ergonomics with moderate traction.
77+
- ‘bootstrap’ is in the upper right quadrant, showing strong traction and relatively high ergonomics.
78+
- ‘reka-ui’ and ‘radix-ui’ are on the right side near the horizontal midline, indicating high traction with moderate ergonomics.
79+
-@chakra-ui/react’ is in the lower right quadrant, suggesting high traction but lower ergonomics.
80+
-@material/web’ is near the bottom center, indicating low ergonomics and moderate traction.
81+
- ‘solid-ui’ is on the far left near the horizontal midline, indicating low traction with moderate ergonomics.
82+
83+
Faint concentric rounded rectangles in the background suggest scoring tiers, and axis lines intersect at the center of the chart.
84+
85+
</figcaption>
86+
</figure>
87+
88+
See the above example [live in action
89+
here](https://npmx.dev/compare?view=charts&packages=bootstrap,@chakra-ui/react,emotion,@material/web,solid-ui,reka-ui,radix-ui).
90+
91+
## We were @ ATmosphereConf 26!
92+
93+
The atproto community gathered in Vancouver for their annual conference. Five members of the npmx community were there, thanks to the support of the atproto community. This wasn't a regular tech conference. We were very impressed by the quality of the talks and conversations, especially about non-technical topics. There was so much hope in the atmosphere.
94+
95+
<BlueskyPostEmbed url="https://bsky.app/profile/npmx.dev/post/3miamtd537s2m" />
96+
97+
There is a lot to unpack, a lot of potential for collaborating with other atproto projects on shared lexicons and cross-linking between our websites. We'd like to thank the organisers and the community at large once more for the warm welcome, and for inviting us to present npmx in one of the keynotes:
98+
99+
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/xPJkoJ6dlqE?si=28jAlZlogB7DuMpq" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" class="w-full aspect-ratio-video rounded-lg" allowfullscreen></iframe>
100+
101+
## Noodles!
102+
103+
Thinking about who we are and what we stand for, we decided to launch noodles. These little changes on the main page focused on what we care about.
104+
105+
<BlueskyPostEmbed url="https://bsky.app/profile/npmx.dev/post/3miet6zoc5s2i" />
106+
107+
Today we're launching our second noodle to celebrate how far humanity can go when we work together. Visit [our landing](/) to enjoy a trip around the moon while searching for packages. If you'd like to help us brainstorm ideas, please join the conversation in the #noodles channel of our builders community and let's cook the best noodles together.
108+
109+
## News
110+
111+
A lot has happened since our [alpha launch](/blog/alpha-release). You can read Alex’s post for an overview of this past month, and to learn about some of the ideas the community is working on.
112+
113+
<BlueskyPostEmbed url="https://bsky.app/profile/alexdln.com/post/3mijbaws34c2q" />
114+
115+
We were also featured in the latest Igalia Chats episode discussing the history of npmx, the community, our ideas regarding funding, and more.
116+
117+
<BlueskyPostEmbed url="https://bsky.app/profile/igalia.com/post/3miwbkgbgyk2m" />
118+
119+
## What’s next
120+
121+
We have several features in the making, npmx 0.9 is already looking like a very interesting milestone for us. If you’re interested in getting involved, join us at [build.npmx.dev](https://build.npmx.dev). We’re just getting started!

modules/blog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ function resolveAuthors(authors: Author[], avatarMap: Map<string, string>): Reso
8888
* Resolves Bluesky avatars at build time.
8989
*/
9090
async function loadBlogPosts(blogDir: string, imagesDir: string): Promise<BlogPostFrontmatter[]> {
91-
const files = await Array.fromAsync(glob(join(blogDir, '*.md').replace(/\\/g, '/')))
91+
const files = await Array.fromAsync(glob(join(blogDir, '**/*.md').replace(/\\/g, '/')))
9292

9393
// First pass: extract raw frontmatter and collect all Bluesky handles
9494
const rawPosts: Array<{ frontmatter: Record<string, unknown> }> = []

modules/security-headers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default defineNuxtModule({
5555
const frameSrc = [
5656
'https://bsky.app',
5757
'https://pdsmoover.com',
58+
'https://www.youtube-nocookie.com/',
5859
...(isDevtoolsRuntime ? ["'self'"] : []),
5960
].join(' ')
6061

@@ -69,6 +70,7 @@ export default defineNuxtModule({
6970
`script-src 'self' 'unsafe-inline'`,
7071
`style-src 'self' 'unsafe-inline'`,
7172
`img-src ${imgSrc}`,
73+
`media-src 'self'`,
7274
`font-src 'self'`,
7375
`connect-src ${connectSrc}`,
7476
`frame-src ${frameSrc}`,
57.2 KB
Loading
67.7 KB
Loading

public/blog/og/release-0_8.png

395 KB
Loading
168 KB
Loading
2.54 MB
Binary file not shown.

0 commit comments

Comments
 (0)