Skip to content

Commit 96817a1

Browse files
committed
将控制按钮和进度条移到页面底部,宽度100%
1 parent 0e80935 commit 96817a1

File tree

4 files changed

+281
-46
lines changed

4 files changed

+281
-46
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/* 底部控制栏 */
2+
.bottom-control-bar {
3+
position: fixed;
4+
bottom: 0;
5+
left: 0;
6+
right: 0;
7+
background: white;
8+
border-top: 1px solid #e0e0e0;
9+
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
10+
z-index: 1000;
11+
padding: 12px 20px 16px;
12+
}
13+
14+
/* 进度条容器 - 100%宽度 */
15+
.bottom-progress-wrapper {
16+
width: 100%;
17+
margin-bottom: 12px;
18+
}
19+
20+
.bottom-progress-wrapper .progress-bar-container {
21+
margin-bottom: 0;
22+
padding: 0;
23+
}
24+
25+
.bottom-progress-wrapper .progress-bar-track {
26+
height: 10px;
27+
}
28+
29+
.bottom-progress-wrapper .progress-bar-thumb {
30+
width: 18px;
31+
height: 18px;
32+
top: -4px;
33+
}
34+
35+
/* 控制按钮容器 */
36+
.bottom-controls-wrapper {
37+
display: flex;
38+
justify-content: center;
39+
align-items: center;
40+
gap: 24px;
41+
flex-wrap: wrap;
42+
}
43+
44+
/* 播放控制按钮组 */
45+
.playback-controls {
46+
display: flex;
47+
gap: 8px;
48+
align-items: center;
49+
}
50+
51+
.bottom-control-bar .ctrl-btn {
52+
padding: 8px 14px;
53+
background: white;
54+
border: 1px solid #ddd;
55+
border-radius: 6px;
56+
cursor: pointer;
57+
font-size: 13px;
58+
transition: all 0.2s;
59+
display: flex;
60+
align-items: center;
61+
gap: 4px;
62+
}
63+
64+
.bottom-control-bar .ctrl-btn:hover:not(:disabled) {
65+
background: #f0f0f0;
66+
border-color: #bbb;
67+
}
68+
69+
.bottom-control-bar .ctrl-btn:disabled {
70+
opacity: 0.5;
71+
cursor: not-allowed;
72+
}
73+
74+
.bottom-control-bar .ctrl-btn.play {
75+
background: #2196F3;
76+
color: white;
77+
border-color: #2196F3;
78+
padding: 8px 20px;
79+
}
80+
81+
.bottom-control-bar .ctrl-btn.play:hover {
82+
background: #1976D2;
83+
}
84+
85+
.bottom-control-bar .ctrl-btn.play.playing {
86+
background: #FF9800;
87+
border-color: #FF9800;
88+
}
89+
90+
/* 速度控制 */
91+
.speed-controls {
92+
display: flex;
93+
align-items: center;
94+
gap: 8px;
95+
font-size: 13px;
96+
color: #666;
97+
}
98+
99+
.bottom-control-bar .speed-btn {
100+
padding: 6px 14px;
101+
background: white;
102+
border: 1px solid #ddd;
103+
border-radius: 4px;
104+
cursor: pointer;
105+
font-size: 12px;
106+
transition: all 0.2s;
107+
}
108+
109+
.bottom-control-bar .speed-btn:hover {
110+
background: #f0f0f0;
111+
}
112+
113+
.bottom-control-bar .speed-btn.active {
114+
background: #2196F3;
115+
color: white;
116+
border-color: #2196F3;
117+
}
118+
119+
/* 响应式布局 */
120+
@media (max-width: 768px) {
121+
.bottom-control-bar {
122+
padding: 10px 12px 14px;
123+
}
124+
125+
.bottom-controls-wrapper {
126+
gap: 12px;
127+
}
128+
129+
.playback-controls {
130+
gap: 4px;
131+
}
132+
133+
.bottom-control-bar .ctrl-btn {
134+
padding: 6px 10px;
135+
font-size: 12px;
136+
}
137+
138+
.bottom-control-bar .ctrl-btn.play {
139+
padding: 6px 14px;
140+
}
141+
142+
.speed-controls {
143+
font-size: 12px;
144+
gap: 4px;
145+
}
146+
147+
.bottom-control-bar .speed-btn {
148+
padding: 4px 10px;
149+
font-size: 11px;
150+
}
151+
}
152+
153+
@media (max-width: 480px) {
154+
.bottom-controls-wrapper {
155+
flex-direction: column;
156+
gap: 10px;
157+
}
158+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React from 'react';
2+
import './BottomControlBar.css';
3+
import ProgressBar from './ProgressBar';
4+
5+
interface BottomControlBarProps {
6+
currentStep: number;
7+
totalSteps: number;
8+
playAnimation: boolean;
9+
playSpeed: number;
10+
onStepChange: (step: number) => void;
11+
onPrevStep: () => void;
12+
onNextStep: () => void;
13+
onTogglePlay: () => void;
14+
onReset: () => void;
15+
onJumpToEnd: () => void;
16+
onSpeedChange: (speed: number) => void;
17+
}
18+
19+
const BottomControlBar: React.FC<BottomControlBarProps> = ({
20+
currentStep,
21+
totalSteps,
22+
playAnimation,
23+
playSpeed,
24+
onStepChange,
25+
onPrevStep,
26+
onNextStep,
27+
onTogglePlay,
28+
onReset,
29+
onJumpToEnd,
30+
onSpeedChange,
31+
}) => {
32+
if (totalSteps === 0) return null;
33+
34+
return (
35+
<div className="bottom-control-bar">
36+
<div className="bottom-progress-wrapper">
37+
<ProgressBar
38+
currentStep={currentStep}
39+
totalSteps={totalSteps}
40+
onStepChange={onStepChange}
41+
/>
42+
</div>
43+
44+
<div className="bottom-controls-wrapper">
45+
<div className="playback-controls">
46+
<button onClick={onReset} className="ctrl-btn" title="重置 (Home)">
47+
48+
</button>
49+
<button
50+
onClick={onPrevStep}
51+
disabled={currentStep === 0}
52+
className="ctrl-btn"
53+
title="上一步 (←)"
54+
>
55+
⏪ ←
56+
</button>
57+
<button
58+
onClick={onTogglePlay}
59+
className={`ctrl-btn play ${playAnimation ? 'playing' : ''}`}
60+
title="播放/暂停 (空格)"
61+
>
62+
{playAnimation ? "⏸ 暂停" : "▶ 播放"} 空格
63+
</button>
64+
<button
65+
onClick={onNextStep}
66+
disabled={currentStep === totalSteps - 1}
67+
className="ctrl-btn"
68+
title="下一步 (→)"
69+
>
70+
→ ⏩
71+
</button>
72+
<button
73+
onClick={onJumpToEnd}
74+
className="ctrl-btn"
75+
title="跳到结束 (End)"
76+
>
77+
78+
</button>
79+
</div>
80+
81+
<div className="speed-controls">
82+
<span>速度:</span>
83+
<button
84+
className={`speed-btn ${playSpeed === 2000 ? 'active' : ''}`}
85+
onClick={() => onSpeedChange(2000)}
86+
>
87+
88+
</button>
89+
<button
90+
className={`speed-btn ${playSpeed === 1000 ? 'active' : ''}`}
91+
onClick={() => onSpeedChange(1000)}
92+
>
93+
94+
</button>
95+
<button
96+
className={`speed-btn ${playSpeed === 500 ? 'active' : ''}`}
97+
onClick={() => onSpeedChange(500)}
98+
>
99+
100+
</button>
101+
</div>
102+
</div>
103+
</div>
104+
);
105+
};
106+
107+
export default BottomControlBar;

src/components/tree/SymmetricTree.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
display: flex;
1313
flex: 1;
1414
overflow: hidden;
15+
padding-bottom: 100px; /* 为底部控制栏留出空间 */
1516
}
1617

