Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576import type { SaveStatus } from './sync-contract'import { AlertTriangle } from 'lucide-react'import './SaveStatusIndicator.css'
interface SaveStatusIndicatorProps { saveStatus: SaveStatus isConcurrentTabOpen: boolean online?: boolean}
function statusLabel(status: SaveStatus, online: boolean): string { switch (status.state) { case 'idle': return '' case 'saving': return 'Saving...' case 'saved': return online ? 'Saved locally' : 'Saved locally · Offline' case 'error': return `Error: ${status.message}` }}
/** * Displays the current save status and concurrent tab warning in the status bar. * * - idle: invisible (no visual noise) * - saving: "Saving" with cycling dots (text only) * - saved: accent "Saved" (text only) * - error: red dot + error message * * Also shows a warning icon when the same document is open in another tab. */export function SaveStatusIndicator({ saveStatus, isConcurrentTabOpen, online = true }: SaveStatusIndicatorProps) { const label = statusLabel(saveStatus, online)
return ( <> {saveStatus.state !== 'idle' && ( <div className="save-status-indicator" data-state={saveStatus.state} role="status" aria-live="polite" aria-label={label} > <span className="save-status-dot" data-state={saveStatus.state} aria-hidden="true" /> <span className="save-status-label"> {saveStatus.state === 'saving' ? ( <> Saving<span className="save-status-ellipsis" aria-hidden="true"> <span>.</span><span>.</span><span>.</span> </span> </> ) : label} </span> </div> )} {isConcurrentTabOpen && ( <div className="concurrent-tab-warning" role="alert" title="This document is open in another tab. Edits may conflict." > <AlertTriangle aria-hidden="true" /> <span>Open in another tab</span> </div> )} </> )}