diff options
| author | Murtaza Sultani <sultani@data-quest.de> | 2026-01-19 12:28:04 +0100 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2026-02-27 15:31:56 +0100 |
| commit | e4f38e0e8cdc2cdd1dce822ca62260df3f588446 (patch) | |
| tree | 38706b5106a1b579dbfd92f75500a7782134d446 | |
| parent | 04b813348082ef0dbf883d3b6a5b63077331eda6 (diff) | |
Resolve "Avatar-Menü: Barrierefreiheitsprobleme beheben"
Closes #6168
Merge request studip/studip!4673
| -rw-r--r-- | resources/vue/components/Dropdown.vue | 6 | ||||
| -rw-r--r-- | resources/vue/components/UserAvatar.vue | 10 | ||||
| -rw-r--r-- | resources/vue/components/forum/ForumMembers.vue | 11 | ||||
| -rw-r--r-- | resources/vue/components/forum/SubscriptionDropdown.vue | 4 | ||||
| -rw-r--r-- | resources/vue/components/forum/UserAvatarDropdown.vue | 14 |
5 files changed, 32 insertions, 13 deletions
diff --git a/resources/vue/components/Dropdown.vue b/resources/vue/components/Dropdown.vue index c02f196..2fb2a24 100644 --- a/resources/vue/components/Dropdown.vue +++ b/resources/vue/components/Dropdown.vue @@ -60,8 +60,8 @@ onBeforeUnmount(() => { v-bind="$attrs" ref="dropdown" class="dropdown" - aria-haspopup="true" - :aria-expanded="isOpen.toString()" + aria-haspopup="menu" + :aria-expanded="isOpen" > <div ref="trigger"> <slot name="trigger"> @@ -73,7 +73,7 @@ onBeforeUnmount(() => { v-if="isOpen" ref="dropdownContent" class="dropdown__content" - aria-labelledby="dropdown-title" + :aria-labelledby="title ? 'dropdown-title' : null" > <button type="button" diff --git a/resources/vue/components/UserAvatar.vue b/resources/vue/components/UserAvatar.vue index 441a41c..fee7f05 100644 --- a/resources/vue/components/UserAvatar.vue +++ b/resources/vue/components/UserAvatar.vue @@ -41,7 +41,7 @@ const openBlubberChat = () => { } </script> <template> - <div class="user-avatar"> + <div class="user-avatar" v-bind="$attrs"> <div class="user-avatar__header"> <img class="user-profile" :src="user.avatar_url" :alt="user.name" /> <div class="user-info"> @@ -50,9 +50,11 @@ const openBlubberChat = () => { </div> </div> <hr /> - <ul class="user-avatar__actions"> + <ul class="user-avatar__actions" role="menu"> <li> <button + role="menuitem" + type="button" v-if="user.id !== AUTH_ID" @click="openBlubberChat" class="action-item" @@ -65,6 +67,7 @@ const openBlubberChat = () => { </li> <li> <a + role="menuitem" class="action-item" :href="userProfileURL" :title="$gettext('Zum Profil von %{name}', { name: user.name })" @@ -76,6 +79,8 @@ const openBlubberChat = () => { </li> <li> <button + role="menuitem" + type="button" v-if="user.id !== AUTH_ID" class="action-item" :title="$gettext('Nachricht schreiben')" @@ -88,6 +93,7 @@ const openBlubberChat = () => { </li> <li> <a + role="menuitem" class="action-item" :href="vCardDownloadURL" :title="$gettext('vCard herunterladen')" diff --git a/resources/vue/components/forum/ForumMembers.vue b/resources/vue/components/forum/ForumMembers.vue index 54d29c4..e24442b 100644 --- a/resources/vue/components/forum/ForumMembers.vue +++ b/resources/vue/components/forum/ForumMembers.vue @@ -52,6 +52,8 @@ const isModerator = role => role === 'moderator'; @click="showAllMembers = !showAllMembers" :title="$gettext('Alle Teilnehmende anzeigen')" :aria-label="$gettext('Alle Teilnehmende anzeigen')" + aria-haspopup="menu" + :aria-expanded="showAllMembers" > <span class="remained-users__count" :style="{ width: size, height: size }"> +{{ remainedMembersCount }} @@ -78,6 +80,8 @@ const isModerator = role => role === 'moderator'; @click="activeUserAvatar = user.id" :title="$gettext('Aufklappen')" :aria-label="$gettext('Aufklappen')" + :aria-expanded="activeUserAvatar === user.id" + :aria-controls="'user-avatar-' + user.id" class="show-avatar button-base"> <StudipIcon shape="arr_1down" :size="15" aria-hidden="true" /> </button> @@ -91,7 +95,8 @@ const isModerator = role => role === 'moderator'; class="hide-avatar button-base"> <StudipIcon shape="arr_1up" :size="15" aria-hidden="true" /> </button> - <UserAvatar v-if="activeUserAvatar === user.id" :user="user" /> + + <UserAvatar v-if="activeUserAvatar === user.id" :id="'user-avatar-' + user.id" :user="user" /> </li> </ul> </div> @@ -122,10 +127,12 @@ const isModerator = role => role === 'moderator'; @click="activeUserAvatar = ''" :title="$gettext('Zuklappen')" :aria-label="$gettext('Zuklappen')" + :aria-expanded="activeUserAvatar === user.id" + :aria-controls="'user-avatar-' + user.id" class="hide-avatar button-base"> <StudipIcon shape="arr_1up" :size="15" aria-hidden="true" /> </button> - <UserAvatar v-if="activeUserAvatar === user.id" :user="user" /> + <UserAvatar v-if="activeUserAvatar === user.id" :id="'user-avatar-' + user.id" :user="user" /> </li> </ul> </div> diff --git a/resources/vue/components/forum/SubscriptionDropdown.vue b/resources/vue/components/forum/SubscriptionDropdown.vue index 4a569f0..75cfaad 100644 --- a/resources/vue/components/forum/SubscriptionDropdown.vue +++ b/resources/vue/components/forum/SubscriptionDropdown.vue @@ -155,6 +155,7 @@ const subscribe = async (notificationType = 'all') => { <template #items> <li> <button + role="menuitem" type="button" :class="{ 'active': subscription?.notification_type === SubscriptionNotificationType.All @@ -174,6 +175,7 @@ const subscribe = async (notificationType = 'all') => { </li> <li> <button + role="menuitem" type="button" :class="{ 'active': subscription?.notification_type === SubscriptionNotificationType.RepliesOnly @@ -193,6 +195,7 @@ const subscribe = async (notificationType = 'all') => { </li> <li> <button + role="menuitem" type="button" :class="{ 'active': subscription?.notification_type === SubscriptionNotificationType.None @@ -212,6 +215,7 @@ const subscribe = async (notificationType = 'all') => { </li> <li> <button + role="menuitem" type="button" :disabled="!subscription?.notification_type" @click="unSubscribe" diff --git a/resources/vue/components/forum/UserAvatarDropdown.vue b/resources/vue/components/forum/UserAvatarDropdown.vue index 82f693d..7484b98 100644 --- a/resources/vue/components/forum/UserAvatarDropdown.vue +++ b/resources/vue/components/forum/UserAvatarDropdown.vue @@ -14,7 +14,7 @@ defineProps({ }, label: { type: String, - default: '' + default: null } }); @@ -24,22 +24,24 @@ const isOpen = defineModel({ default: false }); <Dropdown class="user-avatar-dropdown" v-model="isOpen"> <template #trigger> <button - class="user-avatar-dropdown__preview" + type="button" + class="user-avatar-dropdown__preview button-base" @click="isOpen = !isOpen" v-bind="$attrs" :class="{ 'active': isOpen }" - :title="label ?? user.name" - :aria-label="label ?? $gettext('vCard')" - :aria-pressed="isOpen" + :title="label ?? $gettext('Avatar-Menü öffnen')" + :aria-label="$gettext('Avatar-Menü für „%{ context }“ öffnen', { context: user.name })" + aria-haspopup="menu" + :aria-expanded="isOpen" > <img class="user-profile" :src="user.avatar_url" :style="{ width: size, height: size }" :alt="user.name" /> </button> </template> <template #content> - <UserAvatar :user="user" v-model="isOpen" /> + <UserAvatar :user="user" v-model="isOpen" :id="'user-avatar-' + user.id" /> </template> </Dropdown> </template> |
