brookmind-emails 0.1.11 → 0.1.13
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/foodstudio/config.d.ts +11 -0
- package/dist/foodstudio/config.d.ts.map +1 -0
- package/dist/foodstudio/config.js +12 -0
- package/dist/foodstudio/index.d.ts +16 -0
- package/dist/foodstudio/index.d.ts.map +1 -0
- package/dist/foodstudio/index.js +43 -0
- package/dist/foodstudio/templates/GrantCreditsEmail.d.ts +10 -0
- package/dist/foodstudio/templates/GrantCreditsEmail.d.ts.map +1 -0
- package/dist/foodstudio/templates/GrantCreditsEmail.js +188 -0
- package/dist/foodstudio/templates/OtpEmail.d.ts +8 -0
- package/dist/foodstudio/templates/OtpEmail.d.ts.map +1 -0
- package/dist/foodstudio/templates/OtpEmail.js +144 -0
- package/dist/foodstudio/templates/PromoSubscriptionEmail.d.ts +11 -0
- package/dist/foodstudio/templates/PromoSubscriptionEmail.d.ts.map +1 -0
- package/dist/foodstudio/templates/PromoSubscriptionEmail.js +170 -0
- package/dist/foodstudio/templates/WelcomeEmail.d.ts +6 -0
- package/dist/foodstudio/templates/WelcomeEmail.d.ts.map +1 -0
- package/dist/foodstudio/templates/WelcomeEmail.js +155 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/modelfy/index.d.ts +4 -2
- package/dist/modelfy/index.d.ts.map +1 -1
- package/dist/modelfy/index.js +11 -1
- package/dist/modelfy/templates/FeedbackRequestEmail.d.ts +8 -0
- package/dist/modelfy/templates/FeedbackRequestEmail.d.ts.map +1 -0
- package/dist/modelfy/templates/FeedbackRequestEmail.js +208 -0
- package/dist/modelfy/templates/WelcomeEmail.js +1 -1
- package/eslint.config.js +25 -0
- package/package.json +10 -3
- package/src/foodstudio/config.ts +12 -0
- package/src/foodstudio/index.ts +71 -0
- package/src/foodstudio/templates/GrantCreditsEmail.tsx +352 -0
- package/src/foodstudio/templates/OtpEmail.tsx +273 -0
- package/src/foodstudio/templates/PromoSubscriptionEmail.tsx +344 -0
- package/src/foodstudio/templates/WelcomeEmail.tsx +293 -0
- package/src/index.ts +3 -0
- package/src/modelfy/index.ts +25 -2
- package/src/modelfy/templates/FeedbackRequestEmail.tsx +383 -0
- package/src/modelfy/templates/WelcomeEmail.tsx +1 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Html, Head, Body, Container, Section, Text, Link, Preview, Font, Img, Button as ReactEmailButton, } from "@react-email/components";
|
|
3
|
+
import { foodstudioConfig } from "../config.js";
|
|
4
|
+
// Design System Colors - Matching FoodStudio Landing
|
|
5
|
+
const colors = {
|
|
6
|
+
background: "#0d0d0d",
|
|
7
|
+
cardBg: "#121212",
|
|
8
|
+
primary: "#ea580c",
|
|
9
|
+
white: "#f2f2f2",
|
|
10
|
+
textSecondary: "rgba(242, 242, 242, 0.7)",
|
|
11
|
+
textMuted: "#8c8c8c",
|
|
12
|
+
border: "#262626",
|
|
13
|
+
};
|
|
14
|
+
const styles = {
|
|
15
|
+
body: {
|
|
16
|
+
margin: 0,
|
|
17
|
+
padding: 0,
|
|
18
|
+
backgroundColor: colors.background,
|
|
19
|
+
fontFamily: "'Inter', 'Segoe UI', Arial, sans-serif",
|
|
20
|
+
},
|
|
21
|
+
container: {
|
|
22
|
+
maxWidth: "600px",
|
|
23
|
+
margin: "0 auto",
|
|
24
|
+
backgroundColor: colors.background,
|
|
25
|
+
},
|
|
26
|
+
header: {
|
|
27
|
+
backgroundColor: colors.background,
|
|
28
|
+
padding: "40px 32px 24px",
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
},
|
|
31
|
+
logo: {
|
|
32
|
+
display: "block",
|
|
33
|
+
margin: "0 auto",
|
|
34
|
+
},
|
|
35
|
+
heroSection: {
|
|
36
|
+
padding: "24px 32px 40px",
|
|
37
|
+
textAlign: "center",
|
|
38
|
+
},
|
|
39
|
+
heroTagline: {
|
|
40
|
+
margin: "0 0 12px",
|
|
41
|
+
fontSize: "13px",
|
|
42
|
+
fontWeight: 600,
|
|
43
|
+
color: colors.primary,
|
|
44
|
+
letterSpacing: "2px",
|
|
45
|
+
textTransform: "uppercase",
|
|
46
|
+
},
|
|
47
|
+
heroHeading: {
|
|
48
|
+
margin: "0 0 16px",
|
|
49
|
+
fontSize: "28px",
|
|
50
|
+
fontWeight: 700,
|
|
51
|
+
color: colors.white,
|
|
52
|
+
lineHeight: "1.3",
|
|
53
|
+
},
|
|
54
|
+
heroSubheading: {
|
|
55
|
+
margin: "0 0 28px",
|
|
56
|
+
fontSize: "16px",
|
|
57
|
+
lineHeight: "1.6",
|
|
58
|
+
color: colors.textSecondary,
|
|
59
|
+
},
|
|
60
|
+
heroCta: {
|
|
61
|
+
display: "inline-block",
|
|
62
|
+
padding: "14px 36px",
|
|
63
|
+
fontSize: "15px",
|
|
64
|
+
fontWeight: 600,
|
|
65
|
+
textDecoration: "none",
|
|
66
|
+
borderRadius: "10px",
|
|
67
|
+
backgroundColor: colors.primary,
|
|
68
|
+
color: "#ffffff",
|
|
69
|
+
textAlign: "center",
|
|
70
|
+
},
|
|
71
|
+
welcomeSection: {
|
|
72
|
+
backgroundColor: colors.cardBg,
|
|
73
|
+
padding: "32px",
|
|
74
|
+
textAlign: "center",
|
|
75
|
+
borderTop: `1px solid ${colors.border}`,
|
|
76
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
77
|
+
},
|
|
78
|
+
welcomeText: {
|
|
79
|
+
margin: "0 0 16px",
|
|
80
|
+
fontSize: "16px",
|
|
81
|
+
lineHeight: "1.6",
|
|
82
|
+
color: colors.textSecondary,
|
|
83
|
+
},
|
|
84
|
+
welcomeEmail: {
|
|
85
|
+
color: colors.white,
|
|
86
|
+
fontWeight: 600,
|
|
87
|
+
},
|
|
88
|
+
supportSection: {
|
|
89
|
+
backgroundColor: colors.background,
|
|
90
|
+
padding: "32px",
|
|
91
|
+
textAlign: "center",
|
|
92
|
+
},
|
|
93
|
+
supportText: {
|
|
94
|
+
margin: "0 0 4px",
|
|
95
|
+
fontSize: "13px",
|
|
96
|
+
color: colors.textMuted,
|
|
97
|
+
},
|
|
98
|
+
supportLink: {
|
|
99
|
+
color: colors.primary,
|
|
100
|
+
textDecoration: "none",
|
|
101
|
+
fontWeight: 600,
|
|
102
|
+
},
|
|
103
|
+
footer: {
|
|
104
|
+
backgroundColor: colors.cardBg,
|
|
105
|
+
padding: "24px 32px",
|
|
106
|
+
textAlign: "center",
|
|
107
|
+
borderTop: `1px solid ${colors.border}`,
|
|
108
|
+
},
|
|
109
|
+
footerLogo: {
|
|
110
|
+
display: "block",
|
|
111
|
+
margin: "0 auto 12px",
|
|
112
|
+
opacity: 0.6,
|
|
113
|
+
},
|
|
114
|
+
footerText: {
|
|
115
|
+
margin: "0 0 4px",
|
|
116
|
+
fontSize: "11px",
|
|
117
|
+
color: colors.textMuted,
|
|
118
|
+
lineHeight: "1.6",
|
|
119
|
+
},
|
|
120
|
+
footerLink: {
|
|
121
|
+
color: colors.textMuted,
|
|
122
|
+
textDecoration: "underline",
|
|
123
|
+
},
|
|
124
|
+
downloadSection: {
|
|
125
|
+
backgroundColor: colors.cardBg,
|
|
126
|
+
padding: "24px 32px",
|
|
127
|
+
textAlign: "center",
|
|
128
|
+
borderTop: `1px solid ${colors.border}`,
|
|
129
|
+
},
|
|
130
|
+
downloadText: {
|
|
131
|
+
margin: "0 0 16px",
|
|
132
|
+
fontSize: "14px",
|
|
133
|
+
color: colors.white,
|
|
134
|
+
},
|
|
135
|
+
badgeContainer: {
|
|
136
|
+
textAlign: "center",
|
|
137
|
+
},
|
|
138
|
+
badge: {
|
|
139
|
+
display: "inline-block",
|
|
140
|
+
margin: "0 8px",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
export function WelcomeEmail({ email = "user@example.com" }) {
|
|
144
|
+
return (_jsxs(Html, { lang: "en", children: [_jsxs(Head, { children: [_jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
145
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjp-Ek-_0.woff2",
|
|
146
|
+
format: "woff2",
|
|
147
|
+
}, fontWeight: 400, fontStyle: "normal" }), _jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
148
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuI6fAZ9hjp-Ek-_0.woff2",
|
|
149
|
+
format: "woff2",
|
|
150
|
+
}, fontWeight: 600, fontStyle: "normal" }), _jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
151
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYAZ9hjp-Ek-_0.woff2",
|
|
152
|
+
format: "woff2",
|
|
153
|
+
}, fontWeight: 700, fontStyle: "normal" })] }), _jsx(Preview, { children: "Welcome to FoodStudio" }), _jsx(Body, { style: styles.body, children: _jsxs(Container, { style: styles.container, children: [_jsx(Section, { style: styles.header, children: _jsx(Img, { src: foodstudioConfig.logoUrl, width: "130", height: "auto", alt: "FoodStudio", style: styles.logo }) }), _jsxs(Section, { style: styles.heroSection, children: [_jsx(Text, { style: styles.heroTagline, children: "Welcome to FoodStudio" }), _jsx(Text, { style: styles.heroHeading, children: "Your Account is Ready!" }), _jsx(Text, { style: styles.heroSubheading, children: "We're excited to have you on board. Start exploring FoodStudio and discover all the amazing features waiting for you." }), _jsx(ReactEmailButton, { href: foodstudioConfig.appUrl, style: styles.heroCta, children: "Get Started" })] }), _jsx(Section, { style: styles.welcomeSection, children: _jsxs(Text, { style: styles.welcomeText, children: ["Hi ", _jsx("span", { style: styles.welcomeEmail, children: email }), ", your account is ready.", _jsx("br", {}), "You now have access to the complete FoodStudio platform."] }) }), _jsxs(Section, { style: styles.supportSection, children: [_jsx(Text, { style: styles.supportText, children: "Need help getting started?" }), _jsx(Text, { style: styles.supportText, children: _jsx(Link, { href: `mailto:${foodstudioConfig.supportEmail}`, style: styles.supportLink, children: foodstudioConfig.supportEmail }) })] }), _jsxs(Section, { style: styles.downloadSection, children: [_jsx(Text, { style: styles.downloadText, children: "Get the FoodStudio app" }), _jsxs("div", { style: styles.badgeContainer, children: [_jsx(Link, { href: foodstudioConfig.appStoreUrl, style: styles.badge, children: _jsx(Img, { src: foodstudioConfig.appStoreBadgeUrl, width: "120", height: "40", alt: "Download on the App Store" }) }), _jsx(Link, { href: foodstudioConfig.playStoreUrl, style: styles.badge, children: _jsx(Img, { src: foodstudioConfig.playStoreBadgeUrl, width: "135", height: "40", alt: "Get it on Google Play" }) })] })] }), _jsxs(Section, { style: styles.footer, children: [_jsx(Img, { src: foodstudioConfig.logoUrl, width: "80", height: "auto", alt: "FoodStudio", style: styles.footerLogo }), _jsxs(Text, { style: styles.footerText, children: ["\u00A9 ", new Date().getFullYear(), " ", foodstudioConfig.companyName, ". All rights reserved."] }), _jsx(Text, { style: styles.footerText, children: "You received this email because you signed up for FoodStudio." }), _jsx(Text, { style: styles.footerText, children: _jsx(Link, { href: `${foodstudioConfig.appUrl}/privacy`, style: styles.footerLink, children: "Privacy Policy" }) })] })] }) })] }));
|
|
154
|
+
}
|
|
155
|
+
export default WelcomeEmail;
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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;AAG9C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/modelfy/index.d.ts
CHANGED
|
@@ -2,8 +2,9 @@ import { OtpEmail, type OtpEmailProps } from "./templates/OtpEmail.js";
|
|
|
2
2
|
import { PromoSubscriptionEmail, type PromoSubscriptionEmailProps } from "./templates/PromoSubscriptionEmail.js";
|
|
3
3
|
import { GrantCreditsEmail, type GrantCreditsEmailProps } from "./templates/GrantCreditsEmail.js";
|
|
4
4
|
import { WelcomeEmail, type WelcomeEmailProps } from "./templates/WelcomeEmail.js";
|
|
5
|
-
|
|
6
|
-
export {
|
|
5
|
+
import { FeedbackRequestEmail, type FeedbackRequestEmailProps } from "./templates/FeedbackRequestEmail.js";
|
|
6
|
+
export type { OtpEmailProps, PromoSubscriptionEmailProps, GrantCreditsEmailProps, WelcomeEmailProps, FeedbackRequestEmailProps, };
|
|
7
|
+
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail, WelcomeEmail, FeedbackRequestEmail };
|
|
7
8
|
export interface RenderResult {
|
|
8
9
|
subject: string;
|
|
9
10
|
html: string;
|
|
@@ -13,4 +14,5 @@ export declare function renderOtpEmail(props: OtpEmailProps): Promise<RenderResu
|
|
|
13
14
|
export declare function renderPromoSubscriptionEmail(props: PromoSubscriptionEmailProps): Promise<RenderResult>;
|
|
14
15
|
export declare function renderGrantCreditsEmail(props: GrantCreditsEmailProps): Promise<RenderResult>;
|
|
15
16
|
export declare function renderWelcomeEmail(props: WelcomeEmailProps): Promise<RenderResult>;
|
|
17
|
+
export declare function renderFeedbackRequestEmail(props: FeedbackRequestEmailProps): Promise<RenderResult>;
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +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;AAClG,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;
|
|
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;AAClG,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,EAC/B,MAAM,qCAAqC,CAAC;AAG7C,YAAY,EACV,aAAa,EACb,2BAA2B,EAC3B,sBAAsB,EACtB,iBAAiB,EACjB,yBAAyB,GAC1B,CAAC;AAGF,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAGnG,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;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,YAAY,CAAC,CASvB;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,YAAY,CAAC,CASvB"}
|
package/dist/modelfy/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import { OtpEmail } from "./templates/OtpEmail.js";
|
|
|
3
3
|
import { PromoSubscriptionEmail, } from "./templates/PromoSubscriptionEmail.js";
|
|
4
4
|
import { GrantCreditsEmail } from "./templates/GrantCreditsEmail.js";
|
|
5
5
|
import { WelcomeEmail } from "./templates/WelcomeEmail.js";
|
|
6
|
+
import { FeedbackRequestEmail, } from "./templates/FeedbackRequestEmail.js";
|
|
6
7
|
// Re-export components for preview
|
|
7
|
-
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail, WelcomeEmail };
|
|
8
|
+
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail, WelcomeEmail, FeedbackRequestEmail };
|
|
8
9
|
export async function renderOtpEmail(props) {
|
|
9
10
|
const html = await render(OtpEmail(props));
|
|
10
11
|
const text = await render(OtpEmail(props), { plainText: true });
|
|
@@ -41,3 +42,12 @@ export async function renderWelcomeEmail(props) {
|
|
|
41
42
|
text,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
45
|
+
export async function renderFeedbackRequestEmail(props) {
|
|
46
|
+
const html = await render(FeedbackRequestEmail(props));
|
|
47
|
+
const text = await render(FeedbackRequestEmail(props), { plainText: true });
|
|
48
|
+
return {
|
|
49
|
+
subject: "We'd love your feedback on Modelfy",
|
|
50
|
+
html,
|
|
51
|
+
text,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface FeedbackRequestEmailProps {
|
|
2
|
+
email: string;
|
|
3
|
+
planName: string;
|
|
4
|
+
subscriptionEndDate: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function FeedbackRequestEmail({ email, planName, subscriptionEndDate, }: FeedbackRequestEmailProps): React.ReactElement;
|
|
7
|
+
export default FeedbackRequestEmail;
|
|
8
|
+
//# sourceMappingURL=FeedbackRequestEmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeedbackRequestEmail.d.ts","sourceRoot":"","sources":["../../../src/modelfy/templates/FeedbackRequestEmail.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAoMD,wBAAgB,oBAAoB,CAAC,EACnC,KAA0B,EAC1B,QAAgB,EAChB,mBAAuC,GACxC,EAAE,yBAAyB,GAAG,KAAK,CAAC,YAAY,CAiKhD;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Html, Head, Body, Container, Section, Text, Link, Preview, Font, Img, Button as ReactEmailButton, } from "@react-email/components";
|
|
3
|
+
import { modelfyConfig } from "../config.js";
|
|
4
|
+
// Design System Colors - Matching Modelfy Landing
|
|
5
|
+
const colors = {
|
|
6
|
+
background: "#0d0d0d",
|
|
7
|
+
cardBg: "#121212",
|
|
8
|
+
primary: "#0a8f5a",
|
|
9
|
+
white: "#f2f2f2",
|
|
10
|
+
textSecondary: "rgba(242, 242, 242, 0.7)",
|
|
11
|
+
textMuted: "#8c8c8c",
|
|
12
|
+
border: "#262626",
|
|
13
|
+
};
|
|
14
|
+
const styles = {
|
|
15
|
+
body: {
|
|
16
|
+
margin: 0,
|
|
17
|
+
padding: 0,
|
|
18
|
+
backgroundColor: colors.background,
|
|
19
|
+
fontFamily: "'Inter', 'Segoe UI', Arial, sans-serif",
|
|
20
|
+
},
|
|
21
|
+
container: {
|
|
22
|
+
maxWidth: "600px",
|
|
23
|
+
margin: "0 auto",
|
|
24
|
+
backgroundColor: colors.background,
|
|
25
|
+
},
|
|
26
|
+
header: {
|
|
27
|
+
backgroundColor: colors.background,
|
|
28
|
+
padding: "40px 32px 24px",
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
},
|
|
31
|
+
logo: {
|
|
32
|
+
display: "block",
|
|
33
|
+
margin: "0 auto",
|
|
34
|
+
},
|
|
35
|
+
heroSection: {
|
|
36
|
+
padding: "24px 32px 16px",
|
|
37
|
+
textAlign: "center",
|
|
38
|
+
},
|
|
39
|
+
heroTagline: {
|
|
40
|
+
margin: "0 0 12px",
|
|
41
|
+
fontSize: "13px",
|
|
42
|
+
fontWeight: 600,
|
|
43
|
+
color: colors.primary,
|
|
44
|
+
letterSpacing: "2px",
|
|
45
|
+
textTransform: "uppercase",
|
|
46
|
+
},
|
|
47
|
+
heroHeading: {
|
|
48
|
+
margin: "0 0 16px",
|
|
49
|
+
fontSize: "28px",
|
|
50
|
+
fontWeight: 700,
|
|
51
|
+
color: colors.white,
|
|
52
|
+
lineHeight: "1.3",
|
|
53
|
+
},
|
|
54
|
+
heroSubheading: {
|
|
55
|
+
margin: "0",
|
|
56
|
+
fontSize: "16px",
|
|
57
|
+
lineHeight: "1.6",
|
|
58
|
+
color: colors.textSecondary,
|
|
59
|
+
},
|
|
60
|
+
feedbackSection: {
|
|
61
|
+
backgroundColor: colors.cardBg,
|
|
62
|
+
padding: "32px",
|
|
63
|
+
borderTop: `1px solid ${colors.border}`,
|
|
64
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
65
|
+
},
|
|
66
|
+
feedbackText: {
|
|
67
|
+
margin: "0 0 20px",
|
|
68
|
+
fontSize: "15px",
|
|
69
|
+
lineHeight: "1.6",
|
|
70
|
+
color: colors.textSecondary,
|
|
71
|
+
textAlign: "center",
|
|
72
|
+
},
|
|
73
|
+
feedbackBox: {
|
|
74
|
+
backgroundColor: "rgba(10, 143, 90, 0.1)",
|
|
75
|
+
border: `1px solid rgba(10, 143, 90, 0.3)`,
|
|
76
|
+
borderRadius: "12px",
|
|
77
|
+
padding: "20px 24px",
|
|
78
|
+
marginBottom: "24px",
|
|
79
|
+
},
|
|
80
|
+
feedbackBoxText: {
|
|
81
|
+
margin: 0,
|
|
82
|
+
fontSize: "14px",
|
|
83
|
+
lineHeight: "1.6",
|
|
84
|
+
color: colors.textSecondary,
|
|
85
|
+
textAlign: "center",
|
|
86
|
+
},
|
|
87
|
+
questionsSection: {
|
|
88
|
+
backgroundColor: colors.background,
|
|
89
|
+
padding: "32px",
|
|
90
|
+
},
|
|
91
|
+
questionsSectionTitle: {
|
|
92
|
+
margin: "0 0 20px",
|
|
93
|
+
fontSize: "14px",
|
|
94
|
+
fontWeight: 600,
|
|
95
|
+
color: colors.white,
|
|
96
|
+
textAlign: "center",
|
|
97
|
+
},
|
|
98
|
+
questionsList: {
|
|
99
|
+
margin: "0 auto",
|
|
100
|
+
padding: "0 20px",
|
|
101
|
+
maxWidth: "400px",
|
|
102
|
+
},
|
|
103
|
+
questionItem: {
|
|
104
|
+
margin: "0 0 12px",
|
|
105
|
+
fontSize: "14px",
|
|
106
|
+
lineHeight: "1.5",
|
|
107
|
+
color: colors.textMuted,
|
|
108
|
+
},
|
|
109
|
+
questionBullet: {
|
|
110
|
+
color: colors.primary,
|
|
111
|
+
marginRight: "8px",
|
|
112
|
+
},
|
|
113
|
+
ctaSection: {
|
|
114
|
+
backgroundColor: colors.cardBg,
|
|
115
|
+
padding: "32px",
|
|
116
|
+
textAlign: "center",
|
|
117
|
+
borderTop: `1px solid ${colors.border}`,
|
|
118
|
+
},
|
|
119
|
+
ctaButton: {
|
|
120
|
+
display: "inline-block",
|
|
121
|
+
padding: "14px 36px",
|
|
122
|
+
fontSize: "15px",
|
|
123
|
+
fontWeight: 600,
|
|
124
|
+
textDecoration: "none",
|
|
125
|
+
borderRadius: "10px",
|
|
126
|
+
backgroundColor: colors.primary,
|
|
127
|
+
color: "#ffffff",
|
|
128
|
+
textAlign: "center",
|
|
129
|
+
},
|
|
130
|
+
winbackSection: {
|
|
131
|
+
backgroundColor: colors.background,
|
|
132
|
+
padding: "32px",
|
|
133
|
+
textAlign: "center",
|
|
134
|
+
},
|
|
135
|
+
winbackText: {
|
|
136
|
+
margin: "0 0 8px",
|
|
137
|
+
fontSize: "14px",
|
|
138
|
+
lineHeight: "1.6",
|
|
139
|
+
color: colors.textMuted,
|
|
140
|
+
textAlign: "center",
|
|
141
|
+
},
|
|
142
|
+
winbackLink: {
|
|
143
|
+
color: colors.primary,
|
|
144
|
+
textDecoration: "none",
|
|
145
|
+
fontWeight: 600,
|
|
146
|
+
},
|
|
147
|
+
downloadSection: {
|
|
148
|
+
backgroundColor: colors.cardBg,
|
|
149
|
+
padding: "24px 32px",
|
|
150
|
+
textAlign: "center",
|
|
151
|
+
borderTop: `1px solid ${colors.border}`,
|
|
152
|
+
},
|
|
153
|
+
downloadText: {
|
|
154
|
+
margin: "0 0 16px",
|
|
155
|
+
fontSize: "14px",
|
|
156
|
+
color: colors.white,
|
|
157
|
+
},
|
|
158
|
+
badgeContainer: {
|
|
159
|
+
textAlign: "center",
|
|
160
|
+
},
|
|
161
|
+
badge: {
|
|
162
|
+
display: "inline-block",
|
|
163
|
+
margin: "0 8px",
|
|
164
|
+
},
|
|
165
|
+
footer: {
|
|
166
|
+
backgroundColor: colors.cardBg,
|
|
167
|
+
padding: "24px 32px",
|
|
168
|
+
textAlign: "center",
|
|
169
|
+
borderTop: `1px solid ${colors.border}`,
|
|
170
|
+
},
|
|
171
|
+
footerLogo: {
|
|
172
|
+
display: "block",
|
|
173
|
+
margin: "0 auto 12px",
|
|
174
|
+
opacity: 0.6,
|
|
175
|
+
},
|
|
176
|
+
footerText: {
|
|
177
|
+
margin: "0 0 4px",
|
|
178
|
+
fontSize: "11px",
|
|
179
|
+
color: colors.textMuted,
|
|
180
|
+
lineHeight: "1.6",
|
|
181
|
+
},
|
|
182
|
+
footerLink: {
|
|
183
|
+
color: colors.textMuted,
|
|
184
|
+
textDecoration: "underline",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const feedbackReasons = [
|
|
188
|
+
"The pricing didn't fit my budget",
|
|
189
|
+
"I found an alternative solution",
|
|
190
|
+
"The features didn't meet my needs",
|
|
191
|
+
"I experienced technical issues",
|
|
192
|
+
"I didn't use the product enough",
|
|
193
|
+
"Other reasons",
|
|
194
|
+
];
|
|
195
|
+
export function FeedbackRequestEmail({ email = "user@example.com", planName = "Pro", subscriptionEndDate = "January 1, 2025", }) {
|
|
196
|
+
const feedbackMailto = `mailto:${modelfyConfig.supportEmail}?subject=Feedback%20on%20my%20Modelfy%20subscription&body=Hi%20Modelfy%20team%2C%0A%0AI%27m%20sharing%20feedback%20about%20my%20${encodeURIComponent(planName)}%20subscription%20that%20ended%20on%20${encodeURIComponent(subscriptionEndDate)}.%0A%0A`;
|
|
197
|
+
return (_jsxs(Html, { lang: "en", children: [_jsxs(Head, { children: [_jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
198
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjp-Ek-_0.woff2",
|
|
199
|
+
format: "woff2",
|
|
200
|
+
}, fontWeight: 400, fontStyle: "normal" }), _jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
201
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuI6fAZ9hjp-Ek-_0.woff2",
|
|
202
|
+
format: "woff2",
|
|
203
|
+
}, fontWeight: 600, fontStyle: "normal" }), _jsx(Font, { fontFamily: "Inter", fallbackFontFamily: "Arial", webFont: {
|
|
204
|
+
url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYAZ9hjp-Ek-_0.woff2",
|
|
205
|
+
format: "woff2",
|
|
206
|
+
}, fontWeight: 700, fontStyle: "normal" })] }), _jsx(Preview, { children: "We'd love your feedback on Modelfy - Help us improve" }), _jsx(Body, { style: styles.body, children: _jsxs(Container, { style: styles.container, children: [_jsx(Section, { style: styles.header, children: _jsx(Img, { src: modelfyConfig.logoUrl, width: "130", height: "auto", alt: "Modelfy", style: styles.logo }) }), _jsxs(Section, { style: styles.heroSection, children: [_jsx(Text, { style: styles.heroTagline, children: "We'd Love Your Feedback" }), _jsx(Text, { style: styles.heroHeading, children: "We're Sorry to See You Go" }), _jsxs(Text, { style: styles.heroSubheading, children: ["Hi ", _jsx("span", { style: { color: colors.white, fontWeight: 600 }, children: email }), ", your", " ", _jsx("span", { style: { color: colors.white, fontWeight: 600 }, children: planName }), " subscription ended on", " ", _jsx("span", { style: { color: colors.white, fontWeight: 600 }, children: subscriptionEndDate }), ". Your feedback would help us improve Modelfy for everyone."] })] }), _jsxs(Section, { style: styles.feedbackSection, children: [_jsx(Text, { style: styles.feedbackText, children: "We'd genuinely appreciate hearing about your experience. Just reply to this email or click the button below." }), _jsx("div", { style: styles.feedbackBox, children: _jsxs(Text, { style: styles.feedbackBoxText, children: ["Simply hit reply and let us know what we could do better.", _jsx("br", {}), "All feedback goes directly to our team."] }) })] }), _jsxs(Section, { style: styles.questionsSection, children: [_jsx(Text, { style: styles.questionsSectionTitle, children: "Some things we'd love to know:" }), _jsx("div", { style: styles.questionsList, children: feedbackReasons.map((reason, index) => (_jsxs(Text, { style: styles.questionItem, children: [_jsx("span", { style: styles.questionBullet, children: "\u2022" }), reason] }, index))) })] }), _jsx(Section, { style: styles.ctaSection, children: _jsx(ReactEmailButton, { href: feedbackMailto, style: styles.ctaButton, children: "Share Your Feedback" }) }), _jsxs(Section, { style: styles.winbackSection, children: [_jsx(Text, { style: styles.winbackText, children: "Changed your mind? Your account is still here waiting for you." }), _jsx(Text, { style: styles.winbackText, children: _jsx(Link, { href: modelfyConfig.appUrl, style: styles.winbackLink, children: "Reactivate your subscription" }) })] }), _jsxs(Section, { style: styles.downloadSection, children: [_jsx(Text, { style: styles.downloadText, children: "Get the Modelfy app" }), _jsxs("div", { style: styles.badgeContainer, children: [_jsx(Link, { href: modelfyConfig.appStoreUrl, style: styles.badge, children: _jsx(Img, { src: modelfyConfig.appStoreBadgeUrl, width: "120", height: "40", alt: "Download on the App Store" }) }), _jsx(Link, { href: modelfyConfig.playStoreUrl, style: styles.badge, children: _jsx(Img, { src: modelfyConfig.playStoreBadgeUrl, width: "135", height: "40", alt: "Get it on Google Play" }) })] })] }), _jsxs(Section, { style: styles.footer, children: [_jsx(Img, { src: modelfyConfig.logoUrl, width: "80", height: "auto", alt: "Modelfy", style: styles.footerLogo }), _jsxs(Text, { style: styles.footerText, children: ["\u00A9 ", new Date().getFullYear(), " ", modelfyConfig.companyName, ". All rights reserved."] }), _jsx(Text, { style: styles.footerText, children: "You received this email because your Modelfy subscription has ended." }), _jsx(Text, { style: styles.footerText, children: _jsx(Link, { href: `${modelfyConfig.appUrl}/privacy`, style: styles.footerLink, children: "Privacy Policy" }) })] })] }) })] }));
|
|
207
|
+
}
|
|
208
|
+
export default FeedbackRequestEmail;
|
|
@@ -253,7 +253,7 @@ const styles = {
|
|
|
253
253
|
};
|
|
254
254
|
// Image pools for random selection
|
|
255
255
|
const campaignImages = Array.from({ length: 33 }, (_, i) => `https://bucket.modelfy.ai/app-media/campaign/campaign${i + 1}.jpeg`);
|
|
256
|
-
const
|
|
256
|
+
const _campaignProImages = Array.from({ length: 15 }, (_, i) => `https://bucket.modelfy.ai/app-media/campaign-pro/campaign-pro-${i + 1}.jpg`);
|
|
257
257
|
const studioImages = Array.from({ length: 31 }, (_, i) => `https://bucket.modelfy.ai/app-media/studio/studio${i + 1}.jpeg`);
|
|
258
258
|
const colorSwapImages = Array.from({ length: 10 }, (_, i) => `https://modelfy.ai/images/color-swap/studio-color-change${i + 1}.jpg`);
|
|
259
259
|
const modelImages = [
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import tseslint from "typescript-eslint";
|
|
3
|
+
|
|
4
|
+
export default tseslint.config(
|
|
5
|
+
{ ignores: ["dist/**", "node_modules/**"] },
|
|
6
|
+
...tseslint.configs.recommended,
|
|
7
|
+
{
|
|
8
|
+
files: ["src/**/*.{ts,tsx}"],
|
|
9
|
+
languageOptions: {
|
|
10
|
+
globals: globals.node,
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaFeatures: {
|
|
13
|
+
jsx: true,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
rules: {
|
|
18
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
19
|
+
"@typescript-eslint/no-unused-vars": [
|
|
20
|
+
"error",
|
|
21
|
+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brookmind-emails",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Email templates for Brookmind projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,13 +15,18 @@
|
|
|
15
15
|
"require": "./dist/modelfy/index.js",
|
|
16
16
|
"import": "./dist/modelfy/index.js",
|
|
17
17
|
"types": "./dist/modelfy/index.d.ts"
|
|
18
|
+
},
|
|
19
|
+
"./foodstudio": {
|
|
20
|
+
"require": "./dist/foodstudio/index.js",
|
|
21
|
+
"import": "./dist/foodstudio/index.js",
|
|
22
|
+
"types": "./dist/foodstudio/index.d.ts"
|
|
18
23
|
}
|
|
19
24
|
},
|
|
20
25
|
"scripts": {
|
|
21
26
|
"dev": "email dev --dir src/modelfy/templates",
|
|
22
27
|
"build": "tsc",
|
|
23
28
|
"prepare": "npm run build",
|
|
24
|
-
"lint": "eslint src
|
|
29
|
+
"lint": "eslint src",
|
|
25
30
|
"format": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
26
31
|
},
|
|
27
32
|
"dependencies": {
|
|
@@ -35,8 +40,10 @@
|
|
|
35
40
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
36
41
|
"@typescript-eslint/parser": "^8.18.0",
|
|
37
42
|
"eslint": "^9.16.0",
|
|
43
|
+
"globals": "^17.1.0",
|
|
38
44
|
"prettier": "^3.4.2",
|
|
39
45
|
"react-email": "^3.0.4",
|
|
40
|
-
"typescript": "^5.7.2"
|
|
46
|
+
"typescript": "^5.7.2",
|
|
47
|
+
"typescript-eslint": "^8.53.1"
|
|
41
48
|
}
|
|
42
49
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const foodstudioConfig = {
|
|
2
|
+
logoUrl: "https://foodstudio.ai/FoodStudioLogo.png",
|
|
3
|
+
companyName: "FoodStudio",
|
|
4
|
+
supportEmail: "support@foodstudio.ai",
|
|
5
|
+
appUrl: "https://foodstudio.ai",
|
|
6
|
+
// App Store links
|
|
7
|
+
appStoreUrl: "https://apps.apple.com/app/id6757201826",
|
|
8
|
+
playStoreUrl: "https://play.google.com/store/apps/details?id=com.brookmind.foodstudio",
|
|
9
|
+
// Badge images
|
|
10
|
+
appStoreBadgeUrl: "https://foodstudio.ai/images/appstore.svg",
|
|
11
|
+
playStoreBadgeUrl: "https://foodstudio.ai/images/googleplay.svg",
|
|
12
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { render } from "@react-email/render";
|
|
2
|
+
import { OtpEmail, type OtpEmailProps } from "./templates/OtpEmail.js";
|
|
3
|
+
import {
|
|
4
|
+
PromoSubscriptionEmail,
|
|
5
|
+
type PromoSubscriptionEmailProps,
|
|
6
|
+
} from "./templates/PromoSubscriptionEmail.js";
|
|
7
|
+
import { GrantCreditsEmail, type GrantCreditsEmailProps } from "./templates/GrantCreditsEmail.js";
|
|
8
|
+
import { WelcomeEmail, type WelcomeEmailProps } from "./templates/WelcomeEmail.js";
|
|
9
|
+
|
|
10
|
+
// Re-export types
|
|
11
|
+
export type { OtpEmailProps, PromoSubscriptionEmailProps, GrantCreditsEmailProps, WelcomeEmailProps };
|
|
12
|
+
|
|
13
|
+
// Re-export components for preview
|
|
14
|
+
export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail, WelcomeEmail };
|
|
15
|
+
|
|
16
|
+
// Render functions
|
|
17
|
+
export interface RenderResult {
|
|
18
|
+
subject: string;
|
|
19
|
+
html: string;
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function renderOtpEmail(props: OtpEmailProps): Promise<RenderResult> {
|
|
24
|
+
const html = await render(OtpEmail(props));
|
|
25
|
+
const text = await render(OtpEmail(props), { plainText: true });
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
subject: "Your FoodStudio access code",
|
|
29
|
+
html,
|
|
30
|
+
text,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function renderPromoSubscriptionEmail(
|
|
35
|
+
props: PromoSubscriptionEmailProps
|
|
36
|
+
): Promise<RenderResult> {
|
|
37
|
+
const html = await render(PromoSubscriptionEmail(props));
|
|
38
|
+
const text = await render(PromoSubscriptionEmail(props), { plainText: true });
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
subject: `You've received a ${props.durationDays}-day ${props.planName} subscription!`,
|
|
42
|
+
html,
|
|
43
|
+
text,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function renderGrantCreditsEmail(
|
|
48
|
+
props: GrantCreditsEmailProps
|
|
49
|
+
): Promise<RenderResult> {
|
|
50
|
+
const html = await render(GrantCreditsEmail(props));
|
|
51
|
+
const text = await render(GrantCreditsEmail(props), { plainText: true });
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
subject: `You've received ${(props.credits ?? 0).toLocaleString()} credits on FoodStudio!`,
|
|
55
|
+
html,
|
|
56
|
+
text,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function renderWelcomeEmail(
|
|
61
|
+
props: WelcomeEmailProps
|
|
62
|
+
): Promise<RenderResult> {
|
|
63
|
+
const html = await render(WelcomeEmail(props));
|
|
64
|
+
const text = await render(WelcomeEmail(props), { plainText: true });
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
subject: "Welcome to FoodStudio!",
|
|
68
|
+
html,
|
|
69
|
+
text,
|
|
70
|
+
};
|
|
71
|
+
}
|