react-email 3.0.7 → 4.0.0-alpha.1
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/CHANGELOG.md +17 -0
- package/dist/cli/index.js +10 -4
- package/dist/cli/index.mjs +9 -3
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +14 -12
- package/dist/preview/.next/build-manifest.json +3 -3
- package/dist/preview/.next/cache/.rscinfo +1 -1
- package/dist/preview/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/preview/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/preview/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/preview/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/preview/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +1 -1
- package/dist/preview/.next/required-server-files.json +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
- package/dist/preview/.next/server/app/page.js +1 -1
- package/dist/preview/.next/server/app/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +5 -5
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/196.js +1 -1
- package/dist/preview/.next/server/chunks/282.js +15 -0
- package/dist/preview/.next/server/chunks/667.js +1 -0
- package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.json +1 -1
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/server/webpack-runtime.js +1 -1
- package/dist/preview/.next/static/chunks/207-7ab46c2d84f60fed.js +1 -0
- package/dist/preview/.next/static/chunks/490-9a10c001ec2dffb2.js +1 -0
- package/dist/preview/.next/static/chunks/afa401a5-9ebf2515b1397993.js +6 -0
- package/dist/preview/.next/static/chunks/app/layout-f1bad3fcfbc7eb6b.js +1 -0
- package/dist/preview/.next/static/chunks/app/page-800163ba6c6d943d.js +1 -0
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-5b5c4557fc89db64.js +1 -0
- package/dist/preview/.next/static/chunks/{main-app-771a0fc4ad5aa154.js → main-app-d1b0aa870bcfb13e.js} +1 -1
- package/dist/preview/.next/static/css/d6c4def4cc3fb858.css +3 -0
- package/dist/preview/.next/trace +22 -21
- package/dist/preview/.next/types/app/layout.ts +1 -1
- package/dist/preview/.next/types/app/preview/[...slug]/page.ts +1 -1
- package/package.json +8 -2
- package/src/actions/email-validation/check-images.spec.tsx +90 -0
- package/src/actions/email-validation/check-images.ts +142 -0
- package/src/actions/email-validation/check-links.spec.tsx +92 -0
- package/src/actions/email-validation/check-links.ts +91 -0
- package/src/actions/email-validation/get-line-and-column-from-index.spec.ts +22 -0
- package/src/actions/email-validation/get-line-and-column-from-index.ts +43 -0
- package/src/actions/email-validation/quick-fetch.ts +12 -0
- package/src/animated-icons-data/help.json +1082 -0
- package/src/animated-icons-data/link.json +1309 -0
- package/src/animated-icons-data/load.json +443 -0
- package/src/animated-icons-data/mail.json +1320 -0
- package/src/app/globals.css +0 -24
- package/src/app/layout.tsx +6 -2
- package/src/app/page.tsx +8 -9
- package/src/app/preview/[...slug]/page.tsx +1 -0
- package/src/app/preview/[...slug]/preview.tsx +3 -3
- package/src/app/preview/[...slug]/rendering-error.tsx +6 -6
- package/src/components/button.tsx +53 -42
- package/src/components/code-container.tsx +6 -6
- package/src/components/code-snippet.tsx +11 -0
- package/src/components/code.tsx +4 -4
- package/src/components/icons/icon-button.tsx +1 -1
- package/src/components/icons/icon-circle-check.tsx +21 -0
- package/src/components/icons/icon-circle-close.tsx +17 -0
- package/src/components/icons/icon-circle-warning.tsx +17 -0
- package/src/components/icons/icon-email.tsx +18 -0
- package/src/components/icons/icon-image.tsx +19 -0
- package/src/components/icons/icon-link.tsx +14 -0
- package/src/components/icons/icon-stamp.tsx +14 -0
- package/src/components/send.tsx +9 -9
- package/src/components/shell.tsx +32 -34
- package/src/components/sidebar/checking-results.tsx +150 -0
- package/src/components/sidebar/{sidebar-directory-children.tsx → file-tree-directory-children.tsx} +19 -15
- package/src/components/sidebar/{sidebar-directory.tsx → file-tree-directory.tsx} +9 -10
- package/src/components/sidebar/file-tree.tsx +31 -0
- package/src/components/sidebar/image-checker.tsx +161 -0
- package/src/components/sidebar/link-checker.tsx +151 -0
- package/src/components/sidebar/sidebar.tsx +344 -22
- package/src/components/tooltip-content.tsx +2 -2
- package/src/components/topbar.tsx +13 -16
- package/src/hooks/use-icon-animation.ts +41 -0
- package/tsconfig.json +1 -0
- package/dist/preview/.next/server/chunks/693.js +0 -1
- package/dist/preview/.next/server/chunks/720.js +0 -10
- package/dist/preview/.next/static/chunks/12-b9450aa0845e7574.js +0 -1
- package/dist/preview/.next/static/chunks/154-f7f86c8589140c56.js +0 -1
- package/dist/preview/.next/static/chunks/app/layout-6d33e2ffcffd58d4.js +0 -1
- package/dist/preview/.next/static/chunks/app/page-43a07e4b8c5c0840.js +0 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-71202390d5f9a34b.js +0 -1
- package/dist/preview/.next/static/css/a34876a6c565fff8.css +0 -3
- /package/dist/preview/.next/static/{RZga3-2qKYa2RLg-hxunV → Mn2FuRztLqr32yO8CKHi9}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{RZga3-2qKYa2RLg-hxunV → Mn2FuRztLqr32yO8CKHi9}/_ssgManifest.js +0 -0
package/src/app/globals.css
CHANGED
|
@@ -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
|
}
|
package/src/app/layout.tsx
CHANGED
|
@@ -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=
|
|
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
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import Image from 'next/image';
|
|
3
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
|
|
15
|
-
<div className="
|
|
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: '
|
|
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"
|
|
31
|
+
<Text as="p">
|
|
31
32
|
To start developing your emails, you can create a<br />
|
|
32
|
-
<
|
|
33
|
-
|
|
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>
|
|
@@ -93,7 +93,7 @@ const Preview = ({
|
|
|
93
93
|
<>
|
|
94
94
|
{activeView === 'desktop' && (
|
|
95
95
|
<iframe
|
|
96
|
-
className="w-full bg-white
|
|
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="
|
|
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="
|
|
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="
|
|
9
|
-
<div className="flex
|
|
10
|
-
<h2 className="
|
|
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
|
|
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="
|
|
31
|
-
<pre className="
|
|
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,10 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
|
1
3
|
import * as SlotPrimitive from '@radix-ui/react-slot';
|
|
2
|
-
import * as React from 'react';
|
|
4
|
+
import type * as React from 'react';
|
|
5
|
+
import animatedLoadIcon from '../animated-icons-data/load.json';
|
|
3
6
|
import { cn } from '../utils/cn';
|
|
4
7
|
import { unreachable } from '../utils/unreachable';
|
|
5
8
|
|
|
6
|
-
type
|
|
7
|
-
type RootProps = React.ComponentPropsWithoutRef<'button'>;
|
|
9
|
+
type RootProps = React.ComponentProps<'button'>;
|
|
8
10
|
|
|
9
11
|
type Appearance = 'white' | 'gradient';
|
|
10
12
|
type Size = '1' | '2' | '3' | '4';
|
|
@@ -13,43 +15,51 @@ interface ButtonProps extends RootProps {
|
|
|
13
15
|
asChild?: boolean;
|
|
14
16
|
appearance?: Appearance;
|
|
15
17
|
size?: Size;
|
|
18
|
+
loading?: boolean;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export const Button =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
) => {
|
|
30
|
-
const classNames = cn(
|
|
31
|
-
getSize(size),
|
|
32
|
-
getAppearance(appearance),
|
|
33
|
-
'inline-flex items-center justify-center border font-medium',
|
|
34
|
-
className,
|
|
35
|
-
);
|
|
21
|
+
export const Button = ({
|
|
22
|
+
asChild,
|
|
23
|
+
appearance = 'white',
|
|
24
|
+
className,
|
|
25
|
+
children,
|
|
26
|
+
size = '2',
|
|
27
|
+
loading,
|
|
28
|
+
ref,
|
|
29
|
+
...props
|
|
30
|
+
}: ButtonProps) => {
|
|
31
|
+
const Root = asChild ? SlotPrimitive.Slot : 'button';
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
33
|
+
return (
|
|
34
|
+
<Root
|
|
35
|
+
ref={ref}
|
|
36
|
+
type="button"
|
|
37
|
+
{...props}
|
|
38
|
+
className={cn(
|
|
39
|
+
getSize(size),
|
|
40
|
+
getAppearance(appearance),
|
|
41
|
+
'inline-flex items-center justify-center gap-2 border font-medium',
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
aria-disabled={loading}
|
|
45
|
+
>
|
|
46
|
+
<span
|
|
47
|
+
className={cn(
|
|
48
|
+
'-ml-7 opacity-0 transition-opacity duration-200',
|
|
49
|
+
loading && 'opacity-100',
|
|
50
|
+
)}
|
|
47
51
|
>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
<DotLottieReact
|
|
53
|
+
data={animatedLoadIcon}
|
|
54
|
+
autoplay={false}
|
|
55
|
+
className="h-5 w-5"
|
|
56
|
+
loop={true}
|
|
57
|
+
/>
|
|
58
|
+
</span>
|
|
59
|
+
<SlotPrimitive.Slottable>{children}</SlotPrimitive.Slottable>
|
|
60
|
+
</Root>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
53
63
|
|
|
54
64
|
Button.displayName = 'Button';
|
|
55
65
|
|
|
@@ -58,15 +68,16 @@ const getAppearance = (appearance: Appearance | undefined) => {
|
|
|
58
68
|
case undefined:
|
|
59
69
|
case 'white':
|
|
60
70
|
return [
|
|
61
|
-
'bg-white text-black',
|
|
71
|
+
'border-white bg-white text-black transition-colors duration-200 ease-in-out',
|
|
62
72
|
'hover:bg-white/90',
|
|
63
|
-
'focus:
|
|
73
|
+
'focus:bg-white/90 focus:outline-none focus:ring-2 focus:ring-white/20',
|
|
74
|
+
'mt-2 mb-4 aria-disabled:border-transparent aria-disabled:bg-slate-11',
|
|
64
75
|
];
|
|
65
76
|
case 'gradient':
|
|
66
77
|
return [
|
|
67
|
-
'bg-gradient
|
|
78
|
+
'bg-gradient border-[#34343A] backdrop-blur-[1.25rem]',
|
|
68
79
|
'hover:bg-gradientHover',
|
|
69
|
-
'focus:
|
|
80
|
+
'focus:bg-gradientHover focus:outline-none focus:ring-2 focus:ring-white/20',
|
|
70
81
|
];
|
|
71
82
|
default:
|
|
72
83
|
unreachable(appearance);
|
|
@@ -79,9 +90,9 @@ const getSize = (size: Size | undefined) => {
|
|
|
79
90
|
return '';
|
|
80
91
|
case undefined:
|
|
81
92
|
case '2':
|
|
82
|
-
return 'text-[
|
|
93
|
+
return 'text-[.875rem] h-8 px-3 rounded-md gap-2';
|
|
83
94
|
case '3':
|
|
84
|
-
return 'text-[
|
|
95
|
+
return 'text-[.875rem] h-10 px-4 rounded-md gap-2';
|
|
85
96
|
case '4':
|
|
86
97
|
return 'text-base h-11 px-4 rounded-md gap-2';
|
|
87
98
|
default:
|
|
@@ -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
|
|
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="
|
|
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]
|
|
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
|
|
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
|
|
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
|
|
126
|
+
className="text-gray-11 absolute right-8 top-2 hidden md:block"
|
|
127
127
|
>
|
|
128
128
|
{renderDownloadIcon()}
|
|
129
129
|
</Tooltip.Trigger>
|
package/src/components/code.tsx
CHANGED
|
@@ -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="
|
|
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:
|
|
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
|
|
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%)',
|
|
@@ -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
|
|
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,19 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import type { IconElement, IconProps } from './icon-base';
|
|
3
|
+
import { IconBase } from './icon-base';
|
|
4
|
+
|
|
5
|
+
export const IconImage = forwardRef<IconElement, IconProps>((props, ref) => (
|
|
6
|
+
<IconBase {...props} ref={ref}>
|
|
7
|
+
<g
|
|
8
|
+
fill="none"
|
|
9
|
+
stroke="currentColor"
|
|
10
|
+
strokeLinecap="round"
|
|
11
|
+
strokeLinejoin="round"
|
|
12
|
+
strokeWidth="2"
|
|
13
|
+
>
|
|
14
|
+
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
|
15
|
+
<circle cx="9" cy="9" r="2" />
|
|
16
|
+
<path d="m21 15l-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
|
|
17
|
+
</g>
|
|
18
|
+
</IconBase>
|
|
19
|
+
));
|
|
@@ -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';
|
package/src/components/send.tsx
CHANGED
|
@@ -54,7 +54,7 @@ export const Send = ({ markup }: { markup: string }) => {
|
|
|
54
54
|
>
|
|
55
55
|
<Popover.Trigger asChild>
|
|
56
56
|
<button
|
|
57
|
-
className="box-border
|
|
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={
|
|
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="
|
|
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
|
|
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="
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
>
|