frontend module conversion) ui-state was the smallest, most isolated module: 35 lines, zero legacy- global dependencies, single concern (localStorage helpers under the 'ped_ui/' namespace). Ideal first migration to validate the strangler- fig pattern end-to-end. Changes: - New: client/ui-state.ts — exports get/set/del + UIState bundle. Keeps (window as any).UIState = UIState assignment so the 10+ legacy consumers (sub-nav.js, peGuide.js, app.js, etc.) keep working without modification. As each consumer is migrated, it will replace the window.UIState read with an explicit import. - client/main.ts: import './ui-state' so it gets bundled into main.js. - scripts/build-client.mjs: explicit ENTRIES list (just 'main.ts' for now) — was scanning every top-level .ts as an entry, which produced duplicate ui-state.js bundle. - public/index.html: <script defer src="/js/ui-state.js"> removed; the TS bundle (/dist/main.js) now provides window.UIState. - public/js/ui-state.js: deleted (now lives in client/). Verification: - npm run typecheck:client → 0 errors - npm run build:client → 349-byte main.js bundle (gzipped will be ~200B) - 46/46 unit tests pass - The 10 cross-file consumers of UIState.get/set/del still work because the window assignment lives in the bundle. Pattern documented for next migrations: each new client/X.ts is imported as a side-effect from main.ts. The window-bridge stays until every consumer also moves to ES imports.
37 lines
1.6 KiB
TypeScript
37 lines
1.6 KiB
TypeScript
// ============================================================
|
|
// client/ui-state.ts — sub-pill / sub-tab persistence across browser restart.
|
|
//
|
|
// First file migrated out of public/js/ as ES module + TypeScript.
|
|
// Tab-level selection (ped_last_tab) is handled in app.js (still legacy).
|
|
// This file persists finer-grained choices that would otherwise reset
|
|
// to defaults when the user closes the browser, signs out / back in,
|
|
// or reloads the page — because _componentCache is in-memory only.
|
|
//
|
|
// All keys live under "ped_ui/" in localStorage. Reads and writes are
|
|
// wrapped in try/catch — localStorage can throw in some contexts
|
|
// (Safari private mode, storage quotas), and a persistence failure
|
|
// must never break the UI.
|
|
//
|
|
// Compat: window.UIState is still assigned for the 10+ legacy consumers
|
|
// (app.js, sub-nav.js, several IIFE modules). Once those are migrated
|
|
// to ES module imports, the window assignment can be removed.
|
|
// ============================================================
|
|
|
|
const PREFIX = 'ped_ui/';
|
|
|
|
export function get(key: string): string | null {
|
|
try { return localStorage.getItem(PREFIX + key); } catch (e) { return null; }
|
|
}
|
|
|
|
export function set(key: string, value: string): void {
|
|
try { localStorage.setItem(PREFIX + key, value); } catch (e) { /* swallow — see header */ }
|
|
}
|
|
|
|
export function del(key: string): void {
|
|
try { localStorage.removeItem(PREFIX + key); } catch (e) { /* swallow */ }
|
|
}
|
|
|
|
export const UIState = { get, set, del };
|
|
|
|
// Legacy bridge — kept until every consumer is migrated to ES imports.
|
|
(window as any).UIState = UIState;
|