HistoryDiffView.tsx2.4 KBView on GitHub 'use client';
import { ReadOnlyMarkdownView } from '@/components/read-only-markdown-view';
import { DiffText } from '@/modules/cedar-os/src/cedar-os-components/diffs/DiffText';
export type HistoryDiffMode = 'formatted' | 'diff';
export interface HistoryDiffViewProps {
/** The selected version's markdown, or null while loading / nothing selected. */
markdown: string | null;
/** The previous session's markdown — needed for `mode='diff'`. Null for the
* first session (no previous) or while loading. */
previousMarkdown: string | null;
/** `formatted` renders via the read-only TipTap editor (full rich formatting,
* no diff). `diff` renders the markdown source via DiffText with inline
* added/removed highlights. Falls back to formatted when there is no
* previous version to diff against. */
mode: HistoryDiffMode;
isLoading: boolean;
}
/**
* Renders the selected historical version of a document.
*
* - `mode='formatted'` (default): the markdown is parsed by the same TipTap
* + Markdown stack as the live editor, with `editable: false`. Headings,
* lists, code blocks, tables all look identical to the live editor.
* - `mode='diff'`: DiffText renders the markdown source with previous-vs-
* selected word-level highlights (insertions in green, deletions in red
* strikethrough). Raw markdown text — no rich-text rendering — because
* diff overlays don't compose with parsed ProseMirror nodes.
*/
export function HistoryDiffView({
markdown,
previousMarkdown,
mode,
isLoading,
}: HistoryDiffViewProps) {
if (isLoading && markdown == null) {
return (
<div className="text-sm text-muted-foreground" role="status">
Loading version…
</div>
);
}
if (markdown == null) {
return (
<div className="text-sm italic text-muted-foreground">
Select a version on the right to preview it.
</div>
);
}
if (mode === 'diff' && previousMarkdown != null) {
return (
<div
data-testid="history-diff"
className="whitespace-pre-wrap font-sans text-sm leading-relaxed"
>
<DiffText
oldText={previousMarkdown}
newText={markdown}
diffMode="words"
showRemoved={true}
animateChanges={false}
/>
</div>
);
}
return (
<div data-testid="history-version">
<ReadOnlyMarkdownView markdown={markdown} />
</div>
);
}