Files
Hy2026/client/src/composables/useThemeMode.ts
T
Rafał Tyński 9854133ac0 feat(client): add high-contrast theme option to theme switcher
Extend theme modes with an explicit high-contrast choice (WCAG 1.4.3) and expose i18n label keys for the theme menu.
2026-10-04 04:04:54 +02:00

39 lines
1.4 KiB
TypeScript

import { computed, watch } from 'vue'
import { usePreferredDark, useStorage } from '@vueuse/core'
import { useTheme } from 'vuetify'
export type ThemeMode = 'light' | 'dark' | 'highContrast' | 'system'
export type ResolvedTheme = 'light' | 'dark' | 'highContrast'
export interface ThemeOption {
value: ThemeMode
labelKey: string
icon: string
}
export const themeOptions: ThemeOption[] = [
{ value: 'light', labelKey: 'theme.light', icon: 'mdi-white-balance-sunny' },
{ value: 'dark', labelKey: 'theme.dark', icon: 'mdi-weather-night' },
{ value: 'highContrast', labelKey: 'theme.highContrast', icon: 'mdi-contrast-circle' },
{ value: 'system', labelKey: 'theme.system', icon: 'mdi-theme-light-dark' },
]
/**
* Color-scheme handling: light / dark / high contrast / follow the system.
* `highContrast` is offered explicitly because the OS `system` preference only
* yields light or dark (WCAG 1.4.3 for low-vision users).
*/
export function useThemeMode() {
const theme = useTheme()
const preferredDark = usePreferredDark()
const mode = useStorage<ThemeMode>('tarninahub-theme', 'system')
const resolved = computed<ResolvedTheme>(() =>
mode.value === 'system' ? (preferredDark.value ? 'dark' : 'light') : mode.value,
)
watch(resolved, (value) => theme.change(value), { immediate: true })
return { mode, resolved, preferredDark, themeOptions }
}