@@ -24,10 +24,11 @@ import { Card } from '@/components/ui/Card';
2424import { Input } from '@/components/ui/Input' ;
2525import { Badge } from '@/components/ui/Badge' ;
2626import { Button } from '@/components/ui/Button' ;
27- import { Tabs , TabsList , TabsTrigger , TabsContent } from '@/components/ui/Tabs ' ;
27+ import { TabsNavigation } from '@/components/ui/TabsNavigation ' ;
2828import { fetchAnalysisSessions , fetchAnalysisDetail } from '@/lib/api' ;
2929import { MessageRenderer } from '@/components/shared/CliStreamMonitor/MessageRenderer' ;
3030import { JsonCardView } from '@/components/shared/JsonCardView' ;
31+ import { cn } from '@/lib/utils' ;
3132import type { AnalysisSessionSummary } from '@/types/analysis' ;
3233
3334// ========== Session Card Component ==========
@@ -41,23 +42,22 @@ interface SessionCardProps {
4142function SessionCard ( { session, onClick, isSelected } : SessionCardProps ) {
4243 return (
4344 < Card
44- className = { `p-4 cursor-pointer transition-colors ${
45- isSelected ? 'ring-2 ring-primary bg-accent/50' : 'hover:bg-accent/50'
46- } `}
45+ className = { cn (
46+ 'p-4 cursor-pointer transition-all hover:shadow-md' ,
47+ isSelected && 'ring-2 ring-primary'
48+ ) }
4749 onClick = { onClick }
4850 >
49- < div className = "flex items-start justify-between" >
50- < div className = "flex-1 min-w-0" >
51- < div className = "flex items-center gap-2 mb-1" >
52- < FileSearch className = "w-4 h-4 text-muted-foreground" />
53- < span className = "font-medium truncate" > { session . topic } </ span >
54- </ div >
55- < p className = "text-sm text-muted-foreground truncate" > { session . id } </ p >
51+ < div className = "flex items-start justify-between mb-3" >
52+ < div className = "flex items-center gap-2 flex-1 min-w-0" >
53+ < FileSearch className = "w-5 h-5 text-primary flex-shrink-0" />
54+ < h3 className = "font-medium text-foreground truncate" > { session . topic } </ h3 >
5655 </ div >
5756 < ChevronRight className = "w-4 h-4 text-muted-foreground flex-shrink-0" />
5857 </ div >
59- < div className = "flex items-center gap-3 mt-3" >
60- < Badge variant = { session . status === 'completed' ? 'default' : 'secondary' } >
58+ < p className = "text-sm text-muted-foreground truncate mb-3" > { session . id } </ p >
59+ < div className = "flex items-center gap-3" >
60+ < Badge variant = { session . status === 'completed' ? 'success' : 'warning' } >
6161 { session . status === 'completed' ? (
6262 < > < CheckCircle className = "w-3 h-3 mr-1" /> 完成</ >
6363 ) : (
@@ -82,6 +82,8 @@ interface DetailPanelProps {
8282}
8383
8484function DetailPanel ( { sessionId, projectPath, onClose } : DetailPanelProps ) {
85+ const [ activeTab , setActiveTab ] = useState ( 'discussion' ) ;
86+
8587 const { data : detail , isLoading, error } = useQuery ( {
8688 queryKey : [ 'analysis-detail' , sessionId , projectPath ] ,
8789 queryFn : ( ) => fetchAnalysisDetail ( sessionId , projectPath ) ,
@@ -110,13 +112,20 @@ function DetailPanel({ sessionId, projectPath, onClose }: DetailPanelProps) {
110112
111113 // Build available tabs based on content
112114 const tabs = [
113- { id : 'discussion' , label : '讨论记录' , icon : MessageSquare , content : detail . discussion } ,
114- { id : 'conclusions' , label : '结论' , icon : CheckCircle , content : detail . conclusions } ,
115- { id : 'explorations' , label : '代码探索' , icon : Code , content : detail . explorations } ,
116- { id : 'perspectives' , label : '视角分析' , icon : FileText , content : detail . perspectives } ,
117- ] . filter ( tab => tab . content ) ;
115+ { value : 'discussion' , label : '讨论记录' , icon : < MessageSquare className = "w-4 h-4" /> } ,
116+ { value : 'conclusions' , label : '结论' , icon : < CheckCircle className = "w-4 h-4" /> } ,
117+ { value : 'explorations' , label : '代码探索' , icon : < Code className = "w-4 h-4" /> } ,
118+ { value : 'perspectives' , label : '视角分析' , icon : < FileText className = "w-4 h-4" /> } ,
119+ ] . filter ( tab => {
120+ const key = tab . value as keyof typeof detail ;
121+ return detail [ key ] ;
122+ } ) ;
118123
119- const defaultTab = tabs [ 0 ] ?. id || 'discussion' ;
124+ // Ensure activeTab is valid
125+ const validTab = tabs . find ( t => t . value === activeTab ) ;
126+ if ( ! validTab && tabs . length > 0 ) {
127+ setActiveTab ( tabs [ 0 ] . value ) ;
128+ }
120129
121130 return (
122131 < div className = "h-full flex flex-col" >
@@ -138,46 +147,35 @@ function DetailPanel({ sessionId, projectPath, onClose }: DetailPanelProps) {
138147
139148 { /* Tabs Content */ }
140149 { tabs . length > 0 ? (
141- < Tabs defaultValue = { defaultTab } className = "flex-1 flex flex-col min-h-0" >
142- < TabsList className = "mx-4 mt-4 shrink-0 w-fit" >
143- { tabs . map ( tab => (
144- < TabsTrigger key = { tab . id } value = { tab . id } className = "gap-1.5" >
145- < tab . icon className = "w-3.5 h-3.5" />
146- { tab . label }
147- </ TabsTrigger >
148- ) ) }
149- </ TabsList >
150-
150+ < >
151+ < TabsNavigation
152+ value = { activeTab }
153+ onValueChange = { setActiveTab }
154+ tabs = { tabs }
155+ className = "px-4"
156+ />
151157 < div className = "flex-1 overflow-auto min-h-0 p-4" >
152158 { /* Discussion Tab */ }
153- < TabsContent value = "discussion" className = "mt-0 h-full" >
154- { detail . discussion && (
155- < MessageRenderer content = { detail . discussion } format = "markdown" />
156- ) }
157- </ TabsContent >
159+ { activeTab === 'discussion' && detail . discussion && (
160+ < MessageRenderer content = { detail . discussion } format = "markdown" />
161+ ) }
158162
159163 { /* Conclusions Tab */ }
160- < TabsContent value = "conclusions" className = "mt-0 h-full" >
161- { detail . conclusions && (
162- < JsonCardView data = { detail . conclusions } />
163- ) }
164- </ TabsContent >
164+ { activeTab === 'conclusions' && detail . conclusions && (
165+ < JsonCardView data = { detail . conclusions } />
166+ ) }
165167
166168 { /* Explorations Tab */ }
167- < TabsContent value = "explorations" className = "mt-0 h-full" >
168- { detail . explorations && (
169- < JsonCardView data = { detail . explorations } />
170- ) }
171- </ TabsContent >
169+ { activeTab === 'explorations' && detail . explorations && (
170+ < JsonCardView data = { detail . explorations } />
171+ ) }
172172
173173 { /* Perspectives Tab */ }
174- < TabsContent value = "perspectives" className = "mt-0 h-full" >
175- { detail . perspectives && (
176- < JsonCardView data = { detail . perspectives } />
177- ) }
178- </ TabsContent >
174+ { activeTab === 'perspectives' && detail . perspectives && (
175+ < JsonCardView data = { detail . perspectives } />
176+ ) }
179177 </ div >
180- </ Tabs >
178+ </ >
181179 ) : (
182180 < div className = "flex-1 flex items-center justify-center text-muted-foreground" >
183181 暂无分析内容
@@ -210,14 +208,16 @@ export function AnalysisPage() {
210208 { /* Left Panel - List */ }
211209 < div className = { `p-6 space-y-6 overflow-auto ${ selectedSession ? 'w-[400px] shrink-0' : 'flex-1' } ` } >
212210 { /* Header */ }
213- < div >
214- < h1 className = "text-2xl font-bold flex items-center gap-2" >
215- < FileSearch className = "w-6 h-6" />
216- Analysis Viewer
217- </ h1 >
218- < p className = "text-muted-foreground mt-1" >
219- 查看 /workflow:analyze-with-file 命令的分析结果
220- </ p >
211+ < div className = "flex items-center gap-2" >
212+ < FileSearch className = "w-6 h-6 text-primary" />
213+ < div >
214+ < h1 className = "text-2xl font-semibold text-foreground" >
215+ Analysis Viewer
216+ </ h1 >
217+ < p className = "text-sm text-muted-foreground mt-1" >
218+ 查看 /workflow:analyze-with-file 命令的分析结果
219+ </ p >
220+ </ div >
221221 </ div >
222222
223223 { /* Search */ }
0 commit comments