react-email 3.0.6 → 4.0.0-alpha.0

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 (103) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cli/index.js +768 -763
  3. package/dist/cli/index.mjs +480 -476
  4. package/dist/preview/.next/BUILD_ID +1 -1
  5. package/dist/preview/.next/app-build-manifest.json +14 -12
  6. package/dist/preview/.next/build-manifest.json +5 -5
  7. package/dist/preview/.next/cache/.rscinfo +1 -1
  8. package/dist/preview/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/dist/preview/.next/cache/webpack/client-production/index.pack +0 -0
  10. package/dist/preview/.next/cache/webpack/edge-server-production/index.pack +0 -0
  11. package/dist/preview/.next/cache/webpack/server-production/0.pack +0 -0
  12. package/dist/preview/.next/cache/webpack/server-production/index.pack +0 -0
  13. package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
  14. package/dist/preview/.next/next-server.js.nft.json +1 -1
  15. package/dist/preview/.next/prerender-manifest.json +1 -1
  16. package/dist/preview/.next/server/app/_not-found/page.js +1 -1
  17. package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/dist/preview/.next/server/app/page.js +1 -1
  19. package/dist/preview/.next/server/app/page.js.nft.json +1 -1
  20. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  21. package/dist/preview/.next/server/app/preview/[...slug]/page.js +6 -6
  22. package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
  23. package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
  24. package/dist/preview/.next/server/chunks/273.js +1 -0
  25. package/dist/preview/.next/server/chunks/594.js +10 -0
  26. package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
  27. package/dist/preview/.next/server/pages/500.html +1 -1
  28. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  29. package/dist/preview/.next/server/server-reference-manifest.json +1 -1
  30. package/dist/preview/.next/server/webpack-runtime.js +1 -1
  31. package/dist/preview/.next/static/chunks/18b16e15-6ad9b58e10ff8891.js +1 -0
  32. package/dist/preview/.next/static/chunks/490-48951f2e19ae3aef.js +1 -0
  33. package/dist/preview/.next/static/chunks/600-2e2ca4c8bbd97b61.js +1 -0
  34. package/dist/preview/.next/static/chunks/app/{layout-a2901ed1c2c53661.js → layout-490964e2c3604d33.js} +1 -1
  35. package/dist/preview/.next/static/chunks/app/page-d2432acd08db8fc0.js +1 -0
  36. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-f4e211e00c026401.js +1 -0
  37. package/dist/preview/.next/static/chunks/webpack-7bf1ffb05f5540be.js +1 -0
  38. package/dist/preview/.next/static/css/5e0736cafbb392a9.css +3 -0
  39. package/dist/preview/.next/trace +21 -21
  40. package/package.json +12 -7
  41. package/postcss.config.js +1 -1
  42. package/src/actions/email-validation/check-links.ts +88 -0
  43. package/src/actions/email-validation/get-line-and-column-from-index.spec.ts +22 -0
  44. package/src/actions/email-validation/get-line-and-column-from-index.ts +43 -0
  45. package/src/actions/email-validation/quick-fetch.ts +12 -0
  46. package/src/actions/get-email-path-from-slug.ts +7 -4
  47. package/src/actions/render-email-by-path.tsx +3 -3
  48. package/src/animated-icons-data/help.json +1082 -0
  49. package/src/animated-icons-data/link.json +1309 -0
  50. package/src/animated-icons-data/load.json +443 -0
  51. package/src/animated-icons-data/mail.json +1320 -0
  52. package/src/app/globals.css +0 -24
  53. package/src/app/layout.tsx +7 -3
  54. package/src/app/page.tsx +9 -10
  55. package/src/app/preview/[...slug]/page.tsx +3 -2
  56. package/src/app/preview/[...slug]/preview.tsx +5 -5
  57. package/src/app/preview/[...slug]/rendering-error.tsx +6 -6
  58. package/src/components/button.tsx +8 -8
  59. package/src/components/code-container.tsx +7 -7
  60. package/src/components/code-snippet.tsx +11 -0
  61. package/src/components/code.tsx +4 -4
  62. package/src/components/heading.tsx +1 -1
  63. package/src/components/icons/icon-button.tsx +1 -1
  64. package/src/components/icons/icon-circle-check.tsx +21 -0
  65. package/src/components/icons/icon-circle-close.tsx +17 -0
  66. package/src/components/icons/icon-circle-warning.tsx +17 -0
  67. package/src/components/icons/icon-email.tsx +18 -0
  68. package/src/components/icons/icon-link.tsx +14 -0
  69. package/src/components/icons/icon-stamp.tsx +14 -0
  70. package/src/components/send.tsx +9 -9
  71. package/src/components/shell.tsx +32 -34
  72. package/src/components/sidebar/{sidebar-directory-children.tsx → file-tree-directory-children.tsx} +22 -18
  73. package/src/components/sidebar/{sidebar-directory.tsx → file-tree-directory.tsx} +11 -12
  74. package/src/components/sidebar/file-tree.tsx +31 -0
  75. package/src/components/sidebar/link-checker.tsx +291 -0
  76. package/src/components/sidebar/sidebar.tsx +296 -22
  77. package/src/components/text.tsx +1 -1
  78. package/src/components/tooltip-content.tsx +3 -3
  79. package/src/components/tooltip.tsx +1 -1
  80. package/src/components/topbar.tsx +14 -17
  81. package/src/hooks/use-email-rendering-result.ts +2 -2
  82. package/src/hooks/use-icon-animation.ts +44 -0
  83. package/src/utils/cn.ts +1 -1
  84. package/src/utils/esbuild/renderring-utilities-exporter.ts +1 -1
  85. package/src/utils/get-email-component.ts +6 -6
  86. package/src/utils/get-emails-directory-metadata.spec.ts +0 -1
  87. package/src/utils/improve-error-with-sourcemap.ts +1 -1
  88. package/src/utils/static-node-modules-for-vm.ts +6 -6
  89. package/tsconfig.json +2 -6
  90. package/.eslintrc.js +0 -52
  91. package/.prettierignore +0 -3
  92. package/.prettierrc.js +0 -8
  93. package/dist/preview/.next/cache/eslint/.cache_1c3sgg +0 -1
  94. package/dist/preview/.next/server/chunks/391.js +0 -1
  95. package/dist/preview/.next/server/chunks/720.js +0 -10
  96. package/dist/preview/.next/static/chunks/12-b9450aa0845e7574.js +0 -1
  97. package/dist/preview/.next/static/chunks/154-4202f86af36ccff4.js +0 -1
  98. package/dist/preview/.next/static/chunks/app/page-54a86772095e22e0.js +0 -1
  99. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-2bfad134b65ddd79.js +0 -1
  100. package/dist/preview/.next/static/chunks/webpack-9255716c9496e606.js +0 -1
  101. package/dist/preview/.next/static/css/eb0a93282704d7ab.css +0 -3
  102. /package/dist/preview/.next/static/{Trk1e7GzgKOLunAXBDCy- → fZaiKz58wDr55pxLu9uHa}/_buildManifest.js +0 -0
  103. /package/dist/preview/.next/static/{Trk1e7GzgKOLunAXBDCy- → fZaiKz58wDr55pxLu9uHa}/_ssgManifest.js +0 -0