1718
/* 侧边栏 */

src/components/tree/SymmetricTree.tsx

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { traverseTreeBFS } from '../../utils/TreeUtils';
66
import TreeVisualizationNew from './TreeVisualizationNew';
77
import AlgorithmExplanation from './AlgorithmExplanation';
88
import CodeDisplay from './CodeDisplay';
9-
import ProgressBar from './ProgressBar';
9+
import BottomControlBar from './BottomControlBar';
1010
import Header from './Header';
1111
import WeChatFloat from './WeChatFloat';
1212

@@ -707,51 +707,6 @@ const SymmetricTree: React.FC = () => {
707707
</div>
708708

709709
<AlgorithmExplanation />
710-
711-
{algorithmSteps.length > 0 && (
712-
<div className="animation-controls">
713-
<div className="playback-row">
714-
<button onClick={resetAnimation} className="ctrl-btn" title="重置 (Home)"></button>
715-
<button
716-
onClick={() => { setCurrentStep(Math.max(0, currentStep - 1)); setPlayAnimation(false); }}
717-
disabled={currentStep === 0}
718-
className="ctrl-btn"
719-
title="上一步 (←)"
720-
>⏪ ←</button>
721-
<button
722-
onClick={togglePlayAnimation}
723-
className={`ctrl-btn play ${playAnimation ? 'playing' : ''}`}
724-
title="播放/暂停 (空格)"
725-
>
726-
{playAnimation ? "⏸ 暂停" : "▶ 播放"} 空格
727-
</button>
728-
<button
729-
onClick={() => { setCurrentStep(Math.min(algorithmSteps.length - 1, currentStep + 1)); setPlayAnimation(false); }}
730-
disabled={currentStep === algorithmSteps.length - 1}
731-
className="ctrl-btn"
732-
title="下一步 (→)"
733-
>→ ⏩</button>
734-
<button
735-
onClick={() => setCurrentStep(algorithmSteps.length - 1)}
736-
className="ctrl-btn"
737-
title="跳到结束 (End)"
738-
></button>
739-
</div>
740-
741-
<ProgressBar
742-
currentStep={currentStep}
743-
totalSteps={algorithmSteps.length}
744-
onStepChange={(step) => { setCurrentStep(step); setPlayAnimation(false); }}
745-
/>
746-
747-
<div className="speed-row">
748-
<span>速度:</span>
749-
<button className={`speed-btn ${playSpeed === 2000 ? 'active' : ''}`} onClick={() => changePlaySpeed(2000)}></button>
750-
<button className={`speed-btn ${playSpeed === 1000 ? 'active' : ''}`} onClick={() => changePlaySpeed(1000)}></button>
751-
<button className={`speed-btn ${playSpeed === 500 ? 'active' : ''}`} onClick={() => changePlaySpeed(500)}></button>
752-
</div>
753-
</div>
754-
)}
755710
</aside>
756711

757712
<main className="main-content">
@@ -799,6 +754,20 @@ const SymmetricTree: React.FC = () => {
799754
</main>
800755
</div>
801756

757+
<BottomControlBar
758+
currentStep={currentStep}
759+
totalSteps={algorithmSteps.length}
760+
playAnimation={playAnimation}
761+
playSpeed={playSpeed}
762+
onStepChange={(step) => { setCurrentStep(step); setPlayAnimation(false); }}
763+
onPrevStep={() => { setCurrentStep(Math.max(0, currentStep - 1)); setPlayAnimation(false); }}
764+
onNextStep={() => { setCurrentStep(Math.min(algorithmSteps.length - 1, currentStep + 1)); setPlayAnimation(false); }}
765+
onTogglePlay={togglePlayAnimation}
766+
onReset={resetAnimation}
767+
onJumpToEnd={() => setCurrentStep(algorithmSteps.length - 1)}
768+
onSpeedChange={changePlaySpeed}
769+
/>
770+
802771
<WeChatFloat />
803772
</div>
804773
);

0 commit comments

Comments
 (0)