Skip to content

Commit 07e1ff0

Browse files
committed
fix:Merge remote-tracking branch 'origin/main' into Fix/update-norwegian-translation
2 parents 6705732 + 78e0188 commit 07e1ff0

File tree

189 files changed

+15832
-3102
lines changed

Some content is hidden

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

189 files changed

+15832
-3102
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,8 @@ jobs:
235235

236236
- name: 🌐 Check for missing or dynamic i18n keys
237237
run: pnpm i18n:report
238+
239+
- name: 🌐 Check i18n schema is up to date
240+
run: |
241+
pnpm i18n:schema
242+
git diff --exit-code i18n/schema.json
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: mirror
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- '*'
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
mirror:
15+
name: 🕸️ Mirror to Tangled
16+
runs-on: ubuntu-24.04-arm
17+
18+
steps:
19+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
20+
with:
21+
fetch-depth: 0
22+
23+
- name: 🔑 Configure SSH
24+
env:
25+
TANGLED_SSH_KEY: ${{ secrets.TANGLED_SSH_KEY }}
26+
run: |
27+
mkdir -p ~/.ssh
28+
echo "$TANGLED_SSH_KEY" > ~/.ssh/id_ed25519
29+
chmod 600 ~/.ssh/id_ed25519
30+
ssh-keyscan -t ed25519 tangled.org >> ~/.ssh/known_hosts 2>/dev/null
31+
32+
- name: ⬆︎ Push to Tangled
33+
run: |
34+
git remote add tangled git@tangled.org:npmx.dev/npmx.dev
35+
git push tangled main --force
36+
git push tangled --tags --force

