mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-11-02 10:19:43 +00:00
feat: add live draw feature and clean up docs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
520d0a8444
commit
4c18afaeae
63 files changed
+6728
-12854
No files matched your search
@@ -0,0 +1,97 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import type { StrokeSegment } from '../types';
|
||||
|
||||
interface UseDrawingHistoryReturn {
|
||||
strokes: StrokeSegment[];
|
||||
setStrokes: React.Dispatch<React.SetStateAction<StrokeSegment[]>>;
|
||||
addStroke: (stroke: StrokeSegment) => void;
|
||||
updateStroke: (strokeId: string, points: StrokeSegment['points']) => void;
|
||||
undo: (userId: string) => StrokeSegment | undefined;
|
||||
redo: (userId: string) => StrokeSegment | undefined;
|
||||
canUndo: (userId: string) => boolean;
|
||||
canRedo: (userId: string) => boolean;
|
||||
clearAll: () => void;
|
||||
}
|
||||
|
||||
export function useDrawingHistory(): UseDrawingHistoryReturn {
|
||||
const [strokes, setStrokes] = useState<StrokeSegment[]>([]);
|
||||
const redoStackRef = useRef<StrokeSegment[]>([]);
|
||||
|
||||
const addStroke = useCallback((stroke: StrokeSegment) => {
|
||||
setStrokes((prev) => [...prev, stroke]);
|
||||
// Clear redo stack when new stroke is added
|
||||
redoStackRef.current = [];
|
||||
}, []);
|
||||
|
||||
const updateStroke = useCallback(
|
||||
(strokeId: string, points: StrokeSegment['points']) => {
|
||||
setStrokes((prev) =>
|
||||
prev.map((s) =>
|
||||
s.id === strokeId ? { ...s, points: [...s.points, ...points] } : s
|
||||
)
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const undo = useCallback(
|
||||
(userId: string): StrokeSegment | undefined => {
|
||||
let removed: StrokeSegment | undefined;
|
||||
setStrokes((prev) => {
|
||||
// Find last stroke by this user
|
||||
const idx = [...prev].reverse().findIndex((s) => s.userId === userId);
|
||||
if (idx === -1) return prev;
|
||||
const actualIdx = prev.length - 1 - idx;
|
||||
removed = prev[actualIdx];
|
||||
redoStackRef.current.push(removed);
|
||||
return [...prev.slice(0, actualIdx), ...prev.slice(actualIdx + 1)];
|
||||
});
|
||||
return removed;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const redo = useCallback(
|
||||
(userId: string): StrokeSegment | undefined => {
|
||||
// Find last redo entry for this user
|
||||
const idx = [...redoStackRef.current]
|
||||
.reverse()
|
||||
.findIndex((s) => s.userId === userId);
|
||||
if (idx === -1) return undefined;
|
||||
const actualIdx = redoStackRef.current.length - 1 - idx;
|
||||
const stroke = redoStackRef.current[actualIdx];
|
||||
redoStackRef.current.splice(actualIdx, 1);
|
||||
setStrokes((prev) => [...prev, stroke]);
|
||||
return stroke;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const canUndo = useCallback(
|
||||
(userId: string) => strokes.some((s) => s.userId === userId),
|
||||
[strokes]
|
||||
);
|
||||
|
||||
const canRedo = useCallback(
|
||||
(userId: string) =>
|
||||
redoStackRef.current.some((s) => s.userId === userId),
|
||||
[]
|
||||
);
|
||||
|
||||
const clearAll = useCallback(() => {
|
||||
setStrokes([]);
|
||||
redoStackRef.current = [];
|
||||
}, []);
|
||||
|
||||
return {
|
||||
strokes,
|
||||
setStrokes,
|
||||
addStroke,
|
||||
updateStroke,
|
||||
undo,
|
||||
redo,
|
||||
canUndo,
|
||||
canRedo,
|
||||
clearAll,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user