mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import { useCallback, useEffect, useLayoutEffect, useState } from 'react'
|
|
|
|
export type FontScale = 0.8 | 0.9 | 1 | 1.1 | 1.2
|
|
|
|
export function getFontScaleOptions(): ReadonlyArray<{ value: FontScale; label: string }> {
|
|
return [
|
|
{ value: 0.8, label: '80%' },
|
|
{ value: 0.9, label: '90%' },
|
|
{ value: 1, label: '100%' },
|
|
{ value: 1.1, label: '110%' },
|
|
{ value: 1.2, label: '120%' },
|
|
]
|
|
}
|
|
|
|
function getFontScaleStorageKey(): string {
|
|
return 'hapi-font-scale'
|
|
}
|
|
|
|
function isBrowser(): boolean {
|
|
return typeof window !== 'undefined' && typeof document !== 'undefined'
|
|
}
|
|
|
|
const useIsomorphicLayoutEffect = isBrowser() ? useLayoutEffect : useEffect
|
|
|
|
function safeGetItem(key: string): string | null {
|
|
if (!isBrowser()) {
|
|
return null
|
|
}
|
|
try {
|
|
return localStorage.getItem(key)
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function safeSetItem(key: string, value: string): void {
|
|
if (!isBrowser()) {
|
|
return
|
|
}
|
|
try {
|
|
localStorage.setItem(key, value)
|
|
} catch {
|
|
// Ignore storage errors
|
|
}
|
|
}
|
|
|
|
function safeRemoveItem(key: string): void {
|
|
if (!isBrowser()) {
|
|
return
|
|
}
|
|
try {
|
|
localStorage.removeItem(key)
|
|
} catch {
|
|
// Ignore storage errors
|
|
}
|
|
}
|
|
|
|
function parseFontScale(raw: string | null): FontScale {
|
|
const value = Number(raw)
|
|
if (value === 0.8 || value === 0.9 || value === 1 || value === 1.1 || value === 1.2) {
|
|
return value
|
|
}
|
|
return 1
|
|
}
|
|
|
|
function applyFontScale(scale: FontScale): void {
|
|
if (!isBrowser()) {
|
|
return
|
|
}
|
|
document.documentElement.style.setProperty('--app-font-scale', String(scale))
|
|
}
|
|
|
|
function getInitialFontScale(): FontScale {
|
|
return parseFontScale(safeGetItem(getFontScaleStorageKey()))
|
|
}
|
|
|
|
export function initializeFontScale(): void {
|
|
applyFontScale(getInitialFontScale())
|
|
}
|
|
|
|
export function useFontScale(): { fontScale: FontScale; setFontScale: (scale: FontScale) => void } {
|
|
const [fontScale, setFontScaleState] = useState<FontScale>(getInitialFontScale)
|
|
|
|
useIsomorphicLayoutEffect(() => {
|
|
applyFontScale(fontScale)
|
|
}, [fontScale])
|
|
|
|
useEffect(() => {
|
|
if (!isBrowser()) {
|
|
return
|
|
}
|
|
|
|
const onStorage = (event: StorageEvent) => {
|
|
if (event.key !== getFontScaleStorageKey()) {
|
|
return
|
|
}
|
|
const nextScale = parseFontScale(event.newValue)
|
|
setFontScaleState(nextScale)
|
|
}
|
|
|
|
window.addEventListener('storage', onStorage)
|
|
return () => window.removeEventListener('storage', onStorage)
|
|
}, [])
|
|
|
|
const setFontScale = useCallback((scale: FontScale) => {
|
|
setFontScaleState(scale)
|
|
|
|
if (scale === 1) {
|
|
safeRemoveItem(getFontScaleStorageKey())
|
|
} else {
|
|
safeSetItem(getFontScaleStorageKey(), String(scale))
|
|
}
|
|
}, [])
|
|
|
|
return { fontScale, setFontScale }
|
|
}
|