From ec741923f7653dcbff5a423f0b1130d2e7c9d323 Mon Sep 17 00:00:00 2001 From: userquin <userquin@gmail.com> Date: Sat, 6 Apr 2024 00:26:22 +0200 Subject: [PATCH 1/3] feat(a11y): add access keys shortcuts --- components/main/MainContent.vue | 5 +++++ components/skip/SkipContent.ts | 14 ++++++++++++++ components/skip/SkipContentLink.vue | 5 +++++ constants/access-keys.ts | 6 ++++++ layouts/default.vue | 1 + locales/en.json | 3 ++- locales/es.json | 3 ++- pages/settings.vue | 2 +- pages/settings/about/index.vue | 2 +- pages/settings/interface/index.vue | 2 +- pages/settings/language/index.vue | 2 +- pages/settings/notifications/index.vue | 2 +- pages/settings/notifications/notifications.vue | 2 +- .../settings/notifications/push-notifications.vue | 2 +- pages/settings/preferences/index.vue | 2 +- pages/settings/profile/appearance.vue | 2 +- pages/settings/profile/featured-tags.vue | 2 +- pages/settings/profile/index.vue | 2 +- pages/settings/users/index.vue | 2 +- 19 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 components/skip/SkipContent.ts create mode 100644 components/skip/SkipContentLink.vue create mode 100644 constants/access-keys.ts diff --git a/components/main/MainContent.vue b/components/main/MainContent.vue index 312b5e5288..8a55a1657d 100644 --- a/components/main/MainContent.vue +++ b/components/main/MainContent.vue @@ -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)]" diff --git a/components/skip/SkipContent.ts b/components/skip/SkipContent.ts new file mode 100644 index 0000000000..872a4b016a --- /dev/null +++ b/components/skip/SkipContent.ts @@ -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`)) + }, +}) diff --git a/components/skip/SkipContentLink.vue b/components/skip/SkipContentLink.vue new file mode 100644 index 0000000000..c3b92201c6 --- /dev/null +++ b/components/skip/SkipContentLink.vue @@ -0,0 +1,5 @@ +<template> + <NuxtLink id="skip-content" sr-only> + <slot /> + </NuxtLink> +</template> diff --git a/constants/access-keys.ts b/constants/access-keys.ts new file mode 100644 index 0000000000..82b8aa3e08 --- /dev/null +++ b/constants/access-keys.ts @@ -0,0 +1,6 @@ +export const accessKeys = { + Home: 'S', + SkipContent: '1', + Search: '2', + Shortcuts: '3', +} as const diff --git a/layouts/default.vue b/layouts/default.vue index ecf6c106fd..5634302f5b 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -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> diff --git a/locales/en.json b/locales/en.json index 645eab0cc1..d8990ab1e6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -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", diff --git a/locales/es.json b/locales/es.json index c5d5bf6a7c..6323fb8958 100644 --- a/locales/es.json +++ b/locales/es.json @@ -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", diff --git a/pages/settings.vue b/pages/settings.vue index 1f53497fd8..cd5464c800 100644 --- a/pages/settings.vue +++ b/pages/settings.vue @@ -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 /> diff --git a/pages/settings/about/index.vue b/pages/settings/about/index.vue index d025514a8a..08f1245df3 100644 --- a/pages/settings/about/index.vue +++ b/pages/settings/about/index.vue @@ -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> diff --git a/pages/settings/interface/index.vue b/pages/settings/interface/index.vue index 94ef7e97a9..2639fd4cde 100644 --- a/pages/settings/interface/index.vue +++ b/pages/settings/interface/index.vue @@ -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> diff --git a/pages/settings/language/index.vue b/pages/settings/language/index.vue index 9359af7104..ae465b3f48 100644 --- a/pages/settings/language/index.vue +++ b/pages/settings/language/index.vue @@ -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> diff --git a/pages/settings/notifications/index.vue b/pages/settings/notifications/index.vue index 467dae7f84..48490e4b99 100644 --- a/pages/settings/notifications/index.vue +++ b/pages/settings/notifications/index.vue @@ -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> diff --git a/pages/settings/notifications/notifications.vue b/pages/settings/notifications/notifications.vue index 0cb65cda0c..12124de833 100644 --- a/pages/settings/notifications/notifications.vue +++ b/pages/settings/notifications/notifications.vue @@ -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 /> diff --git a/pages/settings/notifications/push-notifications.vue b/pages/settings/notifications/push-notifications.vue index af5d93ed1c..cce6ce32ab 100644 --- a/pages/settings/notifications/push-notifications.vue +++ b/pages/settings/notifications/push-notifications.vue @@ -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> diff --git a/pages/settings/preferences/index.vue b/pages/settings/preferences/index.vue index b0d6d235bf..09e8737cc8 100644 --- a/pages/settings/preferences/index.vue +++ b/pages/settings/preferences/index.vue @@ -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') }} diff --git a/pages/settings/profile/appearance.vue b/pages/settings/profile/appearance.vue index 54d409543d..54bd1ac613 100644 --- a/pages/settings/profile/appearance.vue +++ b/pages/settings/profile/appearance.vue @@ -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> diff --git a/pages/settings/profile/featured-tags.vue b/pages/settings/profile/featured-tags.vue index 491bf8b74a..0ca91a5246 100644 --- a/pages/settings/profile/featured-tags.vue +++ b/pages/settings/profile/featured-tags.vue @@ -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 /> diff --git a/pages/settings/profile/index.vue b/pages/settings/profile/index.vue index 5b40258c45..4f2f509635 100644 --- a/pages/settings/profile/index.vue +++ b/pages/settings/profile/index.vue @@ -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> diff --git a/pages/settings/users/index.vue b/pages/settings/users/index.vue index b44e978191..5f4f0a099a 100644 --- a/pages/settings/users/index.vue +++ b/pages/settings/users/index.vue @@ -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> From 0b12a6733977d3b76a1adab6e82ca3062f096185 Mon Sep 17 00:00:00 2001 From: userquin <userquin@gmail.com> Date: Sat, 6 Apr 2024 00:52:02 +0200 Subject: [PATCH 2/3] chore: update skip components --- components/main/MainContent.vue | 2 +- components/skip/SkipContent.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/main/MainContent.vue b/components/main/MainContent.vue index 8a55a1657d..370b900233 100644 --- a/components/main/MainContent.vue +++ b/components/main/MainContent.vue @@ -6,7 +6,7 @@ defineProps<{ back?: boolean /** Do not applying overflow hidden to let use floatable components in title */ noOverflowHidden?: boolean - /** Show the skip content link */ + /** Add the skip content link: it is the translation key */ skipContent?: string }>() diff --git a/components/skip/SkipContent.ts b/components/skip/SkipContent.ts index 872a4b016a..be411ac76f 100644 --- a/components/skip/SkipContent.ts +++ b/components/skip/SkipContent.ts @@ -5,7 +5,7 @@ export default defineComponent({ setup() { const { t } = useI18n() return () => h('a', { - id: 'skip', + id: 'skip-navigation', class: 'sr-only', href: '#skip-content', accesskey: accessKeys.SkipContent, From c0915afdb7cfd4d506c407543e9f9db89703f586 Mon Sep 17 00:00:00 2001 From: userquin <userquin@gmail.com> Date: Sat, 6 Apr 2024 01:43:13 +0200 Subject: [PATCH 3/3] chore: add main pages --- pages/blocks.vue | 2 +- pages/bookmarks.vue | 2 +- pages/conversations.vue | 2 +- pages/domain_blocks.vue | 2 +- pages/favourites.vue | 2 +- pages/hashtags.vue | 2 +- pages/home.vue | 2 +- pages/mutes.vue | 2 +- pages/notifications.vue | 6 +++++- pages/pinned.vue | 2 +- 10 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pages/blocks.vue b/pages/blocks.vue index df78355d4b..4d898a9cef 100644 --- a/pages/blocks.vue +++ b/pages/blocks.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent back> + <MainContent back skip-content="nav.blocked_users"> <template #title> <span timeline-title-style>{{ $t('nav.blocked_users') }}</span> </template> diff --git a/pages/bookmarks.vue b/pages/bookmarks.vue index efebad8c9a..9bbc87d927 100644 --- a/pages/bookmarks.vue +++ b/pages/bookmarks.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="nav.bookmarks"> <template #title> <NuxtLink to="/bookmarks" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:bookmark-line /> diff --git a/pages/conversations.vue b/pages/conversations.vue index f0ab6d4099..4e68c6a359 100644 --- a/pages/conversations.vue +++ b/pages/conversations.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="nav.conversations"> <template #title> <NuxtLink to="/conversations" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:at-line /> diff --git a/pages/domain_blocks.vue b/pages/domain_blocks.vue index 5f981c3e67..56f61060bf 100644 --- a/pages/domain_blocks.vue +++ b/pages/domain_blocks.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent back> + <MainContent back skip-content="nav.blocked_domains"> <template #title> <span timeline-title-style>{{ $t('nav.blocked_domains') }}</span> </template> diff --git a/pages/favourites.vue b/pages/favourites.vue index 9882be355a..f8c1609657 100644 --- a/pages/favourites.vue +++ b/pages/favourites.vue @@ -12,7 +12,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="nav.favourites"> <template #title> <NuxtLink to="/favourites" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div :class="useStarFavoriteIcon ? 'i-ri:star-line' : 'i-ri:heart-3-line'" /> diff --git a/pages/hashtags.vue b/pages/hashtags.vue index e7569e64d1..5cc2bc458a 100644 --- a/pages/hashtags.vue +++ b/pages/hashtags.vue @@ -16,7 +16,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="nav.hashtags"> <template #title> <NuxtLink to="/hashtags" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div class="i-ri:hashtag" /> diff --git a/pages/home.vue b/pages/home.vue index 27383c2d61..30023eb534 100644 --- a/pages/home.vue +++ b/pages/home.vue @@ -16,7 +16,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="nav.home"> <template #title> <NuxtLink to="/home" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:home-5-line /> diff --git a/pages/mutes.vue b/pages/mutes.vue index a9b5d24249..54e0f41a22 100644 --- a/pages/mutes.vue +++ b/pages/mutes.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent back> + <MainContent back skip-content="nav.muted_users"> <template #title> <span timeline-title-style>{{ $t('nav.muted_users') }}</span> </template> diff --git a/pages/notifications.vue b/pages/notifications.vue index bb3fec610e..175fdd310b 100644 --- a/pages/notifications.vue +++ b/pages/notifications.vue @@ -65,10 +65,14 @@ const moreOptions = computed<CommonRouteTabMoreOption>(() => ({ tooltip: filterText.value, match: !!filter.value, })) +const skipContent = computed(() => { + const name = route.params.filter + return name ? `tab.notifications_${name}` : 'tab.notifications_all' +}) </script> <template> - <MainContent> + <MainContent :skip-content="skipContent"> <template #title> <NuxtLink to="/notifications" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:notification-4-line /> diff --git a/pages/pinned.vue b/pages/pinned.vue index 5ea9c7c4db..0c79febced 100644 --- a/pages/pinned.vue +++ b/pages/pinned.vue @@ -11,7 +11,7 @@ useHydratedHead({ </script> <template> - <MainContent> + <MainContent skip-content="account.pinned"> <template #title> <NuxtLink to="/public/pinned" timeline-title-style flex items-center gap-2 @click="$scrollToTop"> <div i-ri:pushpin-line />