feat: QR-Code, vCard-Export, Org-Gruppenansicht im Adressbuch
- vcard.ts: shared vCard-Generator (downloadVCard, downloadVCardAll, buildVCardString) - QrModal.svelte + QrButton.svelte: wiederverwendbare QR-Komponenten mit PNG-Download - AdressbuchBlock: Org-Gruppenansicht (Toggle), QR + vCard pro Kontakt, Buchstaben-Trennzeilen, Such-Highlight, "Alle exportieren", Print-Styles - ContactCard: vCard-Download-Button - PostActions: QR-Button für Seiten-URL - qrcode npm-Paket hinzugefügt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import type { ContactEntry } from "./block-types";
|
||||
|
||||
function vcardEscape(s: string): string {
|
||||
return s.replace(/\\/g, "\\\\").replace(/,/g, "\\,").replace(/;/g, "\\;").replace(/\n/g, "\\n");
|
||||
}
|
||||
|
||||
function buildVCard(c: ContactEntry): string {
|
||||
const name = vcardEscape(c.name ?? "");
|
||||
const orgs = (c.organisations ?? [])
|
||||
.filter((o): o is { name?: string } => typeof o === "object" && !!o.name)
|
||||
.map((o) => vcardEscape(o.name ?? ""))
|
||||
.join(", ");
|
||||
return [
|
||||
"BEGIN:VCARD",
|
||||
"VERSION:3.0",
|
||||
`FN:${name}`,
|
||||
"N:;;;;",
|
||||
orgs ? `ORG:${orgs}` : null,
|
||||
c.role ? `TITLE:${vcardEscape(c.role)}` : null,
|
||||
c.phone ? `TEL;TYPE=CELL:${c.phone.replace(/\s/g, "")}` : null,
|
||||
c.email ? `EMAIL:${vcardEscape(c.email)}` : null,
|
||||
c.note ? `ADR:;;${vcardEscape(c.note)};;;;` : null,
|
||||
"END:VCARD",
|
||||
].filter(Boolean).join("\r\n");
|
||||
}
|
||||
|
||||
export function buildVCardString(c: ContactEntry): string {
|
||||
return buildVCard(c);
|
||||
}
|
||||
|
||||
function triggerDownload(content: string, filename: string): void {
|
||||
const blob = new Blob([content], { type: "text/vcard;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
export function downloadVCard(c: ContactEntry): void {
|
||||
triggerDownload(buildVCard(c), `${(c.name ?? "kontakt").toLowerCase().replace(/\s+/g, "-")}.vcf`);
|
||||
}
|
||||
|
||||
export function downloadVCardAll(contacts: ContactEntry[], filename = "kontakte.vcf"): void {
|
||||
triggerDownload(contacts.map(buildVCard).join("\r\n"), filename);
|
||||
}
|
||||
Reference in New Issue
Block a user