返回 presentation-ai
usePresentationHistory.ts
根目录 / src / hooks / presentation / usePresentationHistory.ts
1 "use client";
2
3 import { useEffect, useRef } from "react";
4
5 import { usePresentationHistoryState } from "@/states/presentation-history-state";
6 import { usePresentationState } from "@/states/presentation-state";
7
8 /**
9 * Simplified history hook - only handles keyboard shortcuts and initialization.
10 * History pushing is now done directly in setSlides/updateSlide.
11 */
12 export function usePresentationHistory() {
13 const slides = usePresentationState((s) => s.slides);
14 const theme = usePresentationState((s) => s.theme);
15 const customThemeData = usePresentationState((s) => s.customThemeData);
16 const isGeneratingPresentation = usePresentationState(
17 (s) => s.isGeneratingPresentation,
18 );
19
20 const undo = usePresentationHistoryState((s) => s.undo);
21 const redo = usePresentationHistoryState((s) => s.redo);
22 const canUndo = usePresentationHistoryState((s) => s.canUndo);
23 const canRedo = usePresentationHistoryState((s) => s.canRedo);
24 const initializeHistory = usePresentationHistoryState(
25 (s) => s.initializeHistory,
26 );
27 const clearHistory = usePresentationHistoryState((s) => s.clearHistory);
28 const history = usePresentationHistoryState((s) => s.history);
29
30 useEffect(() => {
31 console.log("history", history);
32 }, [history]);
33
34 const hasInitializedRef = useRef(false);
35
36 // Initialize history when slides are first loaded (after generation completes)
37 useEffect(() => {
38 // Don't initialize during generation
39 if (isGeneratingPresentation) {
40 hasInitializedRef.current = false;
41 return;
42 }
43
44 // Initialize once when we have slides and haven't initialized yet
45 if (
46 slides.length > 0 &&
47 !hasInitializedRef.current &&
48 history.present === null
49 ) {
50 initializeHistory(slides, theme, customThemeData);
51 hasInitializedRef.current = true;
52 }
53 }, [
54 slides,
55 theme,
56 customThemeData,
57 isGeneratingPresentation,
58 initializeHistory,
59 history.present,
60 ]);
61
62 // Clear history when navigating away
63 useEffect(() => {
64 return () => {
65 clearHistory();
66 hasInitializedRef.current = false;
67 };
68 }, [clearHistory]);
69
70 // Keyboard shortcuts for undo/redo
71 useEffect(() => {
72 const handleKeyDown = (event: KeyboardEvent) => {
73 const isModKey = event.ctrlKey || event.metaKey;
74
75 if (!isModKey) return;
76
77 const key = event.key.toLowerCase();
78
79 // Undo: Ctrl+Z or Cmd+Z (but not Shift+Z)
80 if (key === "z" && !event.shiftKey) {
81 event.preventDefault();
82 event.stopPropagation();
83 event.stopImmediatePropagation();
84 if (canUndo) {
85 undo();
86 }
87 return;
88 }
89
90 // Redo: Ctrl+Shift+Z or Cmd+Shift+Z
91 if (key === "z" && event.shiftKey) {
92 event.preventDefault();
93 event.stopPropagation();
94 event.stopImmediatePropagation();
95 if (canRedo) {
96 redo();
97 }
98 return;
99 }
100
101 // Redo: Ctrl+Y or Cmd+Y (alternative)
102 if (key === "y") {
103 event.preventDefault();
104 event.stopPropagation();
105 event.stopImmediatePropagation();
106 if (canRedo) {
107 redo();
108 }
109 return;
110 }
111 };
112
113 // Use capture phase to intercept before Plate.js
114 document.addEventListener("keydown", handleKeyDown, true);
115
116 return () => {
117 document.removeEventListener("keydown", handleKeyDown, true);
118 };
119 }, [undo, redo, canUndo, canRedo]);
120 }
121
121 lines TYPESCRIPT