Files
tolaria/src/hooks/useZoom.ts

84 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect, useCallback } from 'react'
import { getAppStorageItem } from '../constants/appStorage'
import { getVaultConfig, updateVaultConfigField, subscribeVaultConfig } from '../utils/vaultConfigStore'
const MIN_ZOOM = 80
const MAX_ZOOM = 150
const STEP = 10
const DEFAULT_ZOOM = 100
/** Convert vault config zoom (0.81.5 fraction) to percentage (80150). */
function configToPercent(zoom: number | null): number | null {
if (zoom === null) return null
const pct = Math.round(zoom * 100)
return pct >= MIN_ZOOM && pct <= MAX_ZOOM ? pct : null
}
function loadPersistedZoom(): number {
const fromConfig = configToPercent(getVaultConfig().zoom)
if (fromConfig !== null) return fromConfig
// Fallback to localStorage during initial load
const stored = getAppStorageItem('zoom')
if (stored !== null) {
const val = Number(stored)
if (val >= MIN_ZOOM && val <= MAX_ZOOM && val % STEP === 0) return val
}
return DEFAULT_ZOOM
}
function applyZoomToDocument(level: number): void {
document.documentElement.style.setProperty('zoom', `${level}%`)
window.dispatchEvent(new Event('laputa-zoom-change'))
}
function persistZoom(level: number): void {
updateVaultConfigField('zoom', level / 100)
}
export function useZoom() {
const [zoomLevel, setZoomLevel] = useState(() => {
const level = loadPersistedZoom()
// Apply zoom synchronously during init so child components (e.g. CodeMirror)
// measure the correct scale factor in their own effects.
document.documentElement.style.setProperty('zoom', `${level}%`)
return level
})
// Re-sync when vault config becomes available
useEffect(() => {
return subscribeVaultConfig(() => {
const pct = configToPercent(getVaultConfig().zoom)
if (pct !== null) {
setZoomLevel(pct)
applyZoomToDocument(pct)
}
})
}, [])
const zoomIn = useCallback(() => {
setZoomLevel(prev => {
const next = Math.min(MAX_ZOOM, prev + STEP)
applyZoomToDocument(next)
persistZoom(next)
return next
})
}, [])
const zoomOut = useCallback(() => {
setZoomLevel(prev => {
const next = Math.max(MIN_ZOOM, prev - STEP)
applyZoomToDocument(next)
persistZoom(next)
return next
})
}, [])
const zoomReset = useCallback(() => {
setZoomLevel(DEFAULT_ZOOM)
applyZoomToDocument(DEFAULT_ZOOM)
persistZoom(DEFAULT_ZOOM)
}, [])
return { zoomLevel, zoomIn, zoomOut, zoomReset }
}