.lighthouserc.cjs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,18 @@ module.exports = {
3535
chromePath: findChrome(),
3636
puppeteerScript: './lighthouse-setup.cjs',
3737
settings: {
38-
onlyCategories: ['accessibility'],
38+
onlyCategories: process.env.LH_PERF ? ['performance'] : ['accessibility'],
3939
skipAudits: ['valid-source-maps'],
4040
},
4141
},
4242
assert: {
43-
assertions: {
44-
'categories:accessibility': ['error', { minScore: 1 }],
45-
},
43+
assertions: process.env.LH_PERF
44+
? {
45+
'cumulative-layout-shift': ['error', { maxNumericValue: 0 }],
46+
}
47+
: {
48+
'categories:accessibility': ['error', { minScore: 1 }],
49+
},
4650
},
4751
upload: {
4852
target: 'temporary-public-storage',

CONTRIBUTING.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ This focus helps guide our project decisions as a community and what we choose t
5454
- [Unit tests](#unit-tests)
5555
- [Component accessibility tests](#component-accessibility-tests)
5656
- [Lighthouse accessibility tests](#lighthouse-accessibility-tests)
57+
- [Lighthouse performance tests](#lighthouse-performance-tests)
5758
- [End to end tests](#end-to-end-tests)
5859
- [Test fixtures (mocking external APIs)](#test-fixtures-mocking-external-apis)
5960
- [Submitting changes](#submitting-changes)
@@ -114,6 +115,7 @@ pnpm test:unit # Unit tests only
114115
pnpm test:nuxt # Nuxt component tests
115116
pnpm test:browser # Playwright E2E tests
116117
pnpm test:a11y # Lighthouse accessibility audits
118+
pnpm test:perf # Lighthouse performance audits (CLS)
117119
```
118120

119121
### Project structure
@@ -641,18 +643,38 @@ pnpm test:a11y:prebuilt
641643

642644
# Or run a single color mode manually
643645
pnpm build:test
644-
LIGHTHOUSE_COLOR_MODE=dark ./scripts/lighthouse-a11y.sh
646+
LIGHTHOUSE_COLOR_MODE=dark ./scripts/lighthouse.sh
645647
```
646648

647649
This requires Chrome or Chromium to be installed. The script will auto-detect common installation paths. Results are printed to the terminal and saved in `.lighthouseci/`.
648650

649651
#### Configuration
650652

651-
| File | Purpose |
652-
| ---------------------------- | --------------------------------------------------------- |
653-
| `.lighthouserc.cjs` | Lighthouse CI config (URLs, assertions, Chrome path) |
654-
| `lighthouse-setup.cjs` | Puppeteer script for color mode + client-side API mocking |
655-
| `scripts/lighthouse-a11y.sh` | Shell wrapper that runs the audit for a given color mode |
653+
| File | Purpose |
654+
| ----------------------- | --------------------------------------------------------- |
655+
| `.lighthouserc.cjs` | Lighthouse CI config (URLs, assertions, Chrome path) |
656+
| `lighthouse-setup.cjs` | Puppeteer script for color mode + client-side API mocking |
657+
| `scripts/lighthouse.sh` | Shell wrapper that runs the audit for a given color mode |
658+
659+
### Lighthouse performance tests
660+
661+
The project also runs Lighthouse performance audits to enforce zero Cumulative Layout Shift (CLS). These run separately from the accessibility audits and test the same set of URLs.
662+
663+
#### How it works
664+
665+
The same `.lighthouserc.cjs` config is shared between accessibility and performance audits. When the `LH_PERF` environment variable is set, the config switches from the `accessibility` category to the `performance` category and asserts that CLS is exactly 0.
666+
667+
#### Running locally
668+
669+
```bash
670+
# Build + run performance audit
671+
pnpm test:perf
672+
673+
# Or against an existing test build
674+
pnpm test:perf:prebuilt
675+
```
676+
677+
Unlike the accessibility audits, performance audits do not run in separate light/dark modes.
656678

657679
### End to end tests
658680

@@ -767,8 +789,10 @@ Format: `type(scope): description`
767789
- `fix(i18n): update French translations`
768790
- `chore(deps): update vite to v6`
769791

792+
Where front end changes are made, please include before and after screenshots in your pull request description.
793+
770794
> [!NOTE]
771-
> The subject must start with a lowercase letter. Individual commit messages within your PR don't need to follow this format since they'll be squashed.
795+
> Use lowercase letters in your pull request title. Individual commit messages within your PR don't need to follow this format since they'll be squashed.
772796
773797
### PR descriptions
774798

app/components/AppFooter.vue

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,9 @@ const showModal = () => modalRef.value?.showModal?.()
2323
<LinkBase :to="{ name: 'privacy' }">
2424
{{ $t('privacy_policy.title') }}
2525
</LinkBase>
26-
<LinkBase to="https://docs.npmx.dev">
27-
{{ $t('footer.docs') }}
28-
</LinkBase>
29-
<LinkBase to="https://repo.npmx.dev">
30-
{{ $t('footer.source') }}
31-
</LinkBase>
32-
<LinkBase to="https://social.npmx.dev">
33-
{{ $t('footer.social') }}
34-
</LinkBase>
35-
<LinkBase to="https://chat.npmx.dev">
36-
{{ $t('footer.chat') }}
37-
</LinkBase>
38-
3926
<button
4027
type="button"
41-
class="group inline-flex gap-x-1 items-center justify-center underline-offset-[0.2rem] underline decoration-1 decoration-fg/30 font-mono text-fg hover:(decoration-accent text-accent) focus-visible:(decoration-accent text-accent) transition-colors duration-200"
28+
class="cursor-pointer group inline-flex gap-x-1 items-center justify-center underline-offset-[0.2rem] underline decoration-1 decoration-fg/30 font-mono text-fg hover:(decoration-accent text-accent) focus-visible:(decoration-accent text-accent) transition-colors duration-200"
4229
@click.prevent="showModal"
4330
aria-haspopup="dialog"
4431
>
@@ -102,6 +89,18 @@ const showModal = () => modalRef.value?.showModal?.()
10289
</li>
10390
</ul>
10491
</Modal>
92+
<LinkBase to="https://docs.npmx.dev">
93+
{{ $t('footer.docs') }}
94+
</LinkBase>
95+
<LinkBase to="https://repo.npmx.dev">
96+
{{ $t('footer.source') }}
97+
</LinkBase>
98+
<LinkBase to="https://social.npmx.dev">
99+
{{ $t('footer.social') }}
100+
</LinkBase>
101+
<LinkBase to="https://chat.npmx.dev">
102+
{{ $t('footer.chat') }}
103+
</LinkBase>
105104
</div>
106105
</div>
107106
<BuildEnvironment v-if="!isHome" footer />

app/components/BuildEnvironment.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ const { footer = false, buildInfo: buildInfoProp } = defineProps<{
66
buildInfo?: BuildInfo
77
}>()
88
9-
const { locale } = useI18n()
109
const appConfig = useAppConfig()
1110
const buildInfo = computed(() => buildInfoProp || appConfig.buildInfo)
11+
const buildTime = computed(() => new Date(buildInfo.value.time))
1212
</script>
1313

1414
<template>
@@ -18,7 +18,7 @@ const buildInfo = computed(() => buildInfoProp || appConfig.buildInfo)
1818
style="animation-delay: 0.05s"
1919
>
2020
<i18n-t keypath="built_at" scope="global">
21-
<NuxtTime :datetime="buildInfo.time" :locale="locale" relative />
21+
<DateTime :datetime="buildTime" year="numeric" month="short" day="numeric" />
2222
</i18n-t>
2323
<span>&middot;</span>
2424
<LinkBase

app/components/Code/Viewer.vue

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,32 @@ watch(
5757
},
5858
{ immediate: true },
5959
)
60+
61+
// Use Nuxt's `navigateTo` for the rendered import links
62+
function handleImportLinkNavigate() {
63+
if (!codeRef.value) return
64+
65+
const anchors = codeRef.value.querySelectorAll<HTMLAnchorElement>('a.import-link')
66+
anchors.forEach(anchor => {
67+
// NOTE: We do not need to remove previous listeners because we re-create the entire HTML content on each html update
68+
anchor.addEventListener('click', event => {
69+
if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) return
70+
const href = anchor.getAttribute('href')
71+
if (href) {
72+
event.preventDefault()
73+
navigateTo(href)
74+
}
75+
})
76+
})
77+
}
78+
79+
watch(
80+
() => props.html,
81+
() => {
82+
nextTick(handleImportLinkNavigate)
83+
},
84+
{ immediate: true },
85+
)
6086
</script>
6187

6288
<template>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import DownloadAnalytics from '../Package/DownloadAnalytics.vue'
2+
import TrendsChart from '../Package/TrendsChart.vue'
33
44
const { packages } = defineProps<{
55
packages: string[]
@@ -8,6 +8,6 @@ const { packages } = defineProps<{
88

99
<template>
1010
<div class="font-mono">
11-
<DownloadAnalytics :package-names="packages" :in-modal="false" />
11+
<TrendsChart :package-names="packages" :in-modal="false" show-facet-selector />
1212
</div>
1313
</template>

app/components/Compare/PackageSelector.vue

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,22 @@ function handleKeydown(e: KeyboardEvent) {
8989
} else if (hasMatchInPackages) {
9090
addPackage(inputValueTrim)
9191
}
92+
} else if (e.key === 'Escape') {
93+
inputValue.value = ''
9294
}
9395
}
9496
97+
const { start, stop } = useTimeoutFn(() => {
98+
isInputFocused.value = false
99+
}, 200)
100+
95101
function handleBlur() {
96-
useTimeoutFn(() => {
97-
isInputFocused.value = false
98-
}, 200)
102+
start()
103+
}
104+
105+
function handleFocus() {
106+
stop()
107+
isInputFocused.value = true
99108
}
100109
</script>
101110

@@ -151,7 +160,7 @@ function handleBlur() {
151160
size="medium"
152161
class="w-full min-w-25 ps-7"
153162
aria-autocomplete="list"
154-
@focus="isInputFocused = true"
163+
@focus="handleFocus"
155164
@blur="handleBlur"
156165
@keydown="handleKeydown"
157166
/>
@@ -178,13 +187,13 @@ function handleBlur() {
178187
:aria-label="$t('compare.no_dependency.add_column')"
179188
@click="addPackage(NO_DEPENDENCY_ID)"
180189
>
181-
<div class="text-sm text-accent italic flex items-center gap-2">
190+
<span class="text-sm text-accent italic flex items-center gap-2">
182191
<span class="i-carbon:clean w-4 h-4" aria-hidden="true" />
183192
{{ $t('compare.no_dependency.typeahead_title') }}
184-
</div>
185-
<div class="text-xs text-fg-muted truncate mt-0.5">
193+
</span>
194+
<span class="text-xs text-fg-muted truncate mt-0.5">
186195
{{ $t('compare.no_dependency.typeahead_description') }}
187-
</div>
196+
</span>
188197
</ButtonBase>
189198

190199
<div v-if="isSearching" class="px-4 py-3 text-sm text-fg-muted">
@@ -196,10 +205,13 @@ function handleBlur() {
196205
class="block w-full text-start"
197206
@click="addPackage(result.name)"
198207
>
199-
<div class="font-mono text-sm text-fg">{{ result.name }}</div>
200-
<div v-if="result.description" class="text-xs text-fg-muted truncate mt-0.5">
208+
<span class="font-mono text-sm text-fg block">{{ result.name }}</span>
209+
<span
210+
v-if="result.description"
211+
class="text-xs text-fg-muted truncate mt-0.5 w-full block"
212+
>
201213
{{ result.description }}
202-
</div>
214+
</span>
203215
</ButtonBase>
204216
</div>
205217
</Transition>

app/components/Compare/ReplacementSuggestion.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const docUrl = computed(() => {
2525
class="flex items-start gap-2 px-3 py-2 rounded-lg text-sm"
2626
:class="
2727
variant === 'nodep'
28-
? 'bg-amber-500/10 border border-amber-600/30 text-amber-700 dark:text-amber-400'
28+
? 'bg-amber-500/10 border border-amber-600/30 text-amber-800 dark:text-amber-400'
2929
: 'bg-blue-500/10 border border-blue-600/30 text-blue-700 dark:text-blue-400'
3030
"
3131
>

0 commit comments

Comments
 (0)