Skip to content

Commit 09fd230

Browse files
committed
Merge branch 'main' of github.com:nulfrost/npmx.dev into refactor/modal-a11y
2 parents 219e454 + 485cc9c commit 09fd230

75 files changed

Lines changed: 1171 additions & 498 deletions

Some content is hidden

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

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ on:
1111
branches:
1212
- main
1313

14+
# cancel in-progress runs on new commits to same PR (gitub.event.number)
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
17+
cancel-in-progress: true
18+
1419
permissions:
1520
contents: read
1621

CONTRIBUTING.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ For example to check if all Japanese translation keys are up-to-date, run:
301301
pnpm i18n:check ja-JP
302302
```
303303

304+
To automatically add missing keys with English placeholders, use `--fix`:
305+
306+
```bash
307+
pnpm i18n:check:fix fr-FR
308+
```
309+
310+
This will add missing keys with `"EN TEXT TO REPLACE: {english text}"` as placeholder values, making it easier to see what needs translation.
311+
304312
#### Country variants (advanced)
305313

306314
Most languages only need a single locale file. Country variants are only needed when you want to support regional differences (e.g., `es-ES` for Spain vs `es-419` for Latin America).
@@ -361,13 +369,17 @@ We recommend the [i18n-ally](https://marketplace.visualstudio.com/items?itemName
361369

362370
The extension is included in our workspace recommendations, so VSCode should prompt you to install it.
363371

364-
### Formatting with locale
372+
### Formatting numbers and dates
365373

366-
When formatting numbers or dates that should respect the user's locale, pass the locale:
374+
Use vue-i18n's built-in formatters for locale-aware formatting:
367375

368-
```typescript
369-
const { locale } = useI18n()
370-
const formatted = formatNumber(12345, locale.value) // "12,345" in en-US
376+
```vue
377+
<template>
378+
<p>{{ $n(12345) }}</p>
379+
<!-- "12,345" in en-US, "12 345" in fr-FR -->
380+
<p>{{ $d(new Date()) }}</p>
381+
<!-- locale-aware date -->
382+
</template>
371383
```
372384

373385
## Testing

app/app.vue

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const { locale, locales } = useI18n()
1010
initPreferencesOnPrehydrate()
1111
1212
const isHomepage = computed(() => route.name === 'index')
13+
const showKbdHints = shallowRef(false)
1314
1415
const localeMap = locales.value.reduce(
1516
(acc, l) => {
@@ -21,8 +22,9 @@ const localeMap = locales.value.reduce(
2122
2223
useHead({
2324
htmlAttrs: {
24-
lang: () => locale.value,
25-
dir: () => localeMap[locale.value] ?? 'ltr',
25+
'lang': () => locale.value,
26+
'dir': () => localeMap[locale.value] ?? 'ltr',
27+
'data-kbd-hints': () => showKbdHints.value,
2628
},
2729
titleTemplate: titleChunk => {
2830
return titleChunk ? titleChunk : 'npmx - Better npm Package Browser'
@@ -33,16 +35,16 @@ if (import.meta.server) {
3335
setJsonLd(createWebSiteSchema())
3436
}
3537
36-
// Global keyboard shortcut: "/" focuses search or navigates to search page
38+
// Global keyboard shortcut:
39+
// "/" focuses search or navigates to search page
40+
// "?" highlights all keyboard shortcut elements
3741
function handleGlobalKeydown(e: KeyboardEvent) {
3842
const target = e.target as HTMLElement
3943
4044
const isEditableTarget =
4145
target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable
4246
43-
if (isEditableTarget) {
44-
return
45-
}
47+
if (isEditableTarget) return
4648
4749
if (e.key === '/') {
4850
e.preventDefault()
@@ -59,10 +61,20 @@ function handleGlobalKeydown(e: KeyboardEvent) {
5961
6062
router.push('/search')
6163
}
64+
65+
if (e.key === '?') {
66+
e.preventDefault()
67+
showKbdHints.value = true
68+
}
69+
}
70+
71+
function handleGlobalKeyup() {
72+
showKbdHints.value = false
6273
}
6374
6475
if (import.meta.client) {
6576
useEventListener(document, 'keydown', handleGlobalKeydown)
77+
useEventListener(document, 'keyup', handleGlobalKeyup)
6678
}
6779
</script>
6880

@@ -85,3 +97,25 @@ if (import.meta.client) {
8597
<!-- <ConnectorModal /> -->
8698
<AuthModal />
8799
</template>
100+
101+
<style>
102+
/* Keyboard shortcut highlight on "?" key press */
103+
kbd {
104+
position: relative;
105+
}
106+
107+
kbd::before {
108+
content: '';
109+
position: absolute;
110+
inset: 0;
111+
border-radius: inherit;
112+
box-shadow: 0 0 4px 2px var(--accent);
113+
opacity: 0;
114+
transition: opacity 200ms ease-out;
115+
pointer-events: none;
116+
}
117+
118+
html[data-kbd-hints='true'] kbd::before {
119+
opacity: 1;
120+
}
121+
</style>

app/assets/main.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ html.light .shiki span {
463463
border-collapse: collapse;
464464
margin: 1.5rem 0;
465465
font-size: 0.875rem;
466+
word-break: keep-all;
466467
}
467468

468469
.readme-content th,

app/components/AppFooter.vue

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,16 @@ const isHome = computed(() => route.name === 'index')
1313
<p class="font-mono text-balance m-0 hidden sm:block">{{ $t('tagline') }}</p>
1414
<BuildEnvironment v-if="!isHome" footer />
1515
</div>
16-
<div class="flex items-center gap-3 sm:gap-6">
17-
<NuxtLink
18-
to="/about"
19-
class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center"
20-
>
16+
<!-- Desktop: Show all links. Mobile: Links are in MobileMenu -->
17+
<div class="hidden sm:flex items-center gap-6">
18+
<NuxtLink to="/about" class="link-subtle font-mono text-xs min-h-11 flex items-center">
2119
{{ $t('footer.about') }}
2220
</NuxtLink>
2321
<a
2422
href="https://docs.npmx.dev"
2523
target="_blank"
2624
rel="noopener noreferrer"
27-
class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1"
25+
class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1"
2826
>
2927
{{ $t('footer.docs') }}
3028
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
@@ -33,7 +31,7 @@ const isHome = computed(() => route.name === 'index')
3331
href="https://repo.npmx.dev"
3432
target="_blank"
3533
rel="noopener noreferrer"
36-
class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1"
34+
class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1"
3735
>
3836
{{ $t('footer.source') }}
3937
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
@@ -42,7 +40,7 @@ const isHome = computed(() => route.name === 'index')
4240
href="https://social.npmx.dev"
4341
target="_blank"
4442
rel="noopener noreferrer"
45-
class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1"
43+
class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1"
4644
>
4745
{{ $t('footer.social') }}
4846
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
@@ -51,7 +49,7 @@ const isHome = computed(() => route.name === 'index')
5149
href="https://chat.npmx.dev"
5250
target="_blank"
5351
rel="noopener noreferrer"
54-
class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1"
52+
class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1"
5553
>
5654
{{ $t('footer.chat') }}
5755
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />

0 commit comments

Comments
 (0)