fix(email-renderer): include brand logos in AMP and MJML exports
This commit is contained in:
1 parent
612b3945ac
commit
b915a2206f
3 files changed
+24
-3
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/email-renderer",
|
"name": "@wrnexus/email-renderer",
|
||||||
"version": "0.1.15",
|
"version": "0.1.16",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.",
|
"description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -117,9 +117,9 @@ export const emailDocumentBlock = defineBlock({
|
|||||||
emailHtml: ({ node, slots }) =>
|
emailHtml: ({ node, slots }) =>
|
||||||
`<table data-block-id="${html(node.id)}" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;background:${html(attrs(node).background ?? "#f3f4f6")};color:${html(attrs(node).textColor ?? "#111827")};font-family:${html(attrs(node).fontFamily ?? "Arial, sans-serif")};"><tr><td align="center">${attrs(node).logoUrl ? `<img src="${html(attrs(node).logoUrl)}" alt="${html(attrs(node).logoAlt)}" style="display:block;height:auto;max-width:200px;padding:20px;" />` : ""}<table role="presentation" class="wrn-email" width="${html(attrs(node).width)}" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;max-width:100%;width:${html(attrs(node).width)}px;background:${html(attrs(node).contentBackground ?? "#ffffff")};color:${html(attrs(node).textColor ?? "#111827")};font-family:${html(attrs(node).fontFamily ?? "Arial, sans-serif")};">${slots.content}</table></td></tr></table>`,
|
`<table data-block-id="${html(node.id)}" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;background:${html(attrs(node).background ?? "#f3f4f6")};color:${html(attrs(node).textColor ?? "#111827")};font-family:${html(attrs(node).fontFamily ?? "Arial, sans-serif")};"><tr><td align="center">${attrs(node).logoUrl ? `<img src="${html(attrs(node).logoUrl)}" alt="${html(attrs(node).logoAlt)}" style="display:block;height:auto;max-width:200px;padding:20px;" />` : ""}<table role="presentation" class="wrn-email" width="${html(attrs(node).width)}" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;max-width:100%;width:${html(attrs(node).width)}px;background:${html(attrs(node).contentBackground ?? "#ffffff")};color:${html(attrs(node).textColor ?? "#111827")};font-family:${html(attrs(node).fontFamily ?? "Arial, sans-serif")};">${slots.content}</table></td></tr></table>`,
|
||||||
ampEmail: ({ node, slots }) =>
|
ampEmail: ({ node, slots }) =>
|
||||||
`<table role="presentation" width="100%" class="email-bg"><tr><td align="center"><table role="presentation" width="${html(attrs(node).width)}" class="email-body">${slots.content}</table></td></tr></table>`,
|
`<table role="presentation" width="100%" class="email-bg"><tr><td align="center">${attrs(node).logoUrl ? `<amp-img class="marketing-image" src="${html(attrs(node).logoUrl)}" alt="${html(attrs(node).logoAlt)}" width="200" height="64" layout="fixed"></amp-img>` : ""}<table role="presentation" width="${html(attrs(node).width)}" class="email-body">${slots.content}</table></td></tr></table>`,
|
||||||
mjml: ({ node, slots }) =>
|
mjml: ({ node, slots }) =>
|
||||||
`<mjml><mj-body width="${html(attrs(node).width ?? "600")}px" background-color="${html(attrs(node).background ?? "#f3f4f6")}">${slots.content}</mj-body></mjml>`,
|
`<mjml><mj-body width="${html(attrs(node).width ?? "600")}px" background-color="${html(attrs(node).background ?? "#f3f4f6")}">${attrs(node).logoUrl ? `<mj-section padding="20px"><mj-column><mj-image src="${html(attrs(node).logoUrl)}" alt="${html(attrs(node).logoAlt)}" width="200px" padding="0" /></mj-column></mj-section>` : ""}${slots.content}</mj-body></mjml>`,
|
||||||
},
|
},
|
||||||
textRenderer: ({ slots }) => slots.content,
|
textRenderer: ({ slots }) => slots.content,
|
||||||
} satisfies BlockDefinition);
|
} satisfies BlockDefinition);
|
||||||
|
|||||||
@@ -57,6 +57,27 @@ const document: BlockDocument = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("email renderer", () => {
|
describe("email renderer", () => {
|
||||||
|
test("global brand logo survives HTML, AMP, and strict MJML export", async () => {
|
||||||
|
const draft = structuredClone(document);
|
||||||
|
draft.root.props.logoUrl = "https://example.com/logo.png";
|
||||||
|
draft.root.props.logoAlt = 'Brand & "Company"';
|
||||||
|
const result = await renderEmail(draft,{amp:true,mjml:true});
|
||||||
|
expect(result.ok).toBe(true);
|
||||||
|
if (!result.ok) return;
|
||||||
|
for (const output of [result.value.parts.html.content,result.value.parts.amp?.content,result.value.exports?.mjml]) {
|
||||||
|
expect(output).toContain('src="https://example.com/logo.png"');
|
||||||
|
expect(output).toContain('alt="Brand & "Company""');
|
||||||
|
}
|
||||||
|
expect(result.value.parts.amp?.validation.valid).toBe(true);
|
||||||
|
expect(await validateMjml(result.value.exports!.mjml!)).toEqual([]);
|
||||||
|
draft.root.props.logoUrl = "";
|
||||||
|
const empty = await renderEmail(draft,{amp:true,mjml:true});
|
||||||
|
expect(empty.ok).toBe(true);
|
||||||
|
if (empty.ok) {
|
||||||
|
expect(empty.value.parts.amp?.content).not.toContain("<amp-img");
|
||||||
|
expect(empty.value.exports?.mjml).not.toContain("<mj-image");
|
||||||
|
}
|
||||||
|
});
|
||||||
test("text line breaks survive all formats without interpreting entered markup", async () => {
|
test("text line breaks survive all formats without interpreting entered markup", async () => {
|
||||||
const draft = structuredClone(document);
|
const draft = structuredClone(document);
|
||||||
const text = 'First line\r\nSecond line\n\n<script>alert("x")</script>\rLast line';
|
const text = 'First line\r\nSecond line\n\n<script>alert("x")</script>\rLast line';
|
||||||
|
|||||||
Reference in new issue
Block a user