204 lines
5.5 KiB
TypeScript
204 lines
5.5 KiB
TypeScript
"use client"
|
|
|
|
import { useCallback, useEffect, useState } from "react"
|
|
import {
|
|
DEFAULT_PAGE_FORMAT_ID,
|
|
type PageFormatId,
|
|
} from "@/lib/drive/page-formats"
|
|
|
|
export type DocsEditorMode = "edit" | "suggest" | "view"
|
|
|
|
export type DocsCommentsDisplay = "hidden" | "collapsed" | "expanded" | "all"
|
|
|
|
export type DocsViewSettings = {
|
|
pageFormatId: PageFormatId
|
|
zoom: number
|
|
spellcheck: boolean
|
|
chromeCollapsed: boolean
|
|
editorMode: DocsEditorMode
|
|
commentsDisplay: DocsCommentsDisplay
|
|
outlineSidebarExpanded: boolean
|
|
showLayout: boolean
|
|
showRuler: boolean
|
|
showEquationToolbar: boolean
|
|
showNonPrintableChars: boolean
|
|
}
|
|
|
|
const STORAGE_KEY = "ultidrive-docs-view-settings"
|
|
|
|
const DEFAULT_SETTINGS: DocsViewSettings = {
|
|
pageFormatId: DEFAULT_PAGE_FORMAT_ID,
|
|
zoom: 100,
|
|
spellcheck: true,
|
|
chromeCollapsed: false,
|
|
editorMode: "edit",
|
|
commentsDisplay: "expanded",
|
|
outlineSidebarExpanded: false,
|
|
showLayout: true,
|
|
showRuler: true,
|
|
showEquationToolbar: false,
|
|
showNonPrintableChars: 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,
|
|
editorMode: parsed.editorMode ?? DEFAULT_SETTINGS.editorMode,
|
|
commentsDisplay: parsed.commentsDisplay ?? DEFAULT_SETTINGS.commentsDisplay,
|
|
outlineSidebarExpanded:
|
|
parsed.outlineSidebarExpanded ?? DEFAULT_SETTINGS.outlineSidebarExpanded,
|
|
showLayout: parsed.showLayout ?? DEFAULT_SETTINGS.showLayout,
|
|
showRuler: parsed.showRuler ?? DEFAULT_SETTINGS.showRuler,
|
|
showEquationToolbar:
|
|
parsed.showEquationToolbar ?? DEFAULT_SETTINGS.showEquationToolbar,
|
|
showNonPrintableChars:
|
|
parsed.showNonPrintableChars ?? DEFAULT_SETTINGS.showNonPrintableChars,
|
|
}
|
|
} 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
|
|
})
|
|
}, [])
|
|
|
|
const setEditorMode = useCallback((editorMode: DocsEditorMode) => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, editorMode }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const setCommentsDisplay = useCallback((commentsDisplay: DocsCommentsDisplay) => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, commentsDisplay }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleOutlineSidebarExpanded = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, outlineSidebarExpanded: !prev.outlineSidebarExpanded }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleShowLayout = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, showLayout: !prev.showLayout }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleShowRuler = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, showRuler: !prev.showRuler }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleShowEquationToolbar = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, showEquationToolbar: !prev.showEquationToolbar }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const toggleShowNonPrintableChars = useCallback(() => {
|
|
setSettings((prev) => {
|
|
const next = { ...prev, showNonPrintableChars: !prev.showNonPrintableChars }
|
|
writeSettings(next)
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
return {
|
|
settings,
|
|
setPageFormatId,
|
|
setZoom,
|
|
setSpellcheck,
|
|
toggleSpellcheck,
|
|
toggleChromeCollapsed,
|
|
setEditorMode,
|
|
setCommentsDisplay,
|
|
toggleOutlineSidebarExpanded,
|
|
toggleShowLayout,
|
|
toggleShowRuler,
|
|
toggleShowEquationToolbar,
|
|
toggleShowNonPrintableChars,
|
|
zoomMin: ZOOM_MIN,
|
|
zoomMax: ZOOM_MAX,
|
|
}
|
|
}
|