brookmind-emails 0.1.7 → 0.1.9

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.
@@ -5,12 +5,13 @@ import {
5
5
  type PromoSubscriptionEmailProps,
6
6
  } from "./templates/PromoSubscriptionEmail.js";
7
7
  import { GrantCreditsEmail, type GrantCreditsEmailProps } from "./templates/GrantCreditsEmail.js";
8
+ import { WelcomeEmail, type WelcomeEmailProps } from "./templates/WelcomeEmail.js";
8
9
 
9
10
  // Re-export types
10
- export type { OtpEmailProps, PromoSubscriptionEmailProps, GrantCreditsEmailProps };
11
+ export type { OtpEmailProps, PromoSubscriptionEmailProps, GrantCreditsEmailProps, WelcomeEmailProps };
11
12
 
12
13
  // Re-export components for preview
13
- export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail };
14
+ export { OtpEmail, PromoSubscriptionEmail, GrantCreditsEmail, WelcomeEmail };
14
15
 
15
16
  // Render functions
16
17
  export interface RenderResult {
@@ -55,3 +56,16 @@ export async function renderGrantCreditsEmail(
55
56
  text,
56
57
  };
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 Modelfy!",
68
+ html,
69
+ text,
70
+ };
71
+ }
@@ -8,8 +8,9 @@ import {
8
8
  Link,
9
9
  Preview,
10
10
  Font,
11
+ Img,
12
+ Button as ReactEmailButton,
11
13
  } from "@react-email/components";
12
- import { Header, Footer, Button } from "../../shared/components/index.js";
13
14
  import { modelfyConfig } from "../config.js";
14
15
 
