refactor(frontend): adopt store/storage helpers; centralize persistence

- errorDialog + hints now use createStore (drop their bespoke listener arrays).
- theme/sidebarLayout/notifications/App filters/Playlists plSort use readMerged/
  readJSON/writeJSON instead of inline try/JSON.parse/catch.
- Stats, SettingsPanel and App's channel filter/view tabs use usePersistedState
  (the 3 sites that reinvented usePersistedTab inline).
- Every siftlode.* key now sourced from the LS registry (no scattered literals).
This commit is contained in:
npeter83 2026-06-26 03:30:19 +02:00
parent 634921b35a
commit 472aba6480
15 changed files with 80 additions and 147 deletions

View file

@ -4,6 +4,8 @@
// `show`, `sort` and `content` moved to the feed toolbar (above the cards); they are no
// longer sidebar widgets. normalizeLayout drops them from any persisted layout automatically.
import { LS, readJSON, writeJSON } from "./storage";
export type WidgetId = "date" | "language" | "topic" | "tags";
export const ALL_WIDGETS: WidgetId[] = ["date", "language", "topic", "tags"];
@ -27,8 +29,6 @@ export const DEFAULT_LAYOUT: SidebarLayout = {
hidden: {},
};
const KEY = "siftlode.sidebarLayout";
// Tolerate stale/partial data: keep only known widgets and append any that are missing
// (e.g. a widget added in a later version) so nothing silently disappears.
export function normalizeLayout(raw: unknown): SidebarLayout {
@ -45,13 +45,9 @@ export function normalizeLayout(raw: unknown): SidebarLayout {
}
export function loadLayout(): SidebarLayout {
try {
return normalizeLayout(JSON.parse(localStorage.getItem(KEY) || "{}"));
} catch {
return DEFAULT_LAYOUT;
}
return normalizeLayout(readJSON<unknown>(LS.sidebarLayout, {}));
}
export function saveLayoutLocal(l: SidebarLayout): void {
localStorage.setItem(KEY, JSON.stringify(l));
writeJSON(LS.sidebarLayout, l);
}