diff --git a/README.md b/README.md index d2e4df2..b1fc940 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,87 @@ # zulip -A minimal, no-build web app kit using only Lit-based web components via importmaps. +A modern, no-build web application using Lit web components with Zustand state management. +## Architecture Overview -## Quick Start Example +* **Lit-based web components** - Standards-based, framework-agnostic UI +* **No-build tooling** - Import maps only, no bundler required +* **Zustand state management** - Lightweight, vanilla JS store +* **StoreController** - Reactive controller that bridges Zustand and Lit -### 1. Define a Component +## Project Structure + +``` +components/ -> standard lit components, including top-level "app-root" +controllers/ -> lit reactive controllers (such as Zustand<->Lit bridge) +store/ -> defines specific accessor sets +index.html -> entry point with inline importmap and app-root +README.md +``` + +## Data Flow Diagram + +```mermaid +sequenceDiagram + participant User + participant LitComponent + participant StoreController + participant ZustandStore + + User->>LitComponent: Click button + LitComponent->>ZustandStore: Call action (e.g., addItem) + ZustandStore->>ZustandStore: Update state + ZustandStore->>StoreController: Notify subscribers + StoreController->>LitComponent: requestUpdate() + LitComponent->>LitComponent: Re-render + LitComponent->>User: Show updated UI +``` + +## Example + +### 1. Define Store (Zustand Vanilla) + +```javascript +// store/index.js +import { createStore } from 'zustand/vanilla' + +export const store = createStore((set, get) => ({ + count: 0, + increment: () => set(s => ({ count: s.count + 1 })), + decrement: () => set(s => ({ count: s.count - 1 })), +})) +``` + +### 2. Create StoreController (Bridge) + +```javascript +// controllers/store.js +export class StoreController { + constructor(host, store, selector) { + this.host = host + this.store = store + this.selector = selector + host.addController(this) + } + + hostConnected() { + this._unsub = this.store.subscribe((state) => { + const next = this.selector(state) + if (next !== this.value) { + this.value = next + this.host.requestUpdate() + } + }) + this.value = this.selector(this.store.getState()) + } + + hostDisconnected() { + this._unsub?.() + } +} +``` + +### 3. Create Component (Lit + StoreController) ```javascript // components/counter.js @@ -22,16 +98,15 @@ class Counter extends LitElement { } static styles = css` - button { padding: 1rem; font-size: 1.2rem; } + button { padding: 1rem; font-size: 1.2rem; margin: 0.5rem; } ` render() { return html`
Count: ${this.count}
- +Count: ${this.#count.value}
+ +