fix: add PNG icons and Arial font to DOCX export

Replaces text labels (Tel., Mobil, Mail, Adr.) with recolored PNG icons
in the Word export contact section. Sets Arial as default document font
to match Helvetica in the PDF export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Reitz 2026-03-09 20:27:32 +01:00
parent b948027dab
commit f4239760df

View file

@ -512,37 +512,50 @@ export class ProfileExportService {
// Kontakt-Sektion
leftParagraphs.push(this.docxSectionHeading('KONTAKT', accentHex));
const contactItems: Array<{ label: string; text: string }> = [];
if (data.phone) contactItems.push({ label: 'Tel.', text: data.phone });
if (data.mobile) contactItems.push({ label: 'Mobil', text: data.mobile });
if (data.email) contactItems.push({ label: 'Mail', text: data.email });
for (const item of contactItems) {
leftParagraphs.push(
new Paragraph({
children: [
new TextRun({ text: `${item.label} `, bold: true, size: 14, color: accentHex }),
new TextRun({ text: item.text, size: 16, color: '555555' }),
],
spacing: { after: 60 },
}),
);
}
// Icons für DOCX laden (eingefärbt in Akzentfarbe)
const docxPhoneIcon = this.loadIcon('Phone.png', accentColor);
const docxMobileIcon = this.loadIcon('Mobile.png', accentColor);
const docxMailIcon = this.loadIcon('Mail.png', accentColor);
const docxAddressIcon = this.loadIcon('Address.png', accentColor);
const docxIconSize = 12;
// Adresse separat (mit Zeilenumbruch)
if (data.phone) {
const children: (ImageRun | TextRun)[] = [];
if (docxPhoneIcon) {
children.push(new ImageRun({ data: docxPhoneIcon, transformation: { width: docxIconSize, height: docxIconSize }, type: 'png' }));
}
children.push(new TextRun({ text: ' ' + data.phone, size: 16, color: '555555' }));
leftParagraphs.push(new Paragraph({ children, spacing: { after: 60 } }));
}
if (data.mobile) {
const children: (ImageRun | TextRun)[] = [];
if (docxMobileIcon) {
children.push(new ImageRun({ data: docxMobileIcon, transformation: { width: docxIconSize, height: docxIconSize }, type: 'png' }));
}
children.push(new TextRun({ text: ' ' + data.mobile, size: 16, color: '555555' }));
leftParagraphs.push(new Paragraph({ children, spacing: { after: 60 } }));
}
if (data.email) {
const children: (ImageRun | TextRun)[] = [];
if (docxMailIcon) {
children.push(new ImageRun({ data: docxMailIcon, transformation: { width: docxIconSize, height: docxIconSize }, type: 'png' }));
}
children.push(new TextRun({ text: ' ' + data.email, size: 16, color: '555555' }));
leftParagraphs.push(new Paragraph({ children, spacing: { after: 60 } }));
}
if (data.street || data.city) {
const addrRuns: TextRun[] = [
new TextRun({ text: 'Adr. ', bold: true, size: 14, color: accentHex }),
];
const children: (ImageRun | TextRun)[] = [];
if (docxAddressIcon) {
children.push(new ImageRun({ data: docxAddressIcon, transformation: { width: docxIconSize, height: docxIconSize + 2 }, type: 'png' }));
}
if (data.street) {
addrRuns.push(new TextRun({ text: data.street, size: 16, color: '555555' }));
children.push(new TextRun({ text: ' ' + data.street, size: 16, color: '555555' }));
}
const cityLine = [data.postalCode, data.city].filter(Boolean).join(' ');
if (cityLine) {
addrRuns.push(new TextRun({ text: cityLine, size: 16, color: '555555', break: 1 }));
children.push(new TextRun({ text: ' ' + cityLine, size: 16, color: '555555', break: 1 }));
}
leftParagraphs.push(
new Paragraph({ children: addrRuns, spacing: { after: 60 } }),
);
leftParagraphs.push(new Paragraph({ children, spacing: { after: 60 } }));
}
// Sprachen
@ -725,6 +738,15 @@ export class ProfileExportService {
// --- Dokument zusammenstellen ---
const document = new Document({
styles: {
default: {
document: {
run: {
font: 'Arial',
},
},
},
},
sections: [
{
properties: {