/* vueuse local storage has some strange, buggy side-effects, so were re-implementing just the parts we need here */ import { type Ref, ref, watch } from "vue"; import { match } from "@/utils/utils"; function stringify(value: unknown): string { if (typeof value !== "object") { return `${value}`; } else { return JSON.stringify(value); } } function parse(value: string, type: "string" | "number" | "boolean" | "object"): T { return match(type, { string: () => value as T, number: () => parseFloat(value) as T, boolean: () => (value.toLowerCase().trim() === "true" ? true : false) as T, object: () => JSON.parse(value), }); } export function syncRefToLocalStorage(key: string, refToSync: Ref) { let stored = window.localStorage.getItem(key); if (stored === "null" || stored === "undefined") { stored = null; } const sync = () => { const stringified = stringify(refToSync.value); window.localStorage.setItem(key, stringified); }; if (stored !== null) { try { refToSync.value = parse(stored, typeof refToSync.value as "string" | "number" | "boolean" | "object"); } catch (e) { console.error(`Failed to parse value "${stored}" from local storage key "${key}". Resetting key`); sync(); } } else { sync(); } watch( () => refToSync.value, () => { sync(); }, { deep: true }, ); } export function usePersistentRef(key: string, defaultValue: string): Ref; export function usePersistentRef(key: string, defaultValue: number): Ref; export function usePersistentRef(key: string, defaultValue: T): Ref; export function usePersistentRef( key: string, defaultValue: T, ): Ref { const storageSyncedRef = ref(defaultValue) as Ref; syncRefToLocalStorage(key, storageSyncedRef); return storageSyncedRef; }