react-email 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -20,7 +20,7 @@ exports.components = [
|
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
title: 'layout.tsx',
|
|
23
|
-
content: "import * as React from 'react';\nimport { Topbar } from './topbar';\nimport { Sidebar } from './sidebar';\n\ntype LayoutElement = React.ElementRef<'div'>;\ntype RootProps = React.ComponentPropsWithoutRef<'div'>;\n\ninterface LayoutProps extends RootProps {\n navItems: string[];\n viewMode?: string;\n setViewMode?: (viewMode: string) => void;\n}\n\nexport const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(\n (\n { className, title, navItems, children, viewMode, setViewMode, ...props },\n forwardedRef,\n ) => {\n return (\n <>\n <div className=\"flex justify-between h-screen\">\n <Sidebar navItems={navItems} />\n <main className=\"w-
|
|
23
|
+
content: "import * as React from 'react';\nimport { Topbar } from './topbar';\nimport { Sidebar } from './sidebar';\n\ntype LayoutElement = React.ElementRef<'div'>;\ntype RootProps = React.ComponentPropsWithoutRef<'div'>;\n\ninterface LayoutProps extends RootProps {\n navItems: string[];\n viewMode?: string;\n setViewMode?: (viewMode: string) => void;\n}\n\nexport const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(\n (\n { className, title, navItems, children, viewMode, setViewMode, ...props },\n forwardedRef,\n ) => {\n return (\n <>\n <div className=\"flex justify-between h-screen\">\n <Sidebar navItems={navItems} />\n <main className=\"w-[calc(100%_-_275px)] bg-slate-2\">\n {title && (\n <Topbar\n title={title}\n viewMode={viewMode}\n setViewMode={setViewMode}\n />\n )}\n <div className=\"relative h-[calc(100vh_-_70px)] overflow-auto\">\n <div className=\"mx-auto\">{children}</div>\n </div>\n </main>\n </div>\n </>\n );\n },\n);\n\nLayout.displayName = 'Layout';\n",
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
title: 'logo.tsx',
|
package/dist/_preview/pages.js
CHANGED
|
@@ -12,11 +12,11 @@ exports.pages = [
|
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
title: 'index.tsx',
|
|
15
|
-
content: "import { promises as fs } from 'fs';\nimport path from 'path';\nimport { Button, Heading, Text } from '../components';\nimport { Layout } from '../components/layout';\nimport Link from 'next/link';\n\ninterface HomeProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n return emails\n ? { props: { navItems: emails } }\n : { props: { navItems: [] } };\n } catch (error) {\n console.error(error);\n return { props: { navItems: [] } };\n }\n}\n\nconst Home: React.FC<Readonly<HomeProps>> = ({ navItems }: any) => {\n return (\n <Layout navItems={navItems}>\n <div className=\"max-w-md border border-slate-6 mx-auto mt-56 rounded-md p-8\">\n <Heading as=\"h2\" weight=\"medium\">\n Welcome to the React Email preview!\n </Heading>\n <Text as=\"p\" className=\"mt-2 mb-4\">\n
|
|
15
|
+
content: "import { promises as fs } from 'fs';\nimport path from 'path';\nimport { Button, Heading, Text } from '../components';\nimport { Layout } from '../components/layout';\nimport Link from 'next/link';\n\ninterface HomeProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n return emails\n ? { props: { navItems: emails } }\n : { props: { navItems: [] } };\n } catch (error) {\n console.error(error);\n return { props: { navItems: [] } };\n }\n}\n\nconst Home: React.FC<Readonly<HomeProps>> = ({ navItems }: any) => {\n return (\n <Layout navItems={navItems}>\n <div className=\"max-w-md border border-slate-6 mx-auto mt-56 rounded-md p-8\">\n <Heading as=\"h2\" weight=\"medium\">\n Welcome to the React Email preview!\n </Heading>\n <Text as=\"p\" className=\"mt-2 mb-4\">\n To start developing your next email template, you can create a{' '}\n <code>.jsx</code> or <code>.tsx</code> file under the \"emails\" folder.\n </Text>\n\n <Button asChild>\n <Link href=\"https://react.email/docs\">Check the docs</Link>\n </Button>\n </div>\n </Layout>\n );\n};\n\nexport default Home;\n",
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
dir: 'preview',
|
|
19
19
|
title: '[slug].tsx',
|
|
20
|
-
content: "import { promises as fs } from 'fs';\nimport path from 'path';\nimport { render } from '@react-email/render';\nimport { GetStaticPaths } from 'next';\nimport { Layout } from '../../components/layout';\nimport * as React from 'react';\nimport { Code } from '../../components';\nimport Head from 'next/head';\n\ninterface PreviewProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const emails = await getEmails();\n\n const paths = emails.map((email) => {\n return { params: { slug: email } };\n });\n return { paths, fallback: true };\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup } }\n : { notFound: true };\n } catch (error) {\n console.error(error);\n return { notFound: true };\n }\n}\n\nconst Preview: React.FC<Readonly<PreviewProps>> = ({\n navItems,\n markup,\n slug,\n}: any) => {\n const [viewMode, setViewMode] = React.useState('desktop');\n const title = `${slug} — React Email`;\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={setViewMode}\n >\n <Head>\n <title>{title}</title>\n </Head>\n {viewMode === 'desktop' ? (\n <iframe\n srcDoc={markup}\n frameBorder=\"0\"\n className=\"w-full h-[calc(100vh_-_70px)]\"\n />\n ) : (\n <div className=\"
|
|
20
|
+
content: "import { promises as fs } from 'fs';\nimport path from 'path';\nimport { render } from '@react-email/render';\nimport { GetStaticPaths } from 'next';\nimport { Layout } from '../../components/layout';\nimport * as React from 'react';\nimport { Code } from '../../components';\nimport Head from 'next/head';\n\ninterface PreviewProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const emails = await getEmails();\n\n const paths = emails.map((email) => {\n return { params: { slug: email } };\n });\n return { paths, fallback: true };\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n\n const path = `${process.cwd()}/${CONTENT_DIR}/${params.slug}`;\n const reactMarkup = await fs.readFile(`${path}.tsx`, {\n encoding: 'utf-8',\n });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup, reactMarkup } }\n : { notFound: true };\n } catch (error) {\n console.error(error);\n return { notFound: true };\n }\n}\n\nconst Preview: React.FC<Readonly<PreviewProps>> = ({\n navItems,\n markup,\n reactMarkup,\n slug,\n}: any) => {\n const [viewMode, setViewMode] = React.useState('desktop');\n const title = `${slug} — React Email`;\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={setViewMode}\n >\n <Head>\n <title>{title}</title>\n </Head>\n {viewMode === 'desktop' ? (\n <iframe\n srcDoc={markup}\n frameBorder=\"0\"\n className=\"w-full h-[calc(100vh_-_70px)]\"\n />\n ) : (\n <div className=\"flex gap-6 mx-auto p-6\">\n <Code>{reactMarkup}</Code>\n <Code>{markup}</Code>\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
|
|
21
21
|
},
|
|
22
22
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-email",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A live preview of your emails right in your browser.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"email": "./dist/index.js"
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
14
|
"prepare": "npm run build",
|
|
15
|
+
"preprepare": "ts-node ./scripts/prepare-preview",
|
|
15
16
|
"format:check": "prettier --check \"**/*.{js,ts,tsx,json}\"",
|
|
16
17
|
"format": "prettier --write \"**/*.{js,ts,tsx,json}\"",
|
|
17
18
|
"lint": "eslint",
|
|
@@ -20,7 +20,7 @@ export const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(
|
|
|
20
20
|
<>
|
|
21
21
|
<div className="flex justify-between h-screen">
|
|
22
22
|
<Sidebar navItems={navItems} />
|
|
23
|
-
<main className="w-
|
|
23
|
+
<main className="w-[calc(100%_-_275px)] bg-slate-2">
|
|
24
24
|
{title && (
|
|
25
25
|
<Topbar
|
|
26
26
|
title={title}
|
|
@@ -34,8 +34,13 @@ export async function getStaticProps({ params }) {
|
|
|
34
34
|
const Email = (await import(`../../../emails/${params.slug}`)).default;
|
|
35
35
|
const markup = render(<Email />, { pretty: true });
|
|
36
36
|
|
|
37
|
+
const path = `${process.cwd()}/${CONTENT_DIR}/${params.slug}`;
|
|
38
|
+
const reactMarkup = await fs.readFile(`${path}.tsx`, {
|
|
39
|
+
encoding: 'utf-8',
|
|
40
|
+
});
|
|
41
|
+
|
|
37
42
|
return emails
|
|
38
|
-
? { props: { navItems: emails, slug: params.slug, markup } }
|
|
43
|
+
? { props: { navItems: emails, slug: params.slug, markup, reactMarkup } }
|
|
39
44
|
: { notFound: true };
|
|
40
45
|
} catch (error) {
|
|
41
46
|
console.error(error);
|
|
@@ -46,6 +51,7 @@ export async function getStaticProps({ params }) {
|
|
|
46
51
|
const Preview: React.FC<Readonly<PreviewProps>> = ({
|
|
47
52
|
navItems,
|
|
48
53
|
markup,
|
|
54
|
+
reactMarkup,
|
|
49
55
|
slug,
|
|
50
56
|
}: any) => {
|
|
51
57
|
const [viewMode, setViewMode] = React.useState('desktop');
|
|
@@ -68,7 +74,8 @@ const Preview: React.FC<Readonly<PreviewProps>> = ({
|
|
|
68
74
|
className="w-full h-[calc(100vh_-_70px)]"
|
|
69
75
|
/>
|
|
70
76
|
) : (
|
|
71
|
-
<div className="
|
|
77
|
+
<div className="flex gap-6 mx-auto p-6">
|
|
78
|
+
<Code>{reactMarkup}</Code>
|
|
72
79
|
<Code>{markup}</Code>
|
|
73
80
|
</div>
|
|
74
81
|
)}
|
|
@@ -22,7 +22,7 @@ export const components = [
|
|
|
22
22
|
{
|
|
23
23
|
title: 'layout.tsx',
|
|
24
24
|
content:
|
|
25
|
-
"import * as React from 'react';\nimport { Topbar } from './topbar';\nimport { Sidebar } from './sidebar';\n\ntype LayoutElement = React.ElementRef<'div'>;\ntype RootProps = React.ComponentPropsWithoutRef<'div'>;\n\ninterface LayoutProps extends RootProps {\n navItems: string[];\n viewMode?: string;\n setViewMode?: (viewMode: string) => void;\n}\n\nexport const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(\n (\n { className, title, navItems, children, viewMode, setViewMode, ...props },\n forwardedRef,\n ) => {\n return (\n <>\n <div className=\"flex justify-between h-screen\">\n <Sidebar navItems={navItems} />\n <main className=\"w-
|
|
25
|
+
"import * as React from 'react';\nimport { Topbar } from './topbar';\nimport { Sidebar } from './sidebar';\n\ntype LayoutElement = React.ElementRef<'div'>;\ntype RootProps = React.ComponentPropsWithoutRef<'div'>;\n\ninterface LayoutProps extends RootProps {\n navItems: string[];\n viewMode?: string;\n setViewMode?: (viewMode: string) => void;\n}\n\nexport const Layout = React.forwardRef<LayoutElement, Readonly<LayoutProps>>(\n (\n { className, title, navItems, children, viewMode, setViewMode, ...props },\n forwardedRef,\n ) => {\n return (\n <>\n <div className=\"flex justify-between h-screen\">\n <Sidebar navItems={navItems} />\n <main className=\"w-[calc(100%_-_275px)] bg-slate-2\">\n {title && (\n <Topbar\n title={title}\n viewMode={viewMode}\n setViewMode={setViewMode}\n />\n )}\n <div className=\"relative h-[calc(100vh_-_70px)] overflow-auto\">\n <div className=\"mx-auto\">{children}</div>\n </div>\n </main>\n </div>\n </>\n );\n },\n);\n\nLayout.displayName = 'Layout';\n",
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
title: 'logo.tsx',
|
package/source/_preview/pages.ts
CHANGED
|
@@ -12,12 +12,12 @@ export const pages = [
|
|
|
12
12
|
{
|
|
13
13
|
title: 'index.tsx',
|
|
14
14
|
content:
|
|
15
|
-
"import { promises as fs } from 'fs';\nimport path from 'path';\nimport { Button, Heading, Text } from '../components';\nimport { Layout } from '../components/layout';\nimport Link from 'next/link';\n\ninterface HomeProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n return emails\n ? { props: { navItems: emails } }\n : { props: { navItems: [] } };\n } catch (error) {\n console.error(error);\n return { props: { navItems: [] } };\n }\n}\n\nconst Home: React.FC<Readonly<HomeProps>> = ({ navItems }: any) => {\n return (\n <Layout navItems={navItems}>\n <div className=\"max-w-md border border-slate-6 mx-auto mt-56 rounded-md p-8\">\n <Heading as=\"h2\" weight=\"medium\">\n Welcome to the React Email preview!\n </Heading>\n <Text as=\"p\" className=\"mt-2 mb-4\">\n
|
|
15
|
+
"import { promises as fs } from 'fs';\nimport path from 'path';\nimport { Button, Heading, Text } from '../components';\nimport { Layout } from '../components/layout';\nimport Link from 'next/link';\n\ninterface HomeProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n return emails\n ? { props: { navItems: emails } }\n : { props: { navItems: [] } };\n } catch (error) {\n console.error(error);\n return { props: { navItems: [] } };\n }\n}\n\nconst Home: React.FC<Readonly<HomeProps>> = ({ navItems }: any) => {\n return (\n <Layout navItems={navItems}>\n <div className=\"max-w-md border border-slate-6 mx-auto mt-56 rounded-md p-8\">\n <Heading as=\"h2\" weight=\"medium\">\n Welcome to the React Email preview!\n </Heading>\n <Text as=\"p\" className=\"mt-2 mb-4\">\n To start developing your next email template, you can create a{' '}\n <code>.jsx</code> or <code>.tsx</code> file under the \"emails\" folder.\n </Text>\n\n <Button asChild>\n <Link href=\"https://react.email/docs\">Check the docs</Link>\n </Button>\n </div>\n </Layout>\n );\n};\n\nexport default Home;\n",
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
dir: 'preview',
|
|
19
19
|
title: '[slug].tsx',
|
|
20
20
|
content:
|
|
21
|
-
"import { promises as fs } from 'fs';\nimport path from 'path';\nimport { render } from '@react-email/render';\nimport { GetStaticPaths } from 'next';\nimport { Layout } from '../../components/layout';\nimport * as React from 'react';\nimport { Code } from '../../components';\nimport Head from 'next/head';\n\ninterface PreviewProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const emails = await getEmails();\n\n const paths = emails.map((email) => {\n return { params: { slug: email } };\n });\n return { paths, fallback: true };\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup } }\n : { notFound: true };\n } catch (error) {\n console.error(error);\n return { notFound: true };\n }\n}\n\nconst Preview: React.FC<Readonly<PreviewProps>> = ({\n navItems,\n markup,\n slug,\n}: any) => {\n const [viewMode, setViewMode] = React.useState('desktop');\n const title = `${slug} — React Email`;\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={setViewMode}\n >\n <Head>\n <title>{title}</title>\n </Head>\n {viewMode === 'desktop' ? (\n <iframe\n srcDoc={markup}\n frameBorder=\"0\"\n className=\"w-full h-[calc(100vh_-_70px)]\"\n />\n ) : (\n <div className=\"
|
|
21
|
+
"import { promises as fs } from 'fs';\nimport path from 'path';\nimport { render } from '@react-email/render';\nimport { GetStaticPaths } from 'next';\nimport { Layout } from '../../components/layout';\nimport * as React from 'react';\nimport { Code } from '../../components';\nimport Head from 'next/head';\n\ninterface PreviewProps {}\n\nexport const CONTENT_DIR = 'emails';\n\nconst getEmails = async () => {\n const emailsDirectory = path.join(process.cwd(), CONTENT_DIR);\n const filenames = await fs.readdir(emailsDirectory);\n const emails = filenames.map((file) => file.replace('.tsx', ''));\n\n return emails;\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const emails = await getEmails();\n\n const paths = emails.map((email) => {\n return { params: { slug: email } };\n });\n return { paths, fallback: true };\n};\n\nexport async function getStaticProps({ params }) {\n try {\n const emails = await getEmails();\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n\n const path = `${process.cwd()}/${CONTENT_DIR}/${params.slug}`;\n const reactMarkup = await fs.readFile(`${path}.tsx`, {\n encoding: 'utf-8',\n });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup, reactMarkup } }\n : { notFound: true };\n } catch (error) {\n console.error(error);\n return { notFound: true };\n }\n}\n\nconst Preview: React.FC<Readonly<PreviewProps>> = ({\n navItems,\n markup,\n reactMarkup,\n slug,\n}: any) => {\n const [viewMode, setViewMode] = React.useState('desktop');\n const title = `${slug} — React Email`;\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={setViewMode}\n >\n <Head>\n <title>{title}</title>\n </Head>\n {viewMode === 'desktop' ? (\n <iframe\n srcDoc={markup}\n frameBorder=\"0\"\n className=\"w-full h-[calc(100vh_-_70px)]\"\n />\n ) : (\n <div className=\"flex gap-6 mx-auto p-6\">\n <Code>{reactMarkup}</Code>\n <Code>{markup}</Code>\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
|
|
22
22
|
},
|
|
23
23
|
];
|