;; ---------------------------------------------------------------------------
;; Named Stores — page-level signal containers
;; ---------------------------------------------------------------------------

(defcomp ()
  (~docs/page :title "Named Stores"

    (~docs/section :title "The Problem" :id "problem"
      (p "Islands are isolated by default. Signal props work when islands are adjacent, but not when they are:")
      (ul (~tw :tokens "space-y-1 text-stone-600 list-disc pl-5")
        (li "Distant in the DOM tree (header badge + drawer island)")
        (li "Defined in different " (code ".sx") " files")
        (li "Destroyed and recreated by htmx swaps"))
      (p "Named stores solve all three. A store is a named collection of signals that lives at " (em "page") " scope, not island scope."))

    (~docs/section :title "def-store / use-store" :id "api"
      (~docs/code :src (highlight ";; Create a named store — called once at page level\n;; The init function creates signals and computeds\n(def-store \"cart\" (fn ()\n  (let ((items (signal (list))))\n    (dict\n      :items items\n      :count (computed (fn () (length (deref items))))\n      :total (computed (fn () (reduce + 0\n               (map (fn (i) (get i \"price\")) (deref items)))))))))\n\n;; Use the store from any island — returns the signal dict\n(defisland ~reactive-islands/named-stores/cart-badge ()\n  (let ((store (use-store \"cart\")))\n    (span :class \"badge bg-violet-100 text-violet-800 px-2 py-1 rounded-full\"\n      (deref (get store \"count\")))))\n\n(defisland ~reactive-islands/named-stores/cart-drawer ()\n  (let ((store (use-store \"cart\")))\n    (div :class \"p-4\"\n      (h2 \"Cart\")\n      (ul (map (fn (item)\n        (li :class \"flex justify-between py-1\"\n          (span (get item \"name\"))\n          (span :class \"text-stone-500\" \"\£\" (get item \"price\"))))\n        (deref (get store \"items\"))))\n      (div :class \"border-t pt-2 font-semibold\"\n        \"Total: \£\" (deref (get store \"total\"))))))" "lisp"))

      (p (code "def-store") " is " (strong "idempotent") " — calling it again with the same name returns the existing store. This means multiple components can call " (code "def-store") " defensively without double-creating."))

    (~docs/section :title "Lifecycle" :id "lifecycle"
      (ol (~tw :tokens "space-y-2 text-stone-600 list-decimal list-inside")
        (li (strong "Page load: ") (code "def-store") " creates the store in a global registry. Signals are initialized.")
        (li (strong "Island hydration: ") "Each island calls " (code "use-store") " to get the shared signal dict. Derefs create subscriptions.")
        (li (strong "Island swap: ") "An island is destroyed by htmx swap. Its effects are cleaned up. But the store " (em "persists") " — it's in the page-level registry, not the island scope.")
        (li (strong "Island recreation: ") "The new island calls " (code "use-store") " again. Gets the same signals. Reconnects reactively. User state is preserved.")
        (li (strong "Full page navigation: ") (code "clear-stores") " wipes the registry. Clean slate.")))

    (~docs/section :title "Combining with event bridge" :id "combined"
      (p "Named stores + event bridge = full lake→island→island communication:")

      (~docs/code :src (highlight ";; Store persists across island lifecycle\n(def-store \"cart\" (fn () ...))\n\n;; Island 1: product page with htmx lake\n(defisland ~reactive-islands/named-stores/product-island ()\n  (let ((store (use-store \"cart\")))\n    ;; Bridge server-rendered \"Add\" buttons to store\n    (bridge-event container \"cart:add\" (get store \"items\")\n      (fn (detail) (append (deref (get store \"items\")) detail)))\n    ;; Lake content swapped via sx-get\n    (div :id \"product-content\" :sx-get \"/products/featured\")))\n\n;; Island 2: cart badge in header (distant in DOM)\n(defisland ~reactive-islands/named-stores/cart-badge ()\n  (let ((store (use-store \"cart\")))\n    (span (deref (get store \"count\")))))" "lisp"))

      (p "User clicks \"Add to Cart\" in server-rendered product content. " (code "cart:add") " event fires. Product island catches it via bridge. Store's " (code "items") " signal updates. Cart badge — in a completely different island — updates reactively because it reads the same signal."))

    (~docs/section :title "Spec" :id "spec"
      (p "Named stores are spec'd in " (code "signals.sx") " (section 12). Three functions:")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Function")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Description")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "(def-store name init-fn)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Create or return existing named store. init-fn returns a dict of signals/computeds."))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "(use-store name)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Get existing store by name. Errors if store doesn't exist."))
            (tr
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "(clear-stores)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Wipe all stores. Called on full page navigation."))))))))


;; ---------------------------------------------------------------------------
;; Plan — the full design document (moved from plans section)
;; ---------------------------------------------------------------------------
