;; Offline data layer demo — exercises Phase 7d offline mutation queue. ;; ;; Shows connectivity status, note list, and offline mutation queue. ;; When offline, mutations are queued locally. On reconnect, they sync. ;; ;; Open browser console and look for: ;; "sx:offline queued" — mutation added to queue while offline ;; "sx:offline syncing" — reconnected, replaying queued mutations ;; "sx:offline synced" — individual mutation confirmed by server (defcomp ~offline-demo/content (&key notes server-time) (div (~tw :tokens "space-y-8") (div (~tw :tokens "border-b border-stone-200 pb-6") (h1 (~tw :tokens "text-2xl font-bold text-stone-900") "Offline Data Layer") (p (~tw :tokens "mt-2 text-stone-600") "This page tests Phase 7d offline capabilities. Mutations made while " "offline are queued locally and replayed when connectivity returns.")) ;; Connectivity indicator (div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-6 space-y-3") (h2 (~tw :tokens "text-lg font-semibold text-stone-800") "Status") (dl (~tw :tokens "grid grid-cols-2 gap-2 text-sm") (dt (~tw :tokens "font-medium text-stone-600") "Server time") (dd (~tw :tokens "font-mono text-stone-900") server-time) (dt (~tw :tokens "font-medium text-stone-600") "Notes count") (dd (~tw :tokens "text-stone-900") (str (len notes))) (dt (~tw :tokens "font-medium text-stone-600") "Connectivity") (dd (~tw :tokens "text-stone-900") (span :id "offline-status" (~tw :tokens "inline-flex items-center gap-1.5") (span (~tw :tokens "w-2 h-2 rounded-full bg-green-500")) "Online")))) ;; Note list (div (~tw :tokens "space-y-3") (h2 (~tw :tokens "text-lg font-semibold text-stone-800") "Notes") (div :id "offline-notes" (~tw :tokens "space-y-2") (map (fn (note) (div (~tw :tokens "flex items-center justify-between rounded border border-stone-100 bg-white p-3") (div (~tw :tokens "flex items-center gap-3") (span (~tw :tokens "flex-none rounded-full bg-blue-100 text-blue-700 w-6 h-6 flex items-center justify-center text-xs font-bold") (str (get note "id"))) (span (~tw :tokens "text-stone-900") (get note "text"))) (span (~tw :tokens "text-xs text-stone-400 font-mono") (get note "created")))) notes))) ;; Architecture (div (~tw :tokens "space-y-4") (h2 (~tw :tokens "text-lg font-semibold text-stone-800") "How it works") (div (~tw :tokens "space-y-2") (map-indexed (fn (i step) (div (~tw :tokens "flex items-start gap-3 rounded border border-stone-100 bg-white p-3") (span (~tw :tokens "flex-none rounded-full bg-stone-100 text-stone-700 w-6 h-6 flex items-center justify-center text-xs font-bold") (str (+ i 1))) (div (div (~tw :tokens "font-medium text-stone-900") (get step "label")) (div (~tw :tokens "text-sm text-stone-500") (get step "detail"))))) (list (dict :label "Online mutation" :detail "Routes through submit-mutation (Phase 7c) — optimistic predict, server confirm/revert") (dict :label "Offline detection" :detail "Browser 'offline' event sets _is-online to false. offline-aware-mutation routes to queue") (dict :label "Queue mutation" :detail "Mutation stored in _offline-queue with 'pending' status. Optimistic update applied locally") (dict :label "Reconnect" :detail "Browser 'online' event triggers offline-sync — replays queue in order via execute-action") (dict :label "Sync result" :detail "Each mutation marked 'synced' or 'failed'. Failed mutations stay for manual retry"))))) ;; How to test (div (~tw :tokens "rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm space-y-2") (p (~tw :tokens "font-semibold text-amber-800") "How to test offline behavior") (ol (~tw :tokens "list-decimal list-inside text-amber-700 space-y-1") (li "Open the browser console and Network tab") (li "Navigate to this page via client-side routing") (li "In DevTools, set Network to \"Offline\" mode") (li "The connectivity indicator should change to red/Offline") (li "Watch console for " (code (~tw :tokens "bg-amber-100 px-1 rounded") "sx:offline queued")) (li "Re-enable network — watch for " (code (~tw :tokens "bg-amber-100 px-1 rounded") "sx:offline syncing")) (li "Queued mutations replay and confirm or fail")))))