From 82af9cb1f031de818dbbbadc4d8da07c24e28709 Mon Sep 17 00:00:00 2001 From: Thomas Reitz Date: Mon, 9 Mar 2026 12:14:32 +0100 Subject: [PATCH] fix: improve PDF contact icons - smartphone, envelope and map pin shapes Replaced rough vector shapes with proper recognizable icons: - Phone: smartphone outline with display area and home button - Email: envelope with cleaner V-flap proportions - Location: smooth teardrop map pin using bezier curves Co-Authored-By: Claude Opus 4.6 --- .../expert-profile/profile-export.service.ts | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/packages/core-service/src/core/expert-profile/profile-export.service.ts b/packages/core-service/src/core/expert-profile/profile-export.service.ts index f5c88aa..57f3400 100644 --- a/packages/core-service/src/core/expert-profile/profile-export.service.ts +++ b/packages/core-service/src/core/expert-profile/profile-export.service.ts @@ -173,24 +173,25 @@ export class ProfileExportService { // --- KONTAKT --- yLeft = this.pdfSectionTitle(doc, 'KONTAKT', leftColX, yLeft, leftColWidth, accentColor); + const iconTextOffset = 18; // Abstand Icon → Text if (data.phone) { - this.drawPhoneIcon(doc, leftColX, yLeft + 1, accentColor); - yLeft = this.pdfContactText(doc, data.phone, leftColX + 16, yLeft, leftColWidth - 16); + this.drawPhoneIcon(doc, leftColX + 1, yLeft, accentColor); + yLeft = this.pdfContactText(doc, data.phone, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.mobile) { - this.drawPhoneIcon(doc, leftColX, yLeft + 1, accentColor); - yLeft = this.pdfContactText(doc, data.mobile, leftColX + 16, yLeft, leftColWidth - 16); + this.drawPhoneIcon(doc, leftColX + 1, yLeft, accentColor); + yLeft = this.pdfContactText(doc, data.mobile, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.email) { this.drawEmailIcon(doc, leftColX, yLeft + 1, accentColor); - yLeft = this.pdfContactText(doc, data.email, leftColX + 16, yLeft, leftColWidth - 16); + yLeft = this.pdfContactText(doc, data.email, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.street || data.city) { - this.drawLocationIcon(doc, leftColX + 1, yLeft, accentColor); + this.drawLocationIcon(doc, leftColX, yLeft, accentColor); const line1 = data.street || ''; const line2 = [data.postalCode, data.city].filter(Boolean).join(' '); const addressText = [line1, line2].filter(Boolean).join('\n'); - yLeft = this.pdfContactText(doc, addressText, leftColX + 16, yLeft, leftColWidth - 16); + yLeft = this.pdfContactText(doc, addressText, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } yLeft += 10; @@ -732,33 +733,47 @@ export class ProfileExportService { private drawPhoneIcon(doc: PDFKit.PDFDocument, x: number, y: number, color: string): void { doc.save(); - // Telefon-Hörer: abgerundetes Rechteck - doc.roundedRect(x + 1, y, 4, 8, 1.5).fillAndStroke(color, color); - // Hörer-Bogen oben - doc.moveTo(x, y + 1).quadraticCurveTo(x - 1, y + 4, x + 1, y + 7) - .strokeColor(color).lineWidth(1.5).stroke(); + // Smartphone-Icon: abgerundetes Rechteck mit Display und Home-Button + const w = 7; + const h = 10; + doc.roundedRect(x, y - 1, w, h, 1.5).strokeColor(color).lineWidth(1).stroke(); + // Display-Bereich (inneres Rechteck) + doc.rect(x + 1.2, y + 1, w - 2.4, h - 4.5).fill(color); + // Home-Button (kleiner Kreis unten) + doc.circle(x + w / 2, y + h - 2, 0.8).fill(color); doc.restore(); } private drawEmailIcon(doc: PDFKit.PDFDocument, x: number, y: number, color: string): void { doc.save(); - // Briefumschlag - doc.rect(x, y + 1, 10, 7).strokeColor(color).lineWidth(1).stroke(); - // V-Linie oben - doc.moveTo(x, y + 1).lineTo(x + 5, y + 5).lineTo(x + 10, y + 1) + const w = 11; + const h = 8; + // Briefumschlag-Körper + doc.rect(x, y, w, h).strokeColor(color).lineWidth(0.8).stroke(); + // Klappen-Linien (V-Form von oben + Ecken unten) + doc.moveTo(x, y).lineTo(x + w / 2, y + h * 0.55).lineTo(x + w, y) .strokeColor(color).lineWidth(0.8).stroke(); doc.restore(); } private drawLocationIcon(doc: PDFKit.PDFDocument, x: number, y: number, color: string): void { doc.save(); - // Pin-Kopf (Kreis) - doc.circle(x + 4, y + 4, 3).fillAndStroke(color, color); - // Pin-Spitze (Dreieck) - doc.moveTo(x + 1.5, y + 5.5).lineTo(x + 4, y + 11).lineTo(x + 6.5, y + 5.5) + // Map-Pin als Tropfenform mit Bezier-Kurven + const cx = x + 5; // Mittelpunkt X + const top = y - 1; // Oberkante + const r = 4; // Radius des Kopfes + const tip = y + 11; // Spitze des Pins + + // Tropfenform: Start oben, links herum, Spitze unten, rechts hoch + doc.moveTo(cx, top) + .bezierCurveTo(cx - r * 1.1, top, cx - r, top + r * 0.6, cx - r, top + r) + .bezierCurveTo(cx - r, top + r * 1.8, cx - r * 0.3, tip - 2, cx, tip) + .bezierCurveTo(cx + r * 0.3, tip - 2, cx + r, top + r * 1.8, cx + r, top + r) + .bezierCurveTo(cx + r, top + r * 0.6, cx + r * 1.1, top, cx, top) .fill(color); - // Innerer Kreis (weiß) - doc.circle(x + 4, y + 4, 1.2).fill('#ffffff'); + + // Innerer Kreis (weiß) für Pin-Look + doc.circle(cx, top + r, 1.5).fill('#ffffff'); doc.restore(); }