react-email 1.6.2 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,6 @@ exports.pages = [
17
17
  {
18
18
  dir: 'preview',
19
19
  title: '[slug].tsx',
20
- content: "import * as React from 'react';\nimport { 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 { CodeContainer } from '../../components/code-container';\nimport { Code } from '../../components';\nimport Head from 'next/head';\nimport { useRouter } from 'next/router';\n\ninterface PreviewProps {\n navItems: string;\n markup: string;\n reactMarkup: string;\n slug: string;\n}\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\n .map((file) => file.replace(/\\.(jsx|tsx)$/g, ''))\n .filter((file) => file !== 'components');\n return { emails, filenames };\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const { emails } = await getEmails();\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, filenames } = await getEmails();\n const template = filenames.filter((email) => {\n const [fileName] = email.split('.');\n return params.slug === fileName;\n });\n\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n const path = `${process.cwd()}/${CONTENT_DIR}/${template[0]}`;\n const reactMarkup = await fs.readFile(path, {\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 title = `${slug} — React Email`;\n const router = useRouter();\n const [viewMode, setViewMode] = React.useState('desktop');\n\n const handleViewMode = (mode: string) => {\n setViewMode(mode);\n\n router.push({\n pathname: router.pathname,\n query: {\n ...router.query,\n view: mode,\n },\n });\n };\n\n React.useEffect(() => {\n if (router.query.view === 'source' || router.query.view === 'desktop') {\n setViewMode(router.query.view);\n }\n }, [router.query.view]);\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={handleViewMode}\n markup={markup}\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 <CodeContainer\n markups={[\n { language: 'jsx', content: reactMarkup },\n { language: 'markup', content: markup },\n ]}\n />\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
20
+ content: "import * as React from 'react';\nimport { 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 { CodeContainer } from '../../components/code-container';\nimport { Code } from '../../components';\nimport Head from 'next/head';\nimport { useRouter } from 'next/router';\n\ninterface PreviewProps {\n navItems: string;\n markup: string;\n reactMarkup: string;\n slug: string;\n}\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\n .map((file) => file.replace(/\\.(jsx|tsx)$/g, ''))\n .filter((file) => file !== 'components');\n return { emails, filenames };\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const { emails } = await getEmails();\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, filenames } = await getEmails();\n const template = filenames.filter((email) => {\n const [fileName] = email.split('.');\n return params.slug === fileName;\n });\n\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n const plainText = render(<Email />, { plainText: true });\n const path = `${process.cwd()}/${CONTENT_DIR}/${template[0]}`;\n const reactMarkup = await fs.readFile(path, {\n encoding: 'utf-8',\n });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup, reactMarkup, plainText } }\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 plainText,\n slug,\n}: any) => {\n const title = `${slug} — React Email`;\n const router = useRouter();\n const [viewMode, setViewMode] = React.useState('desktop');\n\n const handleViewMode = (mode: string) => {\n setViewMode(mode);\n\n router.push({\n pathname: router.pathname,\n query: {\n ...router.query,\n view: mode,\n },\n });\n };\n\n React.useEffect(() => {\n if (router.query.view === 'source' || router.query.view === 'desktop') {\n setViewMode(router.query.view);\n }\n }, [router.query.view]);\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={handleViewMode}\n markup={markup}\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 <CodeContainer\n markups={[\n { language: 'jsx', content: reactMarkup },\n { language: 'markup', content: markup },\n { language: 'markdown', content: plainText },\n ]}\n />\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
21
21
  },
22
22
  ];
@@ -12,7 +12,7 @@ exports.root = [
12
12
  },
13
13
  {
14
14
  title: 'package.json',
15
- content: '{\n "name": "react-email-preview",\n "version": "0.0.7",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=18.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.2",\n "classnames": "2.3.2",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
15
+ content: '{\n "name": "react-email-preview",\n "version": "0.0.8",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=18.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.6",\n "classnames": "2.3.2",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
16
16
  },
17
17
  {
18
18
  title: 'postcss.config.js',
@@ -16,7 +16,7 @@ exports.utils = [
16
16
  },
17
17
  {
18
18
  title: 'language-map.ts',
19
- content: "const languageMap = {\n jsx: 'React',\n markup: 'HTML',\n};\n\nexport default languageMap;\n",
19
+ content: "const languageMap = {\n jsx: 'React',\n markup: 'HTML',\n markdown: 'Plain Text',\n};\n\nexport default languageMap;\n",
20
20
  },
21
21
  {
22
22
  title: 'unreachable.ts',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "description": "A live preview of your emails right in your browser.",
5
5
  "bin": {
6
6
  "email": "./dist/index.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-email-preview",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "The React Email preview application",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  "@radix-ui/react-slot": "1.0.1",
23
23
  "@radix-ui/react-toggle-group": "1.0.1",
24
24
  "@radix-ui/react-tooltip": "1.0.2",
25
- "@react-email/render": "0.0.2",
25
+ "@react-email/render": "0.0.6",
26
26
  "classnames": "2.3.2",
27
27
  "next": "13.0.4",
28
28
  "prism-react-renderer": "1.3.5",
@@ -45,13 +45,22 @@ export async function getStaticProps({ params }) {
45
45
 
46
46
  const Email = (await import(`../../../emails/${params.slug}`)).default;
47
47
  const markup = render(<Email />, { pretty: true });
48
+ const plainText = render(<Email />, { plainText: true });
48
49
  const path = `${process.cwd()}/${CONTENT_DIR}/${template[0]}`;
49
50
  const reactMarkup = await fs.readFile(path, {
50
51
  encoding: 'utf-8',
51
52
  });
52
53
 
53
54
  return emails
54
- ? { props: { navItems: emails, slug: params.slug, markup, reactMarkup } }
55
+ ? {
56
+ props: {
57
+ navItems: emails,
58
+ slug: params.slug,
59
+ markup,
60
+ reactMarkup,
61
+ plainText,
62
+ },
63
+ }
55
64
  : { notFound: true };
56
65
  } catch (error) {
57
66
  console.error(error);
@@ -63,6 +72,7 @@ const Preview: React.FC<Readonly<PreviewProps>> = ({
63
72
  navItems,
64
73
  markup,
65
74
  reactMarkup,
75
+ plainText,
66
76
  slug,
67
77
  }: any) => {
68
78
  const title = `${slug} — React Email`;
@@ -110,6 +120,7 @@ const Preview: React.FC<Readonly<PreviewProps>> = ({
110
120
  markups={[
111
121
  { language: 'jsx', content: reactMarkup },
112
122
  { language: 'markup', content: markup },
123
+ { language: 'markdown', content: plainText },
113
124
  ]}
114
125
  />
115
126
  </div>
@@ -1,6 +1,7 @@
1
1
  const languageMap = {
2
2
  jsx: 'React',
3
3
  markup: 'HTML',
4
+ markdown: 'Plain Text',
4
5
  };
5
6
 
6
7
  export default languageMap;
@@ -18,6 +18,6 @@ export const pages = [
18
18
  dir: 'preview',
19
19
  title: '[slug].tsx',
20
20
  content:
21
- "import * as React from 'react';\nimport { 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 { CodeContainer } from '../../components/code-container';\nimport { Code } from '../../components';\nimport Head from 'next/head';\nimport { useRouter } from 'next/router';\n\ninterface PreviewProps {\n navItems: string;\n markup: string;\n reactMarkup: string;\n slug: string;\n}\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\n .map((file) => file.replace(/\\.(jsx|tsx)$/g, ''))\n .filter((file) => file !== 'components');\n return { emails, filenames };\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const { emails } = await getEmails();\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, filenames } = await getEmails();\n const template = filenames.filter((email) => {\n const [fileName] = email.split('.');\n return params.slug === fileName;\n });\n\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n const path = `${process.cwd()}/${CONTENT_DIR}/${template[0]}`;\n const reactMarkup = await fs.readFile(path, {\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 title = `${slug} — React Email`;\n const router = useRouter();\n const [viewMode, setViewMode] = React.useState('desktop');\n\n const handleViewMode = (mode: string) => {\n setViewMode(mode);\n\n router.push({\n pathname: router.pathname,\n query: {\n ...router.query,\n view: mode,\n },\n });\n };\n\n React.useEffect(() => {\n if (router.query.view === 'source' || router.query.view === 'desktop') {\n setViewMode(router.query.view);\n }\n }, [router.query.view]);\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={handleViewMode}\n markup={markup}\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 <CodeContainer\n markups={[\n { language: 'jsx', content: reactMarkup },\n { language: 'markup', content: markup },\n ]}\n />\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
21
+ "import * as React from 'react';\nimport { 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 { CodeContainer } from '../../components/code-container';\nimport { Code } from '../../components';\nimport Head from 'next/head';\nimport { useRouter } from 'next/router';\n\ninterface PreviewProps {\n navItems: string;\n markup: string;\n reactMarkup: string;\n slug: string;\n}\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\n .map((file) => file.replace(/\\.(jsx|tsx)$/g, ''))\n .filter((file) => file !== 'components');\n return { emails, filenames };\n};\n\nexport const getStaticPaths: GetStaticPaths = async () => {\n const { emails } = await getEmails();\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, filenames } = await getEmails();\n const template = filenames.filter((email) => {\n const [fileName] = email.split('.');\n return params.slug === fileName;\n });\n\n const Email = (await import(`../../../emails/${params.slug}`)).default;\n const markup = render(<Email />, { pretty: true });\n const plainText = render(<Email />, { plainText: true });\n const path = `${process.cwd()}/${CONTENT_DIR}/${template[0]}`;\n const reactMarkup = await fs.readFile(path, {\n encoding: 'utf-8',\n });\n\n return emails\n ? { props: { navItems: emails, slug: params.slug, markup, reactMarkup, plainText } }\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 plainText,\n slug,\n}: any) => {\n const title = `${slug} — React Email`;\n const router = useRouter();\n const [viewMode, setViewMode] = React.useState('desktop');\n\n const handleViewMode = (mode: string) => {\n setViewMode(mode);\n\n router.push({\n pathname: router.pathname,\n query: {\n ...router.query,\n view: mode,\n },\n });\n };\n\n React.useEffect(() => {\n if (router.query.view === 'source' || router.query.view === 'desktop') {\n setViewMode(router.query.view);\n }\n }, [router.query.view]);\n\n return (\n <Layout\n navItems={navItems}\n title={slug}\n viewMode={viewMode}\n setViewMode={handleViewMode}\n markup={markup}\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 <CodeContainer\n markups={[\n { language: 'jsx', content: reactMarkup },\n { language: 'markup', content: markup },\n { language: 'markdown', content: plainText },\n ]}\n />\n </div>\n )}\n </Layout>\n );\n};\n\nexport default Preview;\n",
22
22
  },
23
23
  ];
@@ -12,7 +12,7 @@ export const root = [
12
12
  {
13
13
  title: 'package.json',
14
14
  content:
15
- '{\n "name": "react-email-preview",\n "version": "0.0.7",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=18.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.2",\n "classnames": "2.3.2",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
15
+ '{\n "name": "react-email-preview",\n "version": "0.0.8",\n "description": "The React Email preview application",\n "license": "MIT",\n "scripts": {\n "dev": "next dev",\n "build": "next build",\n "start": "next start",\n "lint": "next lint",\n "format:check": "prettier --check \\"**/*.{ts,tsx,md}\\"",\n "format": "prettier --write \\"**/*.{ts,tsx,md}\\""\n },\n "engines": {\n "node": ">=18.0.0"\n },\n "dependencies": {\n "@next/font": "13.0.4",\n "@radix-ui/colors": "0.1.8",\n "@radix-ui/react-collapsible": "1.0.1",\n "@radix-ui/react-popover": "1.0.2",\n "@radix-ui/react-slot": "1.0.1",\n "@radix-ui/react-toggle-group": "1.0.1",\n "@radix-ui/react-tooltip": "1.0.2",\n "@react-email/render": "0.0.6",\n "classnames": "2.3.2",\n "next": "13.0.4",\n "prism-react-renderer": "1.3.5",\n "react": "18.2.0",\n "react-dom": "18.2.0"\n },\n "devDependencies": {\n "@types/classnames": "2.3.1",\n "@types/node": "18.11.9",\n "@types/react": "18.0.25",\n "@types/react-dom": "18.0.9",\n "autoprefixer": "10.4.13",\n "postcss": "8.4.19",\n "tailwindcss": "3.2.4",\n "typescript": "4.9.3"\n }\n}\n',
16
16
  },
17
17
  {
18
18
  title: 'postcss.config.js',
@@ -17,7 +17,7 @@ export const utils = [
17
17
  {
18
18
  title: 'language-map.ts',
19
19
  content:
20
- "const languageMap = {\n jsx: 'React',\n markup: 'HTML',\n};\n\nexport default languageMap;\n",
20
+ "const languageMap = {\n jsx: 'React',\n markup: 'HTML',\n markdown: 'Plain Text',\n};\n\nexport default languageMap;\n",
21
21
  },
22
22
  {
23
23
  title: 'unreachable.ts',