diff --git a/frontend/src/components/AddRepoForm.tsx b/frontend/src/components/AddRepoForm.tsx index d160c60..7f01544 100644 --- a/frontend/src/components/AddRepoForm.tsx +++ b/frontend/src/components/AddRepoForm.tsx @@ -1,4 +1,6 @@ import { useState } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { Package, Plus, X } from 'lucide-react' interface AddRepoFormProps { onAdd: (gitUrl: string, branch: string) => Promise @@ -13,110 +15,126 @@ export function AddRepoForm({ onAdd, loading }: AddRepoFormProps) { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!gitUrl) return - await onAdd(gitUrl, branch) setGitUrl('') setBranch('main') setShowForm(false) } - if (!showForm) { - return ( - - ) - } + + + Add Repository + - return ( -
-
- {/* Header */} -
-
-

Add Repository

-

Clone and index a Git repository

-
- -
+ e.stopPropagation()} + className="bg-gradient-to-br from-[#111113] to-[#0a0a0c] border border-white/10 rounded-2xl shadow-2xl w-full max-w-md mx-4" + > + {/* Header */} +
+
+
+ +
+
+

Add Repository

+

Clone and index with AI

+
+
+ +
- {/* Form */} -
-
- - setGitUrl(e.target.value)} - placeholder="https://github.com/username/repo" - className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder:text-gray-500 focus:outline-none focus:border-blue-500/50 focus:ring-1 focus:ring-blue-500/20 transition-all" - required - disabled={loading} - autoFocus - /> -
+ {/* Form */} + +
+ + setGitUrl(e.target.value)} + placeholder="https://github.com/username/repo" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder:text-gray-500 focus:outline-none focus:border-blue-500/50 focus:ring-2 focus:ring-blue-500/20 transition-all" + required + disabled={loading} + autoFocus + /> +
-
- - setBranch(e.target.value)} - placeholder="main" - className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder:text-gray-500 focus:outline-none focus:border-blue-500/50 focus:ring-1 focus:ring-blue-500/20 transition-all" - required - disabled={loading} - /> -

- The repository will be cloned and automatically indexed -

-
+
+ + setBranch(e.target.value)} + placeholder="main" + className="w-full px-4 py-3 bg-white/5 border border-white/10 rounded-xl text-white placeholder:text-gray-500 focus:outline-none focus:border-blue-500/50 focus:ring-2 focus:ring-blue-500/20 transition-all" + required + disabled={loading} + /> +

Repository will be cloned and automatically indexed

