️ Improve email rendering speed (#654)

This commit is contained in:
Luke Vella 2023-04-06 15:40:19 +01:00 committed by GitHub
parent c6e61c3a72
commit 42794fedd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 319 additions and 329 deletions

View file

@ -14,10 +14,9 @@
"@aws-sdk/credential-provider-node": "^3.292.0",
"@react-email/components": "0.0.2",
"@react-email/render": "0.0.6",
"@react-email/tailwind": "0.0.6",
"clsx": "^1.2.1",
"nodemailer": "^6.9.1",
"react-email": "1.7.15"
"react-email": "^1.9.1"
},
"devDependencies": {
"@rallly/tailwind-config": "*",

View file

@ -87,6 +87,7 @@ export const sendEmail = async <T extends TemplateName>(
}
const Template = templates[templateName] as TemplateComponent<T>;
const html = render(<Template {...(options.props as any)} />);
try {
await sendRawEmail({
@ -97,7 +98,7 @@ export const sendEmail = async <T extends TemplateName>(
to: options.to,
subject: options.subject,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
html: render(<Template {...(options.props as any)} />),
html,
});
return;
} catch (e) {

View file

@ -1,19 +1,15 @@
import tailwindConfig from "@rallly/tailwind-config";
import { absoluteUrl } from "@rallly/utils";
import {
Body,
Container,
Head,
Hr,
Html,
Img,
Link,
Preview,
Section,
} from "@react-email/components";
import { Tailwind } from "@react-email/tailwind";
import { Text } from "./styled-components";
import { fontFamily, Section, Text } from "./styled-components";
interface EmailLayoutProps {
preview: string;
@ -21,6 +17,22 @@ interface EmailLayoutProps {
footNote?: React.ReactNode;
}
const containerStyles = {
maxWidth: "600px",
margin: "0 auto",
fontFamily,
};
const sectionStyles = {
marginTop: "16px",
marginBottom: "16px",
};
const linkStyles = {
color: "#64748B",
marginRight: "8px",
};
export const EmailLayout = ({
preview,
recipientName = "Guest",
@ -32,144 +44,38 @@ export const EmailLayout = ({
<Html>
<Head />
<Preview>{preview}</Preview>
<Tailwind
config={{
theme: {
extend: {
...tailwindConfig.theme.extend,
spacing: {
screen: "100vw",
full: "100%",
px: "1px",
0: "0",
0.5: "2px",
1: "4px",
1.5: "6px",
2: "8px",
2.5: "10px",
3: "12px",
3.5: "14px",
4: "16px",
4.5: "18px",
5: "20px",
5.5: "22px",
6: "24px",
6.5: "26px",
7: "28px",
7.5: "30px",
8: "32px",
8.5: "34px",
9: "36px",
9.5: "38px",
10: "40px",
11: "44px",
12: "48px",
14: "56px",
16: "64px",
20: "80px",
24: "96px",
28: "112px",
32: "128px",
36: "144px",
40: "160px",
44: "176px",
48: "192px",
52: "208px",
56: "224px",
60: "240px",
64: "256px",
72: "288px",
80: "320px",
96: "384px",
97.5: "390px",
120: "480px",
150: "600px",
160: "640px",
175: "700px",
"1/2": "50%",
"1/3": "33.333333%",
"2/3": "66.666667%",
"1/4": "25%",
"2/4": "50%",
"3/4": "75%",
"1/5": "20%",
"2/5": "40%",
"3/5": "60%",
"4/5": "80%",
"1/6": "16.666667%",
"2/6": "33.333333%",
"3/6": "50%",
"4/6": "66.666667%",
"5/6": "83.333333%",
"1/12": "8.333333%",
"2/12": "16.666667%",
"3/12": "25%",
"4/12": "33.333333%",
"5/12": "41.666667%",
"6/12": "50%",
"7/12": "58.333333%",
"8/12": "66.666667%",
"9/12": "75%",
"10/12": "83.333333%",
"11/12": "91.666667%",
},
borderRadius: {
none: "0px",
sm: "2px",
DEFAULT: "4px",
md: "6px",
lg: "8px",
xl: "12px",
"2xl": "16px",
"3xl": "24px",
},
},
},
}}
>
<Body className="bg-white p-3">
<Container className="max-w-xl">
<Section className="my-4">
<Body style={{ backgroundColor: "white", padding: "16px" }}>
<Container style={containerStyles}>
<Img src={absoluteUrl("/logo.png")} alt="Rallly" width={128} />
</Section>
<Section>
<Section style={sectionStyles}>
<Text>Hi {firstName},</Text>
{children}
{footNote ? (
<>
<Hr />
<Text light={true}>{footNote}</Text>
</>
<Text style={{ color: "#64748B", fontFamily }}>{footNote}</Text>
) : null}
</Section>
<Section className="mt-4 text-sm text-slate-500">
<Link className="font-sans text-slate-500" href={absoluteUrl()}>
<Section style={{ ...sectionStyles, fontSize: 14 }}>
<Link style={linkStyles} href={absoluteUrl()}>
Home
</Link>
&nbsp;&bull;&nbsp;
<Link
className="font-sans text-slate-500"
href="https://twitter.com/ralllyco"
>
<span>&nbsp;&bull;&nbsp;</span>
<Link style={linkStyles} href="https://twitter.com/ralllyco">
Twitter
</Link>
&nbsp;&bull;&nbsp;
<Link
className="font-sans text-slate-500"
href="https://github.com/lukevella/rallly"
>
<span>&nbsp;&bull;&nbsp;</span>
<Link style={linkStyles} href="https://github.com/lukevella/rallly">
Github
</Link>
&nbsp;&bull;&nbsp;
<span>&nbsp;&bull;&nbsp;</span>
<Link
className="font-sans text-slate-500"
style={linkStyles}
href="https://www.paypal.com/donate/?hosted_button_id=7QXP2CUBLY88E"
>
Donate
</Link>
&nbsp;&bull;&nbsp;
<span>&nbsp;&bull;&nbsp;</span>
<Link
className="font-sans text-slate-500"
style={linkStyles}
href={`mailto:${process.env.SUPPORT_EMAIL}`}
>
Contact
@ -177,7 +83,6 @@ export const EmailLayout = ({
</Section>
</Container>
</Body>
</Tailwind>
</Html>
);
};

View file

@ -1,43 +0,0 @@
import { absoluteUrl } from "@rallly/utils";
import { Hr } from "@react-email/components";
import { Container } from "@react-email/container";
import { Link, SmallText, Text } from "./styled-components";
import { removeProtocalFromUrl } from "./utils";
export interface NewPollBaseEmailProps {
title: string;
name: string;
adminLink: string;
}
export const NewPollBaseEmail = ({
name,
title,
adminLink,
children,
}: React.PropsWithChildren<NewPollBaseEmailProps>) => {
return (
<Container>
<Text>Hi {name},</Text>
<Text>
Your poll <strong>&quot;{title}&quot;</strong> has been created.
</Text>
<Text>
To manage your poll use the <em>admin link</em> below.
</Text>
<Text>
<Link href={adminLink}>
<span className="font-mono">{adminLink}</span> &rarr;
</Link>
</Text>
{children}
<Hr />
<SmallText>
You are receiving this email because a new poll was created with this
email address on{" "}
<Link href={absoluteUrl()}>{removeProtocalFromUrl(absoluteUrl())}</Link>
</SmallText>
</Container>
);
};

View file

@ -10,23 +10,24 @@ import {
Text as UnstyledText,
TextProps,
} from "@react-email/components";
import clsx from "clsx";
import { getDomain } from "./utils";
export const Text = (
props: TextProps & { light?: boolean; small?: boolean },
) => {
const { light, small, className, ...forwardProps } = props;
const { light, small, ...forwardProps } = props;
return (
<UnstyledText
{...forwardProps}
className={clsx(
"my-4 font-sans ",
{ "text-base": !small, "text-sm": small },
{ "text-slate-800": !light, "text-slate-500": light },
className,
)}
style={{
margin: "16px 0",
fontFamily,
fontSize: small ? "14px" : "16px",
color: light ? "#64748B" : "#374151",
lineHeight: "1.5",
...props.style,
}}
/>
);
};
@ -39,10 +40,15 @@ export const Button = (props: ButtonProps) => {
return (
<UnstyledButton
{...props}
className={clsx(
"bg-primary-600 rounded px-3 py-2 font-sans text-white",
props.className,
)}
className={props.className}
style={{
backgroundColor: "#4F46E5",
borderRadius: "4px",
padding: "8px 12px",
fontFamily,
fontSize: "16px",
color: "white",
}}
/>
);
};
@ -51,7 +57,7 @@ export const Link = (props: LinkProps) => {
return (
<UnstyledLink
{...props}
className={clsx("text-primary-600", props.className)}
style={{ color: "#4F46E5", fontFamily, ...props.style }}
/>
);
};
@ -60,35 +66,53 @@ export const Heading = (
props: React.ComponentProps<typeof UnstyledHeading>,
) => {
const { as = "h3" } = props;
const fontSize = {
h1: "32px",
h2: "24px",
h3: "20px",
h4: "16px",
h5: "14px",
h6: "12px",
};
return (
<UnstyledHeading
{...props}
as={as}
className={clsx(
"mt-4 mb-2 font-sans font-semibold text-slate-800",
props.className,
)}
style={{
marginTop: "16px",
marginBottom: "8px",
fontFamily: "sans-serif",
fontWeight: "bold",
fontSize: fontSize[as],
color: "#1E293B",
...props.style,
}}
/>
);
};
export const SubHeadingText = (props: TextProps) => {
const { className, ...forwardProps } = props;
return (
<UnstyledText
{...forwardProps}
className={clsx(
"mb-4 mt-2 font-sans text-base text-slate-800",
className,
)}
{...props}
style={{
marginBottom: "16px",
marginTop: "8px",
fontSize: 16,
color: "#374151",
fontFamily,
...props.style,
}}
/>
);
};
export const Section = (props: SectionProps) => {
const { className, ...forwardProps } = props;
return (
<UnstyledSection {...forwardProps} className={clsx("my-4", className)} />
<UnstyledSection
{...props}
style={{ marginTop: "16px", marginBottom: "16px", ...props.style }}
/>
);
};
@ -96,7 +120,11 @@ export const SmallText = (props: TextProps) => {
return (
<UnstyledText
{...props}
className={clsx("font-sans text-sm text-slate-500", props.className)}
style={{
fontSize: "14px",
color: "#6B7280",
...props.style,
}}
/>
);
};
@ -105,7 +133,20 @@ export const Card = (props: SectionProps) => {
return (
<Section
{...props}
className={clsx("rounded bg-gray-50 px-4", props.className)}
style={{
borderRadius: "4px",
backgroundColor: "#F1F5F9",
paddingRight: "16px",
paddingLeft: "16px",
border: "1px solid #E2E8F0",
}}
/>
);
};
export const trackingWide = {
letterSpacing: 2,
};
export const fontFamily =
"'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;";

View file

@ -5,6 +5,7 @@ import {
Domain,
Heading,
Text,
trackingWide,
} from "./components/styled-components";
import { getDomain } from "./components/utils";
@ -45,7 +46,7 @@ export const LoginEmail = ({
<Card>
<Heading>Option 2: Verification Code</Heading>
<Text>Enter this one-time 6-digit verification code.</Text>
<Heading as="h1" className="tracking-widest" id="code">
<Heading as="h1" style={trackingWide} id="code">
{code}
</Heading>
<Text light={true}>This code will expire in 15 minutes.</Text>

View file

@ -41,6 +41,23 @@ const ShareLink = ({
);
};
const LinkContainer = (props: { href: string }) => {
return (
<Text
style={{
borderRadius: "4px",
backgroundColor: "white",
padding: "12px",
border: "1px solid #E2E8F0",
}}
>
<Link href={props.href} style={{ letterSpacing: 1 }}>
{props.href}
</Link>
</Text>
);
};
export const NewPollEmail = ({
title = "Untitled Poll",
name = "John",
@ -60,18 +77,15 @@ export const NewPollEmail = ({
preview="Share your participant link to start collecting responses."
>
<Text>
Your poll is live! Here are two links you will need to manage your poll.
Your poll for <strong>{title}</strong> is live! Here are two links you
will need to manage your poll.
</Text>
<Card>
<Heading>Admin link</Heading>
<SubHeadingText>
Use this link to view results and make changes to your poll.
</SubHeadingText>
<Text className="rounded bg-white px-4 py-3">
<Link href={adminLink} className="font-mono">
{adminLink}
</Link>
</Text>
<LinkContainer href={adminLink} />
<Text>
<Button href={adminLink}>Go to admin page</Button>
</Text>
@ -82,11 +96,7 @@ export const NewPollEmail = ({
Copy this link and share it with your participants to start collecting
responses.
</SubHeadingText>
<Text className="rounded bg-white px-4 py-3">
<Link href={participantLink} className="font-mono">
{participantLink}
</Link>
</Text>
<LinkContainer href={participantLink} />
<Text>
<ShareLink
title={title}

View file

@ -1,5 +1,10 @@
import { EmailLayout } from "./components/email-layout";
import { Domain, Heading, Text } from "./components/styled-components";
import {
Domain,
Heading,
Text,
trackingWide,
} from "./components/styled-components";
interface RegisterEmailProps {
name: string;
@ -25,7 +30,7 @@ export const RegisterEmail = ({
<Text>
Please use the following 6-digit verification code to verify your email:
</Text>
<Heading as="h1" className="font-sans tracking-widest" id="code">
<Heading as="h1" style={{ ...trackingWide }} id="code">
{code}
</Heading>
<Text>This code is valid for 15 minutes</Text>

253
yarn.lock
View file

@ -2182,6 +2182,107 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@octokit/auth-token@^3.0.0":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.3.tgz#ce7e48a3166731f26068d7a7a7996b5da58cbe0c"
integrity sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==
dependencies:
"@octokit/types" "^9.0.0"
"@octokit/core@^4.1.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.0.tgz#8c253ba9605aca605bc46187c34fcccae6a96648"
integrity sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==
dependencies:
"@octokit/auth-token" "^3.0.0"
"@octokit/graphql" "^5.0.0"
"@octokit/request" "^6.0.0"
"@octokit/request-error" "^3.0.0"
"@octokit/types" "^9.0.0"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^7.0.0":
version "7.0.5"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.5.tgz#2bb2a911c12c50f10014183f5d596ce30ac67dd1"
integrity sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==
dependencies:
"@octokit/types" "^9.0.0"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^5.0.0":
version "5.0.5"
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.5.tgz#a4cb3ea73f83b861893a6370ee82abb36e81afd2"
integrity sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==
dependencies:
"@octokit/request" "^6.0.0"
"@octokit/types" "^9.0.0"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^16.0.0":
version "16.0.0"
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-16.0.0.tgz#d92838a6cd9fb4639ca875ddb3437f1045cc625e"
integrity sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==
"@octokit/plugin-paginate-rest@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz#f34b5a7d9416019126042cd7d7b811e006c0d561"
integrity sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==
dependencies:
"@octokit/types" "^9.0.0"
"@octokit/plugin-request-log@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
"@octokit/plugin-rest-endpoint-methods@^7.0.0":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz#f7ebe18144fd89460f98f35a587b056646e84502"
integrity sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==
dependencies:
"@octokit/types" "^9.0.0"
deprecation "^2.3.1"
"@octokit/request-error@^3.0.0":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.3.tgz#ef3dd08b8e964e53e55d471acfe00baa892b9c69"
integrity sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==
dependencies:
"@octokit/types" "^9.0.0"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^6.0.0":
version "6.2.3"
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.3.tgz#76d5d6d44da5c8d406620a4c285d280ae310bdb4"
integrity sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==
dependencies:
"@octokit/endpoint" "^7.0.0"
"@octokit/request-error" "^3.0.0"
"@octokit/types" "^9.0.0"
is-plain-object "^5.0.0"
node-fetch "^2.6.7"
universal-user-agent "^6.0.0"
"@octokit/rest@19.0.7":
version "19.0.7"
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.7.tgz#d2e21b4995ab96ae5bfae50b4969da7e04e0bb70"
integrity sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==
dependencies:
"@octokit/core" "^4.1.0"
"@octokit/plugin-paginate-rest" "^6.0.0"
"@octokit/plugin-request-log" "^1.0.4"
"@octokit/plugin-rest-endpoint-methods" "^7.0.0"
"@octokit/types@^9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.0.0.tgz#6050db04ddf4188ec92d60e4da1a2ce0633ff635"
integrity sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==
dependencies:
"@octokit/openapi-types" "^16.0.0"
"@peculiar/asn1-schema@^2.1.6", "@peculiar/asn1-schema@^2.3.0":
version "2.3.3"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.3.tgz#21418e1f3819e0b353ceff0c2dad8ccb61acd777"
@ -2586,16 +2687,6 @@
dependencies:
react "18.2.0"
"@react-email/tailwind@0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@react-email/tailwind/-/tailwind-0.0.6.tgz#9342806d430d104f44022a9891977dfd96a5aa28"
integrity sha512-lwLjKJY7+sLGFmh/5GRhmCfmbvPSTiAHi+ERfDTY7FQrReKab4YHIO3oZWCcOOpUZ4JpNdNe8ri09HRBN9VZVA==
dependencies:
html-react-parser "3.0.9"
react "18.2.0"
react-dom "18.2.0"
tw-to-css "0.0.10"
"@react-email/text@0.0.4":
version "0.0.4"
resolved "https://registry.yarnpkg.com/@react-email/text/-/text-0.0.4.tgz#097b725fbd834de90f0f993fd4ddbd716a53fe29"
@ -3647,6 +3738,11 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
before-after-hook@^2.2.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==
big-integer@^1.6.17:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
@ -4180,6 +4276,11 @@ defined@^1.0.0:
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf"
integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
dequal@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
@ -4273,13 +4374,6 @@ domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
domhandler@5.0.3, domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"
domhandler@^4.2.0, domhandler@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
@ -4287,6 +4381,13 @@ domhandler@^4.2.0, domhandler@^4.3.1:
dependencies:
domelementtype "^2.2.0"
domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"
domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
@ -4518,7 +4619,7 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5:
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
@ -4839,11 +4940,6 @@ extend-shallow@^2.0.1:
dependencies:
is-extendable "^0.1.0"
extend@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@ -5001,6 +5097,15 @@ framesync@6.0.1:
dependencies:
tslib "^2.1.0"
fs-extra@11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.0.tgz#5784b102104433bb0e090f48bfc4a30742c357ed"
integrity sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
@ -5311,14 +5416,6 @@ hosted-git-info@^2.1.4:
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
html-dom-parser@3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-3.1.3.tgz#ba87ca379f2817ca733523cac55c90de6bac43dd"
integrity sha512-fI0yyNlIeSboxU+jnrA4v8qj4+M8SI9/q6AKYdwCY2qki22UtKCDTxvagHniECu7sa5/o2zFRdLleA67035lsA==
dependencies:
domhandler "5.0.3"
htmlparser2 "8.0.1"
html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
@ -5326,16 +5423,6 @@ html-parse-stringify@^3.0.1:
dependencies:
void-elements "3.1.0"
html-react-parser@3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-3.0.9.tgz#f9428f3b1689e4b0d538f944ef18f53ea66345d1"
integrity sha512-gOPZmaCMXNYu7Y9+58k2tLhTMXQ+QN8ctNFijzLuBxJaLZ6TsN+tUpN+MhbI+6nGaBCRGT2rpw6y/AqkTFZckg==
dependencies:
domhandler "5.0.3"
html-dom-parser "3.1.3"
react-property "2.0.0"
style-to-js "1.1.3"
html-to-text@9.0.3:
version "9.0.3"
resolved "https://registry.yarnpkg.com/html-to-text/-/html-to-text-9.0.3.tgz#331368f32fcb270c59dbd3a7fdb32813d2a490bc"
@ -5347,7 +5434,7 @@ html-to-text@9.0.3:
htmlparser2 "^8.0.1"
selderee "^0.10.0"
htmlparser2@8.0.1, htmlparser2@^8.0.1:
htmlparser2@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010"
integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==
@ -5454,11 +5541,6 @@ ini@^1.3.4:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inline-style-parser@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
inline-style-prefixer@^6.0.0:
version "6.0.4"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz#4290ed453ab0e4441583284ad86e41ad88384f44"
@ -5649,6 +5731,11 @@ is-plain-object@^2.0.1:
dependencies:
isobject "^3.0.1"
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-reference@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
@ -5871,6 +5958,15 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea"
@ -6484,7 +6580,7 @@ object.values@^1.1.6:
define-properties "^1.1.4"
es-abstract "^1.20.4"
once@^1.3.0:
once@^1.3.0, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@ -6668,15 +6764,6 @@ popmotion@11.0.3:
style-value-types "5.0.0"
tslib "^2.1.0"
postcss-css-variables@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/postcss-css-variables/-/postcss-css-variables-0.18.0.tgz#d97b6da19e86245eb817006e11117382f997bb93"
integrity sha512-lYS802gHbzn1GI+lXvy9MYIYDuGnl1WB4FTKoqMQqJ3Mab09A7a/1wZvGTkCEZJTM8mSbIyb1mJYn8f0aPye0Q==
dependencies:
balanced-match "^1.0.0"
escape-string-regexp "^1.0.3"
extend "^3.0.1"
postcss-import@^14.1.0:
version "14.1.0"
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
@ -6738,7 +6825,7 @@ postcss@8.4.14:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@8.4.21, postcss@^8.0.9, postcss@^8.4.21:
postcss@^8.0.9, postcss@^8.4.21:
version "8.4.21"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
@ -6882,18 +6969,20 @@ react-dom@18.2.0, react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-email@1.7.15:
version "1.7.15"
resolved "https://registry.yarnpkg.com/react-email/-/react-email-1.7.15.tgz#a847891face3c961a72f423a7787ed04936b4148"
integrity sha512-dzjH8YJ5n+Pxe0vkISkiZttBa6ZhHdQ8Fc/8n5rfOwIniGzz1D1LlwwzdL7ctUyHab41S7O4kWsLzD6I82xGXQ==
react-email@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/react-email/-/react-email-1.9.1.tgz#3b38bba3d881e91ba27a1edd826e4f4a14a3d3e0"
integrity sha512-+gRvxDeFIYuXDDg5vM57kOf1KUDGwB38AM1BQzdI9tWUWw3qas3U+yC0yFuxH8nwCQfMUZ4FKN7BqACWo/KSnw==
dependencies:
"@commander-js/extra-typings" "9.4.1"
"@manypkg/find-root" "2.1.0"
"@octokit/rest" "19.0.7"
"@react-email/render" "0.0.6"
chokidar "3.5.3"
commander "9.4.1"
detect-package-manager "2.0.1"
esbuild "0.16.4"
fs-extra "11.1.0"
glob "8.0.3"
log-symbols "4.1.0"
normalize-path "3.0.0"
@ -6954,11 +7043,6 @@ react-overlays@^5.2.1:
uncontrollable "^7.2.1"
warning "^4.0.3"
react-property@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136"
integrity sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==
react-remove-scroll-bar@^2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
@ -7600,20 +7684,6 @@ strnum@^1.0.5:
resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
style-to-js@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.3.tgz#2012d75dc89bf400edc29c545ed61c8626b00184"
integrity sha512-zKI5gN/zb7LS/Vm0eUwjmjrXWw8IMtyA8aPBJZdYiQTXj4+wQ3IucOLIOnF7zCHxvW8UhIGh/uZh/t9zEHXNTQ==
dependencies:
style-to-object "0.4.1"
style-to-object@0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.1.tgz#53cf856f7cf7f172d72939d9679556469ba5de37"
integrity sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==
dependencies:
inline-style-parser "0.1.1"
style-value-types@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-5.0.0.tgz#76c35f0e579843d523187989da866729411fc8ad"
@ -7707,7 +7777,7 @@ tailwindcss-animate@^1.0.5:
resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.5.tgz#a6720e3b0616e1ff922b32846729881c626a069d"
integrity sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==
tailwindcss@3.2.7, tailwindcss@^3.2.4, tailwindcss@^3.2.7:
tailwindcss@^3.2.4, tailwindcss@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.7.tgz#5936dd08c250b05180f0944500c01dce19188c07"
integrity sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==
@ -7910,15 +7980,6 @@ turbo@^1.8.8:
turbo-windows-64 "1.8.8"
turbo-windows-arm64 "1.8.8"
tw-to-css@0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/tw-to-css/-/tw-to-css-0.0.10.tgz#e14afd698d998a1a61ecc307ed2ca5ca1c313f58"
integrity sha512-Uxq/wers7ZAbl5xnISDcFSpfol6DtNxTw6ZUgM1GExgaMUH84RHDB8MMtF4UcFnXc+MByShhC0gAjWhZ6aVWjg==
dependencies:
postcss "8.4.21"
postcss-css-variables "0.18.0"
tailwindcss "3.2.7"
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@ -8008,11 +8069,21 @@ unicode-property-aliases-ecmascript@^2.0.0:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd"
integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
unzipper@^0.10.11:
version "0.10.11"
resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e"