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

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 (76) hide show
  1. package/.react-email/next-env.d.ts +0 -0
  2. package/.react-email/package.json +0 -0
  3. package/.react-email/postcss.config.js +0 -0
  4. package/.react-email/src/components/button.tsx +0 -0
  5. package/.react-email/src/components/code.tsx +0 -0
  6. package/.react-email/src/components/heading.tsx +0 -0
  7. package/.react-email/src/components/icon-base.tsx +0 -0
  8. package/.react-email/src/components/icon-button.tsx +0 -0
  9. package/.react-email/src/components/icon-check.tsx +0 -0
  10. package/.react-email/src/components/icon-clipboard.tsx +0 -0
  11. package/.react-email/src/components/icon-download.tsx +0 -0
  12. package/.react-email/src/components/index.ts +0 -0
  13. package/.react-email/src/components/layout.tsx +0 -0
  14. package/.react-email/src/components/logo.tsx +0 -0
  15. package/.react-email/src/components/send.tsx +0 -0
  16. package/.react-email/src/components/sidebar.tsx +0 -0
  17. package/.react-email/src/components/text.tsx +0 -0
  18. package/.react-email/src/components/tooltip-content.tsx +0 -0
  19. package/.react-email/src/components/tooltip.tsx +0 -0
  20. package/.react-email/src/components/topbar.tsx +0 -0
  21. package/.react-email/src/pages/_app.tsx +26 -0
  22. package/.react-email/src/pages/_document.tsx +0 -0
  23. package/.react-email/src/pages/index.tsx +0 -0
  24. package/.react-email/src/styles/globals.css +0 -0
  25. package/.react-email/src/utils/as.ts +0 -0
  26. package/.react-email/src/utils/copy-text-to-clipboard.ts +0 -0
  27. package/.react-email/src/utils/index.ts +0 -0
  28. package/.react-email/src/utils/unreachable.ts +0 -0
  29. package/.react-email/tailwind.config.js +0 -0
  30. package/.react-email/tsconfig.json +0 -0
  31. package/dist/commands/dev.js +52 -41
  32. package/dist/commands/exportTemplates.js +20 -1
  33. package/dist/utils/watcher.d.ts +1 -0
  34. package/dist/utils/watcher.js +7 -4
  35. package/emails/airbnb-review.tsx +163 -0
  36. package/emails/dropbox-reset-password.tsx +85 -0
  37. package/emails/google-play-policy-update.tsx +229 -0
  38. package/emails/koala-welcome.tsx +97 -0
  39. package/emails/linear-login-code.tsx +124 -0
  40. package/emails/notion-magic-link.tsx +133 -0
  41. package/emails/plaid-verify-identity.tsx +133 -0
  42. package/emails/raycast-magic-link.tsx +107 -0
  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 +152 -0
  70. package/emails/twitch-reset-password.tsx +138 -0
  71. package/emails/vercel-invite-user.tsx +196 -0
  72. package/emails/yelp-recent-login.tsx +158 -0
  73. package/package.json +4 -3
  74. package/source/commands/dev.ts +55 -45
  75. package/source/commands/exportTemplates.ts +28 -1
  76. package/source/utils/watcher.ts +28 -24
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
@@ -0,0 +1,26 @@
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
@@ -18,25 +18,31 @@ const read_pkg_1 = __importDefault(require("read-pkg"));
18
18
  const shelljs_1 = __importDefault(require("shelljs"));
19
19
  const styles_1 = require("../_preview/styles");
