Skip to content

Commit 54c97fd

Browse files
committed
feat(email): welcome email; improvement(emails): ui/ux
1 parent 4da128d commit 54c97fd

25 files changed

+1144
-1059
lines changed

apps/sim/app/api/help/route.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ ${message}
118118
// Send confirmation email to the user
119119
try {
120120
const confirmationHtml = await renderHelpConfirmationEmail(
121-
email,
122121
type as 'bug' | 'feedback' | 'feature_request' | 'other',
123122
images.length
124123
)

apps/sim/app/api/organizations/[id]/invitations/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
376376
const emailHtml = await renderInvitationEmail(
377377
inviter[0]?.name || 'Someone',
378378
organizationEntry[0]?.name || 'organization',
379-
`${getBaseUrl()}/invite/${orgInvitation.id}`,
380-
email
379+
`${getBaseUrl()}/invite/${orgInvitation.id}`
381380
)
382381

383382
emailResult = await sendEmail({

apps/sim/app/api/organizations/[id]/members/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
260260
const emailHtml = await renderInvitationEmail(
261261
inviter[0]?.name || 'Someone',
262262
organizationEntry[0]?.name || 'organization',
263-
`${getBaseUrl()}/invite/organization?id=${invitationId}`,
264-
normalizedEmail
263+
`${getBaseUrl()}/invite/organization?id=${invitationId}`
265264
)
266265

267266
const emailResult = await sendEmail({
Lines changed: 202 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,246 @@
1-
// Base styles for all email templates
1+
/**
2+
* Base styles for all email templates.
3+
* Colors are derived from globals.css light mode tokens.
4+
*/
5+
6+
/** Color tokens from globals.css (light mode) */
7+
export const colors = {
8+
/** Main canvas background */
9+
bgOuter: '#F7F9FC',
10+
/** Card/container background - pure white */
11+
bgCard: '#ffffff',
12+
/** Primary text color */
13+
textPrimary: '#2d2d2d',
14+
/** Secondary text color */
15+
textSecondary: '#404040',
16+
/** Tertiary text color */
17+
textTertiary: '#5c5c5c',
18+
/** Muted text (footer) */
19+
textMuted: '#737373',
20+
/** Brand primary - purple */
21+
brandPrimary: '#6f3dfa',
22+
/** Brand tertiary - green (matches Run/Deploy buttons) */
23+
brandTertiary: '#32bd7e',
24+
/** Border/divider color */
25+
divider: '#ededed',
26+
/** Footer background */
27+
footerBg: '#F7F9FC',
28+
}
29+
30+
/** Typography settings */
31+
export const typography = {
32+
fontFamily: "-apple-system, 'SF Pro Display', 'SF Pro Text', 'Helvetica', sans-serif",
33+
fontSize: {
34+
body: '16px',
35+
small: '14px',
36+
caption: '12px',
37+
},
38+
lineHeight: {
39+
body: '24px',
40+
caption: '20px',
41+
},
42+
}
43+
44+
/** Spacing values */
45+
export const spacing = {
46+
containerWidth: 600,
47+
gutter: 40,
48+
sectionGap: 20,
49+
paragraphGap: 12,
50+
/** Logo width in pixels */
51+
logoWidth: 90,
52+
}
253

354
export const baseStyles = {
4-
fontFamily: 'HelveticaNeue, Helvetica, Arial, sans-serif',
55+
fontFamily: typography.fontFamily,
56+
57+
/** Main body wrapper with outer background */
558
main: {
6-
backgroundColor: '#f5f5f7',
7-
fontFamily: 'HelveticaNeue, Helvetica, Arial, sans-serif',
59+
backgroundColor: colors.bgOuter,
60+
fontFamily: typography.fontFamily,
61+
padding: '32px 0',
62+
},
63+
64+
/** Center wrapper for email content */
65+
wrapper: {
66+
maxWidth: `${spacing.containerWidth}px`,
67+
margin: '0 auto',
868
},
69+
70+
/** Main card container with rounded corners */
971
container: {
10-
maxWidth: '580px',
11-
margin: '30px auto',
12-
backgroundColor: '#ffffff',
13-
borderRadius: '5px',
72+
maxWidth: `${spacing.containerWidth}px`,
73+
margin: '0 auto',
74+
backgroundColor: colors.bgCard,
75+
borderRadius: '16px',
1476
overflow: 'hidden',
1577
},
78+
79+
/** Header section with logo */
1680
header: {
17-
padding: '30px 0',
18-
display: 'flex',
19-
justifyContent: 'center',
20-
alignItems: 'center',
21-
backgroundColor: '#ffffff',
81+
padding: `32px ${spacing.gutter}px 16px ${spacing.gutter}px`,
82+
textAlign: 'left' as const,
2283
},
84+
85+
/** Main content area with horizontal padding */
2386
content: {
24-
padding: '5px 30px 20px 30px',
87+
padding: `0 ${spacing.gutter}px 32px ${spacing.gutter}px`,
2588
},
89+
90+
/** Standard paragraph text */
2691
paragraph: {
27-
fontSize: '16px',
28-
lineHeight: '1.5',
29-
color: '#333333',
30-
margin: '16px 0',
92+
fontSize: typography.fontSize.body,
93+
lineHeight: typography.lineHeight.body,
94+
color: colors.textSecondary,
95+
fontWeight: 400,
96+
fontFamily: typography.fontFamily,
97+
margin: `${spacing.paragraphGap}px 0`,
98+
},
99+
100+
/** Bold label text (e.g., "Platform:", "Time:") */
101+
label: {
102+
fontSize: typography.fontSize.body,
103+
lineHeight: typography.lineHeight.body,
104+
color: colors.textSecondary,
105+
fontWeight: 'bold' as const,
106+
fontFamily: typography.fontFamily,
107+
margin: 0,
108+
display: 'inline',
31109
},
110+
111+
/** Primary CTA button - matches app tertiary button style */
32112
button: {
33113
display: 'inline-block',
34-
backgroundColor: '#6F3DFA',
114+
backgroundColor: colors.brandTertiary,
35115
color: '#ffffff',
36-
fontWeight: 'bold',
37-
fontSize: '16px',
38-
padding: '12px 30px',
116+
fontWeight: 500,
117+
fontSize: '14px',
118+
padding: '6px 12px',
39119
borderRadius: '5px',
40120
textDecoration: 'none',
41121
textAlign: 'center' as const,
42-
margin: '20px 0',
122+
margin: '4px 0',
123+
fontFamily: typography.fontFamily,
43124
},
125+
126+
/** Link text style */
44127
link: {
45-
color: '#6F3DFA',
46-
textDecoration: 'underline',
128+
color: colors.brandTertiary,
129+
fontWeight: 'bold' as const,
130+
textDecoration: 'none',
47131
},
132+
133+
/** Horizontal divider */
134+
divider: {
135+
borderTop: `1px solid ${colors.divider}`,
136+
margin: `16px 0`,
137+
},
138+
139+
/** Footer container (inside gray area below card) */
48140
footer: {
49-
maxWidth: '580px',
141+
maxWidth: `${spacing.containerWidth}px`,
50142
margin: '0 auto',
51-
padding: '20px 0',
52-
textAlign: 'center' as const,
143+
padding: `32px ${spacing.gutter}px`,
144+
textAlign: 'left' as const,
53145
},
146+
147+
/** Footer text style */
54148
footerText: {
55-
fontSize: '12px',
56-
color: '#666666',
57-
margin: '0',
149+
fontSize: typography.fontSize.caption,
150+
lineHeight: typography.lineHeight.caption,
151+
color: colors.textMuted,
152+
fontFamily: typography.fontFamily,
153+
margin: '0 0 10px 0',
58154
},
155+
156+
/** Code/OTP container */
59157
codeContainer: {
60-
margin: '20px 0',
61-
padding: '16px',
158+
margin: '12px 0',
159+
padding: '12px 16px',
62160
backgroundColor: '#f8f9fa',
63-
borderRadius: '5px',
64-
border: '1px solid #eee',
161+
borderRadius: '6px',
162+
border: `1px solid ${colors.divider}`,
65163
textAlign: 'center' as const,
66164
},
165+
166+
/** Code/OTP text */
67167
code: {
68-
fontSize: '28px',
69-
fontWeight: 'bold',
70-
letterSpacing: '4px',
71-
color: '#333333',
168+
fontSize: '24px',
169+
fontWeight: 'bold' as const,
170+
letterSpacing: '3px',
171+
color: colors.textPrimary,
172+
fontFamily: typography.fontFamily,
173+
margin: 0,
174+
},
175+
176+
/** Highlighted info box (e.g., "What you get with Pro") */
177+
infoBox: {
178+
backgroundColor: colors.bgOuter,
179+
padding: '16px 18px',
180+
borderRadius: '6px',
181+
margin: '16px 0',
182+
},
183+
184+
/** Info box title */
185+
infoBoxTitle: {
186+
fontSize: typography.fontSize.body,
187+
lineHeight: typography.lineHeight.body,
188+
fontWeight: 600,
189+
color: colors.textPrimary,
190+
fontFamily: typography.fontFamily,
191+
margin: '0 0 8px 0',
192+
},
193+
194+
/** Info box list content */
195+
infoBoxList: {
196+
fontSize: typography.fontSize.body,
197+
lineHeight: '1.6',
198+
color: colors.textSecondary,
199+
fontFamily: typography.fontFamily,
200+
margin: 0,
72201
},
202+
203+
/** Section borders - decorative accent line */
73204
sectionsBorders: {
74205
width: '100%',
75206
display: 'flex',
76207
},
208+
77209
sectionBorder: {
78-
borderBottom: '1px solid #eeeeee',
210+
borderBottom: `1px solid ${colors.divider}`,
79211
width: '249px',
80212
},
213+
81214
sectionCenter: {
82-
borderBottom: '1px solid #6F3DFA',
215+
borderBottom: `1px solid ${colors.brandTertiary}`,
83216
width: '102px',
84217
},
218+
219+
/** Spacer row for vertical spacing in tables */
220+
spacer: {
221+
border: 0,
222+
margin: 0,
223+
padding: 0,
224+
fontSize: '1px',
225+
lineHeight: '1px',
226+
},
227+
228+
/** Gutter cell for horizontal padding in tables */
229+
gutter: {
230+
border: 0,
231+
margin: 0,
232+
padding: 0,
233+
fontSize: '1px',
234+
lineHeight: '1px',
235+
width: `${spacing.gutter}px`,
236+
},
237+
238+
/** Info row (e.g., Platform, Device location, Time) */
239+
infoRow: {
240+
fontSize: typography.fontSize.body,
241+
lineHeight: typography.lineHeight.body,
242+
color: colors.textSecondary,
243+
fontFamily: typography.fontFamily,
244+
margin: '8px 0',
245+
},
85246
}

0 commit comments

Comments
 (0)