mirror of
https://github.com/docmost/docmost.git
synced 2026-08-30 18:36:26 +08:00
nodes
This commit is contained in:
@@ -32,3 +32,19 @@
|
|||||||
border-radius: rem(2px);
|
border-radius: rem(2px);
|
||||||
padding: 0 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);
|
editor.commands.setContent(content);
|
||||||
|
|
||||||
|
const specialNodeTypes = new Set([
|
||||||
|
"image",
|
||||||
|
"attachment",
|
||||||
|
"video",
|
||||||
|
"excalidraw",
|
||||||
|
"drawio",
|
||||||
|
"mermaid",
|
||||||
|
"mathBlock",
|
||||||
|
"mathInline",
|
||||||
|
"table",
|
||||||
|
"details",
|
||||||
|
"callout",
|
||||||
|
]);
|
||||||
|
|
||||||
const decorations: Decoration[] = [];
|
const decorations: Decoration[] = [];
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
if (change.toB > change.fromB) {
|
if (change.toB > change.fromB) {
|
||||||
decorations.push(
|
let foundSpecialNode: { node: Node; pos: number } | null = null;
|
||||||
Decoration.inline(change.fromB, change.toB, {
|
docNew.nodesBetween(change.fromB, change.toB, (node, pos) => {
|
||||||
class: "history-diff-added",
|
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;
|
addedCount += 1;
|
||||||
}
|
}
|
||||||
if (change.toA > change.fromA) {
|
if (change.toA > change.fromA) {
|
||||||
const deletedText = docOld.textBetween(change.fromA, change.toA, "");
|
let foundDeletedNode: { node: Node; pos: number } | null = null;
|
||||||
if (deletedText) {
|
docOld.nodesBetween(change.fromA, change.toA, (node, pos) => {
|
||||||
|
if (specialNodeTypes.has(node.type.name)) {
|
||||||
|
foundDeletedNode = { node, pos };
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundDeletedNode) {
|
||||||
decorations.push(
|
decorations.push(
|
||||||
Decoration.widget(change.fromB, () => {
|
Decoration.widget(change.fromB, () => {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.className = "history-diff-deleted";
|
span.className = "history-diff-node-deleted";
|
||||||
span.textContent = deletedText;
|
span.textContent = `[${foundDeletedNode!.node.type.name} removed]`;
|
||||||
return span;
|
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;
|
deletedCount += 1;
|
||||||
}
|
}
|
||||||
@@ -104,7 +159,8 @@ export function HistoryEditor({
|
|||||||
editor.setOptions({
|
editor.setOptions({
|
||||||
editorProps: {
|
editorProps: {
|
||||||
...editor.options.editorProps,
|
...editor.options.editorProps,
|
||||||
decorations: () => (highlightChanges ? decorationSet : DecorationSet.empty),
|
decorations: () =>
|
||||||
|
highlightChanges ? decorationSet : DecorationSet.empty,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, [title, content, editor, previousContent, highlightChanges]);
|
}, [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 { PageHistoryRepo } from '@docmost/db/repos/page/page-history.repo';
|
||||||
import { Page } from '@docmost/db/types/entity.types';
|
import { Page } from '@docmost/db/types/entity.types';
|
||||||
import { isDeepStrictEqual } from 'node:util';
|
import { isDeepStrictEqual } from 'node:util';
|
||||||
|
import { EnvironmentService } from '../../integrations/environment/environment.service';
|
||||||
|
|
||||||
export class UpdatedPageEvent {
|
export class UpdatedPageEvent {
|
||||||
page: Page;
|
page: Page;
|
||||||
@@ -12,7 +13,10 @@ export class UpdatedPageEvent {
|
|||||||
export class HistoryListener {
|
export class HistoryListener {
|
||||||
private readonly logger = new Logger(HistoryListener.name);
|
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')
|
@OnEvent('collab.page.updated')
|
||||||
async handleCreatePageHistory(event: UpdatedPageEvent) {
|
async handleCreatePageHistory(event: UpdatedPageEvent) {
|
||||||
@@ -20,7 +24,9 @@ export class HistoryListener {
|
|||||||
|
|
||||||
const pageCreationTime = new Date(page.createdAt).getTime();
|
const pageCreationTime = new Date(page.createdAt).getTime();
|
||||||
const currentTime = Date.now();
|
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) {
|
if (currentTime - pageCreationTime < FIVE_MINUTES) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user