Skip to content

Commit 24a56be

Browse files
committed
Merge branch 'main' into Gianthard-cyh/main
2 parents acc860e + 5e93353 commit 24a56be

96 files changed

Lines changed: 2999 additions & 1514 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.

CONTRIBUTING.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,10 @@ describe('featureName', () => {
409409
410410
### Component accessibility tests
411411

412-
All new components should have a basic accessibility test in `test/nuxt/components.spec.ts`. These tests use [axe-core](https://github.com/dequelabs/axe-core) to catch common accessibility violations.
412+
All Vue components should have accessibility tests in `test/nuxt/a11y.spec.ts`. These tests use [axe-core](https://github.com/dequelabs/axe-core) to catch common accessibility violations and run in a real browser environment via Playwright.
413413

414414
```typescript
415-
import MyComponent from '~/components/MyComponent.vue'
415+
import { MyComponent } from '#components'
416416

417417
describe('MyComponent', () => {
418418
it('should have no accessibility violations', async () => {
@@ -429,6 +429,8 @@ describe('MyComponent', () => {
429429

430430
The `runAxe` helper handles DOM isolation and disables page-level rules that don't apply to isolated component testing.
431431

432+
A coverage test in `test/unit/a11y-component-coverage.spec.ts` ensures all components are either tested or explicitly skipped with justification. When you add a new component, this test will fail until you add accessibility tests for it.
433+
432434
> [!IMPORTANT]
433435
> Just because axe-core doesn't find any obvious issues, it does not mean a component is accessible. Please do additional checks and use best practices.
434436

app/app.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function handleGlobalKeydown(e: KeyboardEvent) {
4949
5050
if (isEditableElement(e.target)) return
5151
52-
if (e.key === '/') {
52+
if (isKeyWithoutModifiers(e, '/')) {
5353
e.preventDefault()
5454
5555
// Try to find and focus search input on current page
@@ -65,7 +65,7 @@ function handleGlobalKeydown(e: KeyboardEvent) {
6565
router.push('/search')
6666
}
6767
68-
if (e.key === '?') {
68+
if (isKeyWithoutModifiers(e, '?')) {
6969
e.preventDefault()
7070
showKbdHints.value = true
7171
}
@@ -75,9 +75,20 @@ function handleGlobalKeyup() {
7575
showKbdHints.value = false
7676
}
7777
78+
/* A hack to get light dismiss to work in safari because it does not support closedby="any" yet */
79+
// https://codepen.io/paramagicdev/pen/gbYompq
80+
// see: https://github.com/npmx-dev/npmx.dev/pull/522#discussion_r2749978022
81+
function handleModalLightDismiss(e: MouseEvent) {
82+
const target = e.target as HTMLElement
83+
if (target.tagName === 'DIALOG' && target.hasAttribute('open')) {
84+
;(target as HTMLDialogElement).close()
85+
}
86+
}
87+
7888
if (import.meta.client) {
7989
useEventListener(document, 'keydown', handleGlobalKeydown)
8090
useEventListener(document, 'keyup', handleGlobalKeyup)
91+
useEventListener(document, 'click', handleModalLightDismiss)
8192
}
8293
</script>
8394

app/assets/main.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,9 @@ input[type='search']::-webkit-search-results-decoration {
233233
animation-duration: 0.3s;
234234
animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
235235
}
236+
237+
/* Locking the scroll whenever any of the modals are open */
238+
html:has(dialog:modal) {
239+
overflow: hidden;
240+
scrollbar-gutter: stable;
241+
}

app/components/AppHeader.vue

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,23 +62,21 @@ function handleSearchFocus() {
6262
}
6363
6464
onKeyStroke(
65-
',',
65+
e => isKeyWithoutModifiers(e, ',') && !isEditableElement(e.target),
6666
e => {
67-
if (isEditableElement(e.target)) return
68-
6967
e.preventDefault()
7068
navigateTo('/settings')
7169
},
7270
{ dedupe: true },
7371
)
7472
7573
onKeyStroke(
76-
'c',
77-
e => {
74+
e =>
75+
isKeyWithoutModifiers(e, 'c') &&
76+
!isEditableElement(e.target) &&
7877
// Allow more specific handlers to take precedence
79-
if (e.defaultPrevented) return
80-
if (isEditableElement(e.target)) return
81-
78+
!e.defaultPrevented,
79+
e => {
8280
e.preventDefault()
8381
navigateTo('/compare')
8482
},
@@ -140,7 +138,7 @@ onKeyStroke(
140138
:class="{ 'hidden sm:flex': !isSearchExpanded }"
141139
>
142140
<!-- Search bar (hidden on mobile unless expanded) -->
143-
<SearchBox
141+
<HeaderSearchBox
144142
ref="searchBoxRef"
145143
:inputClass="isSearchExpanded ? 'w-full' : ''"
146144
:class="{ 'max-w-md': !isSearchExpanded }"
@@ -219,6 +217,6 @@ onKeyStroke(
219217
</nav>
220218

221219
<!-- Mobile menu -->
222-
<MobileMenu v-model:open="showMobileMenu" />
220+
<HeaderMobileMenu v-model:open="showMobileMenu" />
223221
</header>
224222
</template>

app/components/AuthButton.client.vue

Lines changed: 0 additions & 18 deletions
This file was deleted.

app/components/AuthButton.server.vue

Lines changed: 0 additions & 10 deletions
This file was deleted.

app/components/AuthButton.vue

Lines changed: 0 additions & 18 deletions
This file was deleted.

app/components/AuthModal.vue

Lines changed: 0 additions & 198 deletions
This file was deleted.

0 commit comments

Comments
 (0)