Skip to content

Commit 5bc41e6

Browse files
committed
feat: 完善页面功能 - 添加返回LeetCode Hot 100链接 - 添加GitHub Star数显示(带IndexedDB缓存) - 添加算法思路弹窗 - 添加微信交流群悬浮球 - 完善控制面板(快捷键提示、进度条拖拽、速度记忆) - 添加GitHub Actions自动部署配置
1 parent 2e45552 commit 5bc41e6

File tree

14 files changed

+886
-90
lines changed

14 files changed

+886
-90
lines changed

.github/workflows/deploy.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pages: write
12+
id-token: write
13+
14+
concurrency:
15+
group: "pages"
16+
cancel-in-progress: false
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
25+
- name: Setup Node.js
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: '20'
29+
cache: 'npm'
30+
31+
- name: Install dependencies
32+
run: npm ci
33+
34+
- name: Build
35+
run: npm run build
36+
37+
- name: Setup Pages
38+
uses: actions/configure-pages@v4
39+
40+
- name: Upload artifact
41+
uses: actions/upload-pages-artifact@v3
42+
with:
43+
path: './dist'
44+
45+
deploy:
46+
environment:
47+
name: github-pages
48+
url: ${{ steps.deployment.outputs.page_url }}
49+
runs-on: ubuntu-latest
50+
needs: build
51+
steps:
52+
- name: Deploy to GitHub Pages
53+
id: deployment
54+
uses: actions/deploy-pages@v4

