diff --git a/.changeset/pink-rabbits-deny.md b/.changeset/pink-rabbits-deny.md new file mode 100644 index 0000000000..043905ec10 --- /dev/null +++ b/.changeset/pink-rabbits-deny.md @@ -0,0 +1,5 @@ +--- +"@react-email/components": major +--- + +tailwind: update to using tailwindcss@v4 diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..47636f018f --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,39 @@ +{ + "mode": "pre", + "tag": "canary", + "initialVersions": { + "demo": "0.0.0", + "docs": "0.0.0", + "web": "0.0.0", + "@benchmarks/preview-server": "0.0.0", + "@benchmarks/tailwind-component": "0.0.0", + "@react-email/body": "0.1.0", + "@react-email/button": "0.2.0", + "@react-email/code-block": "0.1.0", + "@react-email/code-inline": "0.0.5", + "@react-email/column": "0.0.13", + "@react-email/components": "0.5.7", + "@react-email/container": "0.0.15", + "create-email": "1.2.2", + "@react-email/font": "0.0.9", + "@react-email/head": "0.0.12", + "@react-email/heading": "0.0.15", + "@react-email/hr": "0.0.11", + "@react-email/html": "0.0.11", + "@react-email/img": "0.0.11", + "@react-email/link": "0.0.12", + "@react-email/markdown": "0.0.16", + "@react-email/preview": "0.0.13", + "@react-email/preview-server": "4.3.1", + "react-email": "4.3.1", + "email-dev": "0.0.2", + "@react-email/render": "1.4.0", + "@react-email/row": "0.0.12", + "@react-email/section": "0.0.16", + "@react-email/tailwind": "1.2.2", + "@react-email/text": "0.1.5", + "tsconfig": "0.0.0", + "playground": "0.0.9" + }, + "changesets": ["pink-rabbits-deny", "rich-files-stick"] +} diff --git a/.changeset/rich-files-stick.md b/.changeset/rich-files-stick.md new file mode 100644 index 0000000000..9f5ca355a2 --- /dev/null +++ b/.changeset/rich-files-stick.md @@ -0,0 +1,6 @@ +--- +"@react-email/tailwind": major +--- + +update to using tailwindcss@v4 + diff --git a/apps/demo/emails/magic-links/aws-verify-email.tsx b/apps/demo/emails/magic-links/aws-verify-email.tsx index ab93659440..8155680ee3 100644 --- a/apps/demo/emails/magic-links/aws-verify-email.tsx +++ b/apps/demo/emails/magic-links/aws-verify-email.tsx @@ -9,8 +9,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface AWSVerifyEmailProps { verificationCode?: string; @@ -26,59 +28,76 @@ export default function AWSVerifyEmail({ return ( - - AWS Email Verification - -
-
- AWS's Logo -
-
- Verify your email address - - Thanks for starting the new AWS account creation process. We - want to make sure it's really you. Please enter the following - verification code when prompted. If you don't want to - create an account, you can ignore this message. - -
- Verification code - - {verificationCode} - - (This code is valid for 10 minutes) + + + AWS Email Verification + +
+
+ AWS's Logo +
+
+ + Verify your email address + + + Thanks for starting the new AWS account creation process. We + want to make sure it's really you. Please enter the following + verification code when prompted. If you don't want to + create an account, you can ignore this message. + +
+ + Verification code + + + + {verificationCode} + + + (This code is valid for 10 minutes) + +
+
+
+
+ + Amazon Web Services will never email you and ask you to + disclose or verify your password, credit card, or banking + account number.
-
-
- - Amazon Web Services will never email you and ask you to disclose - or verify your password, credit card, or banking account number. - -
-
- - This message was produced and distributed by Amazon Web Services, - Inc., 410 Terry Ave. North, Seattle, WA 98109. © 2022, Amazon Web - Services, Inc.. All rights reserved. AWS is a registered trademark - of{' '} - - Amazon.com - - , Inc. View our{' '} - - privacy policy - - . - - - + + This message was produced and distributed by Amazon Web Services, + Inc., 410 Terry Ave. North, Seattle, WA 98109. © 2022, Amazon Web + Services, Inc.. All rights reserved. AWS is a registered trademark + of{' '} + + Amazon.com + + , Inc. View our{' '} + + privacy policy + + . + + + + ); } @@ -86,90 +105,3 @@ export default function AWSVerifyEmail({ AWSVerifyEmail.PreviewProps = { verificationCode: '596853', } satisfies AWSVerifyEmailProps; - -const main = { - backgroundColor: '#fff', - color: '#212121', -}; - -const container = { - padding: '20px', - margin: '0 auto', - backgroundColor: '#eee', -}; - -const h1 = { - color: '#333', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '20px', - fontWeight: 'bold', - marginBottom: '15px', -}; - -const link = { - color: '#2754C5', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '14px', - textDecoration: 'underline', -}; - -const text = { - color: '#333', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '14px', - margin: '24px 0', -}; - -const imageSection = { - backgroundColor: '#252f3d', - display: 'flex', - padding: '20px 0', - alignItems: 'center', - justifyContent: 'center', -}; - -const coverSection = { backgroundColor: '#fff' }; - -const upperSection = { padding: '25px 35px' }; - -const lowerSection = { padding: '25px 35px' }; - -const footerText = { - ...text, - fontSize: '12px', - padding: '0 20px', -}; - -const verifyText = { - ...text, - margin: 0, - fontWeight: 'bold', - textAlign: 'center' as const, -}; - -const codeText = { - ...text, - fontWeight: 'bold', - fontSize: '36px', - margin: '10px 0', - textAlign: 'center' as const, -}; - -const validityText = { - ...text, - margin: '0px', - textAlign: 'center' as const, -}; - -const verificationSection = { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', -}; - -const mainText = { ...text, marginBottom: '14px' }; - -const cautionText = { ...text, margin: '0px' }; diff --git a/apps/demo/emails/magic-links/linear-login-code.tsx b/apps/demo/emails/magic-links/linear-login-code.tsx index 6c6265daf6..1e94cb076d 100644 --- a/apps/demo/emails/magic-links/linear-login-code.tsx +++ b/apps/demo/emails/magic-links/linear-login-code.tsx @@ -10,8 +10,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface LinearLoginCodeEmailProps { validationCode?: string; @@ -26,33 +28,46 @@ export const LinearLoginCodeEmail = ({ }: LinearLoginCodeEmailProps) => ( - - Your login code for Linear - - Linear - Your login code for Linear -
- -
- - This link and code will only be valid for the next 5 minutes. If the - link does not work, you can use the login verification code directly: - - {validationCode} -
- - Linear - -
- + + + Your login code for Linear + + Linear + + Your login code for Linear + +
+ +
+ + This link and code will only be valid for the next 5 minutes. If the + link does not work, you can use the login verification code + directly: + + + {validationCode} + +
+ + Linear + +
+ +
); @@ -61,74 +76,3 @@ LinearLoginCodeEmail.PreviewProps = { } as LinearLoginCodeEmailProps; export default LinearLoginCodeEmail; - -const logo = { - borderRadius: 21, - width: 42, - height: 42, -}; - -const main = { - backgroundColor: '#ffffff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const container = { - margin: '0 auto', - padding: '20px 0 48px', - maxWidth: '560px', -}; - -const heading = { - fontSize: '24px', - letterSpacing: '-0.5px', - lineHeight: '1.3', - fontWeight: '400', - color: '#484848', - padding: '17px 0 0', -}; - -const paragraph = { - margin: '0 0 15px', - fontSize: '15px', - lineHeight: '1.4', - color: '#3c4149', -}; - -const buttonContainer = { - padding: '27px 0 27px', -}; - -const button = { - backgroundColor: '#5e6ad2', - borderRadius: '3px', - fontWeight: '600', - color: '#fff', - fontSize: '15px', - textDecoration: 'none', - textAlign: 'center' as const, - display: 'block', - padding: '11px 23px', -}; - -const reportLink = { - fontSize: '14px', - color: '#b4becc', -}; - -const hr = { - borderColor: '#dfe1e4', - margin: '42px 0 26px', -}; - -const code = { - fontFamily: 'monospace', - fontWeight: '700', - padding: '1px 4px', - backgroundColor: '#dfe1e4', - letterSpacing: '-0.3px', - fontSize: '21px', - borderRadius: '4px', - color: '#3c4149', -}; diff --git a/apps/demo/emails/magic-links/notion-magic-link.tsx b/apps/demo/emails/magic-links/notion-magic-link.tsx index 1fe5774d4c..ddbebb400b 100644 --- a/apps/demo/emails/magic-links/notion-magic-link.tsx +++ b/apps/demo/emails/magic-links/notion-magic-link.tsx @@ -7,8 +7,10 @@ import { Img, Link, Preview, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface NotionMagicLinkEmailProps { loginCode?: string; @@ -23,66 +25,54 @@ export const NotionMagicLinkEmail = ({ }: NotionMagicLinkEmailProps) => ( - - Log in with this magic link - - Login - - Click here to log in with this magic link - - - Or, copy and paste this temporary login code: - - {loginCode} - - If you didn't try to login, you can safely ignore this email. - - - Hint: You can set a permanent password in Settings & members → My - account. - - Notion's Logo - + + + Log in with this magic link + + + Login + - Notion.so + Click here to log in with this magic link - , the all-in-one-workspace -
- for your notes, tasks, wikis, and databases. -
-
- + + Or, copy and paste this temporary login code: + + + {loginCode} + + + If you didn't try to login, you can safely ignore this email. + + + Hint: You can set a permanent password in Settings & members → My + account. + + Notion's Logo + + + Notion.so + + , the all-in-one-workspace +
+ for your notes, tasks, wikis, and databases. +
+ + + ); @@ -91,59 +81,3 @@ NotionMagicLinkEmail.PreviewProps = { } as NotionMagicLinkEmailProps; export default NotionMagicLinkEmail; - -const main = { - backgroundColor: '#ffffff', -}; - -const container = { - paddingLeft: '12px', - paddingRight: '12px', - margin: '0 auto', -}; - -const h1 = { - color: '#333', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '24px', - fontWeight: 'bold', - margin: '40px 0', - padding: '0', -}; - -const link = { - color: '#2754C5', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '14px', - textDecoration: 'underline', -}; - -const text = { - color: '#333', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '14px', - margin: '24px 0', -}; - -const footer = { - color: '#898989', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", - fontSize: '12px', - lineHeight: '22px', - marginTop: '12px', - marginBottom: '24px', -}; - -const code = { - display: 'inline-block', - padding: '16px 4.5%', - width: '90.5%', - backgroundColor: '#f4f4f4', - borderRadius: '5px', - border: '1px solid #eee', - color: '#333', -}; diff --git a/apps/demo/emails/magic-links/plaid-verify-identity.tsx b/apps/demo/emails/magic-links/plaid-verify-identity.tsx index cd967538d3..1be7fe2b58 100644 --- a/apps/demo/emails/magic-links/plaid-verify-identity.tsx +++ b/apps/demo/emails/magic-links/plaid-verify-identity.tsx @@ -7,8 +7,10 @@ import { Img, Link, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface PlaidVerifyIdentityEmailProps { validationCode?: string; @@ -23,33 +25,46 @@ export const PlaidVerifyIdentityEmail = ({ }: PlaidVerifyIdentityEmailProps) => ( - - - Plaid - Verify Your Identity - - Enter the following code to finish linking Venmo. - -
- {validationCode} -
- Not expecting this email? - - Contact{' '} - - login@plaid.com - {' '} - if you did not request this code. + + + + Plaid + + Verify Your Identity + + + Enter the following code to finish linking Venmo. + +
+ + {validationCode} + +
+ + Not expecting this email? + + + Contact{' '} + + login@plaid.com + {' '} + if you did not request this code. + +
+ + Securely powered by Plaid. -
- Securely powered by Plaid. - + + ); @@ -58,99 +73,3 @@ PlaidVerifyIdentityEmail.PreviewProps = { } as PlaidVerifyIdentityEmailProps; export default PlaidVerifyIdentityEmail; - -const main = { - backgroundColor: '#ffffff', - fontFamily: 'HelveticaNeue,Helvetica,Arial,sans-serif', -}; - -const container = { - backgroundColor: '#ffffff', - border: '1px solid #eee', - borderRadius: '5px', - boxShadow: '0 5px 10px rgba(20,50,70,.2)', - marginTop: '20px', - maxWidth: '360px', - margin: '0 auto', - padding: '68px 0 130px', -}; - -const logo = { - margin: '0 auto', -}; - -const tertiary = { - color: '#0a85ea', - fontSize: '11px', - fontWeight: 700, - fontFamily: 'HelveticaNeue,Helvetica,Arial,sans-serif', - height: '16px', - letterSpacing: '0', - lineHeight: '16px', - margin: '16px 8px 8px 8px', - textTransform: 'uppercase' as const, - textAlign: 'center' as const, -}; - -const secondary = { - color: '#000', - display: 'inline-block', - fontFamily: 'HelveticaNeue-Medium,Helvetica,Arial,sans-serif', - fontSize: '20px', - fontWeight: 500, - lineHeight: '24px', - marginBottom: '0', - marginTop: '0', - textAlign: 'center' as const, -}; - -const codeContainer = { - background: 'rgba(0,0,0,.05)', - borderRadius: '4px', - margin: '16px auto 14px', - verticalAlign: 'middle', - width: '280px', -}; - -const code = { - color: '#000', - fontFamily: 'HelveticaNeue-Bold', - fontSize: '32px', - fontWeight: 700, - letterSpacing: '6px', - lineHeight: '40px', - paddingBottom: '8px', - paddingTop: '8px', - margin: '0 auto', - display: 'block', - textAlign: 'center' as const, -}; - -const paragraph = { - color: '#444', - fontSize: '15px', - fontFamily: 'HelveticaNeue,Helvetica,Arial,sans-serif', - letterSpacing: '0', - lineHeight: '23px', - padding: '0 40px', - margin: '0', - textAlign: 'center' as const, -}; - -const link = { - color: '#444', - textDecoration: 'underline', -}; - -const footer = { - color: '#000', - fontSize: '12px', - fontWeight: 800, - letterSpacing: '0', - lineHeight: '23px', - margin: '0', - marginTop: '20px', - fontFamily: 'HelveticaNeue,Helvetica,Arial,sans-serif', - textAlign: 'center' as const, - textTransform: 'uppercase' as const, -}; diff --git a/apps/demo/emails/magic-links/raycast-magic-link.tsx b/apps/demo/emails/magic-links/raycast-magic-link.tsx index 5a8e7c1b4e..1d091f0d1c 100644 --- a/apps/demo/emails/magic-links/raycast-magic-link.tsx +++ b/apps/demo/emails/magic-links/raycast-magic-link.tsx @@ -9,8 +9,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface RaycastMagicLinkEmailProps { magicLink?: string; @@ -25,47 +27,52 @@ export const RaycastMagicLinkEmail = ({ }: RaycastMagicLinkEmailProps) => ( - - Log in with this magic link. - - Raycast - 🪄 Your magic link -
- - - 👉 Click here to sign in 👈 - + + + Log in with this magic link. + + Raycast + + 🪄 Your magic link + +
+ + + 👉 Click here to sign in 👈 + + + + If you didn't request this, please ignore this email. + +
+ + Best, +
- Raycast Team
- - If you didn't request this, please ignore this email. +
+ + + Raycast Technologies Inc. -
- - Best, -
- Raycast Team -
-
- - Raycast Technologies Inc. - - 2093 Philadelphia Pike #3222, Claymont, DE 19703 - -
- + + 2093 Philadelphia Pike #3222, Claymont, DE 19703 + + + + ); @@ -74,47 +81,3 @@ RaycastMagicLinkEmail.PreviewProps = { } as RaycastMagicLinkEmailProps; export default RaycastMagicLinkEmail; - -const main = { - backgroundColor: '#ffffff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const container = { - margin: '0 auto', - padding: '20px 25px 48px', - backgroundImage: 'url("/static/raycast-bg.png")', - backgroundPosition: 'bottom', - backgroundRepeat: 'no-repeat, no-repeat', -}; - -const heading = { - fontSize: '28px', - fontWeight: 'bold', - marginTop: '48px', -}; - -const body = { - margin: '24px 0', -}; - -const paragraph = { - fontSize: '16px', - lineHeight: '26px', -}; - -const link = { - color: '#FF6363', -}; - -const hr = { - borderColor: '#dddddd', - marginTop: '48px', -}; - -const footer = { - color: '#8898aa', - fontSize: '12px', - marginLeft: '4px', -}; diff --git a/apps/demo/emails/magic-links/slack-confirm.tsx b/apps/demo/emails/magic-links/slack-confirm.tsx index a9269416ac..01c3a7f546 100644 --- a/apps/demo/emails/magic-links/slack-confirm.tsx +++ b/apps/demo/emails/magic-links/slack-confirm.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface SlackConfirmEmailProps { validationCode?: string; @@ -26,121 +28,127 @@ export const SlackConfirmEmail = ({ }: SlackConfirmEmailProps) => ( - - Confirm your email address - -
- Slack -
- Confirm your email address - - Your confirmation code is below - enter it in your open browser window - and we'll help you get signed in. - + + + Confirm your email address + +
+ Slack +
+ + Confirm your email address + + + Your confirmation code is below - enter it in your open browser + window and we'll help you get signed in. + -
- {validationCode} -
+
+ + {validationCode} + +
- - If you didn't request this email, there's nothing to worry about, you - can safely ignore it. - + + If you didn't request this email, there's nothing to worry about, + you can safely ignore it. + -
- - - Slack - - - - Slack - - +
+ + Slack - - - Slack - - - -
- -
- - Our blog - -    |    - - Policies - -    |    - - Help center - -    |    - - Slack Community - - - ©2022 Slack Technologies, LLC, a Salesforce company.
- 500 Howard Street, San Francisco, CA 94105, USA
-
- All rights reserved. -
-
- - +
+ + + Slack + + + Slack + + + Slack + + +
+
+ +
+ + Our blog + +    |    + + Policies + +    |    + + Help center + +    |    + + Slack Community + + + ©2022 Slack Technologies, LLC, a Salesforce company.
+ 500 Howard Street, San Francisco, CA 94105, USA
+
+ All rights reserved. +
+
+
+ +
); @@ -149,77 +157,3 @@ SlackConfirmEmail.PreviewProps = { } as SlackConfirmEmailProps; export default SlackConfirmEmail; - -const footerText = { - fontSize: '12px', - color: '#b7b7b7', - lineHeight: '15px', - textAlign: 'left' as const, - marginBottom: '50px', -}; - -const footerLink = { - color: '#b7b7b7', - textDecoration: 'underline', -}; - -const footerLogos = { - marginBottom: '32px', - paddingLeft: '8px', - paddingRight: '8px', -}; - -const socialMediaIcon = { - display: 'inline', - marginLeft: '8px', -}; - -const main = { - backgroundColor: '#ffffff', - margin: '0 auto', - fontFamily: - "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", -}; - -const container = { - margin: '0 auto', - padding: '0px 20px', -}; - -const logoContainer = { - marginTop: '32px', -}; - -const h1 = { - color: '#1d1c1d', - fontSize: '36px', - fontWeight: '700', - margin: '30px 0', - padding: '0', - lineHeight: '42px', -}; - -const heroText = { - fontSize: '20px', - lineHeight: '28px', - marginBottom: '30px', -}; - -const codeBox = { - background: 'rgb(245, 244, 245)', - borderRadius: '4px', - marginBottom: '30px', - padding: '40px 10px', -}; - -const confirmationCodeText = { - fontSize: '30px', - textAlign: 'center' as const, - verticalAlign: 'middle', -}; - -const text = { - color: '#000', - fontSize: '14px', - lineHeight: '24px', -}; diff --git a/apps/demo/emails/newsletters/codepen-challengers.tsx b/apps/demo/emails/newsletters/codepen-challengers.tsx index d72e903041..af35271c89 100644 --- a/apps/demo/emails/newsletters/codepen-challengers.tsx +++ b/apps/demo/emails/newsletters/codepen-challengers.tsx @@ -11,8 +11,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` @@ -21,398 +23,263 @@ const baseUrl = process.env.VERCEL_URL export const CodepenChallengersEmail = () => ( - - #CodePenChallenge: Cubes -
- codepen -
- - - View this Challenge on CodePen - - - - This week: #CodePenChallenge:{' '} - Cubes - - -
- The Shape challenge continues! - - - Last week, we kicked things off with round shapes. We "rounded" up - the Pens from week one in our{' '} - #CodePenChallenge: Round collection. + + + #CodePenChallenge: Cubes +
+ codepen +
+ + + + View this Challenge on CodePen + - This week, we move on to cubes 🧊 + + This week: #CodePenChallenge:{' '} + Cubes + + +
+ The Shape challenge continues! + + + Last week, we kicked things off with round shapes. We "rounded" up + the Pens from week one in our{' '} + + #CodePenChallenge: Round + {' '} + collection. + - - Creating cubes in the browser is all about mastery of illusion. Take - control of perspective and shadows and you can make the magic of 3D - on a flat screen 🧙 - + This week, we move on to cubes 🧊 - - This week is a fun chance to work on your CSS shape-building skills, - or dig into a 3D JavaScript library like Three.js. - + + Creating cubes in the browser is all about mastery of illusion. + Take control of perspective and shadows and you can make the magic + of 3D on a flat screen 🧙 + - - This week's starter template features an ice cube emoji to help - inspire a "cool" idea for your Pen. As always, the template is just - as jumping off point. Feel free to incorporate the 🧊 in your - creation, add more elements, or freeze it out completely and start - over from scratch! - + + This week is a fun chance to work on your CSS shape-building + skills, or dig into a 3D JavaScript library like Three.js. + - - 💪 Your Challenge:{' '} - - create a Pen that includes cube shapes. - - + + This week's starter template features an ice cube emoji to help + inspire a "cool" idea for your Pen. As always, the template is + just as jumping off point. Feel free to incorporate the 🧊 in your + creation, add more elements, or freeze it out completely and start + over from scratch! + - codepen + + 💪 Your Challenge:{' '} + + create a Pen that includes cube shapes. + + -
codepen - - CodePen PRO combines a bunch of features that can help any - front-end designer or developer at any experience level. - - - +
+ codepen + + + CodePen PRO combines a bunch of features that can help any + front-end designer or developer at any experience level. + + + +
-
- - - To participate:{' '} - Create a Pen → and tag it{' '} - - codepenchallenge - {' '} - and - - {' '} - cpc-cubes - - . We'll be watching and gathering the Pens into a Collection, and - sharing on Twitter and{' '} - Instagram (Use the #CodePenChallenge tag - on Twitter and Instagram as well). - -
- - - IDEAS! - -
- 🌟 - - This week we move from 2 dimensions to three! Maybe you could - exercise your perspective in CSS - to create a 3D cube. Or, you can try out creating 3D shapes in - JavaScript, using WebGL or - building a Three.js scene. - -
- -
- 🌟 - - There's more to cubes than just six square sides. There are - variations on the cube that could be fun to play with this - week: cuboid shapes are - hexahedrons with faces that aren't always squares. And if you - want to really push the boundaries of shape, consider the 4 - dimensional tesseract! - -
- -
- 🌟 - - Here's a mind-bending idea that can combine the round shapes - from week one with this week's cube theme:{' '} - Spherical Cubes 😳 Solving - longstanding mathematical mysteries is probably outside the - scope of a CodePen challenge, but you could use front-end - tools to explore fitting spheres into cubes, or vice-versa. - -
-
- - RESOURCES! - -
- 📖 - - Learn all about{' '} - How CSS Perspective Works and - how to build a 3D CSS cube from scratch in Amit Sheen's - in-depth tutorial for CSS-Tricks. Or, check out stunning - examples of WebGL cubes from Matthias Hurrle:{' '} - Just Ice and{' '} - Posing. - -
+ + To participate:{' '} + Create a Pen →{' '} + and tag it{' '} + + codepenchallenge + {' '} + and + + {' '} + cpc-cubes + + . We'll be watching and gathering the Pens into a Collection, and + sharing on{' '} + Twitter and{' '} + Instagram (Use + the #CodePenChallenge tag on Twitter and Instagram as well). + -
- 📖 - - Want to go beyond the square cube? Draw inspiration from - EntropyReversed's{' '} - Pulsating Tesseract, Josetxu's{' '} - Rainbow Cuboid Loader, or Ana - Tudor's{' '} - Pure CSS cuboid jellyfish. +
+ + + IDEAS! + +
+ 🌟 + + This week we move from 2 dimensions to three! Maybe you + could exercise your{' '} + + perspective + {' '} + in CSS to create a 3D cube. Or, you can try out creating 3D + shapes in JavaScript, using{' '} + WebGL or + building a{' '} + + Three.js scene + + . + +
+ +
+ 🌟 + + There's more to cubes than just six square sides. There are + variations on the cube that could be fun to play with this + week:{' '} + + cuboid shapes + {' '} + are hexahedrons with faces that aren't always squares. And + if you want to really push the boundaries of shape, consider + the 4 dimensional{' '} + + tesseract! + + +
+ +
+ 🌟 + + Here's a mind-bending idea that can combine the round shapes + from week one with this week's cube theme:{' '} + + Spherical Cubes + {' '} + 😳 Solving longstanding mathematical mysteries is probably + outside the scope of a CodePen challenge, but you could use + front-end tools to explore fitting spheres into cubes, or + vice-versa. + +
+
+ + + RESOURCES! -
-
- 📖 - - Did that spherical cubes concept pique your interest? Explore - Ryan Mulligan's Cube Sphere, - Munir Safi's{' '} - - 3D Sphere to Cube Animation With Virtual Trackball - {' '} - and Ana Tudor's{' '} - Infinitely unpack prism for more - mindbending cube concepts that test the boundaries of how - shapes interact with each other. - -
- - -
+
+ 📖 + + Learn all about{' '} + + How CSS Perspective Works + {' '} + and how to build a 3D CSS cube from scratch in Amit Sheen's + in-depth tutorial for CSS-Tricks. Or, check out stunning + examples of WebGL cubes from Matthias Hurrle:{' '} + Just Ice{' '} + and{' '} + Posing. + +
+ +
+ 📖 + + Want to go beyond the square cube? Draw inspiration from + EntropyReversed's{' '} + + Pulsating Tesseract + + , Josetxu's{' '} + + Rainbow Cuboid Loader + + , or Ana Tudor's{' '} + + Pure CSS cuboid jellyfish + + . + +
+ +
+ 📖 + + Did that spherical cubes concept pique your interest? + Explore Ryan Mulligan's{' '} + + Cube Sphere + + , Munir Safi's{' '} + + 3D Sphere to Cube Animation With Virtual Trackball + {' '} + and Ana Tudor's{' '} + + Infinitely unpack prism + {' '} + for more mindbending cube concepts that test the boundaries + of how shapes interact with each other. + +
+
+
+
-
- -
+
+ +
-
- - You can adjust your{' '} - email preferences any time, or{' '} - instantly opt out of emails of this - kind. Need help with anything? Hit up{' '} - support. - -
-
- +
+ + You can adjust your{' '} + + email preferences + {' '} + any time, or{' '} + + instantly opt out + {' '} + of emails of this kind. Need help with anything? Hit up{' '} + + support + + . + +
+ + +
); export default CodepenChallengersEmail; - -const main = { - fontFamily: '"Google Sans",Roboto,RobotoDraft,Helvetica,Arial,sans-serif', - backgroundColor: '#505050', - margin: '0', -}; - -const imgHeader = { - margin: 'auto', - maxWidth: '100%', -}; - -const imgCube = { - maxWidth: '100%', -}; - -const header = { - width: '100%', - backgroundColor: '#191919', - margin: '0 auto', - paddingBottom: '30px', - zIndex: '999', -}; - -const container = { - margin: '0 auto', - width: '648px', - maxWidth: '100%', - position: 'relative' as const, -}; - -const challengeLink = { - backgroundColor: '#505050', - textAlign: 'center' as const, - padding: '10px 0', - fontSize: '13px', - position: 'absolute' as const, - width: '648px', - maxWidth: '100%', - top: '-28px', - margin: '0 0 16px 0', -}; - -const link = { - color: '#fff', - cursor: 'pointer', -}; - -const blueLink = { - color: '#15c', - cursor: 'pointer', -}; - -const heading = { - background: '#f0d361', - padding: '30px', - color: '#191919', - fontWeight: '400', - marginBottom: '0', -}; - -const section = { - margin: '0', - background: '#fff', - padding: '0 24px', -}; - -const yellowSection = { - background: '#f5d247', - padding: '30px', - fontSize: '18px', - lineHeight: '1.5', -}; - -const text = { - fontSize: '16px', -}; - -const cubeText = { fontSize: '32px', margin: '4px 0 0 0' }; - -const yourChallenge = { - fontSize: '16px', - border: '6px solid #ebd473', - padding: '20px', - margin: '0 0 40px 0', -}; - -const sectionPro = { - marginTop: '40px', - marginBottom: '24px', - textAlign: 'center' as const, - background: '#0b112a', - color: '#fff', - padding: '35px 20px 30px 20px', - border: '6px solid #2138c6', -}; - -const imagePro = { margin: '0 auto 30px auto' }; - -const button = { - background: '#2138c6', - color: '#fff', - border: '0', - fontSize: '15px', - lineHeight: '18px', - cursor: 'pointer', - borderRadius: '4px', - padding: '12px', -}; - -const resourcesTitle = { - fontWeight: '900', - lineHeight: '1.1', - marginTop: '-40px', - fontSize: '18px', -}; - -const ideasTitle = { - fontWeight: '900', - lineHeight: '1.1', - fontSize: '18px', -}; - -const ideas = { - width: '50%', - paddingRight: '10px', -}; - -const resources = { - width: '50%', - paddingLeft: '10px', -}; - -const card = { - padding: '20px', - margin: '0 0 20px 0', - borderRadius: '10px', - fontSize: '36px', - textAlign: 'center' as const, -}; - -const yellowCard = { - ...card, - background: '#fff4c8', - border: '1px solid #f4d247', -}; - -const blueCard = { - ...card, - background: '#d9f6ff', - border: '1px solid #92bfd0', -}; - -const textCard = { - fontSize: '13px', - textAlign: 'left' as const, -}; - -const goToChallenge = { - margin: '40px 0 120px 0', - textAlign: 'center' as const, -}; - -const footerButton = { - fontSize: '26px', - color: '#15c', - background: '#222', - borderRadius: '4px', - fontWeight: 'bold', - cursor: 'pointer', - padding: '15px 30px', -}; - -const footer = { - background: '#fff', - color: '#505050', - padding: '0 24px', - marginBottom: '48px', -}; - -const footerText = { - fontSize: '13px', -}; - -const footerLink = { - textDecoration: 'underline', - color: '#505050', - cursor: 'pointer', -}; diff --git a/apps/demo/emails/newsletters/google-play-policy-update.tsx b/apps/demo/emails/newsletters/google-play-policy-update.tsx index 079e50de8d..0db7403682 100644 --- a/apps/demo/emails/newsletters/google-play-policy-update.tsx +++ b/apps/demo/emails/newsletters/google-play-policy-update.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` @@ -20,171 +22,167 @@ const baseUrl = process.env.VERCEL_URL export const GooglePlayPolicyUpdateEmail = () => ( - - Google Play developers - -
- - - Google Play developers header blue transparent - Google Play - - -
- -
-
- DEVELOPER UPDATE - Hello Google Play Developer, - - We strive to make Google Play a safe and trusted experience for - users. - - - We've added clarifications to our{' '} - - Target API Level policy - - . Because this is a clarification, our enforcement standards and - practices for this policy remain the same. - -
-
- - We’re noting exceptions to the{' '} - - Target API Level policy - - , which can be found in our updated{' '} - - Help Center article. - - These exceptions include permanently private apps and apps that - target automotive or wearables form factors and are bundled within - the same package.{' '} - - Learn more - - -
-
- - We’re also extending the deadline to give you more time to adjust to - these changes. Now, apps that target API level 29 or below will - start experiencing reduced distribution starting Jan 31, 2023{' '} - instead of Nov 1, 2022. If you need more time to update your app, - you can request an extension to keep your app discoverable to all - users until May 1, 2023. - -
-
- -
- Thank you, - - The Google Play team - -
- -
- - Connect with us - - - - + + + Google Play developers + +
+ + Google Play developers header blue transparent - - - - Google Play + + +
+ +
+
+ + DEVELOPER UPDATE + + + Hello Google Play Developer, + + + We strive to make Google Play a safe and trusted experience for + users. + + + We've added clarifications to our{' '} + + Target API Level policy - - - - + . Because this is a clarification, our enforcement standards and + practices for this policy remain the same. + +
+
+ + We're noting exceptions to the{' '} + + Target API Level policy + + , which can be found in our updated{' '} + + Help Center article. - - - - - -
- -
- - © 2022 Google LLC 1600 Amphitheatre Parkway, Mountain View, CA - 94043, USA - - - You have received this mandatory email service announcement to - update you about important changes to your Google Play Developer - account. - -
-
- + These exceptions include permanently private apps and apps that + target automotive or wearables form factors and are bundled within + the same package.{' '} + + Learn more + + +
+
+ + We're also extending the deadline to give you more time to adjust + to these changes. Now, apps that target API level 29 or below will + start experiencing reduced distribution starting{' '} + Jan 31, 2023 instead of Nov 1, 2022. If you need more time + to update your app, you can request an extension to keep your app + discoverable to all users until May 1, 2023. + +
+
+ +
+ + Thank you, + + + The Google Play team + +
+ +
+ + + Connect with us + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + © 2022 Google LLC 1600 Amphitheatre Parkway, Mountain View, CA + 94043, USA + + + You have received this mandatory email service announcement to + update you about important changes to your Google Play Developer + account. + +
+
+ + ); export default GooglePlayPolicyUpdateEmail; -const main = { - backgroundColor: '#dbddde', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - const sectionLogo = { padding: '0 40px', }; diff --git a/apps/demo/emails/newsletters/stack-overflow-tips.tsx b/apps/demo/emails/newsletters/stack-overflow-tips.tsx index f7819747ea..465cd8c278 100644 --- a/apps/demo/emails/newsletters/stack-overflow-tips.tsx +++ b/apps/demo/emails/newsletters/stack-overflow-tips.tsx @@ -11,8 +11,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface StackOverflowTipsEmailProps { tips?: { id: number; description: string }[]; @@ -47,107 +49,143 @@ export const StackOverflowTipsEmail = ({ }: StackOverflowTipsEmailProps) => ( - - Stack overflow tips for searching - -
- -
- -
- - - - Find what you want, faster - - - Tips and tricks for searching on Stack Overflow - - - - - - -
+ + + Stack overflow tips for searching + +
+ +
-
- - Searching for solutions - - - With more than 18 million questions, it's possible that someone has - already provided a solution to the problem you're facing.{' '} - +
+ + + + Find what you want, faster + + + Tips and tricks for searching on Stack Overflow + + + + + + +
-
+
+ + Searching for solutions + + + With more than 18 million questions, it's possible that someone + has already provided a solution to the problem you're facing.{' '} + + +
+ + + Use the search bar at the top of the page to find what you need + + + Here are a few simple search tips to get you started: + +
    + {tips.map((tip) => ( +
  • + + {tip.description} + +
  • + ))} +
+ + + The more information you can put in the search bar, the more + likely you will be to either find the answer you need or feel + confident that no one else has asked the question before. + + +
+ + + Take a break and read about the worst coder in the world + + +
+ + I need a break + +
+
+ - - Use the search bar at the top of the page to find what you need - - - Here are a few simple search tips to get you started: +
+ + You're receiving this email because your Stack Overflow activity + triggered this tip or reminder. -
    - {tips.map((tip) => ( -
  • - {tip.description} -
  • - ))} -
- - The more information you can put in the search bar, the more likely - you will be to either find the answer you need or feel confident - that no one else has asked the question before. + + Unsubscribe from emails like this{' '} + + + Edit email settings{' '} + + + Contact us + + + Privacy + + +
+ + + + Stack Overflow, 110 William Street, 28th Floor, New + York, NY 10038 + + + {'<3'} - -
- - - Take a break and read about the worst coder in the world - - -
- - I need a break - -
- - -
- - You're receiving this email because your Stack Overflow activity - triggered this tip or reminder. - - - - Unsubscribe from emails like this{' '} - - - Edit email settings{' '} - - - Contact us - - - Privacy - - -
- - - - Stack Overflow, 110 William Street, 28th Floor, New - York, NY 10038 - - {'<3'} -
- + + ); @@ -156,136 +194,3 @@ StackOverflowTipsEmail.PreviewProps = { } as StackOverflowTipsEmailProps; export default StackOverflowTipsEmail; - -const main = { - backgroundColor: '#f3f3f5', - fontFamily: 'HelveticaNeue,Helvetica,Arial,sans-serif', -}; - -const headerContent = { padding: '20px 30px 15px' }; - -const headerContentTitle = { - color: '#fff', - fontSize: '27px', - fontWeight: 'bold', - lineHeight: '27px', -}; - -const headerContentSubtitle = { - color: '#fff', - fontSize: '17px', -}; - -const headerImageContainer = { - padding: '30px 10px', -}; - -const headerImage = { - maxWidth: '100%', -}; - -const title = { - margin: '0 0 15px', - fontWeight: 'bold', - fontSize: '21px', - lineHeight: '21px', - color: '#0c0d0e', -}; - -const paragraph = { - fontSize: '15px', - lineHeight: '21px', - color: '#3c3f44', -}; - -const divider = { - margin: '30px 0', -}; - -const container = { - width: '680px', - maxWidth: '100%', - margin: '0 auto', - backgroundColor: '#ffffff', -}; - -const footer = { - width: '680px', - maxWidth: '100%', - margin: '32px auto 0 auto', - padding: '0 30px', -}; - -const content = { - padding: '30px 30px 40px 30px', -}; - -const logo = { - display: 'flex', - background: '#f3f3f5', - padding: '20px 30px', -}; - -const header = { - borderRadius: '5px 5px 0 0', - display: 'flex', - flexDireciont: 'column', - backgroundColor: '#2b2d6e', -}; - -const buttonContainer = { - marginTop: '24px', - display: 'block', -}; - -const button = { - backgroundColor: '#0095ff', - border: '1px solid #0077cc', - fontSize: '17px', - lineHeight: '17px', - padding: '13px 17px', - borderRadius: '4px', - maxWidth: '120px', - color: '#fff', -}; - -const footerDivider = { - ...divider, - borderColor: '#d6d8db', -}; - -const footerText = { - fontSize: '12px', - lineHeight: '15px', - color: '#9199a1', - margin: '0', -}; - -const footerLink = { - display: 'inline-block', - color: '#9199a1', - textDecoration: 'underline', - fontSize: '12px', - marginRight: '10px', - marginBottom: '0', - marginTop: '8px', -}; - -const footerAddress = { - margin: '4px 0', - fontSize: '12px', - lineHeight: '15px', - color: '#9199a1', -}; - -const footerHeart = { - borderRadius: '1px', - border: '1px solid #d6d9dc', - padding: '4px 6px 3px 6px', - fontSize: '11px', - lineHeight: '11px', - fontFamily: 'Consolas,monospace', - color: '#e06c77', - maxWidth: 'min-content', - margin: '0 0 32px 0', -}; diff --git a/apps/demo/emails/notifications/github-access-token.tsx b/apps/demo/emails/notifications/github-access-token.tsx index ee85b69b38..adb8d18885 100644 --- a/apps/demo/emails/notifications/github-access-token.tsx +++ b/apps/demo/emails/notifications/github-access-token.tsx @@ -8,8 +8,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface GithubAccessTokenEmailProps { username?: string; @@ -24,44 +26,51 @@ export const GithubAccessTokenEmail = ({ }: GithubAccessTokenEmailProps) => ( - - - A fine-grained personal access token has been added to your account - - - Github - - - @{username}, a personal access was created on your - account. - - -
- - Hey {username}! - - - A fine-grained personal access token (resend) was - recently added to your account. + + + + A fine-grained personal access token has been added to your account + + + Github + + + @{username}, a personal access was created on your + account. - -
- - Your security audit log ・{' '} - Contact support - +
+ + Hey {username}! + + + A fine-grained personal access token (resend) was + recently added to your account. + + + +
+ + + Your security audit log + {' '} + ・{' '} + Contact support + - - GitHub, Inc. ・88 Colin P Kelly Jr Street ・San Francisco, CA 94107 - -
- + + GitHub, Inc. ・88 Colin P Kelly Jr Street ・San Francisco, CA 94107 + + + + ); @@ -70,58 +79,3 @@ GithubAccessTokenEmail.PreviewProps = { } as GithubAccessTokenEmailProps; export default GithubAccessTokenEmail; - -const main = { - backgroundColor: '#ffffff', - color: '#24292e', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"', -}; - -const container = { - maxWidth: '480px', - margin: '0 auto', - padding: '20px 0 48px', -}; - -const title = { - fontSize: '24px', - lineHeight: 1.25, -}; - -const section = { - padding: '24px', - border: 'solid 1px #dedede', - borderRadius: '5px', - textAlign: 'center' as const, -}; - -const text = { - margin: '0 0 10px 0', - textAlign: 'left' as const, -}; - -const button = { - fontSize: '14px', - backgroundColor: '#28a745', - color: '#fff', - lineHeight: 1.5, - borderRadius: '0.5em', - padding: '12px 24px', -}; - -const links = { - textAlign: 'center' as const, -}; - -const link = { - color: '#0366d6', - fontSize: '12px', -}; - -const footer = { - color: '#6a737d', - fontSize: '12px', - textAlign: 'center' as const, - marginTop: '60px', -}; diff --git a/apps/demo/emails/notifications/yelp-recent-login.tsx b/apps/demo/emails/notifications/yelp-recent-login.tsx index 5b56a4a219..dc350ae55a 100644 --- a/apps/demo/emails/notifications/yelp-recent-login.tsx +++ b/apps/demo/emails/notifications/yelp-recent-login.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface YelpRecentLoginEmailProps { userFirstName?: string; @@ -39,106 +41,88 @@ export const YelpRecentLoginEmail = ({ return ( - - - Yelp recent login - -
- Yelp logo -
- -
- + + + + Yelp recent login + +
+ Yelp logo +
+ +
+ + Yelp header illustration + + + + + + Hi {userFirstName}, + + + We noticed a recent login to your Yelp account. + + + + Time: + {formattedDate} + + + Device: + {loginDevice} + + + Location: + {loginLocation} + + + *Approximate geographic location based on IP address: + {loginIp} + + + + If this was you, there's nothing else you need to do. + + + If this wasn't you or if you have additional questions, + please see our support page. + + + + + + + + +
+ +
Yelp header illustration - - - - - - Hi {userFirstName}, - - - We noticed a recent login to your Yelp account. - - - - Time: - {formattedDate} - - - Device: - {loginDevice} - - - Location: - {loginLocation} - - - *Approximate geographic location based on IP address: - {loginIp} - - - - If this was you, there's nothing else you need to do. - - - If this wasn't you or if you have additional questions, please - see our support page. - - - - - - - - -
- -
- Yelp footer decoration -
- - - © 2022 | Yelp Inc., 350 Mission Street, San Francisco, CA 94105, - U.S.A. | www.yelp.com - -
- +
+ + + © 2022 | Yelp Inc., 350 Mission Street, San Francisco, CA 94105, + U.S.A. | www.yelp.com + +
+ + ); }; @@ -152,51 +136,3 @@ YelpRecentLoginEmail.PreviewProps = { } as YelpRecentLoginEmailProps; export default YelpRecentLoginEmail; - -const main = { - backgroundColor: '#fff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const paragraph = { - fontSize: 16, -}; - -const logo = { - padding: '30px 20px', -}; - -const buttonContainer = { - textAlign: 'center' as const, -}; - -const button = { - backgroundColor: '#e00707', - borderRadius: 3, - color: '#FFF', - fontWeight: 'bold', - border: '1px solid rgb(0,0,0, 0.1)', - cursor: 'pointer', - display: 'inline-block', - padding: '12px 30px', - textDecoration: 'none', -}; - -const content = { - border: '1px solid rgb(0,0,0, 0.1)', - borderRadius: '3px', - overflow: 'hidden', -}; - -const image = { - maxWidth: '100%', -}; - -const boxInfos = { - padding: '20px', -}; - -const containerImageFooter = { - padding: '45px 0 0 0', -}; diff --git a/apps/demo/emails/receipts/apple-receipt.tsx b/apps/demo/emails/receipts/apple-receipt.tsx index 194a2c1348..0fe12f8992 100644 --- a/apps/demo/emails/receipts/apple-receipt.tsx +++ b/apps/demo/emails/receipts/apple-receipt.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` @@ -20,473 +22,313 @@ const baseUrl = process.env.VERCEL_URL export const AppleReceiptEmail = () => ( - - - Apple Receipt - -
- - - Apple Logo - - - - Receipt - - -
-
- - Save 3% on all your Apple purchases with Apple Card. - 1{' '} - - Apply and use in minutes + + + Apple Receipt + +
+ + + Apple Logo + + + + + Receipt + + + +
+
+ + Save 3% on all your Apple purchases with Apple Card. + 1{' '} + + Apply and use in minutes + + 2 + +
+
+ + +
+ + + + APPLE ID + + + alan.turing@gmail.com + + + + + + + + INVOICE DATE + + + 18 Jan 2023 + + + + + + + + ORDER ID + + + ML4F5L8522 + + + + + DOCUMENT NO. + + + 186623754793 + + + +
+
+ + + BILLED TO + + + Visa .... 7461 (Apple Pay) + + + Alan Turing + + + 2125 Chestnut St + + + San Francisco, CA 94123 + + USA + +
+
+
+ + App Store + +
+
+ + + HBO Max + + + + HBO Max: Stream TV & Movies + + + HBO Max Ad-Free (Monthly) + + + Renews Aug 20, 2023 + + + Write a Review + + + | + + + Report a Problem + + + + + + $14.99 + + + +
+
+
+ + + + TOTAL + + + + + + $14.99 + + + +
+
+
+ + + Apple Card + + +
+
+ + + + Save 3% on all your Apple purchases. + + + +
+
+ + + + Apple Wallet + + Apply and use in minutes + + + + +
+
+ + 1. 3% savings is earned as Daily Cash and is transferred to your + Apple Cash card when transactions post to your Apple Card account. + If you do not have an Apple Cash card, Daily Cash can be applied by + you as a credit on your statement balance. 3% is the total amount of + Daily Cash earned for these purchases. See the Apple Card Customer + Agreement for more details on Daily Cash and qualifying + transactions. + + + 2. Subject to credit approval. + + + To access and use all the features of Apple Card, you must add Apple + Card to Wallet on an iPhone or iPad with iOS or iPadOS 13.2 or + later. Update to the latest version of iOS or iPadOS by going to + Settings > General > Software Update. Tap Download and + Install. + + + Available for qualifying applicants in the United States. + + + Apple Card is issued by Goldman Sachs Bank USA, Salt Lake City + Branch. + + + If you reside in the US territories, please call Goldman Sachs at + 877-255-5923 with questions about Apple Card. + + + Privacy: We use a + + {' '} + Subscriber ID{' '} - 2 + to provide reports to developers. + + + Get help with subscriptions and purchases. + + Visit Apple Support. + + + + Learn how to{' '} + + manage your password preferences + {' '} + for iTunes, Apple Books, and App Store purchases. -
-
- - -
- - - APPLE ID - - alan.turing@gmail.com - - - - - - - INVOICE DATE - 18 Jan 2023 - - - - - - ORDER ID - - ML4F5L8522 - - - - DOCUMENT NO. - 186623754793 - - -
-
- - BILLED TO - - Visa .... 7461 (Apple Pay) - - Alan Turing - 2125 Chestnut St - San Francisco, CA 94123 - USA - -
-
-
- App Store -
-
- - - HBO Max - - - HBO Max: Stream TV & Movies - HBO Max Ad-Free (Monthly) - Renews Aug 20, 2023 - - Write a Review - - | - - Report a Problem - - - - $14.99 - - -
-
-
- - - TOTAL - - - - $14.99 - - -
-
-
- - - Apple Card - - -
-
- - - Save 3% on all your Apple purchases. - - -
-
- - - + + {' '} + You have the option to stop receiving email receipts for your + subscription renewals. If you have opted out, you can still view + your receipts in your account under Purchase History. To manage + receipts or to opt in again, go to{' '} + Account Settings. + +
+ + Apple Wallet - Apply and use in minutes - - - -
-
- - 1. 3% savings is earned as Daily Cash and is transferred to your Apple - Cash card when transactions post to your Apple Card account. If you do - not have an Apple Cash card, Daily Cash can be applied by you as a - credit on your statement balance. 3% is the total amount of Daily Cash - earned for these purchases. See the Apple Card Customer Agreement for - more details on Daily Cash and qualifying transactions. - - 2. Subject to credit approval. - - To access and use all the features of Apple Card, you must add Apple - Card to Wallet on an iPhone or iPad with iOS or iPadOS 13.2 or later. - Update to the latest version of iOS or iPadOS by going to Settings - > General > Software Update. Tap Download and Install. - - - Available for qualifying applicants in the United States. - - - Apple Card is issued by Goldman Sachs Bank USA, Salt Lake City Branch. - - - If you reside in the US territories, please call Goldman Sachs at - 877-255-5923 with questions about Apple Card. - - - Privacy: We use a - - {' '} - Subscriber ID{' '} - - to provide reports to developers. - - - Get help with subscriptions and purchases. - - Visit Apple Support. - - - - Learn how to{' '} - - manage your password preferences - {' '} - for iTunes, Apple Books, and App Store purchases. - - - - {' '} - You have the option to stop receiving email receipts for your - subscription renewals. If you have opted out, you can still view your - receipts in your account under Purchase History. To manage receipts or - to opt in again, go to{' '} - Account Settings. - -
- - - Apple Card - - -
- - Account Settings •{' '} - Terms of Sale •{' '} - - Privacy Policy{' '} - - - - Copyright © 2023 Apple Inc.
{' '} - All rights reserved -
- - +
+
+
+ + Account Settings •{' '} + Terms of Sale •{' '} + + Privacy Policy{' '} + + + + Copyright © 2023 Apple Inc.
{' '} + All rights reserved +
+
+ + ); export default AppleReceiptEmail; - -const main = { - fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif', - backgroundColor: '#ffffff', -}; - -const resetText = { - margin: '0', - padding: '0', - lineHeight: 1.4, -}; - -const container = { - margin: '0 auto', - padding: '20px 0 48px', - width: '660px', - maxWidth: '100%', -}; - -const tableCell = { display: 'table-cell' }; - -const heading = { - fontSize: '32px', - fontWeight: '300', - color: '#888888', -}; - -const cupomText = { - textAlign: 'center' as const, - margin: '36px 0 40px 0', - fontSize: '14px', - fontWeight: '500', - color: '#111111', -}; - -const supStyle = { - fontWeight: '300', -}; - -const informationTable = { - borderCollapse: 'collapse' as const, - borderSpacing: '0px', - color: 'rgb(51,51,51)', - backgroundColor: 'rgb(250,250,250)', - borderRadius: '3px', - fontSize: '12px', -}; - -const informationTableRow = { - minHeight: '46px', -}; - -const informationTableColumn = { - paddingLeft: '20px', - borderStyle: 'solid', - borderColor: 'white', - borderWidth: '0px 1px 1px 0px', - minHeight: '44px', -}; - -const informationTableLabel = { - ...resetText, - color: 'rgb(102,102,102)', - fontSize: '10px', -}; - -const informationTableValue = { - fontSize: '12px', - margin: '0', - padding: '0', - lineHeight: 1.4, -}; - -const productTitleTable = { - ...informationTable, - margin: '30px 0 15px 0', - minHeight: '24px', -}; - -const productsTitle = { - background: '#fafafa', - paddingLeft: '10px', - fontSize: '14px', - fontWeight: '500', - margin: '0', -}; - -const productIcon = { - margin: '0 0 0 20px', - borderRadius: '14px', - border: '1px solid rgb(242,242,242)', -}; - -const productTitle = { fontSize: '12px', fontWeight: '600', ...resetText }; - -const productDescription = { - fontSize: '12px', - color: 'rgb(102,102,102)', - ...resetText, -}; - -const productLink = { - fontSize: '12px', - color: 'rgb(0,112,201)', - textDecoration: 'none', -}; - -const divisor = { - marginLeft: '4px', - marginRight: '4px', - color: 'rgb(51,51,51)', - fontWeight: 200, -}; - -const productPriceTotal = { - margin: '0', - color: 'rgb(102,102,102)', - fontSize: '10px', - fontWeight: '600', - padding: '0px 30px 0px 0px', - textAlign: 'right' as const, -}; - -const productPrice = { - fontSize: '12px', - fontWeight: '600', - margin: '0', -}; - -const productPriceLarge = { - margin: '0px 20px 0px 0px', - fontSize: '16px', - fontWeight: '600', - whiteSpace: 'nowrap' as const, - textAlign: 'right' as const, -}; - -const productPriceWrapper = { - display: 'table-cell', - padding: '0px 20px 0px 0px', - width: '100px', - verticalAlign: 'top', -}; - -const productPriceLine = { margin: '30px 0 0 0' }; - -const productPriceVerticalLine = { - minHeight: '48px', - paddingTop: '48px', - borderLeft: '1px solid', - borderColor: 'rgb(238,238,238)', -}; - -const productPriceLargeWrapper = { display: 'table-cell', width: '90px' }; - -const productPriceLineBottom = { margin: '0 0 75px 0' }; - -const block = { display: 'block' }; - -const ctaTitle = { - display: 'block', - margin: '15px 0 0 0', -}; - -const ctaText = { fontSize: '24px', fontWeight: '500' }; - -const walletWrapper = { display: 'table-cell', margin: '10px 0 0 0' }; - -const walletLink = { color: 'rgb(0,126,255)', textDecoration: 'none' }; - -const walletImage = { - display: 'inherit', - paddingRight: '8px', - verticalAlign: 'middle', -}; - -const walletBottomLine = { margin: '65px 0 20px 0' }; - -const footerText = { - fontSize: '12px', - color: 'rgb(102,102,102)', - margin: '0', - lineHeight: 'auto', - marginBottom: '16px', -}; - -const footerTextCenter = { - fontSize: '12px', - color: 'rgb(102,102,102)', - margin: '20px 0', - lineHeight: 'auto', - textAlign: 'center' as const, -}; - -const footerLink = { color: 'rgb(0,115,255)' }; - -const footerIcon = { display: 'block', margin: '40px 0 0 0' }; - -const footerLinksWrapper = { - margin: '8px 0 0 0', - textAlign: 'center' as const, - fontSize: '12px', - color: 'rgb(102,102,102)', -}; - -const footerCopyright = { - margin: '25px 0 0 0', - textAlign: 'center' as const, - fontSize: '12px', - color: 'rgb(102,102,102)', -}; - -const walletLinkText = { - fontSize: '14px', - fontWeight: '400', - textDecoration: 'none', -}; diff --git a/apps/demo/emails/receipts/nike-receipt.tsx b/apps/demo/emails/receipts/nike-receipt.tsx index db13e06a87..d58e6a59a1 100644 --- a/apps/demo/emails/receipts/nike-receipt.tsx +++ b/apps/demo/emails/receipts/nike-receipt.tsx @@ -11,9 +11,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; -import type * as React from 'react'; +import tailwindConfig from '../tailwind.config'; const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` @@ -22,442 +23,336 @@ const baseUrl = process.env.VERCEL_URL export const NikeReceiptEmail = () => ( - - - Get your order summary, estimated delivery date and more - - -
- - - Tracking Number - 1ZV218970300071628 - - - Track Package - - -
-
-
- Nike - It's On Its Way. - - You order's is on its way. Use the link above to track its progress. - - - We´ve also charged your payment method for the cost of your order - and will be removing any authorization holds. For payment details, - please visit your Orders page on Nike.com or in the Nike app. - -
-
-
- Shipping to: Alan Turing - - 2125 Chestnut St, San Francisco, CA 94123 - -
-
-
- - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - - - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - - Size L (12–14) - - -
-
-
- - - Order Number - C0106373851 - - - Order Date - Sep 22, 2022 - - - - - Order Status - - -
-
-
- - Top Picks For You - - - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - - USWNT 2022/23 Stadium Home - - - Women's Nike Dri-FIT Soccer Jersey + + + + Get your order summary, estimated delivery date and more + + +
+ + + + Tracking Number + + + 1ZV218970300071628 + + + + + Track Package + + + +
+
+
+ Nike + + It's On Its Way. + + + You order's is on its way. Use the link above to track its + progress. + + + We´ve also charged your payment method for the cost of your order + and will be removing any authorization holds. For payment details, + please visit your Orders page on Nike.com or in the Nike app. + +
+
+
+ + Shipping to: Alan Turing + + + 2125 Chestnut St, San Francisco, CA 94123 + +
+
+
+ + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + + Size L (12–14) + + + +
+
+
+ + + + Order Number + + + C0106373851 + + + + + Order Date + + + Sep 22, 2022 + + + + + + + Order Status + + + +
+
+
+ + + Top Picks For You - - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - - Brazil 2022/23 Stadium Goalkeeper + + + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + USWNT 2022/23 Stadium Home + + + Women's Nike Dri-FIT Soccer Jersey + + + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + Brazil 2022/23 Stadium Goalkeeper + + + Men's Nike Dri-FIT Short-Sleeve Football Shirt + + + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + FFF + + + Women's Soccer Jacket + + + + Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey + + FFF + + + Women's Nike Pre-Match Football Top + + + +
+
+
+ + Get Help + + + + + Shipping Status + + + + + Shipping & Delivery + + + + + Returns & Exchanges + + + + + + + How to Return + + + + + Contact Options + + + +
+ + + + + Nike Phone + + + + 1-800-806-6453 + + + + + + + 4 am - 11 pm PT + + + +
+
+
+ + + Nike.com - - Men's Nike Dri-FIT Short-Sleeve Football Shirt + + + + + Men + + + + + Women + + + + + Kids + + + + + Customize + + + +
+
+
+ + + + Web Version + + + + + Privacy Policy + + + + + + Please contact us if you have any questions. (If you reply to + this email, we won't be able to see it.) - - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - FFF - Women's Soccer Jacket - - - Brazil 2022/23 Stadium Away Women's Nike Dri-FIT Soccer Jersey - FFF - - Women's Nike Pre-Match Football Top + + + + © 2022 Nike, Inc. All Rights Reserved. - - -
-
-
- - Get Help - - - - - Shipping Status - - - - - Shipping & Delivery - - - - - Returns & Exchanges - - - - - - - How to Return - - - - - Contact Options - - - -
- - - - - Nike Phone - - - - 1-800-806-6453 - - - - - - - 4 am - 11 pm PT + + + + NIKE, INC. One Bowerman Drive, Beaverton, Oregon 97005, USA. - - -
-
-
- - Nike.com - - - - - Men - - - - - Women - - - - - Kids - - - - - Customize - - - -
-
-
- - - Web Version - - - Privacy Policy - - - - - Please contact us if you have any questions. (If you reply to this - email, we won't be able to see it.) - - - - - © 2022 Nike, Inc. All Rights Reserved. - - - - - NIKE, INC. One Bowerman Drive, Beaverton, Oregon 97005, USA. - - -
-
- +
+
+
+ + ); export default NikeReceiptEmail; - -const paddingX = { - paddingLeft: '40px', - paddingRight: '40px', -}; - -const paddingY = { - paddingTop: '22px', - paddingBottom: '22px', -}; - -const paragraph = { - margin: '0', - lineHeight: '2', -}; - -const global = { - paddingX, - paddingY, - defaultPadding: { - ...paddingX, - ...paddingY, - }, - paragraphWithBold: { ...paragraph, fontWeight: 'bold' }, - heading: { - fontSize: '32px', - lineHeight: '1.3', - fontWeight: '700', - textAlign: 'center', - letterSpacing: '-1px', - } as React.CSSProperties, - text: { - ...paragraph, - color: '#747474', - fontWeight: '500', - }, - button: { - border: '1px solid #929292', - fontSize: '16px', - textDecoration: 'none', - padding: '10px 0px', - width: '220px', - display: 'block', - textAlign: 'center', - fontWeight: 500, - color: '#000', - } as React.CSSProperties, - hr: { - borderColor: '#E5E5E5', - margin: '0', - }, -}; - -const main = { - backgroundColor: '#ffffff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const container = { - margin: '10px auto', - width: '600px', - maxWidth: '100%', - border: '1px solid #E5E5E5', -}; - -const track = { - container: { - padding: '22px 40px', - backgroundColor: '#F7F7F7', - }, - number: { - margin: '12px 0 0 0', - fontWeight: 500, - lineHeight: '1.4', - color: '#6F6F6F', - }, -}; - -const message = { - padding: '40px 74px', - textAlign: 'center', -} as React.CSSProperties; - -const adressTitle = { - ...paragraph, - fontSize: '15px', - fontWeight: 'bold', -}; - -const recomendationsText = { - margin: '0', - fontSize: '15px', - lineHeight: '1', - paddingLeft: '10px', - paddingRight: '10px', -}; - -const recomendations = { - container: { - padding: '20px 0', - }, - product: { - verticalAlign: 'top', - textAlign: 'left' as const, - paddingLeft: '2px', - paddingRight: '2px', - }, - title: { ...recomendationsText, paddingTop: '12px', fontWeight: '500' }, - text: { - ...recomendationsText, - paddingTop: '4px', - color: '#747474', - }, -}; - -const menu = { - container: { - paddingLeft: '20px', - paddingRight: '20px', - paddingTop: '20px', - backgroundColor: '#F7F7F7', - }, - content: { - ...paddingY, - paddingLeft: '20px', - paddingRight: '20px', - }, - title: { - paddingLeft: '20px', - paddingRight: '20px', - fontWeight: 'bold', - }, - text: { - fontSize: '13.5px', - marginTop: 0, - fontWeight: 500, - color: '#000', - }, - tel: { - paddingLeft: '20px', - paddingRight: '20px', - paddingTop: '32px', - paddingBottom: '22px', - }, -}; - -const categories = { - container: { - width: '370px', - margin: 'auto', - paddingTop: '12px', - }, - text: { - fontWeight: '500', - color: '#000', - }, -}; - -const footer = { - policy: { - width: '166px', - margin: 'auto', - }, - text: { - margin: '0', - color: '#AFAFAF', - fontSize: '13px', - textAlign: 'center', - } as React.CSSProperties, -}; diff --git a/apps/demo/emails/reset-password/dropbox-reset-password.tsx b/apps/demo/emails/reset-password/dropbox-reset-password.tsx index 91a4ef6d83..907fe6e021 100644 --- a/apps/demo/emails/reset-password/dropbox-reset-password.tsx +++ b/apps/demo/emails/reset-password/dropbox-reset-password.tsx @@ -8,8 +8,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface DropboxResetPasswordEmailProps { userFirstname?: string; @@ -27,39 +29,48 @@ export const DropboxResetPasswordEmail = ({ return ( - - Dropbox reset your password - - Dropbox -
- Hi {userFirstname}, - - Someone recently requested a password change for your Dropbox - account. If this was you, you can set a new password here: - - - - If you don't want to change your password or didn't - request this, just ignore and delete this message. - - - To keep your account secure, please don't forward this email - to anyone. See our Help Center for{' '} - - more security tips. - - - Happy Dropboxing! -
-
- + + + Dropbox reset your password + + Dropbox +
+ + Hi {userFirstname}, + + + Someone recently requested a password change for your Dropbox + account. If this was you, you can set a new password here: + + + + If you don't want to change your password or didn't + request this, just ignore and delete this message. + + + To keep your account secure, please don't forward this + email to anyone. See our Help Center for{' '} + + more security tips. + + + + Happy Dropboxing! + +
+
+ +
); }; @@ -69,41 +80,6 @@ DropboxResetPasswordEmail.PreviewProps = { resetPasswordLink: 'https://www.dropbox.com', } as DropboxResetPasswordEmailProps; -export default DropboxResetPasswordEmail; - -const main = { - backgroundColor: '#f6f9fc', - padding: '10px 0', -}; +DropboxResetPasswordEmail.tailwindConfig = tailwindConfig; -const container = { - backgroundColor: '#ffffff', - border: '1px solid #f0f0f0', - padding: '45px', -}; - -const text = { - fontSize: '16px', - fontFamily: - "'Open Sans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif", - fontWeight: '300', - color: '#404040', - lineHeight: '26px', -}; - -const button = { - backgroundColor: '#007ee6', - borderRadius: '4px', - color: '#fff', - fontFamily: "'Open Sans', 'Helvetica Neue', Arial", - fontSize: '15px', - textDecoration: 'none', - textAlign: 'center' as const, - display: 'block', - width: '210px', - padding: '14px 7px', -}; - -const anchor = { - textDecoration: 'underline', -}; +export default DropboxResetPasswordEmail; diff --git a/apps/demo/emails/reset-password/twitch-reset-password.tsx b/apps/demo/emails/reset-password/twitch-reset-password.tsx index 60eb156c32..de99963778 100644 --- a/apps/demo/emails/reset-password/twitch-reset-password.tsx +++ b/apps/demo/emails/reset-password/twitch-reset-password.tsx @@ -9,8 +9,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface TwitchResetPasswordEmailProps { username?: string; @@ -33,83 +35,85 @@ export const TwitchResetPasswordEmail = ({ return ( - - You updated the password for your Twitch account - -
- Twitch -
-
+ + + You updated the password for your Twitch account + +
+ Twitch +
+
+ + + + + +
+
+ Hi {username}, + + You updated the password for your Twitch account on{' '} + {formattedDate}. If this was you, then no further action is + required. + + + However if you did NOT perform this password change, please{' '} + + reset your account password + {' '} + immediately. + + + Remember to use a password that is both strong and unique to + your Twitch account. To learn more about how to create a strong + and unique password,{' '} + + click here. + + + + Still have questions? Please contact{' '} + + Twitch Support + + + + Thanks, +
+ Twitch Support Team +
+
+
+ +
- - - + + Twitter + + + Facebook + + + + + © 2022 Twitch, All Rights Reserved
+ 350 Bush Street, 2nd Floor, San Francisco, CA, 94104 - USA +
-
- Hi {username}, - - You updated the password for your Twitch account on{' '} - {formattedDate}. If this was you, then no further action is - required. - - - However if you did NOT perform this password change, please{' '} - - reset your account password - {' '} - immediately. - - - Remember to use a password that is both strong and unique to your - Twitch account. To learn more about how to create a strong and - unique password,{' '} - - click here. - - - - Still have questions? Please contact{' '} - - Twitch Support - - - - Thanks, -
- Twitch Support Team -
-
- - -
- - - Twitter - - - Facebook - - - - - © 2022 Twitch, All Rights Reserved
- 350 Bush Street, 2nd Floor, San Francisco, CA, 94104 - USA -
-
-
- + +
); }; @@ -120,56 +124,3 @@ TwitchResetPasswordEmail.PreviewProps = { } as TwitchResetPasswordEmailProps; export default TwitchResetPasswordEmail; - -const fontFamily = 'HelveticaNeue,Helvetica,Arial,sans-serif'; - -const main = { - backgroundColor: '#efeef1', - fontFamily, -}; - -const paragraph = { - lineHeight: 1.5, - fontSize: 14, -}; - -const container = { - maxWidth: '580px', - margin: '30px auto', - backgroundColor: '#ffffff', -}; - -const footer = { - maxWidth: '580px', - margin: '0 auto', -}; - -const content = { - padding: '5px 20px 10px 20px', -}; - -const logo = { - padding: 30, -}; - -const logoImg = { - margin: '0 auto', -}; - -const sectionsBorders = { - width: '100%', -}; - -const sectionBorder = { - borderBottom: '1px solid rgb(238,238,238)', - width: '249px', -}; - -const sectionCenter = { - borderBottom: '1px solid rgb(145,71,255)', - width: '102px', -}; - -const link = { - textDecoration: 'underline', -}; diff --git a/apps/demo/emails/reviews/airbnb-review.tsx b/apps/demo/emails/reviews/airbnb-review.tsx index 52381120bd..d345f8d646 100644 --- a/apps/demo/emails/reviews/airbnb-review.tsx +++ b/apps/demo/emails/reviews/airbnb-review.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface AirbnbReviewEmailProps { authorName?: string; @@ -34,78 +36,100 @@ export const AirbnbReviewEmail = ({ - - {previewText} - -
- Airbnb -
-
- {authorName} -
-
- - Here's what {authorName} wrote - {reviewText} - - Now that the review period is over, we’ve posted {authorName} - ’s review to your Airbnb profile. - - - While it’s too late to write a review of your own, you can send - your feedback to {authorName} using your Airbnb message thread. - - - - -
- -
- -
- - - Common questions - - - - How do reviews work? - - - - - How do star ratings work? + + + {previewText} + +
+ Airbnb +
+
+ {authorName} +
+
+ + + Here's what {authorName} wrote + + + {reviewText} + + + Now that the review period is over, we've posted {authorName} + 's review to your Airbnb profile. + + + While it's too late to write a review of your own, you can + send your feedback to {authorName} using your Airbnb message + thread. + + + + +
+ +
+ +
+ + + Common questions + + + + How do reviews work? + + + + + How do star ratings work? + + + + + Can I leave a review after 14 days? + + +
+ + Airbnb, Inc., 888 Brannan St, San Francisco, CA 94103 + + + Report unsafe behavior - - - - Can I leave a review after 14 days? - - -
- - Airbnb, Inc., 888 Brannan St, San Francisco, CA 94103 - - - Report unsafe behavior - -
-
-
- +
+
+
+ + ); }; @@ -119,77 +143,6 @@ AirbnbReviewEmail.PreviewProps = { host!”`, } as AirbnbReviewEmailProps; -export default AirbnbReviewEmail; - -const main = { - backgroundColor: '#ffffff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const container = { - margin: '0 auto', - padding: '20px 0 48px', - width: '580px', - maxWidth: '100%', -}; - -const userImage = { - margin: '0 auto', - marginBottom: '16px', - borderRadius: '50%', -}; - -const heading = { - fontSize: '32px', - lineHeight: '1.3', - fontWeight: '700', - color: '#484848', -}; - -const paragraph = { - fontSize: '18px', - lineHeight: '1.4', - color: '#484848', -}; - -const review = { - ...paragraph, - padding: '24px', - backgroundColor: '#f2f3f3', - borderRadius: '4px', -}; - -const button = { - backgroundColor: '#ff5a5f', - borderRadius: '3px', - color: '#fff', - fontSize: '18px', - padding: '19px 30px', - textDecoration: 'none', - textAlign: 'center' as const, - display: 'block', -}; - -const link = { - ...paragraph, - color: '#ff5a5f', - display: 'block', -}; - -const reportLink = { - fontSize: '14px', - color: '#9ca299', - textDecoration: 'underline', -}; +AirbnbReviewEmail.tailwindConfig = tailwindConfig; -const hr = { - borderColor: '#cccccc', - margin: '20px 0', -}; - -const footer = { - color: '#9ca299', - fontSize: '14px', - marginBottom: '10px', -}; +export default AirbnbReviewEmail; diff --git a/apps/demo/emails/reviews/amazon-review.tsx b/apps/demo/emails/reviews/amazon-review.tsx index 08fb4a2ffb..02da9acef4 100644 --- a/apps/demo/emails/reviews/amazon-review.tsx +++ b/apps/demo/emails/reviews/amazon-review.tsx @@ -10,8 +10,10 @@ import { Preview, Row, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface AmazonReviewEmailProps { titleText?: string; @@ -38,204 +40,158 @@ export const AmazonReviewEmail = ({ - - Amazon Review - -
- - - + + + Amazon Review + +
+ + + + Amazon Prime Logo + + + +
+ +
+ + + + {titleText} + + {reviewText} + + +
+ +
+ + Amazon Prime Logo - - - -
- -
- - - {titleText} - {reviewText} - - -
- -
- - - Amazon Book - - - - - 14 Habits of Highly Productive Developers (English Edition) - - Start with rating this product - - {reviwStars.map((star, index) => ( + + + + + 14 Habits of Highly Productive Developers (English Edition) + + Start with rating this product + + {reviwStars.map((star, index) => ( + Amazon Rating + ))} + + + Your reviews will be posted on Amazon using your public + name. + Check your public name. + + + +
+ +
+ + + + How about evaluating a previous purchase?{' '} + + View more + + + + +
+ +
+ +
+ + Amazon Rating - ))} - - - Your reviews will be posted on Amazon using your public name. - Check your public name. + + + + {socialMediaIcons.map((src, index) => ( + Amazon Social Midia + ))} + + +
+ +
+ + + Customer reviews must adhere to the{' '} + + Community Guidelines + {' '} + . - - -
- -
- - - - How about evaluating a previous purchase?{' '} - View more + + We hope this message was helpful to you. However, if you + prefer not to receive this type of communication from{' '} + + Amazon.com + {' '} + at{' '} + + alanturing@gmail.com{' '} + + ,{' '} + + click here + {' '} + . - - -
- -
- -
- - - Amazon Logo - - - - {socialMediaIcons.map((src, index) => ( - Amazon Social Midia - ))} - - -
- -
- - - Customer reviews must adhere to the{' '} - Community Guidelines . - - - We hope this message was helpful to you. However, if you prefer - not to receive this type of communication from{' '} - Amazon.com at{' '} - alanturing@gmail.com ,{' '} - click here . - - - Please note that product prices and availability are subject to - change. - - - © 2023 Amazon.com, Inc. or its affiliates. Amazon and all - associated marks are trademarks of Amazon.com, Inc. or its - affiliates. - - Reference: 706784740 - -
-
- + + Please note that product prices and availability are subject + to change. + + + © 2023 Amazon.com, Inc. or its affiliates. Amazon and all + associated marks are trademarks of Amazon.com, Inc. or its + affiliates. + + + Reference: 706784740 + +
+
+
+ + ); }; -export default AmazonReviewEmail; - -const main = { - fontFamily: 'Ember,Helvetica,Arial,sans-seri', - backgroundColor: '#ffffff', -}; - -const container = { - borderTop: '4px solid #FF9900', - margin: '0 auto', - padding: '20px', - width: '640px', -}; - -const title = { - color: '#232f3e', - fontSize: '36px', - lineHeight: '38px', - fontWeight: '400', - margin: '20px 0', -}; - -const ratingContent = { - paddingLeft: '30px', -}; +AmazonReviewEmail.tailwindConfig = tailwindConfig; -const rating = { - display: 'inline-block', -}; - -const previewPurchase = { - background: '#008296', - color: '#ffffff', - padding: '8px 0', -}; - -const previewPurchaseLink = { - color: '#ffffff', - textDecoration: 'underline', - cursor: 'pointer', -}; - -const socialMedia = { - display: 'inline-block', - marginLeft: '10px', -}; - -const communityLink = { - color: '#666666', - textDecoration: 'underline', - cursor: 'pointer', -}; - -const clickHereLink = { - color: '#999999', - textDecoration: 'underline', - cursor: 'pointer', -}; - -const urlLink = { - color: '#1155cc', - textDecoration: 'underline', - cursor: 'pointer', -}; - -const footerText = { - fontSize: '10px', - color: '#666666', - margin: '8px 0', -}; +export default AmazonReviewEmail; diff --git a/apps/demo/emails/tailwind.config.ts b/apps/demo/emails/tailwind.config.ts new file mode 100644 index 0000000000..6568f85368 --- /dev/null +++ b/apps/demo/emails/tailwind.config.ts @@ -0,0 +1,93 @@ +import { pixelBasedPreset, type TailwindConfig } from '@react-email/components'; + +export default { + presets: [pixelBasedPreset], + theme: { + fontFamily: { + amazon: ['Ember', 'Helvetica', 'Arial', 'sans-serif'], + koala: [ + '-apple-system', + 'BlinkMacSystemFont', + 'Segoe UI', + 'Roboto', + 'Oxygen-Sans', + 'Ubuntu', + 'Cantarell', + 'Helvetica Neue', + 'sans-serif', + ], + raycast: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', + slack: + "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", + twitch: ['HelveticaNeue', 'Helvetica', 'Arial', 'sans-serif'], + 'stack-overflow': ['Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'], + 'stack-overflow-mono': 'Consolas,monospace', + github: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"', + yelp: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + 'Oxygen-Sans', + 'Ubuntu', + 'Cantarell', + '"Helvetica Neue"', + 'sans-serif', + ], + nike: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + 'Oxygen-Sans', + 'Ubuntu', + 'Cantarell', + '"Helvetica Neue"', + 'sans-serif', + ], + linear: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', + stripe: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Ubuntu', + 'sans-serif', + ], + notion: + "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", + aws: "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif", + airbnb: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + 'Oxygen-Sans', + 'Ubuntu', + 'Cantarell', + '"Helvetica Neue"', + 'sans-serif', + ], + apple: ['"Helvetica Neue"', 'Helvetica', 'Arial', 'sans-serif'], + dropbox: [ + 'Open Sans', + 'HelveticaNeue-Light', + 'Helvetica Neue Light', + 'Helvetica Neue', + 'Helvetica', + 'Arial', + 'Lucida Grande', + 'sans-serif', + ], + 'dropbox-sans': ['Open Sans', 'Helvetica Neue', 'Arial'], + codepen: '"Google Sans",Roboto,RobotoDraft,Helvetica,Arial,sans-serif', + plaid: 'HelveticaNeue,Helvetica,Arial,sans-serif', + google: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', + }, + }, +} satisfies TailwindConfig; diff --git a/apps/demo/emails/welcome/koala-welcome.tsx b/apps/demo/emails/welcome/koala-welcome.tsx index 5ec1ebe0bc..1267a887ae 100644 --- a/apps/demo/emails/welcome/koala-welcome.tsx +++ b/apps/demo/emails/welcome/koala-welcome.tsx @@ -8,8 +8,10 @@ import { Img, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; interface KoalaWelcomeEmailProps { userFirstname: string; @@ -24,39 +26,47 @@ export const KoalaWelcomeEmail = ({ }: KoalaWelcomeEmailProps) => ( - - - The sales intelligence platform that helps you uncover qualified leads. - - - Koala - Hi {userFirstname}, - - Welcome to Koala, the sales intelligence platform that helps you - uncover qualified leads and close deals faster. - -
- -
- - Best, -
- The Koala team -
-
- - 470 Noor Ave STE B #1148, South San Francisco, CA 94080 - -
- + + + + The sales intelligence platform that helps you uncover qualified + leads. + + + Koala + + Hi {userFirstname}, + + + Welcome to Koala, the sales intelligence platform that helps you + uncover qualified leads and close deals faster. + +
+ +
+ + Best, +
+ The Koala team +
+
+ + 470 Noor Ave STE B #1148, South San Francisco, CA 94080 + +
+ +
); @@ -65,48 +75,3 @@ KoalaWelcomeEmail.PreviewProps = { } as KoalaWelcomeEmailProps; export default KoalaWelcomeEmail; - -const main = { - backgroundColor: '#ffffff', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; - -const container = { - margin: '0 auto', - padding: '20px 0 48px', -}; - -const logo = { - margin: '0 auto', -}; - -const paragraph = { - fontSize: '16px', - lineHeight: '26px', -}; - -const btnContainer = { - textAlign: 'center' as const, -}; - -const button = { - backgroundColor: '#5F51E8', - borderRadius: '3px', - color: '#fff', - fontSize: '16px', - textDecoration: 'none', - textAlign: 'center' as const, - display: 'block', - padding: '12px', -}; - -const hr = { - borderColor: '#cccccc', - margin: '20px 0', -}; - -const footer = { - color: '#8898aa', - fontSize: '12px', -}; diff --git a/apps/demo/emails/welcome/stripe-welcome.tsx b/apps/demo/emails/welcome/stripe-welcome.tsx index 9422531e01..1ceac00d5d 100644 --- a/apps/demo/emails/welcome/stripe-welcome.tsx +++ b/apps/demo/emails/welcome/stripe-welcome.tsx @@ -9,8 +9,10 @@ import { Link, Preview, Section, + Tailwind, Text, } from '@react-email/components'; +import tailwindConfig from '../tailwind.config'; const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` @@ -19,138 +21,98 @@ const baseUrl = process.env.VERCEL_URL export const StripeWelcomeEmail = () => ( - - You're now ready to make live transactions with Stripe! - -
- Stripe -
- - Thanks for submitting your account information. You're now ready to - make live transactions with Stripe! - - - You can view your payments and a variety of other information about - your account right from your dashboard. - - -
- - If you haven't finished your integration, you might find our{' '} - + + + You're now ready to make live transactions with Stripe! + + +
+ Stripe +
+ + Thanks for submitting your account information. You're now ready + to make live transactions with Stripe! + + + You can view your payments and a variety of other information + about your account right from your dashboard. + +
-
- + View your Stripe Dashboard + +
+ + If you haven't finished your integration, you might find our{' '} + + docs + {' '} + handy. + + + Once you're ready to start accepting payments, you'll just need to + use your live{' '} + + API keys + {' '} + instead of your test API keys. Your account can simultaneously be + used for both test and live requests, so you can continue testing + while accepting live payments. Check out our{' '} + + tutorial about account basics + + . + + + Finally, we've put together a{' '} + + quick checklist + {' '} + to ensure your website conforms to card network standards. + + + We'll be here to help you with any step along the way. You can + find answers to most questions and get in touch with us on our{' '} + + support site + + . + + + — The Stripe team + +
+ + Stripe, 354 Oyster Point Blvd, South San Francisco, CA 94080 + +
+
+ + ); export default StripeWelcomeEmail; - -const main = { - backgroundColor: '#f6f9fc', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', -}; - -const container = { - backgroundColor: '#ffffff', - margin: '0 auto', - padding: '20px 0 48px', - marginBottom: '64px', -}; - -const box = { - padding: '0 48px', -}; - -const hr = { - borderColor: '#e6ebf1', - margin: '20px 0', -}; - -const paragraph = { - color: '#525f7f', - - fontSize: '16px', - lineHeight: '24px', - textAlign: 'left' as const, -}; - -const anchor = { - color: '#556cd6', -}; - -const button = { - backgroundColor: '#656ee8', - borderRadius: '5px', - color: '#fff', - fontSize: '16px', - fontWeight: 'bold', - textDecoration: 'none', - textAlign: 'center' as const, - display: 'block', - padding: '10px', -}; - -const footer = { - color: '#8898aa', - fontSize: '12px', - lineHeight: '16px', -}; diff --git a/apps/demo/package.json b/apps/demo/package.json index 79ff536b09..8469564f0f 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -10,14 +10,14 @@ }, "dependencies": { "@react-email/components": "workspace:*", + "email-dev": "workspace:*", "react": "^19", - "react-dom": "^19", - "email-dev": "workspace:*" + "react-dom": "^19" }, "devDependencies": { "@react-email/preview-server": "workspace:*", - "next": "^15.3.2", "@types/react": "^19", - "@types/react-dom": "^19" + "@types/react-dom": "^19", + "next": "^15.3.2" } } diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 109fc2eef2..bc054b60e0 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,16 @@ # @react-email/components +## 1.0.0-canary.0 + +### Major Changes + +- 9360e39: tailwind: update to using tailwindcss@v4 + +### Patch Changes + +- Updated dependencies [9360e39] + - @react-email/tailwind@2.0.0-canary.0 + ## 0.5.7 ### Patch Changes diff --git a/packages/components/package.json b/packages/components/package.json index 059c8d9742..9fbc0ca175 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@react-email/components", - "version": "0.5.7", + "version": "1.0.0-canary.0", "description": "A collection of all components React Email.", "sideEffects": false, "main": "./dist/index.js", @@ -58,7 +58,7 @@ "@react-email/render": "workspace:1.4.0", "@react-email/row": "workspace:0.0.12", "@react-email/section": "workspace:0.0.16", - "@react-email/tailwind": "workspace:1.2.2", + "@react-email/tailwind": "workspace:2.0.0-canary.0", "@react-email/text": "workspace:0.1.5" }, "peerDependencies": { diff --git a/packages/preview-server/src/utils/__snapshots__/get-email-component.spec.ts.snap b/packages/preview-server/src/utils/__snapshots__/get-email-component.spec.ts.snap index a6e818a9d9..3886d5c63b 100644 --- a/packages/preview-server/src/utils/__snapshots__/get-email-component.spec.ts.snap +++ b/packages/preview-server/src/utils/__snapshots__/get-email-component.spec.ts.snap @@ -12,8 +12,7 @@ exports[`getEmailComponent() > with a demo email template 1`] = ` - + with a demo email template 1`] = `
+ style='margin-right:auto;margin-left:auto;margin-bottom:auto;margin-top:auto;background-color:rgb(255,255,255);padding-right:8px;padding-left:8px;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"'>
@@ -40,7 +39,7 @@ exports[`getEmailComponent() > with a demo email template 1`] = ` cellpadding="0" cellspacing="0" role="presentation" - style="margin-left:auto;margin-right:auto;margin-top:40px;margin-bottom:40px;max-width:465px;border-radius:0.25rem;border-width:1px;border-color:rgb(234,234,234);border-style:solid;padding:20px"> + style="max-width:465px;margin-right:auto;margin-left:auto;margin-bottom:40px;margin-top:40px;border-radius:0.25rem;border-style:solid;border-width:1px;border-color:rgb(234,234,234);padding:20px">
@@ -59,26 +58,26 @@ exports[`getEmailComponent() > with a demo email template 1`] = ` alt="Vercel Logo" height="37" src="/static/vercel-logo.png" - style="margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;display:block;outline:none;border:none;text-decoration:none" + style="display:block;outline:none;border:none;text-decoration:none;margin-right:auto;margin-left:auto;margin-bottom:0;margin-top:0" width="40" />

+ style="margin-right:0;margin-left:0;margin-bottom:30px;margin-top:30px;padding:0;text-align:center;font-weight:400;font-size:24px;color:rgb(0,0,0)"> Join Enigma on Vercel

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> Hello alanturing,

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> Alan (alan.turing@example.com) has invited you to the Enigma team on @@ -110,7 +109,7 @@ exports[`getEmailComponent() > with a demo email template 1`] = ` alt="alanturing's profile picture" height="64" src="/static/vercel-user.png" - style="border-radius:9999px;display:block;outline:none;border:none;text-decoration:none" + style="display:block;outline:none;border:none;text-decoration:none;border-radius:9999px" width="64" /> with a demo email template 1`] = ` alt="Enigma team logo" height="64" src="/static/vercel-team.png" - style="border-radius:9999px;display:block;outline:none;border:none;text-decoration:none" + style="display:block;outline:none;border:none;text-decoration:none;border-radius:9999px" width="64" /> @@ -153,7 +152,7 @@ exports[`getEmailComponent() > with a demo email template 1`] = ` with a demo email template 1`] = `

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> or copy and paste this URL into your browser: https://vercel.com


+ style="width:100%;border:none;border-top:1px solid #eaeaea;margin-right:0;margin-left:0;margin-bottom:26px;margin-top:26px;border-style:solid;border-width:1px;border-color:rgb(234,234,234)" />

+ style="font-size:12px;line-height:24px;color:rgb(102,102,102);margin-top:16px;margin-bottom:16px"> This invitation was intended for alanturing. This invite was sent from diff --git a/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap b/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap index 615acfb5ad..7e4c1a61e7 100644 --- a/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap +++ b/packages/react-email/src/commands/testing/__snapshots__/export.spec.ts.snap @@ -10,8 +10,7 @@ exports[`email export 1`] = ` - +
+ style='margin-right:auto;margin-left:auto;margin-bottom:auto;margin-top:auto;background-color:rgb(255,255,255);padding-right:8px;padding-left:8px;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"'>
@@ -38,7 +37,7 @@ exports[`email export 1`] = ` cellpadding="0" cellspacing="0" role="presentation" - style="margin-left:auto;margin-right:auto;margin-top:40px;margin-bottom:40px;max-width:465px;border-radius:0.25rem;border-width:1px;border-color:rgb(234,234,234);border-style:solid;padding:20px"> + style="max-width:465px;margin-right:auto;margin-left:auto;margin-bottom:40px;margin-top:40px;border-radius:0.25rem;border-style:solid;border-width:1px;border-color:rgb(234,234,234);padding:20px">
@@ -57,26 +56,26 @@ exports[`email export 1`] = ` alt="Vercel Logo" height="37" src="/static/vercel-logo.png" - style="margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;display:block;outline:none;border:none;text-decoration:none" + style="display:block;outline:none;border:none;text-decoration:none;margin-right:auto;margin-left:auto;margin-bottom:0;margin-top:0" width="40" />

+ style="margin-right:0;margin-left:0;margin-bottom:30px;margin-top:30px;padding:0;text-align:center;font-weight:400;font-size:24px;color:rgb(0,0,0)"> Join on Vercel

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> Hello ,

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> () has invited you to the team on Vercel. @@ -106,7 +105,7 @@ exports[`email export 1`] = ` undefined's profile picture @@ -147,7 +146,7 @@ exports[`email export 1`] = `

+ style="font-size:14px;line-height:24px;color:rgb(0,0,0);margin-top:16px;margin-bottom:16px"> or copy and paste this URL into your browser:


+ style="width:100%;border:none;border-top:1px solid #eaeaea;margin-right:0;margin-left:0;margin-bottom:26px;margin-top:26px;border-style:solid;border-width:1px;border-color:rgb(234,234,234)" />

+ style="font-size:12px;line-height:24px;color:rgb(102,102,102);margin-top:16px;margin-bottom:16px"> This invitation was intended for . This invite was sent from diff --git a/packages/render/src/shared/options.ts b/packages/render/src/shared/options.ts index 3cc9b672ba..c1f330f6db 100644 --- a/packages/render/src/shared/options.ts +++ b/packages/render/src/shared/options.ts @@ -1,20 +1,31 @@ import type { HtmlToTextOptions } from 'html-to-text'; -import type { pretty } from './utils/pretty'; import type { toPlainText } from './utils/to-plain-text'; export type Options = { /** - * @deprecated use {@link pretty} instead + * @deprecated This option will be removed in a future major release. + * Please format the rendered HTML yourself instead of relying on this option. + * + * @example + * ```ts + * // Render the email to HTML + * const html = await render(email); + * + * // Format the HTML using your preferred formatter (e.g. Prettier) + * const formattedHtml = await format(html); + * ``` + * + * @see https://github.com/resend/react-email/issues/2426 */ pretty?: boolean; } & ( - | { + | { /** * @deprecated use {@link toPlainText} instead */ plainText?: false; } - | { + | { /** * @deprecated use {@link toPlainText} instead */ @@ -27,4 +38,4 @@ export type Options = { */ htmlToTextOptions?: HtmlToTextOptions; } -); + ); diff --git a/packages/render/src/shared/utils/pretty.ts b/packages/render/src/shared/utils/pretty.ts index 63887c1a57..7bc47af7d2 100644 --- a/packages/render/src/shared/utils/pretty.ts +++ b/packages/render/src/shared/utils/pretty.ts @@ -92,6 +92,21 @@ const defaults: Options = { parser: 'html', }; +/** + * @deprecated This function will be removed in a future major release. + * Please format the rendered HTML yourself instead of relying on this function. + * + * @example + * ```ts + * // Render the email to HTML + * const html = await render(email); + * + * // Format the HTML using your preferred formatter (e.g. Prettier) + * const formattedHtml = await format(html); + * ``` + * + * @see https://github.com/resend/react-email/issues/2426 + */ export const pretty = (str: string, options: Options = {}) => { return format(str.replaceAll('\0', ''), { ...defaults, diff --git a/packages/tailwind/CHANGELOG.md b/packages/tailwind/CHANGELOG.md index c5b4772b9f..842ec54e5e 100644 --- a/packages/tailwind/CHANGELOG.md +++ b/packages/tailwind/CHANGELOG.md @@ -1,5 +1,11 @@ # @react-email/tailwind +## 2.0.0-canary.0 + +### Major Changes + +- 9360e39: update to using tailwindcss@v4 + ## 1.2.2 ### Patch Changes diff --git a/packages/tailwind/copy-tailwind-types.mjs b/packages/tailwind/copy-tailwind-types.mjs deleted file mode 100644 index 6fe7008614..0000000000 --- a/packages/tailwind/copy-tailwind-types.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import { promises as fs } from 'node:fs'; -import path from 'node:path'; -import url from 'node:url'; - -const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); - -await fs.cp( - path.resolve(__dirname, './node_modules/tailwindcss/types'), - path.resolve(__dirname, './dist/tailwindcss'), - { - recursive: true, - }, -); diff --git a/packages/tailwind/package.json b/packages/tailwind/package.json index 43ed1c5e28..45dbd8249e 100644 --- a/packages/tailwind/package.json +++ b/packages/tailwind/package.json @@ -1,6 +1,6 @@ { "name": "@react-email/tailwind", - "version": "1.2.2", + "version": "2.0.0-canary.0", "description": "A React component to wrap emails with Tailwind CSS", "sideEffects": false, "main": "./dist/index.js", @@ -23,8 +23,8 @@ }, "license": "MIT", "scripts": { - "build": "tsc && cross-env NODE_ENV=production vite build --mode production && node ./copy-tailwind-types.mjs", - "build:watch": "vite build --watch", + "build": "tsdown", + "build:watch": "tsdown --watch", "clean": "rm -rf dist", "test": "vitest run", "test:watch": "vitest" @@ -43,7 +43,50 @@ "node": ">=18.0.0" }, "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^18.0 || ^19.0 || ^19.0.0-rc", + "@react-email/body": "workspace:*", + "@react-email/button": "workspace:*", + "@react-email/code-block": "workspace:*", + "@react-email/code-inline": "workspace:*", + "@react-email/container": "workspace:*", + "@react-email/heading": "workspace:*", + "@react-email/hr": "workspace:*", + "@react-email/img": "workspace:*", + "@react-email/link": "workspace:*", + "@react-email/preview": "workspace:*", + "@react-email/text": "workspace:*" + }, + "peerDependenciesMeta": { + "@react-email/button": { + "optional": true + }, + "@react-email/body": { + "optional": true + }, + "@react-email/code-block": { + "optional": true + }, + "@react-email/code-inline": { + "optional": true + }, + "@react-email/container": { + "optional": true + }, + "@react-email/heading": { + "optional": true + }, + "@react-email/hr": { + "optional": true + }, + "@react-email/img": { + "optional": true + }, + "@react-email/link": { + "optional": true + }, + "@react-email/preview": { + "optional": true + } }, "devDependencies": { "@react-email/button": "workspace:^", @@ -54,14 +97,12 @@ "@react-email/link": "workspace:*", "@react-email/render": "workspace:*", "@responsive-email/react-email": "0.0.4", + "@types/css-tree": "2.3.10", "@types/shelljs": "0.8.15", "@vitejs/plugin-react": "4.4.1", - "cross-env": "10.0.0", - "postcss": "8.5.3", - "postcss-selector-parser": "7.1.0", + "css-tree": "3.1.0", "react-dom": "^19", "shelljs": "0.9.2", - "tailwindcss": "3.4.10", "tsconfig": "workspace:*", "typescript": "5.8.3", "vite": "6.3.6", @@ -70,5 +111,8 @@ }, "publishConfig": { "access": "public" + }, + "dependencies": { + "tailwindcss": "4.1.12" } } diff --git a/packages/tailwind/src/__snapshots__/tailwind.spec.tsx.snap b/packages/tailwind/src/__snapshots__/tailwind.spec.tsx.snap index 0bdcd1b93d..c6edea3134 100644 --- a/packages/tailwind/src/__snapshots__/tailwind.spec.tsx.snap +++ b/packages/tailwind/src/__snapshots__/tailwind.spec.tsx.snap @@ -1,52 +1,225 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Custom plugins config > uses custom plugins 1`] = `"

"`; +exports[`Tailwind component > - +

I am some text

+ " `; -exports[`Tailwind component > works properly with 'no-underline' 1`] = `"

or copy and paste this URL into your browser: https://react.email

or copy and paste this URL into your browser: https://react.email

"`; +exports[`Tailwind component > works properly with 'no-underline' 1`] = `"

or copy and paste this URL into your browser: https://react.email

or copy and paste this URL into your browser: https://react.email

"`; exports[`Tailwind component > works with Heading component 1`] = `"Hello

My testing heading

friends"`; @@ -57,7 +230,7 @@ exports[`Tailwind component > works with blocklist 1`] = ` @@ -67,63 +240,38 @@ exports[`Tailwind component > works with blocklist 1`] = ` " `; -exports[`Tailwind component > works with calc() with + sign 1`] = `"
something tall
"`; - -exports[`Tailwind component > works with class manipulation done on components 1`] = `"
"`; - -exports[`Tailwind component > works with components that return children 1`] = `"
Hello world

React Email

"`; - -exports[`Tailwind component > works with components that use React.forwardRef 1`] = `"
Hello world

React Email

"`; - -exports[`Tailwind component > works with custom components with fragment at the root 1`] = `"
Hello world

React Email

React Email

"`; - -exports[`non-inlinable styles > adds css to and keeps class names 1`] = `"
"`; - -exports[`non-inlinable styles > does not have duplicate media queries 1`] = ` +exports[`Tailwind component > works with calc() with + sign 1`] = ` " - - - -
- - +
+
something tall
+
+ " `; -exports[`non-inlinable styles > persists existing elements 1`] = `"
"`; - -exports[`non-inlinable styles > throws an error when used without a 1`] = ` -[Error: You are trying to use the following Tailwind classes that cannot be inlined: sm:bg-red-500. -For the media queries to work properly on rendering, they need to be added into a
"`; - -exports[`non-inlinable styles > works with arbitrarily deep (in the React tree) elements 2`] = `"
"`; - -exports[`non-inlinable styles > works with relatively complex media query utilities 1`] = `"

I am some text

"`; diff --git a/packages/tailwind/src/hooks/__snapshots__/use-tailwind.spec.ts.snap b/packages/tailwind/src/hooks/__snapshots__/use-tailwind.spec.ts.snap deleted file mode 100644 index baebff2970..0000000000 --- a/packages/tailwind/src/hooks/__snapshots__/use-tailwind.spec.ts.snap +++ /dev/null @@ -1,16 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`useTailwind() 1`] = ` -".text-red-500 { - color: rgb(239 68 68 / 1) -} - @media (min-width: 640px) { - .sm\\:bg-blue-300 { - background-color: rgb(147 197 253 / 1) - } -} - .bg-slate-900 { - background-color: rgb(15 23 42 / 1) -} -" -`; diff --git a/packages/tailwind/src/hooks/use-suspensed-promise.ts b/packages/tailwind/src/hooks/use-suspended-promise.ts similarity index 100% rename from packages/tailwind/src/hooks/use-suspensed-promise.ts rename to packages/tailwind/src/hooks/use-suspended-promise.ts diff --git a/packages/tailwind/src/hooks/use-suspensed-promise.spec.ts b/packages/tailwind/src/hooks/use-suspensed-promise.spec.ts index a43199c247..2063a1ab49 100644 --- a/packages/tailwind/src/hooks/use-suspensed-promise.spec.ts +++ b/packages/tailwind/src/hooks/use-suspensed-promise.spec.ts @@ -1,5 +1,5 @@ /** biome-ignore-all lint/correctness/useHookAtTopLevel: function is not a React hook */ -import { useSuspensedPromise } from './use-suspensed-promise'; +import { useSuspensedPromise } from './use-suspended-promise'; describe('useSuspensedPromise', () => { beforeEach(() => {}); diff --git a/packages/tailwind/src/tailwind.spec.tsx b/packages/tailwind/src/tailwind.spec.tsx index cc05724cbd..292521e000 100644 --- a/packages/tailwind/src/tailwind.spec.tsx +++ b/packages/tailwind/src/tailwind.spec.tsx @@ -4,10 +4,9 @@ import { Heading } from '@react-email/heading'; import { Hr } from '@react-email/hr'; import { Html } from '@react-email/html'; import { Link } from '@react-email/link'; -import { render } from '@react-email/render'; +import { pretty, render } from '@react-email/render'; import { ResponsiveColumn, ResponsiveRow } from '@responsive-email/react-email'; import React from 'react'; -import { vi } from 'vitest'; import type { TailwindConfig } from '.'; import { Tailwind } from '.'; @@ -26,7 +25,11 @@ describe('Tailwind component', () => { it('works with blocklist', async () => { const actualOutput = await render( - + - - , - { pretty: true }, - ); - - expect(spy).toHaveBeenCalled(); - expect(actualOutput).toMatchSnapshot(); + it('works with shadows', async () => { + expect( + await render( + +
shadow around here
+
, + ).then(pretty), + ).toMatchSnapshot(); }); it('works with class manipulation done on components', async () => { @@ -66,11 +60,9 @@ describe('Tailwind component', () => { }) => { expect( props.style, - 'Styles should be generated the same for a component', - ).toEqual({ - color: 'rgb(96,165,250)', - padding: '1rem', - }); + 'styles should not be generated for a component', + ).toBeUndefined(); + expect(props.className).toBe('p-4 text-blue-400'); return (
{ expect(actualOutput).toMatchSnapshot(); }); - describe('Inline styles', () => { - it('renders children with inline Tailwind styles', async () => { - const actualOutput = await render( - -
- , - ); + it('renders children with inline Tailwind styles', async () => { + const actualOutput = await render( + +
+ , + ); - expect(actualOutput).not.toBeNull(); - }); + expect(actualOutput).toMatchSnapshot(); }); test('