Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { useState, useRef, useEffect } from "react"; | |
| import { FileDown, ChevronDown, Loader2 } from "lucide-react"; | |
| import { EXPORT_FORMATS } from "@/lib/export-utils"; | |
| import type { AnalysisResult } from "@/lib/types"; | |
| export function ExportDropdown({ results }: { results: AnalysisResult }) { | |
| const [open, setOpen] = useState(false); | |
| const [exporting, setExporting] = useState<string | null>(null); | |
| const ref = useRef<HTMLDivElement>(null); | |
| useEffect(() => { | |
| function handleClickOutside(e: MouseEvent) { | |
| if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); | |
| } | |
| document.addEventListener("mousedown", handleClickOutside); | |
| return () => document.removeEventListener("mousedown", handleClickOutside); | |
| }, []); | |
| async function handleExport(key: string, fn: (r: AnalysisResult) => void | Promise<any>) { | |
| setExporting(key); | |
| try { | |
| await fn(results); | |
| } catch (e) { | |
| console.error("Export failed:", e); | |
| } | |
| setExporting(null); | |
| setOpen(false); | |
| } | |
| return ( | |
| <div ref={ref} className="relative"> | |
| <button | |
| onClick={() => setOpen(!open)} | |
| className="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-zinc-600 bg-white border border-zinc-200 rounded-lg hover:bg-zinc-50 hover:border-zinc-300 transition-all shadow-sm" | |
| > | |
| <FileDown className="w-3.5 h-3.5" /> | |
| Export | |
| <ChevronDown className={`w-3 h-3 transition-transform ${open ? "rotate-180" : ""}`} /> | |
| </button> | |
| {open && ( | |
| <div className="absolute right-0 top-full mt-1.5 w-64 bg-white border border-zinc-200 rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in slide-in-from-top-1 duration-150"> | |
| <div className="px-3 py-2 border-b border-zinc-100"> | |
| <p className="text-[10px] font-semibold text-zinc-400 uppercase tracking-wider">Export Report</p> | |
| </div> | |
| <div className="py-1"> | |
| {EXPORT_FORMATS.map((fmt) => ( | |
| <button | |
| key={fmt.key} | |
| onClick={() => handleExport(fmt.key, fmt.fn)} | |
| disabled={exporting !== null} | |
| className="w-full flex items-center gap-3 px-3 py-2.5 text-left hover:bg-zinc-50 transition-colors disabled:opacity-40" | |
| > | |
| <span className="text-base w-5 text-center">{fmt.icon}</span> | |
| <div className="flex-1 min-w-0"> | |
| <p className="text-sm font-medium text-zinc-700">{fmt.label}</p> | |
| <p className="text-[10px] text-zinc-400">{fmt.description}</p> | |
| </div> | |
| {exporting === fmt.key && <Loader2 className="w-3.5 h-3.5 text-zinc-400 animate-spin" />} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |