react-email 1.4.2-canary.2 → 1.4.2-canary.3

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.
Files changed (72) hide show
  1. package/dist/commands/dev.js +33 -13
  2. package/package.json +2 -2
  3. package/readme.md +44 -0
  4. package/source/commands/dev.ts +50 -17
  5. package/.react-email/next-env.d.ts +0 -0
  6. package/.react-email/package.json +0 -0
  7. package/.react-email/postcss.config.js +0 -0
  8. package/.react-email/src/components/button.tsx +0 -0
  9. package/.react-email/src/components/code.tsx +0 -0
  10. package/.react-email/src/components/heading.tsx +0 -0
  11. package/.react-email/src/components/icon-base.tsx +0 -0
  12. package/.react-email/src/components/icon-button.tsx +0 -0
  13. package/.react-email/src/components/icon-check.tsx +0 -0
  14. package/.react-email/src/components/icon-clipboard.tsx +0 -0
  15. package/.react-email/src/components/icon-download.tsx +0 -0
  16. package/.react-email/src/components/index.ts +0 -0
  17. package/.react-email/src/components/layout.tsx +0 -0
  18. package/.react-email/src/components/logo.tsx +0 -0
  19. package/.react-email/src/components/send.tsx +0 -0
  20. package/.react-email/src/components/sidebar.tsx +0 -0
  21. package/.react-email/src/components/text.tsx +0 -0
  22. package/.react-email/src/components/tooltip-content.tsx +0 -0
  23. package/.react-email/src/components/tooltip.tsx +0 -0
  24. package/.react-email/src/components/topbar.tsx +0 -0
  25. package/.react-email/src/pages/_app.tsx +0 -26
  26. package/.react-email/src/pages/_document.tsx +0 -0
  27. package/.react-email/src/pages/index.tsx +0 -0
  28. package/.react-email/src/styles/globals.css +0 -0
  29. package/.react-email/src/utils/as.ts +0 -0
  30. package/.react-email/src/utils/copy-text-to-clipboard.ts +0 -0
  31. package/.react-email/src/utils/index.ts +0 -0
  32. package/.react-email/src/utils/unreachable.ts +0 -0
  33. package/.react-email/tailwind.config.js +0 -0
  34. package/.react-email/tsconfig.json +0 -0
  35. package/emails/airbnb-review.tsx +0 -163
  36. package/emails/dropbox-reset-password.tsx +0 -85
  37. package/emails/google-play-policy-update.tsx +0 -229
  38. package/emails/koala-welcome.tsx +0 -97
  39. package/emails/linear-login-code.tsx +0 -124
  40. package/emails/notion-magic-link.tsx +0 -133
  41. package/emails/plaid-verify-identity.tsx +0 -133
  42. package/emails/raycast-magic-link.tsx +0 -107
  43. package/emails/static/airbnb-logo.png +0 -0
  44. package/emails/static/airbnb-review-user.jpg +0 -0
  45. package/emails/static/chat.png +0 -0
  46. package/emails/static/dropbox.png +0 -0
  47. package/emails/static/google-play-academy.png +0 -0
  48. package/emails/static/google-play-chat.png +0 -0
  49. package/emails/static/google-play-footer.png +0 -0
  50. package/emails/static/google-play-header.png +0 -0
  51. package/emails/static/google-play-icon.png +0 -0
  52. package/emails/static/google-play-logo.png +0 -0
  53. package/emails/static/google-play-pl.png +0 -0
  54. package/emails/static/google-play.png +0 -0
  55. package/emails/static/linear-logo.png +0 -0
  56. package/emails/static/notion-logo.png +0 -0
  57. package/emails/static/plaid.png +0 -0
  58. package/emails/static/raycast-bg.png +0 -0
  59. package/emails/static/raycast-logo.png +0 -0
  60. package/emails/static/stripe-logo.png +0 -0
  61. package/emails/static/twitch-icon-facebook.png +0 -0
  62. package/emails/static/twitch-icon-twitter.png +0 -0
  63. package/emails/static/twitch-logo.png +0 -0
  64. package/emails/static/vercel-arrow.png +0 -0
  65. package/emails/static/vercel-logo.png +0 -0
  66. package/emails/static/yelp-footer.png +0 -0
  67. package/emails/static/yelp-header.png +0 -0
  68. package/emails/static/yelp-logo.png +0 -0
  69. package/emails/stripe-welcome.tsx +0 -152
  70. package/emails/twitch-reset-password.tsx +0 -138
  71. package/emails/vercel-invite-user.tsx +0 -196
  72. package/emails/yelp-recent-login.tsx +0 -158
