Skip to content

Commit 9e9c382

Browse files
committed
feat(ui): 全面升级终端风格主题和交互组件
重构整个应用的UI风格为终端黑客美学主题,包括: 1. 引入新的主题变量和全局样式 2. 重写侧边栏、高亮框和页面布局组件 3. 添加返回顶部按钮和交互动画效果 4. 优化搜索框和导航按钮的终端风格 5. 更新首页内容展示样式 使用自定义CSS变量实现终端风格的配色方案,增强代码高亮和交互反馈视觉效果
1 parent 87ace16 commit 9e9c382

7 files changed

Lines changed: 916 additions & 426 deletions

File tree

index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,20 @@
2727
<meta name="twitter:description" content="深入理解 Qwen CLI 的内部架构与 AI 工具交互模式" />
2828
<meta name="twitter:image" content="https://tt-a1i.github.io/coding-cli-guide/og.png" />
2929

30+
<!-- Google Fonts: JetBrains Mono + IBM Plex Sans -->
31+
<link rel="preconnect" href="https://fonts.googleapis.com" />
32+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
33+
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
34+
3035
<!-- Favicon -->
3136
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
3237
<link rel="apple-touch-icon" href="/favicon.svg" />
3338

3439
<!-- Canonical -->
3540
<link rel="canonical" href="https://tt-a1i.github.io/coding-cli-guide/" />
3641

37-
<!-- Theme Color -->
38-
<meta name="theme-color" content="#0f172a" />
42+
<!-- Theme Color - Terminal Dark -->
43+
<meta name="theme-color" content="#0a0a0f" />
3944

4045
<!-- Dev Tools -->
4146
<script type="module">

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ function App() {
232232
};
233233

