mail-editor-pancake 0.0.8 → 0.1.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/README.md +498 -218
- package/package.json +2 -2
- package/packages/blocks/dist/index.d.ts +12 -0
- package/packages/blocks/dist/index.js +187 -145
- package/packages/blocks/dist/index.js.map +1 -1
- package/packages/blocks/src/html.ts +11 -3
- package/packages/blocks/src/index.ts +2 -0
- package/packages/blocks/src/social.ts +8 -11
- package/packages/blocks/src/socialGroup.ts +8 -11
- package/packages/blocks/src/socialShared.ts +52 -0
- package/packages/blocks/src/text.ts +8 -3
- package/packages/core/dist/index.d.ts +275 -12
- package/packages/core/dist/index.js +4099 -2194
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/style.css +1 -1
- package/packages/core/package.json +1 -1
- package/packages/core/src/editor/BlockCodeModal.ts +84 -2
- package/packages/core/src/editor/Canvas.ts +191 -26
- package/packages/core/src/editor/Editor.ts +589 -76
- package/packages/core/src/editor/ExportModal.ts +1 -1
- package/packages/core/src/editor/ImportDocModal.ts +129 -0
- package/packages/core/src/editor/InlineEditor.ts +246 -22
- package/packages/core/src/editor/LeftPanel.ts +55 -14
- package/packages/core/src/editor/Modal.ts +20 -1
- package/packages/core/src/editor/PreviewModal.ts +2 -2
- package/packages/core/src/editor/RichTextToolbar.ts +125 -18
- package/packages/core/src/editor/RightPanel.ts +165 -7
- package/packages/core/src/editor/Topbar.ts +306 -132
- package/packages/core/src/editor/VariablePickerPanel.ts +145 -0
- package/packages/core/src/editor/styles.css +458 -59
- package/packages/core/src/index.ts +43 -2
- package/packages/core/src/renderer/index.ts +9 -1
- package/packages/core/src/renderer/mjml.ts +4 -5
- package/packages/core/src/store/store.ts +13 -2
- package/packages/core/src/types.ts +67 -2
- package/packages/core/src/utils/docClipboard.ts +89 -0
- package/packages/core/src/utils/dynamicVariantHtml.ts +45 -0
- package/packages/core/src/utils/dynamicVariantKey.ts +24 -0
- package/packages/core/src/utils/dynamicVariantSection.ts +98 -0
- package/packages/core/src/utils/emailListStyles.ts +188 -0
- package/packages/core/src/utils/inlineListEditing.ts +774 -0
- package/packages/core/src/utils/lockedMjml.ts +146 -12
- package/packages/core/src/utils/modalSize.ts +27 -0
- package/packages/core/src/utils/richHtmlEmpty.ts +43 -0
- package/packages/core/src/utils/richHtmlInsert.ts +16 -0
- package/packages/core/src/utils/sectionLayout.ts +2 -2
- package/packages/core/src/variables/index.ts +90 -0
- package/playground/vanilla/src/main.ts +26 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineBlock as h, blockButtonWidthCss as
|
|
1
|
+
import { defineBlock as h, blockButtonWidthCss as F, docContentWidthCss as L, htmlContainsMjmlTags as U, mjRawEmailTableWrap as J, mjRawCellTypographyFromStyles as G, normalizeFontWeightStep as y, FONT_WEIGHT_STEP_OPTIONS as j, isRichHtmlEffectivelyEmpty as q } from "@simple-mail/core";
|
|
2
2
|
const m = {
|
|
3
3
|
html: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><rect x="3.5" y="4" width="17" height="16" rx="2" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M8 8.5l3 3.5-3 3.5M16 8.5l-3 3.5 3 3.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
4
4
|
text: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M5 6h14M5 10h14M5 14h10M5 18h8" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" fill="none"/></svg>',
|
|
@@ -11,7 +11,7 @@ const m = {
|
|
|
11
11
|
social: '<svg width="24" height="24" viewBox="0 0 24 24"><circle cx="6" cy="12" r="2.5" stroke="currentColor" stroke-width="1.4" fill="none"/><circle cx="12" cy="12" r="2.5" stroke="currentColor" stroke-width="1.4" fill="none"/><circle cx="18" cy="12" r="2.5" stroke="currentColor" stroke-width="1.4" fill="none"/></svg>',
|
|
12
12
|
footer: '<svg width="24" height="24" viewBox="0 0 24 24"><rect x="3.5" y="5" width="17" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4" fill="none"/><path d="M5 18h14" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>',
|
|
13
13
|
socialGroup: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5"/><circle cx="8" cy="12" r="2" stroke="currentColor" stroke-width="1.4"/><circle cx="12" cy="12" r="2" stroke="currentColor" stroke-width="1.4"/><circle cx="16" cy="12" r="2" stroke="currentColor" stroke-width="1.4"/></svg>'
|
|
14
|
-
},
|
|
14
|
+
}, f = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), K = h({
|
|
15
15
|
type: "button",
|
|
16
16
|
name: "按钮",
|
|
17
17
|
category: "content",
|
|
@@ -69,22 +69,22 @@ const m = {
|
|
|
69
69
|
placeholder: "按钮文字"
|
|
70
70
|
},
|
|
71
71
|
toMjml: (e) => {
|
|
72
|
-
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = `${e.innerPaddingV}px ${e.innerPaddingH}px`, n =
|
|
73
|
-
return `<mj-button href="${
|
|
72
|
+
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = `${e.innerPaddingV}px ${e.innerPaddingH}px`, n = F(e.width), i = n ? ` width="${f(n)}"` : "";
|
|
73
|
+
return `<mj-button href="${f(e.href)}" background-color="${f(
|
|
74
74
|
e.backgroundColor
|
|
75
|
-
)}" color="${
|
|
75
|
+
)}" color="${f(e.color)}" border-radius="${e.borderRadius}px" font-size="${f(
|
|
76
76
|
e.fontSize
|
|
77
|
-
)}" align="${e.align}" padding="${t}" inner-padding="${o}"${i}>${
|
|
77
|
+
)}" align="${e.align}" padding="${t}" inner-padding="${o}"${i}>${f(
|
|
78
78
|
e.text
|
|
79
79
|
)}</mj-button>`;
|
|
80
80
|
},
|
|
81
81
|
renderPreview: (e) => {
|
|
82
|
-
const t =
|
|
82
|
+
const t = F(e.width), o = t ? `width:${t};max-width:100%;box-sizing:border-box;` : "";
|
|
83
83
|
return `<div style="padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;text-align:${e.align};">
|
|
84
|
-
<a href="${
|
|
84
|
+
<a href="${f(e.href)}" style="display:inline-block;background:${e.backgroundColor};border-radius:${e.borderRadius}px;padding:${e.innerPaddingV}px ${e.innerPaddingH}px;text-decoration:none;font-size:${e.fontSize};line-height:1.2;${o}"><span class="sm-button-text" style="color:${e.color}">${f(e.text)}</span></a>
|
|
85
85
|
</div>`;
|
|
86
86
|
}
|
|
87
|
-
}),
|
|
87
|
+
}), A = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), D = h({
|
|
88
88
|
type: "divider",
|
|
89
89
|
name: "分隔线",
|
|
90
90
|
category: "content",
|
|
@@ -103,11 +103,11 @@ const m = {
|
|
|
103
103
|
{ key: "paddingTop", label: "上边距", type: "number", min: 0, max: 80 },
|
|
104
104
|
{ key: "paddingBottom", label: "下边距", type: "number", min: 0, max: 80 }
|
|
105
105
|
],
|
|
106
|
-
toMjml: (e) => `<mj-divider border-color="${
|
|
106
|
+
toMjml: (e) => `<mj-divider border-color="${A(e.color)}" border-width="${e.thickness}px" width="${A(
|
|
107
107
|
e.width
|
|
108
108
|
)}" padding="${e.paddingTop}px 0px ${e.paddingBottom}px 0px" />`,
|
|
109
109
|
renderPreview: (e) => `<div style="padding:${e.paddingTop}px 0 ${e.paddingBottom}px 0;"><div style="border-top:${e.thickness}px solid ${e.color};width:${e.width};margin:0 auto;"></div></div>`
|
|
110
|
-
}), b = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """),
|
|
110
|
+
}), b = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), X = h({
|
|
111
111
|
type: "custom:footer",
|
|
112
112
|
name: "页脚",
|
|
113
113
|
category: "custom",
|
|
@@ -136,7 +136,7 @@ const m = {
|
|
|
136
136
|
${b(e.address)}<br/>
|
|
137
137
|
<a href="${b(e.unsubscribeHref)}" style="color:${e.textColor};">${b(e.unsubscribeText)}</a>
|
|
138
138
|
</div>`
|
|
139
|
-
}),
|
|
139
|
+
}), k = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), Y = h({
|
|
140
140
|
type: "hero",
|
|
141
141
|
name: "Hero 大图",
|
|
142
142
|
category: "content",
|
|
@@ -197,26 +197,26 @@ const m = {
|
|
|
197
197
|
placeholder: "编写覆盖在图片上的文案…"
|
|
198
198
|
},
|
|
199
199
|
toMjml: (e, t) => {
|
|
200
|
-
const o =
|
|
200
|
+
const o = L(t.doc.meta.width), n = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, i = `${e.height}px`;
|
|
201
201
|
return `<mj-hero
|
|
202
202
|
mode="fixed-height"
|
|
203
203
|
height="${i}"
|
|
204
204
|
background-width="${o}"
|
|
205
205
|
background-height="${i}"
|
|
206
|
-
background-url="${
|
|
207
|
-
background-color="${
|
|
206
|
+
background-url="${k(e.backgroundUrl)}"
|
|
207
|
+
background-color="${k(e.backgroundColor)}"
|
|
208
208
|
padding="${n}"
|
|
209
209
|
vertical-align="${e.verticalAlign}"
|
|
210
210
|
>
|
|
211
211
|
<mj-text
|
|
212
212
|
align="${e.textAlign}"
|
|
213
|
-
color="${
|
|
213
|
+
color="${k(e.textColor)}"
|
|
214
214
|
padding="0"
|
|
215
215
|
>${e.content}</mj-text>
|
|
216
216
|
</mj-hero>`;
|
|
217
217
|
},
|
|
218
218
|
renderPreview: (e, t) => {
|
|
219
|
-
const o =
|
|
219
|
+
const o = L(t.doc.meta.width), n = e.verticalAlign === "top" ? "flex-start" : e.verticalAlign === "bottom" ? "flex-end" : "center", i = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, c = k(e.backgroundUrl);
|
|
220
220
|
return `<div
|
|
221
221
|
style="
|
|
222
222
|
box-sizing:border-box;
|
|
@@ -224,7 +224,7 @@ const m = {
|
|
|
224
224
|
max-width:${o};
|
|
225
225
|
min-height:${e.height}px;
|
|
226
226
|
margin:0 auto;
|
|
227
|
-
background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${
|
|
227
|
+
background-image:linear-gradient(to bottom,rgba(0,0,0,0.25),rgba(0,0,0,0.35)),url(${c});
|
|
228
228
|
background-size:cover;
|
|
229
229
|
background-position:center;
|
|
230
230
|
background-color:${e.backgroundColor};
|
|
@@ -232,7 +232,7 @@ const m = {
|
|
|
232
232
|
align-items:${n};
|
|
233
233
|
justify-content:${e.textAlign === "right" ? "flex-end" : e.textAlign === "center" ? "center" : "flex-start"};
|
|
234
234
|
padding:${i};
|
|
235
|
-
color:${
|
|
235
|
+
color:${k(e.textColor)};
|
|
236
236
|
overflow:hidden;
|
|
237
237
|
border-radius:2px;
|
|
238
238
|
"
|
|
@@ -242,13 +242,13 @@ const m = {
|
|
|
242
242
|
style="
|
|
243
243
|
width:100%;
|
|
244
244
|
text-align:${e.textAlign};
|
|
245
|
-
color:${
|
|
245
|
+
color:${k(e.textColor)};
|
|
246
246
|
text-shadow:0 1px 2px rgba(0,0,0,0.45);
|
|
247
247
|
"
|
|
248
248
|
>${e.content}</div>
|
|
249
249
|
</div>`;
|
|
250
250
|
}
|
|
251
|
-
}),
|
|
251
|
+
}), Z = h({
|
|
252
252
|
type: "html",
|
|
253
253
|
name: "HTML",
|
|
254
254
|
category: "content",
|
|
@@ -265,7 +265,7 @@ const m = {
|
|
|
265
265
|
key: "html",
|
|
266
266
|
label: "HTML",
|
|
267
267
|
type: "textarea",
|
|
268
|
-
help: "
|
|
268
|
+
help: "只写 HTML(如 <a>、<table>),不要写 <mj-text> 等 MJML 标签;MJML 标签在 mj-raw 内不会被编译。简单链接建议用「文本」块。"
|
|
269
269
|
},
|
|
270
270
|
{ key: "paddingTop", label: "内边距", type: "spacing" }
|
|
271
271
|
],
|
|
@@ -278,10 +278,13 @@ const m = {
|
|
|
278
278
|
},
|
|
279
279
|
toMjml: (e, t) => {
|
|
280
280
|
const o = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`;
|
|
281
|
-
return
|
|
281
|
+
return J(o, e.html, G(t.doc.styles));
|
|
282
282
|
},
|
|
283
|
-
renderPreview: (e) =>
|
|
284
|
-
|
|
283
|
+
renderPreview: (e) => {
|
|
284
|
+
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = U(e.html) ? '<div class="sm-html-mjml-warn">检测到 MJML 标签,此处应只写 HTML,预览可能显示异常。</div>' : "";
|
|
285
|
+
return `<div class="sm-html-content" style="padding:${t};min-height:1em;">${o}${e.html}</div>`;
|
|
286
|
+
}
|
|
287
|
+
}), w = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), Q = h({
|
|
285
288
|
type: "image",
|
|
286
289
|
name: "图片",
|
|
287
290
|
category: "content",
|
|
@@ -325,16 +328,16 @@ const m = {
|
|
|
325
328
|
{ key: "paddingTop", label: "内边距", type: "spacing" }
|
|
326
329
|
],
|
|
327
330
|
toMjml: (e) => {
|
|
328
|
-
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.href ? ` href="${
|
|
329
|
-
return `<mj-image src="${
|
|
331
|
+
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.href ? ` href="${w(e.href)}"` : "", n = ` alt="${w(e.alt || "")}"`, i = e.height != null && e.height > 0 ? ` height="${e.height}px"` : "";
|
|
332
|
+
return `<mj-image src="${w(e.src)}"${n}${o} width="${e.width}px"${i} align="${e.align}" padding="${t}" />`;
|
|
330
333
|
},
|
|
331
334
|
renderPreview: (e) => {
|
|
332
335
|
const t = e.align === "center" ? "margin:0 auto;" : e.align === "right" ? "margin-left:auto;" : "", o = e.height != null && e.height > 0 ? e.height : 0, n = o > 0 ? `width:${e.width}px;height:${o}px;object-fit:cover;object-position:center;` : `width:${e.width}px;height:auto;`;
|
|
333
|
-
return `<div style="padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;text-align:${e.align};"><img src="${
|
|
336
|
+
return `<div style="padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;text-align:${e.align};"><img src="${w(
|
|
334
337
|
e.src
|
|
335
|
-
)}" alt="${
|
|
338
|
+
)}" alt="${w(e.alt)}" style="display:block;${t}max-width:100%;${n}border:0;outline:none;" /></div>`;
|
|
336
339
|
}
|
|
337
|
-
}),
|
|
340
|
+
}), M = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), ee = h({
|
|
338
341
|
type: "custom:logo",
|
|
339
342
|
name: "公司 Logo",
|
|
340
343
|
category: "custom",
|
|
@@ -361,25 +364,25 @@ const m = {
|
|
|
361
364
|
]
|
|
362
365
|
}
|
|
363
366
|
],
|
|
364
|
-
toMjml: (e) => `<mj-image src="${
|
|
367
|
+
toMjml: (e) => `<mj-image src="${M(e.src)}" href="${M(e.href)}" width="${e.width}px" align="${e.align}" alt="logo" padding="8px 0px 8px 0px" />`,
|
|
365
368
|
renderPreview: (e) => {
|
|
366
369
|
const t = e.align === "center" ? "margin:0 auto;" : e.align === "right" ? "margin-left:auto;" : "";
|
|
367
|
-
return `<div style="padding:8px 0;text-align:${e.align};"><img src="${
|
|
370
|
+
return `<div style="padding:8px 0;text-align:${e.align};"><img src="${M(
|
|
368
371
|
e.src
|
|
369
372
|
)}" alt="logo" style="display:block;${t}width:${e.width}px;max-width:100%;height:auto;" /></div>`;
|
|
370
373
|
}
|
|
371
374
|
});
|
|
372
|
-
function
|
|
375
|
+
function E(e) {
|
|
373
376
|
const t = e.trim();
|
|
374
377
|
return t === "ig" ? "instagram" : t === "rabbit" || t === "tiktok" || t === "reddit" ? "web" : t;
|
|
375
378
|
}
|
|
376
|
-
const
|
|
379
|
+
const te = [
|
|
377
380
|
{ label: "X", value: "x" },
|
|
378
381
|
{ label: "Rabbit", value: "rabbit" },
|
|
379
382
|
{ label: "Facebook", value: "facebook" },
|
|
380
383
|
{ label: "TikTok", value: "tiktok" },
|
|
381
384
|
{ label: "Instagram", value: "ig" }
|
|
382
|
-
],
|
|
385
|
+
], oe = [
|
|
383
386
|
{ label: "微信", value: "wechat" },
|
|
384
387
|
{ label: "微博", value: "weibo" },
|
|
385
388
|
{ label: "X", value: "x" },
|
|
@@ -390,7 +393,7 @@ const ee = [
|
|
|
390
393
|
{ label: "YouTube", value: "youtube" },
|
|
391
394
|
{ label: "Reddit", value: "reddit" },
|
|
392
395
|
{ label: "网页", value: "web" }
|
|
393
|
-
],
|
|
396
|
+
], ne = {
|
|
394
397
|
wechat: { color: "#1AAD19", preview: "信" },
|
|
395
398
|
weibo: { color: "#E6162D", preview: "微" },
|
|
396
399
|
x: { color: "#000000", preview: "X" },
|
|
@@ -405,74 +408,103 @@ const ee = [
|
|
|
405
408
|
rabbit: { color: "#FF2442", preview: "R" },
|
|
406
409
|
website: { color: "#6b7280", preview: "◇" },
|
|
407
410
|
web: { color: "#6b7280", preview: "◇" }
|
|
408
|
-
}, p = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """),
|
|
409
|
-
function
|
|
410
|
-
return
|
|
411
|
+
}, p = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), ie = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
412
|
+
function N(e) {
|
|
413
|
+
return ne[e] ?? { color: "#6b7280", preview: "·" };
|
|
414
|
+
}
|
|
415
|
+
const le = "https://www.mailjet.com/images/theme/v1/icons/ico-social/", re = {
|
|
416
|
+
facebook: "facebook.png",
|
|
417
|
+
twitter: "twitter.png",
|
|
418
|
+
x: "twitter-x.png",
|
|
419
|
+
google: "google-plus.png",
|
|
420
|
+
pinterest: "pinterest.png",
|
|
421
|
+
linkedin: "linkedin.png",
|
|
422
|
+
instagram: "instagram.png",
|
|
423
|
+
web: "web.png",
|
|
424
|
+
snapchat: "snapchat.png",
|
|
425
|
+
youtube: "youtube.png",
|
|
426
|
+
tumblr: "tumblr.png",
|
|
427
|
+
github: "github.png",
|
|
428
|
+
xing: "xing.png",
|
|
429
|
+
vimeo: "vimeo.png",
|
|
430
|
+
medium: "medium.png",
|
|
431
|
+
soundcloud: "soundcloud.png",
|
|
432
|
+
dribbble: "dribbble.png"
|
|
433
|
+
};
|
|
434
|
+
function ae(e) {
|
|
435
|
+
const t = re[E(e)];
|
|
436
|
+
return t ? `${le}${t}` : null;
|
|
437
|
+
}
|
|
438
|
+
function W(e) {
|
|
439
|
+
const { network: t, iconSize: o, iconBorderRadius: n, iconSrc: i, backgroundColor: c } = e, d = ce(o, n), s = N(t), l = (c == null ? void 0 : c.trim()) || s.color, a = (i == null ? void 0 : i.trim()) || ae(t);
|
|
440
|
+
return a ? `<span style="display:inline-flex;width:${o}px;height:${o}px;border-radius:${d};background:${l};overflow:hidden;align-items:center;justify-content:center;flex-shrink:0;line-height:0;"><img src="${p(a)}" alt="" width="${o}" height="${o}" style="display:block;width:${o}px;height:${o}px;border-radius:${d};" /></span>` : `<span style="display:inline-flex;width:${o}px;height:${o}px;border-radius:${d};background:${l};color:#fff;align-items:center;justify-content:center;font-size:${Math.round(
|
|
441
|
+
o / 2
|
|
442
|
+
)}px;font-weight:600;flex-shrink:0;overflow:hidden;">${s.preview}</span>`;
|
|
411
443
|
}
|
|
412
|
-
function
|
|
444
|
+
function S(e) {
|
|
413
445
|
return `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`;
|
|
414
446
|
}
|
|
415
|
-
function
|
|
447
|
+
function I(e, t) {
|
|
416
448
|
const o = Math.max(1, Number(e) || 28), n = Number(t);
|
|
417
449
|
if (!Number.isFinite(n) || n <= 0) return "0px";
|
|
418
450
|
const i = o / 2;
|
|
419
451
|
return n >= 999 || n >= i ? "999px" : `${Math.min(n, o)}px`;
|
|
420
452
|
}
|
|
421
|
-
function
|
|
453
|
+
function ce(e, t) {
|
|
422
454
|
const o = Math.max(1, Number(e) || 28), n = Number(t);
|
|
423
455
|
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
424
456
|
const i = o / 2;
|
|
425
457
|
return n >= 999 || n >= i ? "50%" : `${Math.min(n, o)}px`;
|
|
426
458
|
}
|
|
427
|
-
function
|
|
459
|
+
function C(e, t = 10) {
|
|
428
460
|
const o = Number(e);
|
|
429
461
|
return !Number.isFinite(o) || o < 0 ? t : Math.min(64, Math.round(o));
|
|
430
462
|
}
|
|
431
|
-
function
|
|
463
|
+
function O(e) {
|
|
432
464
|
return e === "right" ? "flex-end" : e === "left" ? "flex-start" : "center";
|
|
433
465
|
}
|
|
434
|
-
function
|
|
435
|
-
var
|
|
436
|
-
const o = t.labelFontSize > 0 ? t.labelFontSize : 13, n = Math.max(8, Math.min(48, o)), i =
|
|
466
|
+
function _(e, t) {
|
|
467
|
+
var s;
|
|
468
|
+
const o = t.labelFontSize > 0 ? t.labelFontSize : 13, n = Math.max(8, Math.min(48, o)), i = y(t.labelFontWeight), c = ((s = t.labelColor) == null ? void 0 : s.trim()) || "#333333", d = p(i);
|
|
437
469
|
return e.map((l) => {
|
|
438
|
-
var
|
|
439
|
-
const
|
|
440
|
-
`name="${p(
|
|
470
|
+
var T, z, R;
|
|
471
|
+
const a = N(l.network), r = ((T = l.backgroundColor) == null ? void 0 : T.trim()) || a.color, u = [
|
|
472
|
+
`name="${p(E(l.network))}"`,
|
|
441
473
|
`href="${p(l.href)}"`,
|
|
442
|
-
`background-color="${p(
|
|
443
|
-
`color="${p(
|
|
474
|
+
`background-color="${p(r)}"`,
|
|
475
|
+
`color="${p(c)}"`,
|
|
444
476
|
`font-size="${n}px"`,
|
|
445
477
|
`font-weight="${d}"`
|
|
446
|
-
].join(" "),
|
|
447
|
-
return
|
|
448
|
-
${
|
|
478
|
+
].join(" "), $ = (z = l.iconSrc) == null ? void 0 : z.trim(), x = $ ? `${u} src="${p($)}"` : u, B = ((R = l.label) == null ? void 0 : R.trim()) ?? "";
|
|
479
|
+
return B ? ` <mj-social-element ${x}>
|
|
480
|
+
${ie(B)}
|
|
449
481
|
</mj-social-element>` : ` <mj-social-element ${x} />`;
|
|
450
482
|
}).join(`
|
|
451
483
|
`);
|
|
452
484
|
}
|
|
453
|
-
const
|
|
485
|
+
const V = [
|
|
454
486
|
{ network: "x", href: "https://x.com/" },
|
|
455
487
|
{ network: "rabbit", href: "https://example.com" },
|
|
456
488
|
{ network: "facebook", href: "https://facebook.com/" },
|
|
457
489
|
{ network: "tiktok", href: "https://www.tiktok.com/" },
|
|
458
490
|
{ network: "ig", href: "https://instagram.com/" }
|
|
459
491
|
];
|
|
460
|
-
function
|
|
492
|
+
function P(e) {
|
|
461
493
|
var o;
|
|
462
494
|
if ((o = e.elements) != null && o.length) return e.elements;
|
|
463
495
|
const t = e.links;
|
|
464
496
|
return Array.isArray(t) && t.length ? t.map((n) => ({
|
|
465
497
|
network: String(n.network ?? "web"),
|
|
466
498
|
href: String(n.href ?? "")
|
|
467
|
-
})) :
|
|
499
|
+
})) : V;
|
|
468
500
|
}
|
|
469
|
-
const
|
|
501
|
+
const se = h({
|
|
470
502
|
type: "custom:social",
|
|
471
503
|
name: "社交链接",
|
|
472
504
|
category: "custom",
|
|
473
505
|
icon: m.social,
|
|
474
506
|
defaultProps: {
|
|
475
|
-
elements:
|
|
507
|
+
elements: V,
|
|
476
508
|
align: "center",
|
|
477
509
|
iconSize: 28,
|
|
478
510
|
iconBorderRadius: 999,
|
|
@@ -490,7 +522,7 @@ const ie = h({
|
|
|
490
522
|
key: "elements",
|
|
491
523
|
label: "社交链接",
|
|
492
524
|
type: "socialLinkList",
|
|
493
|
-
options:
|
|
525
|
+
options: te,
|
|
494
526
|
help: "平台:X、Rabbit、Facebook、TikTok、Instagram (ig)。可填标签、自定义图标 URL。MJML 侧 Rabbit/TikTok 使用 web 占位图标,需要品牌图时请填「图标 URL」。"
|
|
495
527
|
},
|
|
496
528
|
{
|
|
@@ -506,7 +538,7 @@ const ie = h({
|
|
|
506
538
|
label: "标签字重",
|
|
507
539
|
type: "select",
|
|
508
540
|
selectVariant: "segmented",
|
|
509
|
-
options: [...
|
|
541
|
+
options: [...j]
|
|
510
542
|
},
|
|
511
543
|
{ key: "labelColor", label: "标签颜色", type: "color" },
|
|
512
544
|
{
|
|
@@ -542,37 +574,41 @@ const ie = h({
|
|
|
542
574
|
{ key: "paddingTop", label: "外边距", type: "spacing" }
|
|
543
575
|
],
|
|
544
576
|
toMjml: (e) => {
|
|
545
|
-
const t =
|
|
546
|
-
var
|
|
547
|
-
return (
|
|
577
|
+
const t = S(e), o = I(e.iconSize, e.iconBorderRadius ?? 999), n = C(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, c = P(e).filter((l) => {
|
|
578
|
+
var a;
|
|
579
|
+
return (a = l.href) == null ? void 0 : a.trim();
|
|
548
580
|
}), d = {
|
|
549
581
|
labelFontSize: Number(e.labelFontSize ?? 13),
|
|
550
|
-
labelFontWeight:
|
|
582
|
+
labelFontWeight: y(String(e.labelFontWeight ?? "400")),
|
|
551
583
|
labelColor: String(e.labelColor ?? "#333333")
|
|
552
|
-
},
|
|
553
|
-
return
|
|
554
|
-
${
|
|
584
|
+
}, s = _(c, d);
|
|
585
|
+
return s.trim() ? `<mj-social ${i}>
|
|
586
|
+
${s}
|
|
555
587
|
</mj-social>` : `<mj-social ${i}></mj-social>`;
|
|
556
588
|
},
|
|
557
589
|
renderPreview: (e) => {
|
|
558
|
-
var
|
|
559
|
-
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n =
|
|
590
|
+
var a;
|
|
591
|
+
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = y(e.labelFontWeight), i = ((a = e.labelColor) == null ? void 0 : a.trim()) || "#333333", c = C(e.iconSpacing, 10), d = O(e.align), s = P(e).filter((r) => {
|
|
560
592
|
var g;
|
|
561
|
-
return (g =
|
|
562
|
-
}).map((
|
|
563
|
-
var
|
|
564
|
-
const g =
|
|
565
|
-
|
|
566
|
-
|
|
593
|
+
return (g = r.href) == null ? void 0 : g.trim();
|
|
594
|
+
}).map((r) => {
|
|
595
|
+
var x;
|
|
596
|
+
const g = ((x = r.label) == null ? void 0 : x.trim()) ?? "", u = W({
|
|
597
|
+
network: r.network,
|
|
598
|
+
iconSize: e.iconSize,
|
|
599
|
+
iconBorderRadius: e.iconBorderRadius ?? 999,
|
|
600
|
+
iconSrc: r.iconSrc,
|
|
601
|
+
backgroundColor: r.backgroundColor
|
|
602
|
+
}), $ = g ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
|
|
567
603
|
i
|
|
568
|
-
)} !important;line-height:1.2;">${p(
|
|
604
|
+
)} !important;line-height:1.2;">${p(g)}</span>` : "";
|
|
569
605
|
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
|
|
570
|
-
|
|
571
|
-
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${
|
|
572
|
-
}).join(""),
|
|
573
|
-
return `<div style="display:flex;flex-wrap:wrap;justify-content:${
|
|
606
|
+
r.href
|
|
607
|
+
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${u}</a>${$}</span>`;
|
|
608
|
+
}).join(""), l = S(e);
|
|
609
|
+
return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${c}px;padding:${l};">${s || '<span style="color:#9ca3af;font-size:12px;">请填写链接 URL</span>'}</div>`;
|
|
574
610
|
}
|
|
575
|
-
}),
|
|
611
|
+
}), de = h({
|
|
576
612
|
type: "social-group",
|
|
577
613
|
name: "社交组",
|
|
578
614
|
category: "content",
|
|
@@ -599,7 +635,7 @@ ${a}
|
|
|
599
635
|
key: "elements",
|
|
600
636
|
label: "社交链接",
|
|
601
637
|
type: "socialLinkList",
|
|
602
|
-
options:
|
|
638
|
+
options: oe,
|
|
603
639
|
help: "每行:平台、链接、可选标签文字、自定义图标 URL、图标背景色。标签的字号/字重/颜色在下方统一设置。"
|
|
604
640
|
},
|
|
605
641
|
{
|
|
@@ -615,7 +651,7 @@ ${a}
|
|
|
615
651
|
label: "标签字重",
|
|
616
652
|
type: "select",
|
|
617
653
|
selectVariant: "segmented",
|
|
618
|
-
options: [...
|
|
654
|
+
options: [...j]
|
|
619
655
|
},
|
|
620
656
|
{ key: "labelColor", label: "标签颜色", type: "color" },
|
|
621
657
|
{
|
|
@@ -651,37 +687,41 @@ ${a}
|
|
|
651
687
|
{ key: "paddingTop", label: "外边距", type: "spacing" }
|
|
652
688
|
],
|
|
653
689
|
toMjml: (e) => {
|
|
654
|
-
const t =
|
|
655
|
-
var
|
|
656
|
-
return (
|
|
690
|
+
const t = S(e), o = I(e.iconSize, e.iconBorderRadius ?? 999), n = C(e.iconSpacing, 10), i = `align="${e.align}" icon-size="${e.iconSize}px" mode="horizontal" border-radius="${o}" inner-padding="${n}px" padding="${t}"`, c = e.elements.filter((l) => {
|
|
691
|
+
var a;
|
|
692
|
+
return (a = l.href) == null ? void 0 : a.trim();
|
|
657
693
|
}), d = {
|
|
658
694
|
labelFontSize: Number(e.labelFontSize ?? 13),
|
|
659
|
-
labelFontWeight:
|
|
695
|
+
labelFontWeight: y(String(e.labelFontWeight ?? "400")),
|
|
660
696
|
labelColor: String(e.labelColor ?? "#333333")
|
|
661
|
-
},
|
|
662
|
-
return
|
|
663
|
-
${
|
|
697
|
+
}, s = _(c, d);
|
|
698
|
+
return s.trim() ? `<mj-social ${i}>
|
|
699
|
+
${s}
|
|
664
700
|
</mj-social>` : `<mj-social ${i}></mj-social>`;
|
|
665
701
|
},
|
|
666
702
|
renderPreview: (e) => {
|
|
667
|
-
var
|
|
668
|
-
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n =
|
|
703
|
+
var a;
|
|
704
|
+
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n = y(e.labelFontWeight), i = ((a = e.labelColor) == null ? void 0 : a.trim()) || "#333333", c = C(e.iconSpacing, 10), d = O(e.align), s = e.elements.filter((r) => {
|
|
669
705
|
var g;
|
|
670
|
-
return (g =
|
|
671
|
-
}).map((
|
|
672
|
-
var
|
|
673
|
-
const g =
|
|
674
|
-
|
|
675
|
-
|
|
706
|
+
return (g = r.href) == null ? void 0 : g.trim();
|
|
707
|
+
}).map((r) => {
|
|
708
|
+
var x;
|
|
709
|
+
const g = ((x = r.label) == null ? void 0 : x.trim()) ?? "", u = W({
|
|
710
|
+
network: r.network,
|
|
711
|
+
iconSize: e.iconSize,
|
|
712
|
+
iconBorderRadius: e.iconBorderRadius ?? 999,
|
|
713
|
+
iconSrc: r.iconSrc,
|
|
714
|
+
backgroundColor: r.backgroundColor
|
|
715
|
+
}), $ = g ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
|
|
676
716
|
i
|
|
677
|
-
)} !important;line-height:1.2;">${p(
|
|
717
|
+
)} !important;line-height:1.2;">${p(g)}</span>` : "";
|
|
678
718
|
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
|
|
679
|
-
|
|
680
|
-
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${
|
|
681
|
-
}).join(""),
|
|
682
|
-
return `<div style="display:flex;flex-wrap:wrap;justify-content:${
|
|
719
|
+
r.href
|
|
720
|
+
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${u}</a>${$}</span>`;
|
|
721
|
+
}).join(""), l = S(e);
|
|
722
|
+
return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${c}px;padding:${l};">${s || '<span style="color:#9ca3af;font-size:12px;">请添加社交链接</span>'}</div>`;
|
|
683
723
|
}
|
|
684
|
-
}),
|
|
724
|
+
}), ge = h({
|
|
685
725
|
type: "spacer",
|
|
686
726
|
name: "间距",
|
|
687
727
|
category: "content",
|
|
@@ -690,7 +730,7 @@ ${a}
|
|
|
690
730
|
schema: [{ key: "height", label: "高度 (px)", type: "number", min: 1, max: 200 }],
|
|
691
731
|
toMjml: (e) => `<mj-spacer height="${e.height}px" />`,
|
|
692
732
|
renderPreview: (e) => `<div style="height:${e.height}px;line-height:${e.height}px;"></div>`
|
|
693
|
-
}),
|
|
733
|
+
}), v = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), H = "输入文本…", pe = h({
|
|
694
734
|
type: "text",
|
|
695
735
|
name: "文本",
|
|
696
736
|
category: "content",
|
|
@@ -729,7 +769,7 @@ ${a}
|
|
|
729
769
|
type: "select",
|
|
730
770
|
selectVariant: "segmented",
|
|
731
771
|
inheritGlobal: !0,
|
|
732
|
-
options: [...
|
|
772
|
+
options: [...j]
|
|
733
773
|
},
|
|
734
774
|
{
|
|
735
775
|
key: "lineHeight",
|
|
@@ -764,51 +804,53 @@ ${a}
|
|
|
764
804
|
mode: "rich",
|
|
765
805
|
multiline: !0,
|
|
766
806
|
propKey: "content",
|
|
767
|
-
placeholder:
|
|
807
|
+
placeholder: H
|
|
768
808
|
},
|
|
769
809
|
toMjml: (e) => {
|
|
770
|
-
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.fontFamily ? ` font-family="${
|
|
771
|
-
return `<mj-text align="${e.align}"${l}${
|
|
810
|
+
const t = `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`, o = e.fontFamily ? ` font-family="${v(e.fontFamily)}"` : "", n = String(e.fontWeight ?? "").trim(), i = n ? ` font-weight="${v(y(n))}"` : "", c = String(e.lineHeight ?? "").trim(), d = c ? ` line-height="${v(c)}"` : "", s = String(e.color ?? "").trim(), l = s ? ` color="${v(s)}"` : "", a = String(e.fontSize ?? "").trim(), r = a ? ` font-size="${v(a)}"` : "";
|
|
811
|
+
return `<mj-text align="${e.align}"${l}${r}${d}${o}${i} padding="${t}">${e.content}</mj-text>`;
|
|
772
812
|
},
|
|
773
813
|
renderPreview: (e) => {
|
|
774
|
-
const t = e.fontFamily ? `font-family:${e.fontFamily};` : "", o = String(e.fontWeight ?? "").trim(), n = o ? `font-weight:${
|
|
775
|
-
return `<div class="sm-text-content" style="text-align:${e.align};${
|
|
814
|
+
const t = e.fontFamily ? `font-family:${e.fontFamily};` : "", o = String(e.fontWeight ?? "").trim(), n = o ? `font-weight:${y(o)};` : "", i = String(e.lineHeight ?? "").trim(), c = i ? `line-height:${i};` : "line-height:normal;", d = String(e.color ?? "").trim(), s = d ? `color:${d};` : "", l = String(e.fontSize ?? "").trim(), a = l ? `font-size:${l};` : "", r = q(e.content), g = r ? " is-empty" : "", u = r ? ` data-placeholder="${H}"` : "";
|
|
815
|
+
return `<div class="sm-text-content${g}"${u} style="text-align:${e.align};${s}${a}${n}${c}${t}padding:${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px;">${e.content}</div>`;
|
|
776
816
|
}
|
|
777
|
-
}),
|
|
778
|
-
|
|
779
|
-
|
|
817
|
+
}), he = [
|
|
818
|
+
pe,
|
|
819
|
+
Z,
|
|
820
|
+
Q,
|
|
821
|
+
de,
|
|
780
822
|
Y,
|
|
781
|
-
le,
|
|
782
|
-
X,
|
|
783
|
-
q,
|
|
784
823
|
K,
|
|
785
|
-
|
|
786
|
-
|
|
824
|
+
D,
|
|
825
|
+
ge
|
|
826
|
+
], me = [ee, se, X], ue = [...he, ...me];
|
|
787
827
|
export {
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
828
|
+
oe as SOCIAL_NETWORK_OPTIONS,
|
|
829
|
+
ue as allBlocks,
|
|
830
|
+
he as builtinBlocks,
|
|
831
|
+
K as buttonBlock,
|
|
832
|
+
D as dividerBlock,
|
|
793
833
|
p as escAttr,
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
834
|
+
ie as escMjmlText,
|
|
835
|
+
me as exampleCustomBlocks,
|
|
836
|
+
O as flexJustifyFromAlign,
|
|
837
|
+
X as footerBlock,
|
|
838
|
+
Y as heroBlock,
|
|
839
|
+
Z as htmlBlock,
|
|
840
|
+
Q as imageBlock,
|
|
841
|
+
ee as logoBlock,
|
|
842
|
+
ae as mjSocialDefaultIconSrc,
|
|
843
|
+
E as mjSocialElementName,
|
|
844
|
+
_ as mjSocialElementsLines,
|
|
845
|
+
S as paddingQuad,
|
|
846
|
+
W as renderSocialIconPreviewHtml,
|
|
847
|
+
se as socialBlock,
|
|
848
|
+
de as socialGroupBlock,
|
|
849
|
+
ce as socialIconBorderRadiusCss,
|
|
850
|
+
I as socialIconBorderRadiusMjml,
|
|
851
|
+
C as socialIconSpacingPx,
|
|
852
|
+
N as socialMeta,
|
|
853
|
+
ge as spacerBlock,
|
|
854
|
+
pe as textBlock
|
|
813
855
|
};
|
|
814
856
|
//# sourceMappingURL=index.js.map
|