feat(email-renderer): add marketing and commerce blocks
This commit is contained in:
1 parent
edccf06658
commit
6cdd39ba38
3 files changed
+122
-1
No files matched your search
@@ -326,6 +326,101 @@ export const spacerBlock = leaf(
|
||||
() => "\n",
|
||||
);
|
||||
|
||||
export const videoBlock = leaf(
|
||||
"content.video",
|
||||
"Video",
|
||||
"icon-[lucide--video]",
|
||||
object({
|
||||
title: string({ min: 1, max: 300, default: "Watch video" }),
|
||||
href: safeUrl({ schemes: ["https"] }),
|
||||
thumbnail: safeUrl({ schemes: ["https"] }),
|
||||
alt: string({ max: 1_000, default: "Video thumbnail" }),
|
||||
width: string({ default: "600" }),
|
||||
height: string({ default: "338" }),
|
||||
}) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" style="border:0;display:block;height:auto;max-width:100%;" /></a>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<a href="${html(attrs(node).href)}" aria-label="${html(attrs(node).title)}"><amp-img src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}" height="${html(attrs(node).height)}" layout="responsive"></amp-img></a>`, node),
|
||||
mjml: ({ node }) => `<mj-image href="${html(attrs(node).href)}" src="${html(attrs(node).thumbnail)}" alt="${html(attrs(node).alt)}" width="${html(attrs(node).width)}px" />`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).title)}: ${String(attrs(node).href)}\n\n`,
|
||||
);
|
||||
|
||||
export const socialBlock = leaf(
|
||||
"content.social",
|
||||
"Social links",
|
||||
"icon-[lucide--share-2]",
|
||||
object({
|
||||
label: string({ max: 200, default: "Follow us" }),
|
||||
facebook: safeUrl({ schemes: ["https"], optional: true }),
|
||||
instagram: safeUrl({ schemes: ["https"], optional: true }),
|
||||
linkedin: safeUrl({ schemes: ["https"], optional: true }),
|
||||
x: safeUrl({ schemes: ["https"], optional: true }),
|
||||
}) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`<p style="font-family:Arial,sans-serif;margin:0 0 16px;">${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`<a href="${html(url)}" style="margin-right:12px;">${name}</a>`).join("")}</p>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<p>${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`<a href="${html(url)}">${name}</a>`).join(" ")}</p>`, node),
|
||||
mjml: ({ node }) => `<mj-text>${html(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`<a href="${html(url)}">${name}</a>`).join(" ")}</mj-text>`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).label)}: ${[["Facebook",attrs(node).facebook],["Instagram",attrs(node).instagram],["LinkedIn",attrs(node).linkedin],["X",attrs(node).x]].filter(([,url])=>url).map(([name,url])=>`${name}: ${url}`).join(" · ")}\n\n`,
|
||||
);
|
||||
|
||||
export const countdownBlock = leaf(
|
||||
"content.countdown",
|
||||
"Countdown",
|
||||
"icon-[lucide--timer]",
|
||||
object({
|
||||
label: string({ max: 300, default: "Offer ends" }),
|
||||
deadline: string({ min: 10, max: 40 }),
|
||||
fallback: string({ max: 300, default: "This offer has ended." }),
|
||||
}) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`<p style="font-family:Arial,sans-serif;font-size:20px;font-weight:700;margin:0 0 16px;">${html(attrs(node).label)}: <time datetime="${html(attrs(node).deadline)}">${html(attrs(node).deadline)}</time></p>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<p>${html(attrs(node).label)}: <time datetime="${html(attrs(node).deadline)}">${html(attrs(node).deadline)}</time></p>`, node),
|
||||
mjml: ({ node }) => `<mj-text font-size="20px" font-weight="700">${html(attrs(node).label)}: ${html(attrs(node).deadline)}</mj-text>`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).label)}: ${String(attrs(node).deadline)}\n${String(attrs(node).fallback)}\n\n`,
|
||||
);
|
||||
|
||||
export const surveyBlock = leaf(
|
||||
"content.survey",
|
||||
"Survey",
|
||||
"icon-[lucide--list-checks]",
|
||||
object({ question: string({ min: 1, max: 500 }), buttonLabel: string({ min: 1, max: 200, default: "Answer survey" }), href: safeUrl({ schemes: ["https"] }) }) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`<p style="font-family:Arial,sans-serif;margin:0 0 12px;">${html(attrs(node).question)}</p><p><a href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</a></p>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<p>${html(attrs(node).question)}</p><p><a href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</a></p>`, node),
|
||||
mjml: ({ node }) => `<mj-text>${html(attrs(node).question)}</mj-text><mj-button href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</mj-button>`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).question)}\n${String(attrs(node).buttonLabel)}: ${String(attrs(node).href)}\n\n`,
|
||||
);
|
||||
|
||||
export const feedItemBlock = leaf(
|
||||
"content.feed-item",
|
||||
"RSS article",
|
||||
"icon-[lucide--rss]",
|
||||
object({ title: string({ min: 1, max: 500 }), summary: string({ max: 2_000, default: "" }), href: safeUrl({ schemes: ["https"] }), image: safeUrl({ schemes: ["https"], optional: true }) }) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`${attrs(node).image ? `<img src="${html(attrs(node).image)}" alt="" style="display:block;height:auto;max-width:100%;" />` : ""}<h2 style="font-family:Arial,sans-serif;"><a href="${html(attrs(node).href)}">${html(attrs(node).title)}</a></h2><p style="font-family:Arial,sans-serif;">${html(attrs(node).summary)}</p>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<h2><a href="${html(attrs(node).href)}">${html(attrs(node).title)}</a></h2><p>${html(attrs(node).summary)}</p>`, node),
|
||||
mjml: ({ node }) => `<mj-text font-size="22px" font-weight="700"><a href="${html(attrs(node).href)}">${html(attrs(node).title)}</a></mj-text><mj-text>${html(attrs(node).summary)}</mj-text>`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).title)}\n${String(attrs(node).summary)}\n${String(attrs(node).href)}\n\n`,
|
||||
);
|
||||
|
||||
export const productBlock = leaf(
|
||||
"commerce.product",
|
||||
"Product",
|
||||
"icon-[lucide--shopping-bag]",
|
||||
object({ provider: choice(["shopify", "woocommerce", "manual"] as const, { default: "manual" }), productId: string({ max: 300, default: "" }), title: string({ min: 1, max: 500 }), price: string({ max: 100 }), image: safeUrl({ schemes: ["https"] }), href: safeUrl({ schemes: ["https"] }), buttonLabel: string({ max: 200, default: "Shop now" }) }) as never,
|
||||
{
|
||||
emailHtml: ({ node }) => emailCell(`<img src="${html(attrs(node).image)}" alt="${html(attrs(node).title)}" style="display:block;height:auto;max-width:100%;" /><h2 style="font-family:Arial,sans-serif;">${html(attrs(node).title)}</h2><p style="font-family:Arial,sans-serif;font-weight:700;">${html(attrs(node).price)}</p><p><a href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</a></p>`, node),
|
||||
ampEmail: ({ node }) => emailCell(`<h2>${html(attrs(node).title)}</h2><p>${html(attrs(node).price)}</p><p><a href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</a></p>`, node),
|
||||
mjml: ({ node }) => `<mj-image src="${html(attrs(node).image)}" alt="${html(attrs(node).title)}" /><mj-text font-size="22px" font-weight="700">${html(attrs(node).title)}</mj-text><mj-text>${html(attrs(node).price)}</mj-text><mj-button href="${html(attrs(node).href)}">${html(attrs(node).buttonLabel)}</mj-button>`,
|
||||
},
|
||||
({ node }) => `${String(attrs(node).title)} — ${String(attrs(node).price)}\n${String(attrs(node).buttonLabel)}: ${String(attrs(node).href)}\n\n`,
|
||||
);
|
||||
|
||||
export const emailCoreBlocks: readonly BlockDefinition[] = [
|
||||
emailDocumentBlock,
|
||||
sectionBlock,
|
||||
@@ -337,4 +432,10 @@ export const emailCoreBlocks: readonly BlockDefinition[] = [
|
||||
buttonBlock,
|
||||
dividerBlock,
|
||||
spacerBlock,
|
||||
videoBlock,
|
||||
socialBlock,
|
||||
countdownBlock,
|
||||
surveyBlock,
|
||||
feedItemBlock,
|
||||
productBlock,
|
||||
];
|
||||
Reference in new issue
Block a user