brookmind-emails 0.1.7
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/.prettierrc +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/modelfy/config.d.ts +7 -0
- package/dist/modelfy/config.d.ts.map +1 -0
- package/dist/modelfy/config.js +6 -0
- package/dist/modelfy/index.d.ts +14 -0
- package/dist/modelfy/index.d.ts.map +1 -0
- package/dist/modelfy/index.js +33 -0
- package/dist/modelfy/templates/GrantCreditsEmail.d.ts +10 -0
- package/dist/modelfy/templates/GrantCreditsEmail.d.ts.map +1 -0
- package/dist/modelfy/templates/GrantCreditsEmail.js +101 -0
- package/dist/modelfy/templates/OtpEmail.d.ts +8 -0
- package/dist/modelfy/templates/OtpEmail.d.ts.map +1 -0
- package/dist/modelfy/templates/OtpEmail.js +66 -0
- package/dist/modelfy/templates/PromoSubscriptionEmail.d.ts +11 -0
- package/dist/modelfy/templates/PromoSubscriptionEmail.d.ts.map +1 -0
- package/dist/modelfy/templates/PromoSubscriptionEmail.js +83 -0
- package/dist/modelfy/templates/index.d.ts +4 -0
- package/dist/modelfy/templates/index.d.ts.map +1 -0
- package/dist/modelfy/templates/index.js +3 -0
- package/dist/shared/components/Button.d.ts +7 -0
- package/dist/shared/components/Button.d.ts.map +1 -0
- package/dist/shared/components/Button.js +27 -0
- package/dist/shared/components/Footer.d.ts +8 -0
- package/dist/shared/components/Footer.d.ts.map +1 -0
- package/dist/shared/components/Footer.js +28 -0
- package/dist/shared/components/Header.d.ts +7 -0
- package/dist/shared/components/Header.d.ts.map +1 -0
- package/dist/shared/components/Header.js +40 -0
- package/dist/shared/components/index.d.ts +4 -0
- package/dist/shared/components/index.d.ts.map +1 -0
- package/dist/shared/components/index.js +3 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +1 -0
- package/package.json +40 -0
- package/src/index.ts +5 -0
- package/src/modelfy/config.ts +6 -0
- package/src/modelfy/index.ts +57 -0
- package/src/modelfy/templates/GrantCreditsEmail.tsx +205 -0
- package/src/modelfy/templates/OtpEmail.tsx +128 -0
- package/src/modelfy/templates/PromoSubscriptionEmail.tsx +189 -0
- package/src/modelfy/templates/index.ts +3 -0
- package/src/shared/components/Button.tsx +39 -0
- package/src/shared/components/Footer.tsx +63 -0
- package/src/shared/components/Header.tsx +56 -0
- package/src/shared/components/index.ts +3 -0
- package/src/shared/index.ts +1 -0
- package/tsconfig.json +22 -0
package/.prettierrc
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAGlC,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/modelfy/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;CAKzB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OtpEmail, type OtpEmailProps } from "./templates/OtpEmail.js";
|
|
2
|
+
import { PromoSubscriptionEmail, type PromoSubscriptionEmailProps } from "./templates/PromoSubscriptionEmail.js";
|
|
3
|
+
import { GrantCreditsEmail, type GrantCreditsEmailProps } from "./templates/GrantCreditsEmail.js";
|
|
4
|
+
export type { OtpEmailProps, PromoSubscriptionEmailProps, GrantCreditsEmailProps };
|
|
5
|
+
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail };
|
|
6
|
+
export interface RenderResult {
|
|
7
|
+
subject: string;
|
|
8
|
+
html: string;
|
|
9
|
+
text: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function renderOtpEmail(props: OtpEmailProps): Promise<RenderResult>;
|
|
12
|
+
export declare function renderPromoSubscriptionEmail(props: PromoSubscriptionEmailProps): Promise<RenderResult>;
|
|
13
|
+
export declare function renderGrantCreditsEmail(props: GrantCreditsEmailProps): Promise<RenderResult>;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modelfy/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EACL,sBAAsB,EACtB,KAAK,2BAA2B,EACjC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAGlG,YAAY,EAAE,aAAa,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,CAAC;AAGnF,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,CAAC;AAG/D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAShF;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,YAAY,CAAC,CASvB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,YAAY,CAAC,CASvB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { render } from "@react-email/render";
|
|
2
|
+
import { OtpEmail } from "./templates/OtpEmail.js";
|
|
3
|
+
import { PromoSubscriptionEmail, } from "./templates/PromoSubscriptionEmail.js";
|
|
4
|
+
import { GrantCreditsEmail } from "./templates/GrantCreditsEmail.js";
|
|
5
|
+
// Re-export components for preview
|
|
6
|
+
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail };
|
|
7
|
+
export async function renderOtpEmail(props) {
|
|
8
|
+
const html = await render(OtpEmail(props));
|
|
9
|
+
const text = await render(OtpEmail(props), { plainText: true });
|
|
10
|
+
return {
|
|
11
|
+
subject: "Your Modelfy access code",
|
|
12
|
+
html,
|
|
13
|
+
text,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export async function renderPromoSubscriptionEmail(props) {
|
|
17
|
+
const html = await render(PromoSubscriptionEmail(props));
|
|
18
|
+
const text = await render(PromoSubscriptionEmail(props), { plainText: true });
|
|
19
|
+
return {
|
|
20
|
+
subject: `You've received a ${props.durationDays}-day ${props.planName} subscription!`,
|
|
21
|
+
html,
|
|
22
|
+
text,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export async function renderGrantCreditsEmail(props) {
|
|
26
|
+
const html = await render(GrantCreditsEmail(props));
|
|
27
|
+
const text = await render(GrantCreditsEmail(props), { plainText: true });
|
|
28
|
+
return {
|
|
29
|
+
subject: `You've received ${(props.credits ?? 0).toLocaleString()} credits on Modelfy!`,
|
|
30
|
+
html,
|
|
31
|
+
text,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface GrantCreditsEmailProps {
|
|
2
|
+
email: string;
|
|
3
|
+
credits?: number;
|
|
4
|
+
durationDays: number;
|
|
5
|
+
expiresAt: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function GrantCreditsEmail({ email, credits, durationDays, expiresAt, description, }: GrantCreditsEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default GrantCreditsEmail;
|
|
10
|
+
//# sourceMappingURL=GrantCreditsEmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrantCreditsEmail.d.ts","sourceRoot":"","sources":["../../../src/modelfy/templates/GrantCreditsEmail.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA4FD,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,OAAO,EACP,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,EAAE,sBAAsB,2CAoFxB;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Html, Head, Body, Container, Section, Text, Link, Preview, Font, } from "@react-email/components";
|
|
3
|
+
import { Header, Footer, Button } from "../../shared/components/index.js";
|
|
4
|
+
import { modelfyConfig } from "../config.js";
|
|
5
|
+
const styles = {
|
|
6
|
+
body: {
|
|
7
|
+
margin: 0,
|
|
8
|
+
padding: 0,
|
|
9
|
+
backgroundColor: "#F8FAFC",
|
|
10
|
+
fontFamily: "'Outfit', Arial, sans-serif",
|
|
11
|
+
},
|
|
12
|
+
container: {
|
|
13
|
+
maxWidth: "560px",
|
|
14
|
+
margin: "32px auto",
|
|
15
|
+
backgroundColor: "#ffffff",
|
|
16
|
+
border: "1px solid #E2E8F0",
|
|
17
|
+
borderRadius: "16px",
|
|
18
|
+
boxShadow: "0 24px 48px rgba(15, 23, 42, 0.08)",
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
},
|
|
21
|
+
content: {
|
|
22
|
+
padding: "32px 40px 24px",
|
|
23
|
+
},
|
|
24
|
+
heading: {
|
|
25
|
+
margin: "0 0 16px",
|
|
26
|
+
fontSize: "24px",
|
|
27
|
+
fontWeight: 700,
|
|
28
|
+
color: "#0F172A",
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
},
|
|
31
|
+
paragraph: {
|
|
32
|
+
margin: "0 0 24px",
|
|
33
|
+
fontSize: "16px",
|
|
34
|
+
lineHeight: "1.6",
|
|
35
|
+
color: "rgba(15, 23, 42, 0.72)",
|
|
36
|
+
},
|
|
37
|
+
creditBox: {
|
|
38
|
+
backgroundColor: "rgba(34, 197, 94, 0.08)",
|
|
39
|
+
border: "1px solid rgba(34, 197, 94, 0.24)",
|
|
40
|
+
borderRadius: "12px",
|
|
41
|
+
padding: "24px",
|
|
42
|
+
marginBottom: "24px",
|
|
43
|
+
textAlign: "center",
|
|
44
|
+
},
|
|
45
|
+
creditAmount: {
|
|
46
|
+
fontSize: "48px",
|
|
47
|
+
fontWeight: 700,
|
|
48
|
+
color: "#16A34A",
|
|
49
|
+
margin: "0 0 8px",
|
|
50
|
+
},
|
|
51
|
+
creditLabel: {
|
|
52
|
+
fontSize: "16px",
|
|
53
|
+
color: "rgba(15, 23, 42, 0.6)",
|
|
54
|
+
margin: 0,
|
|
55
|
+
},
|
|
56
|
+
detailsBox: {
|
|
57
|
+
backgroundColor: "#F8FAFC",
|
|
58
|
+
borderRadius: "8px",
|
|
59
|
+
padding: "16px",
|
|
60
|
+
marginBottom: "24px",
|
|
61
|
+
},
|
|
62
|
+
detailRow: {
|
|
63
|
+
display: "flex",
|
|
64
|
+
justifyContent: "space-between",
|
|
65
|
+
marginBottom: "8px",
|
|
66
|
+
},
|
|
67
|
+
detailLabel: {
|
|
68
|
+
fontSize: "14px",
|
|
69
|
+
color: "rgba(15, 23, 42, 0.6)",
|
|
70
|
+
margin: 0,
|
|
71
|
+
},
|
|
72
|
+
detailValue: {
|
|
73
|
+
fontSize: "14px",
|
|
74
|
+
fontWeight: 600,
|
|
75
|
+
color: "#0F172A",
|
|
76
|
+
margin: 0,
|
|
77
|
+
},
|
|
78
|
+
buttonContainer: {
|
|
79
|
+
textAlign: "center",
|
|
80
|
+
marginBottom: "24px",
|
|
81
|
+
},
|
|
82
|
+
smallText: {
|
|
83
|
+
margin: "0 0 12px",
|
|
84
|
+
fontSize: "14px",
|
|
85
|
+
lineHeight: "1.6",
|
|
86
|
+
color: "rgba(15, 23, 42, 0.6)",
|
|
87
|
+
},
|
|
88
|
+
link: {
|
|
89
|
+
color: "#6366F1",
|
|
90
|
+
textDecoration: "none",
|
|
91
|
+
fontWeight: 600,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
export function GrantCreditsEmail({ email, credits, durationDays, expiresAt, description, }) {
|
|
95
|
+
const safeCredits = Number.isFinite(credits) ? Number(credits) : 0;
|
|
96
|
+
return (_jsxs(Html, { lang: "en", children: [_jsx(Head, { children: _jsx(Font, { fontFamily: "Outfit", fallbackFontFamily: "Arial", webFont: {
|
|
97
|
+
url: "https://fonts.gstatic.com/s/outfit/v11/QGYyz_MVcBeNP4NjuGObqx1XmO1I4TC1C4G-EiAou6Y.woff2",
|
|
98
|
+
format: "woff2",
|
|
99
|
+
}, fontWeight: 400, fontStyle: "normal" }) }), _jsxs(Preview, { children: ["You've received ", safeCredits.toLocaleString(), " credits on Modelfy!"] }), _jsx(Body, { style: styles.body, children: _jsxs(Container, { style: styles.container, children: [_jsx(Header, { logoUrl: modelfyConfig.logoUrl, logoAlt: "Modelfy", subtitle: "Credits added" }), _jsxs(Section, { style: styles.content, children: [_jsx(Text, { style: styles.heading, children: "Credits Added to Your Account!" }), _jsxs(Text, { style: styles.paragraph, children: ["Hi ", _jsx("strong", { children: email }), ", you've received bonus credits to use on Modelfy."] }), _jsxs("div", { style: styles.creditBox, children: [_jsxs(Text, { style: styles.creditAmount, children: ["+", safeCredits.toLocaleString()] }), _jsx(Text, { style: styles.creditLabel, children: "credits" })] }), _jsx("div", { style: styles.detailsBox, children: _jsxs("table", { width: "100%", cellPadding: 0, cellSpacing: 0, children: [_jsxs("tr", { children: [_jsx("td", { style: { paddingBottom: "8px" }, children: _jsx(Text, { style: styles.detailLabel, children: "Valid for" }) }), _jsx("td", { style: { paddingBottom: "8px", textAlign: "right" }, children: _jsxs(Text, { style: styles.detailValue, children: [durationDays, " days"] }) })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx(Text, { style: styles.detailLabel, children: "Expires" }) }), _jsx("td", { style: { textAlign: "right" }, children: _jsx(Text, { style: styles.detailValue, children: expiresAt }) })] })] }) }), description && (_jsx(Text, { style: styles.paragraph, children: _jsxs("em", { children: ["\"", description, "\""] }) })), _jsx("div", { style: styles.buttonContainer, children: _jsx(Button, { href: modelfyConfig.appUrl, children: "Start Creating" }) }), _jsxs(Text, { style: styles.smallText, children: ["These credits will be used before your regular credits and expire on ", expiresAt, "."] }), _jsxs(Text, { style: styles.smallText, children: ["Questions? Contact us at", " ", _jsx(Link, { href: `mailto:${modelfyConfig.supportEmail}`, style: styles.link, children: modelfyConfig.supportEmail })] })] }), _jsx(Footer, { companyName: modelfyConfig.companyName, message: "You received this email because credits were added to your Modelfy account.", supportEmail: modelfyConfig.supportEmail })] }) })] }));
|
|
100
|
+
}
|
|
101
|
+
export default GrantCreditsEmail;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface OtpEmailProps {
|
|
2
|
+
otp: string;
|
|
3
|
+
email: string;
|
|
4
|
+
expirationMinutes?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function OtpEmail({ otp, email, expirationMinutes }: OtpEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default OtpEmail;
|
|
8
|
+
//# sourceMappingURL=OtpEmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OtpEmail.d.ts","sourceRoot":"","sources":["../../../src/modelfy/templates/OtpEmail.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAuDD,wBAAgB,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAsB,EAAE,EAAE,aAAa,2CAoD7E;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Html, Head, Body, Container, Section, Text, Link, Preview, Font, } from "@react-email/components";
|
|
3
|
+
import { Header, Footer } from "../../shared/components/index.js";
|
|
4
|
+
import { modelfyConfig } from "../config.js";
|
|
5
|
+
const styles = {
|
|
6
|
+
body: {
|
|
7
|
+
margin: 0,
|
|
8
|
+
padding: 0,
|
|
9
|
+
backgroundColor: "#F8FAFC",
|
|
10
|
+
fontFamily: "'Outfit', Arial, sans-serif",
|
|
11
|
+
},
|
|
12
|
+
container: {
|
|
13
|
+
maxWidth: "560px",
|
|
14
|
+
margin: "32px auto",
|
|
15
|
+
backgroundColor: "#ffffff",
|
|
16
|
+
border: "1px solid #E2E8F0",
|
|
17
|
+
borderRadius: "16px",
|
|
18
|
+
boxShadow: "0 24px 48px rgba(15, 23, 42, 0.08)",
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
},
|
|
21
|
+
content: {
|
|
22
|
+
padding: "32px 40px 24px",
|
|
23
|
+
},
|
|
24
|
+
paragraph: {
|
|
25
|
+
margin: "16px 0 24px",
|
|
26
|
+
fontSize: "16px",
|
|
27
|
+
lineHeight: "1.6",
|
|
28
|
+
color: "rgba(15, 23, 42, 0.72)",
|
|
29
|
+
},
|
|
30
|
+
otpContainer: {
|
|
31
|
+
display: "inline-block",
|
|
32
|
+
backgroundColor: "rgba(99, 102, 241, 0.08)",
|
|
33
|
+
border: "1px solid rgba(99, 102, 241, 0.24)",
|
|
34
|
+
borderRadius: "12px",
|
|
35
|
+
padding: "20px 32px",
|
|
36
|
+
marginBottom: "24px",
|
|
37
|
+
},
|
|
38
|
+
otp: {
|
|
39
|
+
fontSize: "32px",
|
|
40
|
+
letterSpacing: "8px",
|
|
41
|
+
fontWeight: 700,
|
|
42
|
+
color: "#0F172A",
|
|
43
|
+
margin: 0,
|
|
44
|
+
},
|
|
45
|
+
smallText: {
|
|
46
|
+
margin: "0 0 12px",
|
|
47
|
+
fontSize: "15px",
|
|
48
|
+
lineHeight: "1.6",
|
|
49
|
+
color: "rgba(15, 23, 42, 0.72)",
|
|
50
|
+
},
|
|
51
|
+
link: {
|
|
52
|
+
color: "#0F172A",
|
|
53
|
+
textDecoration: "none",
|
|
54
|
+
fontWeight: 600,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
export function OtpEmail({ otp, email, expirationMinutes = 10 }) {
|
|
58
|
+
const sanitizedOtp = (typeof otp === "string" ? otp : String(otp ?? ""))
|
|
59
|
+
.replace(/\s+/g, "")
|
|
60
|
+
.trim();
|
|
61
|
+
return (_jsxs(Html, { lang: "en", children: [_jsx(Head, { children: _jsx(Font, { fontFamily: "Outfit", fallbackFontFamily: "Arial", webFont: {
|
|
62
|
+
url: "https://fonts.gstatic.com/s/outfit/v11/QGYyz_MVcBeNP4NjuGObqx1XmO1I4TC1C4G-EiAou6Y.woff2",
|
|
63
|
+
format: "woff2",
|
|
64
|
+
}, fontWeight: 400, fontStyle: "normal" }) }), _jsxs(Preview, { children: ["Your Modelfy access code: ", sanitizedOtp] }), _jsx(Body, { style: styles.body, children: _jsxs(Container, { style: styles.container, children: [_jsx(Header, { logoUrl: modelfyConfig.logoUrl, logoAlt: "Modelfy", subtitle: "Access code" }), _jsxs(Section, { style: styles.content, children: [_jsxs(Text, { style: styles.paragraph, children: ["Hi ", _jsx("strong", { children: email }), ", use the code below to sign in. It will stay valid for the next ", _jsxs("strong", { children: [expirationMinutes, " minutes"] }), "."] }), _jsx("div", { style: styles.otpContainer, children: _jsx(Text, { style: styles.otp, children: sanitizedOtp }) }), _jsx(Text, { style: styles.smallText, children: "If you didn't request this code, you can safely ignore this email. No one else can access your account without it." }), _jsxs(Text, { style: styles.smallText, children: ["Need a hand? Reach us anytime at", " ", _jsx(Link, { href: `mailto:${modelfyConfig.supportEmail}`, style: styles.link, children: modelfyConfig.supportEmail }), "."] })] }), _jsx(Footer, { companyName: modelfyConfig.companyName, message: "You received this email because someone attempted to sign in to Modelfy with this address.", supportEmail: modelfyConfig.supportEmail })] }) })] }));
|
|
65
|
+
}
|
|
66
|
+
export default OtpEmail;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface PromoSubscriptionEmailProps {
|
|
2
|
+
email: string;
|
|
3
|
+
planName: string;
|
|
4
|
+
durationDays: number;
|
|
5
|
+
credits?: number;
|
|
6
|
+
expiresAt: string;
|
|
7
|
+
notes?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function PromoSubscriptionEmail({ email, planName, durationDays, credits, expiresAt, notes, }: PromoSubscriptionEmailProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default PromoSubscriptionEmail;
|
|
11
|
+
//# sourceMappingURL=PromoSubscriptionEmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromoSubscriptionEmail.d.ts","sourceRoot":"","sources":["../../../src/modelfy/templates/PromoSubscriptionEmail.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0ED,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,SAAS,EACT,KAAK,GACN,EAAE,2BAA2B,2CAoF7B;AAED,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Html, Head, Body, Container, Section, Text, Link, Preview, Font, } from "@react-email/components";
|
|
3
|
+
import { Header, Footer, Button } from "../../shared/components/index.js";
|
|
4
|
+
import { modelfyConfig } from "../config.js";
|
|
5
|
+
const styles = {
|
|
6
|
+
body: {
|
|
7
|
+
margin: 0,
|
|
8
|
+
padding: 0,
|
|
9
|
+
backgroundColor: "#F8FAFC",
|
|
10
|
+
fontFamily: "'Outfit', Arial, sans-serif",
|
|
11
|
+
},
|
|
12
|
+
container: {
|
|
13
|
+
maxWidth: "560px",
|
|
14
|
+
margin: "32px auto",
|
|
15
|
+
backgroundColor: "#ffffff",
|
|
16
|
+
border: "1px solid #E2E8F0",
|
|
17
|
+
borderRadius: "16px",
|
|
18
|
+
boxShadow: "0 24px 48px rgba(15, 23, 42, 0.08)",
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
},
|
|
21
|
+
content: {
|
|
22
|
+
padding: "32px 40px 24px",
|
|
23
|
+
},
|
|
24
|
+
heading: {
|
|
25
|
+
margin: "0 0 16px",
|
|
26
|
+
fontSize: "24px",
|
|
27
|
+
fontWeight: 700,
|
|
28
|
+
color: "#0F172A",
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
},
|
|
31
|
+
paragraph: {
|
|
32
|
+
margin: "0 0 24px",
|
|
33
|
+
fontSize: "16px",
|
|
34
|
+
lineHeight: "1.6",
|
|
35
|
+
color: "rgba(15, 23, 42, 0.72)",
|
|
36
|
+
},
|
|
37
|
+
highlightBox: {
|
|
38
|
+
backgroundColor: "rgba(99, 102, 241, 0.08)",
|
|
39
|
+
border: "1px solid rgba(99, 102, 241, 0.24)",
|
|
40
|
+
borderRadius: "12px",
|
|
41
|
+
padding: "24px",
|
|
42
|
+
marginBottom: "24px",
|
|
43
|
+
},
|
|
44
|
+
highlightRow: {
|
|
45
|
+
display: "flex",
|
|
46
|
+
justifyContent: "space-between",
|
|
47
|
+
marginBottom: "12px",
|
|
48
|
+
},
|
|
49
|
+
highlightLabel: {
|
|
50
|
+
fontSize: "14px",
|
|
51
|
+
color: "rgba(15, 23, 42, 0.6)",
|
|
52
|
+
margin: 0,
|
|
53
|
+
},
|
|
54
|
+
highlightValue: {
|
|
55
|
+
fontSize: "16px",
|
|
56
|
+
fontWeight: 600,
|
|
57
|
+
color: "#0F172A",
|
|
58
|
+
margin: 0,
|
|
59
|
+
},
|
|
60
|
+
buttonContainer: {
|
|
61
|
+
textAlign: "center",
|
|
62
|
+
marginBottom: "24px",
|
|
63
|
+
},
|
|
64
|
+
smallText: {
|
|
65
|
+
margin: "0 0 12px",
|
|
66
|
+
fontSize: "14px",
|
|
67
|
+
lineHeight: "1.6",
|
|
68
|
+
color: "rgba(15, 23, 42, 0.6)",
|
|
69
|
+
},
|
|
70
|
+
link: {
|
|
71
|
+
color: "#6366F1",
|
|
72
|
+
textDecoration: "none",
|
|
73
|
+
fontWeight: 600,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
export function PromoSubscriptionEmail({ email, planName, durationDays, credits, expiresAt, notes, }) {
|
|
77
|
+
const safeCredits = Number.isFinite(credits) ? Number(credits) : 0;
|
|
78
|
+
return (_jsxs(Html, { lang: "en", children: [_jsx(Head, { children: _jsx(Font, { fontFamily: "Outfit", fallbackFontFamily: "Arial", webFont: {
|
|
79
|
+
url: "https://fonts.gstatic.com/s/outfit/v11/QGYyz_MVcBeNP4NjuGObqx1XmO1I4TC1C4G-EiAou6Y.woff2",
|
|
80
|
+
format: "woff2",
|
|
81
|
+
}, fontWeight: 400, fontStyle: "normal" }) }), _jsx(Preview, { children: `You've received a ${durationDays}-day ${planName} subscription!` }), _jsx(Body, { style: styles.body, children: _jsxs(Container, { style: styles.container, children: [_jsx(Header, { logoUrl: modelfyConfig.logoUrl, logoAlt: "Modelfy", subtitle: "Gift for you" }), _jsxs(Section, { style: styles.content, children: [_jsx(Text, { style: styles.heading, children: "You've Got a Gift!" }), _jsxs(Text, { style: styles.paragraph, children: ["Hi ", _jsx("strong", { children: email }), ", great news! You've been granted a promotional", " ", _jsx("strong", { children: planName }), " subscription."] }), _jsx("div", { style: styles.highlightBox, children: _jsxs("table", { width: "100%", cellPadding: 0, cellSpacing: 0, children: [_jsxs("tr", { children: [_jsxs("td", { style: { paddingBottom: "12px" }, children: [_jsx(Text, { style: styles.highlightLabel, children: "Plan" }), _jsx(Text, { style: styles.highlightValue, children: planName })] }), _jsxs("td", { style: { paddingBottom: "12px", textAlign: "right" }, children: [_jsx(Text, { style: styles.highlightLabel, children: "Duration" }), _jsxs(Text, { style: styles.highlightValue, children: [durationDays, " days"] })] })] }), _jsxs("tr", { children: [_jsxs("td", { children: [_jsx(Text, { style: styles.highlightLabel, children: "Credits Included" }), _jsx(Text, { style: styles.highlightValue, children: safeCredits.toLocaleString() })] }), _jsxs("td", { style: { textAlign: "right" }, children: [_jsx(Text, { style: styles.highlightLabel, children: "Expires" }), _jsx(Text, { style: styles.highlightValue, children: expiresAt })] })] })] }) }), notes && (_jsx(Text, { style: styles.paragraph, children: _jsxs("em", { children: ["\"", notes, "\""] }) })), _jsx("div", { style: styles.buttonContainer, children: _jsx(Button, { href: modelfyConfig.appUrl, children: "Open Modelfy" }) }), _jsx(Text, { style: styles.smallText, children: "This promotional subscription will not auto-renew. Enjoy your free access!" }), _jsxs(Text, { style: styles.smallText, children: ["Questions? Contact us at", " ", _jsx(Link, { href: `mailto:${modelfyConfig.supportEmail}`, style: styles.link, children: modelfyConfig.supportEmail })] })] }), _jsx(Footer, { companyName: modelfyConfig.companyName, message: "You received this email because you were granted a promotional subscription.", supportEmail: modelfyConfig.supportEmail })] }) })] }));
|
|
82
|
+
}
|
|
83
|
+
export default PromoSubscriptionEmail;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { OtpEmail, type OtpEmailProps } from "./OtpEmail.js";
|
|
2
|
+
export { PromoSubscriptionEmail, type PromoSubscriptionEmailProps } from "./PromoSubscriptionEmail.js";
|
|
3
|
+
export { GrantCreditsEmail, type GrantCreditsEmailProps } from "./GrantCreditsEmail.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modelfy/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,KAAK,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ButtonProps {
|
|
2
|
+
href: string;
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
variant?: "primary" | "secondary";
|
|
5
|
+
}
|
|
6
|
+
export declare function Button({ href, children, variant }: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/shared/components/Button.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;CACnC;AA0BD,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAmB,EAAE,EAAE,WAAW,2CAM1E"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Button as ReactEmailButton } from "@react-email/components";
|
|
3
|
+
const baseStyles = {
|
|
4
|
+
display: "inline-block",
|
|
5
|
+
padding: "14px 28px",
|
|
6
|
+
fontSize: "16px",
|
|
7
|
+
fontWeight: 600,
|
|
8
|
+
textDecoration: "none",
|
|
9
|
+
borderRadius: "8px",
|
|
10
|
+
textAlign: "center",
|
|
11
|
+
};
|
|
12
|
+
const variants = {
|
|
13
|
+
primary: {
|
|
14
|
+
...baseStyles,
|
|
15
|
+
backgroundColor: "#18181B",
|
|
16
|
+
color: "#ffffff",
|
|
17
|
+
},
|
|
18
|
+
secondary: {
|
|
19
|
+
...baseStyles,
|
|
20
|
+
backgroundColor: "transparent",
|
|
21
|
+
color: "#18181B",
|
|
22
|
+
border: "2px solid #18181B",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export function Button({ href, children, variant = "primary" }) {
|
|
26
|
+
return (_jsx(ReactEmailButton, { href: href, style: variants[variant], children: children }));
|
|
27
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface FooterProps {
|
|
2
|
+
companyName: string;
|
|
3
|
+
year?: number;
|
|
4
|
+
message?: string;
|
|
5
|
+
supportEmail?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function Footer({ companyName, year, message, supportEmail, }: FooterProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=Footer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../src/shared/components/Footer.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA0BD,wBAAgB,MAAM,CAAC,EACrB,WAAW,EACX,IAA+B,EAC/B,OAAO,EACP,YAAY,GACb,EAAE,WAAW,2CAwBb"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Section, Text, Link } from "@react-email/components";
|
|
3
|
+
const styles = {
|
|
4
|
+
footer: {
|
|
5
|
+
padding: "20px 40px",
|
|
6
|
+
backgroundColor: "#F1F5F9",
|
|
7
|
+
borderTop: "1px solid rgba(148, 163, 184, 0.2)",
|
|
8
|
+
},
|
|
9
|
+
text: {
|
|
10
|
+
margin: 0,
|
|
11
|
+
fontSize: "13px",
|
|
12
|
+
lineHeight: "1.6",
|
|
13
|
+
color: "rgba(15, 23, 42, 0.72)",
|
|
14
|
+
},
|
|
15
|
+
noReplyText: {
|
|
16
|
+
margin: "12px 0 0",
|
|
17
|
+
fontSize: "12px",
|
|
18
|
+
lineHeight: "1.5",
|
|
19
|
+
color: "rgba(15, 23, 42, 0.5)",
|
|
20
|
+
},
|
|
21
|
+
link: {
|
|
22
|
+
color: "#6366F1",
|
|
23
|
+
textDecoration: "none",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export function Footer({ companyName, year = new Date().getFullYear(), message, supportEmail, }) {
|
|
27
|
+
return (_jsxs(Section, { style: styles.footer, children: [_jsxs(Text, { style: styles.text, children: ["\u00A9 ", year, " ", companyName, ". All rights reserved.", message && (_jsxs(_Fragment, { children: [_jsx("br", {}), message] }))] }), supportEmail && (_jsxs(Text, { style: styles.noReplyText, children: ["This is an automated message. Please do not reply to this email. For any questions, contact us at", " ", _jsx(Link, { href: `mailto:${supportEmail}`, style: styles.link, children: supportEmail }), "."] }))] }));
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../src/shared/components/Header.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAsCD,wBAAgB,MAAM,CAAC,EAAE,OAAO,EAAE,OAAgB,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAW1E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Section, Img, Text } from "@react-email/components";
|
|
3
|
+
const styles = {
|
|
4
|
+
header: {
|
|
5
|
+
backgroundColor: "#000000",
|
|
6
|
+
padding: "32px 40px",
|
|
7
|
+
borderBottom: "1px solid rgba(148, 163, 184, 0.15)",
|
|
8
|
+
},
|
|
9
|
+
logoContainer: {
|
|
10
|
+
display: "flex",
|
|
11
|
+
flexDirection: "column",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
justifyContent: "center",
|
|
14
|
+
gap: "18px",
|
|
15
|
+
textAlign: "center",
|
|
16
|
+
},
|
|
17
|
+
logoWrapper: {
|
|
18
|
+
display: "flex",
|
|
19
|
+
alignItems: "center",
|
|
20
|
+
justifyContent: "center",
|
|
21
|
+
backgroundColor: "#000",
|
|
22
|
+
borderRadius: "18px",
|
|
23
|
+
padding: "16px 24px",
|
|
24
|
+
},
|
|
25
|
+
logo: {
|
|
26
|
+
display: "block",
|
|
27
|
+
maxWidth: "100%",
|
|
28
|
+
},
|
|
29
|
+
subtitle: {
|
|
30
|
+
fontSize: "16px",
|
|
31
|
+
color: "rgba(255,255,255,0.8)",
|
|
32
|
+
letterSpacing: "4px",
|
|
33
|
+
textTransform: "uppercase",
|
|
34
|
+
fontWeight: 500,
|
|
35
|
+
margin: 0,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
export function Header({ logoUrl, logoAlt = "Logo", subtitle }) {
|
|
39
|
+
return (_jsx(Section, { style: styles.header, children: _jsxs("div", { style: styles.logoContainer, children: [_jsx("div", { style: styles.logoWrapper, children: _jsx(Img, { src: logoUrl, width: "150", height: "auto", alt: logoAlt, style: styles.logo }) }), subtitle && _jsx(Text, { style: styles.subtitle, children: subtitle })] }) }));
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./components/index.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "brookmind-emails",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"description": "Email templates for Brookmind projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./modelfy": {
|
|
14
|
+
"import": "./dist/modelfy/index.js",
|
|
15
|
+
"types": "./dist/modelfy/index.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"dev": "email dev --dir src/modelfy/templates",
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepare": "npm run build",
|
|
22
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
23
|
+
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@react-email/components": "^0.0.31",
|
|
27
|
+
"@react-email/render": "^1.0.3",
|
|
28
|
+
"react": "^19.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^22.10.2",
|
|
32
|
+
"@types/react": "^19.0.1",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
34
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
35
|
+
"eslint": "^9.16.0",
|
|
36
|
+
"prettier": "^3.4.2",
|
|
37
|
+
"react-email": "^3.0.4",
|
|
38
|
+
"typescript": "^5.7.2"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/index.ts
ADDED