react-email 1.0.6 → 1.0.7
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/index.d.ts +2 -0
- package/dist/index.js +46 -0
- package/dist/utils/check-directory-exist.d.ts +1 -0
- package/dist/utils/check-directory-exist.js +9 -0
- package/dist/utils/check-empty-directory.d.ts +1 -0
- package/dist/utils/check-empty-directory.js +12 -0
- package/dist/utils/contants.d.ts +10 -0
- package/dist/utils/contants.js +18 -0
- package/dist/utils/copy-files.d.ts +1 -0
- package/dist/utils/copy-files.js +30 -0
- package/dist/utils/watcher.d.ts +2 -0
- package/dist/utils/watcher.js +22 -0
- package/package.json +30 -9
- package/{base → preview}/next-env.d.ts +0 -0
- package/preview/package.json +52 -0
- package/preview/postcss.config.js +6 -0
- package/preview/src/components/button.tsx +85 -0
- package/{base/src/components/code → preview/src/components}/code.tsx +5 -38
- package/preview/src/components/heading.tsx +114 -0
- package/preview/src/components/index.ts +7 -0
- package/preview/src/components/layout.tsx +76 -0
- package/preview/src/components/logo.tsx +71 -0
- package/preview/src/components/sidebar.tsx +137 -0
- package/preview/src/components/text.tsx +100 -0
- package/preview/src/components/topbar.tsx +55 -0
- package/preview/src/pages/_app.tsx +29 -0
- package/preview/src/pages/_document.tsx +13 -0
- package/preview/src/pages/index.tsx +36 -0
- package/preview/src/pages/preview/[slug].tsx +68 -0
- package/preview/src/styles/globals.css +3 -0
- package/preview/src/utils/as.ts +26 -0
- package/preview/src/utils/index.ts +2 -0
- package/preview/src/utils/unreachable.ts +6 -0
- package/preview/tailwind.config.js +90 -0
- package/preview/tsconfig.json +31 -0
- package/readme.md +0 -0
- package/tsconfig.json +32 -4
- package/.babelrc +0 -3
- package/base/.eslintrc.js +0 -4
- package/base/.next/build-manifest.json +0 -35
- package/base/.next/cache/webpack/client-development/0.pack +0 -0
- package/base/.next/cache/webpack/client-development/1.pack +0 -0
- package/base/.next/cache/webpack/client-development/index.pack +0 -0
- package/base/.next/cache/webpack/client-development/index.pack.old +0 -0
- package/base/.next/cache/webpack/server-development/0.pack +0 -0
- package/base/.next/cache/webpack/server-development/1.pack +0 -0
- package/base/.next/cache/webpack/server-development/index.pack +0 -0
- package/base/.next/cache/webpack/server-development/index.pack.old +0 -0
- package/base/.next/package.json +0 -1
- package/base/.next/react-loadable-manifest.json +0 -1
- package/base/.next/server/emails_notion-magic-link_tsx.js +0 -25
- package/base/.next/server/emails_stripe-welcome_tsx.js +0 -25
- package/base/.next/server/emails_vercel-invite-user_tsx.js +0 -25
- package/base/.next/server/middleware-build-manifest.js +0 -1
- package/base/.next/server/middleware-manifest.json +0 -6
- package/base/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/base/.next/server/pages/[...path].js +0 -386
- package/base/.next/server/pages/_app.js +0 -145
- package/base/.next/server/pages/_document.js +0 -211
- package/base/.next/server/pages/_error.js +0 -56
- package/base/.next/server/pages/api/[...path].js +0 -253
- package/base/.next/server/pages-manifest.json +0 -7
- package/base/.next/server/webpack-api-runtime.js +0 -168
- package/base/.next/server/webpack-runtime.js +0 -168
- package/base/.next/static/chunks/amp.js +0 -872
- package/base/.next/static/chunks/main.js +0 -1166
- package/base/.next/static/chunks/pages/[...path].js +0 -904
- package/base/.next/static/chunks/pages/_app.js +0 -467
- package/base/.next/static/chunks/pages/_error.js +0 -28
- package/base/.next/static/chunks/polyfills.js +0 -1
- package/base/.next/static/chunks/react-refresh.js +0 -62
- package/base/.next/static/chunks/webpack.js +0 -1242
- package/base/.next/static/development/_buildManifest.js +0 -1
- package/base/.next/static/development/_ssgManifest.js +0 -1
- package/base/.next/static/webpack/94b31eaefc86ea7b.webpack.hot-update.json +0 -1
- package/base/.next/static/webpack/webpack.94b31eaefc86ea7b.hot-update.js +0 -36
- package/base/.next/trace +0 -5
- package/base/next.config.js +0 -11
- package/base/package.json +0 -53
- package/base/postcss.config.js +0 -20
- package/base/public/static/fonts/Biotif-Bold.woff +0 -0
- package/base/public/static/fonts/Biotif-Bold.woff2 +0 -0
- package/base/public/static/fonts/Biotif-Book.woff +0 -0
- package/base/public/static/fonts/Biotif-Book.woff2 +0 -0
- package/base/public/static/fonts/Biotif-Regular.woff +0 -0
- package/base/public/static/fonts/Biotif-Regular.woff2 +0 -0
- package/base/public/static/fonts/Biotif-SemiBold.woff +0 -0
- package/base/public/static/fonts/Biotif-SemiBold.woff2 +0 -0
- package/base/public/static/fonts/FiraCode-Regular.woff +0 -0
- package/base/public/static/fonts/FiraCode-Regular.woff2 +0 -0
- package/base/public/static/images/favicon.ico +0 -0
- package/base/public/static/images/notion-logo.png +0 -0
- package/base/public/static/images/stripe-logo.png +0 -0
- package/base/public/static/images/vercel-arrow.png +0 -0
- package/base/public/static/images/vercel-logo.png +0 -0
- package/base/readme.md +0 -19
- package/base/src/components/code/index.ts +0 -1
- package/base/src/components/icon-button/icon-button.tsx +0 -23
- package/base/src/components/icon-button/index.ts +0 -1
- package/base/src/components/icons/icon-base.tsx +0 -26
- package/base/src/components/icons/icon-check.tsx +0 -18
- package/base/src/components/icons/icon-clipboard.tsx +0 -39
- package/base/src/components/icons/icon-download.tsx +0 -18
- package/base/src/components/icons/icon-loading.tsx +0 -33
- package/base/src/components/icons/index.ts +0 -4
- package/base/src/components/layout.tsx +0 -53
- package/base/src/components/tooltip/index.ts +0 -1
- package/base/src/components/tooltip/tooltip-arrow.tsx +0 -1
- package/base/src/components/tooltip/tooltip-content.tsx +0 -26
- package/base/src/components/tooltip/tooltip-provider.tsx +0 -1
- package/base/src/components/tooltip/tooltip-trigger.tsx +0 -1
- package/base/src/components/tooltip/tooltip.tsx +0 -22
- package/base/src/components/topbar/external.tsx +0 -30
- package/base/src/components/topbar/feedback.tsx +0 -89
- package/base/src/components/topbar/logo.tsx +0 -27
- package/base/src/components/topbar/send-test.tsx +0 -95
- package/base/src/components/topbar/toggle-view.tsx +0 -66
- package/base/src/helpers/bulb-icon.json +0 -1
- package/base/src/helpers/chat-icon.json +0 -1
- package/base/src/helpers/check-icon.json +0 -1
- package/base/src/helpers/code-icon.json +0 -1
- package/base/src/helpers/copy-icon.json +0 -1
- package/base/src/helpers/desktop-icon.json +0 -1
- package/base/src/helpers/download-icon.json +0 -1
- package/base/src/helpers/eye-icon.json +0 -1
- package/base/src/helpers/file-icon.json +0 -1
- package/base/src/helpers/folder-icon.json +0 -1
- package/base/src/helpers/inbox-icon.json +0 -1
- package/base/src/helpers/launch-icon.json +0 -1
- package/base/src/helpers/mail-icon.json +0 -1
- package/base/src/helpers/mobile-icon.json +0 -1
- package/base/src/helpers/note-icon.json +0 -1
- package/base/src/helpers/reply-icon.json +0 -1
- package/base/src/pages/[...path].tsx +0 -40
- package/base/src/pages/_app.tsx +0 -11
- package/base/src/pages/_document.tsx +0 -37
- package/base/src/pages/api/[...path].js +0 -20
- package/base/src/styles/globals.css +0 -48
- package/base/src/utils/copy-text-to-clipboard.ts +0 -7
- package/base/tsconfig.json +0 -5
- package/src/index.js +0 -30
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const extra_typings_1 = require("@commander-js/extra-typings");
|
|
8
|
+
const shelljs_1 = __importDefault(require("shelljs"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const contants_1 = require("./utils/contants");
|
|
12
|
+
const watcher_1 = require("./utils/watcher");
|
|
13
|
+
const check_directory_exist_1 = require("./utils/check-directory-exist");
|
|
14
|
+
const check_empty_directory_1 = require("./utils/check-empty-directory");
|
|
15
|
+
const copy_files_1 = require("./utils/copy-files");
|
|
16
|
+
extra_typings_1.program
|
|
17
|
+
.name(contants_1.PACKAGE_NAME)
|
|
18
|
+
.description('A live preview of your emails right in your browser')
|
|
19
|
+
.version('0.0.0');
|
|
20
|
+
extra_typings_1.program
|
|
21
|
+
.command('dev')
|
|
22
|
+
.description('Starts the application in development mode')
|
|
23
|
+
.action(async () => {
|
|
24
|
+
const hasEmailsDirectory = (0, check_directory_exist_1.checkDirectoryExist)(contants_1.DEFAULT_EMAILS_DIRECTORY);
|
|
25
|
+
if (!hasEmailsDirectory) {
|
|
26
|
+
return console.error('Missing emails directory');
|
|
27
|
+
}
|
|
28
|
+
const isEmailsDirectoryEmpty = await (0, check_empty_directory_1.checkEmptyDirectory)(contants_1.DEFAULT_EMAILS_DIRECTORY);
|
|
29
|
+
if (isEmailsDirectoryEmpty) {
|
|
30
|
+
return console.error('Missing email files');
|
|
31
|
+
}
|
|
32
|
+
const isDependencyInstalled = (0, check_directory_exist_1.checkDirectoryExist)(contants_1.NODE_MODULES_PACKAGE_PATH);
|
|
33
|
+
if (!isDependencyInstalled) {
|
|
34
|
+
return console.error('Install the package');
|
|
35
|
+
}
|
|
36
|
+
const hasDotEmailDirectory = (0, check_directory_exist_1.checkDirectoryExist)(contants_1.DOT_EMAIL_DEV);
|
|
37
|
+
if (!hasDotEmailDirectory) {
|
|
38
|
+
await fs_1.default.promises.mkdir(contants_1.DOT_EMAIL_DEV, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
await (0, copy_files_1.copyFiles)();
|
|
41
|
+
shelljs_1.default.cd(path_1.default.join(contants_1.DOT_EMAIL_DEV));
|
|
42
|
+
shelljs_1.default.exec('yarn', { silent: true });
|
|
43
|
+
shelljs_1.default.exec('yarn dev', { async: true });
|
|
44
|
+
(0, watcher_1.watcher)();
|
|
45
|
+
});
|
|
46
|
+
extra_typings_1.program.parse();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const checkDirectoryExist: (path: string) => boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkDirectoryExist = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const checkDirectoryExist = (path) => fs_1.default.existsSync(path);
|
|
9
|
+
exports.checkDirectoryExist = checkDirectoryExist;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const checkEmptyDirectory: (path: string) => Promise<boolean>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkEmptyDirectory = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const checkEmptyDirectory = async (path) => {
|
|
9
|
+
const files = await fs_1.default.promises.readdir(path);
|
|
10
|
+
return files.length === 0;
|
|
11
|
+
};
|
|
12
|
+
exports.checkEmptyDirectory = checkEmptyDirectory;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CURRENT_PATH: string;
|
|
2
|
+
export declare const DEFAULT_EMAILS_DIRECTORY = "emails";
|
|
3
|
+
export declare const PACKAGE_NAME = "react-email";
|
|
4
|
+
export declare const HOME_DIR: string;
|
|
5
|
+
export declare const DOT_EMAIL_DEV: string;
|
|
6
|
+
export declare const NODE_MODULES_PACKAGE_PATH: string;
|
|
7
|
+
export declare const NODE_MODULES_PREVIEW_PATH: string;
|
|
8
|
+
export declare const CLIENT_EMAILS_PATH: string;
|
|
9
|
+
export declare const PACKAGE_EMAILS_PATH: string;
|
|
10
|
+
export declare const EVENT_FILE_DELETED = "unlink";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EVENT_FILE_DELETED = exports.PACKAGE_EMAILS_PATH = exports.CLIENT_EMAILS_PATH = exports.NODE_MODULES_PREVIEW_PATH = exports.NODE_MODULES_PACKAGE_PATH = exports.DOT_EMAIL_DEV = exports.HOME_DIR = exports.PACKAGE_NAME = exports.DEFAULT_EMAILS_DIRECTORY = exports.CURRENT_PATH = void 0;
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
exports.CURRENT_PATH = process.cwd();
|
|
10
|
+
exports.DEFAULT_EMAILS_DIRECTORY = 'emails';
|
|
11
|
+
exports.PACKAGE_NAME = 'react-email';
|
|
12
|
+
exports.HOME_DIR = os_1.default.homedir();
|
|
13
|
+
exports.DOT_EMAIL_DEV = path_1.default.join(exports.HOME_DIR, '.react-email');
|
|
14
|
+
exports.NODE_MODULES_PACKAGE_PATH = path_1.default.join(exports.CURRENT_PATH, 'node_modules', exports.PACKAGE_NAME);
|
|
15
|
+
exports.NODE_MODULES_PREVIEW_PATH = path_1.default.join(exports.NODE_MODULES_PACKAGE_PATH, 'preview');
|
|
16
|
+
exports.CLIENT_EMAILS_PATH = path_1.default.join(exports.CURRENT_PATH, exports.DEFAULT_EMAILS_DIRECTORY);
|
|
17
|
+
exports.PACKAGE_EMAILS_PATH = path_1.default.join(exports.DOT_EMAIL_DEV, exports.DEFAULT_EMAILS_DIRECTORY);
|
|
18
|
+
exports.EVENT_FILE_DELETED = 'unlink';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const copyFiles: () => Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.copyFiles = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const cpy_1 = __importDefault(require("cpy"));
|
|
9
|
+
const contants_1 = require("./contants");
|
|
10
|
+
const copyFiles = async () => {
|
|
11
|
+
try {
|
|
12
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'pages', 'preview'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'pages', 'preview'));
|
|
13
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'pages', '_app.tsx'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'pages'));
|
|
14
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'pages', '_document.tsx'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'pages'));
|
|
15
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'pages', 'index.tsx'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'pages'));
|
|
16
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'styles'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'styles'));
|
|
17
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'components'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'components'));
|
|
18
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'src', 'utils'), path_1.default.join(contants_1.DOT_EMAIL_DEV, 'src', 'utils'));
|
|
19
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'next-env.d.ts'), contants_1.DOT_EMAIL_DEV);
|
|
20
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'package.json'), contants_1.DOT_EMAIL_DEV);
|
|
21
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'postcss.config.js'), contants_1.DOT_EMAIL_DEV);
|
|
22
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'tailwind.config.js'), contants_1.DOT_EMAIL_DEV);
|
|
23
|
+
await (0, cpy_1.default)(path_1.default.join(contants_1.NODE_MODULES_PREVIEW_PATH, 'tsconfig.json'), contants_1.DOT_EMAIL_DEV);
|
|
24
|
+
await (0, cpy_1.default)(contants_1.CLIENT_EMAILS_PATH, contants_1.PACKAGE_EMAILS_PATH);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error({ error });
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
exports.copyFiles = copyFiles;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.watcher = void 0;
|
|
7
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
|
8
|
+
const contants_1 = require("./contants");
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const cpy_1 = __importDefault(require("cpy"));
|
|
12
|
+
const watcher = () => chokidar_1.default
|
|
13
|
+
.watch(contants_1.CURRENT_PATH, { ignoreInitial: true, cwd: contants_1.CURRENT_PATH })
|
|
14
|
+
.on('all', async (event, filename) => {
|
|
15
|
+
if (event === contants_1.EVENT_FILE_DELETED) {
|
|
16
|
+
await fs_1.default.promises.rm(path_1.default.join(contants_1.DOT_EMAIL_DEV, filename));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
await (0, cpy_1.default)(contants_1.CLIENT_EMAILS_PATH, contants_1.PACKAGE_EMAILS_PATH);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
exports.watcher = watcher;
|
package/package.json
CHANGED
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-email",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "A live preview of your emails right in your browser.",
|
|
5
|
-
"
|
|
5
|
+
"bin": {
|
|
6
|
+
"email": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"exports": [
|
|
9
|
+
"./dist/index.js",
|
|
10
|
+
"./preview"
|
|
11
|
+
],
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=14.16"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"prepare": "npm run build",
|
|
19
|
+
"format:check": "prettier --check \"**/*.{js,ts,tsx,json}\"",
|
|
20
|
+
"format": "prettier --write \"**/*.{js,ts,tsx,json}\"",
|
|
21
|
+
"lint": "eslint",
|
|
22
|
+
"clean": "rm -rf dist"
|
|
23
|
+
},
|
|
6
24
|
"license": "MIT",
|
|
7
25
|
"dependencies": {
|
|
8
|
-
"commander": "
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
26
|
+
"@commander-js/extra-typings": "9.4.1",
|
|
27
|
+
"chokidar": "3.5.3",
|
|
28
|
+
"commander": "9.4.1",
|
|
29
|
+
"cpy": "8.1.2",
|
|
30
|
+
"glob": "8.0.3",
|
|
31
|
+
"shelljs": "0.8.5"
|
|
13
32
|
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "18.11.9",
|
|
35
|
+
"@types/shelljs": "0.8.11",
|
|
36
|
+
"prettier": "2.7.1"
|
|
16
37
|
}
|
|
17
38
|
}
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-react-email-test",
|
|
3
|
+
"version": "0.0.10",
|
|
4
|
+
"description": "Create react email",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": "bukinoshita/create-react-email",
|
|
7
|
+
"author": "Bu Kinoshita",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "next dev",
|
|
11
|
+
"build": "next build",
|
|
12
|
+
"start": "next start",
|
|
13
|
+
"lint": "next lint",
|
|
14
|
+
"format:check": "prettier --check \"**/*.{ts,tsx,md}\"",
|
|
15
|
+
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@next/font": "13.0.4",
|
|
19
|
+
"@radix-ui/colors": "0.1.8",
|
|
20
|
+
"@radix-ui/react-collapsible": "1.0.1",
|
|
21
|
+
"@radix-ui/react-slot": "1.0.1",
|
|
22
|
+
"@radix-ui/react-toggle-group": "1.0.1",
|
|
23
|
+
"@react-email/avatar": "0.0.2",
|
|
24
|
+
"@react-email/button": "0.0.3",
|
|
25
|
+
"@react-email/container": "0.0.4",
|
|
26
|
+
"@react-email/head": "0.0.2",
|
|
27
|
+
"@react-email/heading": "0.0.3",
|
|
28
|
+
"@react-email/hr": "0.0.2",
|
|
29
|
+
"@react-email/html": "0.0.2",
|
|
30
|
+
"@react-email/img": "0.0.2",
|
|
31
|
+
"@react-email/link": "0.0.2",
|
|
32
|
+
"@react-email/preview": "0.0.2",
|
|
33
|
+
"@react-email/render": "0.0.2",
|
|
34
|
+
"@react-email/section": "0.0.1",
|
|
35
|
+
"@react-email/text": "0.0.2",
|
|
36
|
+
"classnames": "2.3.2",
|
|
37
|
+
"next": "13.0.4",
|
|
38
|
+
"prism-react-renderer": "1.3.5",
|
|
39
|
+
"react": "18.2.0",
|
|
40
|
+
"react-dom": "18.2.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/classnames": "2.3.1",
|
|
44
|
+
"@types/node": "18.11.9",
|
|
45
|
+
"@types/react": "18.0.25",
|
|
46
|
+
"@types/react-dom": "18.0.9",
|
|
47
|
+
"autoprefixer": "10.4.13",
|
|
48
|
+
"postcss": "8.4.19",
|
|
49
|
+
"tailwindcss": "3.2.4",
|
|
50
|
+
"typescript": "4.9.3"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import { unreachable } from '../utils';
|
|
4
|
+
import * as SlotPrimitive from '@radix-ui/react-slot';
|
|
5
|
+
|
|
6
|
+
type ButtonElement = React.ElementRef<'button'>;
|
|
7
|
+
type RootProps = React.ComponentPropsWithoutRef<'button'>;
|
|
8
|
+
|
|
9
|
+
type Appearance = 'white' | 'gradient';
|
|
10
|
+
type Size = '1' | '2' | '3' | '4';
|
|
11
|
+
|
|
12
|
+
interface ButtonProps extends RootProps {
|
|
13
|
+
asChild?: boolean;
|
|
14
|
+
appearance?: Appearance;
|
|
15
|
+
size?: Size;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Button = React.forwardRef<ButtonElement, Readonly<ButtonProps>>(
|
|
19
|
+
(
|
|
20
|
+
{
|
|
21
|
+
asChild,
|
|
22
|
+
appearance = 'white',
|
|
23
|
+
className,
|
|
24
|
+
children,
|
|
25
|
+
size = '2',
|
|
26
|
+
...props
|
|
27
|
+
},
|
|
28
|
+
forwardedRef,
|
|
29
|
+
) => {
|
|
30
|
+
const classNames = classnames(
|
|
31
|
+
getSize(size),
|
|
32
|
+
getAppearance(appearance),
|
|
33
|
+
'inline-flex items-center justify-center border font-medium',
|
|
34
|
+
className,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return asChild ? (
|
|
38
|
+
<SlotPrimitive.Slot ref={forwardedRef} {...props} className={classNames}>
|
|
39
|
+
<SlotPrimitive.Slottable>{children}</SlotPrimitive.Slottable>
|
|
40
|
+
</SlotPrimitive.Slot>
|
|
41
|
+
) : (
|
|
42
|
+
<button ref={forwardedRef} className={classNames} {...props}>
|
|
43
|
+
{children}
|
|
44
|
+
</button>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
Button.displayName = 'Button';
|
|
50
|
+
|
|
51
|
+
const getAppearance = (appearance: Appearance | undefined) => {
|
|
52
|
+
switch (appearance) {
|
|
53
|
+
case undefined:
|
|
54
|
+
case 'white':
|
|
55
|
+
return [
|
|
56
|
+
'bg-white text-black',
|
|
57
|
+
'hover:bg-white/90',
|
|
58
|
+
'focus:ring-2 focus:ring-white/20 focus:outline-none focus:bg-white/90',
|
|
59
|
+
];
|
|
60
|
+
case 'gradient':
|
|
61
|
+
return [
|
|
62
|
+
'bg-gradient backdrop-blur-[20px] border-[#34343A]',
|
|
63
|
+
'hover:bg-gradientHover',
|
|
64
|
+
'focus:ring-2 focus:ring-white/20 focus:outline-none focus:bg-gradientHover',
|
|
65
|
+
];
|
|
66
|
+
default:
|
|
67
|
+
unreachable(appearance);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const getSize = (size: Size | undefined) => {
|
|
72
|
+
switch (size) {
|
|
73
|
+
case '1':
|
|
74
|
+
return '';
|
|
75
|
+
case undefined:
|
|
76
|
+
case '2':
|
|
77
|
+
return 'text-[14px] h-8 px-3 rounded-md gap-2';
|
|
78
|
+
case '3':
|
|
79
|
+
return 'text-[14px] h-10 px-4 rounded-md gap-2';
|
|
80
|
+
case '4':
|
|
81
|
+
return 'text-base h-11 px-4 rounded-md gap-2';
|
|
82
|
+
default:
|
|
83
|
+
unreachable(size);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import classnames from 'classnames';
|
|
2
2
|
import Highlight, { defaultProps, Language } from 'prism-react-renderer';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { IconButton } from '../icon-button';
|
|
5
|
-
import { copyTextToClipboard } from '../../utils/copy-text-to-clipboard';
|
|
6
|
-
import { IconClipboard, IconCheck, IconDownload } from '../icons';
|
|
7
|
-
import { Tooltip } from '../tooltip';
|
|
8
4
|
|
|
9
5
|
interface CodeProps {
|
|
10
6
|
children: any;
|
|
11
7
|
className?: string;
|
|
12
|
-
language?:
|
|
8
|
+
language?: Language;
|
|
13
9
|
}
|
|
14
10
|
|
|
15
11
|
const theme = {
|
|
@@ -55,11 +51,6 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
55
51
|
const [isCopied, setIsCopied] = React.useState(false);
|
|
56
52
|
const value = children.trim();
|
|
57
53
|
|
|
58
|
-
const file = new File([value], 'template.html', {
|
|
59
|
-
type: 'text/html',
|
|
60
|
-
});
|
|
61
|
-
const url = URL.createObjectURL(file);
|
|
62
|
-
|
|
63
54
|
return (
|
|
64
55
|
<Highlight
|
|
65
56
|
{...defaultProps}
|
|
@@ -70,7 +61,7 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
70
61
|
{({ tokens, getLineProps, getTokenProps }) => (
|
|
71
62
|
<pre
|
|
72
63
|
className={classnames(
|
|
73
|
-
'relative
|
|
64
|
+
'border-slate-6 relative p-4 w-full items-center overflow-auto whitespace-pre rounded-md border text-sm backdrop-blur-md',
|
|
74
65
|
className,
|
|
75
66
|
)}
|
|
76
67
|
style={{
|
|
@@ -80,32 +71,8 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
80
71
|
boxShadow: 'rgb(0 0 0 / 10%) 0px 5px 30px -5px',
|
|
81
72
|
}}
|
|
82
73
|
>
|
|
83
|
-
<Tooltip>
|
|
84
|
-
<Tooltip.Trigger className="absolute top-3 right-3 hidden md:block">
|
|
85
|
-
<IconButton
|
|
86
|
-
onClick={async () => {
|
|
87
|
-
setIsCopied(true);
|
|
88
|
-
await copyTextToClipboard(value);
|
|
89
|
-
setTimeout(() => setIsCopied(false), 3000);
|
|
90
|
-
}}
|
|
91
|
-
>
|
|
92
|
-
{isCopied ? <IconCheck /> : <IconClipboard />}
|
|
93
|
-
</IconButton>
|
|
94
|
-
</Tooltip.Trigger>
|
|
95
|
-
<Tooltip.Content>Copy to Clipboard</Tooltip.Content>
|
|
96
|
-
</Tooltip>
|
|
97
|
-
|
|
98
|
-
<Tooltip>
|
|
99
|
-
<Tooltip.Trigger className="text-gray-11 absolute top-3 right-8 hidden md:block">
|
|
100
|
-
<a title="Download HTML" href={url} download={file.name}>
|
|
101
|
-
<IconDownload />
|
|
102
|
-
</a>
|
|
103
|
-
</Tooltip.Trigger>
|
|
104
|
-
<Tooltip.Content>Download HTML</Tooltip.Content>
|
|
105
|
-
</Tooltip>
|
|
106
|
-
|
|
107
74
|
<div
|
|
108
|
-
className="absolute right-0 top-0 h-px w-[
|
|
75
|
+
className="absolute right-0 top-0 h-px w-[200px]"
|
|
109
76
|
style={{
|
|
110
77
|
background:
|
|
111
78
|
'linear-gradient(90deg, rgba(56, 189, 248, 0) 0%, rgba(56, 189, 248, 0) 0%, rgba(232, 232, 232, 0.2) 33.02%, rgba(143, 143, 143, 0.6719) 64.41%, rgba(236, 72, 153, 0) 98.93%)',
|
|
@@ -117,7 +84,7 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
117
84
|
key={i}
|
|
118
85
|
{...getLineProps({ line, key: i })}
|
|
119
86
|
className={classnames('whitespace-pre', {
|
|
120
|
-
"before:text-
|
|
87
|
+
"before:text-slate-11 before:mr-2 before:content-['$']":
|
|
121
88
|
language === 'bash' && tokens.length === 1,
|
|
122
89
|
})}
|
|
123
90
|
>
|
|
@@ -139,7 +106,7 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
139
106
|
);
|
|
140
107
|
})}
|
|
141
108
|
<div
|
|
142
|
-
className="absolute left-0 bottom-0 h-px w-[
|
|
109
|
+
className="absolute left-0 bottom-0 h-px w-[200px]"
|
|
143
110
|
style={{
|
|
144
111
|
background:
|
|
145
112
|
'linear-gradient(90deg, rgba(56, 189, 248, 0) 0%, rgba(56, 189, 248, 0) 0%, rgba(232, 232, 232, 0.2) 33.02%, rgba(143, 143, 143, 0.6719) 64.41%, rgba(236, 72, 153, 0) 98.93%)',
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as SlotPrimitive from '@radix-ui/react-slot';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { As, unreachable } from '../utils';
|
|
5
|
+
|
|
6
|
+
export type HeadingSize =
|
|
7
|
+
| '1'
|
|
8
|
+
| '2'
|
|
9
|
+
| '3'
|
|
10
|
+
| '4'
|
|
11
|
+
| '5'
|
|
12
|
+
| '6'
|
|
13
|
+
| '7'
|
|
14
|
+
| '8'
|
|
15
|
+
| '9'
|
|
16
|
+
| '10';
|
|
17
|
+
export type HeadingColor = 'white' | 'gray';
|
|
18
|
+
export type HeadingWeight = 'medium' | 'bold';
|
|
19
|
+
|
|
20
|
+
interface HeadingOwnProps {
|
|
21
|
+
size?: HeadingSize;
|
|
22
|
+
color?: HeadingColor;
|
|
23
|
+
weight?: HeadingWeight;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type HeadingProps = As<'h1', 'h2', 'h3', 'h4', 'h5', 'h6'> & HeadingOwnProps;
|
|
27
|
+
|
|
28
|
+
export const Heading = React.forwardRef<
|
|
29
|
+
HTMLHeadingElement,
|
|
30
|
+
Readonly<HeadingProps>
|
|
31
|
+
>(
|
|
32
|
+
(
|
|
33
|
+
{
|
|
34
|
+
as: Tag = 'h1',
|
|
35
|
+
size = '3',
|
|
36
|
+
className,
|
|
37
|
+
color = 'white',
|
|
38
|
+
children,
|
|
39
|
+
weight = 'bold',
|
|
40
|
+
...props
|
|
41
|
+
},
|
|
42
|
+
forwardedRef,
|
|
43
|
+
) => (
|
|
44
|
+
<SlotPrimitive.Slot
|
|
45
|
+
ref={forwardedRef}
|
|
46
|
+
className={classnames(
|
|
47
|
+
className,
|
|
48
|
+
getSizesClassNames(size),
|
|
49
|
+
getColorClassNames(color),
|
|
50
|
+
getWeightClassNames(weight),
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
<Tag>{children}</Tag>
|
|
55
|
+
</SlotPrimitive.Slot>
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const getSizesClassNames = (size: HeadingSize | undefined) => {
|
|
60
|
+
switch (size) {
|
|
61
|
+
case '1':
|
|
62
|
+
return 'text-xs';
|
|
63
|
+
case '2':
|
|
64
|
+
return 'text-sm';
|
|
65
|
+
case undefined:
|
|
66
|
+
case '3':
|
|
67
|
+
return 'text-base';
|
|
68
|
+
case '4':
|
|
69
|
+
return 'text-lg';
|
|
70
|
+
case '5':
|
|
71
|
+
return 'text-xl tracking-[-0.16px]';
|
|
72
|
+
case '6':
|
|
73
|
+
return 'text-2xl tracking-[-0.288px]';
|
|
74
|
+
case '7':
|
|
75
|
+
return 'text-[28px] leading-[34px] tracking-[-0.416px]';
|
|
76
|
+
case '8':
|
|
77
|
+
return 'text-[35px] leading-[42px] tracking-[-0.64px]';
|
|
78
|
+
case '9':
|
|
79
|
+
return 'text-6xl leading-[73px] tracking-[-0.896px]';
|
|
80
|
+
case '10':
|
|
81
|
+
return [
|
|
82
|
+
'text-[38px] leading-[46px]',
|
|
83
|
+
'md:text-[70px] md:leading-[85px] tracking-[-1.024px;]',
|
|
84
|
+
];
|
|
85
|
+
default:
|
|
86
|
+
return unreachable(size);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const getColorClassNames = (color: HeadingColor | undefined) => {
|
|
91
|
+
switch (color) {
|
|
92
|
+
case 'gray':
|
|
93
|
+
return 'text-slate-11';
|
|
94
|
+
case 'white':
|
|
95
|
+
case undefined:
|
|
96
|
+
return 'text-slate-12';
|
|
97
|
+
default:
|
|
98
|
+
return unreachable(color);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const getWeightClassNames = (weight: HeadingWeight | undefined) => {
|
|
103
|
+
switch (weight) {
|
|
104
|
+
case 'medium':
|
|
105
|
+
return 'font-medium';
|
|
106
|
+
case 'bold':
|
|
107
|
+
case undefined:
|
|
108
|
+
return 'font-bold';
|
|
109
|
+
default:
|
|
110
|
+
return unreachable(weight);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
Heading.displayName = 'Heading';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Topbar } from './topbar';
|
|
3
|
+
import { Sidebar } from './sidebar';
|
|
4
|
+
import * as ToggleGroup from '@radix-ui/react-toggle-group';
|
|
5
|
+
import classnames from 'classnames';
|
|
6
|
+
|
|
7
|
+
type LayoutElement = React.ElementRef<'div'>;
|
|
8
|
+
type RootProps = React.ComponentPropsWithoutRef<'div'>;
|
|
9
|
+
|
|
10
|
+
interface LayoutProps extends RootProps {
|
|
11
|
+
navItems: string[];
|
|
12
|
+
viewMode?: string;
|
|
13
|
+
setViewMode?: (viewMode: string) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(
|
|
17
|
+
(
|
|
18
|
+
{ className, title, navItems, children, viewMode, setViewMode, ...props },
|
|
19
|
+
forwardedRef,
|
|
20
|
+
) => {
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<div className="flex justify-between h-screen">
|
|
24
|
+
<Sidebar navItems={navItems} />
|
|
25
|
+
<main className="w-full bg-slate-2">
|
|
26
|
+
{title && <Topbar title={title} />}
|
|
27
|
+
<div className="pt-16 relative h-[calc(100vh_-_70px)] overflow-auto">
|
|
28
|
+
{setViewMode && (
|
|
29
|
+
<ToggleGroup.Root
|
|
30
|
+
className="items-center bg-slate-2 p-1.5 flex gap-1 border border-slate-6 rounded-md absolute top-4 right-4"
|
|
31
|
+
type="single"
|
|
32
|
+
value={viewMode}
|
|
33
|
+
aria-label="View mode"
|
|
34
|
+
onValueChange={(value) => {
|
|
35
|
+
if (!value) {
|
|
36
|
+
return setViewMode('desktop');
|
|
37
|
+
}
|
|
38
|
+
setViewMode(value);
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<ToggleGroup.Item
|
|
42
|
+
className={classnames(
|
|
43
|
+
'text-sm text-slate-11 rounded px-1.5 py-0.5',
|
|
44
|
+
{
|
|
45
|
+
'text-slate-12 bg-slate-3 font-medium':
|
|
46
|
+
viewMode === 'desktop',
|
|
47
|
+
},
|
|
48
|
+
)}
|
|
49
|
+
value="desktop"
|
|
50
|
+
>
|
|
51
|
+
Desktop
|
|
52
|
+
</ToggleGroup.Item>
|
|
53
|
+
<ToggleGroup.Item
|
|
54
|
+
className={classnames(
|
|
55
|
+
'text-sm text-slate-11 rounded px-1.5 py-0.5',
|
|
56
|
+
{
|
|
57
|
+
'text-slate-12 bg-slate-3 font-medium':
|
|
58
|
+
viewMode === 'source',
|
|
59
|
+
},
|
|
60
|
+
)}
|
|
61
|
+
value="source"
|
|
62
|
+
>
|
|
63
|
+
Source
|
|
64
|
+
</ToggleGroup.Item>
|
|
65
|
+
</ToggleGroup.Root>
|
|
66
|
+
)}
|
|
67
|
+
<div className="max-w-[600px] mx-auto">{children}</div>
|
|
68
|
+
</div>
|
|
69
|
+
</main>
|
|
70
|
+
</div>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
Layout.displayName = 'Layout';
|