react-email 1.0.6 → 1.0.8

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 (141) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +42 -0
  3. package/dist/utils/check-directory-exist.d.ts +1 -0
  4. package/dist/utils/check-directory-exist.js +9 -0
  5. package/dist/utils/check-empty-directory.d.ts +1 -0
  6. package/dist/utils/check-empty-directory.js +12 -0
  7. package/dist/utils/contants.d.ts +10 -0
  8. package/dist/utils/contants.js +18 -0
  9. package/dist/utils/copy-files.d.ts +1 -0
  10. package/dist/utils/copy-files.js +30 -0
  11. package/dist/utils/watcher.d.ts +2 -0
  12. package/dist/utils/watcher.js +22 -0
  13. package/package.json +30 -9
  14. package/{base → preview}/next-env.d.ts +0 -0
  15. package/preview/package.json +52 -0
  16. package/preview/postcss.config.js +6 -0
  17. package/preview/src/components/button.tsx +85 -0
  18. package/{base/src/components/code → preview/src/components}/code.tsx +5 -38
  19. package/preview/src/components/heading.tsx +114 -0
  20. package/preview/src/components/index.ts +7 -0
  21. package/preview/src/components/layout.tsx +76 -0
  22. package/preview/src/components/logo.tsx +71 -0
  23. package/preview/src/components/sidebar.tsx +137 -0
  24. package/preview/src/components/text.tsx +100 -0
  25. package/preview/src/components/topbar.tsx +55 -0
  26. package/preview/src/pages/_app.tsx +29 -0
  27. package/preview/src/pages/_document.tsx +13 -0
  28. package/preview/src/pages/index.tsx +36 -0
  29. package/preview/src/pages/preview/[slug].tsx +68 -0
  30. package/preview/src/styles/globals.css +3 -0
  31. package/preview/src/utils/as.ts +26 -0
  32. package/preview/src/utils/index.ts +2 -0
  33. package/preview/src/utils/unreachable.ts +6 -0
  34. package/preview/tailwind.config.js +90 -0
  35. package/preview/tsconfig.json +31 -0
  36. package/readme.md +0 -0
  37. package/tsconfig.json +32 -4
  38. package/.babelrc +0 -3
  39. package/base/.eslintrc.js +0 -4
  40. package/base/.next/build-manifest.json +0 -35
  41. package/base/.next/cache/webpack/client-development/0.pack +0 -0
  42. package/base/.next/cache/webpack/client-development/1.pack +0 -0
  43. package/base/.next/cache/webpack/client-development/index.pack +0 -0
  44. package/base/.next/cache/webpack/client-development/index.pack.old +0 -0
  45. package/base/.next/cache/webpack/server-development/0.pack +0 -0
  46. package/base/.next/cache/webpack/server-development/1.pack +0 -0
  47. package/base/.next/cache/webpack/server-development/index.pack +0 -0
  48. package/base/.next/cache/webpack/server-development/index.pack.old +0 -0
  49. package/base/.next/package.json +0 -1
  50. package/base/.next/react-loadable-manifest.json +0 -1
  51. package/base/.next/server/emails_notion-magic-link_tsx.js +0 -25
  52. package/base/.next/server/emails_stripe-welcome_tsx.js +0 -25
  53. package/base/.next/server/emails_vercel-invite-user_tsx.js +0 -25
  54. package/base/.next/server/middleware-build-manifest.js +0 -1
  55. package/base/.next/server/middleware-manifest.json +0 -6
  56. package/base/.next/server/middleware-react-loadable-manifest.js +0 -1
  57. package/base/.next/server/pages/[...path].js +0 -386
  58. package/base/.next/server/pages/_app.js +0 -145
  59. package/base/.next/server/pages/_document.js +0 -211
  60. package/base/.next/server/pages/_error.js +0 -56
  61. package/base/.next/server/pages/api/[...path].js +0 -253
  62. package/base/.next/server/pages-manifest.json +0 -7
  63. package/base/.next/server/webpack-api-runtime.js +0 -168
  64. package/base/.next/server/webpack-runtime.js +0 -168
  65. package/base/.next/static/chunks/amp.js +0 -872
  66. package/base/.next/static/chunks/main.js +0 -1166
  67. package/base/.next/static/chunks/pages/[...path].js +0 -904
  68. package/base/.next/static/chunks/pages/_app.js +0 -467
  69. package/base/.next/static/chunks/pages/_error.js +0 -28
  70. package/base/.next/static/chunks/polyfills.js +0 -1
  71. package/base/.next/static/chunks/react-refresh.js +0 -62
  72. package/base/.next/static/chunks/webpack.js +0 -1242
  73. package/base/.next/static/development/_buildManifest.js +0 -1
  74. package/base/.next/static/development/_ssgManifest.js +0 -1
  75. package/base/.next/static/webpack/94b31eaefc86ea7b.webpack.hot-update.json +0 -1
  76. package/base/.next/static/webpack/webpack.94b31eaefc86ea7b.hot-update.js +0 -36
  77. package/base/.next/trace +0 -5
  78. package/base/next.config.js +0 -11
  79. package/base/package.json +0 -53
  80. package/base/postcss.config.js +0 -20
  81. package/base/public/static/fonts/Biotif-Bold.woff +0 -0
  82. package/base/public/static/fonts/Biotif-Bold.woff2 +0 -0
  83. package/base/public/static/fonts/Biotif-Book.woff +0 -0
  84. package/base/public/static/fonts/Biotif-Book.woff2 +0 -0
  85. package/base/public/static/fonts/Biotif-Regular.woff +0 -0
  86. package/base/public/static/fonts/Biotif-Regular.woff2 +0 -0
  87. package/base/public/static/fonts/Biotif-SemiBold.woff +0 -0
  88. package/base/public/static/fonts/Biotif-SemiBold.woff2 +0 -0
  89. package/base/public/static/fonts/FiraCode-Regular.woff +0 -0
  90. package/base/public/static/fonts/FiraCode-Regular.woff2 +0 -0
  91. package/base/public/static/images/favicon.ico +0 -0
  92. package/base/public/static/images/notion-logo.png +0 -0
  93. package/base/public/static/images/stripe-logo.png +0 -0
  94. package/base/public/static/images/vercel-arrow.png +0 -0
  95. package/base/public/static/images/vercel-logo.png +0 -0
  96. package/base/readme.md +0 -19
  97. package/base/src/components/code/index.ts +0 -1
  98. package/base/src/components/icon-button/icon-button.tsx +0 -23
  99. package/base/src/components/icon-button/index.ts +0 -1
  100. package/base/src/components/icons/icon-base.tsx +0 -26
  101. package/base/src/components/icons/icon-check.tsx +0 -18
  102. package/base/src/components/icons/icon-clipboard.tsx +0 -39
  103. package/base/src/components/icons/icon-download.tsx +0 -18
  104. package/base/src/components/icons/icon-loading.tsx +0 -33
  105. package/base/src/components/icons/index.ts +0 -4
  106. package/base/src/components/layout.tsx +0 -53
  107. package/base/src/components/tooltip/index.ts +0 -1
  108. package/base/src/components/tooltip/tooltip-arrow.tsx +0 -1
  109. package/base/src/components/tooltip/tooltip-content.tsx +0 -26
  110. package/base/src/components/tooltip/tooltip-provider.tsx +0 -1
  111. package/base/src/components/tooltip/tooltip-trigger.tsx +0 -1
  112. package/base/src/components/tooltip/tooltip.tsx +0 -22
  113. package/base/src/components/topbar/external.tsx +0 -30
  114. package/base/src/components/topbar/feedback.tsx +0 -89
  115. package/base/src/components/topbar/logo.tsx +0 -27
  116. package/base/src/components/topbar/send-test.tsx +0 -95
  117. package/base/src/components/topbar/toggle-view.tsx +0 -66
  118. package/base/src/helpers/bulb-icon.json +0 -1
  119. package/base/src/helpers/chat-icon.json +0 -1
  120. package/base/src/helpers/check-icon.json +0 -1
  121. package/base/src/helpers/code-icon.json +0 -1
  122. package/base/src/helpers/copy-icon.json +0 -1
  123. package/base/src/helpers/desktop-icon.json +0 -1
  124. package/base/src/helpers/download-icon.json +0 -1
  125. package/base/src/helpers/eye-icon.json +0 -1
  126. package/base/src/helpers/file-icon.json +0 -1
  127. package/base/src/helpers/folder-icon.json +0 -1
  128. package/base/src/helpers/inbox-icon.json +0 -1
  129. package/base/src/helpers/launch-icon.json +0 -1
  130. package/base/src/helpers/mail-icon.json +0 -1
  131. package/base/src/helpers/mobile-icon.json +0 -1
  132. package/base/src/helpers/note-icon.json +0 -1
  133. package/base/src/helpers/reply-icon.json +0 -1
  134. package/base/src/pages/[...path].tsx +0 -40
  135. package/base/src/pages/_app.tsx +0 -11
  136. package/base/src/pages/_document.tsx +0 -37
  137. package/base/src/pages/api/[...path].js +0 -20
  138. package/base/src/styles/globals.css +0 -48
  139. package/base/src/utils/copy-text-to-clipboard.ts +0 -7
  140. package/base/tsconfig.json +0 -5
  141. package/src/index.js +0 -30
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
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 hasDotEmailDirectory = (0, check_directory_exist_1.checkDirectoryExist)(contants_1.DOT_EMAIL_DEV);
33
+ if (!hasDotEmailDirectory) {
34
+ await fs_1.default.promises.mkdir(contants_1.DOT_EMAIL_DEV, { recursive: true });
35
+ }
36
+ await (0, copy_files_1.copyFiles)();
37
+ shelljs_1.default.cd(path_1.default.join(contants_1.DOT_EMAIL_DEV));
38
+ shelljs_1.default.exec('yarn', { silent: true });
39
+ shelljs_1.default.exec('yarn dev', { async: true });
40
+ (0, watcher_1.watcher)();
41
+ });
42
+ 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,2 @@
1
+ import chokidar from 'chokidar';
2
+ export declare const watcher: () => chokidar.FSWatcher;
@@ -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.6",
3
+ "version": "1.0.8",
4
4
  "description": "A live preview of your emails right in your browser.",
5
- "main": "src/index.js",
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.4.1",
9
- "copy": "^0.3.2",
10
- "inquirer": "^9.1.4",
11
- "prompts": "^2.4.2",
12
- "shelljs": "^0.8.5"
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
- "bin": {
15
- "email": "src/index.js"
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,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -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?: string;
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 my-8 w-full min-w-full max-w-full overflow-auto whitespace-pre rounded-md border border-gray-6 p-4 text-sm backdrop-blur-md',
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-[300px]"
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-gray-11 before:mr-2 before:content-['$']":
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-[300px]"
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,7 @@
1
+ export * from './button';
2
+ export * from './code';
3
+ export * from './heading';
4
+ export * from './logo';
5
+ export * from './sidebar';
6
+ export * from './text';
7
+ export * from './topbar';
@@ -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';