Skip to content

Commit f65e30f

Browse files
committed
Merge branch 'main' of github.com:harlan-zw/fork-npmx.dev into feat/og-image-v6
2 parents 81c6227 + 8199c1f commit f65e30f

93 files changed

Lines changed: 6488 additions & 1186 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.storybook/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook-vue/nuxt'
22

33
const config = {
44
stories: ['../app/**/*.stories.@(js|ts)'],
5-
addons: ['@storybook/addon-a11y', '@storybook/addon-docs'],
5+
addons: ['@storybook/addon-a11y', '@storybook/addon-docs', '@storybook/addon-themes'],
66
framework: '@storybook-vue/nuxt',
77
features: {
88
backgrounds: false,

.storybook/preview.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Preview } from '@storybook-vue/nuxt'
2+
import { withThemeByDataAttribute } from '@storybook/addon-themes'
23
import { currentLocales } from '../config/i18n'
34
import { fn } from 'storybook/test'
45
import { ACCENT_COLORS } from '../shared/utils/constants'
@@ -58,31 +59,22 @@ const preview: Preview = {
5859
],
5960
},
6061
},
61-
theme: {
62-
name: 'Theme',
63-
description: 'Color mode',
64-
defaultValue: 'dark',
65-
toolbar: {
66-
icon: 'moon',
67-
dynamicTitle: true,
68-
items: [
69-
{ value: 'light', icon: 'sun', title: 'Light' },
70-
{ value: 'dark', icon: 'moon', title: 'Dark' },
71-
],
72-
},
73-
},
7462
},
7563
decorators: [
64+
withThemeByDataAttribute({
65+
themes: {
66+
Light: 'light',
67+
Dark: 'dark',
68+
},
69+
defaultTheme: 'Dark',
70+
attributeName: 'data-theme',
71+
}),
7672
(story, context) => {
77-
const { locale, theme, accentColor } = context.globals as {
73+
const { locale, accentColor } = context.globals as {
7874
locale: string
79-
theme: string
8075
accentColor?: string
8176
}
8277

83-
// Set theme from globals
84-
document.documentElement.setAttribute('data-theme', theme)
85-
8678
// Set accent color from globals
8779
if (accentColor) {
8880
document.documentElement.style.setProperty('--accent-color', `var(--swatch-${accentColor})`)

app/app.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ if (import.meta.server) {
4747
setJsonLd(createWebSiteSchema())
4848
}
4949
50+
const keyboardShortcuts = useKeyboardShortcuts()
51+
5052
onKeyDown(
5153
'/',
5254
e => {
53-
if (isEditableElement(e.target)) return
55+
if (!keyboardShortcuts.value || isEditableElement(e.target)) return
5456
e.preventDefault()
5557
5658
const searchInput = document.querySelector<HTMLInputElement>(
@@ -70,7 +72,7 @@ onKeyDown(
7072
onKeyDown(
7173
'?',
7274
e => {
73-
if (isEditableElement(e.target)) return
75+
if (!keyboardShortcuts.value || isEditableElement(e.target)) return
7476
e.preventDefault()
7577
showKbdHints.value = true
7678
},
@@ -80,7 +82,7 @@ onKeyDown(
8082
onKeyUp(
8183
'?',
8284
e => {
83-
if (isEditableElement(e.target)) return
85+
if (!keyboardShortcuts.value || isEditableElement(e.target)) return
8486
e.preventDefault()
8587
showKbdHints.value = false
8688
},

app/assets/main.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ input[type='search']::-webkit-search-results-decoration {
335335
animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
336336
}
337337

338+
/* Hide keyboard shortcut hints before hydration when user disabled them */
339+
:root[data-kbd-shortcuts='false'] [data-kbd-hint] {
340+
display: none;
341+
}
342+
338343
/* Locking the scroll whenever any of the modals are open */
339344
html:has(dialog:modal) {
340345
overflow: hidden;

app/components/AppFooter.vue

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const isHome = computed(() => route.name === 'index')
66
77
const modalRef = useTemplateRef('modalRef')
88
const showModal = () => modalRef.value?.showModal?.()
9+
const closeModal = () => modalRef.value?.close?.()
910
</script>
1011

1112
<template>
@@ -81,7 +82,7 @@ const showModal = () => modalRef.value?.showModal?.()
8182
<p class="mb-2 font-mono text-fg-subtle">
8283
{{ $t('shortcuts.section.package') }}
8384
</p>
84-
<ul class="mb-6 flex flex-col gap-2">
85+
<ul class="mb-8 flex flex-col gap-2">
8586
<li class="flex gap-2 items-center">
8687
<kbd class="kbd">.</kbd>
8788
<span>{{ $t('shortcuts.open_code_view') }}</span>
@@ -95,6 +96,19 @@ const showModal = () => modalRef.value?.showModal?.()
9596
<span>{{ $t('shortcuts.compare_from_package') }}</span>
9697
</li>
9798
</ul>
99+
<p class="text-fg-muted leading-relaxed">
100+
<i18n-t keypath="shortcuts.disable_shortcuts" tag="span" scope="global">
101+
<template #settings>
102+
<NuxtLink
103+
:to="{ name: 'settings' }"
104+
class="hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg"
105+
@click="closeModal"
106+
>
107+
{{ $t('settings.title') }}
108+
</NuxtLink>
109+
</template>
110+
</i18n-t>
111+
</p>
98112
</Modal>
99113
<LinkBase :to="NPMX_DOCS_SITE">
100114
{{ $t('footer.docs') }}

app/components/AppHeader.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type { NavigationConfig, NavigationConfigWithGroups } from '~/types'
44
import { isEditableElement } from '~/utils/input'
55
import { NPMX_DOCS_SITE } from '#shared/utils/constants'
66
7+
const keyboardShortcuts = useKeyboardShortcuts()
8+
79
withDefaults(
810
defineProps<{
911
showLogo?: boolean
@@ -125,7 +127,7 @@ const mobileLinks = computed<NavigationConfigWithGroups>(() => [
125127
126128
const showFullSearch = shallowRef(false)
127129
const showMobileMenu = shallowRef(false)
128-
const { env } = useAppConfig().buildInfo
130+
const { env, prNumber } = useAppConfig().buildInfo
129131
130132
// On mobile, clicking logo+search button expands search
131133
const route = useRoute()
@@ -175,7 +177,7 @@ function handleSearchFocus() {
175177
176178
onKeyStroke(
177179
e => {
178-
if (isEditableElement(e.target)) {
180+
if (!keyboardShortcuts.value || isEditableElement(e.target)) {
179181
return
180182
}
181183
@@ -225,6 +227,15 @@ onKeyStroke(
225227
{{ env === 'release' ? 'alpha' : env }}
226228
</span>
227229
</NuxtLink>
230+
<NuxtLink
231+
v-if="prNumber"
232+
:to="`https://github.com/npmx-dev/npmx.dev/pull/${prNumber}`"
233+
:aria-label="`Open GitHub pull request ${prNumber}`"
234+
>
235+
<span class="text-xs px-1.5 py-0.5 rounded badge-green font-sans font-medium ms-2">
236+
PR #{{ prNumber }}
237+
</span>
238+
</NuxtLink>
228239
</div>
229240
<!-- Spacer when logo is hidden on desktop -->
230241
<span v-else class="hidden sm:block w-1" />

app/components/Button/Base.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const props = withDefaults(
2626
2727
const el = useTemplateRef('el')
2828
29+
const keyboardShortcutsEnabled = useKeyboardShortcuts()
30+
2931
defineExpose({
3032
focus: () => el.value?.focus(),
3133
getBoundingClientRect: () => el.value?.getBoundingClientRect(),
@@ -56,12 +58,13 @@ defineExpose({
5658
*/
5759
disabled ? true : undefined
5860
"
59-
:aria-keyshortcuts="ariaKeyshortcuts"
61+
:aria-keyshortcuts="keyboardShortcutsEnabled ? ariaKeyshortcuts : undefined"
6062
>
6163
<span v-if="classicon" class="size-[1em]" :class="classicon" aria-hidden="true" />
6264
<slot />
6365
<kbd
64-
v-if="ariaKeyshortcuts"
66+
v-if="keyboardShortcutsEnabled && ariaKeyshortcuts"
67+
data-kbd-hint
6568
class="ms-2 inline-flex items-center justify-center w-4 h-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
6669
aria-hidden="true"
6770
>

app/components/Code/FileTree.vue

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,7 @@ watch(
9494
block
9595
:style="{ paddingLeft: `${depth * 12 + 32}px` }"
9696
>
97-
<svg
98-
class="size-[1em] me-1 shrink-0"
99-
viewBox="0 0 16 16"
100-
fill="currentColor"
101-
aria-hidden="true"
102-
>
97+
<svg class="size-[1em] me-1 shrink-0" viewBox="0 0 16 16" aria-hidden="true">
10398
<use :href="`/file-tree-sprite.svg#${getFileIcon(node.name)}`" />
10499
</svg>
105100
<span class="truncate">{{ node.name }}</span>

app/components/Compare/PackageSelector.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ onClickOutside(containerRef, () => {
301301
v-if="result.description"
302302
class="text-xs text-fg-muted truncate mt-0.5 w-full block"
303303
>
304-
{{ decodeHtmlEntities(result.description) }}
304+
{{ stripHtmlTags(decodeHtmlEntities(result.description)) }}
305305
</span>
306306
</ButtonBase>
307307
</div>

app/components/Header/AuthModal.client.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { useAtproto } from '~/composables/atproto/useAtproto'
33
import { authRedirect } from '~/utils/atproto/helpers'
44
import { isAtIdentifierString } from '@atproto/lex'
55
6+
const authModal = useModal('auth-modal')
7+
68
const handleInput = shallowRef('')
79
const errorMessage = shallowRef('')
810
const route = useRoute()
@@ -72,9 +74,22 @@ watch(user, async newUser => {
7274
</p>
7375
</div>
7476
</div>
75-
<ButtonBase class="w-full" @click="logout">
76-
{{ $t('auth.modal.disconnect') }}
77-
</ButtonBase>
77+
78+
<div class="flex flex-col space-y-4">
79+
<LinkBase
80+
variant="button-secondary"
81+
:to="{ name: 'profile-handle', params: { handle: user.handle } }"
82+
prefetch-on="interaction"
83+
class="w-full"
84+
@click="authModal.close()"
85+
>
86+
{{ $t('auth.modal.profile') }}
87+
</LinkBase>
88+
89+
<ButtonBase class="w-full" @click="logout">
90+
{{ $t('auth.modal.disconnect') }}
91+
</ButtonBase>
92+
</div>
7893
</div>
7994

8095
<!-- Disconnected state -->

0 commit comments

Comments
 (0)