@consilioweb/payload-support 0.9.4 → 0.9.6
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/dist/index.cjs +39 -9
- package/dist/index.js +39 -9
- package/package.json +2 -2
- package/src/utils/emailTemplate.ts +53 -12
package/dist/index.cjs
CHANGED
|
@@ -1457,15 +1457,14 @@ function emailRichContent(html, config) {
|
|
|
1457
1457
|
function convertFencedCodeBlocks(input) {
|
|
1458
1458
|
if (!input.includes("```")) return input;
|
|
1459
1459
|
const normalized = input.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>\s*<(p|div)[^>]*>/gi, "\n").replace(/<(p|div)[^>]*>/gi, "").replace(/<\/(p|div)>/gi, "\n");
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
return
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
if (chunk.startsWith('<div style="margin: 16px 0')) return chunk;
|
|
1460
|
+
const codeBlocks = [];
|
|
1461
|
+
const withMarkers = normalized.replace(/```(\w*)\n?([\s\S]*?)```/g, (_match, lang, code) => {
|
|
1462
|
+
codeBlocks.push(renderCodeBlockHtml(lang || "", code || ""));
|
|
1463
|
+
return `\0CODEBLOCK_${codeBlocks.length - 1}\0`;
|
|
1464
|
+
});
|
|
1465
|
+
return withMarkers.split(/(\x00CODEBLOCK_\d+\x00)/g).map((chunk) => {
|
|
1466
|
+
const markerMatch = chunk.match(/^\x00CODEBLOCK_(\d+)\x00$/);
|
|
1467
|
+
if (markerMatch) return codeBlocks[parseInt(markerMatch[1], 10)];
|
|
1469
1468
|
return chunk.split("\n").map((line) => line.trim() ? `<p>${line}</p>` : "").join("");
|
|
1470
1469
|
}).join("");
|
|
1471
1470
|
}
|
|
@@ -1500,9 +1499,40 @@ function emailButton(text, url, color = "primary", config) {
|
|
|
1500
1499
|
</div>
|
|
1501
1500
|
`;
|
|
1502
1501
|
}
|
|
1502
|
+
function renderCodeBlockHtml(lang, code) {
|
|
1503
|
+
const cleanCode = escapeHtml(code.replace(/\n$/, ""));
|
|
1504
|
+
const label = lang ? lang.trim() : "code";
|
|
1505
|
+
return `<div style="margin: 12px 0; border: 1px solid #1f2937; border-radius: 8px; overflow: hidden; background: #0f172a;">
|
|
1506
|
+
<div style="padding: 6px 14px; background: #1e293b; border-bottom: 1px solid #334155; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 11px; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">${escapeHtml(label)}</div>
|
|
1507
|
+
<pre style="margin: 0; padding: 14px 16px; overflow-x: auto; background: #0f172a; color: #e2e8f0; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 13px; line-height: 1.6; white-space: pre;"><code style="background: transparent; padding: 0; color: inherit; font-family: inherit; font-size: inherit;">${cleanCode}</code></pre>
|
|
1508
|
+
</div>`;
|
|
1509
|
+
}
|
|
1503
1510
|
function emailQuote(content, borderColor, config) {
|
|
1504
1511
|
const c = resolveConfig(config);
|
|
1505
1512
|
const color = borderColor || c.brandColor;
|
|
1513
|
+
if (content && content.includes("```")) {
|
|
1514
|
+
const parts = [];
|
|
1515
|
+
const regex = /```(\w*)\n?([\s\S]*?)```/g;
|
|
1516
|
+
let lastIndex = 0;
|
|
1517
|
+
let match;
|
|
1518
|
+
while ((match = regex.exec(content)) !== null) {
|
|
1519
|
+
const textBefore = content.slice(lastIndex, match.index).trim();
|
|
1520
|
+
if (textBefore) {
|
|
1521
|
+
parts.push(`<p style="margin: 0 0 12px 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textBefore)}</p>`);
|
|
1522
|
+
}
|
|
1523
|
+
parts.push(renderCodeBlockHtml(match[1] || "", match[2] || ""));
|
|
1524
|
+
lastIndex = match.index + match[0].length;
|
|
1525
|
+
}
|
|
1526
|
+
const textAfter = content.slice(lastIndex).trim();
|
|
1527
|
+
if (textAfter) {
|
|
1528
|
+
parts.push(`<p style="margin: 12px 0 0 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textAfter)}</p>`);
|
|
1529
|
+
}
|
|
1530
|
+
return `
|
|
1531
|
+
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
1532
|
+
${parts.join("")}
|
|
1533
|
+
</div>
|
|
1534
|
+
`;
|
|
1535
|
+
}
|
|
1506
1536
|
return `
|
|
1507
1537
|
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
1508
1538
|
<p style="margin: 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(content)}</p>
|
package/dist/index.js
CHANGED
|
@@ -1451,15 +1451,14 @@ function emailRichContent(html, config) {
|
|
|
1451
1451
|
function convertFencedCodeBlocks(input) {
|
|
1452
1452
|
if (!input.includes("```")) return input;
|
|
1453
1453
|
const normalized = input.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>\s*<(p|div)[^>]*>/gi, "\n").replace(/<(p|div)[^>]*>/gi, "").replace(/<\/(p|div)>/gi, "\n");
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
return
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
if (chunk.startsWith('<div style="margin: 16px 0')) return chunk;
|
|
1454
|
+
const codeBlocks = [];
|
|
1455
|
+
const withMarkers = normalized.replace(/```(\w*)\n?([\s\S]*?)```/g, (_match, lang, code) => {
|
|
1456
|
+
codeBlocks.push(renderCodeBlockHtml(lang || "", code || ""));
|
|
1457
|
+
return `\0CODEBLOCK_${codeBlocks.length - 1}\0`;
|
|
1458
|
+
});
|
|
1459
|
+
return withMarkers.split(/(\x00CODEBLOCK_\d+\x00)/g).map((chunk) => {
|
|
1460
|
+
const markerMatch = chunk.match(/^\x00CODEBLOCK_(\d+)\x00$/);
|
|
1461
|
+
if (markerMatch) return codeBlocks[parseInt(markerMatch[1], 10)];
|
|
1463
1462
|
return chunk.split("\n").map((line) => line.trim() ? `<p>${line}</p>` : "").join("");
|
|
1464
1463
|
}).join("");
|
|
1465
1464
|
}
|
|
@@ -1494,9 +1493,40 @@ function emailButton(text, url, color = "primary", config) {
|
|
|
1494
1493
|
</div>
|
|
1495
1494
|
`;
|
|
1496
1495
|
}
|
|
1496
|
+
function renderCodeBlockHtml(lang, code) {
|
|
1497
|
+
const cleanCode = escapeHtml(code.replace(/\n$/, ""));
|
|
1498
|
+
const label = lang ? lang.trim() : "code";
|
|
1499
|
+
return `<div style="margin: 12px 0; border: 1px solid #1f2937; border-radius: 8px; overflow: hidden; background: #0f172a;">
|
|
1500
|
+
<div style="padding: 6px 14px; background: #1e293b; border-bottom: 1px solid #334155; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 11px; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">${escapeHtml(label)}</div>
|
|
1501
|
+
<pre style="margin: 0; padding: 14px 16px; overflow-x: auto; background: #0f172a; color: #e2e8f0; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 13px; line-height: 1.6; white-space: pre;"><code style="background: transparent; padding: 0; color: inherit; font-family: inherit; font-size: inherit;">${cleanCode}</code></pre>
|
|
1502
|
+
</div>`;
|
|
1503
|
+
}
|
|
1497
1504
|
function emailQuote(content, borderColor, config) {
|
|
1498
1505
|
const c = resolveConfig(config);
|
|
1499
1506
|
const color = borderColor || c.brandColor;
|
|
1507
|
+
if (content && content.includes("```")) {
|
|
1508
|
+
const parts = [];
|
|
1509
|
+
const regex = /```(\w*)\n?([\s\S]*?)```/g;
|
|
1510
|
+
let lastIndex = 0;
|
|
1511
|
+
let match;
|
|
1512
|
+
while ((match = regex.exec(content)) !== null) {
|
|
1513
|
+
const textBefore = content.slice(lastIndex, match.index).trim();
|
|
1514
|
+
if (textBefore) {
|
|
1515
|
+
parts.push(`<p style="margin: 0 0 12px 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textBefore)}</p>`);
|
|
1516
|
+
}
|
|
1517
|
+
parts.push(renderCodeBlockHtml(match[1] || "", match[2] || ""));
|
|
1518
|
+
lastIndex = match.index + match[0].length;
|
|
1519
|
+
}
|
|
1520
|
+
const textAfter = content.slice(lastIndex).trim();
|
|
1521
|
+
if (textAfter) {
|
|
1522
|
+
parts.push(`<p style="margin: 12px 0 0 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textAfter)}</p>`);
|
|
1523
|
+
}
|
|
1524
|
+
return `
|
|
1525
|
+
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
1526
|
+
${parts.join("")}
|
|
1527
|
+
</div>
|
|
1528
|
+
`;
|
|
1529
|
+
}
|
|
1500
1530
|
return `
|
|
1501
1531
|
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
1502
1532
|
<p style="margin: 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(content)}</p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@consilioweb/payload-support",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Payload CMS plugin — professional support & ticketing system with AI, SLA, time tracking, live chat, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
|
-
"prepublishOnly": "
|
|
55
|
+
"prepublishOnly": "npm run build"
|
|
56
56
|
},
|
|
57
57
|
"keywords": [
|
|
58
58
|
"payload",
|
|
@@ -88,19 +88,19 @@ export function emailRichContent(html: string, config?: EmailTemplateConfig): st
|
|
|
88
88
|
.replace(/<(p|div)[^>]*>/gi, '')
|
|
89
89
|
.replace(/<\/(p|div)>/gi, '\n')
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<pre style="margin: 0; padding: 14px 16px; overflow-x: auto; background: #0f172a; color: #e2e8f0; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 13px; line-height: 1.6; white-space: pre;"><code style="background: transparent; padding: 0; color: inherit; font-family: inherit; font-size: inherit;">${cleanCode}</code></pre>
|
|
97
|
-
</div>`
|
|
91
|
+
// Replace code blocks with markers to protect them from paragraph wrapping
|
|
92
|
+
const codeBlocks: string[] = []
|
|
93
|
+
const withMarkers = normalized.replace(/```(\w*)\n?([\s\S]*?)```/g, (_match, lang, code) => {
|
|
94
|
+
codeBlocks.push(renderCodeBlockHtml(lang || '', code || ''))
|
|
95
|
+
return `\x00CODEBLOCK_${codeBlocks.length - 1}\x00`
|
|
98
96
|
})
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
|
|
98
|
+
// Wrap non-marker text lines in <p>, then restore code blocks
|
|
99
|
+
return withMarkers
|
|
100
|
+
.split(/(\x00CODEBLOCK_\d+\x00)/g)
|
|
101
101
|
.map((chunk) => {
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
const markerMatch = chunk.match(/^\x00CODEBLOCK_(\d+)\x00$/)
|
|
103
|
+
if (markerMatch) return codeBlocks[parseInt(markerMatch[1], 10)]
|
|
104
104
|
return chunk
|
|
105
105
|
.split('\n')
|
|
106
106
|
.map((line) => line.trim() ? `<p>${line}</p>` : '')
|
|
@@ -165,11 +165,52 @@ export function emailButton(text: string, url: string, color: ButtonColor = 'pri
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
|
-
*
|
|
168
|
+
* Render a single fenced code block as styled email HTML.
|
|
169
|
+
* Email clients don't run JS so we just use a nice static layout.
|
|
170
|
+
*/
|
|
171
|
+
function renderCodeBlockHtml(lang: string, code: string): string {
|
|
172
|
+
const cleanCode = escapeHtml(code.replace(/\n$/, ''))
|
|
173
|
+
const label = lang ? lang.trim() : 'code'
|
|
174
|
+
return `<div style="margin: 12px 0; border: 1px solid #1f2937; border-radius: 8px; overflow: hidden; background: #0f172a;">
|
|
175
|
+
<div style="padding: 6px 14px; background: #1e293b; border-bottom: 1px solid #334155; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 11px; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">${escapeHtml(label)}</div>
|
|
176
|
+
<pre style="margin: 0; padding: 14px 16px; overflow-x: auto; background: #0f172a; color: #e2e8f0; font-family: 'SF Mono', 'Fira Code', Consolas, monospace; font-size: 13px; line-height: 1.6; white-space: pre;"><code style="background: transparent; padding: 0; color: inherit; font-family: inherit; font-size: inherit;">${cleanCode}</code></pre>
|
|
177
|
+
</div>`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Quote block for message previews — supports fenced code blocks.
|
|
169
182
|
*/
|
|
170
183
|
export function emailQuote(content: string, borderColor?: string, config?: EmailTemplateConfig): string {
|
|
171
184
|
const c = resolveConfig(config)
|
|
172
185
|
const color = borderColor || c.brandColor
|
|
186
|
+
|
|
187
|
+
// If content has fenced code blocks, render them as styled blocks
|
|
188
|
+
if (content && content.includes('```')) {
|
|
189
|
+
const parts: string[] = []
|
|
190
|
+
const regex = /```(\w*)\n?([\s\S]*?)```/g
|
|
191
|
+
let lastIndex = 0
|
|
192
|
+
let match: RegExpExecArray | null
|
|
193
|
+
while ((match = regex.exec(content)) !== null) {
|
|
194
|
+
// Text before the code block
|
|
195
|
+
const textBefore = content.slice(lastIndex, match.index).trim()
|
|
196
|
+
if (textBefore) {
|
|
197
|
+
parts.push(`<p style="margin: 0 0 12px 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textBefore)}</p>`)
|
|
198
|
+
}
|
|
199
|
+
parts.push(renderCodeBlockHtml(match[1] || '', match[2] || ''))
|
|
200
|
+
lastIndex = match.index + match[0].length
|
|
201
|
+
}
|
|
202
|
+
// Remaining text after the last code block
|
|
203
|
+
const textAfter = content.slice(lastIndex).trim()
|
|
204
|
+
if (textAfter) {
|
|
205
|
+
parts.push(`<p style="margin: 12px 0 0 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(textAfter)}</p>`)
|
|
206
|
+
}
|
|
207
|
+
return `
|
|
208
|
+
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
209
|
+
${parts.join('')}
|
|
210
|
+
</div>
|
|
211
|
+
`
|
|
212
|
+
}
|
|
213
|
+
|
|
173
214
|
return `
|
|
174
215
|
<div style="margin: 24px 0; padding: 20px 24px; background: #f8f9fa; border-left: 4px solid ${color}; border-radius: 0 8px 8px 0;">
|
|
175
216
|
<p style="margin: 0; font-size: 15px; line-height: 1.75; color: #333333; white-space: pre-wrap;">${escapeHtml(content)}</p>
|