aboutsummaryrefslogtreecommitdiff
path: root/src/stores
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-03-28 08:54:30 +0000
committerFuwn <[email protected]>2026-03-28 08:54:30 +0000
commit802c3f85d1577dc32d670542cb7d2fc4329008dd (patch)
treef67b7b0a114ee42b5ab118870a1e6eab87dacaec /src/stores
parentfix(filters): apply list filter changes immediately (diff)
downloaddue.moe-802c3f85d1577dc32d670542cb7d2fc4329008dd.tar.xz
due.moe-802c3f85d1577dc32d670542cb7d2fc4329008dd.zip
fix(state): restore persisted list UI state
Diffstat (limited to 'src/stores')
-rw-r--r--src/stores/stateBin.ts88
1 files changed, 59 insertions, 29 deletions
diff --git a/src/stores/stateBin.ts b/src/stores/stateBin.ts
index ca61ed77..3fd38a99 100644
--- a/src/stores/stateBin.ts
+++ b/src/stores/stateBin.ts
@@ -18,19 +18,26 @@ let state: StateBin = {};
let changedBeforeHydration = false;
let initialEmission = true;
let applyingStoredValue = false;
+let hydrationPromise = Promise.resolve();
if (browser) {
- localforage.getItem<StateBin>(STORAGE_KEY).then((value) => {
- if (value && typeof value === "object" && !changedBeforeHydration) {
- applyingStoredValue = true;
- baseStore.set(value);
- applyingStoredValue = false;
- }
+ hydrationPromise = localforage
+ .getItem<StateBin>(STORAGE_KEY)
+ .then(async (value): Promise<void> => {
+ if (value && typeof value === "object") {
+ const nextState = changedBeforeHydration
+ ? { ...value, ...state }
+ : value;
- hydrated = true;
+ applyingStoredValue = true;
+ baseStore.set(nextState);
+ applyingStoredValue = false;
+ }
- localforage.setItem(STORAGE_KEY, state);
- });
+ hydrated = true;
+
+ await localforage.setItem(STORAGE_KEY, state);
+ });
baseStore.subscribe((value) => {
state = value;
@@ -44,36 +51,59 @@ if (browser) {
});
}
+export const hydrateStateBin = () => hydrationPromise;
+
const createProxyStore = (store: Writable<StateBin>) => {
- return new Proxy(store, {
- get(target, prop: string) {
- if (prop in target)
- return (target as unknown as Record<string, unknown>)[prop];
+ const keyStores = new Map<
+ string,
+ {
+ subscribe: (run: (value: StateBin[string]) => void) => () => void;
+ set: (value: StateBin[string]) => void;
+ update: (updater: (value: StateBin[string]) => StateBin[string]) => void;
+ }
+ >();
- const derivedKey = writable(get(store)[prop]);
+ const setKeyValue = (prop: string, value: StateBin[string]) => {
+ const state = get(store);
+ const updatedState = { ...state };
- derivedKey.subscribe((value) => {
- const state = get(store);
- const updatedState = { ...state };
+ if (value === null || value === undefined) delete updatedState[prop];
+ else updatedState[prop] = value;
- if (value === null || value === undefined) delete updatedState[prop];
- else updatedState[prop] = value;
+ store.set(updatedState);
+ };
- store.set(updatedState);
- });
+ return new Proxy(store, {
+ get(target, prop: string | symbol) {
+ if (prop in target) return Reflect.get(target, prop);
- return derivedKey;
- },
+ if (typeof prop !== "string") return undefined;
+
+ const existingStore = keyStores.get(prop);
- set(_, prop: string, value) {
- const state = get(store);
- const updatedState = { ...state };
+ if (existingStore) return existingStore;
- if (value === null || value === undefined) delete updatedState[prop];
- else updatedState[prop] = value;
+ const keyStore = {
+ subscribe(run: (value: StateBin[string]) => void) {
+ return store.subscribe((value) => run(value[prop]));
+ },
+ set(value: StateBin[string]) {
+ setKeyValue(prop, value);
+ },
+ update(updater: (value: StateBin[string]) => StateBin[string]) {
+ setKeyValue(prop, updater(get(store)[prop]));
+ },
+ };
+
+ keyStores.set(prop, keyStore);
+
+ return keyStore;
+ },
- store.set(updatedState);
+ set(_, prop: string | symbol, value) {
+ if (typeof prop !== "string") return false;
+ setKeyValue(prop, value);
return true;
},
});