import { useCallback, useEffect, useState } from 'react' import { api, type Document, type DocumentVersion } from '../../api/client' // HistoryPanel is the "time machine" drawer: every snapshot Petal kept of this // document, newest first, with a one-click preview and restore. It's the safety // net that makes trusting Petal with real writing reasonable — a bad edit or a // regretted rewrite is always recoverable, and restoring is itself undoable // (the server keeps a pre_restore copy). Bilingual, zh-first, to match chrome. interface Props { docId: string onClose: () => void // Called after a successful restore with the freshly-restored document so the // editor can reload it. onRestored: (doc: Document) => void } // kindLabel maps a snapshot kind to its bilingual badge + accent color. const KIND: Record = { manual: { zh: '保存点', en: 'Saved point', color: 'var(--color-accent)' }, auto: { zh: '自动', en: 'Auto', color: 'var(--color-muted)' }, pre_restore: { zh: '恢复前', en: 'Before restore', color: 'var(--color-lavender)' }, } // relativeTime renders a UTC timestamp as a gentle "x minutes ago" string. function relativeTime(iso: string): string { const then = new Date(iso).getTime() const secs = Math.max(0, Math.round((Date.now() - then) / 1000)) if (secs < 60) return 'just now · 刚刚' const mins = Math.round(secs / 60) if (mins < 60) return `${mins} min ago · ${mins} 分钟前` const hrs = Math.round(mins / 60) if (hrs < 24) return `${hrs} hr ago · ${hrs} 小时前` const days = Math.round(hrs / 24) return `${days} day${days > 1 ? 's' : ''} ago · ${days} 天前` } export function HistoryPanel({ docId, onClose, onRestored }: Props) { const [versions, setVersions] = useState(null) const [error, setError] = useState(false) const [selected, setSelected] = useState(null) const [preview, setPreview] = useState(null) const [busy, setBusy] = useState(false) const load = useCallback(async () => { setError(false) try { setVersions(await api.listVersions(docId)) } catch { setError(true) } }, [docId]) useEffect(() => { void load() }, [load]) // Escape closes the drawer. useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } window.addEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey) }, [onClose]) const choose = useCallback( async (v: DocumentVersion) => { setSelected(v) setPreview(null) try { setPreview(await api.getVersion(docId, v.id)) } catch { setPreview(null) } }, [docId], ) const restore = useCallback(async () => { if (!selected) return setBusy(true) try { const doc = await api.restoreVersion(docId, selected.id) onRestored(doc) onClose() } catch { setBusy(false) } }, [docId, selected, onRestored, onClose]) return (
{/* Backdrop */}
) }