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.
@@ -0,0 +1,619 @@
1
+ import {
2
+ Html,
3
+ Head,
4
+ Body,
5
+ Container,
6
+ Section,
7
+ Text,
8
+ Link,
9
+ Preview,
10
+ Font,
11
+ Img,
12
+ Button as ReactEmailButton,
13
+ } from "@react-email/components";
14
+ import { modelfyConfig } from "../config.js";
15
+
16
+ export interface WelcomeEmailProps {
17
+ email: string;
18
+ }
19
+
20
+ // Design System Colors - Matching Modelfy Landing
21
+ const colors = {
22
+ background: "#0d0d0d",
23
+ cardBg: "#121212",
24
+ primary: "#0a8f5a",
25
+ primaryLight: "#10b981",
26
+ accent: "#f59e0b",
27
+ accentDark: "#d97706",
28
+ white: "#f2f2f2",
29
+ textSecondary: "rgba(242, 242, 242, 0.7)",
30
+ textMuted: "#8c8c8c",
31
+ border: "#262626",
32
+ };
33
+
34
+ const styles = {
35
+ body: {
36
+ margin: 0,
37
+ padding: 0,
38
+ backgroundColor: colors.background,
39
+ fontFamily: "'Inter', 'Segoe UI', Arial, sans-serif",
40
+ },
41
+ container: {
42
+ maxWidth: "600px",
43
+ margin: "0 auto",
44
+ backgroundColor: colors.background,
45
+ },
46
+ header: {
47
+ backgroundColor: colors.background,
48
+ padding: "40px 32px 24px",
49
+ textAlign: "center" as const,
50
+ },
51
+ logo: {
52
+ display: "block" as const,
53
+ margin: "0 auto",
54
+ },
55
+ heroSection: {
56
+ padding: "24px 32px 40px",
57
+ textAlign: "center" as const,
58
+ },
59
+ heroTagline: {
60
+ margin: "0 0 12px",
61
+ fontSize: "13px",
62
+ fontWeight: 600,
63
+ color: colors.primary,
64
+ letterSpacing: "2px",
65
+ textTransform: "uppercase" as const,
66
+ },
67
+ heroHeading: {
68
+ margin: "0 0 16px",
69
+ fontSize: "28px",
70
+ fontWeight: 700,
71
+ color: colors.white,
72
+ lineHeight: "1.3",
73
+ },
74
+ heroSubheading: {
75
+ margin: "0 0 28px",
76
+ fontSize: "16px",
77
+ lineHeight: "1.6",
78
+ color: colors.textSecondary,
79
+ },
80
+ heroCta: {
81
+ display: "inline-block",
82
+ padding: "14px 36px",
83
+ fontSize: "15px",
84
+ fontWeight: 600,
85
+ textDecoration: "none",
86
+ borderRadius: "10px",
87
+ backgroundColor: colors.primary,
88
+ color: "#ffffff",
89
+ textAlign: "center" as const,
90
+ },
91
+ welcomeSection: {
92
+ backgroundColor: colors.cardBg,
93
+ padding: "32px",
94
+ textAlign: "center" as const,
95
+ borderTop: `1px solid ${colors.border}`,
96
+ borderBottom: `1px solid ${colors.border}`,
97
+ },
98
+ welcomeText: {
99
+ margin: "0 0 16px",
100
+ fontSize: "16px",
101
+ lineHeight: "1.6",
102
+ color: colors.textSecondary,
103
+ },
104
+ welcomeEmail: {
105
+ color: colors.white,
106
+ fontWeight: 600,
107
+ },
108
+ creditsBox: {
109
+ display: "inline-block",
110
+ backgroundColor: "rgba(10, 143, 90, 0.15)",
111
+ border: `1px solid rgba(10, 143, 90, 0.3)`,
112
+ borderRadius: "8px",
113
+ padding: "10px 20px",
114
+ },
115
+ creditsText: {
116
+ margin: 0,
117
+ fontSize: "14px",
118
+ color: colors.white,
119
+ fontWeight: 600,
120
+ },
121
+ featuresSection: {
122
+ backgroundColor: colors.background,
123
+ padding: "40px 24px",
124
+ },
125
+ featuresSectionTitle: {
126
+ margin: "0 0 8px",
127
+ fontSize: "12px",
128
+ fontWeight: 600,
129
+ color: colors.primary,
130
+ letterSpacing: "2px",
131
+ textTransform: "uppercase" as const,
132
+ textAlign: "center" as const,
133
+ },
134
+ featuresSectionHeading: {
135
+ margin: "0 0 32px",
136
+ fontSize: "22px",
137
+ fontWeight: 700,
138
+ color: colors.white,
139
+ textAlign: "center" as const,
140
+ lineHeight: "1.4",
141
+ },
142
+ goldenGradient: {
143
+ background: "linear-gradient(135deg, #f59e0b, #d97706)",
144
+ WebkitBackgroundClip: "text",
145
+ WebkitTextFillColor: "transparent",
146
+ backgroundClip: "text",
147
+ },
148
+ featureRow: {
149
+ marginBottom: "20px",
150
+ backgroundColor: colors.cardBg,
151
+ borderRadius: "12px",
152
+ overflow: "hidden" as const,
153
+ border: `1px solid ${colors.border}`,
154
+ },
155
+ featureImage: {
156
+ width: "100%",
157
+ height: "auto",
158
+ display: "block" as const,
159
+ },
160
+ featureContent: {
161
+ padding: "20px",
162
+ verticalAlign: "middle" as const,
163
+ },
164
+ featureEyebrow: {
165
+ margin: "0 0 6px",
166
+ fontSize: "11px",
167
+ fontWeight: 600,
168
+ color: colors.primary,
169
+ letterSpacing: "1.5px",
170
+ textTransform: "uppercase" as const,
171
+ },
172
+ featureTitle: {
173
+ margin: "0 0 8px",
174
+ fontSize: "18px",
175
+ fontWeight: 700,
176
+ color: colors.white,
177
+ lineHeight: "1.2",
178
+ },
179
+ featureTitleHighlight: {
180
+ color: colors.primary,
181
+ },
182
+ featureDescription: {
183
+ margin: 0,
184
+ fontSize: "13px",
185
+ lineHeight: "1.5",
186
+ color: colors.textMuted,
187
+ },
188
+ ctaSection: {
189
+ backgroundColor: colors.cardBg,
190
+ padding: "40px 32px",
191
+ textAlign: "center" as const,
192
+ borderTop: `1px solid ${colors.border}`,
193
+ },
194
+ ctaHeading: {
195
+ margin: "0 0 12px",
196
+ fontSize: "22px",
197
+ fontWeight: 700,
198
+ color: colors.white,
199
+ },
200
+ ctaSubheading: {
201
+ margin: "0 0 24px",
202
+ fontSize: "15px",
203
+ color: colors.textSecondary,
204
+ },
205
+ ctaButton: {
206
+ display: "inline-block",
207
+ padding: "16px 48px",
208
+ fontSize: "15px",
209
+ fontWeight: 600,
210
+ textDecoration: "none",
211
+ borderRadius: "10px",
212
+ backgroundColor: colors.primary,
213
+ color: "#ffffff",
214
+ textAlign: "center" as const,
215
+ },
216
+ supportSection: {
217
+ backgroundColor: colors.background,
218
+ padding: "32px",
219
+ textAlign: "center" as const,
220
+ },
221
+ supportText: {
222
+ margin: "0 0 4px",
223
+ fontSize: "13px",
224
+ color: colors.textMuted,
225
+ },
226
+ supportLink: {
227
+ color: colors.primary,
228
+ textDecoration: "none",
229
+ fontWeight: 600,
230
+ },
231
+ footer: {
232
+ backgroundColor: colors.cardBg,
233
+ padding: "24px 32px",
234
+ textAlign: "center" as const,
235
+ borderTop: `1px solid ${colors.border}`,
236
+ },
237
+ footerLogo: {
238
+ display: "block" as const,
239
+ margin: "0 auto 12px",
240
+ opacity: 0.6,
241
+ },
242
+ footerText: {
243
+ margin: "0 0 4px",
244
+ fontSize: "11px",
245
+ color: colors.textMuted,
246
+ lineHeight: "1.6",
247
+ },
248
+ footerLink: {
249
+ color: colors.textMuted,
250
+ textDecoration: "underline",
251
+ },
252
+ downloadSection: {
253
+ backgroundColor: colors.cardBg,
254
+ padding: "24px 32px",
255
+ textAlign: "center" as const,
256
+ borderTop: `1px solid ${colors.border}`,
257
+ },
258
+ downloadText: {
259
+ margin: "0 0 16px",
260
+ fontSize: "14px",
261
+ color: colors.white,
262
+ },
263
+ badgeContainer: {
264
+ textAlign: "center" as const,
265
+ },
266
+ badge: {
267
+ display: "inline-block",
268
+ margin: "0 8px",
269
+ },
270
+ };
271
+
272
+ // Image pools for random selection
273
+ const campaignImages = Array.from(
274
+ { length: 33 },
275
+ (_, i) => `https://bucket.modelfy.ai/app-media/campaign/campaign${i + 1}.jpeg`
276
+ );
277
+ const campaignProImages = Array.from(
278
+ { length: 15 },
279
+ (_, i) => `https://bucket.modelfy.ai/app-media/campaign-pro/campaign-pro-${i + 1}.jpg`
280
+ );
281
+ const colorSwapImages = Array.from(
282
+ { length: 10 },
283
+ (_, i) => `https://modelfy.ai/images/color-swap/studio-color-change${i + 1}.jpg`
284
+ );
285
+ const modelImages = [
286
+ "https://modelfy.ai/images/result-model-1.jpg",
287
+ "https://modelfy.ai/images/result-model-2.jpg",
288
+ "https://modelfy.ai/images/result-model-3.jpg",
289
+ ];
290
+
291
+ function getRandomImage(images: string[]): string {
292
+ return images[Math.floor(Math.random() * images.length)];
293
+ }
294
+
295
+ const features = [
296
+ {
297
+ eyebrow: "AI MODELS",
298
+ titleBefore: "Create your own",
299
+ titleHighlight: "AI Models",
300
+ titleAfter: "",
301
+ description: "Build custom AI models that capture your brand's unique aesthetic. Train once, use across every campaign.",
302
+ getImage: () => getRandomImage(modelImages),
303
+ isVideo: false,
304
+ },
305
+ {
306
+ eyebrow: "CAMPAIGNS",
307
+ titleBefore: "Professional",
308
+ titleHighlight: "Campaign",
309
+ titleAfter: "Photography",
310
+ description: "Place your products in any scene imaginable. Rooftop nights, city streets, beach sunsets, or fully custom environments.",
311
+ getImage: () => getRandomImage(campaignImages),
312
+ isVideo: false,
313
+ },
314
+ {
315
+ eyebrow: "STUDIO",
316
+ titleBefore: "Studio-Quality",
317
+ titleHighlight: "Product",
318
+ titleAfter: "Shots",
319
+ description: "Clean backgrounds, perfect lighting. E-commerce ready in seconds.",
320
+ getImage: () => getRandomImage(campaignProImages),
321
+ isVideo: false,
322
+ },
323
+ {
324
+ eyebrow: "COLOR SWAP",
325
+ titleBefore: "Instant",
326
+ titleHighlight: "Color",
327
+ titleAfter: "Variations",
328
+ description: "Generate every color variant your product comes in. One shoot, unlimited colors.",
329
+ getImage: () => getRandomImage(colorSwapImages),
330
+ isVideo: false,
331
+ },
332
+ {
333
+ eyebrow: "VIDEO",
334
+ titleBefore: "Create",
335
+ titleHighlight: "Videos",
336
+ titleAfter: "with Audio",
337
+ description: "Create stunning product videos with AI-generated audio, music, and voiceovers.",
338
+ getImage: () => getRandomImage(campaignImages),
339
+ isVideo: true,
340
+ videoLink: "https://modelfy.ai/#features",
341
+ },
342
+ {
343
+ eyebrow: "SUBTITLES",
344
+ titleBefore: "Auto-Generate",
345
+ titleHighlight: "Subtitles",
346
+ titleAfter: "",
347
+ description: "Auto-generate customizable subtitles for social media videos. Upload, generate, customize, download.",
348
+ getImage: () => "https://bucket.modelfy.ai/app-media/emails/subtitles.png",
349
+ isVideo: false,
350
+ },
351
+ {
352
+ eyebrow: "EXPORT",
353
+ titleBefore: "Every",
354
+ titleHighlight: "Format",
355
+ titleAfter: "You Need",
356
+ description: "Stories, Reels, Posts, Square, Landscape, Portrait. Up to 4K resolution.",
357
+ getImage: () => getRandomImage(campaignProImages),
358
+ isVideo: false,
359
+ },
360
+ ];
361
+
362
+ export function WelcomeEmail({ email = "user@example.com" }: WelcomeEmailProps) {
363
+ return (
364
+ <Html lang="en">
365
+ <Head>
366
+ <Font
367
+ fontFamily="Inter"
368
+ fallbackFontFamily="Arial"
369
+ webFont={{
370
+ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hjp-Ek-_0.woff2",
371
+ format: "woff2",
372
+ }}
373
+ fontWeight={400}
374
+ fontStyle="normal"
375
+ />
376
+ <Font
377
+ fontFamily="Inter"
378
+ fallbackFontFamily="Arial"
379
+ webFont={{
380
+ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuI6fAZ9hjp-Ek-_0.woff2",
381
+ format: "woff2",
382
+ }}
383
+ fontWeight={600}
384
+ fontStyle="normal"
385
+ />
386
+ <Font
387
+ fontFamily="Inter"
388
+ fallbackFontFamily="Arial"
389
+ webFont={{
390
+ url: "https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuFuYAZ9hjp-Ek-_0.woff2",
391
+ format: "woff2",
392
+ }}
393
+ fontWeight={700}
394
+ fontStyle="normal"
395
+ />
396
+ </Head>
397
+ <Preview>Welcome to Modelfy - Transform your product photography with AI</Preview>
398
+ <Body style={styles.body}>
399
+ <Container style={styles.container}>
400
+ {/* Header */}
401
+ <Section style={styles.header}>
402
+ <Img
403
+ src={modelfyConfig.logoUrl}
404
+ width="130"
405
+ height="auto"
406
+ alt="Modelfy"
407
+ style={styles.logo}
408
+ />
409
+ </Section>
410
+
411
+ {/* Hero Section */}
412
+ <Section style={styles.heroSection}>
413
+ <Text style={styles.heroTagline}>Welcome to Modelfy</Text>
414
+ <Text style={styles.heroHeading}>
415
+ Turn Your Product Photos Into Endless Professional Content
416
+ </Text>
417
+ <Text style={styles.heroSubheading}>
418
+ From one product photo to AI-powered professional campaigns, lifestyle content, and social posts.{" "}
419
+ <span style={{ color: colors.white }}>No photographers, no models, no reshoots.</span>
420
+ </Text>
421
+ <ReactEmailButton href={modelfyConfig.appUrl} style={styles.heroCta}>
422
+ Start Creating
423
+ </ReactEmailButton>
424
+ </Section>
425
+
426
+ {/* Welcome Message */}
427
+ <Section style={styles.welcomeSection}>
428
+ <Text style={styles.welcomeText}>
429
+ Hi <span style={styles.welcomeEmail}>{email}</span>, your account is ready.
430
+ <br />
431
+ You now have access to the complete Modelfy platform.
432
+ </Text>
433
+ <div style={styles.creditsBox}>
434
+ <Text style={styles.creditsText}>2 Free Generations Included</Text>
435
+ </div>
436
+ </Section>
437
+
438
+ {/* Features Section */}
439
+ <Section style={styles.featuresSection}>
440
+ <Text style={styles.featuresSectionTitle}>Features</Text>
441
+ <Text style={styles.featuresSectionHeading}>
442
+ Everything you need to create{" "}
443
+ <span style={{ color: colors.accent }}>stunning</span>{" "}
444
+ marketing, social, and e-commerce content
445
+ </Text>
446
+
447
+ {/* Feature Rows - Alternating Layout */}
448
+ {features.map((feature, index) => {
449
+ const isReversed = index % 2 === 1;
450
+
451
+ const imageContent = feature.isVideo ? (
452
+ <Link href={feature.videoLink || modelfyConfig.appUrl} style={{ display: "block", position: "relative" as const }}>
453
+ <div style={{ position: "relative" as const }}>
454
+ <Img
455
+ src={feature.getImage()}
456
+ alt={feature.titleHighlight}
457
+ width="100%"
458
+ style={{
459
+ ...styles.featureImage,
460
+ aspectRatio: "3/4",
461
+ objectFit: "cover" as const,
462
+ }}
463
+ />
464
+ {/* Play button overlay */}
465
+ <div
466
+ style={{
467
+ position: "absolute" as const,
468
+ top: "50%",
469
+ left: "50%",
470
+ transform: "translate(-50%, -50%)",
471
+ width: "60px",
472
+ height: "60px",
473
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
474
+ borderRadius: "50%",
475
+ display: "flex" as const,
476
+ alignItems: "center" as const,
477
+ justifyContent: "center" as const,
478
+ }}
479
+ >
480
+ <div
481
+ style={{
482
+ width: "0",
483
+ height: "0",
484
+ borderTop: "12px solid transparent",
485
+ borderBottom: "12px solid transparent",
486
+ borderLeft: "20px solid white",
487
+ marginLeft: "4px",
488
+ }}
489
+ />
490
+ </div>
491
+ </div>
492
+ </Link>
493
+ ) : (
494
+ <Img
495
+ src={feature.getImage()}
496
+ alt={feature.titleHighlight}
497
+ width="100%"
498
+ style={{
499
+ ...styles.featureImage,
500
+ aspectRatio: "3/4",
501
+ objectFit: "cover" as const,
502
+ }}
503
+ />
504
+ );
505
+
506
+ const imageCell = (
507
+ <td style={{ width: "45%", verticalAlign: "top" }}>
508
+ {imageContent}
509
+ </td>
510
+ );
511
+
512
+ const contentCell = (
513
+ <td style={{ ...styles.featureContent, width: "55%" }}>
514
+ <Text style={styles.featureEyebrow}>{feature.eyebrow}</Text>
515
+ <Text style={styles.featureTitle}>
516
+ {feature.titleBefore}{" "}
517
+ <span style={styles.featureTitleHighlight}>{feature.titleHighlight}</span>
518
+ {feature.titleAfter && ` ${feature.titleAfter}`}
519
+ </Text>
520
+ <Text style={styles.featureDescription}>{feature.description}</Text>
521
+ </td>
522
+ );
523
+
524
+ return (
525
+ <div key={index} style={styles.featureRow}>
526
+ <table cellPadding={0} cellSpacing={0} style={{ width: "100%" }}>
527
+ <tbody>
528
+ <tr>
529
+ {isReversed ? (
530
+ <>
531
+ {contentCell}
532
+ {imageCell}
533
+ </>
534
+ ) : (
535
+ <>
536
+ {imageCell}
537
+ {contentCell}
538
+ </>
539
+ )}
540
+ </tr>
541
+ </tbody>
542
+ </table>
543
+ </div>
544
+ );
545
+ })}
546
+ </Section>
547
+
548
+ {/* CTA Section */}
549
+ <Section style={styles.ctaSection}>
550
+ <Text style={styles.ctaHeading}>Ready to Transform Your Content?</Text>
551
+ <Text style={styles.ctaSubheading}>
552
+ Upload your first product photo and see the magic happen.
553
+ </Text>
554
+ <ReactEmailButton href={modelfyConfig.appUrl} style={styles.ctaButton}>
555
+ Get Started Free
556
+ </ReactEmailButton>
557
+ </Section>
558
+
559
+ {/* Support Section */}
560
+ <Section style={styles.supportSection}>
561
+ <Text style={styles.supportText}>Need help getting started?</Text>
562
+ <Text style={styles.supportText}>
563
+ <Link href={`mailto:${modelfyConfig.supportEmail}`} style={styles.supportLink}>
564
+ {modelfyConfig.supportEmail}
565
+ </Link>
566
+ </Text>
567
+ </Section>
568
+
569
+ {/* Download App Section */}
570
+ <Section style={styles.downloadSection}>
571
+ <Text style={styles.downloadText}>Get the Modelfy app</Text>
572
+ <div style={styles.badgeContainer}>
573
+ <Link href={modelfyConfig.appStoreUrl} style={styles.badge}>
574
+ <Img
575
+ src={modelfyConfig.appStoreBadgeUrl}
576
+ width="120"
577
+ height="40"
578
+ alt="Download on the App Store"
579
+ />
580
+ </Link>
581
+ <Link href={modelfyConfig.playStoreUrl} style={styles.badge}>
582
+ <Img
583
+ src={modelfyConfig.playStoreBadgeUrl}
584
+ width="135"
585
+ height="40"
586
+ alt="Get it on Google Play"
587
+ />
588
+ </Link>
589
+ </div>
590
+ </Section>
591
+
592
+ {/* Footer */}
593
+ <Section style={styles.footer}>
594
+ <Img
595
+ src={modelfyConfig.logoUrl}
596
+ width="80"
597
+ height="auto"
598
+ alt="Modelfy"
599
+ style={styles.footerLogo}
600
+ />
601
+ <Text style={styles.footerText}>
602
+ © {new Date().getFullYear()} {modelfyConfig.companyName}. All rights reserved.
603
+ </Text>
604
+ <Text style={styles.footerText}>
605
+ You received this email because you signed up for Modelfy.
606
+ </Text>
607
+ <Text style={styles.footerText}>
608
+ <Link href={`${modelfyConfig.appUrl}/privacy`} style={styles.footerLink}>
609
+ Privacy Policy
610
+ </Link>
611
+ </Text>
612
+ </Section>
613
+ </Container>
614
+ </Body>
615
+ </Html>
616
+ );
617
+ }
618
+
619
+ export default WelcomeEmail;
@@ -1,3 +1,4 @@
1
1
  export { OtpEmail, type OtpEmailProps } from "./OtpEmail.js";
2
2
  export { PromoSubscriptionEmail, type PromoSubscriptionEmailProps } from "./PromoSubscriptionEmail.js";
3
3
  export { GrantCreditsEmail, type GrantCreditsEmailProps } from "./GrantCreditsEmail.js";
4
+ export { WelcomeEmail, type WelcomeEmailProps } from "./WelcomeEmail.js";