@@ -2,30 +2,6 @@
2
2
  @tailwind components;
3
3
  @tailwind utilities;
4
4
 
5
- :root {
6
- --foreground-rgb: 0, 0, 0;
7
- --background-start-rgb: 214, 219, 220;
8
- --background-end-rgb: 255, 255, 255;
9
- }
10
-
11
- @media (prefers-color-scheme: dark) {
12
- :root {
13
- --foreground-rgb: 255, 255, 255;
14
- --background-start-rgb: 0, 0, 0;
15
- --background-end-rgb: 0, 0, 0;
16
- }
17
- }
18
-
19
- body {
20
- color: rgb(var(--foreground-rgb));
21
- background: linear-gradient(
22
- to bottom,
23
- transparent,
24
- rgb(var(--background-end-rgb))
25
- )
26
- rgb(var(--background-start-rgb));
27
- }
28
-
29
5
  .popup-open iframe {
30
6
  pointer-events: none;
31
7
  }
@@ -1,7 +1,7 @@
1
1
  import type { Metadata } from 'next';
2
2
  import './globals.css';
3
- import { emailsDirectoryAbsolutePath } from '../utils/emails-directory-absolute-path';
4
3
  import { EmailsProvider } from '../contexts/emails';
4
+ import { emailsDirectoryAbsolutePath } from '../utils/emails-directory-absolute-path';
5
5
  import { getEmailsDirectoryMetadata } from '../utils/get-emails-directory-metadata';
6
6
  import { inter } from './inter';
7
7
 
@@ -23,13 +23,17 @@ const RootLayout = async ({ children }: { children: React.ReactNode }) => {
23
23
  }
24
24
 
