113 lines
2.8 KiB
TypeScript
113 lines
2.8 KiB
TypeScript
"use client"
|
|
|
|
import { useCallback, useEffect, useState } from "react"
|
|
import {
|
|
DEFAULT_PAGE_FORMAT_ID,
|
|
type PageFormatId,
|
|
} from "@/lib/drive/page-formats"
|
|
|
|
export type DocsViewSettings = {
|
|
pageFormatId: PageFormatId
|
|
zoom: number
|
|
spellcheck: boolean
|
|
chromeCollapsed: boolean
|
|
}
|
|
|
|
const STORAGE_KEY = "ultidrive-docs-view-settings"
|
|
|
|
const DEFAULT_SETTINGS: DocsViewSettings = {
|
|
pageFormatId: DEFAULT_PAGE_FORMAT_ID,
|
|
zoom: 100,
|
|
spellcheck: true,
|
|
chromeCollapsed: false,
|
|
}
|
|
|
|
const ZOOM_MIN = 50
|
|
const ZOOM_MAX = 200
|
|
const ZOOM_STEP = 10
|
|
|
|
export function clampZoom(value: number): number {
|
|
return Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, Math.round(value / ZOOM_STEP) * ZOOM_STEP))
|
|
}
|
|
|
|
function readSettings(): DocsViewSettings {
|
|
if (typeof localStorage === "undefined") return DEFAULT_SETTINGS
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY)
|
|
if (!raw) return DEFAULT_SETTINGS
|
|
const parsed = JSON.parse(raw) as Partial<DocsViewSettings>
|
|
return {
|
|
pageFormatId: parsed.pageFormatId ?? DEFAULT_PAGE_FORMAT_ID,
|
|
zoom: clampZoom(parsed.zoom ?? DEFAULT_SETTINGS.zoom),
|
|
spellcheck: parsed.spellcheck ?? DEFAULT_SETTINGS.spellcheck,
|
|
chromeCollapsed: parsed.chromeCollapsed ?? DEFAULT_SETTINGS.chromeCollapsed,
|
|
}
|
|
} catch {
|
|
return DEFAULT_SETTINGS
|
|
}
|
|
}
|
|
|
|
function writeSettings(settings: DocsViewSettings) {
|
|
if (typeof localStorage === "undefined") return
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))
|
|
}
|
|
|
|
export function useDocsViewSettings() {
|
|
const [settings, setSettings] = useState<DocsViewSettings>(DEFAULT_SETTINGS)
|
|
|
|
useEffect(() => {
|
|
setSettings(readSettings())
|
|
}, [])
|
|
|
|
const setPageFormatId = useCallback((pageFormatId: PageFormatId) => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, pageFormatId }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const setZoom = useCallback((zoom: number) => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, zoom: clampZoom(zoom) }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const setSpellcheck = useCallback((spellcheck: boolean) => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, spellcheck }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleSpellcheck = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, spellcheck: !prev.spellcheck }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleChromeCollapsed = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, chromeCollapsed: !prev.chromeCollapsed }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
return {
|
|
settings,
|
|
setPageFormatId,
|
|
setZoom,
|
|
setSpellcheck,
|
|
toggleSpellcheck,
|
|
toggleChromeCollapsed,
|
|
zoomMin: ZOOM_MIN,
|
|
zoomMax: ZOOM_MAX,
|
|
}
|
|
}
|