Copy Create an offline-first feature explainer with Tailwind CSS. Use a three-stage horizontal journey for local save, encrypted queue, and cloud sync, plus a document preview and connection-state control. Show pending change counts, last synced time, and conflict-free status. Add JavaScript that cycles between online, offline, and reconnecting modes, updates the journey indicators, queues simulated edits while offline, and drains the queue after reconnection. <div class="mx-auto max-w-4xl p-6"><section class="rounded-3xl bg-neutral-950 p-6 text-white md:p-8"><div class="flex flex-col justify-between gap-4 md:flex-row md:items-start"><div><span class="rounded-full bg-emerald-400/10 px-3 py-1 text-xs font-medium text-emerald-300">Local-first</span><h2 class="mt-4 text-2xl font-semibold">Keep working through every connection.</h2><p class="mt-2 max-w-xl text-sm leading-6 text-white/55">Changes land on your device first, then sync securely when the network returns.</p></div><select id="syncMode" class="rounded-xl border border-white/10 bg-white/5 px-3 py-2 text-sm text-white"><option value="online">Online</option><option value="offline">Offline</option><option value="reconnecting">Reconnecting</option></select></div><div class="mt-8 grid gap-6 md:grid-cols-[1.3fr_1fr]"><div class="rounded-2xl bg-white p-5 text-neutral-900"><div class="flex items-center justify-between"><div><p class="text-xs text-neutral-400">launch-notes.md</p><p id="syncStamp" class="mt-1 text-xs text-green-700">Synced just now</p></div><button id="simulateEdit" class="rounded-lg bg-neutral-900 px-3 py-2 text-xs font-medium text-white">Make an edit</button></div><div class="mt-5 space-y-3"><div class="h-3 w-2/3 rounded-full bg-neutral-900"></div><div class="h-2 w-full rounded-full bg-neutral-100"></div><div class="h-2 w-5/6 rounded-full bg-neutral-100"></div><div class="h-24 rounded-xl bg-violet-50"></div></div></div><div class="space-y-3" id="syncStages"><div data-stage="local" class="rounded-2xl border border-emerald-400/30 bg-emerald-400/10 p-4"><p class="text-sm font-medium">1 · Saved locally</p><p class="mt-1 text-xs text-white/50">Instant, even without a network.</p></div><div data-stage="queue" class="rounded-2xl border border-white/10 p-4"><div class="flex justify-between"><p class="text-sm font-medium">2 · Encrypted queue</p><span id="queueCount" class="text-xs text-white/50">0 changes</span></div><p class="mt-1 text-xs text-white/50">Held safely until delivery.</p></div><div data-stage="cloud" class="rounded-2xl border border-white/10 p-4"><p class="text-sm font-medium">3 · Cloud synchronized</p><p id="cloudState" class="mt-1 text-xs text-white/50">All collaborators are current.</p></div></div></div></section></div> var mode = document.getElementById("syncMode"); var count = 0; var drainTimer;
function styleStage(name, active) { var stage = document.querySelector('[data-stage="' + name + '"]'); stage.className = active ? "rounded-2xl border border-emerald-400/30 bg-emerald-400/10 p-4" : "rounded-2xl border border-white/10 p-4"; }
function renderSync() { var state = mode.value; styleStage("local", state === "offline"); styleStage("queue", state === "offline" || state === "reconnecting"); styleStage("cloud", state === "online"); document.getElementById("queueCount").textContent = count + (count === 1 ? " change" : " changes"); document.getElementById("syncStamp").textContent = state === "online" ? "Synced just now" : state === "offline" ? "Saved on this device" : "Reconnecting securely"; document.getElementById("cloudState").textContent = state === "online" ? "All collaborators are current." : state === "offline" ? "Waiting for a connection." : "Sending " + count + " queued changes."; }
function reconnect() { clearInterval(drainTimer); drainTimer = setInterval(function () { count = Math.max(0, count - 1); renderSync(); if (!count) { clearInterval(drainTimer); mode.value = "online"; renderSync(); } }, 500); }
mode.addEventListener("change", function () { if (mode.value === "reconnecting") reconnect(); else { clearInterval(drainTimer); renderSync(); } }); document.getElementById("simulateEdit").addEventListener("click", function () { if (mode.value === "online") document.getElementById("syncStamp").textContent = "Synced just now"; else count += 1; renderSync(); }); renderSync();