58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
import { z } from 'astro:schema'
|
|
|
|
import { zodParseJSON, type ZodJSON } from './json'
|
|
import { typedObjectEntries } from './objects'
|
|
|
|
function makeTypedLocalStorage<
|
|
Schemas extends Record<string, ZodJSON>,
|
|
T extends {
|
|
[K in keyof Schemas]: {
|
|
schema: Schemas[K]
|
|
default?: z.output<Schemas[K]> | undefined
|
|
key?: string
|
|
}
|
|
},
|
|
>(options: T) {
|
|
return Object.fromEntries(
|
|
typedObjectEntries(options).map(([originalKey, option]) => {
|
|
const key = option.key ?? originalKey
|
|
|
|
return [
|
|
key,
|
|
{
|
|
get: () => {
|
|
return zodParseJSON(option.schema, localStorage.getItem(key), option.default)
|
|
},
|
|
|
|
set: (value: z.input<typeof option.schema>) => {
|
|
localStorage.setItem(key, JSON.stringify(value))
|
|
},
|
|
|
|
remove: () => {
|
|
localStorage.removeItem(key)
|
|
},
|
|
|
|
default: option.default,
|
|
},
|
|
]
|
|
})
|
|
) as {
|
|
[K in keyof T]: {
|
|
get: () => z.output<T[K]['schema']> | (T[K] extends { default: infer D } ? D : undefined)
|
|
set: (value: z.input<T[K]['schema']>) => void
|
|
remove: () => void
|
|
default: z.output<T[K]['schema']> | undefined
|
|
}
|
|
}
|
|
}
|
|
|
|
export const typedLocalStorage = makeTypedLocalStorage({
|
|
pushNotificationsBannerDismissedAt: {
|
|
schema: z.coerce.date(),
|
|
},
|
|
browserNotificationsEnabled: {
|
|
schema: z.boolean(),
|
|
default: false,
|
|
},
|
|
})
|