-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import { withI18n } from "@languine/react-email"; | ||
import { | ||
Body, | ||
Button, | ||
Column, | ||
Container, | ||
Head, | ||
Heading, | ||
Hr, | ||
Html, | ||
Img, | ||
Link, | ||
Preview, | ||
Row, | ||
Section, | ||
Tailwind, | ||
Text, | ||
} from "@react-email/components"; | ||
import * as React from "react"; | ||
|
||
interface VercelInviteUserEmailProps { | ||
username?: string; | ||
userImage?: string; | ||
invitedByUsername?: string; | ||
invitedByEmail?: string; | ||
teamName?: string; | ||
teamImage?: string; | ||
inviteLink?: string; | ||
inviteFromIp?: string; | ||
inviteFromLocation?: string; | ||
} | ||
|
||
const baseUrl = process.env.VERCEL_URL | ||
? `https://${process.env.VERCEL_URL}` | ||
: ""; | ||
|
||
export const VercelInviteUserEmail = withI18n( | ||
({ | ||
username, | ||
userImage, | ||
invitedByUsername, | ||
invitedByEmail, | ||
teamName, | ||
teamImage, | ||
inviteLink, | ||
inviteFromIp, | ||
inviteFromLocation, | ||
}: VercelInviteUserEmailProps) => { | ||
const previewText = `Join ${invitedByUsername} on Vercel`; | ||
|
||
return ( | ||
<Html> | ||
<Head /> | ||
<Preview>{previewText}</Preview> | ||
<Tailwind> | ||
<Body className="bg-white my-auto mx-auto font-sans px-2"> | ||
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]"> | ||
<Section className="mt-[32px]"> | ||
<Img | ||
src={`${baseUrl}/static/vercel-logo.png`} | ||
width="40" | ||
height="37" | ||
alt="Vercel" | ||
className="my-0 mx-auto" | ||
/> | ||
</Section> | ||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0"> | ||
Join <strong>{teamName}</strong> on <strong>Vercel</strong> | ||
</Heading> | ||
<Text className="text-black text-[14px] leading-[24px]"> | ||
Hello {username}, | ||
</Text> | ||
<Text className="text-black text-[14px] leading-[24px]"> | ||
<strong>{invitedByUsername}</strong> ( | ||
<Link | ||
href={`mailto:${invitedByEmail}`} | ||
className="text-blue-600 no-underline" | ||
> | ||
{invitedByEmail} | ||
</Link> | ||
) has invited you to the <strong>{teamName}</strong> team on{" "} | ||
<strong>Vercel</strong>. | ||
</Text> | ||
<Section> | ||
<Row> | ||
<Column align="right"> | ||
<Img | ||
className="rounded-full" | ||
src={userImage} | ||
width="64" | ||
height="64" | ||
/> | ||
</Column> | ||
<Column align="center"> | ||
<Img | ||
src={`${baseUrl}/static/vercel-arrow.png`} | ||
width="12" | ||
height="9" | ||
alt="invited you to" | ||
/> | ||
</Column> | ||
<Column align="left"> | ||
<Img | ||
className="rounded-full" | ||
src={teamImage} | ||
width="64" | ||
height="64" | ||
/> | ||
</Column> | ||
</Row> | ||
</Section> | ||
<Section className="text-center mt-[32px] mb-[32px]"> | ||
<Button | ||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3" | ||
href={inviteLink} | ||
> | ||
Join the team | ||
</Button> | ||
</Section> | ||
<Text className="text-black text-[14px] leading-[24px]"> | ||
or copy and paste this URL into your browser:{" "} | ||
<Link href={inviteLink} className="text-blue-600 no-underline"> | ||
{inviteLink} | ||
</Link> | ||
</Text> | ||
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" /> | ||
<Text className="text-[#666666] text-[12px] leading-[24px]"> | ||
This invitation was intended for{" "} | ||
<span className="text-black">{username}</span>. This invite was | ||
sent from <span className="text-black">{inviteFromIp}</span>{" "} | ||
located in{" "} | ||
<span className="text-black">{inviteFromLocation}</span>. If you | ||
were not expecting this invitation, you can ignore this email. | ||
If you are concerned about your account's safety, please reply | ||
to this email to get in touch with us. | ||
</Text> | ||
</Container> | ||
</Body> | ||
</Tailwind> | ||
</Html> | ||
); | ||
}, | ||
"en", | ||
); | ||
|
||
VercelInviteUserEmail.PreviewProps = { | ||
username: "alanturing", | ||
userImage: `${baseUrl}/static/vercel-user.png`, | ||
invitedByUsername: "Alan", | ||
invitedByEmail: "[email protected]", | ||
teamName: "Enigma", | ||
teamImage: `${baseUrl}/static/vercel-team.png`, | ||
inviteLink: "https://vercel.com/teams/invite/foo", | ||
inviteFromIp: "204.13.186.218", | ||
inviteFromLocation: "São Paulo, Brazil", | ||
} as VercelInviteUserEmailProps; | ||
|
||
export default VercelInviteUserEmail; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export default { | ||
en: require("./en.json"), | ||
// es: require("./es.json"), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "react-email-starter", | ||
"version": "0.1.6", | ||
"private": true, | ||
"scripts": { | ||
"build": "email build", | ||
"dev": "email dev", | ||
"export": "email export" | ||
}, | ||
"dependencies": { | ||
"@languine/react-email": "workspace:*", | ||
"@react-email/components": "0.0.31", | ||
"react-dom": "19.0.0", | ||
"react": "19.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "19.0.1", | ||
"@types/react-dom": "19.0.1", | ||
"react-email": "3.0.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# React Email Starter | ||
|
||
A live preview right in your browser so you don't need to keep sending real emails during development. | ||
|
||
## Getting Started | ||
|
||
First, install the dependencies: | ||
|
||
```sh | ||
npm install | ||
# or | ||
yarn | ||
``` | ||
|
||
Then, run the development server: | ||
|
||
```sh | ||
npm run dev | ||
# or | ||
yarn dev | ||
``` | ||
|
||
Open [localhost:3000](http://localhost:3000) with your browser to see the result. | ||
|
||
## License | ||
|
||
MIT License |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "@languine/react-email", | ||
"version": "1.0.0", | ||
"files": ["dist", "README.md"], | ||
"main": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"license": "MIT", | ||
"scripts": { | ||
"clean": "rm -rf .turbo node_modules", | ||
"lint": "biome check .", | ||
"format": "biome format --write .", | ||
"typecheck": "tsc --noEmit", | ||
"build": "tsup --clean src/index.tsx" | ||
}, | ||
"peerDependencies": { | ||
"i18n-js": "^4.5.1" | ||
}, | ||
"devDependencies": { | ||
"tsup": "^8.3.5", | ||
"typescript": "^5.7.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { join } from "node:path"; | ||
import { I18n } from "i18n-js"; | ||
|
||
export function withI18n<Props extends object>( | ||
Component: React.ComponentType<Props>, | ||
locale: string, | ||
) { | ||
const WithI18nComponent = (props: Props) => { | ||
// Read and parse i18n config file | ||
const configPath = join(process.cwd(), "locales/i18n.config.ts"); | ||
const config = require(configPath); | ||
|
||
if (!config) { | ||
throw new Error("i18n.config.ts not found"); | ||
} | ||
|
||
const i18n = new I18n(config); | ||
|
||
i18n.locale = locale; | ||
i18n.enableFallback = true; | ||
|
||
return <Component {...props} locale={locale} i18n={i18n} />; | ||
}; | ||
|
||
WithI18nComponent.displayName = `withI18n(${ | ||
Component.displayName || Component.name || "Component" | ||
})`; | ||
|
||
return WithI18nComponent; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"include": ["src/**/*.ts", "src/**/*.tsx"], | ||
"compilerOptions": { | ||
"target": "esnext", | ||
"module": "NodeNext", | ||
"moduleResolution": "nodenext", | ||
"allowJs": true, | ||
"strict": true, | ||
"skipLibCheck": true, | ||
"isolatedModules": true, | ||
"esModuleInterop": true, | ||
"outDir": "dist", | ||
"resolveJsonModule": true, | ||
"declaration": true, | ||
"declarationMap": true, | ||
"sourceMap": true, | ||
"noEmit": false, | ||
"customConditions": ["source"], | ||
"jsx": "react-jsx" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { defineConfig } from "tsup"; | ||
|
||
export default defineConfig({ | ||
dts: true, | ||
format: "esm", | ||
entry: ["src/index.ts"], | ||
}); |