- Fix all 3 address constants: Christescu (nr. 12, 400416), Unirii (nr. 3 sc. 3 ap. 26, 400432), Albac (nr. 2 ap. 1, 400459) - Add 3rd address option (Albac) to all company address selectors - Default address changed to Christescu for all companies - Update US brand colors to logo blue (#345476), SDT to logo teal (#0182A1) - Fix slashAccent for US/SDT (was pointing to logo files instead of slash assets) - Add logoDimensions to CompanyBranding type for per-company logo sizing - Set US logo to 140x24 and SDT to 71x24 (matching SVG aspect ratios) - Fix sidebar hydration error: remove unused useTheme() hook call - Update color palettes in configurator to match logo-derived colors Tasks: 1.01 (verified), 1.02 (address toggle + fixes)
147 lines
7.0 KiB
TypeScript
147 lines
7.0 KiB
TypeScript
import type { SignatureConfig, CompanyBranding } from "../types";
|
|
import { getBranding } from "./company-branding";
|
|
|
|
export function formatPhone(raw: string): { display: string; link: string } {
|
|
const clean = raw.replace(/\s/g, "");
|
|
if (clean.length === 10 && clean.startsWith("07")) {
|
|
return {
|
|
display: `+40 ${clean.substring(1, 4)} ${clean.substring(4, 7)} ${clean.substring(7, 10)}`,
|
|
link: `tel:+40${clean.substring(1)}`,
|
|
};
|
|
}
|
|
return { display: raw, link: `tel:${clean}` };
|
|
}
|
|
|
|
export function generateSignatureHtml(config: SignatureConfig): string {
|
|
const branding = getBranding(config.company);
|
|
const address = config.addressOverride ?? branding.address;
|
|
const { display: phone, link: phoneLink } = formatPhone(config.phone);
|
|
const images = config.useSvg
|
|
? {
|
|
logo: branding.logo.svg,
|
|
greySlash: branding.slashGrey.svg,
|
|
accentSlash: branding.slashAccent.svg,
|
|
}
|
|
: {
|
|
logo: branding.logo.png,
|
|
greySlash: branding.slashGrey.png,
|
|
accentSlash: branding.slashAccent.png,
|
|
};
|
|
|
|
const {
|
|
greenLineWidth,
|
|
gutterWidth,
|
|
iconTextSpacing,
|
|
iconVerticalOffset,
|
|
mottoSpacing,
|
|
sectionSpacing,
|
|
titleSpacing,
|
|
logoSpacing,
|
|
} = config.layout;
|
|
const colors = config.colors;
|
|
|
|
const isReply = config.variant === "reply" || config.variant === "minimal";
|
|
const isMinimal = config.variant === "minimal";
|
|
|
|
const logoDim = branding.logoDimensions ?? { width: 162, height: 24 };
|
|
|
|
const hide =
|
|
"mso-hide:all;display:none!important;max-height:0;overflow:hidden;font-size:0;line-height:0;";
|
|
const hideTitle = isReply ? hide : "";
|
|
const hideLogo = isReply ? hide : "";
|
|
const hideBottom = isMinimal ? hide : "";
|
|
const hidePhoneIcon = isMinimal ? hide : "";
|
|
|
|
const spacerWidth = Math.max(0, iconTextSpacing);
|
|
const textPaddingLeft = Math.max(0, -iconTextSpacing);
|
|
|
|
const prefixHtml = config.prefix
|
|
? `<span style="font-size:13px; color:${colors.prefix};">${esc(config.prefix)} </span>`
|
|
: "";
|
|
|
|
return `<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="540" style="font-family: Arial, Helvetica, sans-serif; color:#333333; font-size:14px; line-height:18px;">
|
|
<tbody>
|
|
<tr><td style="padding:0 0 ${titleSpacing}px 0;">${prefixHtml}<span style="font-size:15px; color:${colors.name}; font-weight:700;">${esc(config.name)}</span></td></tr>
|
|
<tr style="${hideTitle}"><td style="padding:0 0 8px 0;"><span style="font-size:12px; color:${colors.title};">${esc(config.title)}</span></td></tr>
|
|
<tr style="${hideBottom}">
|
|
<td style="padding:0; font-size:0; line-height:0;">
|
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="540">
|
|
<tr>
|
|
<td width="${greenLineWidth}" height="2" bgcolor="${branding.accent}" style="font-size:0; line-height:0; height:2px;"></td>
|
|
<td width="${540 - greenLineWidth}" height="2" style="font-size:0; line-height:0; height:2px;"></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
<tr style="${hideLogo}"><td style="padding:${logoSpacing}px 0 ${logoSpacing + 2}px 0;">
|
|
${
|
|
images.logo
|
|
? `<a href="https://${branding.website}" style="text-decoration:none; border:0;">
|
|
<img src="${images.logo}" alt="${esc(branding.name)}" style="display:block; border:0; height:${logoDim.height}px; width:${logoDim.width}px;" height="${logoDim.height}" width="${logoDim.width}">
|
|
</a>`
|
|
: ""
|
|
}
|
|
</td></tr>
|
|
<tr>
|
|
<td style="padding-top:${hideLogo ? "0" : sectionSpacing}px;">
|
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="540" style="font-size:13px; line-height:18px;">
|
|
<tbody>
|
|
<tr style="${hideLogo}">
|
|
<td width="${gutterWidth}" style="width:${gutterWidth}px; font-size:0; line-height:0;"></td>
|
|
<td width="11" style="width:11px; vertical-align:top; padding-top:${4 + iconVerticalOffset}px;">
|
|
${images.greySlash ? `<img src="${images.greySlash}" alt="" width="11" height="11" style="display:block; border:0;">` : ""}
|
|
</td>
|
|
<td width="${spacerWidth}" style="width:${spacerWidth}px; font-size:0; line-height:0;"></td>
|
|
<td style="vertical-align:top; padding:0 0 0 ${textPaddingLeft}px;">
|
|
<span style="color:${colors.address}; text-decoration:none;">${address.join("<br>")}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td width="${gutterWidth}" style="width:${gutterWidth}px; font-size:0; line-height:0;"></td>
|
|
<td width="11" style="width:11px; vertical-align:top; padding-top:${12 + iconVerticalOffset}px; ${hidePhoneIcon}">
|
|
${images.accentSlash ? `<img src="${images.accentSlash}" alt="" width="11" height="7" style="display:block; border:0;">` : ""}
|
|
</td>
|
|
<td width="${isMinimal ? 0 : spacerWidth}" style="width:${isMinimal ? 0 : spacerWidth}px; font-size:0; line-height:0;"></td>
|
|
<td style="vertical-align:top; padding:8px 0 0 ${isMinimal ? 0 : textPaddingLeft}px;">
|
|
<a href="${phoneLink}" style="color:${colors.phone}; text-decoration:none;"><span style="color:${colors.phone}; text-decoration:none;">${phone}</span></a>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
${branding.website ? `<tr style="${hideBottom}"><td style="padding:${sectionSpacing}px 0 ${mottoSpacing}px 0;"><a href="https://${branding.website}" style="color:${colors.website}; text-decoration:none;"><span style="color:${colors.website}; text-decoration:none;">${branding.website}</span></a></td></tr>` : ""}
|
|
<tr style="${hideBottom}">
|
|
<td style="padding:0; font-size:0; line-height:0;">
|
|
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="540">
|
|
<tr>
|
|
<td width="${greenLineWidth}" height="1" bgcolor="${branding.accent}" style="font-size:0; line-height:0; height:1px;"></td>
|
|
<td width="${540 - greenLineWidth}" height="1" style="font-size:0; line-height:0; height:1px;"></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
${branding.motto ? `<tr style="${hideBottom}"><td style="padding:${mottoSpacing}px 0 0 0;"><span style="font-size:12px; color:${colors.motto}; font-style:italic;">${esc(branding.motto)}</span></td></tr>` : ""}
|
|
</tbody>
|
|
</table>`;
|
|
}
|
|
|
|
function esc(text: string): string {
|
|
return text
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|
|
|
|
export function downloadSignatureHtml(html: string, filename: string): void {
|
|
const blob = new Blob([html], { type: "text/html" });
|
|
const a = document.createElement("a");
|
|
a.href = URL.createObjectURL(blob);
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(a.href);
|
|
}
|