+
- {/* Actions */} -
- - -
-
-
-
+ {/* Actions */} +
+ + + {loading ? ( + <> +
+ Adding... + + ) : ( + <> + + Add & Index + + )} + +
+ + + + )} + + ) } diff --git a/frontend/src/components/DependencyGraph.tsx b/frontend/src/components/DependencyGraph.tsx index 193b2a0..f788134 100644 --- a/frontend/src/components/DependencyGraph.tsx +++ b/frontend/src/components/DependencyGraph.tsx @@ -9,6 +9,7 @@ import ReactFlow, { } from 'reactflow' import type { Node, Edge } from 'reactflow' import dagre from 'dagre' +import { Lightbulb } from 'lucide-react' import 'reactflow/dist/style.css' import { useDependencyGraph } from '../hooks/useCachedQuery' @@ -235,21 +236,21 @@ export function DependencyGraph({ repoId, apiUrl, apiKey }: DependencyGraphProps
Total Files
-
{allNodes.length}
+
{allNodes.length}
Dependencies
-
{edges.length}
+
{edges.length}
Avg per File
-
+
{metrics?.avg_dependencies?.toFixed(1) || 0}
Showing
-
{nodes.length}
+
{nodes.length}
@@ -357,8 +358,9 @@ export function DependencyGraph({ repoId, apiUrl, apiKey }: DependencyGraphProps Dependency
-
- 💡 Click any node to highlight its dependencies • Drag to pan • Scroll to zoom +
+ + Click any node to highlight its dependencies • Drag to pan • Scroll to zoom
diff --git a/frontend/src/components/ImpactAnalyzer.tsx b/frontend/src/components/ImpactAnalyzer.tsx index 6130e6a..a656d0e 100644 --- a/frontend/src/components/ImpactAnalyzer.tsx +++ b/frontend/src/components/ImpactAnalyzer.tsx @@ -129,7 +129,7 @@ export function ImpactAnalyzer({ repoId, apiUrl, apiKey }: ImpactAnalyzerProps)
Direct Dependencies
-
+
{result.dependency_count}
@@ -139,7 +139,7 @@ export function ImpactAnalyzer({ repoId, apiUrl, apiKey }: ImpactAnalyzerProps)
Total Impact
-
+
{result.dependent_count}
@@ -149,7 +149,7 @@ export function ImpactAnalyzer({ repoId, apiUrl, apiKey }: ImpactAnalyzerProps)
Test Files
-
+
{result.test_files?.length || 0}
diff --git a/frontend/src/components/RepoList.tsx b/frontend/src/components/RepoList.tsx index 2b1b650..14b241a 100644 --- a/frontend/src/components/RepoList.tsx +++ b/frontend/src/components/RepoList.tsx @@ -1,3 +1,5 @@ +import { useState, useRef, useMemo } from 'react' +import { motion } from 'framer-motion' import type { Repository } from '../types' import { RepoGridSkeleton } from './ui/Skeleton' @@ -8,129 +10,133 @@ interface RepoListProps { loading?: boolean } -// Status indicator with glow effect -const StatusIndicator = ({ status }: { status: string }) => { - const config = { - indexed: { color: 'green', label: 'Indexed', icon: '✓' }, - cloned: { color: 'blue', label: 'Ready', icon: '✓' }, - indexing: { color: 'yellow', label: 'Indexing', icon: '◌' }, - cloning: { color: 'yellow', label: 'Cloning', icon: '◌' }, - error: { color: 'red', label: 'Error', icon: '✗' }, - }[status] || { color: 'gray', label: status, icon: '•' } - - const colorClasses = { - green: 'bg-green-500/10 text-green-400 border-green-500/20', - blue: 'bg-blue-500/10 text-blue-400 border-blue-500/20', - yellow: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20', - red: 'bg-red-500/10 text-red-400 border-red-500/20', - gray: 'bg-white/5 text-gray-400 border-white/10', - }[config.color] +const StatusBadge = ({ status }: { status: string }) => { + const isIndexed = status === 'indexed' + + return ( + + + {isIndexed ? 'Indexed' : 'Pending'} + + ) +} - const glowClasses = { - green: 'shadow-green-500/20', - blue: 'shadow-blue-500/20', - yellow: 'shadow-yellow-500/20', - red: 'shadow-red-500/20', - gray: '', - }[config.color] +const RepoCard = ({ repo, index, onSelect }: { + repo: Repository + index: number + onSelect: () => void +}) => { + const cardRef = useRef(null) + const [mousePos, setMousePos] = useState({ x: 0, y: 0 }) + const [hovering, setHovering] = useState(false) return ( - - {config.icon} - {config.label} - + { + if (!cardRef.current) return + const rect = cardRef.current.getBoundingClientRect() + setMousePos({ x: e.clientX - rect.left, y: e.clientY - rect.top }) + }} + onMouseEnter={() => setHovering(true)} + onMouseLeave={() => setHovering(false)} + className="group relative text-left rounded-2xl overflow-hidden w-full + bg-[#111113] border border-white/[0.06] hover:border-blue-500/40 + focus:outline-none focus:ring-2 focus:ring-blue-500/50 p-5 transition-colors" + > + {/* Mouse glow */} + {hovering && ( +
+ )} + +
+ {/* Header */} +
+
+ + + +
+ +
+ + {/* Title */} +

+ {repo.name} +

+

{repo.branch}

