add skip link

This commit is contained in:
axolotle 2023-08-06 16:27:24 +02:00
parent 2e90b14d0a
commit ec02765545
7 changed files with 140 additions and 94 deletions

13
components/PageTitle.vue Normal file
View file

@ -0,0 +1,13 @@
<script setup lang="ts">
const props = defineProps<{
text?: string
}>()
</script>
<template>
<h2 id="main-target" tabindex="-1" class="text-4xl font-bold mb-3">
<slot name="default">
{{ text }}
</slot>
</h2>
</template>

View file

@ -2,7 +2,7 @@
const { t } = useI18n() const { t } = useI18n()
const isLoggedIn = useIsLoggedIn() const isLoggedIn = useIsLoggedIn()
const { userData: me } = await useUserInfo() const { userData: me } = await useUserInfo()
const skipLink: Ref<HTMLLinkElement | null> = ref(null)
const colorMode = useColorMode() const colorMode = useColorMode()
const themes = [ const themes = [
'system', 'system',
@ -68,6 +68,16 @@ async function logout() {
<template> <template>
<div class="container mx-auto p-10 min-h-screen flex flex-col"> <div class="container mx-auto p-10 min-h-screen flex flex-col">
<header class="py-10"> <header class="py-10">
<div class="h-10 -mt-10">
<a
id="skip-link"
ref="skipLink"
class="link sr-only focus:not-sr-only"
href="#main-target"
>{{ $t('skip_to_main_content') }}</a
>
</div>
<slot name="header"> <slot name="header">
<div class="flex flex-row flex-wrap items-center min-w-full"> <div class="flex flex-row flex-wrap items-center min-w-full">
<NuxtLink to="/"> <NuxtLink to="/">

View file

@ -1,4 +1,5 @@
{ {
"app_list": "App list",
"back_to_apps": "Go back to app list", "back_to_apps": "Go back to app list",
"portal": "YunoHost Portal", "portal": "YunoHost Portal",
"information": "Your info", "information": "Your info",
@ -50,5 +51,6 @@
"footerlink_edit": "Edit my profile", "footerlink_edit": "Edit my profile",
"footerlink_documentation": "Documentation", "footerlink_documentation": "Documentation",
"footerlink_support": "Support", "footerlink_support": "Support",
"footerlink_administration": "Administration" "footerlink_administration": "Administration",
"skip_to_main_content": "Skip to main content",
} }

View file

@ -0,0 +1,8 @@
export default defineNuxtRouteMiddleware((to) => {
if (!to.hash) {
// Auto select skip link on route change
nextTick(() => {
document.getElementById('skip-link')?.focus()
})
}
})

View file

@ -42,58 +42,65 @@ const onSubmit = handleSubmit(async (form) => {
</script> </script>
<template> <template>
<!-- {{ initialValues }} --> <div>
<form novalidate @submit="onSubmit"> <PageTitle :text="$t('footerlink_edit')" />
<div class="flex justify-between">
<div class="w-1/3">
<FormField name="username" :label="$t('username')" class="mb-3">
<TextInput
name="username"
type="text"
:placeholder="$t('username')"
disabled
class="w-full"
/>
</FormField>
<FormField name="fullname" :label="$t('fullname')"> <form novalidate class="my-10" @submit="onSubmit">
<TextInput <div class="sm:flex sm:justify-between">
name="fullname" <div class="sm:w-1/3">
type="text" <FormField name="username" :label="$t('username')" class="mb-3">
:placeholder="$t('fullname')" <TextInput
autocomplete="name" name="username"
class="w-full" type="text"
/> :placeholder="$t('username')"
</FormField> disabled
</div> class="w-full"
/>
</FormField>
<div class="basis-1/2"> <FormField name="fullname" :label="$t('fullname')">
<FormField name="mailalias" :label="$t('mail_addresses')" class="mb-10"> <TextInput
<TextInputList name="fullname"
type="text"
:placeholder="$t('fullname')"
autocomplete="name"
class="w-full"
/>
</FormField>
</div>
<div class="basis-1/2 mt-10 sm:mt-0">
<FormField
name="mailalias" name="mailalias"
type="text" :label="$t('mail_addresses')"
:placeholder="$t('new_mail')" class="mb-10"
/> >
</FormField> <TextInputList
name="mailalias"
type="text"
:placeholder="$t('new_mail')"
/>
</FormField>
<FormField name="mailforward" :label="$t('mail_forward')"> <FormField name="mailforward" :label="$t('mail_forward')">
<TextInputList <TextInputList
name="mailforward" name="mailforward"
type="text" type="text"
:placeholder="$t('new_forward')" :placeholder="$t('new_forward')"
/> />
</FormField> </FormField>
</div>
</div> </div>
</div>
<div class="flex mt-10"> <div class="flex mt-10">
<NuxtLink to="/password" class="btn btn-primary"> <NuxtLink to="/password" class="btn btn-primary">
{{ $t('change_password') }} {{ $t('change_password') }}
</NuxtLink> </NuxtLink>
<NuxtLink to="/" class="btn ml-auto mr-2"> <NuxtLink to="/" class="btn ml-auto mr-2">
{{ $t('cancel') }} {{ $t('cancel') }}
</NuxtLink> </NuxtLink>
<YButton :text="$t('ok')" type="submit" variant="success" /> <YButton :text="$t('save')" type="submit" variant="success" />
</div> </div>
</form> </form>
</div>
</template> </template>

View file

@ -25,7 +25,7 @@ const me = computed(() => {
// ['bg-purple-500', 'text-purple-100'], // ['bg-purple-500', 'text-purple-100'],
// ['bg-rose-500', 'text-rose-100'], // ['bg-rose-500', 'text-rose-100'],
] ]
if (!userData.value) return
return { return {
...userData.value, ...userData.value,
apps: Object.entries(userData.value.apps).map(([id, app]) => { apps: Object.entries(userData.value.apps).map(([id, app]) => {
@ -41,8 +41,10 @@ const me = computed(() => {
</script> </script>
<template> <template>
<div v-if="me"> <div>
<div id="apps" class="py-10"> <PageTitle :text="$t('app_list')" />
<div id="apps" class="my-10">
<div v-if="!me.apps.length" class="w-2/3"> <div v-if="!me.apps.length" class="w-2/3">
<em>{{ t('no_apps') }}</em> <em>{{ t('no_apps') }}</em>
</div> </div>

View file

@ -31,51 +31,55 @@ const onSubmit = handleSubmit(async (form) => {
</script> </script>
<template> <template>
<form novalidate @submit="onSubmit"> <div>
<!-- FIXME replace with accessible component --> <PageTitle :text="$t('change_password')" />
<div role="alert" class="alert alert-warning mb-10">
<Icon name="mdi:warning-outline" size="2em" />
{{ $t('good_practices_about_user_password') }}
</div>
<div class="md:flex"> <form novalidate class="my-10" @submit="onSubmit">
<div class="basis-1/2 mb-10 md:mr-10"> <!-- FIXME replace with accessible component -->
<FormField name="current" :label="$t('current_password')"> <div role="alert" class="alert alert-warning mb-10">
<TextInput <Icon name="mdi:warning-outline" size="2em" />
name="current" {{ $t('good_practices_about_user_password') }}
type="password"
autocomplete="currrent-password"
class="w-full"
/>
</FormField>
</div> </div>
<div class="basis-1/2 md:ml-10"> <div class="md:flex">
<FormField name="password" :label="$t('new_password')" class="mb-3"> <div class="basis-1/2 mb-10 md:mr-10">
<TextInput <FormField name="current" :label="$t('current_password')">
name="password" <TextInput
type="password" name="current"
autocomplete="new-password" type="password"
class="w-full" autocomplete="currrent-password"
/> class="w-full"
</FormField> />
</FormField>
</div>
<FormField name="confirmPassword" :label="$t('confirm_new_password')"> <div class="basis-1/2 md:ml-10">
<TextInput <FormField name="password" :label="$t('new_password')" class="mb-3">
name="confirmPassword" <TextInput
type="password" name="password"
autocomplete="new-password" type="password"
class="w-full" autocomplete="new-password"
/> class="w-full"
</FormField> />
</FormField>
<FormField name="confirmPassword" :label="$t('confirm_new_password')">
<TextInput
name="confirmPassword"
type="password"
autocomplete="new-password"
class="w-full"
/>
</FormField>
</div>
</div> </div>
</div>
<div class="flex mt-10"> <div class="flex mt-10">
<NuxtLink to="/" class="btn ml-auto mr-2"> <NuxtLink to="/" class="btn ml-auto mr-2">
{{ $t('cancel') }} {{ $t('cancel') }}
</NuxtLink> </NuxtLink>
<YButton :text="$t('ok')" type="submit" variant="success" /> <YButton :text="$t('ok')" type="submit" variant="success" />
</div> </div>
</form> </form>
</div>
</template> </template>