Skip to content

Commit 53a8e30

Browse files
authored
Merge pull request #1 from tt-a1i/feat/gemini-cli-updates-and-ui-overhaul
feat: 新增 Gemini CLI 最新功能页面并全面优化 UI
2 parents dd08f41 + 62bc5f4 commit 53a8e30

9 files changed

Lines changed: 3777 additions & 388 deletions

File tree

src/App.tsx

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,17 @@ const NonInteractiveDeep = lazy(() => import('./pages/NonInteractiveDeep').then(
168168
const IDEClient = lazy(() => import('./pages/IDEClient').then(m => ({ default: m.IDEClient })));
169169
const MessageRendering = lazy(() => import('./pages/MessageRendering').then(m => ({ default: m.MessageRendering })));
170170
const ContextSystem = lazy(() => import('./pages/ContextSystem').then(m => ({ default: m.ContextSystem })));
171+
const PlanMode = lazy(() => import('./pages/PlanMode').then(m => ({ default: m.PlanMode })));
172+
const InteractiveShell = lazy(() => import('./pages/InteractiveShell').then(m => ({ default: m.InteractiveShell })));
173+
const BrowserAgent = lazy(() => import('./pages/BrowserAgent').then(m => ({ default: m.BrowserAgent })));
174+
const TaskTracking = lazy(() => import('./pages/TaskTracking').then(m => ({ default: m.TaskTracking })));
171175

172-
// 页面加载 fallback
173176
function PageLoading() {
174177
return (
175178
<div className="flex items-center justify-center min-h-[400px]">
176-
<div className="flex items-center gap-3 text-gray-400">
177-
<div className="w-5 h-5 border-2 border-cyan-400 border-t-transparent rounded-full animate-spin" />
178-
<span>加载页面...</span>
179+
<div className="flex items-center gap-3 text-[var(--text-muted)]">
180+
<div className="w-4 h-4 border-2 border-[var(--terminal-green-dim)] border-t-transparent rounded-full animate-spin" />
181+
<span className="text-sm">加载中...</span>
179182
</div>
180183
</div>
181184
);
@@ -574,13 +577,21 @@ function App() {
574577
return <MessageRendering />;
575578
case 'context-system':
576579
return <ContextSystem />;
580+
case 'plan-mode':
581+
return <PlanMode />;
582+
case 'interactive-shell':
583+
return <InteractiveShell />;
584+
case 'browser-agent':
585+
return <BrowserAgent />;
586+
case 'task-tracking':
587+
return <TaskTracking />;
577588
default:
578589
return <StartHere onNavigate={(tab) => navigateToTab(tab)} />;
579590
}
580591
};
581592

582593
return (
583-
<div className="flex h-screen overflow-hidden bg-gray-950">
594+
<div className="flex h-screen overflow-hidden bg-[var(--bg-void)]">
584595
{/* Desktop Sidebar */}
585596
<div className="hidden md:block">
586597
<Sidebar activeTab={activeTab} onTabChange={(tab) => navigateToTab(tab)} />
@@ -590,11 +601,11 @@ function App() {
590601
{isMobileSidebarOpen && (
591602
<div className="md:hidden fixed inset-0 z-50">
592603
<button
593-
aria-label="Close sidebar overlay"
604+
aria-label="关闭侧边栏"
594605
onClick={() => setIsMobileSidebarOpen(false)}
595-
className="absolute inset-0 bg-black/60"
606+
className="absolute inset-0 bg-black/60 backdrop-blur-sm"
596607
/>
597-
<div className="absolute inset-y-0 left-0 w-72 max-w-[85vw] shadow-2xl">
608+
<div className="absolute inset-y-0 left-0 w-72 max-w-[85vw] shadow-2xl shadow-black/40">
598609
<Sidebar
599610
activeTab={activeTab}
600611
onTabChange={(tab) => {
@@ -609,32 +620,29 @@ function App() {
609620
{/* Main Content */}
610621
<main className="flex-1 overflow-y-auto">
611622
{/* Mobile Top Bar */}
612-
<div className="md:hidden sticky top-0 z-20 bg-gray-950/80 backdrop-blur border-b border-gray-800">
613-
<div className="px-4 py-3 flex items-center gap-3">
623+
<div className="md:hidden sticky top-0 z-20 bg-[var(--bg-void)]/90 backdrop-blur-md border-b border-[var(--border-subtle)]">
624+
<div className="px-4 py-2.5 flex items-center gap-3">
614625
<button
615626
onClick={() => setIsMobileSidebarOpen(true)}
616-
className="px-3 py-2 rounded-lg bg-gray-900/30 border border-gray-800 text-gray-200 hover:bg-gray-800/40"
617-
aria-label="Open sidebar"
627+
className="p-2 rounded-lg bg-[var(--bg-panel)] border border-[var(--border-subtle)] text-[var(--text-secondary)] hover:text-[var(--text-primary)] transition-colors"
628+
aria-label="打开侧边栏"
618629
>
619-
630+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /></svg>
620631
</button>
621632
<div className="flex-1 min-w-0">
622-
<div className="text-sm text-gray-200 truncate">{activeTabLabel}</div>
623-
<div className="text-xs text-gray-500 truncate">
624-
搜索页面:Ctrl/⌘ + K
625-
</div>
633+
<div className="text-sm text-[var(--text-primary)] truncate font-medium">{activeTabLabel}</div>
626634
</div>
627635
<button
628636
onClick={() => navigateToTab('start-here')}
629-
className="px-3 py-2 rounded-lg bg-gray-900/30 border border-gray-800 text-gray-200 hover:bg-gray-800/40"
630-
aria-label="Go to start"
637+
className="p-2 rounded-lg bg-[var(--bg-panel)] border border-[var(--border-subtle)] text-[var(--text-secondary)] hover:text-[var(--terminal-green)] transition-colors"
638+
aria-label="回到首页"
631639
>
632-
640+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /></svg>
633641
</button>
634642
</div>
635643
</div>
636644

637-
<div className="max-w-5xl mx-auto p-4 md:p-8">
645+
<div className="max-w-4xl mx-auto px-4 py-6 md:px-8 md:py-10">
638646
<div className="animate-fadeIn">
639647
<PageLayout activeTab={activeTab} onNavigate={navigateToTab}>
640648
<Suspense fallback={<PageLoading />}>

src/components/PageLayout.tsx

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ function BackToTop() {
3131
return (
3232
<button
3333
onClick={scrollToTop}
34-
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+
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-dim)] hover:text-[var(--terminal-green)] transition-all duration-200 shadow-lg shadow-black/20"
3535
title="回到顶部"
36+
aria-label="回到顶部"
3637
>
3738
<svg
38-
className="w-5 h-5 transition-transform group-hover:-translate-y-0.5"
39+
className="w-4 h-4 transition-transform group-hover:-translate-y-0.5"
3940
fill="none"
4041
stroke="currentColor"
4142
viewBox="0 0 24 24"
@@ -55,7 +56,6 @@ function ShareButtons({ activeSectionId }: { activeSectionId: string | null }) {
5556
setCopied(type);
5657
setTimeout(() => setCopied(null), 2000);
5758
} catch {
58-
// fallback for older browsers
5959
const textarea = document.createElement('textarea');
6060
textarea.value = text;
6161
document.body.appendChild(textarea);
@@ -82,41 +82,41 @@ function ShareButtons({ activeSectionId }: { activeSectionId: string | null }) {
8282
}, [activeSectionId, copyToClipboard]);
8383

8484
return (
85-
<div className="flex items-center gap-2 mb-4">
85+
<div className="flex items-center gap-2 mb-5">
8686
<button
8787
onClick={copyPageLink}
88-
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"
88+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs 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-colors duration-150"
8989
>
9090
{copied === 'page' ? (
9191
<>
92-
<span className="text-[var(--terminal-green)]"></span>
93-
<span className="text-[var(--terminal-green)]">copied!</span>
92+
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>
93+
<span>已复制</span>
9494
</>
9595
) : (
9696
<>
97-
<span className="opacity-60">$</span>
98-
<span>cp link</span>
97+
<svg className="w-3 h-3 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" /></svg>
98+
<span>复制链接</span>
9999
</>
100100
)}
101101
</button>
102102
<button
103103
onClick={copySectionLink}
104104
disabled={!activeSectionId}
105-
className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono rounded-md border transition-all duration-200 ${
105+
className={`flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border transition-colors duration-150 ${
106106
activeSectionId
107107
? '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)]'
108108
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
109109
}`}
110110
>
111111
{copied === 'section' ? (
112112
<>
113-
<span className="text-[var(--terminal-green)]"></span>
114-
<span className="text-[var(--terminal-green)]">copied!</span>
113+
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" /></svg>
114+
<span>已复制</span>
115115
</>
116116
) : (
117117
<>
118-
<span className="opacity-60">#</span>
119-
<span>cp section</span>
118+
<span className="opacity-40 font-mono">#</span>
119+
<span>复制段落</span>
120120
</>
121121
)}
122122
</button>
@@ -141,21 +141,15 @@ function PageOutline({
141141
if (items.length === 0) return null;
142142

143143
return (
144-
<div className="bg-[var(--bg-panel)] border border-[var(--border-subtle)] rounded-lg p-4 mb-6 relative overflow-hidden">
145-
{/* Decorative corner accent */}
146-
<div className="absolute top-0 left-0 w-16 h-16 opacity-20">
147-
<div className="absolute top-0 left-0 w-full h-[1px] bg-gradient-to-r from-[var(--terminal-green)] to-transparent" />
148-
<div className="absolute top-0 left-0 w-[1px] h-full bg-gradient-to-b from-[var(--terminal-green)] to-transparent" />
149-
</div>
150-
151-
<div className="flex items-center justify-between gap-3 mb-4">
152-
<div className="text-sm font-mono text-[var(--terminal-green)] flex items-center gap-2">
153-
<span className="opacity-60"></span>
154-
<span>目录索引</span>
144+
<div className="bg-[var(--bg-panel)] border border-[var(--border-subtle)] rounded-lg p-4 mb-8">
145+
<div className="flex items-center justify-between gap-3 mb-3">
146+
<div className="text-xs font-medium text-[var(--text-secondary)] flex items-center gap-2">
147+
<svg className="w-3.5 h-3.5 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h7" /></svg>
148+
目录
155149
</div>
156-
<div className="text-xs text-[var(--text-muted)] font-mono">// 点击跳转</div>
150+
<div className="text-[10px] text-[var(--text-muted)]">{items.length} 个章节</div>
157151
</div>
158-
<div className="flex flex-wrap gap-2">
152+
<div className="flex flex-wrap gap-1.5">
159153
{items.map((s, index) => (
160154
<a
161155
key={s.id}
@@ -164,14 +158,13 @@ function PageOutline({
164158
e.preventDefault();
165159
onSelectSection(s.id);
166160
}}
167-
className={`px-3 py-1.5 rounded-md text-sm font-mono border transition-all duration-200 ${
161+
className={`px-2.5 py-1 rounded-md text-xs border transition-colors duration-150 ${
168162
activeSectionId === s.id
169-
? 'bg-[var(--terminal-green)]/10 border-[var(--terminal-green)]/40 text-[var(--terminal-green)] shadow-[0_0_10px_var(--terminal-green-glow)]'
163+
? 'bg-[var(--terminal-green)]/8 border-[var(--terminal-green)]/30 text-[var(--terminal-green)]'
170164
: '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)]'
171165
}`}
172-
style={{ animationDelay: `${index * 30}ms` }}
173166
>
174-
<span className="opacity-50 mr-1">{String(index + 1).padStart(2, '0')}.</span>
167+
<span className="opacity-40 mr-1 font-mono text-[10px]">{String(index + 1).padStart(2, '0')}</span>
175168
{s.title}
176169
</a>
177170
))}
@@ -247,33 +240,30 @@ export function PageLayout({
247240
{children}
248241

249242
{/* Navigation Footer */}
250-
<div className="mt-12 pt-6 border-t border-[var(--border-subtle)]">
243+
<div className="mt-16 pt-6 border-t border-[var(--border-subtle)]">
251244
<div className="flex items-center justify-between gap-4">
252245
<button
253246
disabled={!prev}
254247
onClick={() => prev && onNavigate(prev.id)}
255-
className={`group flex items-center gap-2 px-4 py-2.5 rounded-md text-sm font-mono border transition-all duration-200 ${
248+
className={`group flex items-center gap-2 px-4 py-2.5 rounded-lg text-xs border transition-colors duration-150 ${
256249
prev
257250
? '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)]'
258-
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
251+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-40'
259252
}`}
260253
>
261254
<span className={`transition-transform duration-200 ${prev ? 'group-hover:-translate-x-1' : ''}`}></span>
262-
<span className="max-w-[120px] truncate">{prev ? prev.label : 'EOF'}</span>
255+
<span className="max-w-[140px] truncate">{prev ? prev.label : ''}</span>
263256
</button>
264-
<div className="text-xs text-[var(--text-muted)] font-mono hidden sm:block">
265-
// navigate
266-
</div>
267257
<button
268258
disabled={!next}
269259
onClick={() => next && onNavigate(next.id)}
270-
className={`group flex items-center gap-2 px-4 py-2.5 rounded-md text-sm font-mono border transition-all duration-200 ${
260+
className={`group flex items-center gap-2 px-4 py-2.5 rounded-lg text-xs border transition-colors duration-150 ${
271261
next
272262
? '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)]'
273-
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-50'
263+
: 'bg-[var(--bg-void)] border-[var(--border-subtle)] text-[var(--text-muted)] cursor-not-allowed opacity-40'
274264
}`}
275265
>
276-
<span className="max-w-[120px] truncate">{next ? next.label : 'EOF'}</span>
266+
<span className="max-w-[140px] truncate">{next ? next.label : ''}</span>
277267
<span className={`transition-transform duration-200 ${next ? 'group-hover:translate-x-1' : ''}`}></span>
278268
</button>
279269
</div>

0 commit comments

Comments
 (0)