State Overview
WikiOnitViewer maintains the simplest state model among all wiki viewers: just one custom array plus inherited properties from the base class.Copy
┌─────────────────────────────────────────────────────┐
│ State Inventory │
├─────────────────────────────────────────────────────┤
│ │
│ Own State: │
│ sessions: OnitSession[] │
│ │
│ Inherited State (from WikiBaseViewer): │
│ container: HTMLElement | null │
│ projectSlug: string │
│ category: string │
│ isWip: boolean │
│ settings: WikiViewerSettings │
│ currentDocument: string │
│ │
│ Total: 7 properties (6 inherited + 1 own) │
│ │
└─────────────────────────────────────────────────────┘
Sessions Array
The only state property unique to OnIt:Copy
┌───────────────────────────────────────────────────────────────────────┐
│ SESSIONS ARRAY │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ DECLARATION: │
│ private sessions: OnitSession[] = [] │
│ │
│ CHARACTERISTICS: │
│ ├── Array of parsed session objects │
│ ├── Sorted newest first (descending sortKey) │
│ ├── Populated during loadSessions() │
│ └── Completely replaced on refresh() │
│ │
└───────────────────────────────────────────────────────────────────────┘
Copy
┌───────────────────────────────────────────────────────────────────────┐
│ sessions[0] = { │
│ │
│ path: "/full/path/2025-12-28-14-30-session.md" │
│ name: "2025-12-28-14-30-session.md" │
│ date: "2025-12-28" │
│ time: "14:30" │
│ sessionName: "session" │
│ pattern: 3 │
│ sortKey: "2025-12-28T14:30:00" │
│ status: "active" │
│ │
│ } │
└───────────────────────────────────────────────────────────────────────┘
State Lifecycle
Initialization
Copy
┌─────────────────────────────────────────────────────┐
│ Initialization State Changes │
├─────────────────────────────────────────────────────┤
│ │
│ BEFORE init(): │
│ container: null │
│ sessions: [] │
│ isWip: true (default) │
│ │
│ ↓ init(container, projectSlug, "onit") │
│ │
│ AFTER init(): │
│ container: HTMLElement (assigned) │
│ sessions: [OnitSession, ...] │
│ isWip: true (unchanged) │
│ category: "onit" │
│ settings: loaded from localStorage │
│ │
└─────────────────────────────────────────────────────┘
Toggle Transition
Copy
┌─────────────────────────────────────────────────────┐
│ WIP/Wiki Toggle Effect │
├─────────────────────────────────────────────────────┤
│ │
│ WIP Mode: │
│ isWip: true │
│ sessions: [WIP sessions from wip/onit/] │
│ │
│ ↓ User clicks [Wiki] button │
│ │
│ Wiki Mode: │
│ isWip: false │
│ sessions: [Wiki sessions from wiki/onit/] │
│ │
│ Note: Other properties unchanged │
│ │
└─────────────────────────────────────────────────────┘
Refresh Cycle
Copy
┌─────────────────────────────────────────────────────┐
│ Refresh State Changes │
├─────────────────────────────────────────────────────┤
│ │
│ BEFORE refresh(): │
│ sessions: [old data - may be stale] │
│ │
│ ↓ refresh() called │
│ │
│ AFTER refresh(): │
│ sessions: [new data - fresh from filesystem] │
│ │
│ Note: Complete array replacement │
│ DOM fully re-rendered │
│ Accordion states LOST │
│ │
└─────────────────────────────────────────────────────┘
State Dependencies
Path construction depends on three state properties:Copy
┌───────────────────────────────────────────────────────────────────────┐
│ PATH CALCULATION (getBasePath) │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ BASE = "~/Library/Application Support/monolex/protocols/niia/work" │
│ │
│ FORMULA: │
│ folder = isWip ? "wip" : "wiki" │
│ path = "{base}/{projectSlug}/{folder}/{category}" │
│ │
│ EXAMPLE: │
│ projectSlug = "monolex-006" │
│ isWip = true │
│ category = "onit" │
│ │
│ Result: ~/Library/.../work/monolex-006/wip/onit/ │
│ │
│ Changing ANY dependency changes the filesystem path │
│ and thus the loaded sessions. │
│ │
└───────────────────────────────────────────────────────────────────────┘
Unidirectional Data Flow
State flows in one direction only:Copy
┌─────────────────────────────────────────────────────┐
│ Data Flow │
├─────────────────────────────────────────────────────┤
│ │
│ User Action (click toggle/refresh) │
│ ↓ │
│ Event Handler │
│ ↓ │
│ State Update (isWip, sessions) │
│ ↓ │
│ Re-render (render() called) │
│ ↓ │
│ DOM Updated (content replaced) │
│ ↓ │
│ Event Listeners Attached (to new elements) │
│ ↓ │
│ (Loop back to User Action) │
│ │
│ No reverse flow: DOM → State │
│ │
└─────────────────────────────────────────────────────┘
DOM vs JavaScript State
Clear separation between persistent state and ephemeral UI state: JavaScript State (this.*):sessions: OnitSession[] (source of truth)isWip: booleansettings: ViewerSettings- Persists across renders
- Accordion expanded/collapsed
- Content loaded (
data-loaded) - Arrow rotation
- Scroll position
- Lost on re-render
- JS state is source of truth for data
- DOM state is ephemeral (recreated on render)
- Re-render regenerates DOM from JS state
- No two-way binding
State Reset Pattern
Complete replacement on refresh:Copy
┌───────────────────────────────────────────────────────────────────────┐
│ REFRESH PATTERN │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ refresh() │
│ │ │
│ ├── await this.loadSessions() ← REPLACES this.sessions │
│ │ │
│ └── this.render() ← Re-renders entire DOM │
│ │
│ EFFECT: │
│ ├── No incremental updates │
│ ├── No diffing/patching │
│ ├── Guaranteed consistency │
│ └── Accordion states lost │
│ │
│ TRADE-OFFS: │
│ ├── Simplicity (SMPC principle) │
│ ├── Easy to reason about │
│ ├── Potential performance impact on large lists │
│ └── Loses UI state │
│ │
└───────────────────────────────────────────────────────────────────────┘
Memory Management
Automatic cleanup via garbage collection: On refresh():this.sessions = new array→ Old array becomes unreachable- Container content replaced → Old DOM nodes removed
- JavaScript GC cleans up old arrays
- Browser GC cleans up old DOM nodes
- Event listeners on old nodes auto-removed
Settings Management
User preferences loaded from localStorage:Copy
┌───────────────────────────────────────────────────────────────────────┐
│ WIKI VIEWER SETTINGS │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ INTERFACE: │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ fontSize: string // "12" │ │
│ │ fontWeight: string // "300" │ │
│ │ lineHeight: string // "1.6" │ │
│ │ opacity: string // "75" │ │
│ │ fontFamily: string // "CodexMono, CodexMono EA" │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ LOADING: │
│ For each setting: │
│ value = localStorage.getItem("wikiViewer{Setting}") || default │
│ │
│ DEFAULTS: │
│ fontSize = "12" │
│ fontWeight = "300" │
│ lineHeight = "1.6" │
│ opacity = "75" │
│ fontFamily = "CodexMono, CodexMono EA" │
│ │
│ Settings apply to entire viewer container via getViewerStyles() │
│ │
└───────────────────────────────────────────────────────────────────────┘
State Comparison
OnIt has the simplest state model:| Viewer | Own State Props | Total State | Complexity |
|---|---|---|---|
| OnIt | 1 | 7 | Simplest |
| Prepare | 2 | 8 | Low-Medium |
| Prove | 3 | 9 | Medium |
| Unified | 4 | 10 | Medium-High |
| Docs | 5 | 11 | Highest |
THE CENTER
Simple state enables predictable behavior
Technical Credibility
Single source of truth pattern. Unidirectional data flow. TypeScript type safety via interfaces. Automatic garbage collection for memory management. No manual listener cleanup required.