@@ -104,24 +104,36 @@ const createAppFiles = async () => {
104
104
  }
105
105
  };
106
106
  const generateEmailsPreview = async () => {
107
- const spinner = (0, ora_1.default)('Generating emails preview').start();
108
- const hasEmailsDirectory = fs_1.default.existsSync(utils_1.CLIENT_EMAILS_PATH);
107
+ try {
108
+ const spinner = (0, ora_1.default)('Generating emails preview').start();
109
+ await createEmailPreviews();
110
+ await createStatisFiles();
111
+ await createComponents();
112
+ spinner.stopAndPersist({
113
+ symbol: log_symbols_1.default.success,
114
+ text: 'Emails preview generated',
115
+ });
116
+ }
117
+ catch (error) {
118
+ console.log({ error });
119
+ }
120
+ };
121
+ const createEmailPreviews = async () => {
122
+ const hasEmailsDirectory = (0, utils_1.checkDirectoryExist)(utils_1.CLIENT_EMAILS_PATH);
109
123
  const isEmailsDirectoryEmpty = hasEmailsDirectory
110
124
  ? await (0, utils_1.checkEmptyDirectory)(utils_1.CLIENT_EMAILS_PATH)
111
125
  : true;
112
126
  if (isEmailsDirectoryEmpty) {
113
- return spinner.stopAndPersist({
114
- symbol: log_symbols_1.default.warning,
115
- text: 'Emails preview directory is empty',
116
- });
117
127
  }
118
128
  const hasPackageEmailsDirectory = (0, utils_1.checkDirectoryExist)(utils_1.PACKAGE_EMAILS_PATH);
119
- const hasPackageStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.REACT_EMAIL_ROOT}/public/static`);
120
- const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/static`);
121
129
  if (hasPackageEmailsDirectory) {
122
130
  await fs_1.default.promises.rm(utils_1.PACKAGE_EMAILS_PATH, { recursive: true });
123
131
  }
124
132
  await (0, cpy_1.default)(`${utils_1.CLIENT_EMAILS_PATH}/*{.tsx,.jsx}`, utils_1.PACKAGE_EMAILS_PATH);
