Skip to content

Commit

Permalink
/docs/usage page (#202)
Browse files Browse the repository at this point in the history
* Usage page init

* Add resend version of usage

* dual resend and nodemailer content

* few more touches

* Fixing and improving content

* formatting

* finetune

* Add Ul mdx element stylings

* Improve integrations texts

* fix mdx styling

* Make usage steps more real world
  • Loading branch information
ChcJohnie authored Aug 11, 2023
1 parent 50491f2 commit b1ec402
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 5 deletions.
12 changes: 12 additions & 0 deletions src/docs/components/MdxComponents/DocElements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,15 @@ export const MdxCode = ({
}: React.ComponentPropsWithoutRef<"code">) => (
<code className="text-neutral-300">{children}</code>
);

export const MdxOl = ({ children }: React.ComponentPropsWithoutRef<"ol">) => (
<ol className="list-inside list-decimal pl-2 text-lg text-neutral-500 md:text-xl">
{children}
</ol>
);

export const MdxUl = ({ children }: React.ComponentPropsWithoutRef<"ul">) => (
<ul className="list-inside list-disc pl-2 text-lg text-neutral-500 md:text-xl">
{children}
</ul>
);
28 changes: 28 additions & 0 deletions src/docs/components/MdxComponents/EmailSourceTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { TabbedCode, TabbedCodeItem } from "@components/Code";
import { getContentEmail } from "@components/MdxComponents/utils";

export type ComponentSourceTabsProps = {
emailId: string;
};

export const EmailSourceTabs = async ({
emailId,
}: ComponentSourceTabsProps) => {
const emailSource = await getContentEmail(emailId);

const tabs: TabbedCodeItem[] = [
{
id: `${emailSource.id}.tsx`,
htmlCode: emailSource.source,
},
];
return (
<div className="relative overflow-hidden rounded-md">
<TabbedCode
tabs={tabs}
collapsedClassName="max-h-[350px]"
className="min-h-[350px]"
></TabbedCode>
</div>
);
};
12 changes: 11 additions & 1 deletion src/docs/components/MdxComponents/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { ComponentSourceTabsProps } from "./ComponentSourceTabs";

export { type ComponentSourceTabsProps };
export { MdxH1, MdxH2, MdxH3, MdxP, MdxA, MdxCode } from "./DocElements";
export {
MdxH1,
MdxH2,
MdxH3,
MdxP,
MdxA,
MdxCode,
MdxUl,
MdxOl,
} from "./DocElements";
export { DocArticle } from "./DocArticle";
export { DocCollapsible } from "./DocCollapsible";
export { DocPre } from "./DocPre";
export { ComponentDemo } from "./ComponentDemo";
export { ComponentSourceTabs } from "./ComponentSourceTabs";
export { ComponentExamples } from "./ComponentExamples";
export { EmailSourceTabs } from "./EmailSourceTabs";
export {
getComponentSource,
getComponentData,
Expand Down
29 changes: 26 additions & 3 deletions src/docs/components/MdxComponents/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const getComponentData = (type: string) => {
return component;
};

export const CONTENT_DIR = "src/docs/examples";
export const CONTENT_DIR = "src/docs/content";
export const EXAMPLES_DIR = "src/docs/examples";
export const SOURCE_DIR = "src/mailingui/components";

/**
Expand All @@ -32,7 +33,12 @@ export const getDemo = async (type: string): Promise<ComponentExampleProps> => {
const component = getComponentData(type);

// Create directory path for component type
const demoPath = join(process.cwd(), CONTENT_DIR, component.type, "Demo.tsx");
const demoPath = join(
process.cwd(),
EXAMPLES_DIR,
component.type,
"Demo.tsx"
);

// Initiate instance of highlighter
const highlighter = await getHighlighter();
Expand Down Expand Up @@ -84,7 +90,7 @@ export const getComponentExamples = async (componentType: string) => {
const component = getComponentData(componentType);

// Create directory path for component type
const typePath = join(process.cwd(), CONTENT_DIR, component.type);
const typePath = join(process.cwd(), EXAMPLES_DIR, component.type);

// Read all the files in that dir
const files = readdirSync(typePath)
Expand Down Expand Up @@ -121,3 +127,20 @@ export const getComponentExamples = async (componentType: string) => {

return examples;
};

export const getContentEmail = async (emailId: string) => {
const emailPath = join(
process.cwd(),
CONTENT_DIR,
"emails-data",
`${emailId}.tsx`
);
const highlighter = await getHighlighter();
const data = readFileSync(emailPath, "utf8");
const source = await highlight(highlighter, data);

return {
id: emailId,
source,
};
};
5 changes: 5 additions & 0 deletions src/docs/constants/docsItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export const docsItems: DocItems = [
label: "Installation",
description: "Learn about the MailingUI",
},
{
href: "/docs/usage",
label: "Usage",
description: "Learn how to use MailingUI",
},
],
},
{
Expand Down
131 changes: 131 additions & 0 deletions src/docs/content/Usage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { EmailSourceTabs } from "src/docs/components/MdxComponents";

import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@components/Tabs/Tabs";

# Usage

As **MailingUI** is collection of email components developed on top of [react-email](https://react.email) library, it also utilize its rendering capabilities to efficiently generate accurate HTML markup that is optimized for various email clients. Once the HTML markup is rendered, you have the flexibility to employ any preferred email sending service or library to effectively deliver your emails.

Usually you would use Javascript integration of email providers to send emails from your application. In this quick guide, we'll illustrate how to use **MailingUI** with [Resend](https://resend.com/) and [Nodemailer](https://nodemailer.com) providers. For alternative providers, please refer to their documentation or explore [Usefull links section](/docs/usage#usefull-links) for more information.

## 1. Install dependencies

For **MailingUI** install [see Installation section](/docs/installation).

<Tabs defaultValue="resend">
<div className="flex items-center justify-start w-full mb-8">
<TabsList className="rounded-2xl">
<TabsTrigger value="resend" className="px-7 py-2 rounded-[10px]">Using Resend</TabsTrigger>
<TabsTrigger value="nodemailer" className="px-7 py-2 rounded-[10px]">Using Nodemailer</TabsTrigger>
</TabsList>
</div>

<TabsContent value="resend">
```bash
npm install resend
```
</TabsContent>
<TabsContent value="nodemailer">
```bash
npm install nodemailer
```
</TabsContent>
</Tabs>

## 2. Create email template

You can use both **MailingUI** components installed and and any other _react-email_ components to create email template. For example:

<EmailSourceTabs emailId="hello-world" />

## 3. Send email

Usually you would place email integration on server side of your Next.js application like API route handler or similar. Our example uses Next.js app router _route handlers_ to send email.

<Tabs defaultValue="resend">
<div className="flex items-center justify-start w-full mb-8">
<TabsList className="rounded-2xl">
<TabsTrigger value="resend" className="px-7 py-2 rounded-[10px]">Using Resend</TabsTrigger>
<TabsTrigger value="nodemailer" className="px-7 py-2 rounded-[10px]">Using Nodemailer</TabsTrigger>
</TabsList>
</div>

<TabsContent value="resend">
Given _Resend_ is operated by same team as _react-email_, email rendering is built-in in _Resend's SDK_. Thus you can use its sendEmail method directly.
<br/>

```ts
import { NextResponse } from 'next/server';
import { Resend } from "resend";
import HelloWorldEmail from "@/emails/test";

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST() {
try {
const data = await resend.emails.send({
from: process.env.RESEND_SENDER,
to: "user@email.com",
subject: "hello world",
react: HelloWorldEmail({farewellMessage: "Goodbye from MailingUI team!"}),
});
return NextResponse.json(data);
} catch (error) {
return NextResponse.json({ error });
}
}
```

</TabsContent>
<TabsContent value="nodemailer">
With Nodemailer (and generally most others providers) you need to render email template first and then send it with provider's API.
<br/>

```ts
import { NextResponse } from 'next/server';
import { render } from "@react-email/render";
import Nodemailer from "nodemailer";
import HelloWorldEmail from "@/emails/test";

const nodemailer = Nodemailer.createTransport({
host: process.env.NODEMAILER_HOST,
port: 465,
secure: true,
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASS,
},
});

export async function POST() {
try {
const emailHtml = render(HelloWorldEmail({
farewellMessage: "Goodbye from MailingUI team!"
}));
const data = await nodemailer.sendMail({
from: process.env.NODEMAILER_SENDER,
to: "user@email.com",
subject: "hello world",
html: emailHtml,
});
return NextResponse.json(data);
} catch (error) {
return NextResponse.json({ error });
}
}
```

</TabsContent>
</Tabs>

# Usefull links

To gain a deeper understanding of how to utilize combination of _react-email_, _MailingUI_ components and email providers services, please refer to following resources:

- [render utility](https://react.email/docs/utilities/render) - how to use render utility, with more examples (plain text etc.)
- [react-email integrations](https://react.email/docs/integrations/overview) - other email sending services integrations, with _react-email_ examples
49 changes: 49 additions & 0 deletions src/docs/content/emails-data/hello-world.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Body, Container, Html, Row } from "@react-email/components";
import { Text } from "@mailingui/components";

type EmailProps = {
welcomeMessage?: string;
farewellMessage?: string;
};

const HelloWorld = (props?: EmailProps) => {
const { welcomeMessage, farewellMessage } = {
welcomeMessage: "Hello World!",
...props,
};
return (
<Html>
<Body style={main}>
<Container style={container} width={600}>
<Row style={{ marginBottom: "16px" }}>
<Text style={{ fontSize: "32px" }}>{welcomeMessage}</Text>
</Row>
<Row>
<Text>
I am email written in React utilizing MailingUI components.
</Text>
</Row>
{farewellMessage && (
<Row style={{ marginTop: "16px" }}>
<Text>{farewellMessage}</Text>
</Row>
)}
</Container>
</Body>
</Html>
);
};
export default HelloWorld;

const main = {
backgroundColor: "#f6f9fc",
padding: "60px 0 122px 0",
};

const container = {
backgroundColor: "#ffffff",
border: "1px solid #f0f0f0",
padding: "40px",
fontFamily:
"'Inter', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif",
};
1 change: 1 addition & 0 deletions src/docs/content/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ComponentType } from "react";

export const mdxDocs: Record<string, ComponentType<MDXProps>> = {
installation: dynamic(() => import(`src/docs/content/Installation.mdx`)),
usage: dynamic(() => import(`src/docs/content/Usage.mdx`)),
components: dynamic(() => import(`src/docs/content/Components.mdx`)),
"components/badges": dynamic(
() => import(`src/docs/content/components/badges.mdx`)
Expand Down
5 changes: 4 additions & 1 deletion src/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
MdxA,
MdxCode,
DocPre,
MdxUl,
MdxOl,
} from "@components/MdxComponents";

// This file allows you to provide custom React components
Expand All @@ -23,12 +25,13 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
// ),
h1: MdxH1,
h2: MdxH2,

h3: MdxH3,
p: MdxP,
pre: ({ children }) => <DocPre>{children}</DocPre>,
a: MdxA,
code: MdxCode,
ol: MdxOl,
ul: MdxUl,
...components,
};
}

1 comment on commit b1ec402

@vercel
Copy link

@vercel vercel bot commented on b1ec402 Aug 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.