| import { useState } from "react"; |
| import { Copy, Check, ArrowLeftRight, Wand2 } from "lucide-react"; |
| import { toast } from "sonner"; |
| import type { FormatResult } from "@/lib/api"; |
|
|
| interface FormatterPanelProps { |
| result: FormatResult | null; |
| onApplyToEditor?: (sql: string) => void; |
| } |
|
|
| export function FormatterPanel({ result, onApplyToEditor }: FormatterPanelProps) { |
| const [copied, setCopied] = useState(false); |
|
|
| const handleCopy = async () => { |
| if (!result) return; |
| await navigator.clipboard.writeText(result.formatted); |
| setCopied(true); |
| toast.success("Copied to clipboard"); |
| setTimeout(() => setCopied(false), 2000); |
| }; |
|
|
| const handleApply = () => { |
| if (!result) return; |
| onApplyToEditor?.(result.formatted); |
| toast.success("Applied to editor"); |
| }; |
|
|
| if (!result) { |
| return ( |
| <div className="flex flex-col items-center justify-center h-full gap-3 text-[oklch(0.45_0.010_264)]"> |
| <Wand2 size={32} className="opacity-30" /> |
| <p className="text-sm">Run analysis to see formatted SQL</p> |
| </div> |
| ); |
| } |
|
|
| return ( |
| <div className="flex flex-col h-full"> |
| {/* Toolbar */} |
| <div className="flex items-center gap-2 px-3 py-2 border-b border-[oklch(0.22_0.010_264)] flex-shrink-0"> |
| <div className="flex items-center gap-2 flex-1"> |
| {result.changed ? ( |
| <div className="flex items-center gap-1.5 text-xs" style={{ color: "oklch(0.72 0.17 160)" }}> |
| <Wand2 size={13} /> |
| <span className="font-medium">{result.fixes_applied} fix{result.fixes_applied !== 1 ? "es" : ""} applied</span> |
| </div> |
| ) : ( |
| <div className="flex items-center gap-1.5 text-xs text-[oklch(0.55_0.010_264)]"> |
| <Check size={13} /> |
| <span>No formatting changes needed</span> |
| </div> |
| )} |
| <span className="text-[10px] text-[oklch(0.38_0.010_264)] font-mono ml-2"> |
| dialect: {result.dialect} |
| </span> |
| </div> |
| |
| <button |
| onClick={handleCopy} |
| className="flex items-center gap-1.5 h-7 px-2 text-xs rounded transition-colors" |
| style={{ color: "var(--text-secondary)", background: "transparent" }} |
| > |
| {copied ? <Check size={12} /> : <Copy size={12} />} |
| {copied ? "Copied" : "Copy"} |
| </button> |
| |
| <button |
| onClick={handleApply} |
| className="flex items-center gap-1.5 h-7 px-2 text-xs font-semibold rounded" |
| style={{ background: "var(--accent-blue)", color: "var(--bg-base)" }} |
| > |
| <ArrowLeftRight size={12} /> |
| Apply to Editor |
| </button> |
| </div> |
| |
| {/* Diff indicator */} |
| {result.changed && ( |
| <div className="flex items-center gap-2 px-3 py-1.5 border-b border-[oklch(0.22_0.010_264)] flex-shrink-0 bg-[oklch(0.72_0.17_160_/_0.05)]"> |
| <ArrowLeftRight size={11} style={{ color: "oklch(0.72 0.17 160)" }} /> |
| <span className="text-[10px] text-[oklch(0.60_0.010_264)]"> |
| Formatted SQL differs from original |
| </span> |
| </div> |
| )} |
| |
| {/* Formatted SQL output */} |
| <div className="flex-1 overflow-auto"> |
| <pre |
| className="p-4 text-xs font-mono leading-relaxed text-[oklch(0.85_0.010_264)] whitespace-pre-wrap break-words" |
| style={{ fontFamily: "'JetBrains Mono', monospace" }} |
| > |
| {result.formatted} |
| </pre> |
| </div> |
| </div> |
| ); |
| } |
|
|