234234
return (
235-
<div className="flex min-h-screen bg-gray-950">
235+
<div className="flex h-screen overflow-hidden bg-gray-950">
236236
{/* Desktop Sidebar */}
237237
<div className="hidden md:block">
238238
<Sidebar activeTab={activeTab} onTabChange={(tab) => navigateToTab(tab)} />

src/components/HighlightBox.tsx

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,41 @@ interface HighlightBoxProps {
88
}
99

1010
const variantStyles = {
11-
default: 'bg-orange-500/10 border-orange-500',
12-
blue: 'bg-cyan-500/10 border-cyan-500',
13-
green: 'bg-green-500/10 border-green-500',
14-
purple: 'bg-purple-500/10 border-purple-500',
15-
red: 'bg-red-500/10 border-red-500',
16-
yellow: 'bg-yellow-500/10 border-yellow-500',
17-
orange: 'bg-orange-500/10 border-orange-500',
11+
default: {
12+
container: 'bg-[var(--amber)]/5 border-[var(--amber)]/30 hover:border-[var(--amber)]/50',
13+
title: 'text-[var(--amber)]',
14+
accent: 'bg-[var(--amber)]',
15+
},
16+
blue: {
17+
container: 'bg-[var(--cyber-blue)]/5 border-[var(--cyber-blue)]/30 hover:border-[var(--cyber-blue)]/50',
18+
title: 'text-[var(--cyber-blue)]',
19+
accent: 'bg-[var(--cyber-blue)]',
20+
},
21+
green: {
22+
container: 'bg-[var(--terminal-green)]/5 border-[var(--terminal-green)]/30 hover:border-[var(--terminal-green)]/50',
23+
title: 'text-[var(--terminal-green)]',
24+
accent: 'bg-[var(--terminal-green)]',
25+
},
26+
purple: {
27+
container: 'bg-purple-500/5 border-purple-500/30 hover:border-purple-500/50',
28+
title: 'text-purple-400',
29+
accent: 'bg-purple-500',
30+
},
31+
red: {
32+
container: 'bg-red-500/5 border-red-500/30 hover:border-red-500/50',
33+
title: 'text-red-400',
34+
accent: 'bg-red-500',
35+
},
36+
yellow: {
37+
container: 'bg-[var(--amber)]/5 border-[var(--amber)]/30 hover:border-[var(--amber)]/50',
38+
title: 'text-[var(--amber)]',
39+
accent: 'bg-[var(--amber)]',
40+
},
41+
orange: {
42+
container: 'bg-[var(--amber)]/5 border-[var(--amber)]/30 hover:border-[var(--amber)]/50',
43+
title: 'text-[var(--amber)]',
44+
accent: 'bg-[var(--amber)]',
45+
},
1846
};
1947

2048
export function HighlightBox({
@@ -26,14 +54,22 @@ export function HighlightBox({
2654
className = '',
2755
}: HighlightBoxProps) {
2856
const style = variant || color || 'default';
57+
const styles = variantStyles[style];
58+
2959
return (
3060
<div
31-
className={`rounded-lg border p-4 my-4 ${variantStyles[style]} ${className}`}
61+
className={`rounded-lg border p-5 my-4 transition-all duration-200 relative overflow-hidden ${styles.container} ${className}`}
3262
>
63+
{/* Decorative corner accent */}
64+
<div className="absolute top-0 left-0 w-8 h-8 pointer-events-none">
65+
<div className={`absolute top-0 left-0 w-full h-[1px] ${styles.accent} opacity-40`} />
66+
<div className={`absolute top-0 left-0 w-[1px] h-full ${styles.accent} opacity-40`} />
67+
</div>
68+
3369
{title && (
34-
<div className="font-bold mb-2 flex items-center gap-2">
35-
{icon && <span>{icon}</span>}
36-
{title}
70+
<div className={`font-bold font-mono mb-3 flex items-center gap-2 ${styles.title}`}>
71+
{icon && <span className="opacity-80">{icon}</span>}
72+
<span>{title}</span>
3773
</div>
3874
)}
3975
{children}

src/components/PageLayout.tsx

Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,48 @@ import { flatNavItems } from '../nav';
33
import { useOutline } from './OutlineContext';
44
import { OutlineProvider } from './OutlineProvider';
55

6+
function BackToTop() {
7+
const [visible, setVisible] = useState(false);
8+
9+
useEffect(() => {
10+
const main = document.querySelector('main');
11+
if (!main) return;
12+
13+
const handleScroll = () => {
14+
setVisible(main.scrollTop > 400);
15+
};
16+
17+
main.addEventListener('scroll', handleScroll);
18+
return () => main.removeEventListener('scroll', handleScroll);
19+
}, []);
20+
21+
const scrollToTop = useCallback(() => {
22+
const main = document.querySelector('main');
23+
if (main) {
24+
main.scrollTo({ top: 0, behavior: 'smooth' });
25+
}
26+
}, []);
27+
28+
if (!visible) return null;
29+
30+
return (
31+
<button
32+
onClick={scrollToTop}
33+
className="fixed bottom-6 right-6 z-50 flex items-center justify-center w-10 h-10 rounded-lg bg-[var(--bg-panel)] border border-[var(--border-subtle)] text-[var(--text-secondary)] hover:border-[var(--terminal-green)] hover:text-[var(--terminal-green)] hover:shadow-[0_0_15px_var(--terminal-green-glow)] transition-all duration-200 group"
34+
title="回到顶部"
35+
>
36+
<svg
37+
className="w-5 h-5 transition-transform group-hover:-translate-y-0.5"
38+
fill="none"
39+
stroke="currentColor"
40+
viewBox="0 0 24 24"
41+
>
42+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 10l7-7m0 0l7 7m-7-7v18" />
43+
</svg>
44+
</button>
45+
);
46+
}
47+
648
function ShareButtons({ activeSectionId }: { activeSectionId: string | null }) {
749
const [copied, setCopied] = useState<'page' | 'section' | null>(null);
850

@@ -42,38 +84,38 @@ function ShareButtons({ activeSectionId }: { activeSectionId: string | null }) {
4284
<div className="flex items-center gap-2 mb-4">
4385
<button
4486
onClick={copyPageLink}
45-
className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg bg-gray-900/30 border border-gray-700 text-gray-300 hover:bg-gray-800/40 hover:border-gray-600 hover:text-cyan-300 transition-colors"
87+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono rounded-md bg-[var(--bg-panel)] border border-[var(--border-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:border-[var(--terminal-green-dim)] hover:text-[var(--terminal-green)] transition-all duration-200"
4688
>
4789
{copied === 'page' ? (
4890
<>
49-
<span className="text-green-400"></span>
50-
<span>已复制</span>
91+
<span className="text-[var(--terminal-green)]"></span>
92+
<span className="text-[var(--terminal-green)]">copied!</span>
5193
</>
5294
) : (
5395
<>
54-
<span>🔗</span>
55-
<span>复制本页链接</span>
96+
<span className="opacity-60">$</span>
97+
<span>cp link</span>
5698
</>
5799
)}
58100
</button>
59101
<button
60102
onClick={copySectionLink}
61103
disabled={!activeSectionId}
62-
className={`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg border transition-colors ${
104+
className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono rounded-md border transition-all duration-200 ${
63105
activeSectionId
64-
? 'bg-gray-900/30 border-gray-700 text-gray-300 hover:bg-gray-800/40 hover:border-gray-600 hover:text-cyan-300'
65-
: 'bg-gray-900/10 border-gray-800 text-gray-600 cursor-not-allowed'
106+
? 'bg-[var(--bg-panel)] border-[var(--border-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:border-[var(--amber-dim)] hover:text-[var(--amber)]'
107+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
66108
}`}
67109
>
68110
{copied === 'section' ? (
69111
<>
70-
<span className="text-green-400"></span>
71-
<span>已复制</span>
112+
<span className="text-[var(--terminal-green)]"></span>
113+
<span className="text-[var(--terminal-green)]">copied!</span>
72114
</>
73115
) : (
74116
<>
75-
<span>#</span>
76-
<span>复制当前章节链接</span>
117+
<span className="opacity-60">#</span>
118+
<span>cp section</span>
77119
</>
78120
)}
79121
</button>
@@ -98,26 +140,37 @@ function PageOutline({
98140
if (items.length === 0) return null;
99141

100142
return (
101-
<div className="bg-gray-900/30 border border-gray-700 rounded-xl p-4 mb-6">
102-
<div className="flex items-center justify-between gap-3 mb-3">
103-
<div className="text-sm font-semibold text-cyan-300">本页目录</div>
104-
<div className="text-xs text-gray-500">点击快速跳转</div>
143+
<div className="bg-[var(--bg-panel)] border border-[var(--border-subtle)] rounded-lg p-4 mb-6 relative overflow-hidden">
144+
{/* Decorative corner accent */}
145+
<div className="absolute top-0 left-0 w-16 h-16 opacity-20">
146+
<div className="absolute top-0 left-0 w-full h-[1px] bg-gradient-to-r from-[var(--terminal-green)] to-transparent" />
147+
<div className="absolute top-0 left-0 w-[1px] h-full bg-gradient-to-b from-[var(--terminal-green)] to-transparent" />
148+
</div>
149+
150+
<div className="flex items-center justify-between gap-3 mb-4">
151+
<div className="text-sm font-mono text-[var(--terminal-green)] flex items-center gap-2">
152+
<span className="opacity-60"></span>
153+
<span>目录索引</span>
154+
</div>
155+
<div className="text-xs text-[var(--text-muted)] font-mono">// 点击跳转</div>
105156
</div>
106157
<div className="flex flex-wrap gap-2">
107-
{items.map((s) => (
158+
{items.map((s, index) => (
108159
<a
109160
key={s.id}
110161
href={`#${s.id}`}
111162
onClick={(e) => {
112163
e.preventDefault();
113164
onSelectSection(s.id);
114165
}}
115-
className={`px-3 py-1.5 rounded-lg text-sm border transition-colors ${
166+
className={`px-3 py-1.5 rounded-md text-sm font-mono border transition-all duration-200 ${
116167
activeSectionId === s.id
117-
? 'bg-cyan-500/10 border-cyan-500/40 text-cyan-200'
118-
: 'bg-gray-950/40 border-gray-700 text-gray-200 hover:bg-gray-800/40 hover:border-gray-600'
168+
? 'bg-[var(--terminal-green)]/10 border-[var(--terminal-green)]/40 text-[var(--terminal-green)] shadow-[0_0_10px_var(--terminal-green-glow)]'
169+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:border-[var(--border-default)] hover:text-[var(--text-primary)]'
119170
}`}
171+
style={{ animationDelay: `${index * 30}ms` }}
120172
>
173+
<span className="opacity-50 mr-1">{String(index + 1).padStart(2, '0')}.</span>
121174
{s.title}
122175
</a>
123176
))}
@@ -181,36 +234,45 @@ export function PageLayout({
181234

182235
return (
183236
<OutlineProvider key={activeTab}>
237+
<BackToTop />
184238
<OutlineHeader
185239
activeSectionId={activeSectionId}
186240
setActiveSectionId={setActiveSectionId}
187241
onSelectSection={onSelectSection}
188242
/>
189243
{children}
190244

191-
<div className="mt-10 flex items-center justify-between gap-4">
192-
<button
193-
disabled={!prev}
194-
onClick={() => prev && onNavigate(prev.id)}
195-
className={`px-4 py-2 rounded-lg text-sm border transition-colors ${
196-
prev
197-
? 'bg-gray-900/30 border-gray-700 text-gray-200 hover:bg-gray-800/40 hover:border-gray-600'
198-
: 'bg-gray-900/10 border-gray-800 text-gray-600 cursor-not-allowed'
199-
}`}
200-
>
201-
{prev ? `← ${prev.label}` : '← 没有上一页'}
202-
</button>
203-
<button
204-
disabled={!next}
205-
onClick={() => next && onNavigate(next.id)}
206-
className={`px-4 py-2 rounded-lg text-sm border transition-colors ${
207-
next
208-
? 'bg-gray-900/30 border-gray-700 text-gray-200 hover:bg-gray-800/40 hover:border-gray-600'
209-
: 'bg-gray-900/10 border-gray-800 text-gray-600 cursor-not-allowed'
210-
}`}
211-
>
212-
{next ? `${next.label} →` : '没有下一页 →'}
213-
</button>
245+
{/* Navigation Footer */}
246+
<div className="mt-12 pt-6 border-t border-[var(--border-subtle)]">
247+
<div className="flex items-center justify-between gap-4">
248+
<button
249+
disabled={!prev}
250+
onClick={() => prev && onNavigate(prev.id)}
251+
className={`group flex items-center gap-2 px-4 py-2.5 rounded-md text-sm font-mono border transition-all duration-200 ${
252+
prev
253+
? 'bg-[var(--bg-panel)] border-[var(--border-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:border-[var(--cyber-blue-dim)] hover:text-[var(--cyber-blue)]'
254+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
255+
}`}
256+
>
257+
<span className={`transition-transform duration-200 ${prev ? 'group-hover:-translate-x-1' : ''}`}></span>
258+
<span className="max-w-[120px] truncate">{prev ? prev.label : 'EOF'}</span>
259+
</button>
260+
<div className="text-xs text-[var(--text-muted)] font-mono hidden sm:block">
261+
// navigate
262+
</div>
263+
<button
264+
disabled={!next}
265+
onClick={() => next && onNavigate(next.id)}
266+
className={`group flex items-center gap-2 px-4 py-2.5 rounded-md text-sm font-mono border transition-all duration-200 ${
267+
next
268+
? 'bg-[var(--bg-panel)] border-[var(--border-subtle)] text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:border-[var(--terminal-green-dim)] hover:text-[var(--terminal-green)]'
269+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
270+
}`}
271+
>
272+
<span className="max-w-[120px] truncate">{next ? next.label : 'EOF'}</span>
273+
<span className={`transition-transform duration-200 ${next ? 'group-hover:translate-x-1' : ''}`}></span>
274+
</button>
275+
</div>
214276
</div>
215277
</OutlineProvider>
216278
);

0 commit comments

Comments
 (0)