feat(a11y): add semantic markup to interface settings (#2809)
Co-authored-by: TAKAHASHI Shuuji <shuuji3@gmail.com>
This commit is contained in:
parent
f78ce97f05
commit
c504e14ff5
|
@ -67,61 +67,69 @@ function save() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form aria-labelledby="interface-bn" aria-describedby="interface-bn-desc" @submit.prevent="save">
|
<section space-y-2>
|
||||||
<!-- preview -->
|
<h2 id="interface-bn" font-medium>
|
||||||
<div aria-hidden="true" flex="~ gap4 wrap" items-center select-settings h-14 p0>
|
{{ $t('settings.interface.bottom_nav') }}
|
||||||
<nav
|
</h2>
|
||||||
v-for="availableNavButton in selectedNavButtons" :key="availableNavButton.name"
|
<form aria-labelledby="interface-bn" aria-describedby="interface-bn-desc" @submit.prevent="save">
|
||||||
flex="~ 1" items-center justify-center text-xl
|
<p id="interface-bn-desc" pb-2>
|
||||||
scrollbar-hide overscroll-none
|
{{ $t('settings.interface.bottom_nav_instructions') }}
|
||||||
>
|
</p>
|
||||||
<button btn-base :class="availableNavButton.icon" mx-4 tabindex="-1" />
|
<!-- preview -->
|
||||||
</nav>
|
<div aria-hidden="true" flex="~ gap4 wrap" items-center select-settings h-14 p0>
|
||||||
</div>
|
<nav
|
||||||
|
v-for="availableNavButton in selectedNavButtons" :key="availableNavButton.name"
|
||||||
|
flex="~ 1" items-center justify-center text-xl
|
||||||
|
scrollbar-hide overscroll-none
|
||||||
|
>
|
||||||
|
<button btn-base :class="availableNavButton.icon" mx-4 tabindex="-1" />
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- button selection -->
|
<!-- button selection -->
|
||||||
<div flex="~ gap4 wrap" py4>
|
<div flex="~ gap4 wrap" py4>
|
||||||
<button
|
<button
|
||||||
v-for="{ name, label, icon } in availableNavButtons"
|
v-for="{ name, label, icon } in availableNavButtons"
|
||||||
:key="name"
|
:key="name"
|
||||||
btn-text flex="~ gap-2" items-center p2 border="~ base rounded" bg-base ws-nowrap
|
btn-text flex="~ gap-2" items-center p2 border="~ base rounded" bg-base ws-nowrap
|
||||||
:class="isAdded(name) ? 'text-secondary hover:text-second bg-auto' : ''"
|
:class="isAdded(name) ? 'text-secondary hover:text-second bg-auto' : ''"
|
||||||
type="button"
|
type="button"
|
||||||
role="switch"
|
role="switch"
|
||||||
:aria-checked="isAdded(name)"
|
:aria-checked="isAdded(name)"
|
||||||
@click="isAdded(name) ? remove(name) : append(name)"
|
@click="isAdded(name) ? remove(name) : append(name)"
|
||||||
>
|
>
|
||||||
<span :class="icon" />
|
<span :class="icon" />
|
||||||
{{ label ? $t(label) : 'More menu' }}
|
{{ label ? $t(label) : 'More menu' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div flex="~ col" gap-y-4 gap-x-2 py-1 sm="~ justify-end flex-row">
|
<div flex="~ col" gap-y-4 gap-x-2 py-1 sm="~ justify-end flex-row">
|
||||||
<button
|
<button
|
||||||
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="selectedNavButtonNames.length === 0"
|
:disabled="selectedNavButtonNames.length === 0"
|
||||||
:class="selectedNavButtonNames.length === 0 ? 'border-none' : undefined"
|
:class="selectedNavButtonNames.length === 0 ? 'border-none' : undefined"
|
||||||
@click="clear"
|
@click="clear"
|
||||||
>
|
>
|
||||||
<span aria-hidden="true" class="block i-ri:delete-bin-line" />
|
<span aria-hidden="true" class="block i-ri:delete-bin-line" />
|
||||||
{{ $t('action.clear') }}
|
{{ $t('action.clear') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||||||
type="reset"
|
type="reset"
|
||||||
@click="reset"
|
@click="reset"
|
||||||
>
|
>
|
||||||
<span aria-hidden="true" class="block i-ri:repeat-line" />
|
<span aria-hidden="true" class="block i-ri:repeat-line" />
|
||||||
{{ $t('action.reset') }}
|
{{ $t('action.reset') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
btn-solid font-bold py2 full-w sm-wa flex="~ gap2 center"
|
btn-solid font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||||||
:disabled="!canSave"
|
:disabled="!canSave"
|
||||||
>
|
>
|
||||||
<span aria-hidden="true" i-ri:save-2-fill />
|
<span aria-hidden="true" i-ri:save-2-fill />
|
||||||
{{ $t('action.save') }}
|
{{ $t('action.save') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -27,18 +27,23 @@ const modes = [
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex="~ gap4 wrap" w-full role="group" aria-labelledby="interface-cm">
|
<section space-y-2>
|
||||||
<button
|
<h2 id="interface-cm" font-medium>
|
||||||
v-for="{ icon, label, mode } in modes"
|
{{ $t('settings.interface.color_mode') }}
|
||||||
:key="mode"
|
</h2>
|
||||||
type="button"
|
<div flex="~ gap4 wrap" w-full role="group" aria-labelledby="interface-cm">
|
||||||
btn-text flex-1 flex="~ gap-1 center" p4 border="~ base rounded" bg-base ws-nowrap
|
<button
|
||||||
:aria-pressed="colorMode.preference === mode ? 'true' : 'false'"
|
v-for="{ icon, label, mode } in modes"
|
||||||
:class="colorMode.preference === mode ? 'pointer-events-none' : 'filter-saturate-0'"
|
:key="mode"
|
||||||
@click="setColorMode(mode)"
|
type="button"
|
||||||
>
|
btn-text flex-1 flex="~ gap-1 center" p4 border="~ base rounded" bg-base ws-nowrap
|
||||||
<span :class="`${icon}`" />
|
:aria-pressed="colorMode.preference === mode ? 'true' : 'false'"
|
||||||
{{ $t(label) }}
|
:class="colorMode.preference === mode ? 'pointer-events-none' : 'filter-saturate-0'"
|
||||||
</button>
|
@click="setColorMode(mode)"
|
||||||
</div>
|
>
|
||||||
|
<span :class="`${icon}`" />
|
||||||
|
{{ $t(label) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -13,40 +13,45 @@ function setFontSize(e: Event) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex items-center space-x-4>
|
<section space-y-2>
|
||||||
<span text-xs text-secondary>Aa</span>
|
<h2 id="interface-fs" font-medium>
|
||||||
<div flex-1 relative flex items-center>
|
{{ $t('settings.interface.font_size') }}
|
||||||
<input
|
</h2>
|
||||||
aria-labelledby="interface-fs"
|
<div flex items-center space-x-4 select-settings>
|
||||||
:value="sizes.indexOf(userSettings.fontSize)"
|
<span text-xs text-secondary>Aa</span>
|
||||||
:aria-valuetext="`${userSettings.fontSize}${userSettings.fontSize === DEFAULT_FONT_SIZE ? ` ${$t('settings.interface.default')}` : ''}`"
|
<div flex-1 relative flex items-center>
|
||||||
:min="0"
|
<input
|
||||||
:max="sizes.length - 1"
|
aria-labelledby="interface-fs"
|
||||||
:step="1"
|
:value="sizes.indexOf(userSettings.fontSize)"
|
||||||
type="range"
|
:aria-valuetext="`${userSettings.fontSize}${userSettings.fontSize === DEFAULT_FONT_SIZE ? ` ${$t('settings.interface.default')}` : ''}`"
|
||||||
focus:outline-none
|
:min="0"
|
||||||
appearance-none bg-transparent
|
:max="sizes.length - 1"
|
||||||
w-full cursor-pointer
|
:step="1"
|
||||||
@change="setFontSize"
|
type="range"
|
||||||
>
|
focus:outline-none
|
||||||
<div flex items-center justify-between absolute w-full pointer-events-none>
|
appearance-none bg-transparent
|
||||||
<div
|
w-full cursor-pointer
|
||||||
v-for="i in sizes.length" :key="i"
|
@change="setFontSize"
|
||||||
class="container-marker"
|
|
||||||
h-3 w-3
|
|
||||||
rounded-full bg-secondary-light
|
|
||||||
relative
|
|
||||||
>
|
>
|
||||||
|
<div flex items-center justify-between absolute w-full pointer-events-none>
|
||||||
<div
|
<div
|
||||||
v-if="(sizes.indexOf(userSettings.fontSize)) === i - 1"
|
v-for="i in sizes.length" :key="i"
|
||||||
absolute rounded-full class="-top-1 -left-1"
|
class="container-marker"
|
||||||
bg-primary h-5 w-5
|
h-3 w-3
|
||||||
/>
|
rounded-full bg-secondary-light
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="(sizes.indexOf(userSettings.fontSize)) === i - 1"
|
||||||
|
absolute rounded-full class="-top-1 -left-1"
|
||||||
|
bg-primary h-5 w-5
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span text-xl text-secondary>Aa</span>
|
||||||
</div>
|
</div>
|
||||||
<span text-xl text-secondary>Aa</span>
|
</section>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -64,7 +69,7 @@ function setFontSize(e: Event) {
|
||||||
input[type=range]::-webkit-slider-runnable-track {
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
--at-apply: bg-secondary-light rounded-full h1 op60;
|
--at-apply: bg-secondary-light rounded-full h1 op60;
|
||||||
}
|
}
|
||||||
input[type=range]:focus:-webkit-slider-runnable-track {
|
input[type=range]:focus::-webkit-slider-runnable-track {
|
||||||
--at-apply: outline-2 outline-red;
|
--at-apply: outline-2 outline-red;
|
||||||
}
|
}
|
||||||
input[type=range]::-webkit-slider-thumb {
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
|
|
@ -12,20 +12,25 @@ function updateTheme(theme: ThemeColors) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex="~ gap4 wrap" p2 role="group" aria-labelledby="interface-tc">
|
<section space-y-2>
|
||||||
<button
|
<h2 id="interface-tc" font-medium>
|
||||||
v-for="[key, theme] in themes" :key="key"
|
{{ $t('settings.interface.theme_color') }}
|
||||||
:style="{
|
</h2>
|
||||||
'background': key,
|
<div flex="~ gap4 wrap" p2 role="group" aria-labelledby="interface-tc">
|
||||||
'--local-ring-color': key,
|
<button
|
||||||
}"
|
v-for="[key, theme] in themes" :key="key"
|
||||||
type="button"
|
:style="{
|
||||||
:class="currentTheme === theme['--theme-color-name'] ? 'ring-2' : 'scale-90'"
|
'background': key,
|
||||||
:aria-pressed="currentTheme === theme['--theme-color-name'] ? 'true' : 'false'"
|
'--local-ring-color': key,
|
||||||
:title="theme['--theme-color-name']"
|
}"
|
||||||
w-8 h-8 rounded-full transition-all
|
type="button"
|
||||||
ring="$local-ring-color offset-3 offset-$c-bg-base"
|
:class="currentTheme === theme['--theme-color-name'] ? 'ring-2' : 'scale-90'"
|
||||||
@click="updateTheme(theme)"
|
:aria-pressed="currentTheme === theme['--theme-color-name'] ? 'true' : 'false'"
|
||||||
/>
|
:title="theme['--theme-color-name']"
|
||||||
</div>
|
w-8 h-8 rounded-full transition-all
|
||||||
|
ring="$local-ring-color offset-3 offset-$c-bg-base"
|
||||||
|
@click="updateTheme(theme)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -13,34 +13,11 @@ useHydratedHead({
|
||||||
<span>{{ $t('settings.interface.label') }}</span>
|
<span>{{ $t('settings.interface.label') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div p6 flex="~ col gap6">
|
<div px-6 pt-3 pb-6 flex="~ col gap6">
|
||||||
<div space-y-2>
|
<SettingsFontSize />
|
||||||
<p id="interface-fs" font-medium>
|
<SettingsColorMode />
|
||||||
{{ $t('settings.interface.font_size') }}
|
<SettingsThemeColors />
|
||||||
</p>
|
<SettingsBottomNav />
|
||||||
<SettingsFontSize select-settings />
|
|
||||||
</div>
|
|
||||||
<div space-y-2>
|
|
||||||
<p id="interface-cm" font-medium>
|
|
||||||
{{ $t('settings.interface.color_mode') }}
|
|
||||||
</p>
|
|
||||||
<SettingsColorMode />
|
|
||||||
</div>
|
|
||||||
<div space-y-2>
|
|
||||||
<p id="interface-tc" font-medium>
|
|
||||||
{{ $t('settings.interface.theme_color') }}
|
|
||||||
</p>
|
|
||||||
<SettingsThemeColors />
|
|
||||||
</div>
|
|
||||||
<div space-y-2>
|
|
||||||
<p id="interface-bn" font-medium>
|
|
||||||
{{ $t('settings.interface.bottom_nav') }}
|
|
||||||
</p>
|
|
||||||
<p id="interface-bn-desc">
|
|
||||||
{{ $t('settings.interface.bottom_nav_instructions') }}
|
|
||||||
</p>
|
|
||||||
<SettingsBottomNav />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MainContent>
|
</MainContent>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in a new issue