+ + {/* Stats */} +
+
+ Functions + + {(repo.file_count || 0).toLocaleString()} + +
+
+
+ ) } export function RepoList({ repos, selectedRepo, onSelect, loading }: RepoListProps) { - if (loading) { - return - } + if (loading) return if (repos.length === 0) { return ( -
-
- 📦 + +
+ + +

No repositories yet

-

- Add your first repository to start searching code semantically with AI +

+ Add your first repository to start searching code with AI

-
+ ) } + // Sort: indexed first, then by function count desc + const sortedRepos = useMemo(() => { + return [...repos].sort((a, b) => { + if (a.status === 'indexed' && b.status !== 'indexed') return -1 + if (b.status === 'indexed' && a.status !== 'indexed') return 1 + return (b.file_count || 0) - (a.file_count || 0) + }) + }, [repos]) + return (
- {repos.map((repo, index) => { - const isSelected = selectedRepo === repo.id - - return ( - - ) - })} + {sortedRepos.map((repo, index) => ( + onSelect(repo.id)} + /> + ))}
) } diff --git a/frontend/src/components/RepoOverview.tsx b/frontend/src/components/RepoOverview.tsx index 24348c2..670a1e2 100644 --- a/frontend/src/components/RepoOverview.tsx +++ b/frontend/src/components/RepoOverview.tsx @@ -1,4 +1,5 @@ import { useState, useEffect, useRef } from 'react' +import { motion } from 'framer-motion' import { toast } from 'sonner' import { Progress } from '@/components/ui/progress' import type { Repository } from '../types' @@ -24,16 +25,10 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr const [progress, setProgress] = useState(null) const wsRef = useRef(null) const completedRef = useRef(false) - - // Cache invalidation hook const invalidateCache = useInvalidateRepoCache() useEffect(() => { - return () => { - if (wsRef.current) { - wsRef.current.close() - } - } + return () => { if (wsRef.current) wsRef.current.close() } }, []) const handleReindex = async () => { @@ -41,32 +36,19 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr setProgress({ files_processed: 0, functions_indexed: 0, total_files: 0, progress_pct: 0 }) completedRef.current = false - const wsUrl = `${WS_URL}/ws/index/${repo.id}?token=${apiKey}` - try { - const ws = new WebSocket(wsUrl) + const ws = new WebSocket(`${WS_URL}/ws/index/${repo.id}?token=${apiKey}`) wsRef.current = ws - - ws.onopen = () => { - toast.loading('Indexing started...', { id: 'reindex' }) - } - + ws.onopen = () => toast.loading('Indexing started...', { id: 'reindex' }) ws.onmessage = (event) => { const data = JSON.parse(event.data) - if (data.type === 'progress') { - setProgress({ - files_processed: data.files_processed, - functions_indexed: data.functions_indexed, - total_files: data.total_files, - progress_pct: data.progress_pct - }) + setProgress({ files_processed: data.files_processed, functions_indexed: data.functions_indexed, total_files: data.total_files, progress_pct: data.progress_pct }) } else if (data.type === 'complete') { completedRef.current = true toast.success(`Indexing complete! ${data.total_functions} functions indexed.`, { id: 'reindex' }) setIndexing(false) setProgress(null) - // Invalidate caches after re-index invalidateCache(repo.id) onReindex() } else if (data.type === 'error') { @@ -76,20 +58,8 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr setProgress(null) } } - - ws.onerror = () => { - if (!completedRef.current) { - toast.dismiss('reindex') - fallbackToHttp() - } - } - - ws.onclose = () => { - if (!completedRef.current) { - fallbackToHttp() - } - } - + ws.onerror = () => { if (!completedRef.current) { toast.dismiss('reindex'); fallbackToHttp() } } + ws.onclose = () => { if (!completedRef.current) fallbackToHttp() } } catch { fallbackToHttp() } @@ -97,26 +67,13 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr const fallbackToHttp = async () => { if (completedRef.current) return - toast.loading('Using fallback indexing...', { id: 'reindex' }) - try { await onReindex() toast.success('Re-indexing started!', { id: 'reindex' }) - let pct = 10 - const interval = setInterval(() => { - pct = Math.min(pct + 10, 90) - setProgress(prev => prev ? { ...prev, progress_pct: pct } : null) - }, 1000) - - setTimeout(() => { - clearInterval(interval) - setProgress(null) - setIndexing(false) - completedRef.current = true - }, 8000) - + const interval = setInterval(() => { pct = Math.min(pct + 10, 90); setProgress(prev => prev ? { ...prev, progress_pct: pct } : null) }, 1000) + setTimeout(() => { clearInterval(interval); setProgress(null); setIndexing(false); completedRef.current = true }, 8000) } catch { setIndexing(false) setProgress(null) @@ -126,122 +83,126 @@ export function RepoOverview({ repo, onReindex, apiUrl, apiKey }: RepoOverviewPr return (
- {/* Stats Cards */} + {/* Stats Grid */}
-
-
Status
-
- {repo.status === 'indexed' && ( - - ✓ Indexed - - )} - {repo.status === 'cloned' && ( - - ✓ Ready - - )} - {repo.status === 'indexing' && ( - - 🔄 Indexing - - )} -
-
- -
-
Functions Indexed
-
- {repo.file_count?.toLocaleString() || 0} -
-
- -
-
Branch
-
- {repo.branch} + {/* Status */} + +

