@tracked/emails 0.1.5 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/content.d.ts +58 -0
- package/dist/components/content.d.ts.map +1 -0
- package/dist/components/content.js +166 -0
- package/dist/components/content.js.map +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +11 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/interactive.d.ts +23 -0
- package/dist/components/interactive.d.ts.map +1 -0
- package/dist/components/interactive.js +66 -0
- package/dist/components/interactive.js.map +1 -0
- package/dist/components/layout.d.ts +27 -0
- package/dist/components/layout.d.ts.map +1 -0
- package/dist/components/layout.js +83 -0
- package/dist/components/layout.js.map +1 -0
- package/dist/components/tokens.d.ts +58 -0
- package/dist/components/tokens.d.ts.map +1 -0
- package/dist/components/tokens.js +64 -0
- package/dist/components/tokens.js.map +1 -0
- package/dist/components/typography.d.ts +31 -0
- package/dist/components/typography.d.ts.map +1 -0
- package/dist/components/typography.js +72 -0
- package/dist/components/typography.js.map +1 -0
- package/dist/emails/anniversary.d.ts +12 -0
- package/dist/emails/anniversary.d.ts.map +1 -0
- package/dist/emails/anniversary.js +41 -0
- package/dist/emails/anniversary.js.map +1 -0
- package/dist/emails/app-review-request.d.ts +11 -0
- package/dist/emails/app-review-request.d.ts.map +1 -0
- package/dist/emails/app-review-request.js +24 -0
- package/dist/emails/app-review-request.js.map +1 -0
- package/dist/emails/bodyweight-goal-reached.d.ts +1 -1
- package/dist/emails/bodyweight-goal-reached.d.ts.map +1 -1
- package/dist/emails/bodyweight-goal-reached.js +86 -159
- package/dist/emails/bodyweight-goal-reached.js.map +1 -1
- package/dist/emails/client-inactive-alert.d.ts +14 -0
- package/dist/emails/client-inactive-alert.d.ts.map +1 -0
- package/dist/emails/client-inactive-alert.js +34 -0
- package/dist/emails/client-inactive-alert.js.map +1 -0
- package/dist/emails/client-onboarded.d.ts +35 -0
- package/dist/emails/client-onboarded.d.ts.map +1 -0
- package/dist/emails/client-onboarded.js +66 -0
- package/dist/emails/client-onboarded.js.map +1 -0
- package/dist/emails/coach-invite.d.ts +1 -1
- package/dist/emails/coach-invite.d.ts.map +1 -1
- package/dist/emails/coach-invite.js +13 -121
- package/dist/emails/coach-invite.js.map +1 -1
- package/dist/emails/coach-removed-client.d.ts +1 -1
- package/dist/emails/coach-removed-client.d.ts.map +1 -1
- package/dist/emails/coach-removed-client.js +3 -76
- package/dist/emails/coach-removed-client.js.map +1 -1
- package/dist/emails/direct-message.d.ts +1 -1
- package/dist/emails/direct-message.d.ts.map +1 -1
- package/dist/emails/direct-message.js +22 -96
- package/dist/emails/direct-message.js.map +1 -1
- package/dist/emails/feature-discovery.d.ts +2 -1
- package/dist/emails/feature-discovery.d.ts.map +1 -1
- package/dist/emails/feature-discovery.js +20 -117
- package/dist/emails/feature-discovery.js.map +1 -1
- package/dist/emails/first-workout-assigned.d.ts +1 -1
- package/dist/emails/first-workout-assigned.d.ts.map +1 -1
- package/dist/emails/first-workout-assigned.js +3 -94
- package/dist/emails/first-workout-assigned.js.map +1 -1
- package/dist/emails/first-workout-completed.d.ts +1 -1
- package/dist/emails/first-workout-completed.d.ts.map +1 -1
- package/dist/emails/first-workout-completed.js +14 -125
- package/dist/emails/first-workout-completed.js.map +1 -1
- package/dist/emails/inactive-reengagement.d.ts +10 -0
- package/dist/emails/inactive-reengagement.d.ts.map +1 -0
- package/dist/emails/inactive-reengagement.js +31 -0
- package/dist/emails/inactive-reengagement.js.map +1 -0
- package/dist/emails/index.d.ts +1 -0
- package/dist/emails/index.d.ts.map +1 -1
- package/dist/emails/index.js +1 -0
- package/dist/emails/index.js.map +1 -1
- package/dist/emails/monthly-report.d.ts +2 -1
- package/dist/emails/monthly-report.d.ts.map +1 -1
- package/dist/emails/monthly-report.js +14 -166
- package/dist/emails/monthly-report.js.map +1 -1
- package/dist/emails/new-follower.d.ts +1 -1
- package/dist/emails/new-follower.d.ts.map +1 -1
- package/dist/emails/new-follower.js +7 -91
- package/dist/emails/new-follower.js.map +1 -1
- package/dist/emails/nps-survey.d.ts +9 -0
- package/dist/emails/nps-survey.d.ts.map +1 -0
- package/dist/emails/nps-survey.js +51 -0
- package/dist/emails/nps-survey.js.map +1 -0
- package/dist/emails/subscription-canceled.d.ts +1 -1
- package/dist/emails/subscription-canceled.d.ts.map +1 -1
- package/dist/emails/subscription-canceled.js +20 -127
- package/dist/emails/subscription-canceled.js.map +1 -1
- package/dist/emails/support-email.d.ts +1 -1
- package/dist/emails/support-email.d.ts.map +1 -1
- package/dist/emails/support-email.js +3 -38
- package/dist/emails/support-email.js.map +1 -1
- package/dist/emails/team-invite.d.ts.map +1 -1
- package/dist/emails/team-invite.js +7 -96
- package/dist/emails/team-invite.js.map +1 -1
- package/dist/emails/team-member-removed-email.d.ts +1 -1
- package/dist/emails/team-member-removed-email.d.ts.map +1 -1
- package/dist/emails/team-member-removed-email.js +3 -93
- package/dist/emails/team-member-removed-email.js.map +1 -1
- package/dist/emails/tracked-magic-link-activate.d.ts +2 -2
- package/dist/emails/tracked-magic-link-activate.d.ts.map +1 -1
- package/dist/emails/tracked-magic-link-activate.js +3 -91
- package/dist/emails/tracked-magic-link-activate.js.map +1 -1
- package/dist/emails/tracked-magic-link.d.ts +3 -3
- package/dist/emails/tracked-magic-link.d.ts.map +1 -1
- package/dist/emails/tracked-magic-link.js +3 -99
- package/dist/emails/tracked-magic-link.js.map +1 -1
- package/dist/emails/week-one-checkin.d.ts +3 -2
- package/dist/emails/week-one-checkin.d.ts.map +1 -1
- package/dist/emails/week-one-checkin.js +22 -136
- package/dist/emails/week-one-checkin.js.map +1 -1
- package/dist/emails/weekly-progress-digest.d.ts +21 -0
- package/dist/emails/weekly-progress-digest.d.ts.map +1 -0
- package/dist/emails/weekly-progress-digest.js +78 -0
- package/dist/emails/weekly-progress-digest.js.map +1 -0
- package/dist/emails/welcome.d.ts +3 -2
- package/dist/emails/welcome.d.ts.map +1 -1
- package/dist/emails/welcome.js +16 -142
- package/dist/emails/welcome.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/package.json +20 -20
- package/src/components/content.tsx +351 -0
- package/src/components/index.ts +44 -0
- package/src/components/interactive.tsx +260 -0
- package/src/components/layout.tsx +217 -0
- package/src/components/tokens.ts +74 -0
- package/src/components/typography.tsx +148 -0
- package/src/emails/anniversary.tsx +133 -0
- package/src/emails/app-review-request.tsx +100 -0
- package/src/emails/bodyweight-goal-reached.tsx +202 -350
- package/src/emails/client-inactive-alert.tsx +130 -0
- package/src/emails/client-onboarded.tsx +272 -0
- package/src/emails/coach-invite.tsx +67 -250
- package/src/emails/coach-removed-client.tsx +36 -197
- package/src/emails/direct-message.tsx +69 -227
- package/src/emails/feature-discovery.tsx +82 -266
- package/src/emails/first-workout-assigned.tsx +52 -238
- package/src/emails/first-workout-completed.tsx +88 -294
- package/src/emails/inactive-reengagement.tsx +81 -0
- package/src/emails/index.tsx +1 -0
- package/src/emails/monthly-report.tsx +198 -520
- package/src/emails/new-follower.tsx +60 -238
- package/src/emails/nps-survey.tsx +149 -0
- package/src/emails/subscription-canceled.tsx +88 -294
- package/src/emails/support-email.tsx +33 -67
- package/src/emails/team-invite.tsx +47 -240
- package/src/emails/team-member-removed-email.tsx +23 -218
- package/src/emails/tracked-magic-link-activate.tsx +29 -237
- package/src/emails/tracked-magic-link.tsx +31 -251
- package/src/emails/week-one-checkin.tsx +108 -329
- package/src/emails/weekly-progress-digest.tsx +248 -0
- package/src/emails/welcome.tsx +58 -326
- package/src/index.ts +19 -2
- package/dist/emails/client-accepted-invitation.d.ts +0 -10
- package/dist/emails/client-accepted-invitation.d.ts.map +0 -1
- package/dist/emails/client-accepted-invitation.js +0 -99
- package/dist/emails/client-accepted-invitation.js.map +0 -1
- package/src/emails/client-accepted-invitation.tsx +0 -258
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Img, Section } from "@react-email/components";
|
|
3
|
+
import { colors, borderRadius, spacing } from "./tokens";
|
|
4
|
+
|
|
5
|
+
// ============================================
|
|
6
|
+
// PrimaryButton - Main CTA button
|
|
7
|
+
// ============================================
|
|
8
|
+
interface PrimaryButtonProps {
|
|
9
|
+
href: string;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
fullWidth?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const PrimaryButton = ({
|
|
15
|
+
href,
|
|
16
|
+
children,
|
|
17
|
+
fullWidth = false,
|
|
18
|
+
}: PrimaryButtonProps) => {
|
|
19
|
+
return (
|
|
20
|
+
<Section style={{ margin: `${spacing.lg} 0`, textAlign: "left" as const }}>
|
|
21
|
+
<a
|
|
22
|
+
href={href}
|
|
23
|
+
style={{
|
|
24
|
+
backgroundColor: colors.primary,
|
|
25
|
+
borderRadius: borderRadius.md,
|
|
26
|
+
color: "#ffffff",
|
|
27
|
+
fontSize: "16px",
|
|
28
|
+
fontWeight: "bold",
|
|
29
|
+
textDecoration: "none",
|
|
30
|
+
padding: "12px 32px",
|
|
31
|
+
display: fullWidth ? "block" : "inline-block",
|
|
32
|
+
textAlign: "center" as const,
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</a>
|
|
37
|
+
</Section>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ============================================
|
|
42
|
+
// SecondaryButton - Secondary action button
|
|
43
|
+
// ============================================
|
|
44
|
+
interface SecondaryButtonProps {
|
|
45
|
+
href: string;
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
fullWidth?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const SecondaryButton = ({
|
|
51
|
+
href,
|
|
52
|
+
children,
|
|
53
|
+
fullWidth = false,
|
|
54
|
+
}: SecondaryButtonProps) => {
|
|
55
|
+
return (
|
|
56
|
+
<Section style={{ margin: `${spacing.md} 0`, textAlign: "left" as const }}>
|
|
57
|
+
<a
|
|
58
|
+
href={href}
|
|
59
|
+
style={{
|
|
60
|
+
backgroundColor: colors.surface,
|
|
61
|
+
border: `1px solid ${colors.borderStrong}`,
|
|
62
|
+
borderRadius: borderRadius.md,
|
|
63
|
+
color: colors.textPrimary,
|
|
64
|
+
fontSize: "16px",
|
|
65
|
+
fontWeight: "600",
|
|
66
|
+
textDecoration: "none",
|
|
67
|
+
padding: "12px 32px",
|
|
68
|
+
display: fullWidth ? "block" : "inline-block",
|
|
69
|
+
textAlign: "center" as const,
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
{children}
|
|
73
|
+
</a>
|
|
74
|
+
</Section>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// SocialButtons - Discord and YouTube icon buttons
|
|
80
|
+
// ============================================
|
|
81
|
+
export const SocialButtons = () => {
|
|
82
|
+
return (
|
|
83
|
+
<Section style={{ margin: `${spacing.sm} 0`, textAlign: "center" as const }}>
|
|
84
|
+
<table cellPadding="0" cellSpacing="0" style={{ margin: "0 auto" }}>
|
|
85
|
+
<tr>
|
|
86
|
+
{/* Discord */}
|
|
87
|
+
<td style={{ paddingRight: "12px" }}>
|
|
88
|
+
<a
|
|
89
|
+
href="https://www.discord.gg/trackedgg"
|
|
90
|
+
style={{
|
|
91
|
+
display: "inline-block",
|
|
92
|
+
textDecoration: "none",
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<svg
|
|
96
|
+
width="24"
|
|
97
|
+
height="24"
|
|
98
|
+
viewBox="0 0 127.14 96.36"
|
|
99
|
+
>
|
|
100
|
+
<path
|
|
101
|
+
fill={colors.textSecondary}
|
|
102
|
+
d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"
|
|
103
|
+
/>
|
|
104
|
+
</svg>
|
|
105
|
+
</a>
|
|
106
|
+
</td>
|
|
107
|
+
{/* YouTube */}
|
|
108
|
+
<td style={{ paddingRight: "12px" }}>
|
|
109
|
+
<a
|
|
110
|
+
href="https://www.youtube.com/@Keenanrmalloy"
|
|
111
|
+
style={{
|
|
112
|
+
display: "inline-block",
|
|
113
|
+
textDecoration: "none",
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<svg
|
|
117
|
+
width="24"
|
|
118
|
+
height="24"
|
|
119
|
+
viewBox="0 0 24 24"
|
|
120
|
+
>
|
|
121
|
+
<path
|
|
122
|
+
fill={colors.textSecondary}
|
|
123
|
+
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
|
|
124
|
+
/>
|
|
125
|
+
</svg>
|
|
126
|
+
</a>
|
|
127
|
+
</td>
|
|
128
|
+
{/* TikTok */}
|
|
129
|
+
<td style={{ paddingRight: "12px" }}>
|
|
130
|
+
<a
|
|
131
|
+
href="https://www.tiktok.com/@keenanrmalloy"
|
|
132
|
+
style={{
|
|
133
|
+
display: "inline-block",
|
|
134
|
+
textDecoration: "none",
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
<svg
|
|
138
|
+
width="24"
|
|
139
|
+
height="24"
|
|
140
|
+
viewBox="0 0 24 24"
|
|
141
|
+
>
|
|
142
|
+
<path
|
|
143
|
+
fill={colors.textSecondary}
|
|
144
|
+
d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-5.2 1.74 2.89 2.89 0 0 1 2.31-4.64 2.93 2.93 0 0 1 .88.13V9.4a6.84 6.84 0 0 0-1-.05A6.33 6.33 0 0 0 5 20.1a6.34 6.34 0 0 0 10.86-4.43v-7a8.16 8.16 0 0 0 4.77 1.52v-3.4a4.85 4.85 0 0 1-1-.1z"
|
|
145
|
+
/>
|
|
146
|
+
</svg>
|
|
147
|
+
</a>
|
|
148
|
+
</td>
|
|
149
|
+
{/* Instagram */}
|
|
150
|
+
<td style={{ paddingRight: "12px" }}>
|
|
151
|
+
<a
|
|
152
|
+
href="https://www.instagram.com/keenanrmalloy/"
|
|
153
|
+
style={{
|
|
154
|
+
display: "inline-block",
|
|
155
|
+
textDecoration: "none",
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
<svg
|
|
159
|
+
width="24"
|
|
160
|
+
height="24"
|
|
161
|
+
viewBox="0 0 24 24"
|
|
162
|
+
>
|
|
163
|
+
<path
|
|
164
|
+
fill={colors.textSecondary}
|
|
165
|
+
d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"
|
|
166
|
+
/>
|
|
167
|
+
</svg>
|
|
168
|
+
</a>
|
|
169
|
+
</td>
|
|
170
|
+
{/* Reddit */}
|
|
171
|
+
<td>
|
|
172
|
+
<a
|
|
173
|
+
href="https://www.reddit.com/r/trackedapp/"
|
|
174
|
+
style={{
|
|
175
|
+
display: "inline-block",
|
|
176
|
+
textDecoration: "none",
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
<svg
|
|
180
|
+
width="24"
|
|
181
|
+
height="24"
|
|
182
|
+
viewBox="0 0 24 24"
|
|
183
|
+
>
|
|
184
|
+
<path
|
|
185
|
+
fill={colors.textSecondary}
|
|
186
|
+
d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z"
|
|
187
|
+
/>
|
|
188
|
+
</svg>
|
|
189
|
+
</a>
|
|
190
|
+
</td>
|
|
191
|
+
</tr>
|
|
192
|
+
</table>
|
|
193
|
+
</Section>
|
|
194
|
+
);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Keep DiscordButton for backward compatibility
|
|
198
|
+
export const DiscordButton = SocialButtons;
|
|
199
|
+
|
|
200
|
+
// ============================================
|
|
201
|
+
// AppStoreButtons - iOS/Android download buttons
|
|
202
|
+
// ============================================
|
|
203
|
+
export const AppStoreButtons = () => {
|
|
204
|
+
return (
|
|
205
|
+
<Section style={{ marginTop: spacing.lg, textAlign: "center" as const }}>
|
|
206
|
+
<table cellPadding="0" cellSpacing="0" style={{ margin: "0 auto" }}>
|
|
207
|
+
<tr>
|
|
208
|
+
<td style={{ paddingRight: "8px" }}>
|
|
209
|
+
<a
|
|
210
|
+
href="https://apps.apple.com/app/tracked-training/id6450913418"
|
|
211
|
+
style={{ display: "block", textDecoration: "none" }}
|
|
212
|
+
>
|
|
213
|
+
<Img
|
|
214
|
+
src="https://cdn.trckd.ca/assets/Download_on_the_App_Store_Badge_US-UK_RGB_blk_092917.svg"
|
|
215
|
+
alt="Download on the App Store"
|
|
216
|
+
height="36"
|
|
217
|
+
style={{ display: "block" }}
|
|
218
|
+
/>
|
|
219
|
+
</a>
|
|
220
|
+
</td>
|
|
221
|
+
<td style={{ paddingLeft: "8px" }}>
|
|
222
|
+
<a
|
|
223
|
+
href="https://play.google.com/store/apps/details?id=com.tracked.mobile"
|
|
224
|
+
style={{ display: "block", textDecoration: "none" }}
|
|
225
|
+
>
|
|
226
|
+
<Img
|
|
227
|
+
src="https://cdn.trckd.ca/assets/GetItOnGooglePlay_Badge_Web_color_English.svg"
|
|
228
|
+
alt="Get it on Google Play"
|
|
229
|
+
height="36"
|
|
230
|
+
style={{ display: "block" }}
|
|
231
|
+
/>
|
|
232
|
+
</a>
|
|
233
|
+
</td>
|
|
234
|
+
</tr>
|
|
235
|
+
</table>
|
|
236
|
+
</Section>
|
|
237
|
+
);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// ============================================
|
|
241
|
+
// TextLink - Inline text link
|
|
242
|
+
// ============================================
|
|
243
|
+
interface TextLinkProps {
|
|
244
|
+
href: string;
|
|
245
|
+
children: React.ReactNode;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export const TextLink = ({ href, children }: TextLinkProps) => {
|
|
249
|
+
return (
|
|
250
|
+
<a
|
|
251
|
+
href={href}
|
|
252
|
+
style={{
|
|
253
|
+
color: colors.accent,
|
|
254
|
+
textDecoration: "underline",
|
|
255
|
+
}}
|
|
256
|
+
>
|
|
257
|
+
{children}
|
|
258
|
+
</a>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Body,
|
|
4
|
+
Container,
|
|
5
|
+
Head,
|
|
6
|
+
Hr,
|
|
7
|
+
Html,
|
|
8
|
+
Img,
|
|
9
|
+
Link,
|
|
10
|
+
Preview,
|
|
11
|
+
Section,
|
|
12
|
+
Text,
|
|
13
|
+
} from "@react-email/components";
|
|
14
|
+
import { colors, typography, spacing } from "./tokens";
|
|
15
|
+
import { AppStoreButtons } from "./interactive";
|
|
16
|
+
|
|
17
|
+
const baseUrl = "https://tracked.gg/android-chrome-192x192.png";
|
|
18
|
+
const defaultWebsiteUrl = "https://tracked.gg";
|
|
19
|
+
|
|
20
|
+
// ============================================
|
|
21
|
+
// EmailLayout - Main wrapper component
|
|
22
|
+
// ============================================
|
|
23
|
+
interface EmailLayoutProps {
|
|
24
|
+
preview: string;
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const EmailLayout = ({ preview, children }: EmailLayoutProps) => {
|
|
29
|
+
return (
|
|
30
|
+
<Html>
|
|
31
|
+
<Head>
|
|
32
|
+
<meta name="color-scheme" content="light only" />
|
|
33
|
+
<meta name="supported-color-schemes" content="light only" />
|
|
34
|
+
</Head>
|
|
35
|
+
<Preview>{preview}</Preview>
|
|
36
|
+
<Body style={mainStyle}>
|
|
37
|
+
<Container style={containerStyle}>
|
|
38
|
+
<Section style={boxStyle}>{children}</Section>
|
|
39
|
+
</Container>
|
|
40
|
+
</Body>
|
|
41
|
+
</Html>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const mainStyle = {
|
|
46
|
+
backgroundColor: colors.background,
|
|
47
|
+
fontFamily: typography.fontFamily,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const containerStyle = {
|
|
51
|
+
backgroundColor: colors.background,
|
|
52
|
+
margin: "0 auto",
|
|
53
|
+
padding: "20px 0 48px",
|
|
54
|
+
maxWidth: "600px",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const boxStyle = {
|
|
58
|
+
padding: "0 24px",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ============================================
|
|
62
|
+
// EmailHeader - Logo and brand name
|
|
63
|
+
// ============================================
|
|
64
|
+
interface EmailHeaderProps {
|
|
65
|
+
showDivider?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const EmailHeader = ({ showDivider = true }: EmailHeaderProps) => {
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<table cellPadding="0" cellSpacing="0" style={{ marginBottom: spacing.sm }}>
|
|
72
|
+
<tr>
|
|
73
|
+
<td style={{ verticalAlign: "middle" }}>
|
|
74
|
+
<Img src={baseUrl} width="28" height="28" alt="Tracked" />
|
|
75
|
+
</td>
|
|
76
|
+
<td style={{ verticalAlign: "middle", paddingLeft: "6px" }}>
|
|
77
|
+
<Text style={logoStyle}>TRACKED</Text>
|
|
78
|
+
</td>
|
|
79
|
+
</tr>
|
|
80
|
+
</table>
|
|
81
|
+
{showDivider && <Hr style={headerDividerStyle} />}
|
|
82
|
+
</>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const logoStyle = {
|
|
87
|
+
fontSize: "28px",
|
|
88
|
+
fontWeight: "900" as const,
|
|
89
|
+
fontFamily: typography.brandFont,
|
|
90
|
+
color: colors.textPrimary,
|
|
91
|
+
margin: "0",
|
|
92
|
+
lineHeight: "32px",
|
|
93
|
+
letterSpacing: "-0.5px",
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const headerDividerStyle = {
|
|
97
|
+
borderColor: colors.border,
|
|
98
|
+
margin: `${spacing.lg} 0`,
|
|
99
|
+
borderWidth: "1px",
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ============================================
|
|
103
|
+
// EmailFooter - Copyright and links
|
|
104
|
+
// ============================================
|
|
105
|
+
interface EmailFooterProps {
|
|
106
|
+
websiteUrl?: string;
|
|
107
|
+
marketing?: boolean;
|
|
108
|
+
unsubscribeUrl?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const EmailFooter = ({
|
|
112
|
+
websiteUrl = defaultWebsiteUrl,
|
|
113
|
+
marketing = false,
|
|
114
|
+
unsubscribeUrl,
|
|
115
|
+
}: EmailFooterProps) => {
|
|
116
|
+
return (
|
|
117
|
+
<>
|
|
118
|
+
<Hr style={footerDividerStyle} />
|
|
119
|
+
<AppStoreButtons />
|
|
120
|
+
<Text style={footerTextStyle}>
|
|
121
|
+
Copyright © {new Date().getFullYear()} Tracked Training Platform Inc.{" "}
|
|
122
|
+
<br />
|
|
123
|
+
9101 Horne Street, Vancouver, BC
|
|
124
|
+
</Text>
|
|
125
|
+
<Section style={{ textAlign: "center" as const }}>
|
|
126
|
+
<Link href={`${websiteUrl}/terms`} style={footerLinkStyle}>
|
|
127
|
+
Terms
|
|
128
|
+
</Link>
|
|
129
|
+
<Text style={footerDividerTextStyle}> | </Text>
|
|
130
|
+
<Link href={`${websiteUrl}/privacy`} style={footerLinkStyle}>
|
|
131
|
+
Privacy
|
|
132
|
+
</Link>
|
|
133
|
+
<Text style={footerDividerTextStyle}> | </Text>
|
|
134
|
+
<Link href={`${websiteUrl}/support`} style={footerLinkStyle}>
|
|
135
|
+
Support
|
|
136
|
+
</Link>
|
|
137
|
+
{marketing && unsubscribeUrl && (
|
|
138
|
+
<>
|
|
139
|
+
<Text style={footerDividerTextStyle}> | </Text>
|
|
140
|
+
<Link href={unsubscribeUrl} style={footerLinkStyle}>
|
|
141
|
+
Unsubscribe
|
|
142
|
+
</Link>
|
|
143
|
+
</>
|
|
144
|
+
)}
|
|
145
|
+
</Section>
|
|
146
|
+
<Text style={footerDisclaimerStyle}>
|
|
147
|
+
{marketing
|
|
148
|
+
? "You're receiving this email because you opted in to marketing communications from Tracked."
|
|
149
|
+
: "This is a service notification by the Tracked Training Platform."}
|
|
150
|
+
</Text>
|
|
151
|
+
</>
|
|
152
|
+
);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const footerDividerStyle = {
|
|
156
|
+
borderColor: colors.border,
|
|
157
|
+
margin: `${spacing.lg} 0`,
|
|
158
|
+
borderWidth: "1px",
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const footerTextStyle = {
|
|
162
|
+
color: colors.textMuted,
|
|
163
|
+
fontSize: "12px",
|
|
164
|
+
lineHeight: "16px",
|
|
165
|
+
textAlign: "center" as const,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const footerLinkStyle = {
|
|
169
|
+
color: colors.textMuted,
|
|
170
|
+
fontSize: "12px",
|
|
171
|
+
textDecoration: "none",
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const footerDividerTextStyle = {
|
|
175
|
+
color: colors.textMuted,
|
|
176
|
+
fontSize: "12px",
|
|
177
|
+
display: "inline" as const,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const footerDisclaimerStyle = {
|
|
181
|
+
color: colors.textMuted,
|
|
182
|
+
fontSize: "12px",
|
|
183
|
+
lineHeight: "16px",
|
|
184
|
+
textAlign: "center" as const,
|
|
185
|
+
marginTop: spacing.md,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// ============================================
|
|
189
|
+
// ContentSection - Padded content wrapper
|
|
190
|
+
// ============================================
|
|
191
|
+
interface ContentSectionProps {
|
|
192
|
+
children: React.ReactNode;
|
|
193
|
+
style?: React.CSSProperties;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export const ContentSection = ({ children, style }: ContentSectionProps) => {
|
|
197
|
+
return <Section style={{ marginBottom: spacing.lg, ...style }}>{children}</Section>;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// ============================================
|
|
201
|
+
// Divider - Horizontal rule
|
|
202
|
+
// ============================================
|
|
203
|
+
interface DividerProps {
|
|
204
|
+
accent?: boolean;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export const Divider = ({ accent = false }: DividerProps) => {
|
|
208
|
+
return (
|
|
209
|
+
<Hr
|
|
210
|
+
style={{
|
|
211
|
+
borderColor: accent ? colors.borderAccent : colors.border,
|
|
212
|
+
margin: `${spacing.lg} 0`,
|
|
213
|
+
borderWidth: "1px",
|
|
214
|
+
}}
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design tokens for email templates
|
|
3
|
+
* Light/professional theme
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const colors = {
|
|
7
|
+
// Backgrounds
|
|
8
|
+
background: "#ffffff",
|
|
9
|
+
surface: "#f8fafc", // slate-50
|
|
10
|
+
surfaceAlt: "#f1f5f9", // slate-100
|
|
11
|
+
|
|
12
|
+
// Text
|
|
13
|
+
textPrimary: "#0f172a", // slate-900
|
|
14
|
+
textSecondary: "#475569", // slate-600
|
|
15
|
+
textMuted: "#94a3b8", // slate-400
|
|
16
|
+
|
|
17
|
+
// Brand
|
|
18
|
+
primary: "#0f172a", // dark navy for buttons
|
|
19
|
+
accent: "#10b981", // emerald-500 for highlights
|
|
20
|
+
discord: "#5865F2",
|
|
21
|
+
youtube: "#FF0000",
|
|
22
|
+
tiktok: "#000000",
|
|
23
|
+
instagram: "#E4405F",
|
|
24
|
+
|
|
25
|
+
// Borders
|
|
26
|
+
border: "#e2e8f0", // slate-200
|
|
27
|
+
borderStrong: "#cbd5e1", // slate-300
|
|
28
|
+
borderAccent: "#10b981", // emerald-500
|
|
29
|
+
|
|
30
|
+
// Status
|
|
31
|
+
success: "#10b981", // emerald-500
|
|
32
|
+
error: "#ef4444", // red-500
|
|
33
|
+
warning: "#f59e0b", // amber-500
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const typography = {
|
|
37
|
+
fontFamily:
|
|
38
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
39
|
+
brandFont:
|
|
40
|
+
'Raleway, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const spacing = {
|
|
44
|
+
xs: "4px",
|
|
45
|
+
sm: "8px",
|
|
46
|
+
md: "16px",
|
|
47
|
+
lg: "24px",
|
|
48
|
+
xl: "32px",
|
|
49
|
+
xxl: "48px",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const borderRadius = {
|
|
53
|
+
sm: "4px",
|
|
54
|
+
md: "8px",
|
|
55
|
+
lg: "12px",
|
|
56
|
+
full: "9999px",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Base styles used across components
|
|
60
|
+
export const baseStyles = {
|
|
61
|
+
main: {
|
|
62
|
+
backgroundColor: colors.background,
|
|
63
|
+
fontFamily: typography.fontFamily,
|
|
64
|
+
},
|
|
65
|
+
container: {
|
|
66
|
+
backgroundColor: colors.background,
|
|
67
|
+
margin: "0 auto",
|
|
68
|
+
padding: "20px 0 48px",
|
|
69
|
+
maxWidth: "600px",
|
|
70
|
+
},
|
|
71
|
+
box: {
|
|
72
|
+
padding: "0 24px",
|
|
73
|
+
},
|
|
74
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Text, Heading as EmailHeading } from "@react-email/components";
|
|
3
|
+
import { colors, spacing } from "./tokens";
|
|
4
|
+
|
|
5
|
+
// ============================================
|
|
6
|
+
// Heading - Title text with variants
|
|
7
|
+
// ============================================
|
|
8
|
+
interface HeadingProps {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
as?: "h1" | "h2" | "h3";
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const Heading = ({ children, as = "h1", style }: HeadingProps) => {
|
|
15
|
+
const baseStyle = headingStyles[as];
|
|
16
|
+
return (
|
|
17
|
+
<EmailHeading as={as} style={{ ...baseStyle, ...style }}>
|
|
18
|
+
{children}
|
|
19
|
+
</EmailHeading>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const headingStyles = {
|
|
24
|
+
h1: {
|
|
25
|
+
color: colors.textPrimary,
|
|
26
|
+
fontSize: "24px",
|
|
27
|
+
lineHeight: "32px",
|
|
28
|
+
fontWeight: "bold" as const,
|
|
29
|
+
marginBottom: spacing.md,
|
|
30
|
+
marginTop: "0",
|
|
31
|
+
},
|
|
32
|
+
h2: {
|
|
33
|
+
color: colors.textPrimary,
|
|
34
|
+
fontSize: "20px",
|
|
35
|
+
lineHeight: "28px",
|
|
36
|
+
fontWeight: "600" as const,
|
|
37
|
+
marginBottom: spacing.sm,
|
|
38
|
+
marginTop: "0",
|
|
39
|
+
},
|
|
40
|
+
h3: {
|
|
41
|
+
color: colors.textPrimary,
|
|
42
|
+
fontSize: "16px",
|
|
43
|
+
lineHeight: "24px",
|
|
44
|
+
fontWeight: "600" as const,
|
|
45
|
+
marginBottom: spacing.sm,
|
|
46
|
+
marginTop: "0",
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// ============================================
|
|
51
|
+
// Paragraph - Standard body text
|
|
52
|
+
// ============================================
|
|
53
|
+
interface ParagraphProps {
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
muted?: boolean;
|
|
56
|
+
style?: React.CSSProperties;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const Paragraph = ({ children, muted = false, style }: ParagraphProps) => {
|
|
60
|
+
return (
|
|
61
|
+
<Text
|
|
62
|
+
style={{
|
|
63
|
+
color: muted ? colors.textSecondary : colors.textPrimary,
|
|
64
|
+
fontSize: "16px",
|
|
65
|
+
lineHeight: "24px",
|
|
66
|
+
textAlign: "left" as const,
|
|
67
|
+
margin: `0 0 ${spacing.md} 0`,
|
|
68
|
+
...style,
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
</Text>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// ============================================
|
|
77
|
+
// Label - Small muted text for labels
|
|
78
|
+
// ============================================
|
|
79
|
+
interface LabelProps {
|
|
80
|
+
children: React.ReactNode;
|
|
81
|
+
style?: React.CSSProperties;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const Label = ({ children, style }: LabelProps) => {
|
|
85
|
+
return (
|
|
86
|
+
<Text
|
|
87
|
+
style={{
|
|
88
|
+
color: colors.textMuted,
|
|
89
|
+
fontSize: "14px",
|
|
90
|
+
lineHeight: "20px",
|
|
91
|
+
margin: "0",
|
|
92
|
+
...style,
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{children}
|
|
96
|
+
</Text>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// ============================================
|
|
101
|
+
// HighlightText - Accent-colored text
|
|
102
|
+
// ============================================
|
|
103
|
+
interface HighlightTextProps {
|
|
104
|
+
children: React.ReactNode;
|
|
105
|
+
style?: React.CSSProperties;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const HighlightText = ({ children, style }: HighlightTextProps) => {
|
|
109
|
+
return (
|
|
110
|
+
<Text
|
|
111
|
+
style={{
|
|
112
|
+
color: colors.accent,
|
|
113
|
+
fontSize: "16px",
|
|
114
|
+
fontWeight: "600" as const,
|
|
115
|
+
lineHeight: "24px",
|
|
116
|
+
margin: "0",
|
|
117
|
+
...style,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{children}
|
|
121
|
+
</Text>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// ============================================
|
|
126
|
+
// SmallText - Smaller body text
|
|
127
|
+
// ============================================
|
|
128
|
+
interface SmallTextProps {
|
|
129
|
+
children: React.ReactNode;
|
|
130
|
+
muted?: boolean;
|
|
131
|
+
style?: React.CSSProperties;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const SmallText = ({ children, muted = false, style }: SmallTextProps) => {
|
|
135
|
+
return (
|
|
136
|
+
<Text
|
|
137
|
+
style={{
|
|
138
|
+
color: muted ? colors.textMuted : colors.textSecondary,
|
|
139
|
+
fontSize: "14px",
|
|
140
|
+
lineHeight: "20px",
|
|
141
|
+
margin: "0",
|
|
142
|
+
...style,
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
{children}
|
|
146
|
+
</Text>
|
|
147
|
+
);
|
|
148
|
+
};
|