133
+ };
134
+ const createStatisFiles = async () => {
135
+ const hasPackageStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.REACT_EMAIL_ROOT}/public/static`);
136
+ const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/static`);
125
137
  if (hasPackageStaticDirectory) {
126
138
  await fs_1.default.promises.rm(`${utils_1.REACT_EMAIL_ROOT}/public/static`, {
127
139
  recursive: true,
@@ -130,10 +142,18 @@ const generateEmailsPreview = async () => {
130
142
  if (hasStaticDirectory) {
131
143
  await (0, cpy_1.default)(`${utils_1.CLIENT_EMAILS_PATH}/static`, `${utils_1.REACT_EMAIL_ROOT}/public/static`);
132
144
  }
133
- return spinner.stopAndPersist({
134
- symbol: log_symbols_1.default.success,
135
- text: 'Emails preview generated',
136
- });
145
+ };
146
+ const createComponents = async () => {
147
+ const hasPackageComponentsDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.PACKAGE_EMAILS_PATH}/components`);
148
+ const hasComponentsDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/components`);
149
+ if (hasPackageComponentsDirectory) {
150
+ await fs_1.default.promises.rm(`${utils_1.PACKAGE_EMAILS_PATH}/components`, {
151
+ recursive: true,
152
+ });
153
+ }
154
+ if (hasComponentsDirectory) {
155
+ await (0, cpy_1.default)(`${utils_1.CLIENT_EMAILS_PATH}/components`, `${utils_1.PACKAGE_EMAILS_PATH}/components`);
156
+ }
137
157
  };
138
158
  const syncPkg = async () => {
139
159
  const previewPkg = (0, utils_1.getPreviewPkg)();
@@ -148,7 +168,7 @@ const syncPkg = async () => {
148
168
  await fs_1.default.promises.writeFile(path_1.default.join(utils_1.REACT_EMAIL_ROOT, 'package.json'), JSON.stringify(pkg));
149
169
  };
150
170
  const installDependencies = async () => {
151
- const spinner = (0, ora_1.default)('Installing dependencies...').start();
171
+ const spinner = (0, ora_1.default)('Installing dependencies...\n').start();
152
172
  shelljs_1.default.cd(path_1.default.join(utils_1.REACT_EMAIL_ROOT));
153
173
  shelljs_1.default.exec('yarn');
154
174
  spinner.stopAndPersist({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.4.2-canary.2",
3
+ "version": "1.4.2-canary.3",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/index.js"
@@ -48,4 +48,4 @@
48
48
  "prettier": "2.7.1",
49
49
  "ts-node": "10.9.1"
50
50
  }
51
- }
51
+ }
package/readme.md CHANGED
@@ -0,0 +1,44 @@
1
+ ![React email cover](https://react.email/static/covers/react-email.png)
2
+
3
+ <div align="center"><strong>React Email</strong></div>
4
+ <div align="center">The next generation of writing emails.<br />High-quality, unstyled components for creating emails.</div>
5
+ <br />
6
+ <div align="center">
7
+ <a href="https://react.email">Website</a>
8
+ <span> · </span>
9
+ <a href="https://github.com/zenorocha/react-email">GitHub</a>
10
+ <span> · </span>
11
+ <a href="https://react.email/discord">Discord</a>
12
+ </div>
13
+
14
+ ## Getting started
15
+
16
+ To get started, open a new shell and run:
17
+
18
+ ```sh
19
+ npx create-email
20
+ ```
21
+
22
+ This will create a new folder called `emails` with a few email templates.
23
+
24
+ ## Commands
25
+
26
+ ### `email dev`
27
+
28
+ Starts a local development server that will watch your files and automatically rebuild your email when you make changes.
29
+
30
+ ```sh
31
+ npx react-email dev
32
+ ```
33
+
34
+ ### `email export`
35
+
36
+ Generates the plain HTML files of your emails into a `out` directory.
37
+
38
+ ```sh
39
+ npx react-email export
40
+ ```
41
+
42
+ ## License
43
+
44
+ MIT License
@@ -122,33 +122,48 @@ const createAppFiles = async () => {
122
122
  };
123
123
 
124
124
  const generateEmailsPreview = async () => {
125
- const spinner = ora('Generating emails preview').start();
125
+ try {
126
+ const spinner = ora('Generating emails preview').start();
127
+
128
+ await createEmailPreviews();
129
+ await createStatisFiles();
130
+ await createComponents();
131
+
132
+ spinner.stopAndPersist({
133
+ symbol: logSymbols.success,
134
+ text: 'Emails preview generated',
135
+ });
136
+ } catch (error) {
137
+ console.log({ error });
138
+ }
139
+ };
140
+
141
+ const createEmailPreviews = async () => {
142
+ const hasEmailsDirectory = checkDirectoryExist(CLIENT_EMAILS_PATH);
126
143
 
127
- const hasEmailsDirectory = fs.existsSync(CLIENT_EMAILS_PATH);
128
144
  const isEmailsDirectoryEmpty = hasEmailsDirectory
129
145
  ? await checkEmptyDirectory(CLIENT_EMAILS_PATH)
130
146
  : true;
131
147
 
132
148
  if (isEmailsDirectoryEmpty) {
133
- return spinner.stopAndPersist({
134
- symbol: logSymbols.warning,
135
- text: 'Emails preview directory is empty',
136
- });
137
149
  }
138
150
 
139
151
  const hasPackageEmailsDirectory = checkDirectoryExist(PACKAGE_EMAILS_PATH);
140
- const hasPackageStaticDirectory = checkDirectoryExist(
141
- `${REACT_EMAIL_ROOT}/public/static`,
142
- );
143
- const hasStaticDirectory = checkDirectoryExist(
144
- `${CLIENT_EMAILS_PATH}/static`,
145
- );
146
152
 
147
153
  if (hasPackageEmailsDirectory) {
148
154
  await fs.promises.rm(PACKAGE_EMAILS_PATH, { recursive: true });
149
155
  }
150
156
 
151
157
  await copy(`${CLIENT_EMAILS_PATH}/*{.tsx,.jsx}`, PACKAGE_EMAILS_PATH);
158
+ };
159
+
160
+ const createStatisFiles = async () => {
161
+ const hasPackageStaticDirectory = checkDirectoryExist(
162
+ `${REACT_EMAIL_ROOT}/public/static`,
163
+ );
164
+ const hasStaticDirectory = checkDirectoryExist(
165
+ `${CLIENT_EMAILS_PATH}/static`,
166
+ );
152
167
 
153
168
  if (hasPackageStaticDirectory) {
154
169
  await fs.promises.rm(`${REACT_EMAIL_ROOT}/public/static`, {
@@ -162,11 +177,29 @@ const generateEmailsPreview = async () => {
162
177
  `${REACT_EMAIL_ROOT}/public/static`,
163
178
  );
164
179
  }
180
+ };
165
181
 
166
- return spinner.stopAndPersist({
167
- symbol: logSymbols.success,
168
- text: 'Emails preview generated',
169
- });
182
+ const createComponents = async () => {
183
+ const hasPackageComponentsDirectory = checkDirectoryExist(
184
+ `${PACKAGE_EMAILS_PATH}/components`,
185
+ );
186
+
187
+ const hasComponentsDirectory = checkDirectoryExist(
188
+ `${CLIENT_EMAILS_PATH}/components`,
189
+ );
190
+
191
+ if (hasPackageComponentsDirectory) {
192
+ await fs.promises.rm(`${PACKAGE_EMAILS_PATH}/components`, {
193
+ recursive: true,
194
+ });
195
+ }
196
+
197
+ if (hasComponentsDirectory) {
198
+ await copy(
199
+ `${CLIENT_EMAILS_PATH}/components`,
200
+ `${PACKAGE_EMAILS_PATH}/components`,
201
+ );
202
+ }
170
203
  };
171
204
 
172
205
  const syncPkg = async () => {
@@ -186,7 +219,7 @@ const syncPkg = async () => {
186
219
  };
187
220
 
188
221
  const installDependencies = async () => {
189
- const spinner = ora('Installing dependencies...').start();
222
+ const spinner = ora('Installing dependencies...\n').start();
190
223
 
191
224
  shell.cd(path.join(REACT_EMAIL_ROOT));
192
225
  shell.exec('yarn');
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,26 +0,0 @@
1
- import '../styles/globals.css';
2
- import type { AppProps } from 'next/app';
3
- import { Inter } from '@next/font/google';
4
- import classnames from 'classnames';
5
- import Head from 'next/head';
6
- import { Tooltip } from '../components/tooltip';
7
-
8
- export const inter = Inter({
9
- subsets: ['latin'],
10
- variable: '--font-inter',
11
- });
12
-
13
- function MyApp({ Component, pageProps }: AppProps) {
14
- return (
15
- <div className={classnames(inter.variable, 'font-sans')}>
16
- <Head>
17
- <title>React Email</title>
18
- </Head>
19
- <Tooltip.Provider>
20
- <Component {...pageProps} />
21
- </Tooltip.Provider>
22
- </div>
23
- );
24
- }
25
-
26
- export default MyApp;
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,163 +0,0 @@
1
- import { Button } from '@react-email/button';
2
- import { Container } from '@react-email/container';
3
- import { Head } from '@react-email/head';
4
- import { Hr } from '@react-email/hr';
5
- import { Html } from '@react-email/html';
6
- import { Img } from '@react-email/img';
7
- import { Link } from '@react-email/link';
8
- import { Preview } from '@react-email/preview';
9
- import { Section } from '@react-email/section';
10
- import { Text } from '@react-email/text';
11
- import * as React from 'react';
12
-
13
- export default function Email() {
14
- return (
15
- <Html>
16
- <Head />
17
- <Preview>Read Alex's review</Preview>
18
- <Section style={main}>
19
- <Container style={container}>
20
- <Img
21
- src="/static/airbnb-logo.png"
22
- width="96"
23
- height="30"
24
- alt="Airbnb"
25
- />
26
- <Section>
27
- <Img
28
- src="/static/airbnb-review-user.jpg"
29
- width="96"
30
- height="96"
31
- alt="Alex"
32
- style={userImage}
33
- />
34
- </Section>
35
- <Text style={heading}>Here's what Alex wrote</Text>
36
- <Text style={review}>
37
- “Zeno was a great guest! Easy communication, the apartment was left
38
- in great condition, very polite, and respectful of all house rules.
39
- He’s welcome back anytime and would easily recommend him to any
40
- host!”
41
- </Text>
42
- <Text style={paragraph}>
43
- Now that the review period is over, we’ve posted Alex’s review to
44
- your Airbnb profile.
45
- </Text>
46
- <Text style={paragraph}>
47
- While it’s too late to write a review of your own, you can send your
48
- feedback to Alex using your Airbnb message thread.
49
- </Text>
50
- <Section style={{ padding: '16px 0 20px' }}>
51
- <Button pY={19} style={button} href="https://airbnb.com/">
52
- Send My Feedback
53
- </Button>
54
- </Section>
55
- <Hr style={hr} />
56
- <Text style={{ ...paragraph, fontWeight: '700' }}>
57
- Commom questions
58
- </Text>
59
- <Text>
60
- <Link href="https://airbnb.com/help/article/13" style={link}>
61
- How do reviews work?
62
- </Link>
63
- </Text>
64
- <Text>
65
- <Link href="https://airbnb.com/help/article/1257" style={link}>
66
- How do star ratings work?
67
- </Link>
68
- </Text>
69
- <Text>
70
- <Link href="https://airbnb.com/help/article/995" style={link}>
71
- Can I leave a review after 14 days?
72
- </Link>
73
- </Text>
74
- <Hr style={hr} />
75
- <Text style={footer}>
76
- Airbnb, Inc., 888 Brannan St, San Francisco, CA 94103
77
- </Text>
78
- <Link href="https://airbnb.com" style={reportLink}>
79
- Report unsafe behavior
80
- </Link>
81
- </Container>
82
- </Section>
83
- </Html>
84
- );
85
- }
86
-
87
- const fontFamily =
88
- '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
89
-
90
- const main = {
91
- backgroundColor: '#ffffff',
92
- };
93
-
94
- const container = {
95
- margin: '0 auto',
96
- padding: '20px 0 48px',
97
- width: '580px',
98
- };
99
-
100
- const userImage = {
101
- margin: '0 auto',
102
- marginBottom: '16px',
103
- borderRadius: '50%',
104
- };
105
-
106
- const heading = {
107
- fontFamily,
108
- fontSize: '32px',
109
- lineHeight: '1.3',
110
- fontWeight: '700',
111
- color: '#484848',
112
- };
113
-
114
- const paragraph = {
115
- fontFamily,
116
- fontSize: '18px',
117
- lineHeight: '1.4',
118
- color: '#484848',
119
- };
120
-
121
- const review = {
122
- ...paragraph,
123
- padding: '24px',
124
- backgroundColor: '#f2f3f3',
125
- borderRadius: '4px',
126
- };
127
-
128
- const button = {
129
- fontFamily,
130
- backgroundColor: '#ff5a5f',
131
- borderRadius: '3px',
132
- color: '#fff',
133
- fontSize: '18px',
134
- textDecoration: 'none',
135
- textAlign: 'center' as const,
136
- display: 'block',
137
- width: '100%',
138
- };
139
-
140
- const link = {
141
- ...paragraph,
142
- color: '#ff5a5f',
143
- display: 'block',
144
- };
145
-
146
- const reportLink = {
147
- fontFamily,
148
- fontSize: '14px',
149
- color: '#9ca299',
150
- textDecoration: 'underline',
151
- };
152
-
153
- const hr = {
154
- borderColor: '#cccccc',
155
- margin: '20px 0',
156
- };
157
-
158
- const footer = {
159
- fontFamily,
160
- color: '#9ca299',
161
- fontSize: '14px',
162
- marginBottom: '10px',
163
- };
@@ -1,85 +0,0 @@
1
- import { Button } from '@react-email/button';
2
- import { Container } from '@react-email/container';
3
- import { Head } from '@react-email/head';
4
- import { Html } from '@react-email/html';
5
- import { Img } from '@react-email/img';
6
- import { Link } from '@react-email/link';
7
- import { Preview } from '@react-email/preview';
8
- import { Section } from '@react-email/section';
9
- import { Text } from '@react-email/text';
10
- import * as React from 'react';
11
-
12
- export default function Email() {
13
- return (
14
- <Html>
15
- <Head />
16
- <Preview>Dropbox reset your password</Preview>
17
- <Section style={main}>
18
- <Container style={container}>
19
- <Img src="/static/dropbox.png" width="40" height="33" alt="Dropbox" />
20
- <Section>
21
- <Text style={text}>Hi Zeno,</Text>
22
- <Text style={text}>
23
- Someone recently requested a password change for your Dropbox
24
- account. If this was you, you can set a new password here:
25
- </Text>
26
- <Button style={button} href="https://dropbox.com">
27
- Reset password
28
- </Button>
29
- <Text style={text}>
30
- If you don&apos;t want to change your password or didn&apos;t
31
- request this, just ignore and delete this message.
32
- </Text>
33
- <Text style={text}>
34
- To keep your account secure, please don&apos;t forward this email
35
- to anyone. See our Help Center for{' '}
36
- <Link style={anchor} href="https://dropbox.com">
37
- more security tips.
38
- </Link>
39
- </Text>
40
- <Text style={text}>Happy Dropboxing!</Text>
41
- </Section>
42
- </Container>
43
- </Section>
44
- </Html>
45
- );
46
- }
47
-
48
- const main = {
49
- backgroundColor: '#f6f9fc',
50
- padding: '10px 0',
51
- };
52
-
53
- const container = {
54
- margin: '0 auto',
55
- backgroundColor: '#ffffff',
56
- border: '1px solid #f0f0f0',
57
- width: '600px',
58
- padding: '45px',
59
- };
60
-
61
- const text = {
62
- fontSize: '16px',
63
- fontFamily:
64
- "'Open Sans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif",
65
- fontWeight: '300',
66
- color: '#404040',
67
- lineHeight: '26px',
68
- };
69
-
70
- const button = {
71
- backgroundColor: '#007ee6',
72
- borderRadius: '4px',
73
- color: '#fff',
74
- fontFamily: "'Open Sans', 'Helvetica Neue', Arial",
75
- fontSize: '15px',
76
- textDecoration: 'none',
77
- textAlign: 'center' as const,
78
- display: 'block',
79
- width: '210px',
80
- padding: '14px 7px',
81
- };
82
-
83
- const anchor = {
84
- textDecoration: 'underline',
85
- };