Status

+
+ + {repo.status === 'indexed' ? 'Indexed' : 'Pending'}
-
+ + + {/* Functions */} + +

Functions Indexed

+

+ {(repo.file_count || 0).toLocaleString()} +

+
+ + {/* Branch */} + +

Branch

+

{repo.branch}

+
{/* Indexing Progress */} {indexing && progress && ( -
+
-

🔄 Indexing in Progress

+
+ + Indexing in Progress +
{progress.progress_pct}%
- -
+ +
Files: {progress.files_processed}/{progress.total_files || '?'} Functions: {progress.functions_indexed}
-
+
)} - {/* Repository Info */} -
-

Repository Details

- + {/* Repository Details */} + +

Repository Details

- Name: - {repo.name} + Name + {repo.name}
- -
- Local Path: - {repo.local_path} + Local Path + {repo.local_path}
-
+ {/* Actions */} -
-

Actions

-

- Re-indexing uses incremental mode - only processes changed files for 100x faster updates! + +

Actions

+

+ Re-indexing uses incremental mode — only processes changed files.

-
- - {/* Quick Guide */} -
-

💡 Quick Guide

-
    -
  • Search tab - Find code by meaning, not keywords
  • -
  • Dependencies tab - Visualize code architecture
  • -
  • Code Style tab - Analyze team coding patterns
  • -
  • Impact tab - See what breaks when you change a file
  • -
  • • Use with Claude Desktop via MCP for AI-powered code understanding
  • -
