payload-plugin-newsletter 0.11.0 → 0.12.1
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 +33 -2
- package/dist/components.cjs +442 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +33 -1
- package/dist/components.d.ts +33 -1
- package/dist/components.js +447 -0
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +14 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## [0.12.1] - 2025-07-20
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
- Resolved ESLint errors in email preview components
|
|
5
|
+
- Removed unused imports and variables
|
|
6
|
+
- Fixed console.info statements in template loader
|
|
7
|
+
|
|
8
|
+
## [0.12.0] - 2025-07-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Email preview feature for broadcasts with inline preview component
|
|
12
|
+
- React Email integration for reliable email template rendering
|
|
13
|
+
- Custom email template support
|
|
14
|
+
- Desktop and mobile preview modes
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Broadcast collection now includes inline email preview below content editor
|
|
18
|
+
|
|
1
19
|
## [0.11.0] - 2025-07-20
|
|
2
20
|
|
|
3
21
|
### Added
|
|
@@ -7,12 +25,25 @@
|
|
|
7
25
|
- Image upload support with Media collection integration
|
|
8
26
|
- Custom email blocks (Button and Divider)
|
|
9
27
|
- Enhanced link feature with "open in new tab" option
|
|
28
|
+
- Email preview feature for broadcasts:
|
|
29
|
+
- Live preview with manual update button
|
|
30
|
+
- Desktop and mobile responsive views
|
|
31
|
+
- React Email template rendering
|
|
32
|
+
- Custom template support via `email-templates/broadcast-template.tsx`
|
|
33
|
+
- Inline preview below content editor
|
|
10
34
|
- Comprehensive image handling in email HTML conversion:
|
|
11
35
|
- Responsive images with proper email-safe HTML
|
|
12
36
|
- Support for captions and alt text
|
|
13
37
|
- Automatic media URL handling for different storage backends
|
|
14
|
-
-
|
|
15
|
-
-
|
|
38
|
+
- New utilities and components:
|
|
39
|
+
- `contentTransformer` for preview content processing
|
|
40
|
+
- `templateLoader` for custom template discovery
|
|
41
|
+
- `DefaultBroadcastTemplate` bundled email template
|
|
42
|
+
- `BroadcastInlinePreview` component
|
|
43
|
+
- Documentation:
|
|
44
|
+
- Media collection setup guide (`docs/guides/media-collection-setup.md`)
|
|
45
|
+
- Email preview feature guide (`docs/features/email-preview.md`)
|
|
46
|
+
- Prerequisites section in README mentioning Media collection requirement
|
|
16
47
|
|
|
17
48
|
### Changed
|
|
18
49
|
- Removed 'name' field from Broadcasts collection (now uses 'subject' as title)
|
package/dist/components.cjs
CHANGED
|
@@ -32,11 +32,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var components_exports = {};
|
|
33
33
|
__export(components_exports, {
|
|
34
34
|
BroadcastEditor: () => BroadcastEditor,
|
|
35
|
+
BroadcastInlinePreview: () => BroadcastInlinePreview,
|
|
36
|
+
BroadcastPreviewField: () => BroadcastPreviewField,
|
|
37
|
+
DefaultBroadcastTemplate: () => DefaultBroadcastTemplate,
|
|
35
38
|
EmailPreview: () => EmailPreview,
|
|
36
39
|
EmailPreviewField: () => EmailPreviewField,
|
|
40
|
+
EmailRenderer: () => EmailRenderer,
|
|
37
41
|
MagicLinkVerify: () => MagicLinkVerify,
|
|
38
42
|
NewsletterForm: () => NewsletterForm,
|
|
39
43
|
PreferencesForm: () => PreferencesForm,
|
|
44
|
+
PreviewControls: () => PreviewControls,
|
|
40
45
|
createMagicLinkVerify: () => createMagicLinkVerify,
|
|
41
46
|
createNewsletterForm: () => createNewsletterForm,
|
|
42
47
|
createPreferencesForm: () => createPreferencesForm,
|
|
@@ -1726,14 +1731,451 @@ var BroadcastEditor = (props) => {
|
|
|
1726
1731
|
] })
|
|
1727
1732
|
] });
|
|
1728
1733
|
};
|
|
1734
|
+
|
|
1735
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
1736
|
+
var import_react9 = require("react");
|
|
1737
|
+
var import_ui3 = require("@payloadcms/ui");
|
|
1738
|
+
|
|
1739
|
+
// src/utils/contentTransformer.ts
|
|
1740
|
+
async function transformContentForPreview(lexicalState, options = {}) {
|
|
1741
|
+
const html = await convertToEmailSafeHtml(lexicalState, {
|
|
1742
|
+
mediaUrl: options.mediaUrl
|
|
1743
|
+
});
|
|
1744
|
+
const processedHtml = processCustomBlocks(html);
|
|
1745
|
+
return processedHtml;
|
|
1746
|
+
}
|
|
1747
|
+
function processCustomBlocks(html) {
|
|
1748
|
+
return html;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
// src/email-templates/DefaultBroadcastTemplate.tsx
|
|
1752
|
+
var import_components2 = require("@react-email/components");
|
|
1753
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1754
|
+
var DefaultBroadcastTemplate = ({
|
|
1755
|
+
subject,
|
|
1756
|
+
preheader,
|
|
1757
|
+
content
|
|
1758
|
+
}) => {
|
|
1759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Html, { children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Head, {}),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Preview, { children: preheader || subject }),
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Body, { style: main, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Container, { style: container, children: [
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Section, { style: contentSection, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { dangerouslySetInnerHTML: { __html: content } }) }),
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Hr, { style: divider }),
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Section, { style: footer, children: [
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Text, { style: footerText, children: "You're receiving this email because you subscribed to our newsletter." }),
|
|
1767
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Text, { style: footerText, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Link, { href: "{{unsubscribe_url}}", style: footerLink, children: "Unsubscribe" }) })
|
|
1768
|
+
] })
|
|
1769
|
+
] }) })
|
|
1770
|
+
] });
|
|
1771
|
+
};
|
|
1772
|
+
var main = {
|
|
1773
|
+
backgroundColor: "#ffffff",
|
|
1774
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
1775
|
+
};
|
|
1776
|
+
var container = {
|
|
1777
|
+
margin: "0 auto",
|
|
1778
|
+
padding: "40px 20px",
|
|
1779
|
+
maxWidth: "600px"
|
|
1780
|
+
};
|
|
1781
|
+
var contentSection = {
|
|
1782
|
+
fontSize: "16px",
|
|
1783
|
+
lineHeight: "1.6",
|
|
1784
|
+
color: "#374151"
|
|
1785
|
+
};
|
|
1786
|
+
var divider = {
|
|
1787
|
+
borderColor: "#e5e7eb",
|
|
1788
|
+
margin: "40px 0 20px"
|
|
1789
|
+
};
|
|
1790
|
+
var footer = {
|
|
1791
|
+
textAlign: "center"
|
|
1792
|
+
};
|
|
1793
|
+
var footerText = {
|
|
1794
|
+
fontSize: "14px",
|
|
1795
|
+
lineHeight: "1.5",
|
|
1796
|
+
color: "#6b7280",
|
|
1797
|
+
margin: "0 0 10px"
|
|
1798
|
+
};
|
|
1799
|
+
var footerLink = {
|
|
1800
|
+
color: "#6b7280",
|
|
1801
|
+
textDecoration: "underline"
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
// src/utils/templateLoader.ts
|
|
1805
|
+
var TemplateLoader = class {
|
|
1806
|
+
constructor() {
|
|
1807
|
+
this.loadAttempted = false;
|
|
1808
|
+
this.defaultTemplate = DefaultBroadcastTemplate;
|
|
1809
|
+
}
|
|
1810
|
+
async loadTemplate() {
|
|
1811
|
+
if (!this.loadAttempted) {
|
|
1812
|
+
this.loadAttempted = true;
|
|
1813
|
+
await this.attemptCustomTemplateLoad();
|
|
1814
|
+
}
|
|
1815
|
+
return this.customTemplate || this.defaultTemplate;
|
|
1816
|
+
}
|
|
1817
|
+
async attemptCustomTemplateLoad() {
|
|
1818
|
+
try {
|
|
1819
|
+
const customTemplatePath = `${process.cwd()}/email-templates/broadcast-template`;
|
|
1820
|
+
const module2 = await import(
|
|
1821
|
+
/* @vite-ignore */
|
|
1822
|
+
/* webpackIgnore: true */
|
|
1823
|
+
customTemplatePath
|
|
1824
|
+
).catch(() => null);
|
|
1825
|
+
if (module2) {
|
|
1826
|
+
this.customTemplate = module2.default || module2.BroadcastTemplate;
|
|
1827
|
+
}
|
|
1828
|
+
} catch {
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
// Reset for testing
|
|
1832
|
+
reset() {
|
|
1833
|
+
this.customTemplate = void 0;
|
|
1834
|
+
this.loadAttempted = false;
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
var templateLoader = new TemplateLoader();
|
|
1838
|
+
async function loadTemplate() {
|
|
1839
|
+
return templateLoader.loadTemplate();
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
// src/components/Broadcasts/EmailRenderer.tsx
|
|
1843
|
+
var import_react8 = require("react");
|
|
1844
|
+
var import_render = require("@react-email/render");
|
|
1845
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1846
|
+
var EmailRenderer = ({
|
|
1847
|
+
template,
|
|
1848
|
+
data,
|
|
1849
|
+
device = "desktop",
|
|
1850
|
+
onRender
|
|
1851
|
+
}) => {
|
|
1852
|
+
const [renderedHtml, setRenderedHtml] = (0, import_react8.useState)("");
|
|
1853
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1854
|
+
const iframeRef = (0, import_react8.useRef)(null);
|
|
1855
|
+
const renderEmail = (0, import_react8.useCallback)(async () => {
|
|
1856
|
+
try {
|
|
1857
|
+
const TemplateComponent = template;
|
|
1858
|
+
const element = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TemplateComponent, { ...data });
|
|
1859
|
+
const html = await (0, import_render.render)(element, {
|
|
1860
|
+
pretty: true
|
|
1861
|
+
});
|
|
1862
|
+
setRenderedHtml(html);
|
|
1863
|
+
onRender?.(html);
|
|
1864
|
+
setError(null);
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
setError(err);
|
|
1867
|
+
console.error("Failed to render email template:", err);
|
|
1868
|
+
}
|
|
1869
|
+
}, [template, data, onRender]);
|
|
1870
|
+
(0, import_react8.useEffect)(() => {
|
|
1871
|
+
renderEmail();
|
|
1872
|
+
}, [renderEmail]);
|
|
1873
|
+
(0, import_react8.useEffect)(() => {
|
|
1874
|
+
if (iframeRef.current && renderedHtml) {
|
|
1875
|
+
const iframe = iframeRef.current;
|
|
1876
|
+
const doc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
1877
|
+
if (doc) {
|
|
1878
|
+
doc.open();
|
|
1879
|
+
doc.write(renderedHtml);
|
|
1880
|
+
doc.close();
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
}, [renderedHtml]);
|
|
1884
|
+
const containerStyle = {
|
|
1885
|
+
width: "100%",
|
|
1886
|
+
height: "100%",
|
|
1887
|
+
display: "flex",
|
|
1888
|
+
alignItems: "center",
|
|
1889
|
+
justifyContent: "center"
|
|
1890
|
+
};
|
|
1891
|
+
const iframeStyle = {
|
|
1892
|
+
width: device === "mobile" ? "375px" : "600px",
|
|
1893
|
+
maxWidth: "100%",
|
|
1894
|
+
height: "100%",
|
|
1895
|
+
background: "white",
|
|
1896
|
+
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
1897
|
+
borderRadius: device === "mobile" ? "20px" : "8px",
|
|
1898
|
+
border: "none",
|
|
1899
|
+
display: "block"
|
|
1900
|
+
};
|
|
1901
|
+
const errorStyle = {
|
|
1902
|
+
background: "white",
|
|
1903
|
+
border: "1px solid #ef4444",
|
|
1904
|
+
borderRadius: "4px",
|
|
1905
|
+
padding: "2rem",
|
|
1906
|
+
maxWidth: "500px"
|
|
1907
|
+
};
|
|
1908
|
+
if (error) {
|
|
1909
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: errorStyle, children: [
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: "Template Render Error" }),
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { style: {
|
|
1912
|
+
background: "#f9fafb",
|
|
1913
|
+
padding: "1rem",
|
|
1914
|
+
borderRadius: "4px",
|
|
1915
|
+
overflowX: "auto",
|
|
1916
|
+
fontSize: "12px",
|
|
1917
|
+
color: "#374151",
|
|
1918
|
+
margin: 0
|
|
1919
|
+
}, children: error.message })
|
|
1920
|
+
] });
|
|
1921
|
+
}
|
|
1922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1923
|
+
"iframe",
|
|
1924
|
+
{
|
|
1925
|
+
ref: iframeRef,
|
|
1926
|
+
style: iframeStyle,
|
|
1927
|
+
sandbox: "allow-same-origin",
|
|
1928
|
+
title: "Email Preview"
|
|
1929
|
+
}
|
|
1930
|
+
) });
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
// src/components/Broadcasts/PreviewControls.tsx
|
|
1934
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1935
|
+
var PreviewControls = ({
|
|
1936
|
+
onUpdate,
|
|
1937
|
+
device,
|
|
1938
|
+
onDeviceChange,
|
|
1939
|
+
isLoading = false
|
|
1940
|
+
}) => {
|
|
1941
|
+
const controlsStyle = {
|
|
1942
|
+
display: "flex",
|
|
1943
|
+
alignItems: "center",
|
|
1944
|
+
justifyContent: "space-between",
|
|
1945
|
+
padding: "1rem",
|
|
1946
|
+
background: "white",
|
|
1947
|
+
borderBottom: "1px solid #e5e7eb"
|
|
1948
|
+
};
|
|
1949
|
+
const updateButtonStyle = {
|
|
1950
|
+
padding: "0.5rem 1rem",
|
|
1951
|
+
background: "#10b981",
|
|
1952
|
+
color: "white",
|
|
1953
|
+
border: "none",
|
|
1954
|
+
borderRadius: "4px",
|
|
1955
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
1956
|
+
fontSize: "14px",
|
|
1957
|
+
fontWeight: 500,
|
|
1958
|
+
opacity: isLoading ? 0.6 : 1
|
|
1959
|
+
};
|
|
1960
|
+
const deviceSelectorStyle = {
|
|
1961
|
+
display: "flex",
|
|
1962
|
+
gap: "0.5rem"
|
|
1963
|
+
};
|
|
1964
|
+
const deviceButtonStyle = (isActive) => ({
|
|
1965
|
+
display: "flex",
|
|
1966
|
+
alignItems: "center",
|
|
1967
|
+
gap: "0.5rem",
|
|
1968
|
+
padding: "0.5rem 0.75rem",
|
|
1969
|
+
background: isActive ? "#1f2937" : "white",
|
|
1970
|
+
color: isActive ? "white" : "#374151",
|
|
1971
|
+
border: `1px solid ${isActive ? "#1f2937" : "#e5e7eb"}`,
|
|
1972
|
+
borderRadius: "4px",
|
|
1973
|
+
cursor: "pointer",
|
|
1974
|
+
fontSize: "14px"
|
|
1975
|
+
});
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: controlsStyle, children: [
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1978
|
+
"button",
|
|
1979
|
+
{
|
|
1980
|
+
style: updateButtonStyle,
|
|
1981
|
+
onClick: onUpdate,
|
|
1982
|
+
disabled: isLoading,
|
|
1983
|
+
children: isLoading ? "Updating..." : "Update Preview"
|
|
1984
|
+
}
|
|
1985
|
+
),
|
|
1986
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: deviceSelectorStyle, children: [
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1988
|
+
"button",
|
|
1989
|
+
{
|
|
1990
|
+
style: deviceButtonStyle(device === "desktop"),
|
|
1991
|
+
onClick: () => onDeviceChange("desktop"),
|
|
1992
|
+
"aria-label": "Desktop view",
|
|
1993
|
+
children: [
|
|
1994
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1995
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
|
|
1998
|
+
] }),
|
|
1999
|
+
"Desktop"
|
|
2000
|
+
]
|
|
2001
|
+
}
|
|
2002
|
+
),
|
|
2003
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2004
|
+
"button",
|
|
2005
|
+
{
|
|
2006
|
+
style: deviceButtonStyle(device === "mobile"),
|
|
2007
|
+
onClick: () => onDeviceChange("mobile"),
|
|
2008
|
+
"aria-label": "Mobile view",
|
|
2009
|
+
children: [
|
|
2010
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }),
|
|
2012
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "12", y1: "18", x2: "12", y2: "18" })
|
|
2013
|
+
] }),
|
|
2014
|
+
"Mobile"
|
|
2015
|
+
]
|
|
2016
|
+
}
|
|
2017
|
+
)
|
|
2018
|
+
] })
|
|
2019
|
+
] });
|
|
2020
|
+
};
|
|
2021
|
+
|
|
2022
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
2023
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2024
|
+
var BroadcastInlinePreview = () => {
|
|
2025
|
+
const [device, setDevice] = (0, import_react9.useState)("desktop");
|
|
2026
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(false);
|
|
2027
|
+
const [showPreview, setShowPreview] = (0, import_react9.useState)(false);
|
|
2028
|
+
const [previewData, setPreviewData] = (0, import_react9.useState)(null);
|
|
2029
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
2030
|
+
const fields = (0, import_ui3.useFormFields)(([fields2]) => ({
|
|
2031
|
+
subject: fields2.subject?.value,
|
|
2032
|
+
preheader: fields2.preheader?.value,
|
|
2033
|
+
content: fields2.content?.value
|
|
2034
|
+
}));
|
|
2035
|
+
const updatePreview = (0, import_react9.useCallback)(async () => {
|
|
2036
|
+
if (!fields.content) {
|
|
2037
|
+
setError(new Error("Please add some content before previewing"));
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
setIsLoading(true);
|
|
2041
|
+
setError(null);
|
|
2042
|
+
try {
|
|
2043
|
+
const htmlContent = await transformContentForPreview(fields.content, {
|
|
2044
|
+
mediaUrl: "/api/media"
|
|
2045
|
+
});
|
|
2046
|
+
const template = await loadTemplate();
|
|
2047
|
+
setPreviewData({
|
|
2048
|
+
template,
|
|
2049
|
+
data: {
|
|
2050
|
+
subject: fields.subject || "",
|
|
2051
|
+
preheader: fields.preheader || "",
|
|
2052
|
+
content: htmlContent
|
|
2053
|
+
}
|
|
2054
|
+
});
|
|
2055
|
+
setShowPreview(true);
|
|
2056
|
+
} catch (err) {
|
|
2057
|
+
setError(err);
|
|
2058
|
+
console.error("Failed to update preview:", err);
|
|
2059
|
+
} finally {
|
|
2060
|
+
setIsLoading(false);
|
|
2061
|
+
}
|
|
2062
|
+
}, [fields]);
|
|
2063
|
+
const containerStyle = {
|
|
2064
|
+
marginTop: "2rem",
|
|
2065
|
+
border: "1px solid #e5e7eb",
|
|
2066
|
+
borderRadius: "8px",
|
|
2067
|
+
overflow: "hidden"
|
|
2068
|
+
};
|
|
2069
|
+
const headerStyle = {
|
|
2070
|
+
display: "flex",
|
|
2071
|
+
alignItems: "center",
|
|
2072
|
+
justifyContent: "space-between",
|
|
2073
|
+
padding: "1rem",
|
|
2074
|
+
background: "#f9fafb",
|
|
2075
|
+
borderBottom: "1px solid #e5e7eb"
|
|
2076
|
+
};
|
|
2077
|
+
const titleStyle = {
|
|
2078
|
+
fontSize: "16px",
|
|
2079
|
+
fontWeight: 600,
|
|
2080
|
+
color: "#1f2937",
|
|
2081
|
+
margin: 0
|
|
2082
|
+
};
|
|
2083
|
+
const previewContainerStyle = {
|
|
2084
|
+
height: "600px",
|
|
2085
|
+
display: "flex",
|
|
2086
|
+
flexDirection: "column",
|
|
2087
|
+
background: "#f3f4f6"
|
|
2088
|
+
};
|
|
2089
|
+
const errorStyle = {
|
|
2090
|
+
padding: "2rem",
|
|
2091
|
+
textAlign: "center"
|
|
2092
|
+
};
|
|
2093
|
+
const toggleButtonStyle = {
|
|
2094
|
+
padding: "0.5rem 1rem",
|
|
2095
|
+
background: showPreview ? "#ef4444" : "#3b82f6",
|
|
2096
|
+
color: "white",
|
|
2097
|
+
border: "none",
|
|
2098
|
+
borderRadius: "4px",
|
|
2099
|
+
cursor: "pointer",
|
|
2100
|
+
fontSize: "14px",
|
|
2101
|
+
fontWeight: 500
|
|
2102
|
+
};
|
|
2103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: containerStyle, children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: headerStyle, children: [
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { style: titleStyle, children: "Email Preview" }),
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2107
|
+
"button",
|
|
2108
|
+
{
|
|
2109
|
+
onClick: () => showPreview ? setShowPreview(false) : updatePreview(),
|
|
2110
|
+
style: toggleButtonStyle,
|
|
2111
|
+
disabled: isLoading,
|
|
2112
|
+
children: isLoading ? "Loading..." : showPreview ? "Hide Preview" : "Show Preview"
|
|
2113
|
+
}
|
|
2114
|
+
)
|
|
2115
|
+
] }),
|
|
2116
|
+
showPreview && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: previewContainerStyle, children: error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: errorStyle, children: [
|
|
2117
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: error.message }),
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2119
|
+
"button",
|
|
2120
|
+
{
|
|
2121
|
+
onClick: updatePreview,
|
|
2122
|
+
style: {
|
|
2123
|
+
padding: "0.5rem 1rem",
|
|
2124
|
+
background: "#3b82f6",
|
|
2125
|
+
color: "white",
|
|
2126
|
+
border: "none",
|
|
2127
|
+
borderRadius: "4px",
|
|
2128
|
+
cursor: "pointer"
|
|
2129
|
+
},
|
|
2130
|
+
children: "Retry"
|
|
2131
|
+
}
|
|
2132
|
+
)
|
|
2133
|
+
] }) : previewData ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2135
|
+
PreviewControls,
|
|
2136
|
+
{
|
|
2137
|
+
onUpdate: updatePreview,
|
|
2138
|
+
device,
|
|
2139
|
+
onDeviceChange: setDevice,
|
|
2140
|
+
isLoading
|
|
2141
|
+
}
|
|
2142
|
+
),
|
|
2143
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "2rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2144
|
+
EmailRenderer,
|
|
2145
|
+
{
|
|
2146
|
+
template: previewData.template,
|
|
2147
|
+
data: previewData.data,
|
|
2148
|
+
device
|
|
2149
|
+
}
|
|
2150
|
+
) })
|
|
2151
|
+
] }) : null })
|
|
2152
|
+
] });
|
|
2153
|
+
};
|
|
2154
|
+
|
|
2155
|
+
// src/components/Broadcasts/BroadcastPreviewField.tsx
|
|
2156
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2157
|
+
var BroadcastPreviewField = () => {
|
|
2158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: {
|
|
2159
|
+
padding: "1rem",
|
|
2160
|
+
background: "#f9fafb",
|
|
2161
|
+
borderRadius: "4px",
|
|
2162
|
+
fontSize: "14px",
|
|
2163
|
+
color: "#6b7280"
|
|
2164
|
+
}, children: "Email preview is available inline below the content editor." });
|
|
2165
|
+
};
|
|
1729
2166
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1730
2167
|
0 && (module.exports = {
|
|
1731
2168
|
BroadcastEditor,
|
|
2169
|
+
BroadcastInlinePreview,
|
|
2170
|
+
BroadcastPreviewField,
|
|
2171
|
+
DefaultBroadcastTemplate,
|
|
1732
2172
|
EmailPreview,
|
|
1733
2173
|
EmailPreviewField,
|
|
2174
|
+
EmailRenderer,
|
|
1734
2175
|
MagicLinkVerify,
|
|
1735
2176
|
NewsletterForm,
|
|
1736
2177
|
PreferencesForm,
|
|
2178
|
+
PreviewControls,
|
|
1737
2179
|
createMagicLinkVerify,
|
|
1738
2180
|
createNewsletterForm,
|
|
1739
2181
|
createPreferencesForm,
|