This commit is contained in:
Timothy Jaeryang Baek 2026-10-21 09:47:21 +09:00
parent d5038fec44
commit 33e4c5f514
6 changed files with 38 additions and 12 deletions

View file

@ -9,10 +9,14 @@
const labelId = `admin-setting-${uuidv4()}`;
</script>
<div class="flex items-center justify-between gap-4 {className}">
<div id={labelId} class="min-w-0 text-xs text-gray-600 dark:text-gray-400 {labelClassName}">
<div class="group/setting-row flex items-center justify-between gap-4 {className}">
<label
for={`${labelId}-control`}
id={labelId}
class="min-w-0 text-xs text-gray-600 group-has-[[role=switch]:enabled]/setting-row:cursor-pointer group-has-[[role=switch]:disabled]/setting-row:cursor-not-allowed transition-colors duration-150 group-hover/setting-row:text-gray-900 group-focus-within/setting-row:text-gray-900 dark:text-gray-400 dark:group-hover/setting-row:text-white dark:group-focus-within/setting-row:text-white {labelClassName}"
>
<slot name="label">{label}</slot>
</div>
</label>
<div class="min-w-0">
<slot {labelId} />

View file

@ -263,8 +263,9 @@
</AdminSettingSection>
<AdminSettingSection title={$i18n.t('Multi-factor authentication')}>
<AdminSettingRow label={$i18n.t('Require an authenticator for all users')}>
<AdminSettingRow let:labelId label={$i18n.t('Require an authenticator for all users')}>
<Switch
ariaLabelledbyId={labelId}
bind:state={adminConfig.ENABLE_MFA}
ariaLabel={$i18n.t('Require an authenticator for all users')}
/>
@ -273,14 +274,20 @@
{$i18n.t('Changes sign out all devices. Users enroll on their next sign-in.')}
</p>
{#if adminConfig.ENABLE_MFA}
<AdminSettingRow label={$i18n.t('Allow OAuth sign-in without an authenticator')}
<AdminSettingRow
let:labelId
label={$i18n.t('Allow OAuth sign-in without an authenticator')}
><Switch
ariaLabelledbyId={labelId}
bind:state={adminConfig.MFA_ALLOW_OAUTH_BYPASS}
ariaLabel={$i18n.t('Allow OAuth sign-in without an authenticator')}
/></AdminSettingRow
>
<AdminSettingRow label={$i18n.t('Allow trusted-header sign-in without an authenticator')}
<AdminSettingRow
let:labelId
label={$i18n.t('Allow trusted-header sign-in without an authenticator')}
><Switch
ariaLabelledbyId={labelId}
bind:state={adminConfig.MFA_ALLOW_TRUSTED_HEADER_BYPASS}
ariaLabel={$i18n.t('Allow trusted-header sign-in without an authenticator')}
/></AdminSettingRow

View file

@ -224,12 +224,14 @@
{/if}
<UserSettingRow
let:labelId
label={$i18n.t('settings.personal.audio.instantAutoSendAfterVoiceTranscription.label')}
description={$i18n.t(
'settings.personal.audio.instantAutoSendAfterVoiceTranscription.description'
)}
>
<Switch
ariaLabelledbyId={labelId}
state={speechAutoSend}
ariaLabel={$i18n.t(
'settings.personal.audio.instantAutoSendAfterVoiceTranscription.label'
@ -276,10 +278,12 @@
{/if}
<UserSettingRow
let:labelId
label={$i18n.t('settings.personal.audio.autoPlaybackResponse.label')}
description={$i18n.t('settings.personal.audio.autoPlaybackResponse.description')}
>
<Switch
ariaLabelledbyId={labelId}
state={responseAutoPlayback}
ariaLabel={$i18n.t('settings.personal.audio.autoPlaybackResponse.label')}
on:change={(event) => {
@ -368,10 +372,11 @@
</SettingsSelect>
</UserSettingField>
<UserSettingRow
let:labelId
label={$i18n.t('settings.personal.audio.allowNonLocalVoices.label')}
description={$i18n.t('settings.personal.audio.allowNonLocalVoices.description')}
>
<Switch bind:state={nonLocalVoices} />
<Switch ariaLabelledbyId={labelId} bind:state={nonLocalVoices} />
</UserSettingRow>
</UserSettingSection>
{:else if $config.audio.tts.engine !== ''}

View file

@ -119,6 +119,7 @@
first
>
<UserSettingRow
let:labelId
description={$i18n
.t('settings.personal.personalization.memory.description')
.replace(
@ -132,6 +133,7 @@
</div>
<Switch
ariaLabelledbyId={labelId}
bind:state={enableMemory}
on:change={async () => {
saveSettings({ memory: enableMemory });

View file

@ -1,17 +1,25 @@
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
export let label = '';
export let description = '';
export let className = '';
export let labelClassName = '';
const labelId = `user-setting-${uuidv4()}`;
</script>
<div class="flex items-center justify-between gap-2.5 {className}">
<div class="min-w-0 text-xs text-gray-600 dark:text-gray-400 {labelClassName}">
<div class="group/setting-row flex items-center justify-between gap-2.5 {className}">
<label
id={labelId}
for={`${labelId}-control`}
class="min-w-0 text-xs text-gray-600 group-has-[[role=switch]:enabled]/setting-row:cursor-pointer group-has-[[role=switch]:disabled]/setting-row:cursor-not-allowed transition-colors duration-150 group-hover/setting-row:text-gray-900 group-focus-within/setting-row:text-gray-900 dark:text-gray-400 dark:group-hover/setting-row:text-white dark:group-focus-within/setting-row:text-white {labelClassName}"
>
<slot name="label">{label}</slot>
</div>
</label>
<div class="min-w-0">
<slot />
<slot {labelId} />
</div>
</div>

View file

@ -35,7 +35,7 @@
<Switch.Root
bind:checked={state}
{disabled}
{id}
id={id || (ariaLabelledbyId ? `${ariaLabelledbyId}-control` : '')}
aria-labelledby={ariaLabelledbyId || undefined}
aria-label={ariaLabel || undefined}
class="focus-ring relative h-4 min-h-4 w-7 shrink-0 cursor-pointer rounded-full mx-[0.0625rem] transition-colors duration-150 disabled:cursor-not-allowed disabled:opacity-50 {($settings?.highContrastMode ??