-
+
) } diff --git a/frontend/src/components/SearchPanel.tsx b/frontend/src/components/SearchPanel.tsx index 4d0a2d7..ab91e0d 100644 --- a/frontend/src/components/SearchPanel.tsx +++ b/frontend/src/components/SearchPanel.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { toast } from 'sonner'; +import { Zap, Search } from 'lucide-react'; import { SearchBox, ResultCard } from './search'; import type { SearchResult } from '../types'; @@ -83,7 +84,10 @@ export function SearchPanel({ repoId, apiUrl, apiKey, repoUrl }: SearchPanelProp {cached && ( <> - ⚡ Cached + + + Cached + )}
@@ -108,7 +112,7 @@ export function SearchPanel({ repoId, apiUrl, apiKey, repoUrl }: SearchPanelProp {results.length === 0 && hasSearched && !loading && (
- 🔍 +

No results found

diff --git a/frontend/src/components/StyleInsights.tsx b/frontend/src/components/StyleInsights.tsx index 81ca84f..7b5abd2 100644 --- a/frontend/src/components/StyleInsights.tsx +++ b/frontend/src/components/StyleInsights.tsx @@ -41,14 +41,14 @@ export function StyleInsights({ repoId, apiUrl, apiKey }: StyleInsightsProps) {

Async Adoption
-
+
{data.summary?.async_adoption || '0%'}
Type Hints
-
+
{data.summary?.type_hints_usage || '0%'}
@@ -126,7 +126,7 @@ export function StyleInsights({ repoId, apiUrl, apiKey }: StyleInsightsProps) { Async/Await Usage
{data.patterns?.async_usage} - + {data.patterns?.async_percentage?.toFixed(0)}%
@@ -136,7 +136,7 @@ export function StyleInsights({ repoId, apiUrl, apiKey }: StyleInsightsProps) { Type Annotations
{data.patterns?.type_annotations} - + {data.patterns?.typed_percentage?.toFixed(0)}%
diff --git a/frontend/src/components/dashboard/DashboardHome.tsx b/frontend/src/components/dashboard/DashboardHome.tsx index d96e7da..feeb9c8 100644 --- a/frontend/src/components/dashboard/DashboardHome.tsx +++ b/frontend/src/components/dashboard/DashboardHome.tsx @@ -1,5 +1,7 @@ import { useState, useEffect } from 'react' +import { motion, AnimatePresence } from 'framer-motion' import { toast } from 'sonner' +import { LayoutDashboard, Search, GitFork, Code2, Zap } from 'lucide-react' import { useAuth } from '../../contexts/AuthContext' import { RepoList } from '../RepoList' import { AddRepoForm } from '../AddRepoForm' @@ -8,7 +10,7 @@ import { DependencyGraph } from '../DependencyGraph' import { RepoOverview } from '../RepoOverview' import { StyleInsights } from '../StyleInsights' import { ImpactAnalyzer } from '../ImpactAnalyzer' -import { PerformanceDashboard } from '../PerformanceDashboard' +import { DashboardStats } from './DashboardStats' import type { Repository } from '../../types' import { API_URL } from '../../config/api' @@ -21,11 +23,9 @@ export function DashboardHome() { const [activeTab, setActiveTab] = useState('overview') const [loading, setLoading] = useState(false) const [reposLoading, setReposLoading] = useState(true) - const [showPerformance, setShowPerformance] = useState(false) const fetchRepos = async () => { if (!session?.access_token) return - try { const response = await fetch(`${API_URL}/repos`, { headers: { 'Authorization': `Bearer ${session.access_token}` } @@ -49,7 +49,6 @@ export function DashboardHome() { try { setLoading(true) const name = gitUrl.split('/').pop()?.replace('.git', '') || 'unknown' - const response = await fetch(`${API_URL}/repos`, { method: 'POST', headers: { @@ -58,23 +57,16 @@ export function DashboardHome() { }, body: JSON.stringify({ name, git_url: gitUrl, branch }) }) - const data = await response.json() - await fetch(`${API_URL}/repos/${data.repo_id}/index`, { method: 'POST', headers: { 'Authorization': `Bearer ${session?.access_token}` } }) - await fetchRepos() - toast.success('Repository added!', { - description: `${name} is now being indexed` - }) + toast.success('Repository added!', { description: `${name} is now being indexed` }) } catch (error) { console.error('Error adding repo:', error) - toast.error('Failed to add repository', { - description: 'Please check the Git URL and try again' - }) + toast.error('Failed to add repository', { description: 'Please check the Git URL and try again' }) } finally { setLoading(false) } @@ -82,7 +74,6 @@ export function DashboardHome() { const handleReindex = async () => { if (!selectedRepo) return - try { setLoading(true) await fetch(`${API_URL}/repos/${selectedRepo}/index`, { @@ -91,9 +82,7 @@ export function DashboardHome() { }) await fetchRepos() } catch (error) { - toast.error('Re-indexing failed', { - description: 'Please check the console for details' - }) + toast.error('Re-indexing failed', { description: 'Please check the console for details' }) } finally { setLoading(false) } @@ -102,151 +91,154 @@ export function DashboardHome() { const selectedRepoData = repos.find(r => r.id === selectedRepo) const isRepoView = selectedRepo && selectedRepoData - // Tab button component - const TabButton = ({ tab, label }: { tab: RepoTab; label: string }) => ( - - ) + const tabs = [ + { id: 'overview', label: 'Overview', icon: LayoutDashboard }, + { id: 'search', label: 'Search', icon: Search }, + { id: 'dependencies', label: 'Dependencies', icon: GitFork }, + { id: 'insights', label: 'Code Style', icon: Code2 }, + { id: 'impact', label: 'Impact', icon: Zap }, + ] as const return (
- {/* Performance Dashboard Toggle */} - {showPerformance && ( -
- -
- )} - - {/* Repository List View */} - {!isRepoView && ( -
-
-
-

Repositories

-

- {repos.length} repositories • {repos.filter(r => r.status === 'indexed').length} indexed -

-
-
- + + {/* Repository List View */} + {!isRepoView && ( + + {/* Header */} +
+
+

Repositories

+

+ Semantic code search powered by AI +

+
-
- - { - setSelectedRepo(id) - setActiveTab('overview') - }} - /> -
- )} - - {/* Single Repo View */} - {isRepoView && ( -
- {/* Back Button & Header */} -
- + /> + + )} + + {/* Single Repo View */} + {isRepoView && ( + + {/* Header */} +
+ -
-
-

{selectedRepoData.name}

-

{selectedRepoData.git_url}

+
+
+
+ + + +
+
+

{selectedRepoData.name}

+ + {selectedRepoData.git_url} + +
+
- - {selectedRepoData.status === 'indexed' && ( - - ✓ Indexed - - )}
-
- - {/* Tabs */} -
- - - - - -
- - {/* Tab Content */} -
- {activeTab === 'overview' && ( - - )} - - {activeTab === 'search' && ( - - )} - - {activeTab === 'dependencies' && ( - - )} - {activeTab === 'insights' && ( - - )} + {/* Tabs */} +
+ {tabs.map(tab => ( + + ))} +
- {activeTab === 'impact' && ( - - )} -
-
- )} + {/* Tab Content */} +
+ {activeTab === 'overview' && ( + + )} + {activeTab === 'search' && ( + + )} + {activeTab === 'dependencies' && ( + + )} + {activeTab === 'insights' && ( + + )} + {activeTab === 'impact' && ( + + )} +
+
+ )} +
) } diff --git a/frontend/src/components/dashboard/DashboardStats.tsx b/frontend/src/components/dashboard/DashboardStats.tsx new file mode 100644 index 0000000..7d31fb1 --- /dev/null +++ b/frontend/src/components/dashboard/DashboardStats.tsx @@ -0,0 +1,82 @@ +import { useEffect, useState } from 'react' +import { motion } from 'framer-motion' +import type { Repository } from '../../types' + +interface DashboardStatsProps { + repos: Repository[] +} + +const useAnimatedCounter = (end: number, duration: number = 1200) => { + const [count, setCount] = useState(0) + + useEffect(() => { + if (end === 0) { setCount(0); return } + let startTime: number | null = null + const animate = (timestamp: number) => { + if (!startTime) startTime = timestamp + const progress = Math.min((timestamp - startTime) / duration, 1) + const easeOut = 1 - Math.pow(1 - progress, 3) + setCount(Math.floor(easeOut * end)) + if (progress < 1) requestAnimationFrame(animate) + } + requestAnimationFrame(animate) + }, [end, duration]) + + return count +} + +export function DashboardStats({ repos }: DashboardStatsProps) { + const totalRepos = repos.length + const indexedRepos = repos.filter(r => r.status === 'indexed').length + const totalFunctions = repos.reduce((acc, r) => acc + (r.file_count || 0), 0) + const indexingCount = repos.filter(r => r.status === 'indexing' || r.status === 'cloning').length + + const animatedTotal = useAnimatedCounter(totalRepos) + const animatedIndexed = useAnimatedCounter(indexedRepos) + const animatedFunctions = useAnimatedCounter(totalFunctions) + + return ( +
+ {/* Total Repos */} + +

Total Repositories

+

{animatedTotal}

+
+ + {/* Indexed */} + +

Indexed

+
+ {animatedIndexed} + /{totalRepos} +
+ {indexingCount > 0 && ( +
+ + {indexingCount} indexing... +
+ )} +
+ + {/* Functions */} + +

Functions Indexed

+

{animatedFunctions.toLocaleString()}

+
+
+ ) +} diff --git a/frontend/src/components/search/ResultCard.tsx b/frontend/src/components/search/ResultCard.tsx index 35079b5..81ec78a 100644 --- a/frontend/src/components/search/ResultCard.tsx +++ b/frontend/src/components/search/ResultCard.tsx @@ -2,6 +2,7 @@ import { useState, useRef, useEffect } from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { toast } from 'sonner'; +import { Sparkles } from 'lucide-react'; import type { SearchResult } from '../../types'; interface ResultCardProps { @@ -121,7 +122,7 @@ export function ResultCard({ {aiSummary && isTopResult && (
- +

AI Summary

{aiSummary}