20
20
  const dev = async () => {
21
- const hasReactEmailDirectory = (0, utils_1.checkDirectoryExist)(utils_1.REACT_EMAIL_ROOT);
22
- if (hasReactEmailDirectory) {
23
- const isUpToDate = await (0, utils_1.checkPackageIsUpToDate)();
24
- if (isUpToDate) {
25
- await Promise.all([generateEmailsPreview(), syncPkg()]);
26
- await installDependencies();
27
- shelljs_1.default.exec('yarn dev', { async: true });
28
- (0, utils_1.watcher)();
29
- return;
21
+ try {
22
+ const hasReactEmailDirectory = (0, utils_1.checkDirectoryExist)(utils_1.REACT_EMAIL_ROOT);
23
+ if (hasReactEmailDirectory) {
24
+ const isUpToDate = await (0, utils_1.checkPackageIsUpToDate)();
25
+ if (isUpToDate) {
26
+ await Promise.all([generateEmailsPreview(), syncPkg()]);
27
+ await installDependencies();
28
+ shelljs_1.default.exec('yarn dev', { async: true });
29
+ (0, utils_1.watcher)();
30
+ return;
31
+ }
32
+ await fs_1.default.promises.rm(utils_1.REACT_EMAIL_ROOT, { recursive: true });
30
33
  }
31
- await fs_1.default.promises.rm(utils_1.REACT_EMAIL_ROOT, { recursive: true });
34
+ await createBasicStructure();
35
+ await createAppDirectories();
36
+ await createAppFiles();
37
+ await Promise.all([generateEmailsPreview(), syncPkg()]);
38
+ await installDependencies();
39
+ shelljs_1.default.exec('yarn dev', { async: true });
40
+ (0, utils_1.watcher)();
41
+ }
42
+ catch (error) {
43
+ await utils_1.watcherInstance.close();
44
+ shelljs_1.default.exit(1);
32
45
  }
33
- await createBasicStructure();
34
- await createAppDirectories();
35
- await createAppFiles();
36
- await Promise.all([generateEmailsPreview(), syncPkg()]);
37
- await installDependencies();
38
- shelljs_1.default.exec('yarn dev', { async: true });
39
- (0, utils_1.watcher)();
40
46
  };
41
47
  exports.dev = dev;
42
48
  const createBasicStructure = async () => {
@@ -67,30 +73,35 @@ const createAppDirectories = async () => {
67
73
  }
68
74
  };
69
75
  const createAppFiles = async () => {
70
- const creation = (appFiles, name) => {
71
- return appFiles.map((file) => {
72
- const location = name
73
- ? `${utils_1.SRC_PATH}/${name}/${file.title}`
74
- : `${utils_1.REACT_EMAIL_ROOT}/${file.title}`;
75
- return fs_1.default.promises.writeFile(location, file.content);
76
+ try {
77
+ const creation = (appFiles, name) => {
78
+ return appFiles.map((file) => {
79
+ const location = name
80
+ ? `${utils_1.SRC_PATH}/${name}/${file.title}`
81
+ : `${utils_1.REACT_EMAIL_ROOT}/${file.title}`;
82
+ return fs_1.default.promises.writeFile(location, file.content);
83
+ });
84
+ };
85
+ const pageCreation = pages_1.pages.map((page) => {
86
+ const location = page.dir
87
+ ? `${utils_1.SRC_PATH}/pages/${page.dir}/${page.title}`
88
+ : `${utils_1.SRC_PATH}/pages/${page.title}`;
89
+ if (page.dir) {
90
+ (0, utils_1.createDirectory)(`${utils_1.SRC_PATH}/pages/${page.dir}`);
91
+ }
92
+ return fs_1.default.promises.writeFile(location, page.content);
76
93
  });
77
- };
78
- const pageCreation = pages_1.pages.map((page) => {
79
- const location = page.dir
80
- ? `${utils_1.SRC_PATH}/pages/${page.dir}/${page.title}`
81
- : `${utils_1.SRC_PATH}/pages/${page.title}`;
82
- if (page.dir) {
83
- (0, utils_1.createDirectory)(`${utils_1.SRC_PATH}/pages/${page.dir}`);
84
- }
85
- return fs_1.default.promises.writeFile(location, page.content);
86
- });
87
- await Promise.all([
88
- ...creation(utils_2.utils, 'utils'),
89
- ...creation(components_1.components, 'components'),
90
- ...creation(styles_1.styles, 'styles'),
91
- ...creation(root_1.root),
92
- ...pageCreation,
93
- ]);
94
+ await Promise.all([
95
+ ...creation(utils_2.utils, 'utils'),
96
+ ...creation(components_1.components, 'components'),
97
+ ...creation(styles_1.styles, 'styles'),
98
+ ...creation(root_1.root),
99
+ ...pageCreation,
100
+ ]);
101
+ }
102
+ catch (error) {
103
+ throw new Error('Error creating app files');
104
+ }
94
105
  };
95
106
  const generateEmailsPreview = async () => {
96
107
  const spinner = (0, ora_1.default)('Generating emails preview').start();
@@ -139,7 +150,7 @@ const syncPkg = async () => {
139
150
  const installDependencies = async () => {
140
151
  const spinner = (0, ora_1.default)('Installing dependencies...').start();
141
152
  shelljs_1.default.cd(path_1.default.join(utils_1.REACT_EMAIL_ROOT));
142
- shelljs_1.default.exec('yarn', { silent: true });
153
+ shelljs_1.default.exec('yarn');
143
154
  spinner.stopAndPersist({
144
155
  symbol: log_symbols_1.default.success,
145
156
  text: 'Dependencies installed',
@@ -29,15 +29,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.exportTemplates = void 0;
30
30
  const glob_1 = require("glob");
31
31
  const esbuild_1 = __importDefault(require("esbuild"));
32
+ const tree_node_cli_1 = __importDefault(require("tree-node-cli"));
33
+ const ora_1 = __importDefault(require("ora"));
34
+ const log_symbols_1 = __importDefault(require("log-symbols"));
32
35
  const render_1 = require("@react-email/render");
33
36
  const fs_1 = require("fs");
37
+ const cpy_1 = __importDefault(require("cpy"));
38
+ const utils_1 = require("../utils");
34
39
  /*
35
40
  This first builds all the templates using esbuild and then puts the output in the `.js`
36
41
  files. Then these `.js` files are imported dynamically and rendered to `.html` files
37
42
  using the `render` function.
38
43
  */
39
44
  const exportTemplates = async (outDir, pretty) => {
40
- const allTemplates = glob_1.glob.sync('emails/*.{tsx,jsx}');
45
+ const spinner = (0, ora_1.default)('Preparing files...\n').start();
46
+ const allTemplates = glob_1.glob.sync(`${utils_1.CLIENT_EMAILS_PATH}/*.{tsx,jsx}`);
41
47
  esbuild_1.default.buildSync({
42
48
  bundle: true,
43
49
  entryPoints: allTemplates,
@@ -55,5 +61,18 @@ const exportTemplates = async (outDir, pretty) => {
55
61
  (0, fs_1.writeFileSync)(htmlPath, rendered);
56
62
  (0, fs_1.unlinkSync)(template);
57
63
  }
64
+ const hasStaticDirectory = (0, utils_1.checkDirectoryExist)(`${utils_1.CLIENT_EMAILS_PATH}/static`);
65
+ if (hasStaticDirectory) {
66
+ await (0, cpy_1.default)(`${utils_1.CLIENT_EMAILS_PATH}/static`, `${outDir}/static`);
67
+ }
68
+ const fileTree = (0, tree_node_cli_1.default)(outDir, {
69
+ allFiles: true,
70
+ maxDepth: 4,
71
+ });
72
+ console.log(fileTree);
73
+ spinner.stopAndPersist({
74
+ symbol: log_symbols_1.default.success,
75
+ text: 'Successfully exported emails',
76
+ });
58
77
  };
59
78
  exports.exportTemplates = exportTemplates;
@@ -1,2 +1,3 @@
1
1
  import chokidar from 'chokidar';
2
+ export declare const watcherInstance: chokidar.FSWatcher;
2
3
  export declare const watcher: () => chokidar.FSWatcher;
@@ -3,15 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.watcher = void 0;
6
+ exports.watcher = exports.watcherInstance = void 0;
7
7
  const chokidar_1 = __importDefault(require("chokidar"));
8
8
  const constants_1 = require("./constants");
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const cpy_1 = __importDefault(require("cpy"));
12
- const watcher = () => chokidar_1.default
13
- .watch(constants_1.CLIENT_EMAILS_PATH, { ignoreInitial: true, cwd: constants_1.CURRENT_PATH })
14
- .on('all', async (event, filename) => {
12
+ exports.watcherInstance = chokidar_1.default.watch(constants_1.CLIENT_EMAILS_PATH, {
13
+ ignoreInitial: true,
14
+ cwd: constants_1.CURRENT_PATH,
15
+ ignored: /(^|[\/\\])\../,
16
+ });
17
+ const watcher = () => exports.watcherInstance.on('all', async (event, filename) => {
15
18
  if (event === constants_1.EVENT_FILE_DELETED) {
16
19
  const file = filename.split('/');
17
20
  if (file[1] === 'static') {
@@ -0,0 +1,163 @@
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
+ };
@@ -0,0 +1,85 @@
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
+ };