payload-plugin-newsletter 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +103 -0
- package/PREVIEW_CUSTOMIZATION_TASK.md +201 -0
- package/README.md +97 -0
- package/dist/collections.cjs +177 -20
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +177 -20
- package/dist/collections.js.map +1 -1
- package/dist/components.cjs +314 -143
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +2 -0
- package/dist/components.d.ts +2 -0
- package/dist/components.js +251 -80
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +201 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +198 -20
- package/dist/index.js.map +1 -1
- package/dist/types.d.cts +23 -0
- package/dist/types.d.ts +23 -0
- package/dist/utils.cjs +172 -18
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +5 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +172 -18
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -559,12 +559,15 @@ var init_broadcast2 = __esm({
|
|
|
559
559
|
// src/index.ts
|
|
560
560
|
var src_exports = {};
|
|
561
561
|
__export(src_exports, {
|
|
562
|
+
PluginConfigProvider: () => PluginConfigProvider,
|
|
562
563
|
default: () => newsletterPlugin,
|
|
563
564
|
getServerSideAuth: () => getServerSideAuth,
|
|
564
565
|
getTokenFromRequest: () => getTokenFromRequest,
|
|
565
566
|
isAuthenticated: () => isAuthenticated,
|
|
566
567
|
newsletterPlugin: () => newsletterPlugin,
|
|
567
568
|
requireAuth: () => requireAuth,
|
|
569
|
+
usePluginConfig: () => usePluginConfig,
|
|
570
|
+
usePluginConfigOptional: () => usePluginConfigOptional,
|
|
568
571
|
verifyToken: () => verifyToken
|
|
569
572
|
});
|
|
570
573
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -3584,6 +3587,12 @@ async function convertToEmailSafeHtml(editorState, options) {
|
|
|
3584
3587
|
const rawHtml = await lexicalToEmailHtml(editorState, options?.mediaUrl, options?.customBlockConverter);
|
|
3585
3588
|
const sanitizedHtml = import_isomorphic_dompurify2.default.sanitize(rawHtml, EMAIL_SAFE_CONFIG);
|
|
3586
3589
|
if (options?.wrapInTemplate) {
|
|
3590
|
+
if (options.customWrapper) {
|
|
3591
|
+
return await Promise.resolve(options.customWrapper(sanitizedHtml, {
|
|
3592
|
+
preheader: options.preheader,
|
|
3593
|
+
subject: options.subject
|
|
3594
|
+
}));
|
|
3595
|
+
}
|
|
3587
3596
|
return wrapInEmailTemplate(sanitizedHtml, options.preheader);
|
|
3588
3597
|
}
|
|
3589
3598
|
return sanitizedHtml;
|
|
@@ -3637,9 +3646,9 @@ async function convertParagraph(node, mediaUrl, customBlockConverter) {
|
|
|
3637
3646
|
);
|
|
3638
3647
|
const children = childParts.join("");
|
|
3639
3648
|
if (!children.trim()) {
|
|
3640
|
-
return '<p style="margin: 0 0 16px 0; min-height: 1em;"> </p>';
|
|
3649
|
+
return '<p class="mobile-margin-bottom-16" style="margin: 0 0 16px 0; min-height: 1em;"> </p>';
|
|
3641
3650
|
}
|
|
3642
|
-
return `<p style="margin: 0 0 16px 0; text-align: ${align};">${children}</p>`;
|
|
3651
|
+
return `<p class="mobile-margin-bottom-16" style="margin: 0 0 16px 0; text-align: ${align}; font-size: 16px; line-height: 1.5;">${children}</p>`;
|
|
3643
3652
|
}
|
|
3644
3653
|
async function convertHeading(node, mediaUrl, customBlockConverter) {
|
|
3645
3654
|
const tag = node.tag || "h1";
|
|
@@ -3653,8 +3662,14 @@ async function convertHeading(node, mediaUrl, customBlockConverter) {
|
|
|
3653
3662
|
h2: "font-size: 24px; font-weight: 600; margin: 0 0 16px 0; line-height: 1.3;",
|
|
3654
3663
|
h3: "font-size: 20px; font-weight: 600; margin: 0 0 12px 0; line-height: 1.4;"
|
|
3655
3664
|
};
|
|
3665
|
+
const mobileClasses = {
|
|
3666
|
+
h1: "mobile-font-size-24",
|
|
3667
|
+
h2: "mobile-font-size-20",
|
|
3668
|
+
h3: "mobile-font-size-16"
|
|
3669
|
+
};
|
|
3656
3670
|
const style = `${styles2[tag] || styles2.h3} text-align: ${align};`;
|
|
3657
|
-
|
|
3671
|
+
const mobileClass = mobileClasses[tag] || mobileClasses.h3;
|
|
3672
|
+
return `<${tag} class="${mobileClass}" style="${style}">${children}</${tag}>`;
|
|
3658
3673
|
}
|
|
3659
3674
|
async function convertList(node, mediaUrl, customBlockConverter) {
|
|
3660
3675
|
const tag = node.listType === "number" ? "ol" : "ul";
|
|
@@ -3662,8 +3677,8 @@ async function convertList(node, mediaUrl, customBlockConverter) {
|
|
|
3662
3677
|
(node.children || []).map((child) => convertNode(child, mediaUrl, customBlockConverter))
|
|
3663
3678
|
);
|
|
3664
3679
|
const children = childParts.join("");
|
|
3665
|
-
const style = tag === "ul" ? "margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc;" : "margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal;";
|
|
3666
|
-
return `<${tag} style="${style}">${children}</${tag}>`;
|
|
3680
|
+
const style = tag === "ul" ? "margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc; font-size: 16px; line-height: 1.5;" : "margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal; font-size: 16px; line-height: 1.5;";
|
|
3681
|
+
return `<${tag} class="mobile-margin-bottom-16" style="${style}">${children}</${tag}>`;
|
|
3667
3682
|
}
|
|
3668
3683
|
async function convertListItem(node, mediaUrl, customBlockConverter) {
|
|
3669
3684
|
const childParts = await Promise.all(
|
|
@@ -3720,16 +3735,16 @@ function convertUpload(node, mediaUrl) {
|
|
|
3720
3735
|
}
|
|
3721
3736
|
const alt = node.fields?.altText || upload.alt || "";
|
|
3722
3737
|
const caption = node.fields?.caption || "";
|
|
3723
|
-
const imgHtml = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" style="max-width: 100%; height: auto; display: block; margin: 0 auto;" />`;
|
|
3738
|
+
const imgHtml = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" class="mobile-width-100" style="max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 6px;" />`;
|
|
3724
3739
|
if (caption) {
|
|
3725
3740
|
return `
|
|
3726
|
-
<div style="margin: 0 0 16px 0; text-align: center;">
|
|
3741
|
+
<div style="margin: 0 0 16px 0; text-align: center;" class="mobile-margin-bottom-16">
|
|
3727
3742
|
${imgHtml}
|
|
3728
|
-
<p style="margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic;">${escapeHtml(caption)}</p>
|
|
3743
|
+
<p style="margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic; text-align: center;" class="mobile-font-size-14">${escapeHtml(caption)}</p>
|
|
3729
3744
|
</div>
|
|
3730
3745
|
`;
|
|
3731
3746
|
}
|
|
3732
|
-
return `<div style="margin: 0 0 16px 0; text-align: center;">${imgHtml}</div>`;
|
|
3747
|
+
return `<div style="margin: 0 0 16px 0; text-align: center;" class="mobile-margin-bottom-16">${imgHtml}</div>`;
|
|
3733
3748
|
}
|
|
3734
3749
|
async function convertBlock(node, mediaUrl, customBlockConverter) {
|
|
3735
3750
|
const blockType = node.fields?.blockName || node.blockName;
|
|
@@ -3802,11 +3817,14 @@ function escapeHtml(text) {
|
|
|
3802
3817
|
}
|
|
3803
3818
|
function wrapInEmailTemplate(content, preheader) {
|
|
3804
3819
|
return `<!DOCTYPE html>
|
|
3805
|
-
<html lang="en">
|
|
3820
|
+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
3806
3821
|
<head>
|
|
3807
3822
|
<meta charset="UTF-8">
|
|
3808
3823
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
3809
|
-
<
|
|
3824
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
3825
|
+
<meta name="x-apple-disable-message-reformatting">
|
|
3826
|
+
<title>Newsletter</title>
|
|
3827
|
+
|
|
3810
3828
|
<!--[if mso]>
|
|
3811
3829
|
<noscript>
|
|
3812
3830
|
<xml>
|
|
@@ -3816,16 +3834,155 @@ function wrapInEmailTemplate(content, preheader) {
|
|
|
3816
3834
|
</xml>
|
|
3817
3835
|
</noscript>
|
|
3818
3836
|
<![endif]-->
|
|
3837
|
+
|
|
3838
|
+
<style>
|
|
3839
|
+
/* Reset and base styles */
|
|
3840
|
+
* {
|
|
3841
|
+
-webkit-text-size-adjust: 100%;
|
|
3842
|
+
-ms-text-size-adjust: 100%;
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
body {
|
|
3846
|
+
margin: 0 !important;
|
|
3847
|
+
padding: 0 !important;
|
|
3848
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
|
|
3849
|
+
font-size: 16px;
|
|
3850
|
+
line-height: 1.5;
|
|
3851
|
+
color: #1A1A1A;
|
|
3852
|
+
background-color: #f8f9fa;
|
|
3853
|
+
-webkit-font-smoothing: antialiased;
|
|
3854
|
+
-moz-osx-font-smoothing: grayscale;
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
table {
|
|
3858
|
+
border-spacing: 0 !important;
|
|
3859
|
+
border-collapse: collapse !important;
|
|
3860
|
+
table-layout: fixed !important;
|
|
3861
|
+
margin: 0 auto !important;
|
|
3862
|
+
}
|
|
3863
|
+
|
|
3864
|
+
table table table {
|
|
3865
|
+
table-layout: auto;
|
|
3866
|
+
}
|
|
3867
|
+
|
|
3868
|
+
img {
|
|
3869
|
+
-ms-interpolation-mode: bicubic;
|
|
3870
|
+
max-width: 100%;
|
|
3871
|
+
height: auto;
|
|
3872
|
+
border: 0;
|
|
3873
|
+
outline: none;
|
|
3874
|
+
text-decoration: none;
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
/* Responsive styles */
|
|
3878
|
+
@media only screen and (max-width: 640px) {
|
|
3879
|
+
.mobile-hide {
|
|
3880
|
+
display: none !important;
|
|
3881
|
+
}
|
|
3882
|
+
|
|
3883
|
+
.mobile-center {
|
|
3884
|
+
text-align: center !important;
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
.mobile-width-100 {
|
|
3888
|
+
width: 100% !important;
|
|
3889
|
+
max-width: 100% !important;
|
|
3890
|
+
}
|
|
3891
|
+
|
|
3892
|
+
.mobile-padding {
|
|
3893
|
+
padding: 20px !important;
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3896
|
+
.mobile-padding-sm {
|
|
3897
|
+
padding: 16px !important;
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
.mobile-font-size-14 {
|
|
3901
|
+
font-size: 14px !important;
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
.mobile-font-size-16 {
|
|
3905
|
+
font-size: 16px !important;
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
.mobile-font-size-20 {
|
|
3909
|
+
font-size: 20px !important;
|
|
3910
|
+
line-height: 1.3 !important;
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
.mobile-font-size-24 {
|
|
3914
|
+
font-size: 24px !important;
|
|
3915
|
+
line-height: 1.2 !important;
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
/* Stack sections on mobile */
|
|
3919
|
+
.mobile-stack {
|
|
3920
|
+
display: block !important;
|
|
3921
|
+
width: 100% !important;
|
|
3922
|
+
}
|
|
3923
|
+
|
|
3924
|
+
/* Mobile-specific spacing */
|
|
3925
|
+
.mobile-margin-bottom-16 {
|
|
3926
|
+
margin-bottom: 16px !important;
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
.mobile-margin-bottom-20 {
|
|
3930
|
+
margin-bottom: 20px !important;
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
/* Dark mode support */
|
|
3935
|
+
@media (prefers-color-scheme: dark) {
|
|
3936
|
+
.dark-mode-bg {
|
|
3937
|
+
background-color: #1a1a1a !important;
|
|
3938
|
+
}
|
|
3939
|
+
|
|
3940
|
+
.dark-mode-text {
|
|
3941
|
+
color: #ffffff !important;
|
|
3942
|
+
}
|
|
3943
|
+
|
|
3944
|
+
.dark-mode-border {
|
|
3945
|
+
border-color: #333333 !important;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3949
|
+
/* Outlook-specific fixes */
|
|
3950
|
+
<!--[if mso]>
|
|
3951
|
+
<style>
|
|
3952
|
+
table {
|
|
3953
|
+
border-collapse: collapse;
|
|
3954
|
+
border-spacing: 0;
|
|
3955
|
+
border: none;
|
|
3956
|
+
margin: 0;
|
|
3957
|
+
}
|
|
3958
|
+
|
|
3959
|
+
div, p {
|
|
3960
|
+
margin: 0;
|
|
3961
|
+
}
|
|
3962
|
+
</style>
|
|
3963
|
+
<![endif]-->
|
|
3964
|
+
</style>
|
|
3819
3965
|
</head>
|
|
3820
|
-
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #
|
|
3821
|
-
${preheader ?
|
|
3822
|
-
|
|
3966
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #1A1A1A; background-color: #f8f9fa;">
|
|
3967
|
+
${preheader ? `
|
|
3968
|
+
<!-- Preheader text -->
|
|
3969
|
+
<div style="display: none; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: transparent;">
|
|
3970
|
+
${escapeHtml(preheader)}
|
|
3971
|
+
</div>
|
|
3972
|
+
` : ""}
|
|
3973
|
+
|
|
3974
|
+
<!-- Main container -->
|
|
3975
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="margin: 0; padding: 0; background-color: #f8f9fa;">
|
|
3823
3976
|
<tr>
|
|
3824
|
-
<td align="center" style="padding: 20px
|
|
3825
|
-
|
|
3977
|
+
<td align="center" style="padding: 20px 10px;">
|
|
3978
|
+
<!-- Email wrapper -->
|
|
3979
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="600" class="mobile-width-100" style="margin: 0 auto; max-width: 600px;">
|
|
3826
3980
|
<tr>
|
|
3827
|
-
<td style="padding:
|
|
3828
|
-
|
|
3981
|
+
<td class="mobile-padding" style="padding: 0;">
|
|
3982
|
+
<!-- Content area with light background -->
|
|
3983
|
+
<div style="background-color: #ffffff; padding: 40px 30px; border-radius: 8px;" class="mobile-padding">
|
|
3984
|
+
${content}
|
|
3985
|
+
</div>
|
|
3829
3986
|
</td>
|
|
3830
3987
|
</tr>
|
|
3831
3988
|
</table>
|
|
@@ -4269,11 +4426,14 @@ var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
|
|
|
4269
4426
|
const mediaUrl = req.payload.config.serverURL ? `${req.payload.config.serverURL}/api/media` : "/api/media";
|
|
4270
4427
|
req.payload.logger?.info("Populating media fields for email preview...");
|
|
4271
4428
|
const populatedContent = await populateMediaFields(content, req.payload, config);
|
|
4429
|
+
const emailPreviewConfig = config.customizations?.broadcasts?.emailPreview;
|
|
4272
4430
|
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
4273
|
-
wrapInTemplate: true,
|
|
4431
|
+
wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,
|
|
4274
4432
|
preheader,
|
|
4433
|
+
subject,
|
|
4275
4434
|
mediaUrl,
|
|
4276
|
-
customBlockConverter: config.customizations?.broadcasts?.customBlockConverter
|
|
4435
|
+
customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,
|
|
4436
|
+
customWrapper: emailPreviewConfig?.customWrapper
|
|
4277
4437
|
});
|
|
4278
4438
|
return Response.json({
|
|
4279
4439
|
success: true,
|
|
@@ -5177,6 +5337,24 @@ var isAuthenticated = (req, secret) => {
|
|
|
5177
5337
|
return !!decoded;
|
|
5178
5338
|
};
|
|
5179
5339
|
|
|
5340
|
+
// src/contexts/PluginConfigContext.tsx
|
|
5341
|
+
var import_react = require("react");
|
|
5342
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
5343
|
+
var PluginConfigContext = (0, import_react.createContext)(null);
|
|
5344
|
+
var PluginConfigProvider = ({ config, children }) => {
|
|
5345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PluginConfigContext.Provider, { value: config, children });
|
|
5346
|
+
};
|
|
5347
|
+
var usePluginConfig = () => {
|
|
5348
|
+
const config = (0, import_react.useContext)(PluginConfigContext);
|
|
5349
|
+
if (!config) {
|
|
5350
|
+
throw new Error("usePluginConfig must be used within PluginConfigProvider");
|
|
5351
|
+
}
|
|
5352
|
+
return config;
|
|
5353
|
+
};
|
|
5354
|
+
var usePluginConfigOptional = () => {
|
|
5355
|
+
return (0, import_react.useContext)(PluginConfigContext);
|
|
5356
|
+
};
|
|
5357
|
+
|
|
5180
5358
|
// src/index.ts
|
|
5181
5359
|
var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
|
|
5182
5360
|
const config = {
|
|
@@ -5354,11 +5532,14 @@ var newsletterPlugin = (pluginConfig) => (incomingConfig) => {
|
|
|
5354
5532
|
};
|
|
5355
5533
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5356
5534
|
0 && (module.exports = {
|
|
5535
|
+
PluginConfigProvider,
|
|
5357
5536
|
getServerSideAuth,
|
|
5358
5537
|
getTokenFromRequest,
|
|
5359
5538
|
isAuthenticated,
|
|
5360
5539
|
newsletterPlugin,
|
|
5361
5540
|
requireAuth,
|
|
5541
|
+
usePluginConfig,
|
|
5542
|
+
usePluginConfigOptional,
|
|
5362
5543
|
verifyToken
|
|
5363
5544
|
});
|
|
5364
5545
|
//# sourceMappingURL=index.cjs.map
|