ar9avg's picture
fix
17e7bd7
import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Database, Table2, ChevronDown, ChevronRight, GitFork, ShoppingCart } from 'lucide-react'
import { useStore } from '../store/useStore'
import type { Difficulty } from '../lib/types'
const DIFFICULTY_CONFIG: Record<Difficulty, { label: string; bg: string; text: string; border: string }> = {
easy: { label: 'Easy', bg: 'bg-green-500/10', text: 'text-green-400', border: 'border-green-500/30' },
medium: { label: 'Medium', bg: 'bg-amber-500/10', text: 'text-amber-400', border: 'border-amber-500/30' },
hard: { label: 'Hard', bg: 'bg-red-500/10', text: 'text-red-400', border: 'border-red-500/30' },
}
export function LeftSidebar() {
const { tables, taskDifficulty, setTaskDifficulty, dbSeeded, isCustomDb, dbLabel } = useStore()
const [tablesExpanded, setTablesExpanded] = useState(true)
const cfg = DIFFICULTY_CONFIG[taskDifficulty]
return (
<div className="flex flex-col gap-4 py-1">
{/* Task Difficulty — hidden for custom databases */}
{!isCustomDb && (
<section>
<div className="text-[10px] font-semibold text-gray-500 uppercase tracking-widest mb-2 flex items-center gap-1.5">
<GitFork size={10} className="text-violet-400" />
Task Difficulty
</div>
<div className="flex flex-col gap-1">
{(Object.keys(DIFFICULTY_CONFIG) as Difficulty[]).map((d) => {
const c = DIFFICULTY_CONFIG[d]
const active = d === taskDifficulty
return (
<button
key={d}
onClick={() => setTaskDifficulty(d)}
className={`flex items-center justify-between px-3 py-2 rounded-lg border text-xs font-medium transition-all ${
active
? `${c.bg} ${c.text} ${c.border}`
: 'border-transparent text-gray-500 hover:text-gray-300 hover:bg-white/5'
}`}
>
<span>{c.label}</span>
{active && (
<span className={`text-[9px] font-mono ${c.text} opacity-70`}>selected</span>
)}
</button>
)
})}
</div>
</section>
)}
{/* Schema Tables */}
<section>
<button
className="text-[10px] font-semibold text-gray-500 uppercase tracking-widest mb-2 flex items-center gap-1.5 w-full"
onClick={() => setTablesExpanded((v) => !v)}
>
<Database size={10} className="text-blue-400" />
<span className="flex-1 text-left">Database Schema</span>
{tablesExpanded ? <ChevronDown size={10} /> : <ChevronRight size={10} />}
</button>
<AnimatePresence>
{tablesExpanded && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="overflow-hidden"
>
{dbSeeded && tables.length > 0 ? (
<div className="flex flex-col gap-1">
{tables.map((t) => (
<div
key={t.name}
className="flex items-center justify-between px-2.5 py-1.5 rounded-lg border border-white/[0.04] bg-white/[0.02] hover:bg-white/[0.04] transition-colors"
>
<div className="flex items-center gap-1.5">
<Table2 size={10} className="text-blue-400 shrink-0" />
<span className="text-xs text-gray-300 font-mono">{t.name}</span>
</div>
<span className="text-[9px] text-gray-600 font-mono tabular-nums">
{t.rows.toLocaleString()}
</span>
</div>
))}
</div>
) : (
<div className="flex flex-col gap-1">
{[120, 80, 95, 60, 70].map((w, i) => (
<div
key={i}
className="flex items-center justify-between px-2.5 py-1.5 rounded-lg border border-white/[0.04] bg-white/[0.02]"
>
<div
className="h-2 rounded bg-white/10 animate-pulse"
style={{ width: w }}
/>
<div className="h-2 w-8 rounded bg-white/10 animate-pulse" />
</div>
))}
</div>
)}
</motion.div>
)}
</AnimatePresence>
</section>
{/* Business Context */}
<section>
<div className="text-[10px] font-semibold text-gray-500 uppercase tracking-widest mb-2 flex items-center gap-1.5">
<ShoppingCart size={10} className="text-orange-400" />
Business Context
</div>
<div
className="rounded-xl border border-white/[0.05] p-3 text-[11px] text-gray-500 leading-relaxed"
style={{ background: 'var(--bg-card)' }}
>
{isCustomDb ? (
<p className="text-gray-600 italic">
Connected to <span className="text-violet-400 not-italic font-medium">{dbLabel}</span>.
Ask questions about your data in natural language.
</p>
) : (
<>
<p className="mb-2 text-gray-400 font-medium">E-Commerce Marketplace</p>
<p>
Multi-vendor marketplace with products, orders, sellers, users, and reviews.
Supports complex analytical queries across sales, inventory, and user behavior.
</p>
<div className="mt-2 flex flex-wrap gap-1">
{['Products', 'Orders', 'Sellers', 'Users', 'Reviews', 'Categories'].map((t) => (
<span
key={t}
className="text-[9px] px-1.5 py-0.5 rounded border border-white/[0.06] text-gray-600"
>
{t}
</span>
))}
</div>
</>
)}
</div>
</section>
{/* Current task badge — hidden for custom databases */}
{!isCustomDb && (
<section>
<div
className={`rounded-xl border ${cfg.border} ${cfg.bg} p-3 flex flex-col gap-1.5`}
>
<div className="flex items-center justify-between">
<span className={`text-[10px] font-semibold uppercase tracking-wider ${cfg.text}`}>
Current Task
</span>
<span className={`text-[10px] font-mono ${cfg.text}`}>{cfg.label}</span>
</div>
<p className="text-[11px] text-gray-400 leading-relaxed">
{taskDifficulty === 'easy'
? 'Simple SELECT queries, basic filtering and aggregation'
: taskDifficulty === 'medium'
? 'Multi-table JOINs, GROUP BY, subqueries, window functions'
: 'Complex CTEs, rolling aggregations, cohort analysis, ranking'}
</p>
</div>
</section>
)}
</div>
)
}