import { useCallback, useEffect, useState } from "react" export enum Key { LAST_VAULT_PATH = "app.state.last_vault_path", RECENTLY_OPENED_VAULTS = "app.state.recently_opened_vaults", PREFERRED_LOCALE = "app.config.locale", ENABLE_AUTO_LOCK = "app.config.enable_auto_lock", AUTO_LOCK_AFTER = "app.config.auto_lock_after", UI_FONT = "app.config.font.ui", MONOSPACE_FONT = "app.config.font.monospace", } interface StoredData { [Key.LAST_VAULT_PATH]: string [Key.RECENTLY_OPENED_VAULTS]: string[] [Key.PREFERRED_LOCALE]: string [Key.ENABLE_AUTO_LOCK]: boolean [Key.AUTO_LOCK_AFTER]: number [Key.UI_FONT]: string [Key.MONOSPACE_FONT]: string } const events = new Map(Object.values(Key).map(key => [key, new Set()])) as { get(key: K): Set<(value: StoredData[Key]) => void> } export function useStorage(key: K) { const [state, setState] = useState(get(key)!) useEffect(() => { events.get(key).add(setState as any) return () => { events.get(key).delete(setState as any) } }, [key]) const setState2 = useCallback( (value: ((value: StoredData[K]) => StoredData[K]) | StoredData[K]) => { set(key, value) }, [key] ) return [state, setState2] as const } export function get(key: K): StoredData[K] | undefined { try { const value = localStorage.getItem(key) return value == null ? undefined : (JSON.parse(value!) as StoredData[K]) } catch {} } export function set( key: K, value: ((value: StoredData[K]) => StoredData[K]) | StoredData[K] ) { try { if (typeof value === "function") { value = value(get(key)!) } localStorage.setItem(key, JSON.stringify(value)) events.get(key).forEach(fn => fn(value as StoredData[K])) } catch (e) { console.error(e) } } export function remove(key: Key) { try { localStorage.removeItem(key) } catch {} } const defaults: typeof set = (key, value) => { if (!(key in localStorage)) { set(key, value) } } defaults(Key.ENABLE_AUTO_LOCK, true) defaults(Key.AUTO_LOCK_AFTER, 180) defaults(Key.RECENTLY_OPENED_VAULTS, []) defaults(Key.UI_FONT, "") defaults(Key.MONOSPACE_FONT, "")