aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurtaza Sultani <sultani@data-quest.de>2026-01-19 12:28:04 +0100
committerMurtaza Sultani <sultani@data-quest.de>2026-01-19 12:28:04 +0100
commitf6dd19e51de52e73c1c6a3e70467eb9a062e7440 (patch)
tree9fb7a54d30d76fc9bdb7c6da04c8fd1cfe9e3b25
parent0d8b969f29e484c28516d23a5edf22fe9d04a74c (diff)
Resolve "Avatar-Menü: Barrierefreiheitsprobleme beheben"
Closes #6168 Merge request studip/studip!4673
-rw-r--r--resources/vue/components/Dropdown.vue6
-rw-r--r--resources/vue/components/avatar/UserAvatar.vue8
-rw-r--r--resources/vue/components/avatar/UserAvatarDropdown.vue13
-rw-r--r--resources/vue/components/forum/ForumMembers.vue11
-rw-r--r--resources/vue/components/forum/SubscriptionDropdown.vue4
5 files changed, 29 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/avatar/UserAvatar.vue b/resources/vue/components/avatar/UserAvatar.vue
index def6719..5509090 100644
--- a/resources/vue/components/avatar/UserAvatar.vue
+++ b/resources/vue/components/avatar/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,10 @@ 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"
@@ -66,6 +67,7 @@ const openBlubberChat = () => {
</li>
<li>
<a
+ role="menuitem"
class="action-item"
:href="userProfileURL"
:title="$gettext('Zum Profil von %{name}', { name: user.name })"
@@ -77,6 +79,7 @@ const openBlubberChat = () => {
</li>
<li>
<button
+ role="menuitem"
type="button"
v-if="user.id !== AUTH_ID"
class="action-item button-base"
@@ -90,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/avatar/UserAvatarDropdown.vue b/resources/vue/components/avatar/UserAvatarDropdown.vue
index 6706990..a58b205 100644
--- a/resources/vue/components/avatar/UserAvatarDropdown.vue
+++ b/resources/vue/components/avatar/UserAvatarDropdown.vue
@@ -13,7 +13,7 @@ defineProps({
},
label: {
type: String,
- default: ''
+ default: null
}
});
@@ -23,23 +23,24 @@ const isOpen = defineModel({ default: false });
<Dropdown class="user-avatar-dropdown" v-model="isOpen">
<template #trigger>
<button
- class="user-avatar-dropdown__preview button-base"
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 ?? user.name"
- :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>
diff --git a/resources/vue/components/forum/ForumMembers.vue b/resources/vue/components/forum/ForumMembers.vue
index d8f4e6e..f9e1097 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 9976959..66153ae 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="button-base"
:class="{
@@ -175,6 +176,7 @@ const subscribe = async (notificationType = 'all') => {
</li>
<li>
<button
+ role="menuitem"
type="button"
class="button-base"
:class="{
@@ -195,6 +197,7 @@ const subscribe = async (notificationType = 'all') => {
</li>
<li>
<button
+ role="menuitem"
type="button"
class="button-base"
:class="{
@@ -215,6 +218,7 @@ const subscribe = async (notificationType = 'all') => {
</li>
<li>
<button
+ role="menuitem"
type="button"
class="button-base"
:disabled="!subscription?.notification_type"