POC versioning slider

This commit is contained in:
Marcel Mraz 2024-11-27 15:12:00 +01:00
parent 725c25c966
commit 59a0653fd4
No known key found for this signature in database
GPG key ID: 4EBD6E62DC830CD2
5 changed files with 155 additions and 21 deletions

View file

@ -16,6 +16,7 @@ import type {
FileId,
NonDeletedExcalidrawElement,
OrderedExcalidrawElement,
SceneElementsMap,
} from "../packages/excalidraw/element/types";
import { useCallbackRefState } from "../packages/excalidraw/hooks/useCallbackRefState";
import { t } from "../packages/excalidraw/i18n";
@ -134,6 +135,10 @@ import DebugCanvas, {
import { AIComponents } from "./components/AI";
import { ExcalidrawPlusIframeExport } from "./ExcalidrawPlusIframeExport";
import { isElementLink } from "../packages/excalidraw/element/elementLink";
import type { ElementsChange } from "../packages/excalidraw/change";
import Slider from "rc-slider";
import "rc-slider/assets/index.css";
polyfill();
@ -365,16 +370,26 @@ const ExcalidrawWrapper = () => {
const [, setShareDialogState] = useAtom(shareDialogStateAtom);
const [collabAPI] = useAtom(collabAPIAtom);
const [syncAPI] = useAtom(syncAPIAtom);
const [nextVersion, setNextVersion] = useState(-1);
const currentVersion = useRef(-1);
const [acknowledgedChanges, setAcknowledgedChanges] = useState<
ElementsChange[]
>([]);
const [isCollaborating] = useAtomWithInitialValue(isCollaboratingAtom, () => {
return isCollaborationLink(window.location.href);
});
const collabError = useAtomValue(collabErrorIndicatorAtom);
useEffect(() => {
const interval = setInterval(() => {
setAcknowledgedChanges([...(syncAPI?.acknowledgedChanges ?? [])]);
}, 250);
syncAPI?.reconnect();
return () => {
syncAPI?.disconnect();
clearInterval(interval);
};
}, [syncAPI]);
@ -807,6 +822,44 @@ const ExcalidrawWrapper = () => {
},
};
const debouncedTimeTravel = debounce((value: number) => {
let elements = new Map(
excalidrawAPI?.getSceneElements().map((x) => [x.id, x]),
);
let changes: ElementsChange[] = [];
const goingLeft =
currentVersion.current === -1 || value - currentVersion.current <= 0;
if (goingLeft) {
changes = acknowledgedChanges
.slice(value)
.reverse()
.map((x) => x.inverse());
} else {
changes = acknowledgedChanges.slice(currentVersion.current, value) ?? [];
}
for (const change of changes) {
[elements] = change.applyTo(
elements as SceneElementsMap,
excalidrawAPI?.store.snapshot.elements!,
);
}
excalidrawAPI?.updateScene({
appState: {
...excalidrawAPI?.getAppState(),
viewModeEnabled: value !== acknowledgedChanges.length,
},
elements: Array.from(elements.values()),
storeAction: StoreAction.UPDATE,
});
currentVersion.current = value;
}, 0);
return (
<div
style={{ height: "100%" }}
@ -814,6 +867,23 @@ const ExcalidrawWrapper = () => {
"is-collaborating": isCollaborating,
})}
>
<Slider
style={{
position: "fixed",
bottom: "25px",
zIndex: 999,
width: "60%",
left: "25%",
}}
step={1}
min={0}
max={acknowledgedChanges.length}
value={nextVersion === -1 ? acknowledgedChanges.length : nextVersion}
onChange={(value) => {
setNextVersion(value as number);
debouncedTimeTravel(value as number);
}}
/>
<Excalidraw
excalidrawAPI={excalidrawRefCallback}
onChange={onChange}

View file

@ -33,6 +33,7 @@
"i18next-browser-languagedetector": "6.1.4",
"idb-keyval": "6.0.3",
"jotai": "2.11.0",
"rc-slider": "11.1.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"socket.io-client": "4.7.2",