|
1 | 1 | import React, { useEffect } from 'react'; |
2 | | -import SolutionCode from './components/SolutionCode'; |
3 | | -import D3TwoPointerVisualizer from './components/D3TwoPointerVisualizer'; |
4 | | -import LinkedListCreator from './components/LinkedListCreator'; |
| 2 | +import { TabView, Tab } from './components/TabView'; |
| 3 | +import Header from './components/layout/Header'; |
| 4 | +import VisualizationTab from './components/layout/VisualizationTab'; |
| 5 | +import CodeTab from './components/layout/CodeTab'; |
5 | 6 | import ProblemDescription from './components/ProblemDescription'; |
| 7 | +import LinkedListCreator from './components/LinkedListCreator'; |
| 8 | +import { useStateManagement } from './hooks/algorithmSteps'; |
6 | 9 | import { useAlgorithmSteps } from './hooks/useAlgorithmSteps'; |
7 | | -import { TabView, Tab } from './components/TabView'; |
8 | 10 |
|
9 | 11 | const App: React.FC = () => { |
| 12 | + const { |
| 13 | + showCreator, |
| 14 | + setShowCreator |
| 15 | + } = useStateManagement(); |
| 16 | + |
10 | 17 | const { |
11 | 18 | state, |
12 | | - showCreator, |
13 | | - openCreator, |
14 | | - closeCreator, |
15 | 19 | createRandomExample, |
16 | 20 | createCustomExample, |
17 | 21 | handleStepForward, |
18 | 22 | handleStepBackward, |
19 | 23 | handleSpeedChange, |
20 | 24 | toggleAutoExecution, |
21 | | - resetExecution |
| 25 | + resetExecution, |
| 26 | + handleChangeSolution |
22 | 27 | } = useAlgorithmSteps(); |
23 | 28 |
|
24 | | - // 添加键盘事件监听器 |
25 | 29 | useEffect(() => { |
26 | | - const handleKeyDown = (event: KeyboardEvent) => { |
27 | | - // 确保未在可编辑元素内(如输入框、文本区域等) |
28 | | - if ( |
29 | | - document.activeElement?.tagName === 'INPUT' || |
30 | | - document.activeElement?.tagName === 'TEXTAREA' || |
31 | | - showCreator // 如果创建器对话框打开,不响应键盘 |
32 | | - ) { |
33 | | - return; |
34 | | - } |
35 | | - |
36 | | - // 左箭头 - 上一步 |
37 | | - if (event.key === 'ArrowLeft' && !(state.step === 0 || state.listA.nodes.length === 0)) { |
38 | | - handleStepBackward(); |
39 | | - } |
40 | | - // 右箭头 - 下一步 |
41 | | - else if (event.key === 'ArrowRight' && !(state.completed || state.listA.nodes.length === 0)) { |
42 | | - handleStepForward(); |
43 | | - } |
44 | | - // 空格键 - 暂停/运行 |
45 | | - else if (event.key === ' ' && state.listA.nodes.length > 0) { |
46 | | - event.preventDefault(); // 防止页面滚动 |
47 | | - toggleAutoExecution(); |
48 | | - } |
49 | | - }; |
| 30 | + console.log('App组件 - showCreator状态变化:', showCreator); |
| 31 | + }, [showCreator]); |
50 | 32 |
|
51 | | - window.addEventListener('keydown', handleKeyDown); |
52 | | - |
53 | | - // 清理函数 |
54 | | - return () => { |
55 | | - window.removeEventListener('keydown', handleKeyDown); |
56 | | - }; |
57 | | - }, [state.step, state.completed, state.listA.nodes.length, handleStepBackward, handleStepForward, toggleAutoExecution, showCreator, state.isRunning]); |
| 33 | + console.log('App组件渲染 - showCreator状态值:', showCreator); |
58 | 34 |
|
59 | 35 | return ( |
60 | 36 | <div className="app-container"> |
61 | | - <header className="app-header"> |
62 | | - <h1> |
63 | | - <a href="https://leetcode.cn/problems/intersection-of-two-linked-lists/description/" |
64 | | - target="_blank" |
65 | | - rel="noopener noreferrer" |
66 | | - className="title-link"> |
67 | | - LeetCode 160: 相交链表 |
68 | | - </a> |
69 | | - </h1> |
70 | | - <a |
71 | | - href="https://github.com/fuck-algorithm/leetcode-160-intersection-of-two-linked-lists" |
72 | | - target="_blank" |
73 | | - rel="noopener noreferrer" |
74 | | - className="github-link" |
75 | | - title="View on GitHub" |
76 | | - > |
77 | | - <svg |
78 | | - xmlns="http://www.w3.org/2000/svg" |
79 | | - width="24" |
80 | | - height="24" |
81 | | - viewBox="0 0 24 24" |
82 | | - fill="white" |
83 | | - > |
84 | | - <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/> |
85 | | - </svg> |
86 | | - </a> |
87 | | - </header> |
| 37 | + <Header /> |
88 | 38 |
|
89 | | - <main className="app-content"> |
| 39 | + <main className="app-content" style={{ |
| 40 | + minHeight: '80vh', |
| 41 | + display: 'flex', |
| 42 | + flexDirection: 'column' |
| 43 | + }}> |
90 | 44 | <TabView defaultTab="visualization"> |
91 | 45 | <Tab id="visualization" label="可视化"> |
92 | | - <div className="visualization-tab"> |
93 | | - <div className="control-panel"> |
94 | | - <div className="button-group"> |
95 | | - <button className="control-button create" onClick={openCreator}>创建示例</button> |
96 | | - <div className="step-controls"> |
97 | | - <button |
98 | | - className="control-button prev" |
99 | | - onClick={handleStepBackward} |
100 | | - disabled={state.step === 0 || state.listA.nodes.length === 0} |
101 | | - title="使用键盘左箭头键(←)也可以执行此操作" |
102 | | - > |
103 | | - <span className="button-text">← 上一步</span> |
104 | | - <span className="keyboard-hint">←</span> |
105 | | - </button> |
106 | | - <button |
107 | | - className="control-button step" |
108 | | - onClick={handleStepForward} |
109 | | - disabled={state.completed || state.listA.nodes.length === 0} |
110 | | - title="使用键盘右箭头键(→)也可以执行此操作" |
111 | | - > |
112 | | - <span className="button-text">下一步 →</span> |
113 | | - <span className="keyboard-hint">→</span> |
114 | | - </button> |
115 | | - </div> |
116 | | - <button |
117 | | - className="control-button play" |
118 | | - onClick={toggleAutoExecution} |
119 | | - disabled={state.completed || state.listA.nodes.length === 0} |
120 | | - title="使用空格键可以暂停/继续执行" |
121 | | - > |
122 | | - <span className="button-text">{state.isRunning ? '暂停' : '连续执行'}</span> |
123 | | - <span className="keyboard-hint">Space</span> |
124 | | - </button> |
125 | | - <button |
126 | | - className="control-button reset" |
127 | | - onClick={resetExecution} |
128 | | - disabled={state.step === 0 || state.listA.nodes.length === 0} |
129 | | - > |
130 | | - 重置 |
131 | | - </button> |
132 | | - </div> |
133 | | - |
134 | | - <div className="selection-group"> |
135 | | - <label htmlFor="speed-control">执行延迟:</label> |
136 | | - <input |
137 | | - id="speed-control" |
138 | | - type="range" |
139 | | - min="100" |
140 | | - max="2000" |
141 | | - step="100" |
142 | | - value={state.speed} |
143 | | - onChange={handleSpeedChange} |
144 | | - disabled={state.isRunning} |
145 | | - className="speed-slider" |
146 | | - title="数值越小执行越快,数值越大执行越慢" |
147 | | - /> |
148 | | - <span className="delay-value">{state.speed}ms</span> |
149 | | - </div> |
150 | | - </div> |
151 | | - <div className="visualization-container"> |
152 | | - <D3TwoPointerVisualizer |
153 | | - listA={state.listA} |
154 | | - listB={state.listB} |
155 | | - currentNodeA={state.currentNodeA} |
156 | | - currentNodeB={state.currentNodeB} |
157 | | - intersectionNode={state.intersection} |
158 | | - speed={state.speed} |
159 | | - isRunning={state.isRunning} |
160 | | - message={state.message} |
161 | | - step={state.step} |
162 | | - onAnimationComplete={() => { |
163 | | - // 不需要在这里调用toggleAutoExecution, |
164 | | - // 自动执行逻辑已在useAlgorithmSteps hook的useEffect中处理 |
165 | | - // 调用它会导致自动执行在一步后停止 |
166 | | - }} |
167 | | - /> |
168 | | - </div> |
169 | | - </div> |
| 46 | + <VisualizationTab |
| 47 | + state={state} |
| 48 | + onOpenCreator={() => { |
| 49 | + console.log('App直接设置showCreator为true'); |
| 50 | + setShowCreator(true); |
| 51 | + }} |
| 52 | + onStepForward={handleStepForward} |
| 53 | + onStepBackward={handleStepBackward} |
| 54 | + onSpeedChange={handleSpeedChange} |
| 55 | + onToggleExecution={toggleAutoExecution} |
| 56 | + onReset={resetExecution} |
| 57 | + /> |
170 | 58 | </Tab> |
171 | 59 | <Tab id="problem" label="题目描述"> |
172 | 60 | <ProblemDescription /> |
173 | 61 | </Tab> |
174 | 62 | <Tab id="code" label="算法代码"> |
175 | | - <div className="solution-panel full-height"> |
176 | | - <h3>双指针解法代码</h3> |
177 | | - <SolutionCode solutionType={state.solutionType} /> |
178 | | - </div> |
| 63 | + <CodeTab solutionType={state.solutionType} /> |
179 | 64 | </Tab> |
180 | 65 | </TabView> |
181 | 66 | </main> |
182 | 67 |
|
183 | 68 | {showCreator && ( |
184 | 69 | <LinkedListCreator |
185 | | - onCreateCustom={createCustomExample} |
186 | | - onCreateRandom={createRandomExample} |
187 | | - onClose={closeCreator} |
| 70 | + onCreateCustom={(valuesA, valuesB, intersectionValues) => { |
| 71 | + console.log('App调用createCustomExample'); |
| 72 | + createCustomExample(valuesA, valuesB, intersectionValues); |
| 73 | + console.log('App额外调用setShowCreator(false)'); |
| 74 | + setShowCreator(false); |
| 75 | + }} |
| 76 | + onCreateRandom={() => { |
| 77 | + console.log('App调用createRandomExample'); |
| 78 | + createRandomExample(); |
| 79 | + console.log('App额外调用setShowCreator(false)'); |
| 80 | + setShowCreator(false); |
| 81 | + }} |
| 82 | + onClose={() => { |
| 83 | + console.log('App直接设置showCreator为false'); |
| 84 | + setShowCreator(false); |
| 85 | + }} |
188 | 86 | /> |
189 | 87 | )} |
190 | 88 | </div> |
|
0 commit comments