25
25
  return (
26
- <html lang="en">
27
- <body className={inter.className}>
26
+ <html className={inter.className} lang="en">
27
+ <body className="relative flex h-screen flex-col overflow-x-hidden bg-black text-slate-11 leading-loose selection:bg-cyan-5 selection:text-cyan-12">
28
28
  <EmailsProvider
29
29
  initialEmailsDirectoryMetadata={emailsDirectoryMetadata}
30
30
  >
31
31
  {children}
32
32
  </EmailsProvider>
33
+ <div
34
+ aria-hidden
35
+ className="pointer-events-none absolute inset-0 bg-gradient-to-t from-slate-3"
36
+ />
33
37
  </body>
34
38
  </html>
35
39
  );
package/src/app/page.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import path from 'node:path';
2
- import Link from 'next/link';
3
2
  import Image from 'next/image';
3
+ import Link from 'next/link';
4
4
  import { Button, Heading, Text } from '../components';
5
+ import CodeSnippet from '../components/code-snippet';
5
6
  import { Shell } from '../components/shell';
6
7
  import { emailsDirectoryAbsolutePath } from '../utils/emails-directory-absolute-path';
7
8
  import logo from './logo.png';
@@ -11,8 +12,8 @@ const Home = () => {
11
12
 
12
13
  return (
13
14
  <Shell>
14
- <div className="relative max-w-lg mx-auto p-8 flex items-center justify-center h-[inherit]">
15
- <div className="relative z-10 flex flex-col text-center items-center">
15
+ <div className="relative mx-auto flex h-[inherit] max-w-lg items-center justify-center p-8">
16
+ <div className="-mt-10 relative flex flex-col items-center gap-3 text-center">
16
17
  <Image
17
18
  alt="React Email Icon"
18
19
  className="mb-8"
@@ -20,22 +21,20 @@ const Home = () => {
20
21
  src={logo}
21
22
  style={{
22
23
  borderRadius: 34,
23
- boxShadow: '0px 10px 200px 20px #2B7CA080',
24
+ boxShadow: '0 .625rem 12.5rem 1.25rem #2B7CA080',
24
25
  }}
25
26
  width={141}
26
27
  />
27
28
  <Heading as="h2" size="6" weight="medium">
28
29
  Welcome to React Email
29
30
  </Heading>
30
- <Text as="p" className="mt-2 mb-4">
31
+ <Text as="p">
31
32
  To start developing your emails, you can create a<br />
32
- <code className="text-slate-12">.jsx</code> or{' '}
33
- <code className="text-slate-12">.tsx</code> file under your{' '}
34
- <code className="text-slate-12">{baseEmailsDirectoryName}</code>{' '}
33
+ <CodeSnippet>.jsx</CodeSnippet> or <CodeSnippet>.tsx</CodeSnippet>{' '}
34
+ file under your <CodeSnippet>{baseEmailsDirectoryName}</CodeSnippet>{' '}
35
35
  folder.
36
36
  </Text>
37
-
38
- <Button asChild size="3">
37
+ <Button asChild className="mt-3" size="3">
39
38
  <Link href="https://react.email/docs">Check the docs</Link>
40
39
  </Button>
41
40
  </div>
@@ -1,11 +1,11 @@
1
1
  import path from 'node:path';
2
- import { Suspense } from 'react';
3
2
  import { redirect } from 'next/navigation';
3
+ import { Suspense } from 'react';
4
4
  import { getEmailPathFromSlug } from '../../../actions/get-email-path-from-slug';
5
5
  import { renderEmailByPath } from '../../../actions/render-email-by-path';
6
6
  import { emailsDirectoryAbsolutePath } from '../../../utils/emails-directory-absolute-path';
7
- import Home from '../../page';
8
7
  import { getEmailsDirectoryMetadata } from '../../../utils/get-emails-directory-metadata';
8
+ import Home from '../../page';
9
9
  import Preview from './preview';
10
10
 
11
11
  export const dynamicParams = true;
@@ -80,6 +80,7 @@ export async function generateMetadata({
80
80
  params: Promise<PreviewParams>;
81
81
  }) {
82
82
  const { slug } = await params;
83
+
83
84
  return { title: `${path.basename(slug.join('/'))} — React Email` };
84
85
  }
85
86
 
@@ -3,13 +3,13 @@
3
3
  import { usePathname, useRouter, useSearchParams } from 'next/navigation';
4
4
  import React from 'react';
5
5
  import { Toaster } from 'sonner';
6
- import { useHotreload } from '../../../hooks/use-hot-reload';
7
6
  import type { EmailRenderingResult } from '../../../actions/render-email-by-path';
8
7
  import { CodeContainer } from '../../../components/code-container';
9
8
  import { Shell } from '../../../components/shell';
10
9
  import { Tooltip } from '../../../components/tooltip';
11
- import { useRenderingMetadata } from '../../../hooks/use-rendering-metadata';
12
10
  import { useEmailRenderingResult } from '../../../hooks/use-email-rendering-result';
11
+ import { useHotreload } from '../../../hooks/use-hot-reload';
12
+ import { useRenderingMetadata } from '../../../hooks/use-rendering-metadata';
13
13
  import { RenderingError } from './rendering-error';
14
14
 
15
15
  interface PreviewProps {
@@ -93,7 +93,7 @@ const Preview = ({
93
93
  <>
94
94
  {activeView === 'desktop' && (
95
95
  <iframe
96
- className="w-full bg-white h-[calc(100vh_-_140px)] lg:h-[calc(100vh_-_70px)]"
96
+ className="h-full w-full bg-white"
97
97
  srcDoc={renderedEmailMetadata.markup}
98
98
  title={slug}
99
99
  />
@@ -101,14 +101,14 @@ const Preview = ({
101
101
 
102
102
  {activeView === 'mobile' && (
103
103
  <iframe
104
- className="w-[360px] bg-white h-[calc(100vh_-_140px)] lg:h-[calc(100vh_-_70px)] mx-auto"
104
+ className="mx-auto h-full w-[360px] bg-white"
105
105
  srcDoc={renderedEmailMetadata.markup}
106
106
  title={slug}
107
107
  />
108
108
  )}
109
109
 
110
110
  {activeView === 'source' && (
111
- <div className="flex gap-6 mx-auto p-6 max-w-3xl">
111
+ <div className="mx-auto flex max-w-3xl gap-6 p-6">
112
112
  <Tooltip.Provider>
113
113
  <CodeContainer
114
114
  activeLang={activeLang}
@@ -5,11 +5,11 @@ export const RenderingError = (props: { error: ErrorObject }) => {
5
5
  return (
6
6
  <>
7
7
  <div className="absolute inset-0 z-50 bg-black/80" />
8
- <div className="md:max-w-[568px] lg:max-w-[968px] absolute left-[50%] top-[50%] min-h-[50vh] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-t-4 bg-white text-black p-6 shadow-lg duration-200 sm:rounded-lg rounded-t-sm">
9
- <div className="flex flex-col max-w-full min-w-0 space-y-1.5">
10
- <h2 className="text-lg flex items-center flex-shrink gap-4 font-semibold pb-2 leading-none tracking-tight">
8
+ <div className="absolute left-[50%] top-[50%] z-50 grid min-h-[50vh] w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-t-sm border border-t-4 bg-white p-6 text-black shadow-lg duration-200 sm:rounded-lg md:max-w-[568px] lg:max-w-[968px]">
9
+ <div className="flex min-w-0 max-w-full flex-col space-y-1.5">
10
+ <h2 className="flex flex-shrink items-center gap-4 pb-2 text-lg font-semibold leading-none tracking-tight">
11
11
  <svg
12
- className="h-6 w-6 text-red-600 font-extrabold"
12
+ className="h-6 w-6 font-extrabold text-red-600"
13
13
  fill="none"
14
14
  height="24"
15
15
  stroke="currentColor"
@@ -27,8 +27,8 @@ export const RenderingError = (props: { error: ErrorObject }) => {
27
27
  {props.error.name}: {props.error.message}
28
28
  </h2>
29
29
  {props.error.stack ? (
30
- <div className="text-sm p-2 flex-grow scroll-px-4 overflow-x-auto bg-red-500 rounded-lg text-gray-100">
31
- <pre className="font-mono w-full min-w-0 leading-7">
30
+ <div className="flex-grow scroll-px-4 overflow-x-auto rounded-lg bg-red-500 p-2 text-sm text-gray-100">
31
+ <pre className="w-full min-w-0 font-mono leading-7">
32
32
  {props.error.stack}
33
33
  </pre>
34
34
  </div>
@@ -1,9 +1,9 @@
1
1
  import * as SlotPrimitive from '@radix-ui/react-slot';
2
2
  import * as React from 'react';
3
- import { unreachable } from '../utils/unreachable';
4
3
  import { cn } from '../utils/cn';
4
+ import { unreachable } from '../utils/unreachable';
5
5
 
6
- type ButtonElement = React.ElementRef<'button'>;
6
+ type ButtonElement = React.ComponentRef<'button'>;
7
7
  type RootProps = React.ComponentPropsWithoutRef<'button'>;
8
8
 
9
9
  type Appearance = 'white' | 'gradient';
@@ -58,15 +58,15 @@ const getAppearance = (appearance: Appearance | undefined) => {
58
58
  case undefined:
59
59
  case 'white':
60
60
  return [
61
- 'bg-white text-black',
61
+ 'border-white bg-white text-black transition-colors duration-200 ease-in-out',
62
62
  'hover:bg-white/90',
63
- 'focus:ring-2 focus:ring-white/20 focus:outline-none focus:bg-white/90',
63
+ 'focus:bg-white/90 focus:outline-none focus:ring-2 focus:ring-white/20',
64
64
  ];
65
65
  case 'gradient':
66
66
  return [
67
- 'bg-gradient backdrop-blur-[20px] border-[#34343A]',
67
+ 'bg-gradient border-[#34343A] backdrop-blur-[1.25rem]',
68
68
  'hover:bg-gradientHover',
69
- 'focus:ring-2 focus:ring-white/20 focus:outline-none focus:bg-gradientHover',
69
+ 'focus:bg-gradientHover focus:outline-none focus:ring-2 focus:ring-white/20',
70
70
  ];
71
71
  default:
72
72
  unreachable(appearance);
@@ -79,9 +79,9 @@ const getSize = (size: Size | undefined) => {
79
79
  return '';
80
80
  case undefined:
81
81
  case '2':
82
- return 'text-[14px] h-8 px-3 rounded-md gap-2';
82
+ return 'text-[.875rem] h-8 px-3 rounded-md gap-2';
83
83
  case '3':
84
- return 'text-[14px] h-10 px-4 rounded-md gap-2';
84
+ return 'text-[.875rem] h-10 px-4 rounded-md gap-2';
85
85
  case '4':
86
86
  return 'text-base h-11 px-4 rounded-md gap-2';
87
87
  default:
@@ -2,8 +2,8 @@ import { LayoutGroup, motion } from 'framer-motion';
2
2
  import type { Language } from 'prism-react-renderer';
3
3
  import * as React from 'react';
4
4
  import { copyTextToClipboard } from '../utils';
5
- import languageMap from '../utils/language-map';
6
5
  import { tabTransition } from '../utils/constants';
6
+ import languageMap from '../utils/language-map';
7
7
  import { Code } from './code';
8
8
  import { IconButton } from './icons/icon-button';
9
9
  import { IconCheck } from './icons/icon-check';
@@ -37,7 +37,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
37
37
 
38
38
  return (
39
39
  <a
40
- className="text-slate-11 transition ease-in-out duration-200 hover:text-slate-12"
40
+ className="text-slate-11 transition duration-200 ease-in-out hover:text-slate-12"
41
41
  download={file.name}
42
42
  href={url}
43
43
  >
@@ -72,7 +72,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
72
72
 
73
73
  return (
74
74
  <div
75
- className="border-slate-6 relative w-full items-center whitespace-pre rounded-md border text-sm backdrop-blur-md"
75
+ className="relative w-full items-center whitespace-pre rounded-md border border-slate-6 text-sm backdrop-blur-md"
76
76
  style={{
77
77
  lineHeight: '130%',
78
78
  background:
@@ -87,7 +87,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
87
87
  const isCurrentLang = activeLang === language;
88
88
  return (
89
89
  <motion.button
90
- className={`relative py-[8px] px-4 text-sm font-medium font-sans transition ease-in-out duration-200 hover:text-slate-12 ${
90
+ className={`relative px-4 py-[8px] font-sans text-sm font-medium transition duration-200 ease-in-out hover:text-slate-12 ${
91
91
  activeLang !== language ? 'text-slate-11' : 'text-slate-12'
92
92
  }`}
93
93
  key={language}
@@ -98,7 +98,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
98
98
  {isCurrentLang ? (
99
99
  <motion.span
100
100
  animate={{ opacity: 1 }}
101
- className="absolute left-0 right-0 top-0 bottom-0 bg-slate-4"
101
+ className="absolute bottom-0 left-0 right-0 top-0 bg-slate-4"
102
102
  exit={{ opacity: 0 }}
103
103
  initial={{ opacity: 0 }}
104
104
  layoutId="code"
@@ -114,7 +114,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
114
114
  <Tooltip>
115
115
  <Tooltip.Trigger
116
116
  asChild
117
- className="absolute top-2 right-2 hidden md:block"
117
+ className="absolute right-2 top-2 hidden md:block"
118
118
  >
119
119
  {renderClipboardIcon()}
120
120
  </Tooltip.Trigger>
@@ -123,7 +123,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
123
123
  <Tooltip>
124
124
  <Tooltip.Trigger
125
125
  asChild
126
- className="text-gray-11 absolute top-2 right-8 hidden md:block"
126
+ className="text-gray-11 absolute right-8 top-2 hidden md:block"
127
127
  >
128
128
  {renderDownloadIcon()}
129
129
  </Tooltip.Trigger>
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+
3
+ const CodeSnippet = ({ children }) => {
4
+ return (
5
+ <code className="m-0.5 inline-block rounded-md bg-white/10 p-1 font-mono leading-none text-slate-12">
6
+ {children}
7
+ </code>
8
+ );
9
+ };
10
+
11
+ export default CodeSnippet;
@@ -60,7 +60,7 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
60
60
  '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%)',
61
61
  }}
62
62
  />
63
- <pre className="p-4 h-[650px] overflow-auto">
63
+ <pre className="h-[650px] overflow-auto p-4">
64
64
  {tokens.map((line, i) => {
65
65
  const lineProps = getLineProps({
66
66
  line,
@@ -68,12 +68,12 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
68
68
  });
69
69
  return (
70
70
  <div
71
- key={i}
72
71
  {...lineProps}
73
72
  className={cn('whitespace-pre', {
74
- "before:text-slate-11 before:mr-2 before:content-['$']":
73
+ "before:mr-2 before:text-slate-11 before:content-['$']":
75
74
  language === 'bash' && tokens.length === 1,
76
75
  })}
76
+ key={i}
77
77
  >
78
78
  {line.map((token, key) => {
79
79
  const tokenProps = getTokenProps({
@@ -99,7 +99,7 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
99
99
  })}
100
100
  </pre>
101
101
  <div
102
- className="absolute left-0 bottom-0 h-px w-[200px]"
102
+ className="absolute bottom-0 left-0 h-px w-[200px]"
103
103
  style={{
104
104
  background:
105
105
  '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%)',
@@ -1,6 +1,6 @@
1
1
  import * as SlotPrimitive from '@radix-ui/react-slot';
2
2
  import * as React from 'react';
3
- import { type As, unreachable, cn } from '../utils';
3
+ import { type As, cn, unreachable } from '../utils';
4
4
 
5
5
  export type HeadingSize =
6
6
  | '1'
@@ -11,7 +11,7 @@ export const IconButton = React.forwardRef<
11
11
  type="button"
12
12
  {...props}
13
13
  className={cn(
14
- 'rounded text-slate-11 focus:text-slate-12 ease-in-out transition duration-200 focus:outline-none focus:ring-2 focus:ring-gray-8 hover:text-slate-12',
14
+ 'focus:ring-gray-8 rounded text-slate-11 transition duration-200 ease-in-out hover:text-slate-12 focus:text-slate-12 focus:outline-none focus:ring-2',
15
15
  className,
16
16
  )}
17
17
  ref={forwardedRef}
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconCircleCheck = React.forwardRef<
6
+ IconElement,
7
+ Readonly<IconProps>
8
+ >(({ ...props }, forwardedRef) => (
9
+ <IconBase ref={forwardedRef} {...props}>
10
+ <g fill="currentColor">
11
+ <path d="M10.243 16.314L6 12.07l1.414-1.414l2.829 2.828l5.656-5.657l1.415 1.415z" />
12
+ <path
13
+ clipRule="evenodd"
14
+ d="M1 12C1 5.925 5.925 1 12 1s11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12m11 9a9 9 0 1 1 0-18a9 9 0 0 1 0 18"
15
+ fillRule="evenodd"
16
+ />
17
+ </g>
18
+ </IconBase>
19
+ ));
20
+
21
+ IconCircleCheck.displayName = 'IconCircleCheck';
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconCircleClose = React.forwardRef<
6
+ IconElement,
7
+ Readonly<IconProps>
8
+ >(({ ...props }, forwardedRef) => (
9
+ <IconBase ref={forwardedRef} {...props}>
10
+ <path
11
+ d="M12 4a8 8 0 1 0 0 16a8 8 0 0 0 0-16M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12m5.793-4.207a1 1 0 0 1 1.414 0L12 10.586l2.793-2.793a1 1 0 1 1 1.414 1.414L13.414 12l2.793 2.793a1 1 0 0 1-1.414 1.414L12 13.414l-2.793 2.793a1 1 0 0 1-1.414-1.414L10.586 12L7.793 9.207a1 1 0 0 1 0-1.414"
12
+ fill="currentColor"
13
+ />
14
+ </IconBase>
15
+ ));
16
+
17
+ IconCircleClose.displayName = 'IconCircleClose';
@@ -0,0 +1,17 @@
1
+ import * as React from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconCircleWarning = React.forwardRef<
6
+ IconElement,
7
+ Readonly<IconProps>
8
+ >(({ ...props }, forwardedRef) => (
9
+ <IconBase ref={forwardedRef} {...props}>
10
+ <path
11
+ d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8"
12
+ fill="currentColor"
13
+ />
14
+ </IconBase>
15
+ ));
16
+
17
+ IconCircleWarning.displayName = 'IconCircleWarning';
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconEmail = React.forwardRef<IconElement, Readonly<IconProps>>(
6
+ (props, forwardedRef) => {
7
+ return (
8
+ <IconBase {...props} ref={forwardedRef}>
9
+ <path
10
+ d="M20 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2m0 4.7l-8 5.334L4 8.7V6.297l8 5.333l8-5.333z"
11
+ fill="currentColor"
12
+ />
13
+ </IconBase>
14
+ );
15
+ },
16
+ );
17
+
18
+ IconEmail.displayName = 'IconEmail';
@@ -0,0 +1,14 @@
1
+ import { forwardRef } from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconLink = forwardRef<IconElement, IconProps>((props, ref) => (
6
+ <IconBase {...props} ref={ref}>
7
+ <path
8
+ d="m10 17.55l-1.77 1.72a2.47 2.47 0 0 1-3.5-3.5l4.54-4.55a2.46 2.46 0 0 1 3.39-.09l.12.1a1 1 0 0 0 1.4-1.43a3 3 0 0 0-.18-.21a4.46 4.46 0 0 0-6.09.22l-4.6 4.55a4.48 4.48 0 0 0 6.33 6.33L11.37 19A1 1 0 0 0 10 17.55M20.69 3.31a4.49 4.49 0 0 0-6.33 0L12.63 5A1 1 0 0 0 14 6.45l1.73-1.72a2.47 2.47 0 0 1 3.5 3.5l-4.54 4.55a2.46 2.46 0 0 1-3.39.09l-.12-.1a1 1 0 0 0-1.4 1.43a3 3 0 0 0 .23.21a4.47 4.47 0 0 0 6.09-.22l4.55-4.55a4.49 4.49 0 0 0 .04-6.33"
9
+ fill="currentColor"
10
+ />
11
+ </IconBase>
12
+ ));
13
+
14
+ IconLink.displayName = 'IconLink';
@@ -0,0 +1,14 @@
1
+ import { forwardRef } from 'react';
2
+ import type { IconElement, IconProps } from './icon-base';
3
+ import { IconBase } from './icon-base';
4
+
5
+ export const IconStamp = forwardRef<IconElement, IconProps>((props, ref) => (
6
+ <IconBase {...props} ref={ref}>
7
+ <path
8
+ d="M9.122 4.388A2.25 2.25 0 0 1 11.368 2h1.31a2.25 2.25 0 0 1 2.247 2.388l-.604 9.862h4.202a2.25 2.25 0 0 1 2.25 2.25v3.25a.75.75 0 0 1-.75.75h-.5v.75a.75.75 0 0 1-.75.75h-13.5a.75.75 0 0 1-.75-.75v-.75h-.5a.75.75 0 0 1-.75-.75V16.5a2.25 2.25 0 0 1 2.25-2.25h4.203zM19.273 19v-2.5a.75.75 0 0 0-.75-.75h-13a.75.75 0 0 0-.75.75V19zM13.427 4.296a.75.75 0 0 0-.748-.796h-1.31a.75.75 0 0 0-.75.796l.61 9.954h1.589z"
9
+ fill="currentColor"
10
+ />
11
+ </IconBase>
12
+ ));
13
+
14
+ IconStamp.displayName = 'IconStamp';
@@ -54,7 +54,7 @@ export const Send = ({ markup }: { markup: string }) => {
54
54
  >
55
55
  <Popover.Trigger asChild>
56
56
  <button
57
- className="box-border outline-none self-center w-20 h-5 flex items-center justify-center rounded-lg bg-slate-2 text-center transition duration-300 ease-in-out border border-slate-6 text-slate-11 text-sm px-4 py-4 hover:border-slate-10 hover:text-slate-12 font-sans"
57
+ className="box-border flex h-5 w-20 items-center justify-center self-center rounded-lg border border-slate-6 bg-slate-2 px-4 py-4 text-center font-sans text-sm text-slate-11 outline-none transition duration-300 ease-in-out hover:border-slate-10 hover:text-slate-12"
58
58
  type="submit"
59
59
  >
60
60
  Send
@@ -64,19 +64,19 @@ export const Send = ({ markup }: { markup: string }) => {
64
64
  <Popover.Portal>
65
65
  <Popover.Content
66
66
  align="end"
67
- className={`w-80 -mt-10 p-3 bg-black/70 backdrop-blur-lg border border-slate-6 text-slate-11 rounded-lg shadow-md font-sans ${inter.variable}`}
67
+ className={`-mt-10 w-80 rounded-lg border border-slate-6 bg-black/70 p-3 font-sans text-slate-11 shadow-md backdrop-blur-lg ${inter.variable}`}
68
68
  sideOffset={48}
69
69
  >
70
70
  <form className="mt-1" onSubmit={(e) => void onFormSubmit(e)}>
71
71
  <label
72
- className="text-slate-10 text-xs uppercase mb-2 block"
72
+ className="mb-2 block text-xs uppercase text-slate-10"
73
73
  htmlFor="to"
74
74
  >
75
75
  Recipient
76
76
  </label>
77
77
  <input
78
78
  autoFocus
79
- className="appearance-none rounded-lg px-2 py-1 mb-3 outline-none w-full bg-slate-3 border placeholder-slate-10 border-slate-6 text-slate-12 text-sm focus:ring-1 focus:ring-slate-10 transition duration-300 ease-in-out"
79
+ className="mb-3 w-full appearance-none rounded-lg border border-slate-6 bg-slate-3 px-2 py-1 text-sm text-slate-12 placeholder-slate-10 outline-none transition duration-300 ease-in-out focus:ring-1 focus:ring-slate-10"
80
80
  defaultValue={to}
81
81
  id="to"
82
82
  onChange={(e) => {
@@ -87,13 +87,13 @@ export const Send = ({ markup }: { markup: string }) => {
87
87
  type="email"
88
88
  />
89
89
  <label
90
- className="text-slate-10 text-xs uppercase mb-2 mt-1 block"
90
+ className="mb-2 mt-1 block text-xs uppercase text-slate-10"
91
91
  htmlFor="subject"
92
92
  >
93
93
  Subject
94
94
  </label>
95
95
  <input
96
- className="appearance-none rounded-lg px-2 py-1 mb-3 outline-none w-full bg-slate-3 border placeholder-slate-10 border-slate-6 text-slate-12 text-sm focus:ring-1 focus:ring-slate-10 transition duration-300 ease-in-out"
96
+ className="mb-3 w-full appearance-none rounded-lg border border-slate-6 bg-slate-3 px-2 py-1 text-sm text-slate-12 placeholder-slate-10 outline-none transition duration-300 ease-in-out focus:ring-1 focus:ring-slate-10"
97
97
  defaultValue={subject}
98
98
  id="subject"
99
99
  onChange={(e) => {
@@ -107,11 +107,11 @@ export const Send = ({ markup }: { markup: string }) => {
107
107
  className="appearance-none checked:bg-blue-500"
108
108
  type="checkbox"
109
109
  />
110
- <div className="flex items-center justify-between mt-3">
110
+ <div className="mt-3 flex items-center justify-between">
111
111
  <Text className="inline-block" size="1">
112
112
  Powered by{' '}
113
113
  <a
114
- className="text-white/85 hover:text-slate-12 transition ease-in-out duration-300"
114
+ className="text-white/85 transition duration-300 ease-in-out hover:text-slate-12"
115
115
  href="https://resend.com"
116
116
  rel="noreferrer"
117
117
  target="_blank"
@@ -120,7 +120,7 @@ export const Send = ({ markup }: { markup: string }) => {
120
120
  </a>
121
121
  </Text>
122
122
  <Button
123
- className="disabled:bg-slate-11 disabled:border-transparent"
123
+ className="disabled:border-transparent disabled:bg-slate-11"
124
124
  disabled={subject.length === 0 || to.length === 0 || isSending}
125
125
  type="submit"
126
126
  >