Added satori and improved react email (#1877)
* Improved the react email docs and added a video * Copy * Added a link to the cursor rules * Added satori example * Copy updates * Added react pdf link
This commit is contained in:
+4
-3
@@ -332,14 +332,15 @@
|
||||
"guides/examples/open-ai-with-retrying",
|
||||
"guides/examples/pdf-to-image",
|
||||
"guides/examples/puppeteer",
|
||||
"guides/examples/react-pdf",
|
||||
"guides/examples/react-email",
|
||||
"guides/examples/resend-email-sequence",
|
||||
"guides/examples/satori",
|
||||
"guides/examples/scrape-hacker-news",
|
||||
"guides/examples/sentry-error-tracking",
|
||||
"guides/examples/sharp-image-processing",
|
||||
"guides/examples/supabase-database-operations",
|
||||
"guides/examples/supabase-storage-upload",
|
||||
"guides/examples/react-pdf",
|
||||
"guides/examples/react-email",
|
||||
"guides/examples/resend-email-sequence",
|
||||
"guides/examples/vercel-ai-sdk",
|
||||
"guides/examples/vercel-sync-env-vars"
|
||||
]
|
||||
|
||||
@@ -6,11 +6,11 @@ description: "Learn how to send beautiful emails using React Email and Trigger.d
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use Trigger.dev to send emails using React Email.
|
||||
This example demonstrates how to use Trigger.dev to send emails using [React Email](https://react.email/).
|
||||
|
||||
<Note>
|
||||
This example uses [Resend](https://resend.com) as the email provider. You can use other email
|
||||
providers like [SendGrid](https://sendgrid.com) or [Loops](https://loops.so) as well. Full list of
|
||||
providers like [Loops](https://loops.so) or [SendGrid](https://sendgrid.com) etc. Full list of
|
||||
their integrations can be found [here](https://react.email/docs/introduction#integrations).
|
||||
</Note>
|
||||
|
||||
@@ -98,7 +98,7 @@ export const sendEmail = task({
|
||||
});
|
||||
```
|
||||
|
||||
## How the email should look
|
||||
## The email
|
||||
|
||||
This example email should look like this:
|
||||

|
||||
@@ -121,3 +121,184 @@ To test this task in the [dashboard](https://cloud.trigger.dev), you can use the
|
||||
## Deploying your task
|
||||
|
||||
Deploy the task to production using the Trigger.dev CLI `deploy` command.
|
||||
|
||||
## Using Cursor / AI to build your emails
|
||||
|
||||
In this video you can see how we use Cursor to build a welcome email.
|
||||
|
||||
We recommend using our [Cursor rules](https://trigger.dev/changelog/cursor-rules-writing-tasks/) to help you build your tasks and emails.
|
||||
|
||||
#### Video: creating a new email template using Cursor
|
||||
|
||||
<video
|
||||
src="https://content.trigger.dev/trigger-welcome-email-cursor.mp4"
|
||||
controls
|
||||
muted
|
||||
autoPlay
|
||||
loop
|
||||
/>
|
||||
|
||||
#### The generated email template
|
||||
|
||||

|
||||
|
||||
#### The generated code
|
||||
|
||||
```tsx trigger/welcome.tsx
|
||||
import {
|
||||
Body,
|
||||
Button,reac
|
||||
Container,
|
||||
Head,
|
||||
Hr,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
Text,
|
||||
} from "@react-email/components";
|
||||
|
||||
const baseUrl = process.env.VERCEL_URL
|
||||
? `https://${process.env.VERCEL_URL}`
|
||||
: "";
|
||||
|
||||
export const TriggerDevWelcomeEmail = () => (
|
||||
<Html>
|
||||
<Head />
|
||||
<Preview>Welcome to Trigger.dev - Your background jobs platform!</Preview>
|
||||
<Body style={main}>
|
||||
<Container style={container}>
|
||||
<Section style={box}>
|
||||
<Img
|
||||
src="https://trigger.dev/assets/triggerdev-lockup--light.svg"
|
||||
width="150"
|
||||
height="40"
|
||||
alt="Trigger.dev"
|
||||
/>
|
||||
<Hr style={hr} />
|
||||
<Text style={paragraph}>
|
||||
Thanks for signing up for Trigger.dev! You're now ready to start
|
||||
creating powerful background jobs and workflows.
|
||||
</Text>
|
||||
<Text style={paragraph}>
|
||||
You can monitor your jobs, view runs, and manage your projects right
|
||||
from your dashboard.
|
||||
</Text>
|
||||
<Button style={button} href="https://cloud.trigger.dev/dashboard">
|
||||
View your Trigger.dev Dashboard
|
||||
</Button>
|
||||
<Hr style={hr} />
|
||||
<Text style={paragraph}>
|
||||
To help you get started, check out our{" "}
|
||||
<Link style={anchor} href="https://trigger.dev/docs">
|
||||
documentation
|
||||
</Link>{" "}
|
||||
and{" "}
|
||||
<Link style={anchor} href="https://trigger.dev/docs/quickstart">
|
||||
quickstart guide
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
<Text style={paragraph}>
|
||||
You can create your first job using our SDK, set up integrations,
|
||||
and configure triggers to automate your workflows. Take a look at
|
||||
our{" "}
|
||||
<Link style={anchor} href="https://trigger.dev/docs/examples">
|
||||
examples
|
||||
</Link>{" "}
|
||||
for inspiration.
|
||||
</Text>
|
||||
<Text style={paragraph}>
|
||||
Join our{" "}
|
||||
<Link style={anchor} href="https://discord.gg/kA47vcd8Qr">
|
||||
Discord community
|
||||
</Link>{" "}
|
||||
to connect with other developers and get help when you need it.
|
||||
</Text>
|
||||
<Text style={paragraph}>
|
||||
We're here to help you build amazing things. If you have any
|
||||
questions, check out our{" "}
|
||||
<Link style={anchor} href="https://trigger.dev/docs">
|
||||
documentation
|
||||
</Link>{" "}
|
||||
or reach out to us on Discord.
|
||||
</Text>
|
||||
<Text style={paragraph}>— The Trigger.dev team</Text>
|
||||
<Hr style={hr} />
|
||||
<Text style={footer}>Trigger.dev Inc.</Text>
|
||||
</Section>
|
||||
</Container>
|
||||
</Body>
|
||||
</Html>
|
||||
);
|
||||
|
||||
export default TriggerDevWelcomeEmail;
|
||||
|
||||
const main = {
|
||||
backgroundColor: "#0E0C15",
|
||||
fontFamily:
|
||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||
};
|
||||
|
||||
const container = {
|
||||
backgroundColor: "#1D1B27",
|
||||
margin: "0 auto",
|
||||
padding: "20px 0 48px",
|
||||
marginBottom: "64px",
|
||||
};
|
||||
|
||||
const box = {
|
||||
padding: "0 48px",
|
||||
};
|
||||
|
||||
const hr = {
|
||||
borderColor: "#2D2B3B",
|
||||
margin: "20px 0",
|
||||
};
|
||||
|
||||
const paragraph = {
|
||||
color: "#E1E1E3",
|
||||
fontSize: "16px",
|
||||
lineHeight: "24px",
|
||||
textAlign: "left" as const,
|
||||
};
|
||||
|
||||
const anchor = {
|
||||
color: "#A78BFA",
|
||||
};
|
||||
|
||||
const button = {
|
||||
backgroundColor: "#7C3AED",
|
||||
borderRadius: "6px",
|
||||
color: "#fff",
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
textDecoration: "none",
|
||||
textAlign: "center" as const,
|
||||
display: "block",
|
||||
width: "100%",
|
||||
padding: "12px",
|
||||
};
|
||||
|
||||
const footer = {
|
||||
color: "#9CA3AF",
|
||||
fontSize: "12px",
|
||||
lineHeight: "16px",
|
||||
};
|
||||
```
|
||||
|
||||
## Learn more
|
||||
|
||||
### React Email docs
|
||||
|
||||
Check out the [React Email docs](https://react.email/docs) and learn how to set up and use React Email, including how to preview your emails locally.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Components" icon="puzzle-piece" href="https://react.email/components">
|
||||
Pre-built components you can copy and paste into your emails.
|
||||
</Card>
|
||||
<Card title="Templates" icon="rectangle-list" href="https://react.email/templates">
|
||||
Extensive pre-built templates ready to use.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -6,7 +6,7 @@ description: "This example will show you how to generate a PDF using Trigger.dev
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use Trigger.dev to generate a PDF using `react-pdf` and save it to Cloudflare R2.
|
||||
This example demonstrates how to use Trigger.dev to generate a PDF using [react-pdf](https://react-pdf.org/) and save it to Cloudflare R2.
|
||||
|
||||
## Task code
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: "Generate OG Images using Satori"
|
||||
sidebarTitle: "Satori OG Images"
|
||||
description: "Learn how to generate dynamic Open Graph images using Satori and Trigger.dev."
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use Trigger.dev to generate dynamic Open Graph (OG) images using Vercel's [Satori](https://github.com/vercel/satori). The task takes a title and image URL as input and generates a beautiful OG image with text overlay.
|
||||
|
||||
This can be customized and extended however you like, full list of options can be found [here](https://github.com/vercel/satori).
|
||||
|
||||
## Task code
|
||||
|
||||
```tsx trigger/generateOgImage.ts
|
||||
import { schemaTask } from "@trigger.dev/sdk/v3";
|
||||
import { z } from "zod";
|
||||
import satori from "satori";
|
||||
import sharp from "sharp";
|
||||
import { join } from "path";
|
||||
import fs from "fs/promises";
|
||||
|
||||
export const generateOgImage = schemaTask({
|
||||
id: "generate-og-image",
|
||||
schema: z.object({
|
||||
width: z.number().optional(),
|
||||
height: z.number().optional(),
|
||||
title: z.string(),
|
||||
imageUrl: z.string().url(),
|
||||
}),
|
||||
run: async (payload) => {
|
||||
// Load font
|
||||
const fontResponse = await fetch(
|
||||
"https://github.com/googlefonts/roboto/raw/main/src/hinted/Roboto-Regular.ttf"
|
||||
).then((res) => res.arrayBuffer());
|
||||
|
||||
// Fetch and convert image to base64
|
||||
const imageResponse = await fetch(payload.imageUrl);
|
||||
const imageBuffer = await imageResponse.arrayBuffer();
|
||||
const imageBase64 = `data:${
|
||||
imageResponse.headers.get("content-type") || "image/jpeg"
|
||||
};base64,${Buffer.from(imageBuffer).toString("base64")}`;
|
||||
|
||||
const markup = (
|
||||
<div
|
||||
style={{
|
||||
width: payload.width ?? 1200,
|
||||
height: payload.height ?? 630,
|
||||
display: "flex",
|
||||
backgroundColor: "#121317",
|
||||
position: "relative",
|
||||
fontFamily: "Roboto",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={imageBase64}
|
||||
width={payload.width ?? 1200}
|
||||
height={payload.height ?? 630}
|
||||
style={{
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
<h1
|
||||
style={{
|
||||
fontSize: "60px",
|
||||
fontWeight: "bold",
|
||||
color: "#fff",
|
||||
margin: 0,
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
left: "48px",
|
||||
maxWidth: "60%",
|
||||
textShadow: "0 2px 4px rgba(0,0,0,0.5)",
|
||||
}}
|
||||
>
|
||||
{payload.title}
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
|
||||
const svg = await satori(markup, {
|
||||
width: payload.width ?? 1200,
|
||||
height: payload.height ?? 630,
|
||||
fonts: [
|
||||
{
|
||||
name: "Roboto",
|
||||
data: fontResponse,
|
||||
weight: 400,
|
||||
style: "normal",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const fileName = `og-${Date.now()}.jpg`;
|
||||
const tempDir = join(process.cwd(), "tmp");
|
||||
await fs.mkdir(tempDir, { recursive: true });
|
||||
const outputPath = join(tempDir, fileName);
|
||||
|
||||
await sharp(Buffer.from(svg))
|
||||
.jpeg({
|
||||
quality: 90,
|
||||
mozjpeg: true,
|
||||
})
|
||||
.toFile(outputPath);
|
||||
|
||||
return {
|
||||
filePath: outputPath,
|
||||
width: payload.width,
|
||||
height: payload.height,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Image example
|
||||
|
||||
This image was generated using the above task.
|
||||
|
||||

|
||||
|
||||
## Testing your task
|
||||
|
||||
To test this task in the [dashboard](https://cloud.trigger.dev), you can use the following payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "My Awesome OG image",
|
||||
"imageUrl": "<your-image-url>",
|
||||
"width": 1200, // optional, defaults to 1200
|
||||
"height": 630 // optional, defaults to 630
|
||||
}
|
||||
```
|
||||
@@ -77,6 +77,10 @@ Task code you can copy and paste to use in your project. They can all be extende
|
||||
| [Vercel AI SDK](/guides/examples/vercel-ai-sdk) | Use Vercel AI SDK to generate text using OpenAI. |
|
||||
| [Vercel sync environment variables](/guides/examples/vercel-sync-env-vars) | Automatically sync environment variables from your Vercel projects to Trigger.dev. |
|
||||
|
||||
## Cursor rules
|
||||
|
||||
If you use Cursor, we have a set of Cursor rules which will help you build your tasks. You can find our installation guide [here](https://trigger.dev/changelog/cursor-rules-writing-tasks/).
|
||||
|
||||
<Note>
|
||||
If you would like to see a guide for your framework, or an example task for your use case, please
|
||||
request it in our [Discord server](https://trigger.dev/discord) and we'll add it to the list.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Reference in New Issue
Block a user