This commit is contained in:
Philipinho
2026-01-31 21:54:22 +00:00
parent 7d7decb459
commit 70124475ab
3 changed files with 90 additions and 12 deletions
@@ -32,3 +32,19 @@
border-radius: rem(2px);
padding: 0 rem(2px);
}
:global(.history-diff-node-added) {
outline: rem(2px) solid light-dark(var(--mantine-color-green-5), var(--mantine-color-green-7));
outline-offset: rem(2px);
border-radius: rem(4px);
}
:global(.history-diff-node-deleted) {
display: inline-block;
background: light-dark(var(--mantine-color-red-0), rgba(255, 0, 0, 0.1));
border: rem(1px) dashed light-dark(var(--mantine-color-red-4), var(--mantine-color-red-6));
border-radius: rem(4px);
padding: rem(4px) rem(8px);
color: light-dark(var(--mantine-color-red-7), var(--mantine-color-red-4));
font-size: rem(12px);
}
@@ -64,27 +64,82 @@ export function HistoryEditor({
editor.commands.setContent(content);
const specialNodeTypes = new Set([
"image",
"attachment",
"video",
"excalidraw",
"drawio",
"mermaid",
"mathBlock",
"mathInline",
"table",
"details",
"callout",
]);
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",
}),
);
let foundSpecialNode: { node: Node; pos: number } | null = null;
docNew.nodesBetween(change.fromB, change.toB, (node, pos) => {
if (specialNodeTypes.has(node.type.name)) {
foundSpecialNode = { node, pos };
return false;
}
});
if (foundSpecialNode) {
const nodeEnd =
foundSpecialNode.pos + foundSpecialNode.node.nodeSize;
decorations.push(
Decoration.node(foundSpecialNode.pos, nodeEnd, {
class: "history-diff-node-added",
}),
);
} else {
decorations.push(
Decoration.inline(change.fromB, change.toB, {
class: "history-diff-added",
}),
);
}
addedCount += 1;
}
if (change.toA > change.fromA) {
const deletedText = docOld.textBetween(change.fromA, change.toA, "");
if (deletedText) {
let foundDeletedNode: { node: Node; pos: number } | null = null;
docOld.nodesBetween(change.fromA, change.toA, (node, pos) => {
if (specialNodeTypes.has(node.type.name)) {
foundDeletedNode = { node, pos };
return false;
}
});
if (foundDeletedNode) {
decorations.push(
Decoration.widget(change.fromB, () => {
const span = document.createElement("span");
span.className = "history-diff-deleted";
span.textContent = deletedText;
span.className = "history-diff-node-deleted";
span.textContent = `[${foundDeletedNode!.node.type.name} removed]`;
return span;
}),
);
} else {
const deletedText = docOld.textBetween(
change.fromA,
change.toA,
"",
);
if (deletedText) {
decorations.push(
Decoration.widget(change.fromB, () => {
const span = document.createElement("span");
span.className = "history-diff-deleted";
span.textContent = deletedText;
return span;
}),
);
}
}
deletedCount += 1;
}
@@ -104,7 +159,8 @@ export function HistoryEditor({
editor.setOptions({
editorProps: {
...editor.options.editorProps,
decorations: () => (highlightChanges ? decorationSet : DecorationSet.empty),
decorations: () =>
highlightChanges ? decorationSet : DecorationSet.empty,
},
});
}, [title, content, editor, previousContent, highlightChanges]);
@@ -3,6 +3,7 @@ import { OnEvent } from '@nestjs/event-emitter';
import { PageHistoryRepo } from '@docmost/db/repos/page/page-history.repo';
import { Page } from '@docmost/db/types/entity.types';
import { isDeepStrictEqual } from 'node:util';
import { EnvironmentService } from '../../integrations/environment/environment.service';
export class UpdatedPageEvent {
page: Page;
@@ -12,7 +13,10 @@ export class UpdatedPageEvent {
export class HistoryListener {
private readonly logger = new Logger(HistoryListener.name);
constructor(private readonly pageHistoryRepo: PageHistoryRepo) {}
constructor(
private readonly pageHistoryRepo: PageHistoryRepo,
private readonly environmentService: EnvironmentService,
) {}
@OnEvent('collab.page.updated')
async handleCreatePageHistory(event: UpdatedPageEvent) {
@@ -20,7 +24,9 @@ export class HistoryListener {
const pageCreationTime = new Date(page.createdAt).getTime();
const currentTime = Date.now();
const FIVE_MINUTES = 5 * 60 * 1000;
const FIVE_MINUTES = this.environmentService.isDevelopment()
? 30 * 1000
: 5 * 60 * 1000;
if (currentTime - pageCreationTime < FIVE_MINUTES) {
return;