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}`;

}