style(journals): stabilize and standardize all configuration interfaces
- Implemented 'untrack' safeguards in all modal effect blocks to prevent reactivity loops. - Standardized Module, Journal, and Entry configuration with unified tabbed UI and Aether Orange theme. - Fixed critical 'journal is undefined' and ReferenceErrors in configuration modals. - Restored missing button toggles and visibility options in journal-level settings. - Documented Dexie liveQuery '$' prefix mandate in GEMINI.md and project documentation. - Eliminated legacy JournalEntry_SettingsMenu in favor of ModalJournalEntryConfig.
This commit is contained in:
@@ -71,8 +71,9 @@ This document outlines the modernization of the Journals module UI in the Svelte
|
||||
### Phase 4: Polish & Security (ACTIVE)
|
||||
- [x] Implement Auto-Save toggle and visual status indicators.
|
||||
- [x] Extract decryption workflow to non-reactive helper.
|
||||
- [ ] Solidify E2EE passcode system for Journals and Entries.
|
||||
- [x] **Standardize Configuration Modals:** Refactored Module, Journal, and Entry configuration into a unified tabbed UI.
|
||||
- [x] **RESOLVED:** Decryption workflow stability (Fixed via dependency isolation).
|
||||
- [ ] Solidify E2EE passcode system for Journals and Entries.
|
||||
- [ ] Audit encryption flow for Quick Added and Imported entries.
|
||||
- [ ] Integrate Outbound Email sharing.
|
||||
|
||||
@@ -80,14 +81,25 @@ This document outlines the modernization of the Journals module UI in the Svelte
|
||||
|
||||
## 🧠 Lessons Learned: Solving the Svelte 5 Reactivity Hang
|
||||
|
||||
During the implementation of the Privacy/Decryption toggle, we encountered a critical browser hang caused by an infinite reactivity loop. Here is how we resolved it and the patterns we should follow in the future:
|
||||
During the implementation of the Privacy/Decryption toggle and the new Configuration Modals, we encountered critical browser hangs caused by infinite reactivity loops. Here is how we resolved them:
|
||||
|
||||
### 1. Rigorous Dependency Isolation (`untrack`)
|
||||
Svelte 5 runes (`$effect`, `$derived`) automatically track **every** reactive variable read inside them.
|
||||
* **The Problem:** An effect would read `save_status` or `tmp_entry_obj.content` to decide if it should sync, but the act of syncing would update those same variables, re-triggering the effect.
|
||||
* **The Fix:** Wrap any "check-only" state or store reads in `untrack(() => ... )`. This allows the effect to use the value without becoming a dependency of it.
|
||||
* **The Fix:** Wrap any "check-only" state or store reads in `untrack(() => ... )`. This allows the effect to use the value without becoming a dependency of it. This is **CRITICAL** when initializing local state from props inside an effect.
|
||||
|
||||
### 2. Manual Deep Copying vs. Proxies
|
||||
### 2. Standardized Modal UI ("Aether Orange")
|
||||
We have established a unified design language for configuration interfaces:
|
||||
* **Header/Footer:** Use `bg-orange-100 dark:bg-orange-900` with consistent borders.
|
||||
* **Tabs:** Center-aligned tabbed navigation using Skeleton UI `btn` and `variant-filled-primary` / `variant-soft-surface`.
|
||||
* **Icons:** Every tab and primary action should have a Lucide icon for better scannability.
|
||||
* **Explicit Persistence:** All configuration modals must follow an "Edit working copy -> Save Changes" pattern to prevent accidental store/API churn.
|
||||
|
||||
### 3. Dexie LiveQuery Subscriptions
|
||||
* **The Problem:** Accessing `liveQuery` observables directly in templates results in `[object Object]` or `undefined` property errors.
|
||||
* **The Mandate:** ALWAYS use the `$` prefix (e.g. `$lq__obj`) when passing or using data from a Dexie `liveQuery`.
|
||||
|
||||
### 4. Manual Deep Copying vs. Proxies
|
||||
Svelte 5 state is backed by Proxies.
|
||||
* **The Problem:** Using `JSON.parse(JSON.stringify(proxy))` can sometimes trigger unexpected behavior or loops when used inside a reactive context.
|
||||
* **The Fix:** Implement a manual `deep_copy` helper or selective property assignment when syncing "Original" vs "Temporary" state. This ensures `orig_entry_obj` is a plain JS object, making the `has_unsaved_changes` check stable.
|
||||
|
||||
Reference in New Issue
Block a user