Initial commit: OmniAI Web Frontend
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { useCallback, useRef } from "react";
|
||||
|
||||
export interface CanvasHistorySnapshot {
|
||||
textNodes: unknown[];
|
||||
imageNodes: unknown[];
|
||||
videoNodes: unknown[];
|
||||
manualLinks: unknown[];
|
||||
nodePackages: unknown[];
|
||||
}
|
||||
|
||||
interface CanvasHistoryState {
|
||||
past: CanvasHistorySnapshot[];
|
||||
future: CanvasHistorySnapshot[];
|
||||
}
|
||||
|
||||
const MAX_HISTORY = 50;
|
||||
|
||||
export function useCanvasHistory() {
|
||||
const historyRef = useRef<CanvasHistoryState>({ past: [], future: [] });
|
||||
const lastPushRef = useRef<number>(0);
|
||||
|
||||
const pushSnapshot = useCallback((snapshot: CanvasHistorySnapshot) => {
|
||||
const now = Date.now();
|
||||
// Debounce: skip if pushed within 300ms (e.g. rapid drag moves)
|
||||
if (now - lastPushRef.current < 300) return;
|
||||
lastPushRef.current = now;
|
||||
|
||||
const history = historyRef.current;
|
||||
history.past = [...history.past.slice(-(MAX_HISTORY - 1)), snapshot];
|
||||
history.future = [];
|
||||
}, []);
|
||||
|
||||
const undo = useCallback(
|
||||
(currentSnapshot: CanvasHistorySnapshot): CanvasHistorySnapshot | null => {
|
||||
const history = historyRef.current;
|
||||
if (!history.past.length) return null;
|
||||
const previous = history.past[history.past.length - 1];
|
||||
history.past = history.past.slice(0, -1);
|
||||
history.future = [...history.future, currentSnapshot];
|
||||
return previous;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const redo = useCallback(
|
||||
(currentSnapshot: CanvasHistorySnapshot): CanvasHistorySnapshot | null => {
|
||||
const history = historyRef.current;
|
||||
if (!history.future.length) return null;
|
||||
const next = history.future[history.future.length - 1];
|
||||
history.future = history.future.slice(0, -1);
|
||||
history.past = [...history.past, currentSnapshot];
|
||||
return next;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const canUndo = useCallback(() => historyRef.current.past.length > 0, []);
|
||||
const canRedo = useCallback(() => historyRef.current.future.length > 0, []);
|
||||
|
||||
const clear = useCallback(() => {
|
||||
historyRef.current = { past: [], future: [] };
|
||||
}, []);
|
||||
|
||||
return { pushSnapshot, undo, redo, canUndo, canRedo, clear };
|
||||
}
|
||||
Reference in New Issue
Block a user