File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -47,10 +47,12 @@ if (import.meta.server) {
4747 setJsonLd (createWebSiteSchema ())
4848}
4949
50+ const keyboardShortcuts = useKeyboardShortcuts ()
51+
5052onKeyDown (
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(
7072onKeyDown (
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(
8082onKeyUp (
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 },
Original file line number Diff line number Diff line change @@ -6,6 +6,7 @@ const isHome = computed(() => route.name === 'index')
66
77const modalRef = useTemplateRef (' modalRef' )
88const 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_description" 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') }}
Original file line number Diff line number Diff line change 11<script setup lang="ts">
2+ import { ClientOnly } from ' #components'
23import type { IconClass } from ' ~/types'
34
45const props = withDefaults (
@@ -21,6 +22,8 @@ const props = withDefaults(
2122
2223const el = useTemplateRef (' el' )
2324
25+ const keyboardShortcutsEnabled = computed (() => import .meta .client && useKeyboardShortcuts ().value )
26+
2427defineExpose ({
2528 focus : () => el .value ?.focus (),
2629 getBoundingClientRect : () => el .value ?.getBoundingClientRect (),
@@ -51,16 +54,18 @@ defineExpose({
5154 */
5255 disabled ? true : undefined
5356 "
54- :aria-keyshortcuts =" ariaKeyshortcuts"
57+ :aria-keyshortcuts =" keyboardShortcutsEnabled ? ariaKeyshortcuts : undefined "
5558 >
5659 <span v-if =" classicon" class =" size-[1em]" :class =" classicon" aria-hidden =" true" />
5760 <slot />
58- <kbd
59- v-if =" ariaKeyshortcuts"
60- 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"
61- aria-hidden =" true"
62- >
63- {{ ariaKeyshortcuts }}
64- </kbd >
61+ <ClientOnly >
62+ <kbd
63+ v-if =" keyboardShortcutsEnabled && ariaKeyshortcuts"
64+ 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"
65+ aria-hidden =" true"
66+ >
67+ {{ ariaKeyshortcuts }}
68+ </kbd >
69+ </ClientOnly >
6570 </button >
6671</template >
Original file line number Diff line number Diff line change @@ -98,6 +98,8 @@ function removePackage(name: string) {
9898}
9999
100100function handleKeydown(e : KeyboardEvent ) {
101+ if (! useKeyboardShortcuts ().value ) return
102+
101103 const items = navigableItems .value
102104 const count = items .length
103105
Original file line number Diff line number Diff line change @@ -59,6 +59,7 @@ const isLink = computed(() => props.variant === 'link')
5959const isButton = computed (() => ! isLink .value )
6060const isButtonSmall = computed (() => props .size === ' small' && ! isLink .value )
6161const isButtonMedium = computed (() => props .size === ' medium' && ! isLink .value )
62+ const keyboardShortcutsEnabled = computed (() => import .meta .client && useKeyboardShortcuts ().value )
6263 </script >
6364
6465<template >
@@ -97,7 +98,7 @@ const isButtonMedium = computed(() => props.size === 'medium' && !isLink.value)
9798 variant === 'button-primary',
9899 }"
99100 :to =" to"
100- :aria-keyshortcuts =" ariaKeyshortcuts"
101+ :aria-keyshortcuts =" keyboardShortcutsEnabled ? ariaKeyshortcuts : undefined "
101102 :target =" isLinkExternal ? '_blank' : undefined"
102103 >
103104 <span v-if =" classicon" class =" size-[1em]" :class =" classicon" aria-hidden =" true" />
@@ -113,12 +114,14 @@ const isButtonMedium = computed(() => props.size === 'medium' && !isLink.value)
113114 class =" i-lucide:link size-[1em] opacity-0 group-hover/link:opacity-100 transition-opacity duration-200"
114115 aria-hidden =" true"
115116 />
116- <kbd
117- v-if =" ariaKeyshortcuts"
118- class =" ms-2 inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
119- aria-hidden =" true"
120- >
121- {{ ariaKeyshortcuts }}
122- </kbd >
117+ <ClientOnly >
118+ <kbd
119+ v-if =" keyboardShortcutsEnabled && ariaKeyshortcuts"
120+ class =" ms-2 inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
121+ aria-hidden =" true"
122+ >
123+ {{ ariaKeyshortcuts }}
124+ </kbd >
125+ </ClientOnly >
123126 </NuxtLink >
124127</template >
Original file line number Diff line number Diff line change @@ -29,6 +29,8 @@ export interface AppSettings {
2929 selectedLocale : LocaleObject [ 'code' ] | null
3030 /** Search provider for package search */
3131 searchProvider : SearchProvider
32+ /** Enable/disable keyboard shortcuts */
33+ keyboardShortcuts : boolean
3234 /** Connector preferences */
3335 connector : {
3436 /** Automatically open the web auth page in the browser */
@@ -48,6 +50,7 @@ const DEFAULT_SETTINGS: AppSettings = {
4850 selectedLocale : null ,
4951 preferredBackgroundTheme : null ,
5052 searchProvider : import . meta. test ? 'npm' : 'algolia' ,
53+ keyboardShortcuts : true ,
5154 connector : {
5255 autoOpenURL : false ,
5356 } ,
@@ -87,6 +90,15 @@ export function useRelativeDates() {
8790 return computed ( ( ) => settings . value . relativeDates )
8891}
8992
93+ /**
94+ * Composable for accessing just the keyboard shortcuts setting.
95+ * Useful for components that only need to read this specific setting.
96+ */
97+ export function useKeyboardShortcuts ( ) {
98+ const { settings } = useSettings ( )
99+ return computed ( ( ) => settings . value . keyboardShortcuts )
100+ }
101+
90102/**
91103 * Composable for managing accent color.
92104 */
Original file line number Diff line number Diff line change @@ -683,8 +683,10 @@ const codeLink = computed((): RouteLocationRaw | null => {
683683 }
684684})
685685
686+ const keyboardShortcuts = useKeyboardShortcuts ()
687+
686688onKeyStroke (
687- e => isKeyWithoutModifiers (e , ' .' ) && ! isEditableElement (e .target ),
689+ e => keyboardShortcuts . value && isKeyWithoutModifiers (e , ' .' ) && ! isEditableElement (e .target ),
688690 e => {
689691 if (codeLink .value === null ) return
690692 e .preventDefault ()
@@ -695,7 +697,7 @@ onKeyStroke(
695697)
696698
697699onKeyStroke (
698- e => isKeyWithoutModifiers (e , ' d' ) && ! isEditableElement (e .target ),
700+ e => keyboardShortcuts . value && isKeyWithoutModifiers (e , ' d' ) && ! isEditableElement (e .target ),
699701 e => {
700702 if (! docsLink .value ) return
701703 e .preventDefault ()
@@ -705,7 +707,7 @@ onKeyStroke(
705707)
706708
707709onKeyStroke (
708- e => isKeyWithoutModifiers (e , ' c' ) && ! isEditableElement (e .target ),
710+ e => keyboardShortcuts . value && isKeyWithoutModifiers (e , ' c' ) && ! isEditableElement (e .target ),
709711 e => {
710712 if (! pkg .value ) return
711713 e .preventDefault ()
Original file line number Diff line number Diff line change @@ -205,6 +205,7 @@ const setLocale: typeof setNuxti18nLocale = locale => {
205205 </div >
206206 </section >
207207
208+ <!-- LANGUAGE Section -->
208209 <section >
209210 <h2 class =" text-xs text-fg-muted uppercase tracking-wider mb-4" >
210211 {{ $t('settings.sections.language') }}
@@ -260,6 +261,20 @@ const setLocale: typeof setNuxti18nLocale = locale => {
260261 </template >
261262 </div >
262263 </section >
264+
265+ <!-- KEYBOARD SHORTCUTS Section -->
266+ <section >
267+ <h2 class =" text-xs text-fg-muted uppercase tracking-wider mb-4" >
268+ {{ $t('settings.sections.keyboard_shortcuts') }}
269+ </h2 >
270+ <div class =" bg-bg-subtle border border-border rounded-lg p-4 sm:p-6" >
271+ <SettingsToggle
272+ :label =" $t('settings.keyboard_shortcuts_enabled')"
273+ :description =" $t('settings.keyboard_shortcuts_enabled_description')"
274+ v-model =" settings.keyboardShortcuts"
275+ />
276+ </div >
277+ </section >
263278 </div >
264279 </article >
265280 </main >
Original file line number Diff line number Diff line change 3333 "navigate_results" : " Navigate results" ,
3434 "go_to_result" : " Go to result" ,
3535 "open_code_view" : " Open code view" ,
36- "open_docs" : " Open docs"
36+ "open_docs" : " Open docs" ,
37+ "disable_shortcuts" : " Disable shortcuts" ,
38+ "disable_shortcuts_description" : " You could disable keyboard shortcuts in {settings}."
3739 },
3840 "search" : {
3941 "label" : " Search npm packages" ,
8486 "appearance" : " Appearance" ,
8587 "display" : " Display" ,
8688 "search" : " Data source" ,
87- "language" : " Language"
89+ "language" : " Language" ,
90+ "keyboard_shortcuts" : " Keyboard shortcuts"
8891 },
8992 "data_source" : {
9093 "label" : " Data source" ,
108111 "accent_colors" : " Accent colors" ,
109112 "clear_accent" : " Clear accent color" ,
110113 "translation_progress" : " Translation progress" ,
111- "background_themes" : " Background shade"
114+ "background_themes" : " Background shade" ,
115+ "keyboard_shortcuts_enabled" : " Enable keyboard shortcuts" ,
116+ "keyboard_shortcuts_enabled_description" : " Keyboard shortcuts can be disabled if they conflict with other browser or system shortcuts"
112117 },
113118 "i18n" : {
114119 "missing_keys" : " {count} missing translation | {count} missing translations" ,
Original file line number Diff line number Diff line change 105105 },
106106 "open_docs" : {
107107 "type" : " string"
108+ },
109+ "disable_shortcuts" : {
110+ "type" : " string"
111+ },
112+ "disable_shortcuts_description" : {
113+ "type" : " string"
108114 }
109115 },
110116 "additionalProperties" : false
258264 },
259265 "language" : {
260266 "type" : " string"
267+ },
268+ "keyboard_shortcuts" : {
269+ "type" : " string"
261270 }
262271 },
263272 "additionalProperties" : false
330339 },
331340 "background_themes" : {
332341 "type" : " string"
342+ },
343+ "keyboard_shortcuts_enabled" : {
344+ "type" : " string"
345+ },
346+ "keyboard_shortcuts_enabled_description" : {
347+ "type" : " string"
333348 }
334349 },
335350 "additionalProperties" : false
You can’t perform that action at this time.
0 commit comments