mail-editor-pancake 0.0.9 → 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 +461 -303
- package/package.json +2 -2
- package/packages/blocks/dist/index.js +153 -150
- package/packages/blocks/dist/index.js.map +1 -1
- package/packages/blocks/src/html.ts +11 -3
- package/packages/blocks/src/text.ts +8 -3
- package/packages/core/dist/index.d.ts +220 -10
- package/packages/core/dist/index.js +3963 -2250
- 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 +182 -26
- package/packages/core/src/editor/Editor.ts +414 -68
- 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 +238 -24
- 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 +410 -52
- package/packages/core/src/index.ts +32 -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 +65 -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/sectionLayout.ts +2 -2
- package/packages/core/src/variables/index.ts +3 -4
- package/playground/vanilla/src/main.ts +26 -1
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mail-editor-pancake",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "面向运营的轻量邮件可视化编辑器",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@biomejs/biome": "^1.9.4",
|
|
8
8
|
"@types/node": "^25.6.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineBlock as h, blockButtonWidthCss as F, docContentWidthCss as L, mjRawEmailTableWrap 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 = F(e.width), i = n ? ` width="${
|
|
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
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
|
-
}), k = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """),
|
|
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",
|
|
@@ -216,7 +216,7 @@ const m = {
|
|
|
216
216
|
</mj-hero>`;
|
|
217
217
|
},
|
|
218
218
|
renderPreview: (e, t) => {
|
|
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`,
|
|
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};
|
|
@@ -248,7 +248,7 @@ const m = {
|
|
|
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",
|
|
@@ -334,7 +337,7 @@ const m = {
|
|
|
334
337
|
e.src
|
|
335
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 Z = [
|
|
|
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,11 +408,11 @@ const Z = [
|
|
|
405
408
|
rabbit: { color: "#FF2442", preview: "R" },
|
|
406
409
|
website: { color: "#6b7280", preview: "◇" },
|
|
407
410
|
web: { color: "#6b7280", preview: "◇" }
|
|
408
|
-
},
|
|
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: "·" };
|
|
411
414
|
}
|
|
412
|
-
const
|
|
415
|
+
const le = "https://www.mailjet.com/images/theme/v1/icons/ico-social/", re = {
|
|
413
416
|
facebook: "facebook.png",
|
|
414
417
|
twitter: "twitter.png",
|
|
415
418
|
x: "twitter-x.png",
|
|
@@ -428,26 +431,26 @@ const oe = "https://www.mailjet.com/images/theme/v1/icons/ico-social/", ne = {
|
|
|
428
431
|
soundcloud: "soundcloud.png",
|
|
429
432
|
dribbble: "dribbble.png"
|
|
430
433
|
};
|
|
431
|
-
function
|
|
432
|
-
const t =
|
|
433
|
-
return t ? `${
|
|
434
|
+
function ae(e) {
|
|
435
|
+
const t = re[E(e)];
|
|
436
|
+
return t ? `${le}${t}` : null;
|
|
434
437
|
}
|
|
435
|
-
function
|
|
436
|
-
const { network: t, iconSize: o, iconBorderRadius: n, iconSrc: i, backgroundColor:
|
|
437
|
-
return
|
|
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(
|
|
438
441
|
o / 2
|
|
439
|
-
)}px;font-weight:600;flex-shrink:0;overflow:hidden;">${
|
|
442
|
+
)}px;font-weight:600;flex-shrink:0;overflow:hidden;">${s.preview}</span>`;
|
|
440
443
|
}
|
|
441
444
|
function S(e) {
|
|
442
445
|
return `${e.paddingTop}px ${e.paddingRight}px ${e.paddingBottom}px ${e.paddingLeft}px`;
|
|
443
446
|
}
|
|
444
|
-
function
|
|
447
|
+
function I(e, t) {
|
|
445
448
|
const o = Math.max(1, Number(e) || 28), n = Number(t);
|
|
446
449
|
if (!Number.isFinite(n) || n <= 0) return "0px";
|
|
447
450
|
const i = o / 2;
|
|
448
451
|
return n >= 999 || n >= i ? "999px" : `${Math.min(n, o)}px`;
|
|
449
452
|
}
|
|
450
|
-
function
|
|
453
|
+
function ce(e, t) {
|
|
451
454
|
const o = Math.max(1, Number(e) || 28), n = Number(t);
|
|
452
455
|
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
453
456
|
const i = o / 2;
|
|
@@ -457,51 +460,51 @@ function C(e, t = 10) {
|
|
|
457
460
|
const o = Number(e);
|
|
458
461
|
return !Number.isFinite(o) || o < 0 ? t : Math.min(64, Math.round(o));
|
|
459
462
|
}
|
|
460
|
-
function
|
|
463
|
+
function O(e) {
|
|
461
464
|
return e === "right" ? "flex-end" : e === "left" ? "flex-start" : "center";
|
|
462
465
|
}
|
|
463
|
-
function
|
|
464
|
-
var
|
|
465
|
-
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);
|
|
466
469
|
return e.map((l) => {
|
|
467
|
-
var
|
|
468
|
-
const
|
|
469
|
-
`name="${
|
|
470
|
-
`href="${
|
|
471
|
-
`background-color="${
|
|
472
|
-
`color="${
|
|
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))}"`,
|
|
473
|
+
`href="${p(l.href)}"`,
|
|
474
|
+
`background-color="${p(r)}"`,
|
|
475
|
+
`color="${p(c)}"`,
|
|
473
476
|
`font-size="${n}px"`,
|
|
474
477
|
`font-weight="${d}"`
|
|
475
|
-
].join(" "), $ = (
|
|
476
|
-
return
|
|
477
|
-
${
|
|
478
|
-
</mj-social-element>` : ` <mj-social-element ${
|
|
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)}
|
|
481
|
+
</mj-social-element>` : ` <mj-social-element ${x} />`;
|
|
479
482
|
}).join(`
|
|
480
483
|
`);
|
|
481
484
|
}
|
|
482
|
-
const
|
|
485
|
+
const V = [
|
|
483
486
|
{ network: "x", href: "https://x.com/" },
|
|
484
487
|
{ network: "rabbit", href: "https://example.com" },
|
|
485
488
|
{ network: "facebook", href: "https://facebook.com/" },
|
|
486
489
|
{ network: "tiktok", href: "https://www.tiktok.com/" },
|
|
487
490
|
{ network: "ig", href: "https://instagram.com/" }
|
|
488
491
|
];
|
|
489
|
-
function
|
|
492
|
+
function P(e) {
|
|
490
493
|
var o;
|
|
491
494
|
if ((o = e.elements) != null && o.length) return e.elements;
|
|
492
495
|
const t = e.links;
|
|
493
496
|
return Array.isArray(t) && t.length ? t.map((n) => ({
|
|
494
497
|
network: String(n.network ?? "web"),
|
|
495
498
|
href: String(n.href ?? "")
|
|
496
|
-
})) :
|
|
499
|
+
})) : V;
|
|
497
500
|
}
|
|
498
|
-
const
|
|
501
|
+
const se = h({
|
|
499
502
|
type: "custom:social",
|
|
500
503
|
name: "社交链接",
|
|
501
504
|
category: "custom",
|
|
502
505
|
icon: m.social,
|
|
503
506
|
defaultProps: {
|
|
504
|
-
elements:
|
|
507
|
+
elements: V,
|
|
505
508
|
align: "center",
|
|
506
509
|
iconSize: 28,
|
|
507
510
|
iconBorderRadius: 999,
|
|
@@ -519,7 +522,7 @@ const re = h({
|
|
|
519
522
|
key: "elements",
|
|
520
523
|
label: "社交链接",
|
|
521
524
|
type: "socialLinkList",
|
|
522
|
-
options:
|
|
525
|
+
options: te,
|
|
523
526
|
help: "平台:X、Rabbit、Facebook、TikTok、Instagram (ig)。可填标签、自定义图标 URL。MJML 侧 Rabbit/TikTok 使用 web 占位图标,需要品牌图时请填「图标 URL」。"
|
|
524
527
|
},
|
|
525
528
|
{
|
|
@@ -535,7 +538,7 @@ const re = h({
|
|
|
535
538
|
label: "标签字重",
|
|
536
539
|
type: "select",
|
|
537
540
|
selectVariant: "segmented",
|
|
538
|
-
options: [...
|
|
541
|
+
options: [...j]
|
|
539
542
|
},
|
|
540
543
|
{ key: "labelColor", label: "标签颜色", type: "color" },
|
|
541
544
|
{
|
|
@@ -571,41 +574,41 @@ const re = h({
|
|
|
571
574
|
{ key: "paddingTop", label: "外边距", type: "spacing" }
|
|
572
575
|
],
|
|
573
576
|
toMjml: (e) => {
|
|
574
|
-
const t = S(e), o =
|
|
575
|
-
var
|
|
576
|
-
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();
|
|
577
580
|
}), d = {
|
|
578
581
|
labelFontSize: Number(e.labelFontSize ?? 13),
|
|
579
|
-
labelFontWeight:
|
|
582
|
+
labelFontWeight: y(String(e.labelFontWeight ?? "400")),
|
|
580
583
|
labelColor: String(e.labelColor ?? "#333333")
|
|
581
|
-
},
|
|
582
|
-
return
|
|
583
|
-
${
|
|
584
|
+
}, s = _(c, d);
|
|
585
|
+
return s.trim() ? `<mj-social ${i}>
|
|
586
|
+
${s}
|
|
584
587
|
</mj-social>` : `<mj-social ${i}></mj-social>`;
|
|
585
588
|
},
|
|
586
589
|
renderPreview: (e) => {
|
|
587
|
-
var
|
|
588
|
-
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n =
|
|
589
|
-
var
|
|
590
|
-
return (
|
|
591
|
-
}).map((
|
|
592
|
-
var
|
|
593
|
-
const
|
|
594
|
-
network:
|
|
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) => {
|
|
592
|
+
var g;
|
|
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,
|
|
595
598
|
iconSize: e.iconSize,
|
|
596
599
|
iconBorderRadius: e.iconBorderRadius ?? 999,
|
|
597
|
-
iconSrc:
|
|
598
|
-
backgroundColor:
|
|
599
|
-
}), $ =
|
|
600
|
+
iconSrc: r.iconSrc,
|
|
601
|
+
backgroundColor: r.backgroundColor
|
|
602
|
+
}), $ = g ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
|
|
600
603
|
i
|
|
601
|
-
)} !important;line-height:1.2;">${g
|
|
602
|
-
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${
|
|
603
|
-
|
|
604
|
-
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${
|
|
604
|
+
)} !important;line-height:1.2;">${p(g)}</span>` : "";
|
|
605
|
+
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
|
|
606
|
+
r.href
|
|
607
|
+
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${u}</a>${$}</span>`;
|
|
605
608
|
}).join(""), l = S(e);
|
|
606
|
-
return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${
|
|
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>`;
|
|
607
610
|
}
|
|
608
|
-
}),
|
|
611
|
+
}), de = h({
|
|
609
612
|
type: "social-group",
|
|
610
613
|
name: "社交组",
|
|
611
614
|
category: "content",
|
|
@@ -632,7 +635,7 @@ ${c}
|
|
|
632
635
|
key: "elements",
|
|
633
636
|
label: "社交链接",
|
|
634
637
|
type: "socialLinkList",
|
|
635
|
-
options:
|
|
638
|
+
options: oe,
|
|
636
639
|
help: "每行:平台、链接、可选标签文字、自定义图标 URL、图标背景色。标签的字号/字重/颜色在下方统一设置。"
|
|
637
640
|
},
|
|
638
641
|
{
|
|
@@ -648,7 +651,7 @@ ${c}
|
|
|
648
651
|
label: "标签字重",
|
|
649
652
|
type: "select",
|
|
650
653
|
selectVariant: "segmented",
|
|
651
|
-
options: [...
|
|
654
|
+
options: [...j]
|
|
652
655
|
},
|
|
653
656
|
{ key: "labelColor", label: "标签颜色", type: "color" },
|
|
654
657
|
{
|
|
@@ -684,41 +687,41 @@ ${c}
|
|
|
684
687
|
{ key: "paddingTop", label: "外边距", type: "spacing" }
|
|
685
688
|
],
|
|
686
689
|
toMjml: (e) => {
|
|
687
|
-
const t = S(e), o =
|
|
688
|
-
var
|
|
689
|
-
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();
|
|
690
693
|
}), d = {
|
|
691
694
|
labelFontSize: Number(e.labelFontSize ?? 13),
|
|
692
|
-
labelFontWeight:
|
|
695
|
+
labelFontWeight: y(String(e.labelFontWeight ?? "400")),
|
|
693
696
|
labelColor: String(e.labelColor ?? "#333333")
|
|
694
|
-
},
|
|
695
|
-
return
|
|
696
|
-
${
|
|
697
|
+
}, s = _(c, d);
|
|
698
|
+
return s.trim() ? `<mj-social ${i}>
|
|
699
|
+
${s}
|
|
697
700
|
</mj-social>` : `<mj-social ${i}></mj-social>`;
|
|
698
701
|
},
|
|
699
702
|
renderPreview: (e) => {
|
|
700
|
-
var
|
|
701
|
-
const t = e.labelFontSize != null && e.labelFontSize > 0 ? e.labelFontSize : 13, o = Math.max(8, Math.min(48, t)), n =
|
|
702
|
-
var
|
|
703
|
-
return (
|
|
704
|
-
}).map((
|
|
705
|
-
var
|
|
706
|
-
const
|
|
707
|
-
network:
|
|
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) => {
|
|
705
|
+
var g;
|
|
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,
|
|
708
711
|
iconSize: e.iconSize,
|
|
709
712
|
iconBorderRadius: e.iconBorderRadius ?? 999,
|
|
710
|
-
iconSrc:
|
|
711
|
-
backgroundColor:
|
|
712
|
-
}), $ =
|
|
713
|
+
iconSrc: r.iconSrc,
|
|
714
|
+
backgroundColor: r.backgroundColor
|
|
715
|
+
}), $ = g ? `<span style="font-size:${o}px !important;font-weight:${n};color:${p(
|
|
713
716
|
i
|
|
714
|
-
)} !important;line-height:1.2;">${g
|
|
715
|
-
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${
|
|
716
|
-
|
|
717
|
-
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${
|
|
717
|
+
)} !important;line-height:1.2;">${p(g)}</span>` : "";
|
|
718
|
+
return `<span style="display:inline-flex;align-items:center;gap:6px;"><a href="${p(
|
|
719
|
+
r.href
|
|
720
|
+
)}" style="display:inline-flex;align-items:center;text-decoration:none;line-height:0;">${u}</a>${$}</span>`;
|
|
718
721
|
}).join(""), l = S(e);
|
|
719
|
-
return `<div style="display:flex;flex-wrap:wrap;justify-content:${d};align-items:center;gap:${
|
|
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>`;
|
|
720
723
|
}
|
|
721
|
-
}),
|
|
724
|
+
}), ge = h({
|
|
722
725
|
type: "spacer",
|
|
723
726
|
name: "间距",
|
|
724
727
|
category: "content",
|
|
@@ -727,7 +730,7 @@ ${c}
|
|
|
727
730
|
schema: [{ key: "height", label: "高度 (px)", type: "number", min: 1, max: 200 }],
|
|
728
731
|
toMjml: (e) => `<mj-spacer height="${e.height}px" />`,
|
|
729
732
|
renderPreview: (e) => `<div style="height:${e.height}px;line-height:${e.height}px;"></div>`
|
|
730
|
-
}), v = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """),
|
|
733
|
+
}), v = (e) => e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """), H = "输入文本…", pe = h({
|
|
731
734
|
type: "text",
|
|
732
735
|
name: "文本",
|
|
733
736
|
category: "content",
|
|
@@ -766,7 +769,7 @@ ${c}
|
|
|
766
769
|
type: "select",
|
|
767
770
|
selectVariant: "segmented",
|
|
768
771
|
inheritGlobal: !0,
|
|
769
|
-
options: [...
|
|
772
|
+
options: [...j]
|
|
770
773
|
},
|
|
771
774
|
{
|
|
772
775
|
key: "lineHeight",
|
|
@@ -801,53 +804,53 @@ ${c}
|
|
|
801
804
|
mode: "rich",
|
|
802
805
|
multiline: !0,
|
|
803
806
|
propKey: "content",
|
|
804
|
-
placeholder:
|
|
807
|
+
placeholder: H
|
|
805
808
|
},
|
|
806
809
|
toMjml: (e) => {
|
|
807
|
-
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(
|
|
808
|
-
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>`;
|
|
809
812
|
},
|
|
810
813
|
renderPreview: (e) => {
|
|
811
|
-
const t = e.fontFamily ? `font-family:${e.fontFamily};` : "", o = String(e.fontWeight ?? "").trim(), n = o ? `font-weight:${
|
|
812
|
-
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>`;
|
|
813
816
|
}
|
|
814
|
-
}),
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
817
|
+
}), he = [
|
|
818
|
+
pe,
|
|
819
|
+
Z,
|
|
820
|
+
Q,
|
|
821
|
+
de,
|
|
822
|
+
Y,
|
|
819
823
|
K,
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
], ge = [Y, re, J], he = [...de, ...ge];
|
|
824
|
+
D,
|
|
825
|
+
ge
|
|
826
|
+
], me = [ee, se, X], ue = [...he, ...me];
|
|
824
827
|
export {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
828
|
+
oe as SOCIAL_NETWORK_OPTIONS,
|
|
829
|
+
ue as allBlocks,
|
|
830
|
+
he as builtinBlocks,
|
|
831
|
+
K as buttonBlock,
|
|
832
|
+
D as dividerBlock,
|
|
833
|
+
p as escAttr,
|
|
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,
|
|
842
845
|
S as paddingQuad,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
846
|
+
W as renderSocialIconPreviewHtml,
|
|
847
|
+
se as socialBlock,
|
|
848
|
+
de as socialGroupBlock,
|
|
849
|
+
ce as socialIconBorderRadiusCss,
|
|
850
|
+
I as socialIconBorderRadiusMjml,
|
|
848
851
|
C as socialIconSpacingPx,
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
+
N as socialMeta,
|
|
853
|
+
ge as spacerBlock,
|
|
854
|
+
pe as textBlock
|
|
852
855
|
};
|
|
853
856
|
//# sourceMappingURL=index.js.map
|