This commit is contained in:
Philipinho
2026-01-31 19:01:43 +00:00
parent a09e35ba8f
commit cd52acc415
2 changed files with 51 additions and 80 deletions
@@ -3,7 +3,10 @@
light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
border-radius: rem(10px);
padding: rem(12px);
background: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7));
background: light-dark(
var(--mantine-color-gray-0),
var(--mantine-color-dark-7)
);
}
:global(.history-diff-added) {
@@ -16,12 +19,9 @@
position: absolute;
z-index: -1;
inset: 0;
left: rem(-12px);
right: 0;
border-left: rem(4px) solid
light-dark(var(--mantine-color-green-6), var(--mantine-color-green-4));
background: light-dark(var(--mantine-color-green-0), rgba(0, 255, 0, 0.06));
border-radius: rem(6px);
border-radius: rem(4px);
pointer-events: none;
}
@@ -39,8 +39,6 @@
inset: 0;
left: rem(-12px);
right: 0;
border-left: rem(4px) solid
light-dark(var(--mantine-color-red-6), var(--mantine-color-red-4));
border-top: rem(1px) dashed
light-dark(var(--mantine-color-red-4), var(--mantine-color-red-6));
border-right: rem(1px) dashed
@@ -51,5 +49,3 @@
border-radius: rem(6px);
pointer-events: none;
}
@@ -1,14 +1,14 @@
import "@/features/editor/styles/index.css";
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import { EditorContent, useEditor } from "@tiptap/react";
import { mainExtensions } from "@/features/editor/extensions/extensions";
import { Badge, Divider, Group, Text, Title } from "@mantine/core";
import { Decoration, DecorationSet } from "@tiptap/pm/view";
import { computeHistoryBlockDiff } from "@/features/page-history/utils/history-diff";
import classes from "./history-diff.module.css";
import historyClasses from "./history.module.css";
import { recreateTransform } from "@docmost/editor-ext";
import { Node, Schema, DOMSerializer } from "@tiptap/pm/model";
import { Node } from "@tiptap/pm/model";
import { ChangeSet, simplifyChanges } from "prosemirror-changeset";
export interface HistoryEditorProps {
title: string;
@@ -35,90 +35,65 @@ export function HistoryEditor({
});
useEffect(() => {
if (editor && previousContent && content) {
const schema = editor.schema;
if (!editor || !content) return;
let decorationSet = DecorationSet.empty;
let addedCount = 0;
let deletedCount = 0;
if (previousContent) {
try {
console.log(
"previousContent type:",
previousContent?.type,
"content type:",
content?.type,
);
const schema = editor.schema;
const docOld = Node.fromJSON(schema, previousContent);
const docNew = Node.fromJSON(schema, content);
const t0 = performance.now();
const transform = recreateTransform(docOld, docNew, {
const tr = recreateTransform(docOld, docNew, {
complexSteps: true,
wordDiffs: true,
simplifyDiff: true,
});
console.log(
`recreateTransform: ${(performance.now() - t0).toFixed(3)}ms`,
const changeSet = ChangeSet.create(docOld).addSteps(
tr.doc,
tr.mapping.maps,
[],
);
const changes = simplifyChanges(changeSet.changes, docNew);
//console.log(transform);
} catch (e) {
console.error("Node.fromJSON failed:", e);
}
}
}, [editor]);
editor.commands.setContent(content);
useEffect(() => {
if (editor && content) {
let decorationSet = DecorationSet.empty;
let addedCount = 0;
let deletedCount = 0;
if (previousContent) {
try {
const currentDoc = editor.schema.nodeFromJSON(content);
const prevDoc = editor.schema.nodeFromJSON(previousContent);
const {
diffDoc,
addedNodeRanges,
deletedNodeRanges,
addedCount: aCount,
deletedCount: dCount,
} = computeHistoryBlockDiff(currentDoc, prevDoc);
editor.commands.setContent(diffDoc.toJSON());
addedCount = aCount;
deletedCount = dCount;
const decos = addedNodeRanges.map((r) =>
Decoration.node(r.from, r.to, { class: "history-diff-added" }),
);
const deletedDecos = deletedNodeRanges.map((r) =>
Decoration.node(r.from, r.to, { class: "history-diff-deleted" }),
);
decorationSet = DecorationSet.create(diffDoc, [
...decos,
...deletedDecos,
]);
} catch {
decorationSet = DecorationSet.empty;
addedCount = 0;
deletedCount = 0;
editor.commands.setContent(content);
const decorations: Decoration[] = [];
for (const change of changes) {
if (change.toB > change.fromB) {
decorations.push(
Decoration.inline(change.fromB, change.toB, {
class: "history-diff-added",
}),
);
addedCount += 1;
}
if (change.toA > change.fromA) {
deletedCount += 1;
}
}
} else {
decorationSet = DecorationSet.create(docNew, decorations);
} catch (e) {
console.error("History diff failed:", e);
editor.commands.setContent(content);
}
setDiffCounts({ added: addedCount, deleted: deletedCount });
const existingEditorProps = editor.options.editorProps ?? {};
editor.setOptions({
editorProps: {
...existingEditorProps,
decorations: () => decorationSet,
},
});
} else {
editor.commands.setContent(content);
}
setDiffCounts({ added: addedCount, deleted: deletedCount });
editor.setOptions({
editorProps: {
...editor.options.editorProps,
decorations: () => decorationSet,
},
});
}, [title, content, editor, previousContent]);
return (