WIP jordan
This commit is contained in:
18
app/utils/refDebounced.ts
Normal file
18
app/utils/refDebounced.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ref, watch, type Ref } from 'vue'
|
||||
|
||||
/** Debounced mirror of a ref (no @vueuse dependency). */
|
||||
export function refDebounced<T>(source: Ref<T>, ms: number): Ref<T> {
|
||||
const debounced = ref(source.value) as Ref<T>
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
watch(
|
||||
source,
|
||||
(v) => {
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
debounced.value = v
|
||||
}, ms)
|
||||
},
|
||||
{ flush: 'sync' }
|
||||
)
|
||||
return debounced
|
||||
}
|
||||
40
app/utils/useLocalStorageRef.ts
Normal file
40
app/utils/useLocalStorageRef.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { ref, watch, type Ref } from 'vue'
|
||||
|
||||
/**
|
||||
* JSON persisted ref for client-only state (replaces @vueuse/useStorage for shallow objects).
|
||||
*/
|
||||
export function useLocalStorageRef<T extends object>(key: string, defaults: () => T): Ref<T> {
|
||||
const data = ref(defaults()) as Ref<T>
|
||||
if (import.meta.server) return data
|
||||
|
||||
try {
|
||||
const raw = localStorage.getItem(key)
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw)
|
||||
const def = defaults()
|
||||
if (Array.isArray(def) && Array.isArray(parsed)) {
|
||||
data.value = parsed as T
|
||||
} else if (def !== null && typeof def === 'object' && !Array.isArray(def)) {
|
||||
data.value = { ...(def as object), ...(parsed as object) } as T
|
||||
} else {
|
||||
data.value = parsed as T
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
watch(
|
||||
data,
|
||||
(v) => {
|
||||
try {
|
||||
localStorage.setItem(key, JSON.stringify(v))
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
return data
|
||||
}
|
||||
Reference in New Issue
Block a user