Skip to content

Commit ff2f9cf

Browse files
authored
Merge branch 'npmx-dev:main' into main
2 parents 7067246 + a5b2e9c commit ff2f9cf

31 files changed

Lines changed: 768 additions & 194 deletions

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ We welcome contributions – please do feel free to explore the project and
155155
- [npm-userscript](https://github.com/bluwy/npm-userscript) – Browser userscript with various improvements and fixes for npmjs.com
156156
- [npm-alt](https://npm.willow.sh/) – An alternative npm package browser
157157
- [npkg.lorypelli.dev](https://npkg.lorypelli.dev/) – An alternative frontend to npm made with as little client-side JavaScript as possible
158-
- [vscode-npmx](https://github.com/npmx-dev/vscode-npmx) – VSCode extension for npmx
158+
- [vscode-npmx](https://github.com/npmx-dev/vscode-npmx) – Official VSCode extension for npmx
159+
- [vscode-open-in-npmx](https://github.com/sybers/vscode-open-in-npmx) – VSCode shortcut to open packages on npmx
159160
- [nxjt](https://nxjt.netlify.app) – npmx Jump To: Quickly navigate to npmx common webpages.
160161
- [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).
161162
- [npmx-digest](https://npmx-digest.trueberryless.org/) – An automated news aggregation website that summarizes npmx activity from GitHub and Bluesky every 8 hours.

app/app.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,12 @@ if (import.meta.client) {
121121
<template>
122122
<div class="min-h-screen flex flex-col bg-bg text-fg">
123123
<NuxtPwaAssets />
124-
<LinkBase to="#main-content" variant="button-primary" class="skip-link">{{
125-
$t('common.skip_link')
126-
}}</LinkBase>
124+
<LinkBase
125+
:to="{ hash: '#main-content', query: route.query, params: route.params }"
126+
variant="button-primary"
127+
class="skip-link"
128+
>{{ $t('common.skip_link') }}</LinkBase
129+
>
127130

128131
<AppHeader :show-logo="!isHomepage" />
129132

app/components/AppHeader.vue

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const mobileLinks = computed<NavigationConfigWithGroups>(() => [
107107
target: '_blank',
108108
type: 'link',
109109
external: true,
110-
iconClass: 'i-simple-icons:bluesky',
110+
iconClass: 'i-carbon:logo-bluesky',
111111
},
112112
{
113113
name: 'Chat',
@@ -124,6 +124,7 @@ const mobileLinks = computed<NavigationConfigWithGroups>(() => [
124124
125125
const showFullSearch = shallowRef(false)
126126
const showMobileMenu = shallowRef(false)
127+
const { env } = useAppConfig().buildInfo
127128
128129
// On mobile, clicking logo+search button expands search
129130
const route = useRoute()
@@ -212,10 +213,16 @@ onKeyStroke(
212213
:to="{ name: 'index' }"
213214
:aria-label="$t('header.home')"
214215
dir="ltr"
215-
class="inline-flex items-center gap-1 header-logo font-mono text-lg font-medium text-fg hover:text-fg/90 transition-colors duration-200 rounded"
216+
class="relative inline-flex items-center gap-1 header-logo font-mono text-lg font-medium text-fg hover:text-fg/90 transition-colors duration-200 rounded"
216217
>
217-
<AppLogo class="w-8 h-8 rounded-lg" />
218-
<span>npmx</span>
218+
<AppLogo class="w-7 h-7 rounded-lg" />
219+
<span class="pb-0.5">npmx</span>
220+
<span
221+
aria-hidden="true"
222+
class="scale-35 transform-origin-br font-mono tracking-wide text-accent absolute bottom-0.5 -inset-ie-1"
223+
>
224+
{{ env === 'release' ? 'alpha' : env }}
225+
</span>
219226
</NuxtLink>
220227
</div>
221228
<!-- Spacer when logo is hidden on desktop -->

app/components/CallToAction.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const socialLinks = computed(() => [
1919
{
2020
id: 'bluesky',
2121
href: 'https://social.npmx.dev',
22-
icon: 'i-simple-icons:bluesky',
22+
icon: 'i-carbon:logo-bluesky',
2323
titleKey: $t('about.get_involved.follow.title'),
2424
descriptionKey: $t('about.get_involved.follow.description'),
2525
ctaKey: $t('about.get_involved.follow.cta'),

app/components/Header/AccountMenu.client.vue

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,12 @@ function openAuthModal() {
142142
<!-- Connected accounts section -->
143143
<div v-if="hasAnyConnection" class="py-1">
144144
<!-- npm CLI connection -->
145-
<button
145+
<ButtonBase
146146
v-if="isNpmConnected && npmUser"
147-
type="button"
148147
role="menuitem"
149-
class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-muted transition-colors text-start rounded-md"
148+
class="w-full text-start gap-x-3 border-none"
150149
@click="openConnectorModal"
150+
out
151151
>
152152
<img
153153
v-if="npmAvatar"
@@ -182,14 +182,13 @@ function openAuthModal() {
182182
})
183183
}}
184184
</span>
185-
</button>
185+
</ButtonBase>
186186

187187
<!-- Atmosphere connection -->
188-
<button
188+
<ButtonBase
189189
v-if="atprotoUser"
190-
type="button"
191190
role="menuitem"
192-
class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-muted transition-colors text-start rounded-md"
191+
class="w-full text-start gap-x-3 border-none"
193192
@click="openAuthModal"
194193
>
195194
<img
@@ -212,7 +211,7 @@ function openAuthModal() {
212211
>
213212
<span class="text-xs text-fg-subtle">{{ $t('account_menu.atmosphere') }}</span>
214213
</span>
215-
</button>
214+
</ButtonBase>
216215
</div>
217216

218217
<!-- Divider (only if we have connections AND options to connect) -->
@@ -223,11 +222,10 @@ function openAuthModal() {
223222

224223
<!-- Connect options -->
225224
<div v-if="!isNpmConnected || !atprotoUser" class="py-1">
226-
<button
225+
<ButtonBase
227226
v-if="!isNpmConnected"
228-
type="button"
229227
role="menuitem"
230-
class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-muted transition-colors text-start rounded-md"
228+
class="w-full text-start gap-x-3 border-none"
231229
@click="openConnectorModal"
232230
>
233231
<span class="w-8 h-8 rounded-full bg-bg-muted flex items-center justify-center">
@@ -248,13 +246,12 @@ function openAuthModal() {
248246
</span>
249247
<span class="text-xs text-fg-subtle">{{ $t('account_menu.npm_cli_desc') }}</span>
250248
</span>
251-
</button>
249+
</ButtonBase>
252250

253-
<button
251+
<ButtonBase
254252
v-if="!atprotoUser"
255-
type="button"
256253
role="menuitem"
257-
class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-muted transition-colors text-start rounded-md"
254+
class="w-full text-start gap-x-3 border-none"
258255
@click="openAuthModal"
259256
>
260257
<span class="w-8 h-8 rounded-full bg-bg-muted flex items-center justify-center">
@@ -266,7 +263,7 @@ function openAuthModal() {
266263
</span>
267264
<span class="text-xs text-fg-subtle">{{ $t('account_menu.atmosphere_desc') }}</span>
268265
</span>
269-
</button>
266+
</ButtonBase>
270267
</div>
271268
</div>
272269
</div>

app/components/Header/AuthModal.client.vue

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,9 @@ watch(handleInput, newHandleInput => {
6464
</p>
6565
</div>
6666
</div>
67-
<button
68-
class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70"
69-
@click="logout"
70-
>
67+
<ButtonBase class="w-full" @click="logout">
7168
{{ $t('auth.modal.disconnect') }}
72-
</button>
69+
</ButtonBase>
7370
</div>
7471

7572
<!-- Disconnected state -->
@@ -111,19 +108,13 @@ watch(handleInput, newHandleInput => {
111108
<span class="font-bold">npmx.dev</span>
112109
</template>
113110
<template #atproto>
114-
<a :href="atprotoLink" target="_blank" class="text-blue-400 hover:underline">
115-
AT Protocol
116-
</a>
111+
<LinkBase :to="atprotoLink"> AT Protocol </LinkBase>
117112
</template>
118113
<template #bluesky>
119-
<a href="https://bsky.app" target="_blank" class="text-blue-400 hover:underline">
120-
Bluesky
121-
</a>
114+
<LinkBase to="https://bsky.app"> Bluesky </LinkBase>
122115
</template>
123116
<template #tangled>
124-
<a href="https://tangled.org" target="_blank" class="text-blue-400 hover:underline">
125-
Tangled
126-
</a>
117+
<LinkBase to="https://tangled.org"> Tangled </LinkBase>
127118
</template>
128119
</i18n-t>
129120
</div>
@@ -133,18 +124,17 @@ watch(handleInput, newHandleInput => {
133124
<ButtonBase type="submit" variant="primary" :disabled="!handleInput.trim()" class="w-full">
134125
{{ $t('auth.modal.connect') }}
135126
</ButtonBase>
136-
<ButtonBase type="button" variant="primary" class="w-full" @click="handleCreateAccount">
127+
<ButtonBase type="button" class="w-full" @click="handleCreateAccount">
137128
{{ $t('auth.modal.create_account') }}
138129
</ButtonBase>
139130
<hr class="color-border" />
140-
<ButtonBase type="button" variant="primary" class="w-full" @click="handleBlueskySignIn" block>
131+
<ButtonBase
132+
type="button"
133+
class="w-full"
134+
@click="handleBlueskySignIn"
135+
classicon="i-carbon:logo-bluesky"
136+
>
141137
{{ $t('auth.modal.connect_bluesky') }}
142-
<svg fill="none" viewBox="0 0 64 57" width="20" style="width: 20px">
143-
<path
144-
fill="#0F73FF"
145-
d="M13.873 3.805C21.21 9.332 29.103 20.537 32 26.55v15.882c0-.338-.13.044-.41.867-1.512 4.456-7.418 21.847-20.923 7.944-7.111-7.32-3.819-14.64 9.125-16.85-7.405 1.264-15.73-.825-18.014-9.015C1.12 23.022 0 8.51 0 6.55 0-3.268 8.579-.182 13.873 3.805ZM50.127 3.805C42.79 9.332 34.897 20.537 32 26.55v15.882c0-.338.13.044.41.867 1.512 4.456 7.418 21.847 20.923 7.944 7.111-7.32 3.819-14.64-9.125-16.85 7.405 1.264 15.73-.825 18.014-9.015C62.88 23.022 64 8.51 64 6.55c0-9.818-8.578-6.732-13.873-2.745Z"
146-
></path>
147-
</svg>
148138
</ButtonBase>
149139
</form>
150140
</Modal>

app/components/Header/ConnectorModal.vue

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,9 @@ function handleDisconnect() {
8080
{{ $t('connector.modal.connected_hint') }}
8181
</div>
8282

83-
<button
84-
type="button"
85-
class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70"
86-
@click="handleDisconnect"
87-
>
83+
<ButtonBase type="button" class="w-full" @click="handleDisconnect">
8884
{{ $t('connector.modal.disconnect') }}
89-
</button>
85+
</ButtonBase>
9086
</div>
9187

9288
<!-- Disconnected state -->
@@ -100,14 +96,11 @@ function handleDisconnect() {
10096
<p class="text-sm text-fg-muted">
10197
<i18n-t keypath="connector.modal.contributor_notice" scope="global">
10298
<template #link>
103-
<a
104-
href="https://github.com/npmx-dev/npmx.dev/blob/main/CONTRIBUTING.md#local-connector-cli"
105-
target="_blank"
106-
rel="noopener noreferrer"
107-
class="text-blue-400 hover:underline"
99+
<LinkBase
100+
to="https://github.com/npmx-dev/npmx.dev/blob/main/CONTRIBUTING.md#local-connector-cli"
108101
>
109102
{{ $t('connector.modal.contributor_link') }}
110-
</a>
103+
</LinkBase>
111104
</template>
112105
</i18n-t>
113106
</p>
@@ -124,15 +117,12 @@ function handleDisconnect() {
124117
>
125118
<span class="text-fg-subtle">$</span>
126119
<span class="text-fg-subtle ms-2">pnpm npmx-connector</span>
127-
<button
128-
type="button"
120+
<ButtonBase
129121
:aria-label="copied ? $t('connector.modal.copied') : $t('connector.modal.copy_command')"
130-
class="ms-auto text-fg-subtle p-1.5 -m-1.5 hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded"
131122
@click="copy('pnpm npmx-connector')"
132-
>
133-
<span v-if="!copied" class="i-carbon:copy block w-5 h-5" aria-hidden="true" />
134-
<span v-else class="i-carbon:checkmark block w-5 h-5 text-green-500" aria-hidden="true" />
135-
</button>
123+
class="ms-auto"
124+
:classicon="copied ? 'i-carbon:checkmark text-green-500' : 'i-carbon:copy'"
125+
/>
136126
</div>
137127

138128
<!-- TODO: Uncomment when npmx-connector is published to npm

app/components/Terminal/Install.vue

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
<script setup lang="ts">
22
import type { JsrPackageInfo } from '#shared/types/jsr'
3+
import type { DevDependencySuggestion } from '#shared/utils/dev-dependency'
34
import type { PackageManagerId } from '~/utils/install-command'
45
56
const props = defineProps<{
67
packageName: string
78
requestedVersion?: string | null
89
installVersionOverride?: string | null
910
jsrInfo?: JsrPackageInfo | null
11+
devDependencySuggestion?: DevDependencySuggestion | null
1012
typesPackageName?: string | null
1113
executableInfo?: { hasExecutable: boolean; primaryCommand?: string } | null
1214
createPackageInfo?: { packageName: string } | null
@@ -30,6 +32,20 @@ function getInstallPartsForPM(pmId: PackageManagerId) {
3032
})
3133
}
3234
35+
const devDependencySuggestion = computed(
36+
() => props.devDependencySuggestion ?? { recommended: false as const },
37+
)
38+
39+
function getDevInstallPartsForPM(pmId: PackageManagerId) {
40+
return getInstallCommandParts({
41+
packageName: props.packageName,
42+
packageManager: pmId,
43+
version: props.requestedVersion,
44+
jsrInfo: props.jsrInfo,
45+
dev: true,
46+
})
47+
}
48+
3349
// Generate run command parts for a specific package manager
3450
function getRunPartsForPM(pmId: PackageManagerId, command?: string) {
3551
return getRunCommandParts({
@@ -68,7 +84,7 @@ function getTypesInstallPartsForPM(pmId: PackageManagerId) {
6884
const pm = packageManagers.find(p => p.id === pmId)
6985
if (!pm) return []
7086
71-
const devFlag = pmId === 'bun' ? '-d' : '-D'
87+
const devFlag = getDevDependencyFlag(pmId)
7288
const pkgSpec = pmId === 'deno' ? `npm:${props.typesPackageName}` : props.typesPackageName
7389
7490
return [pm.label, pm.action, devFlag, pkgSpec]
@@ -95,6 +111,18 @@ const copyRunCommand = (command?: string) => copyRun(getFullRunCommand(command))
95111
96112
const { copied: createCopied, copy: copyCreate } = useClipboard({ copiedDuring: 2000 })
97113
const copyCreateCommand = () => copyCreate(getFullCreateCommand())
114+
115+
const { copied: devInstallCopied, copy: copyDevInstall } = useClipboard({ copiedDuring: 2000 })
116+
const copyDevInstallCommand = () =>
117+
copyDevInstall(
118+
getInstallCommand({
119+
packageName: props.packageName,
120+
packageManager: selectedPM.value,
121+
version: props.requestedVersion,
122+
jsrInfo: props.jsrInfo,
123+
dev: true,
124+
}),
125+
)
98126
</script>
99127

100128
<template>
@@ -133,6 +161,42 @@ const copyCreateCommand = () => copyCreate(getFullCreateCommand())
133161
</button>
134162
</div>
135163

164+
<!-- Suggested dev dependency install command -->
165+
<template v-if="devDependencySuggestion.recommended">
166+
<div class="flex items-center gap-2 pt-1 select-none">
167+
<span class="text-fg-subtle font-mono text-sm"
168+
># {{ $t('package.get_started.dev_dependency_hint') }}</span
169+
>
170+
</div>
171+
<div
172+
v-for="pm in packageManagers"
173+
:key="`install-dev-${pm.id}`"
174+
:data-pm-cmd="pm.id"
175+
class="flex items-center gap-2 group/devinstallcmd min-w-0"
176+
>
177+
<span class="text-fg-subtle font-mono text-sm select-none shrink-0">$</span>
178+
<code class="font-mono text-sm min-w-0"
179+
><span
180+
v-for="(part, i) in getDevInstallPartsForPM(pm.id)"
181+
:key="i"
182+
:class="i === 0 ? 'text-fg' : 'text-fg-muted'"
183+
>{{ i > 0 ? ' ' : '' }}{{ part }}</span
184+
></code
185+
>
186+
<ButtonBase
187+
type="button"
188+
size="small"
189+
class="text-fg-muted bg-bg-subtle/80 border-border opacity-0 group-hover/devinstallcmd:opacity-100 active:scale-95 focus-visible:opacity-100 select-none"
190+
:aria-label="$t('package.get_started.copy_dev_command')"
191+
@click.stop="copyDevInstallCommand"
192+
>
193+
<span aria-live="polite">{{
194+
devInstallCopied ? $t('common.copied') : $t('common.copy')
195+
}}</span>
196+
</ButtonBase>
197+
</div>
198+
</template>
199+
136200
<!-- @types package install - render all PM variants when types package exists -->
137201
<template v-if="typesPackageName && showTypesInInstall">
138202
<div

app/composables/useGlobalSearch.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export function useGlobalSearch() {
2626
urlQuery => {
2727
const value = normalizeSearchParam(urlQuery)
2828
if (!value) searchQuery.value = ''
29+
if (!searchQuery.value) searchQuery.value = value
2930
},
3031
)
3132
const updateUrlQueryImpl = (value: string, provider: 'npm' | 'algolia') => {

0 commit comments

Comments
 (0)