Skip to content

Commit a712ebe

Browse files
committed
VPR-104 fix(a11y): CTS assessment bubbles, banners, button labels
- Rewrite AssessmentBubble as semantic button/span with visible numeric rating and aria-label instead of an icon-only q-icon - Replace raw red error divs with StatusBanner across Assessment* pages; add v-model:visible support so dismissible banners reset - Fix MyAssessments heading hierarchy (h1/h2) and label expand toggles with aria-expanded - Add missing aria-labels and select label on CourseStudents - Fix ManageLevels add/edit form visibility toggle
1 parent f586754 commit a712ebe

9 files changed

Lines changed: 128 additions & 62 deletions

File tree

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { ref, watch } from "vue"
2+
import { computed } from "vue"
33
44
const props = withDefaults(
55
defineProps<{
@@ -18,42 +18,33 @@ const emit = defineEmits<{
1818
"bubble-click": [id: number]
1919
}>()
2020
21-
const classes5 = [
22-
"assessmentBubble5_1",
23-
"assessmentBubble5_2",
24-
"assessmentBubble5_3",
25-
"assessmentBubble5_4",
26-
"assessmentBubble5_5",
27-
]
21+
const levelClass = computed(() => {
22+
if (props.maxValue === 5 && props.value >= 1 && props.value <= 5) {
23+
return `assessmentBubble--level-${props.value}`
24+
}
25+
return ""
26+
})
2827
29-
const bubbleClass = ref("")
28+
const displayValue = computed(() => (props.value >= 1 && props.value <= props.maxValue ? props.value : "?"))
3029
31-
watch(props, () => {
32-
setBubbleAttrs()
33-
})
30+
const staticLabel = computed(() => `Rating ${displayValue.value} of ${props.maxValue}`)
31+
const clickableLabel = computed(() => `${staticLabel.value}, open details`)
3432
3533
function clickBubble() {
3634
if (props.id !== undefined) {
3735
emit("bubble-click", props.id)
3836
}
3937
}
40-
41-
function setBubbleAttrs() {
42-
if (props.maxValue === 5 && props.value <= 5 && props.value > 0) {
43-
const index = props.value - 1
44-
bubbleClass.value = classes5[index] ?? ""
45-
}
46-
}
47-
48-
setBubbleAttrs()
4938
</script>
5039
<template>
51-
<q-icon
52-
name="circle"
53-
size="sm"
54-
:class="'assessmentIcon cursor-pointer ' + bubbleClass"
40+
<button
41+
v-if="id !== undefined"
42+
type="button"
43+
:class="['assessmentBubble', 'assessmentBubble--clickable', levelClass]"
44+
:aria-label="clickableLabel"
5545
@click="clickBubble"
5646
>
47+
<span aria-hidden="true">{{ displayValue }}</span>
5748
<q-tooltip
5849
style="white-space: pre-wrap"
5950
class="text-body2"
@@ -62,5 +53,66 @@ setBubbleAttrs()
6253
<br />
6354
{{ props.text }}
6455
</q-tooltip>
65-
</q-icon>
56+
</button>
57+
<span
58+
v-else
59+
:class="['assessmentBubble', levelClass]"
60+
role="img"
61+
:aria-label="staticLabel"
62+
>
63+
<span aria-hidden="true">{{ displayValue }}</span>
64+
</span>
6665
</template>
66+
<style scoped>
67+
.assessmentBubble {
68+
display: inline-flex;
69+
align-items: center;
70+
justify-content: center;
71+
width: 1.75rem;
72+
height: 1.75rem;
73+
margin: 0 0.125rem;
74+
border: 0.0625rem solid var(--ucdavis-blue-100);
75+
border-radius: 50%;
76+
background-color: var(--ucdavis-blue-70);
77+
color: white;
78+
font-weight: 700;
79+
font-size: 0.875rem;
80+
line-height: 1;
81+
padding: 0;
82+
vertical-align: middle;
83+
}
84+
85+
.assessmentBubble--clickable {
86+
cursor: pointer;
87+
}
88+
89+
.assessmentBubble--clickable:hover,
90+
.assessmentBubble--clickable:focus {
91+
filter: brightness(1.1);
92+
}
93+
94+
.assessmentBubble--clickable:focus-visible {
95+
outline: 0.125rem solid var(--ucdavis-gold-90);
96+
outline-offset: 0.125rem;
97+
}
98+
99+
.assessmentBubble--level-1 {
100+
background-color: var(--ucdavis-blue-70);
101+
}
102+
103+
.assessmentBubble--level-2 {
104+
background-color: var(--ucdavis-blue-80);
105+
}
106+
107+
.assessmentBubble--level-3 {
108+
background-color: var(--ucdavis-blue-90);
109+
}
110+
111+
.assessmentBubble--level-4 {
112+
background-color: var(--ucdavis-blue-100);
113+
}
114+
115+
.assessmentBubble--level-5 {
116+
background-color: #011a38;
117+
}
118+
</style>

VueApp/src/CTS/pages/AssessmentCompetency.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useRoute } from "vue-router"
55
import type { Competency, MilestoneLevel } from "@/CTS/types"
66
import StudentSelect from "@/components/StudentSelect.vue"
77
import LevelSelect from "@/CTS/components/LevelSelect.vue"
8+
import StatusBanner from "@/components/StatusBanner.vue"
89
910
const route = useRoute()
1011
@@ -84,13 +85,13 @@ function submitMilestone() {}
8485
v-bind="studentMilestone"
8586
v-show="selectedStudentId > 0"
8687
>
87-
<div
88-
class="bg-red-5 text-white q-pa-sm rounded q-mb-md"
88+
<StatusBanner
8989
v-if="submitErrors?.message?.length > 0"
90+
type="error"
9091
>
9192
{{ submitErrors.message }}
9293
Please make sure you have selected a service, EPA, student, and a level on the entrustment scale.
93-
</div>
94+
</StatusBanner>
9495
<LevelSelect
9596
level-type="milestone"
9697
@level-change="(selectedLevelId: number) => (levelId = selectedLevelId)"

VueApp/src/CTS/pages/AssessmentEpa.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ watch(selectedStudentId, () => {
126126

127127
<StatusBanner
128128
v-if="success"
129+
v-model:visible="success"
129130
type="success"
130131
dismissible
131132
>
@@ -154,13 +155,13 @@ watch(selectedStudentId, () => {
154155
v-bind="studentEpa"
155156
v-show="selectedStudentId > 0"
156157
>
157-
<div
158-
class="bg-red-5 text-white q-pa-sm rounded q-mb-md"
158+
<StatusBanner
159159
v-if="submitErrors"
160+
type="error"
160161
>
161162
Please make sure you have selected a service, EPA, student, a level on the entrustment scale,
162163
and entered a comment.
163-
</div>
164+
</StatusBanner>
164165
<LevelSelect
165166
level-type="epa"
166167
@level-change="(selectedLevelId: number) => (levelId = selectedLevelId)"

VueApp/src/CTS/pages/AssessmentEpaEdit.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ getStudentEpa()
7676
>
7777
<StatusBanner
7878
v-if="success"
79+
v-model:visible="success"
7980
type="success"
8081
dismissible
8182
>
@@ -110,13 +111,13 @@ getStudentEpa()
110111
</div>
111112
</div>
112113
<q-form @submit="submitEpa">
113-
<div
114-
class="bg-red-5 text-white q-pa-sm rounded"
114+
<StatusBanner
115115
v-if="submitErrors?.message?.length > 0"
116+
type="error"
116117
>
117118
{{ submitErrors.message }}
118119
Please make sure you have selected a service, EPA, student, and a level on the entrustment scale.
119-
</div>
120+
</StatusBanner>
120121
<LevelSelect
121122
level-type="epa"
122123
@level-change="(selectedLevelId: number) => (levelId = selectedLevelId)"

VueApp/src/CTS/pages/CourseStudents.vue

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const student = ref("")
1212
dense
1313
options-dense
1414
outlined
15+
label="Student"
1516
:options="['Student 1', 'Student 2']"
1617
v-model="student"
1718
></q-select>
@@ -28,22 +29,23 @@ const student = ref("")
2829
>
2930
<thead>
3031
<tr>
31-
<th>Assess Competency</th>
32+
<th class="text-center">Assess Competency</th>
3233
<th class="text-left">Student</th>
3334
<th class="text-left">Time</th>
3435
<th class="text-center">Manually Added</th>
35-
<th class="text-left">Remove</th>
36+
<th class="text-center">Remove</th>
3637
</tr>
3738
</thead>
3839
<tbody>
3940
<tr>
40-
<td>
41+
<td class="text-center">
4142
<q-btn
4243
dense
4344
flat
4445
icon="assignment"
4546
size="sm"
4647
color="primary"
48+
aria-label="Assess competency for Montserrat Armero"
4749
to="AssessmentCompetency?studentId=23631&sessionId="
4850
></q-btn>
4951
</td>
@@ -54,26 +56,29 @@ const student = ref("")
5456
name="check"
5557
color="primary"
5658
size="sm"
59+
aria-label="Manually added"
5760
></q-icon>
5861
</td>
59-
<td>
62+
<td class="text-center">
6063
<q-btn
6164
dense
6265
icon="delete"
6366
color="negative"
6467
flat
6568
size="sm"
69+
aria-label="Remove Montserrat Armero"
6670
></q-btn>
6771
</td>
6872
</tr>
6973
<tr>
70-
<td>
74+
<td class="text-center">
7175
<q-btn
7276
dense
7377
flat
7478
icon="assignment"
7579
size="sm"
7680
color="primary"
81+
aria-label="Assess competency for Hailey Atwood"
7782
to="AssessmentCompetency?studentId=34123&sessionId="
7883
></q-btn>
7984
</td>
@@ -84,26 +89,29 @@ const student = ref("")
8489
name="check"
8590
color="primary"
8691
size="sm"
92+
aria-label="Manually added"
8793
></q-icon>
8894
</td>
89-
<td>
95+
<td class="text-center">
9096
<q-btn
9197
dense
9298
icon="delete"
9399
color="negative"
94100
flat
95101
size="sm"
102+
aria-label="Remove Hailey Atwood"
96103
></q-btn>
97104
</td>
98105
</tr>
99106
<tr>
100-
<td>
107+
<td class="text-center">
101108
<q-btn
102109
dense
103110
flat
104111
icon="assignment"
105112
size="sm"
106113
color="primary"
114+
aria-label="Assess competency for Xander Avila"
107115
to="AssessmentCompetency?studentId=34158&sessionId="
108116
></q-btn>
109117
</td>
@@ -114,15 +122,17 @@ const student = ref("")
114122
name="check"
115123
color="primary"
116124
size="sm"
125+
aria-label="Manually added"
117126
></q-icon>
118127
</td>
119-
<td>
128+
<td class="text-center">
120129
<q-btn
121130
dense
122131
icon="delete"
123132
color="negative"
124133
flat
125134
size="sm"
135+
aria-label="Remove Xander Avila"
126136
></q-btn>
127137
</td>
128138
</tr>

VueApp/src/CTS/pages/ManageLevels.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ loadLevels()
144144
@click="showForm = true"
145145
></q-btn>
146146
</div>
147-
<div v-if="Object.keys(level).length">
147+
<div v-if="showForm">
148148
{{ level?.levelId ? "Update" : "Add" }} Level
149149
<div class="row">
150150
<q-toggle

0 commit comments

Comments
 (0)