From 353cadda600beba728055fe3af5717576aa6daf1 Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Sat, 5 Sep 2026 10:58:41 +0530 Subject: [PATCH] feat(email-renderer): add global brand styling --- packages/email-renderer/package.json | 2 +- packages/email-renderer/src/blocks.ts | 10 ++++++++-- packages/email-renderer/src/email.ts | 9 +++++++-- packages/email-renderer/test/email.test.ts | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/email-renderer/package.json b/packages/email-renderer/package.json index dfa18968..8446336c 100644 --- a/packages/email-renderer/package.json +++ b/packages/email-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@wrnexus/email-renderer", - "version": "0.1.1", + "version": "0.1.2", "type": "module", "description": "WRNexus block email renderers with HTML, text, AMP Email, and MJML interoperability.", "exports": { diff --git a/packages/email-renderer/src/blocks.ts b/packages/email-renderer/src/blocks.ts index 8d744cf2..3f86eec8 100644 --- a/packages/email-renderer/src/blocks.ts +++ b/packages/email-renderer/src/blocks.ts @@ -44,6 +44,12 @@ export const emailDocumentBlock = defineBlock({ props: object({ width: string({ default: "600" }), background: string({ default: "#f3f4f6" }), + contentBackground: string({ default: "#ffffff" }), + fontFamily: string({ default: "Arial, sans-serif" }), + textColor: string({ default: "#111827" }), + linkColor: string({ default: "#2563eb" }), + logoUrl: safeUrl({ schemes: ["https"], optional: true }), + logoAlt: string({ max: 300, default: "" }), }) as never, styles, slots: { content: contentSlot }, @@ -52,13 +58,13 @@ export const emailDocumentBlock = defineBlock({ id: id(), type: "layout.email-document", version: 1, - props: { width: "600", background: "#f3f4f6" }, + props: { width: "600", background: "#f3f4f6", contentBackground: "#ffffff", fontFamily: "Arial, sans-serif", textColor: "#111827", linkColor: "#2563eb", logoUrl: "", logoAlt: "" }, styles: {}, slots: { content: [] }, }), renderers: { emailHtml: ({ node, slots }) => - `
${slots.content}
`, + `
${attrs(node).logoUrl ? `${html(attrs(node).logoAlt)}` : ""}${slots.content}
`, ampEmail: ({ node, slots }) => ``, mjml: ({ node, slots }) => diff --git a/packages/email-renderer/src/email.ts b/packages/email-renderer/src/email.ts index c5df48a3..ccdfe4a2 100644 --- a/packages/email-renderer/src/email.ts +++ b/packages/email-renderer/src/email.ts @@ -71,8 +71,13 @@ export const emailKind = defineDocumentKind({ urlSchemes: ["https", "mailto"], }); -const head = (document: BlockDocument, body: string, direction: "ltr" | "rtl") => - `${escapeHtml(document.meta.subject)}${document.meta.preheader ? `
${escapeHtml(document.meta.preheader)}
` : ""}${body}`; +const head = (document: BlockDocument, body: string, direction: "ltr" | "rtl") => { + const props = document.root.props as Record; + const textColor = escapeHtml(props.textColor ?? "#111827"); + const linkColor = escapeHtml(props.linkColor ?? "#2563eb"); + const fontFamily = escapeHtml(props.fontFamily ?? "Arial, sans-serif"); + return `${escapeHtml(document.meta.subject)}${document.meta.preheader ? `
${escapeHtml(document.meta.preheader)}
` : ""}${body}`; +}; const ampHead = (document: BlockDocument, body: string, direction: "ltr" | "rtl") => `${body}`; diff --git a/packages/email-renderer/test/email.test.ts b/packages/email-renderer/test/email.test.ts index f1535974..1be9ddf8 100644 --- a/packages/email-renderer/test/email.test.ts +++ b/packages/email-renderer/test/email.test.ts @@ -63,6 +63,7 @@ describe("email renderer", () => { if (!first.ok) return; const value: EmailRenderBundle = first.value; expect(value.parts.html.content).toContain("Hello <world>"); + expect(value.parts.html.content).toContain("color:#111827"); expect(value.parts.text.content).toContain("Hello "); expect(value.parts.amp?.validation.valid).toBe(true); expect(value.exports?.mjml).toContain("");