node_modules/.vite/vitest/results.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.module.css

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,55 @@
99
.header {
1010
background: linear-gradient(135deg, #4a90d9 0%, #357abd 100%);
1111
color: white;
12-
padding: 4px 24px;
13-
text-align: center;
12+
padding: 6px 24px;
1413
flex-shrink: 0;
1514
display: flex;
1615
align-items: center;
17-
justify-content: center;
16+
justify-content: space-between;
1817
gap: 16px;
19-
position: relative;
2018
}
2119

22-
.githubLink {
23-
position: absolute;
24-
right: 16px;
25-
top: 50%;
26-
transform: translateY(-50%);
20+
.backLink {
2721
color: white;
22+
text-decoration: none;
23+
font-size: 13px;
2824
opacity: 0.9;
29-
transition: opacity 0.2s, transform 0.2s;
25+
transition: opacity 0.2s;
26+
white-space: nowrap;
27+
flex-shrink: 0;
28+
}
29+
30+
.backLink:hover {
31+
opacity: 1;
32+
text-decoration: underline;
33+
}
34+
35+
.titleArea {
36+
text-align: center;
37+
flex: 1;
38+
}
39+
40+
.headerRight {
3041
display: flex;
3142
align-items: center;
32-
justify-content: center;
43+
gap: 12px;
44+
flex-shrink: 0;
3345
}
3446

35-
.githubLink:hover {
36-
opacity: 1;
37-
transform: translateY(-50%) scale(1.1);
47+
.guideButton {
48+
background: rgba(255, 255, 255, 0.15);
49+
border: none;
50+
color: white;
51+
padding: 6px 12px;
52+
border-radius: 16px;
53+
font-size: 13px;
54+
cursor: pointer;
55+
transition: all 0.2s;
56+
white-space: nowrap;
57+
}
58+
59+
.guideButton:hover {
60+
background: rgba(255, 255, 255, 0.25);
3861
}
3962

4063
.title {

src/App.tsx

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { CodeDisplay } from './components/CodeDisplay';
88
import { TreeVisualization } from './components/TreeVisualization';
99
import { VariableWatchPanel } from './components/VariableWatchPanel';
1010
import { CallStackDisplay } from './components/CallStackDisplay';
11+
import { GitHubStars } from './components/GitHubStars';
12+
import { AlgorithmGuide } from './components/AlgorithmGuide';
13+
import { WeChatFloat } from './components/WeChatFloat';
1114
import { useAnimationController } from './hooks/useAnimationController';
1215
import { buildCallStack } from './core/variableState';
1316
import { generateAnimationSteps } from './core/stepGenerator';
@@ -77,7 +80,7 @@ function App() {
7780
previousStepRef.current = currentStep;
7881
}, [currentStep]);
7982

80-
// 键盘快捷键:左箭头=上一步,右箭头=下一步,空格=播放/暂停
83+
// 键盘快捷键:左箭头=上一步,右箭头=下一步,空格=播放/暂停,R=重置
8184
useEffect(() => {
8285
const handleKeyDown = (e: KeyboardEvent) => {
8386
// 如果焦点在输入框中,不处理快捷键
@@ -106,45 +109,58 @@ function App() {
106109
actions.play();
107110
}
108111
break;
112+
case 'r':
113+
case 'R':
114+
e.preventDefault();
115+
actions.reset();
116+
break;
109117
}
110118
};
111119

112120
window.addEventListener('keydown', handleKeyDown);
113121
return () => window.removeEventListener('keydown', handleKeyDown);
114122
}, [state.isPlaying, state.currentStepIndex, state.totalSteps, actions]);
115123

124+
const [showGuide, setShowGuide] = useState(false);
125+
116126
return (
117127
<div className={styles.container}>
118128
<header className={styles.header}>
119-
<h1 className={styles.title}>
120-
<a
121-
href="https://leetcode.cn/problems/letter-combinations-of-a-phone-number/"
122-
target="_blank"
123-
rel="noopener noreferrer"
124-
className={styles.titleLink}
125-
>
126-
17. 电话号码的字母组合
127-
</a>
128-
</h1>
129-
<p className={styles.subtitle}>回溯算法可视化演示 · 点击标题查看原题</p>
130129
<a
131-
href="https://github.com/fuck-algorithm/leetcode-17-letter-combinations-of-a-phone-number"
130+
href="https://fuck-algorithm.github.io/leetcode-hot-100/"
132131
target="_blank"
133132
rel="noopener noreferrer"
134-
className={styles.githubLink}
135-
title="View on GitHub"
133+
className={styles.backLink}
136134
>
137-
<svg
138-
viewBox="0 0 24 24"
139-
width="24"
140-
height="24"
141-
fill="currentColor"
142-
aria-hidden="true"
143-
>
144-
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
145-
</svg>
135+
← LeetCode Hot 100
146136
</a>
137+
<div className={styles.titleArea}>
138+
<h1 className={styles.title}>
139+
<a
140+
href="https://leetcode.cn/problems/letter-combinations-of-a-phone-number/"
141+
target="_blank"
142+
rel="noopener noreferrer"
143+
className={styles.titleLink}
144+
>
145+
17. 电话号码的字母组合
146+
</a>
147+
</h1>
148+
<p className={styles.subtitle}>回溯算法可视化演示 · 点击标题查看原题</p>
149+
</div>
150+
<div className={styles.headerRight}>
151+
<button
152+
className={styles.guideButton}
153+
onClick={() => setShowGuide(true)}
154+
title="查看算法思路"
155+
>
156+
💡 算法思路
157+
</button>
158+
<GitHubStars />
159+
</div>
147160
</header>
161+
162+
{showGuide && <AlgorithmGuide onClose={() => setShowGuide(false)} />}
163+
<WeChatFloat />
148164

149165
<main className={styles.main}>
150166
<div className={styles.leftPanel}>
@@ -167,6 +183,7 @@ function App() {
167183
onPrev={actions.prevStep}
168184
onReset={actions.reset}
169185
onSpeedChange={actions.setSpeed}
186+
onSeek={actions.goToStep}
170187
/>
171188

172189
<PhoneKeypad

src/components/AlgorithmGuide.module.css

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,126 @@
322322
padding: 4px 10px;
323323
border-radius: 6px;
324324
}
325+
326+
327+
/* 弹窗样式 */
328+
.modalOverlay {
329+
position: fixed;
330+
top: 0;
331+
left: 0;
332+
right: 0;
333+
bottom: 0;
334+
background: rgba(0, 0, 0, 0.5);
335+
display: flex;
336+
align-items: center;
337+
justify-content: center;
338+
z-index: 2000;
339+
animation: fadeIn 0.2s ease;
340+
}
341+
342+
@keyframes fadeIn {
343+
from { opacity: 0; }
344+
to { opacity: 1; }
345+
}
346+
347+
.modal {
348+
background: white;
349+
border-radius: 16px;
350+
width: 90%;
351+
max-width: 600px;
352+
max-height: 80vh;
353+
overflow: hidden;
354+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
355+
animation: slideUp 0.3s ease;
356+
}
357+
358+
@keyframes slideUp {
359+
from {
360+
opacity: 0;
361+
transform: translateY(20px);
362+
}
363+
to {
364+
opacity: 1;
365+
transform: translateY(0);
366+
}
367+
}
368+
369+
.modalHeader {
370+
display: flex;
371+
align-items: center;
372+
justify-content: space-between;
373+
padding: 16px 20px;
374+
background: linear-gradient(135deg, #4a90d9 0%, #357abd 100%);
375+
color: white;
376+
}
377+
378+
.modalTitle {
379+
margin: 0;
380+
font-size: 18px;
381+
font-weight: 600;
382+
}
383+
384+
.closeButton {
385+
background: rgba(255, 255, 255, 0.2);
386+
border: none;
387+
color: white;
388+
width: 32px;
389+
height: 32px;
390+
border-radius: 50%;
391+
cursor: pointer;
392+
font-size: 16px;
393+
display: flex;
394+
align-items: center;
395+
justify-content: center;
396+
transition: background 0.2s;
397+
}
398+
399+
.closeButton:hover {
400+
background: rgba(255, 255, 255, 0.3);
401+
}
402+
403+
.modalContent {
404+
padding: 20px;
405+
overflow-y: auto;
406+
max-height: calc(80vh - 60px);
407+
}
408+
409+
.section {
410+
margin-bottom: 20px;
411+
}
412+
413+
.section:last-child {
414+
margin-bottom: 0;
415+
}
416+
417+
.section h3 {
418+
margin: 0 0 10px 0;
419+
font-size: 15px;
420+
color: #333;
421+
display: flex;
422+
align-items: center;
423+
gap: 8px;
424+
}
425+
426+
.section p {
427+
margin: 0;
428+
font-size: 14px;
429+
color: #555;
430+
line-height: 1.7;
431+
}
432+
433+
.list {
434+
margin: 0;
435+
padding-left: 20px;
436+
font-size: 14px;
437+
color: #555;
438+
line-height: 1.8;
439+
}
440+
441+
.list li {
442+
margin-bottom: 6px;
443+
}
444+
445+
.list strong {
446+
color: #333;
447+
}

0 commit comments

Comments
 (0)