diff --git a/Icons/Address.png b/Icons/Address.png new file mode 100644 index 0000000..70bf4e9 Binary files /dev/null and b/Icons/Address.png differ diff --git a/Icons/Mail.png b/Icons/Mail.png new file mode 100644 index 0000000..437d1b4 Binary files /dev/null and b/Icons/Mail.png differ diff --git a/Icons/Mobile.png b/Icons/Mobile.png new file mode 100644 index 0000000..d6c2abd Binary files /dev/null and b/Icons/Mobile.png differ diff --git a/Icons/Phone.png b/Icons/Phone.png new file mode 100644 index 0000000..7a5ad07 Binary files /dev/null and b/Icons/Phone.png differ diff --git a/packages/core-service/assets/icons/Address.png b/packages/core-service/assets/icons/Address.png new file mode 100644 index 0000000..70bf4e9 Binary files /dev/null and b/packages/core-service/assets/icons/Address.png differ diff --git a/packages/core-service/assets/icons/Mail.png b/packages/core-service/assets/icons/Mail.png new file mode 100644 index 0000000..437d1b4 Binary files /dev/null and b/packages/core-service/assets/icons/Mail.png differ diff --git a/packages/core-service/assets/icons/Mobile.png b/packages/core-service/assets/icons/Mobile.png new file mode 100644 index 0000000..d6c2abd Binary files /dev/null and b/packages/core-service/assets/icons/Mobile.png differ diff --git a/packages/core-service/assets/icons/Phone.png b/packages/core-service/assets/icons/Phone.png new file mode 100644 index 0000000..7a5ad07 Binary files /dev/null and b/packages/core-service/assets/icons/Phone.png differ 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 7aa8652..a245302 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 @@ -1,6 +1,8 @@ import { Injectable, Logger } from '@nestjs/common'; import { ExpertProfileService } from './expert-profile.service'; import PDFDocument from 'pdfkit'; +import * as fs from 'fs'; +import * as path from 'path'; import { Document, Packer, @@ -95,8 +97,24 @@ function lightenColor(hex: string, factor: number): string { export class ProfileExportService { private readonly logger = new Logger(ProfileExportService.name); + // Pfad zu den Icon-Assets (relativ zum Working Directory /app im Container) + private readonly iconsDir = path.resolve(process.cwd(), 'assets', 'icons'); + constructor(private readonly expertProfileService: ExpertProfileService) {} + private loadIcon(name: string): Buffer | null { + try { + const iconPath = path.join(this.iconsDir, name); + if (fs.existsSync(iconPath)) { + return fs.readFileSync(iconPath); + } + this.logger.warn(`Icon nicht gefunden: ${iconPath}`); + } catch (err) { + this.logger.warn(`Icon konnte nicht geladen werden: ${name}`, err); + } + return null; + } + // ============================================================ // PDF Export // ============================================================ @@ -173,21 +191,28 @@ export class ProfileExportService { // --- KONTAKT --- yLeft = this.pdfSectionTitle(doc, 'KONTAKT', leftColX, yLeft, leftColWidth, accentColor); - const iconTextOffset = 18; // Abstand Icon → Text + // Icons laden + const phoneIcon = this.loadIcon('Phone.png'); + const mobileIcon = this.loadIcon('Mobile.png'); + const mailIcon = this.loadIcon('Mail.png'); + const addressIcon = this.loadIcon('Address.png'); + const iconSize = 12; + const iconTextOffset = 20; // Abstand Icon → Text + if (data.phone) { - this.drawHandsetIcon(doc, leftColX + 1, yLeft, accentColor); + if (phoneIcon) doc.image(phoneIcon, leftColX, yLeft - 1, { width: iconSize, height: iconSize }); yLeft = this.pdfContactText(doc, data.phone, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.mobile) { - this.drawMobileIcon(doc, leftColX + 1, yLeft, accentColor); + if (mobileIcon) doc.image(mobileIcon, leftColX + 1, yLeft - 1, { width: iconSize, height: iconSize }); yLeft = this.pdfContactText(doc, data.mobile, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.email) { - this.drawEmailIcon(doc, leftColX, yLeft + 1, accentColor); + if (mailIcon) doc.image(mailIcon, leftColX, yLeft - 1, { width: iconSize, height: iconSize }); yLeft = this.pdfContactText(doc, data.email, leftColX + iconTextOffset, yLeft, leftColWidth - iconTextOffset); } if (data.street || data.city) { - this.drawLocationIcon(doc, leftColX, yLeft, accentColor); + if (addressIcon) doc.image(addressIcon, leftColX + 1, yLeft - 2, { width: iconSize, height: iconSize + 2 }); const line1 = data.street || ''; const line2 = [data.postalCode, data.city].filter(Boolean).join(' '); const addressText = [line1, line2].filter(Boolean).join('\n'); @@ -729,76 +754,6 @@ export class ProfileExportService { return y + Math.max(textHeight, 10) + 3; } - // --- Vektor-Icons für Kontakt --- - - private drawHandsetIcon(doc: PDFKit.PDFDocument, x: number, y: number, color: string): void { - doc.save(); - // Klassischer Telefonhörer als zusammenhängende Silhouette - // Ohrmuschel + Sprechmuschel als Blöcke, Griff als gefüllter Bogen - - // Ohrmuschel (oben) - doc.roundedRect(x, y, 10, 3.5, 1.5).fill(color); - - // Sprechmuschel (unten) - doc.roundedRect(x, y + 7.5, 10, 3.5, 1.5).fill(color); - - // Griff: gefüllte Bogenform (Crescent) — verbindet nahtlos - // Äußerer Bogen (weit nach links) - doc.moveTo(x + 4, y + 3) - .bezierCurveTo(x - 2, y + 4, x - 2, y + 7, x + 4, y + 8) - // Innerer Bogen (zurück, näher zur Mitte) - .bezierCurveTo(x + 1.5, y + 6.5, x + 1.5, y + 4.5, x + 4, y + 3) - .fill(color); - - doc.restore(); - } - - private drawMobileIcon(doc: PDFKit.PDFDocument, x: number, y: number, color: string): void { - doc.save(); - // 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(); - 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(); - // 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ß) für Pin-Look - doc.circle(cx, top + r, 1.5).fill('#ffffff'); - doc.restore(); - } - // ============================================================ // DOCX-Hilfsfunktionen // ============================================================ diff --git a/templates/cv/default/Address.png b/templates/cv/default/Address.png new file mode 100644 index 0000000..70bf4e9 Binary files /dev/null and b/templates/cv/default/Address.png differ diff --git a/templates/cv/default/Mail.png b/templates/cv/default/Mail.png new file mode 100644 index 0000000..437d1b4 Binary files /dev/null and b/templates/cv/default/Mail.png differ diff --git a/templates/cv/default/Mobile.png b/templates/cv/default/Mobile.png new file mode 100644 index 0000000..d6c2abd Binary files /dev/null and b/templates/cv/default/Mobile.png differ diff --git a/templates/cv/default/Phone.png b/templates/cv/default/Phone.png new file mode 100644 index 0000000..7a5ad07 Binary files /dev/null and b/templates/cv/default/Phone.png differ