ewdlop's picture
App.tsx
42ae0b9
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>
);
}