15
16
  export interface GrantCreditsEmailProps {
@@ -20,101 +21,187 @@ export interface GrantCreditsEmailProps {
20
21
  description?: string;
21
22
  }
22
23
 
24
+ // Design System Colors - Matching Modelfy Landing
25
+ const colors = {
26
+ background: "#0d0d0d",
27
+ cardBg: "#121212",
28
+ primary: "#0a8f5a",
29
+ white: "#f2f2f2",
30
+ textSecondary: "rgba(242, 242, 242, 0.7)",
31
+ textMuted: "#8c8c8c",
32
+ border: "#262626",
33
+ };
34
+
23
35
  const styles = {
24
36
  body: {
25
37
  margin: 0,
26
38
  padding: 0,
27
- backgroundColor: "#F8FAFC",
28
- fontFamily: "'Outfit', Arial, sans-serif",
39
+ backgroundColor: colors.background,
40
+ fontFamily: "'Inter', 'Segoe UI', Arial, sans-serif",
29
41
  },
30
42
  container: {
31
- maxWidth: "560px",
32
- margin: "32px auto",
33
- backgroundColor: "#ffffff",
34
- border: "1px solid #E2E8F0",
35
- borderRadius: "16px",
36
- boxShadow: "0 24px 48px rgba(15, 23, 42, 0.08)",
37
- overflow: "hidden",
38
- },
39
- content: {
40
- padding: "32px 40px 24px",
41
- },
42
- heading: {
43
+ maxWidth: "600px",
44
+ margin: "0 auto",
45
+ backgroundColor: colors.background,
46
+ },
47
+ header: {
48
+ backgroundColor: colors.background,
49
+ padding: "40px 32px 24px",
50
+ textAlign: "center" as const,
51
+ },
52
+ logo: {
53
+ display: "block" as const,
54
+ margin: "0 auto",
55
+ },
56
+ heroSection: {
57
+ padding: "24px 32px 40px",
58
+ textAlign: "center" as const,
59
+ },
60
+ heroTagline: {
61
+ margin: "0 0 12px",
62
+ fontSize: "13px",
63
+ fontWeight: 600,
64
+ color: colors.primary,
65
+ letterSpacing: "2px",
66
+ textTransform: "uppercase" as const,
67
+ },
68
+ heroHeading: {
43
69
  margin: "0 0 16px",
44
- fontSize: "24px",
70
+ fontSize: "28px",
45
71
  fontWeight: 700,
46
- color: "#0F172A",
47
- textAlign: "center" as const,
72
+ color: colors.white,
73
+ lineHeight: "1.3",
48
74
  },
49
75
  paragraph: {
50
- margin: "0 0 24px",
76
+ margin: "0 0 28px",
51
77
  fontSize: "16px",
52
78
  lineHeight: "1.6",
53
- color: "rgba(15, 23, 42, 0.72)",
79
+ color: colors.textSecondary,
80
+ textAlign: "center" as const,
54
81
  },
55
82
  creditBox: {
56
- backgroundColor: "rgba(34, 197, 94, 0.08)",
57
- border: "1px solid rgba(34, 197, 94, 0.24)",
83
+ backgroundColor: "rgba(10, 143, 90, 0.15)",
84
+ border: `1px solid rgba(10, 143, 90, 0.3)`,
58
85
  borderRadius: "12px",
59
86
  padding: "24px",
60
- marginBottom: "24px",
87
+ marginBottom: "28px",
61
88
  textAlign: "center" as const,
62
89
  },
63
90
  creditAmount: {
64
91
  fontSize: "48px",
65
92
  fontWeight: 700,
66
- color: "#16A34A",
67
- margin: "0 0 8px",
93
+ color: colors.white,
94
+ margin: "0 0 4px",
68
95
  },
69
96
  creditLabel: {
70
- fontSize: "16px",
71
- color: "rgba(15, 23, 42, 0.6)",
97
+ fontSize: "14px",
98
+ color: colors.textMuted,
72
99
  margin: 0,
73
100
  },
74
101
  detailsBox: {
75
- backgroundColor: "#F8FAFC",
76
- borderRadius: "8px",
77
- padding: "16px",
78
- marginBottom: "24px",
79
- },
80
- detailRow: {
81
- display: "flex" as const,
82
- justifyContent: "space-between" as const,
83
- marginBottom: "8px",
102
+ backgroundColor: colors.cardBg,
103
+ border: `1px solid ${colors.border}`,
104
+ borderRadius: "12px",
105
+ padding: "20px 24px",
106
+ marginBottom: "28px",
84
107
  },
85
108
  detailLabel: {
86
- fontSize: "14px",
87
- color: "rgba(15, 23, 42, 0.6)",
88
- margin: 0,
109
+ fontSize: "13px",
110
+ color: colors.textMuted,
111
+ margin: "0 0 4px",
89
112
  },
90
113
  detailValue: {
91
- fontSize: "14px",
114
+ fontSize: "16px",
92
115
  fontWeight: 600,
93
- color: "#0F172A",
116
+ color: colors.white,
94
117
  margin: 0,
95
118
  },
96
119
  buttonContainer: {
97
120
  textAlign: "center" as const,
98
- marginBottom: "24px",
121
+ marginBottom: "28px",
122
+ },
123
+ ctaButton: {
124
+ display: "inline-block",
125
+ padding: "14px 36px",
126
+ fontSize: "15px",
127
+ fontWeight: 600,
128
+ textDecoration: "none",
129
+ borderRadius: "10px",
130
+ backgroundColor: colors.primary,
131
+ color: "#ffffff",
132
+ textAlign: "center" as const,
133
+ },
134
+ contentSection: {
135
+ backgroundColor: colors.cardBg,
136
+ padding: "32px",
137
+ borderTop: `1px solid ${colors.border}`,
99
138
  },
100
139
  smallText: {
101
140
  margin: "0 0 12px",
102
141
  fontSize: "14px",
103
142
  lineHeight: "1.6",
104
- color: "rgba(15, 23, 42, 0.6)",
143
+ color: colors.textMuted,
144
+ textAlign: "center" as const,
145
+ },
146
+ descriptionText: {
147
+ margin: "0 0 24px",
148
+ fontSize: "15px",
149
+ lineHeight: "1.6",
150
+ color: colors.textSecondary,
151
+ textAlign: "center" as const,
152
+ fontStyle: "italic" as const,
105
153
  },
106
154
  link: {
107
- color: "#6366F1",
155
+ color: colors.primary,
108
156
  textDecoration: "none",
109
157
  fontWeight: 600,
110
158
  },
159
+ footer: {
160
+ backgroundColor: colors.cardBg,
161
+ padding: "24px 32px",
162
+ textAlign: "center" as const,
163
+ borderTop: `1px solid ${colors.border}`,
164
+ },
165
+ footerLogo: {
166
+ display: "block" as const,
167
+ margin: "0 auto 12px",
168
+ opacity: 0.6,
169
+ },
170
+ footerText: {
171
+ margin: "0 0 4px",
172
+ fontSize: "11px",
173
+ color: colors.textMuted,
174
+ lineHeight: "1.6",
175
+ },
176
+ footerLink: {
177
+ color: colors.textMuted,
178
+ textDecoration: "underline",
179
+ },
180
+ downloadSection: {
181
+ backgroundColor: colors.cardBg,
182
+ padding: "24px 32px",
183
+ textAlign: "center" as const,
184
+ borderTop: `1px solid ${colors.border}`,
185
+ },
186
+ downloadText: {
187
+ margin: "0 0 16px",
188
+ fontSize: "14px",
189
+ color: colors.white,
190
+ },
191
+ badgeContainer: {
192
+ textAlign: "center" as const,
193
+ },
194
+ badge: {
195
+ display: "inline-block",
196
+ margin: "0 8px",
197
+ },
111
198
  };
112
199
 
113
200
  export function GrantCreditsEmail({
114
- email,
201
+ email = "user@example.com",
115
202
  credits,
116
- durationDays,
117
- expiresAt,
203
+ durationDays = 30,
204
+ expiresAt = "January 31, 2025",
118
205
  description,
119
206
  }: GrantCreditsEmailProps) {
120
207
  const safeCredits = Number.isFinite(credits) ? Number(credits) : 0;
@@ -123,79 +210,139 @@ export function GrantCreditsEmail({
123
210
  <Html lang="en">
124
211
  <Head>
125
212
  <Font
126
- fontFamily="Outfit"
213
+ fontFamily="Inter"
127
214
  fallbackFontFamily="Arial"
128
215
  webFont={{
129
- url: "https://fonts.gstatic.com/s/outfit/v11/QGYyz_MVcBeNP4NjuGObqx1XmO1I4TC1C4G-EiAou6Y.woff2",
216
+ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjp-Ek-_0.woff2",
130
217
  format: "woff2",
131
218
  }}
132
219
  fontWeight={400}
133
220
  fontStyle="normal"
134
221
  />
222
+ <Font
223
+ fontFamily="Inter"
224
+ fallbackFontFamily="Arial"
225
+ webFont={{
226
+ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYAZ9hjp-Ek-_0.woff2",
227
+ format: "woff2",
228
+ }}
229
+ fontWeight={700}
230
+ fontStyle="normal"
231
+ />
135
232
  </Head>
136
233
  <Preview>
137
234
  You've received {safeCredits.toLocaleString()} credits on Modelfy!
138
235
  </Preview>
139
236
  <Body style={styles.body}>
140
237
  <Container style={styles.container}>
141
- <Header logoUrl={modelfyConfig.logoUrl} logoAlt="Modelfy" subtitle="Credits added" />
142
- <Section style={styles.content}>
143
- <Text style={styles.heading}>Credits Added to Your Account!</Text>
238
+ {/* Header */}
239
+ <Section style={styles.header}>
240
+ <Img
241
+ src={modelfyConfig.logoUrl}
242
+ width="130"
243
+ height="auto"
244
+ alt="Modelfy"
245
+ style={styles.logo}
246
+ />
247
+ </Section>
248
+
249
+ {/* Hero Section */}
250
+ <Section style={styles.heroSection}>
251
+ <Text style={styles.heroTagline}>Bonus Credits</Text>
252
+ <Text style={styles.heroHeading}>Credits Added to Your Account!</Text>
144
253
  <Text style={styles.paragraph}>
145
- Hi <strong>{email}</strong>, you've received bonus credits to use on Modelfy.
254
+ Hi <span style={{ color: colors.white, fontWeight: 600 }}>{email}</span>, you've
255
+ received bonus credits to use on Modelfy.
146
256
  </Text>
147
257
 
148
258
  <div style={styles.creditBox}>
149
- <Text style={styles.creditAmount}>+{safeCredits.toLocaleString()}</Text>
259
+ <Text style={styles.creditAmount}>{safeCredits.toLocaleString()}</Text>
150
260
  <Text style={styles.creditLabel}>credits</Text>
151
261
  </div>
152
262
 
153
263
  <div style={styles.detailsBox}>
154
264
  <table width="100%" cellPadding={0} cellSpacing={0}>
155
- <tr>
156
- <td style={{ paddingBottom: "8px" }}>
157
- <Text style={styles.detailLabel}>Valid for</Text>
158
- </td>
159
- <td style={{ paddingBottom: "8px", textAlign: "right" }}>
160
- <Text style={styles.detailValue}>{durationDays} days</Text>
161
- </td>
162
- </tr>
163
- <tr>
164
- <td>
165
- <Text style={styles.detailLabel}>Expires</Text>
166
- </td>
167
- <td style={{ textAlign: "right" }}>
168
- <Text style={styles.detailValue}>{expiresAt}</Text>
169
- </td>
170
- </tr>
265
+ <tbody>
266
+ <tr>
267
+ <td style={{ paddingBottom: "16px" }}>
268
+ <Text style={styles.detailLabel}>Valid for</Text>
269
+ <Text style={styles.detailValue}>{durationDays} days</Text>
270
+ </td>
271
+ <td style={{ paddingBottom: "16px", textAlign: "right" as const }}>
272
+ <Text style={styles.detailLabel}>Expires</Text>
273
+ <Text style={styles.detailValue}>{expiresAt}</Text>
274
+ </td>
275
+ </tr>
276
+ </tbody>
171
277
  </table>
172
278
  </div>
173
279
 
174
- {description && (
175
- <Text style={styles.paragraph}>
176
- <em>"{description}"</em>
177
- </Text>
178
- )}
280
+ {description && <Text style={styles.descriptionText}>"{description}"</Text>}
179
281
 
180
282
  <div style={styles.buttonContainer}>
181
- <Button href={modelfyConfig.appUrl}>Start Creating</Button>
283
+ <ReactEmailButton href={modelfyConfig.appUrl} style={styles.ctaButton}>
284
+ Start Creating
285
+ </ReactEmailButton>
182
286
  </div>
287
+ </Section>
183
288
 
289
+ {/* Content Section */}
290
+ <Section style={styles.contentSection}>
184
291
  <Text style={styles.smallText}>
185
292
  These credits will be used before your regular credits and expire on {expiresAt}.
186
293
  </Text>
187
294
  <Text style={styles.smallText}>
188
- Questions? Contact us at{" "}
295
+ Questions?{" "}
189
296
  <Link href={`mailto:${modelfyConfig.supportEmail}`} style={styles.link}>
190
297
  {modelfyConfig.supportEmail}
191
298
  </Link>
192
299
  </Text>
193
300
  </Section>
194
- <Footer
195
- companyName={modelfyConfig.companyName}
196
- message="You received this email because credits were added to your Modelfy account."
197
- supportEmail={modelfyConfig.supportEmail}
198
- />
301
+
302
+ {/* Download App Section */}
303
+ <Section style={styles.downloadSection}>
304
+ <Text style={styles.downloadText}>Get the Modelfy app</Text>
305
+ <div style={styles.badgeContainer}>
306
+ <Link href={modelfyConfig.appStoreUrl} style={styles.badge}>
307
+ <Img
308
+ src={modelfyConfig.appStoreBadgeUrl}
309
+ width="120"
310
+ height="40"
311
+ alt="Download on the App Store"
312
+ />
313
+ </Link>
314
+ <Link href={modelfyConfig.playStoreUrl} style={styles.badge}>
315
+ <Img
316
+ src={modelfyConfig.playStoreBadgeUrl}
317
+ width="135"
318
+ height="40"
319
+ alt="Get it on Google Play"
320
+ />
321
+ </Link>
322
+ </div>
323
+ </Section>
324
+
325
+ {/* Footer */}
326
+ <Section style={styles.footer}>
327
+ <Img
328
+ src={modelfyConfig.logoUrl}
329
+ width="80"
330
+ height="auto"
331
+ alt="Modelfy"
332
+ style={styles.footerLogo}
333
+ />
334
+ <Text style={styles.footerText}>
335
+ © {new Date().getFullYear()} {modelfyConfig.companyName}. All rights reserved.
336
+ </Text>
337
+ <Text style={styles.footerText}>
338
+ You received this email because credits were added to your Modelfy account.
339
+ </Text>
340
+ <Text style={styles.footerText}>
341
+ <Link href={`${modelfyConfig.appUrl}/privacy`} style={styles.footerLink}>
342
+ Privacy Policy
343
+ </Link>
344
+ </Text>
345
+ </Section>
199
346
  </Container>
200
347
  </Body>
201
348
  </Html>