feat(a11y): add access keys shortcuts

This commit is contained in:
userquin 2024-04-06 00:26:22 +02:00
parent 25fb7c1c97
commit ec741923f7
19 changed files with 47 additions and 14 deletions

View file

@ -6,6 +6,8 @@ defineProps<{
back?: boolean
/** Do not applying overflow hidden to let use floatable components in title */
noOverflowHidden?: boolean
/** Show the skip content link */
skipContent?: string
}>()
const container = ref()
@ -26,6 +28,9 @@ const containerClass = computed(() => {
<template>
<div ref="container" :class="containerClass">
<SkipContentLink v-if="skipContent">
{{ $t(skipContent) }}
</SkipContentLink>
<div
sticky top-0 z10
pt="[env(safe-area-inset-top,0)]"

View file

@ -0,0 +1,14 @@
// @unocss-include
import { accessKeys } from '~/constants/access-keys'
export default defineComponent({
setup() {
const { t } = useI18n()
return () => h('a', {
id: 'skip',
class: 'sr-only',
href: '#skip-content',
accesskey: accessKeys.SkipContent,
}, t(`a11y.skip_navigation`))
},
})

View file

@ -0,0 +1,5 @@
<template>
<NuxtLink id="skip-content" sr-only>
<slot />
</NuxtLink>
</template>

6
constants/access-keys.ts Normal file
View file

@ -0,0 +1,6 @@
export const accessKeys = {
Home: 'S',
SkipContent: '1',
Search: '2',
Shortcuts: '3',
} as const

View file

@ -16,6 +16,7 @@ const isGrayscale = usePreferences('grayscaleMode')
<template>
<div h-full :data-mode="isHydrated && isGrayscale ? 'grayscale' : ''" data-tauri-drag-region>
<SkipContent />
<main flex w-full mxa lg:max-w-80rem class="native:grid native:sm:grid-cols-[auto_1fr] native:lg:grid-cols-[auto_minmax(600px,2fr)_1fr]">
<aside class="native:w-auto w-1/8 md:w-1/6 lg:w-1/5 xl:w-1/4 zen-hide" hidden sm:flex justify-end xl:me-4 native:me-0 relative>
<div sticky top-0 w-20 xl:w-100 h-100dvh flex="~ col" lt-xl-items-center>

View file

@ -4,7 +4,8 @@
"loading_titled_page": "Loading {0} page, please wait",
"locale_changed": "Language changed to {0}",
"locale_changing": "Changing language, please wait",
"route_loaded": "Page {0} loaded"
"route_loaded": "Page {0} loaded",
"skip_navigation": "Skip navigation"
},
"account": {
"authorize": "Authorize to follow",

View file

@ -4,7 +4,8 @@
"loading_titled_page": "Cargando página {0}, espera por favor",
"locale_changed": "Idioma cambiado a {0}",
"locale_changing": "Cambiando idioma, espera por favor",
"route_loaded": "Página {0} cargada"
"route_loaded": "Página {0} cargada",
"skip_navigation": "Saltar navegación"
},
"account": {
"authorize": "Autorizar seguimiento",

View file

@ -18,7 +18,7 @@ const isRootPath = computed(() => route.name === 'settings')
<div>
<div min-h-screen flex>
<div border="e base" :class="isRootPath ? 'block lg:flex-none flex-1' : 'hidden lg:block'">
<MainContent>
<MainContent :skip-content="isRootPath ? 'nav.settings' : undefined">
<template #title>
<div timeline-title-style flex items-center gap-2 @click="$scrollToTop">
<div i-ri:settings-3-line />

View file

@ -17,7 +17,7 @@ function handleShowCommit() {
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.about.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.about.label') }}</span>

View file

@ -7,7 +7,7 @@ useHydratedHead({
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.interface.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.interface.label') }}</span>

View file

@ -15,7 +15,7 @@ const status = computed(() => {
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.language.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.language.label') }}</span>

View file

@ -12,7 +12,7 @@ useHydratedHead({
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.notifications.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.notifications.label') }}</span>

View file

@ -11,7 +11,7 @@ useHydratedHead({
</script>
<template>
<MainContent back>
<MainContent back skip-content="settings.notifications.notifications.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<div i-ri:test-tube-line />

View file

@ -14,7 +14,7 @@ useHydratedHead({
</script>
<template>
<MainContent back>
<MainContent back skip-content="settings.notifications.push_notifications.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.notifications.push_notifications.label') }}</span>

View file

@ -9,7 +9,7 @@ const userSettings = useUserSettings()
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.preferences.label">
<template #title>
<h1 text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
{{ $t('settings.preferences.label') }}

View file

@ -103,7 +103,7 @@ onReactivated(refreshInfo)
</script>
<template>
<MainContent back>
<MainContent back skip-content="settings.profile.appearance.title">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.profile.appearance.title') }}</span>

View file

@ -11,7 +11,7 @@ useHydratedHead({
</script>
<template>
<MainContent back>
<MainContent back skip-content="settings.profile.featured_tags.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<div i-ri:test-tube-line />

View file

@ -11,7 +11,7 @@ useHydratedHead({
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.profile.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.profile.label') }}</span>

View file

@ -66,7 +66,7 @@ async function importTokens() {
</script>
<template>
<MainContent back-on-small-screen>
<MainContent back-on-small-screen skip-content="settings.users.label">
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.users.label') }}</span>