feat: add TodoMVC example with editorial design
Full TodoMVC implementation using Pocketbook's synced atom: - Add, toggle, edit (double-click), destroy todos - Filter: All / Active / Completed - Toggle all, clear completed - Live sync status indicator (online/offline/pending) - Data persists in IndexedDB, syncs to server via Transit Design: Ink & Paper aesthetic — cream paper background with grain texture, Instrument Serif italic header, Newsreader body text, DM Mono UI chrome, terracotta accent with green completion marks, deckled left border on card. Also: - Server now serves static files from resources/public (/ → todomvc.html) - Fix CLJS compilation: resolve close!/put! naming conflicts with core.async, use qualified async/close!, add clojure.string require - Fix unbalanced parens in do-pull! - Remove old placeholder example
This commit is contained in:
@@ -11,7 +11,8 @@
|
||||
"
|
||||
(:require [pocketbook.idb :as idb]
|
||||
[pocketbook.sync :as sync]
|
||||
[cljs.core.async :refer [go go-loop <! >! chan put! close! timeout alts!]]))
|
||||
[clojure.string :as str]
|
||||
[cljs.core.async :as async :refer [go go-loop <! >! chan put! timeout alts!]]))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Connection (IDB handle)
|
||||
@@ -25,17 +26,17 @@
|
||||
(go
|
||||
(let [db (<! (idb/open db-name))]
|
||||
(>! ch {:db db :db-name db-name})
|
||||
(close! ch)))
|
||||
(async/close! ch)))
|
||||
ch))
|
||||
|
||||
(defn close!
|
||||
(defn shutdown!
|
||||
"Close a Pocketbook connection."
|
||||
[{:keys [db atoms]}]
|
||||
;; Stop all sync loops
|
||||
(doseq [[_ sa] @(or atoms (atom {}))]
|
||||
(when-let [stop (:stop-fn sa)]
|
||||
(stop)))
|
||||
(idb/close! db))
|
||||
(idb/close-db! db))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Synced Atom — implements IAtom semantics
|
||||
@@ -122,7 +123,7 @@
|
||||
(.now js/Date))
|
||||
|
||||
(defn- doc-in-group? [group id]
|
||||
(clojure.string/starts-with? id (prefix-str group)))
|
||||
(str/starts-with? id (prefix-str group)))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; IDB ↔ Atom sync
|
||||
@@ -151,7 +152,7 @@
|
||||
(str "last-sync:" (.-group sa))))]
|
||||
(reset! (.-last_sync sa) (or ls 0)))
|
||||
(put! ch true)
|
||||
(close! ch)))
|
||||
(async/close! ch)))
|
||||
ch))
|
||||
|
||||
(defn- write-doc-to-idb!
|
||||
@@ -188,12 +189,12 @@
|
||||
[sa]
|
||||
(go
|
||||
(when-let [opts (.-server_opts sa)]
|
||||
(let [since @(.-last_sync sa)
|
||||
(let [since @(.-last_sync sa)
|
||||
result (<! (sync/pull! opts (.-group sa) since))]
|
||||
(when (:ok result)
|
||||
(let [docs (:docs result)
|
||||
max-ts (reduce max @(.-last_sync sa)
|
||||
(map :updated docs))]
|
||||
(let [docs (:docs result)
|
||||
max-ts (reduce max @(.-last_sync sa)
|
||||
(map :updated docs))]
|
||||
;; Merge each doc into cache
|
||||
(doseq [doc docs]
|
||||
(let [id (:id doc)]
|
||||
@@ -215,7 +216,7 @@
|
||||
;; Update last-sync
|
||||
(reset! (.-last_sync sa) max-ts)
|
||||
(idb/set-meta! (:db (.-conn sa))
|
||||
(str "last-sync:" (.-group sa)) max-ts)))
|
||||
(str "last-sync:" (.-group sa)) max-ts))
|
||||
true)))))
|
||||
|
||||
(defn- do-push!
|
||||
@@ -325,7 +326,7 @@
|
||||
(go
|
||||
(<! (load-from-idb! sa))
|
||||
(put! ready-ch true)
|
||||
(close! ready-ch)
|
||||
(async/close! ready-ch)
|
||||
;; Initial sync
|
||||
(when server-opts
|
||||
(<! (do-sync! sa))
|
||||
|
||||
Reference in New Issue
Block a user