Skip to content

Commit

Permalink
Improve accessibility of language modal
Browse files Browse the repository at this point in the history
Even though Knossos is not very accessible right now, at least this new
feature can be.
  • Loading branch information
brawaru committed Nov 30, 2022
1 parent 21b83ba commit e4e5906
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 20 deletions.
108 changes: 88 additions & 20 deletions components/ui/ModalLanguages.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@
<div class="languages-grid-container">
<div v-if="automatic" class="automatic-overlay">
<div class="automatic-overlay-icon">
<GlobeIcon />
<GlobeIcon aria-hidden="true" />
</div>
<div class="automatic-overlay-title">
{{ $t('component.modal-languages.auto-lockout.title') }}
</div>
<div class="automatic-overlay-description">
<IntlFormatted
message-id="component.modal-languages.auto-lockout.description"
:values="{ language: currentLanguage.displayName }"
/>
<div class="automatic-overlay-content" tabindex="0">
<h3 class="automatic-overlay-title">
{{ $t('component.modal-languages.auto-lockout.title') }}
</h3>
<p class="automatic-overlay-description">
<IntlFormatted
message-id="component.modal-languages.auto-lockout.description"
:values="{ language: currentLanguage.displayName }"
/>
</p>
</div>
<div class="automatic-overlay-actions">
<button
Expand All @@ -53,8 +55,31 @@
$t('component.modal-languages.field.search.placeholder')
"
:disabled="automatic"
aria-describedby="slm-s-desc"
@keypress="onSearchKeyPress"
/>
<div class="languages-grid" :class="{ empty }">
<div id="slm-s-desc" class="sr-only">
{{ $t('component.modal-languages.field.search.description') }}
</div>
<div id="slm-sr-results" class="sr-only" aria-live="polite">
{{
typedSearchQuery === ''
? ''
: $t(
'component.modal-languages.announcement.search-results',
{
matches: matchingLanguages.length,
}
)
}}
</div>
<div
ref="gridRef"
class="languages-grid"
:class="{ empty }"
:aria-label="$t('component.modal-languages.grid.legend')"
role="list"
>
<div
v-for="language in matchingLanguages"
:key="language.code"
Expand All @@ -65,6 +90,7 @@
"
class="language"
:class="{ active: selectedLanguage === language.code }"
role="listitem"
>
<input
:id="language.inputID"
Expand All @@ -78,7 +104,16 @@
/>
<div class="language-info">
<label :for="language.inputID" class="language-label">
<div class="display-name">
<div
class="display-name"
:lang="language.code"
:aria-label="
$t('component.modal-languages.language.label', {
displayName: language.displayName,
translatedName: language.translatedName,
})
"
>
{{ language.displayName }}
</div>
<span
Expand All @@ -90,7 +125,12 @@
"
class="browser-locale"
>
<GlobeIcon />
<GlobeIcon aria-hidden="true" />
<span class="sr-only">{{
$t(
'component.modal-languages.language.icon-labels.browser-preferred'
)
}}</span>
</span>
<span
v-if="isCurrentlyUsed(language)"
Expand All @@ -99,7 +139,12 @@
"
class="current-locale"
>
<Check />
<Check aria-hidden="true" />
<span class="sr-only">{{
$t(
'component.modal-languages.language.icon-labels.currently-used'
)
}}</span>
</span>
</label>
<div class="translated-name">
Expand All @@ -110,16 +155,24 @@
<div
v-if="!empty && matchingLanguages.length < 4"
class="language spacer"
aria-hidden="true"
/>
<div
v-if="!empty && matchingLanguages.length < 3"
class="language spacer"
aria-hidden="true"
/>
<div
v-if="!empty && matchingLanguages.length < 2"
class="language spacer"
aria-hidden="true"
/>
<div v-if="empty" class="placeholder">
<div
v-if="empty"
class="placeholder"
tabindex="0"
role="listitem"
>
{{ $t('component.modal-languages.filler.no-results') }}
</div>
</div>
Expand Down Expand Up @@ -202,7 +255,9 @@ export default defineComponent({
/** @type {null | InstanceType<import('./Modal.vue').default>} */ (null)
)
return { modalRef }
const gridRef = ref(/** @type {null | HTMLFieldSetElement} */ (null))
return { modalRef, gridRef }
},
data() {
return initialState.call(this)
Expand Down Expand Up @@ -360,9 +415,7 @@ export default defineComponent({
)
}
const result = this.fuse.search(this.searchQuery)
console.log(result)
return result.map((_) => _.item)
return this.fuse.search(this.searchQuery).map((_) => _.item)
},
/** @returns {boolean} Whether there are no search results. */
empty() {
Expand Down Expand Up @@ -414,8 +467,22 @@ export default defineComponent({
},
},
methods: {
applyChanges() {
return this.$i18n.changeLocale(this.selectedLanguage)
/** @param {KeyboardEvent} e Keyboard event */
onSearchKeyPress(e) {
const anyModifierPressed =
e.altKey || e.ctrlKey || e.metaKey || e.shiftKey
if (e.key === 'Enter' && !anyModifierPressed) {
const focusable =
/** @type {HTMLInputElement | HTMLDivElement | undefined} */ (
this.gridRef?.querySelector('input,div.placeholder')
)
focusable?.focus({ preventScroll: true })
}
},
async applyChanges() {
await this.$i18n.changeLocale(this.selectedLanguage)
},
/**
* @param {Language} language Language to check.
Expand Down Expand Up @@ -557,6 +624,7 @@ export default defineComponent({
white-space: pre-line;
max-width: 400px;
color: var(--color-overlay-description);
margin: 0;
}
}
Expand Down
11 changes: 11 additions & 0 deletions i18n/en-US/index.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ contribution-notice = """Modrinth is translated by volunteers. \
filler.no-results = "No results"
action.enable-automatic = "Automatic"
field.search.placeholder = "Search language..."
field.search.description = "Submit to focus the first search result."
announcement.search-results = """\
{matches, plural,\
=0 {No languages match}\
one {# language matches}\
other {# languages match}\
} your search."""
grid.legend = "Select a language"

[component.modal-languages.auto-lockout]
title = "Using your browser's language"
Expand All @@ -165,6 +173,9 @@ action = "Use a different language"
[component.modal-languages.language]
browser-preferred = "Browser language"
currently-used = "Currently used"
label = "{displayName} ({translatedName})"
icon-labels.browser-preferred = "(browser language)"
icon-labels.currently-used = "(currently used)"

[component.modal-report]
title = "Report {itemType, select, user {user} other {project}}"
Expand Down

0 comments on commit e4e5906

Please sign in to comment.