File size: 1,387 Bytes
db7ef8e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /** CSV / SQL helpers for per-component export & copy. */
export function rowsToCsv(rows: any[]): string {
if (!rows?.length) return "";
const cols = Object.keys(rows[0]);
const esc = (v: any): string => {
if (v == null) return "";
const s = typeof v === "string" ? v : JSON.stringify(v);
if (/[",\n]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
return s;
};
const head = cols.join(",");
const body = rows.map((r) => cols.map((c) => esc(r[c])).join(",")).join("\n");
return head + "\n" + body;
}
export function downloadFile(name: string, content: string, mime = "text/csv") {
const blob = new Blob([content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = name;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
}
export async function copyToClipboard(text: string): Promise<boolean> {
try {
await navigator.clipboard.writeText(text);
return true;
} catch {
return false;
}
}
export function safeFilename(s: string, ext: string): string {
const base = (s || "export")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "_")
.replace(/^_+|_+$/g, "")
.slice(0, 50);
return `${base || "export"}.${ext}`;
}
|