11import { memo , useState } from 'react'
2- import { X , ChevronDown , ChevronRight , AlertTriangle , FileCode2 , ExternalLink , Search } from 'lucide-react'
2+ import {
3+ X ,
4+ ChevronDown ,
5+ ChevronRight ,
6+ AlertTriangle ,
7+ FileCode2 ,
8+ ExternalLink ,
9+ Search ,
10+ CheckCircle2 ,
11+ Flame ,
12+ CircleAlert ,
13+ MapPin
14+ } from 'lucide-react'
315import { cn } from '@/lib/utils'
16+ import { Button } from '@/components/ui/button'
17+ import { Card , CardContent , CardHeader } from '@/components/ui/card'
18+ import { Badge } from '@/components/ui/badge'
419import type { RiskLevel , ImpactResult } from './hooks/useImpactAnalysis'
520
621interface ImpactPanelProps {
@@ -13,33 +28,39 @@ interface ImpactPanelProps {
1328 onAnalyzeInSearch ?: ( fileId : string ) => void
1429}
1530
16- const RISK_CONFIG : Record < RiskLevel , { bg : string ; border : string ; text : string ; icon : string ; label : string } > = {
31+ const RISK_CONFIG : Record < RiskLevel , {
32+ bg : string
33+ border : string
34+ text : string
35+ icon : typeof CheckCircle2
36+ label : string
37+ } > = {
1738 low : {
1839 bg : 'bg-emerald-50 dark:bg-emerald-500/10' ,
1940 border : 'border-emerald-200 dark:border-emerald-500/30' ,
2041 text : 'text-emerald-600 dark:text-emerald-400' ,
21- icon : '✓' ,
42+ icon : CheckCircle2 ,
2243 label : 'Low Risk'
2344 } ,
2445 medium : {
2546 bg : 'bg-yellow-50 dark:bg-yellow-500/10' ,
2647 border : 'border-yellow-200 dark:border-yellow-500/30' ,
2748 text : 'text-yellow-600 dark:text-yellow-400' ,
28- icon : '⚠' ,
49+ icon : CircleAlert ,
2950 label : 'Medium Risk'
3051 } ,
3152 high : {
3253 bg : 'bg-orange-50 dark:bg-orange-500/10' ,
3354 border : 'border-orange-200 dark:border-orange-500/30' ,
3455 text : 'text-orange-600 dark:text-orange-400' ,
35- icon : '⚠' ,
56+ icon : AlertTriangle ,
3657 label : 'High Risk'
3758 } ,
3859 critical : {
3960 bg : 'bg-rose-50 dark:bg-rose-500/10' ,
4061 border : 'border-rose-200 dark:border-rose-500/30' ,
4162 text : 'text-rose-600 dark:text-rose-400' ,
42- icon : '🔥' ,
63+ icon : Flame ,
4364 label : 'Critical'
4465 } ,
4566}
@@ -114,7 +135,7 @@ function CollapsibleSection({
114135 < ChevronRight className = "w-4 h-4 text-zinc-400 dark:text-zinc-500" />
115136 ) }
116137 < span className = { cn ( 'text-sm font-medium' , variantStyles [ variant ] ) } > { title } </ span >
117- < span className = "text-xs text-zinc-400 dark:text-zinc-500 ml-auto " > { count } </ span >
138+ < Badge variant = "secondary" className = "ml-auto text-[10px] px-1.5 py-0 h-5 " > { count } </ Badge >
118139 </ button >
119140
120141 { isOpen && (
@@ -143,12 +164,12 @@ function ImpactPanelComponent({
143164 onAnalyzeInSearch,
144165} : ImpactPanelProps ) {
145166 const risk = RISK_CONFIG [ impact . riskLevel ]
167+ const RiskIcon = risk . icon
146168 const totalDependents = impact . allDependents . length
147169
148170 return (
149171 < div className = "w-80 bg-white dark:bg-zinc-900 border-l border-zinc-200 dark:border-zinc-800 h-full flex flex-col animate-in slide-in-from-right duration-200" >
150- { /* Header */ }
151- < div className = "p-4 border-b border-zinc-200 dark:border-zinc-800" >
172+ < CardHeader className = "p-4 border-b border-zinc-200 dark:border-zinc-800" >
152173 < div className = "flex items-start justify-between gap-2" >
153174 < div className = "min-w-0 flex-1" >
154175 < h3 className = "font-semibold text-zinc-800 dark:text-zinc-100 truncate" title = { fullPath } >
@@ -158,20 +179,16 @@ function ImpactPanelComponent({
158179 { fullPath }
159180 </ p >
160181 </ div >
161- < button
162- onClick = { onClose }
163- className = "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded transition-colors flex-shrink-0"
164- >
165- < X className = "w-4 h-4 text-zinc-500 dark:text-zinc-400" />
166- </ button >
182+ < Button variant = "ghost" size = "icon" className = "h-8 w-8 flex-shrink-0" onClick = { onClose } >
183+ < X className = "w-4 h-4" />
184+ </ Button >
167185 </ div >
168186
169- { /* Risk Badge */ }
170187 < div className = { cn (
171188 'mt-3 px-3 py-2 rounded-lg border flex items-center gap-2' ,
172189 risk . bg , risk . border
173190 ) } >
174- < span className = "text-lg" > { risk . icon } </ span >
191+ < RiskIcon className = { cn ( 'w-5 h-5' , risk . text ) } / >
175192 < div >
176193 < div className = { cn ( 'font-semibold text-sm' , risk . text ) } > { risk . label } </ div >
177194 < div className = "text-xs text-zinc-500 dark:text-zinc-400" >
@@ -183,25 +200,22 @@ function ImpactPanelComponent({
183200 </ div >
184201 </ div >
185202
186- { /* Warning for critical files */ }
187203 { impact . riskLevel === 'critical' && (
188204 < div className = "mt-2 flex items-start gap-2 text-xs text-rose-600 dark:text-rose-400 bg-rose-50 dark:bg-rose-500/10 px-3 py-2 rounded-lg" >
189205 < AlertTriangle className = "w-3.5 h-3.5 flex-shrink-0 mt-0.5" />
190206 < span > Changes to this file have high blast radius. Test thoroughly.</ span >
191207 </ div >
192208 ) }
193209
194- { /* Entry Point indicator */ }
195210 { impact . isEntryPoint && (
196211 < div className = "mt-2 flex items-center gap-2 text-xs text-emerald-600 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-500/10 px-3 py-2 rounded-lg" >
197- < span > 📍 </ span >
198- < span > Entry point - this file is a root of the dependency tree</ span >
212+ < MapPin className = "w-3.5 h-3.5" / >
213+ < span > Entry point - root of the dependency tree</ span >
199214 </ div >
200215 ) }
201- </ div >
216+ </ CardHeader >
202217
203- { /* Dependents Lists */ }
204- < div className = "flex-1 overflow-y-auto p-4 space-y-3" >
218+ < CardContent className = "flex-1 overflow-y-auto p-4 space-y-3" >
205219 < CollapsibleSection
206220 title = "Direct Dependents"
207221 count = { impact . directDependents . length }
@@ -221,18 +235,14 @@ function ImpactPanelComponent({
221235 onFileClick = { onFileClick }
222236 onFileHover = { onFileHover }
223237 />
224- </ div >
238+ </ CardContent >
225239
226- { /* Actions Footer */ }
227240 { onAnalyzeInSearch && (
228241 < div className = "p-4 border-t border-zinc-200 dark:border-zinc-800" >
229- < button
230- onClick = { ( ) => onAnalyzeInSearch ( fullPath ) }
231- className = "w-full flex items-center justify-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium rounded-lg transition-colors"
232- >
233- < Search className = "w-4 h-4" />
242+ < Button className = "w-full" onClick = { ( ) => onAnalyzeInSearch ( fullPath ) } >
243+ < Search className = "w-4 h-4 mr-2" />
234244 Analyze in Search
235- </ button >
245+ </ Button >
236246 </ div >
237247 ) }
238248 </ div >
0 commit comments