diff --git a/apps/web/.gitignore b/apps/web/.gitignore index b3c2ea94a2..c740f35936 100644 --- a/apps/web/.gitignore +++ b/apps/web/.gitignore @@ -30,4 +30,6 @@ Thumbs.db ## Environment variables ### Prevent `.env` files from being tracked by Git to avoid exposing sensitive information. -.env* \ No newline at end of file +.env* + +next-env.d.ts \ No newline at end of file diff --git a/apps/web/license.md b/apps/web/license.md index 5058f53ebb..2b4b9fc0ba 100644 --- a/apps/web/license.md +++ b/apps/web/license.md @@ -1,4 +1,4 @@ -Copyright 2024 Plus Five Five, Inc +Copyright 2025 Plus Five Five, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts deleted file mode 100644 index 830fb594ca..0000000000 --- a/apps/web/next-env.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/web/next.config.js b/apps/web/next.config.ts similarity index 89% rename from apps/web/next.config.js rename to apps/web/next.config.ts index 3bcd85fb2d..a19fa874ce 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.ts @@ -1,10 +1,6 @@ -/** @type {import('next').NextConfig} */ +import type { NextConfig } from 'next'; -module.exports = { - devIndicators: { - appIsrStatus: false, - }, - reactStrictMode: true, +const nextConfig: NextConfig = { serverExternalPackages: ['@react-email/components', '@react-email/render'], async redirects() { return [ @@ -48,3 +44,5 @@ module.exports = { ]; }, }; + +export default nextConfig; diff --git a/apps/web/src/app/api/check-spam/route.ts b/apps/web/src/app/api/check-spam/route.ts index 25599c0088..db63e84b19 100644 --- a/apps/web/src/app/api/check-spam/route.ts +++ b/apps/web/src/app/api/check-spam/route.ts @@ -2,8 +2,6 @@ import { type NextRequest, NextResponse } from 'next/server'; import { ZodError, z } from 'zod'; import { checkSpam } from './check-spam'; -export const dynamic = 'force-dynamic'; - export function OPTIONS() { return Promise.resolve(NextResponse.json({})); } diff --git a/apps/web/src/app/api/send/test/route.ts b/apps/web/src/app/api/send/test/route.ts index 6110e75a68..17800c1130 100644 --- a/apps/web/src/app/api/send/test/route.ts +++ b/apps/web/src/app/api/send/test/route.ts @@ -3,8 +3,6 @@ import { type NextRequest, NextResponse } from 'next/server'; import { Resend } from 'resend'; import { z } from 'zod'; -export const dynamic = 'force-dynamic'; - export function OPTIONS() { return Promise.resolve(NextResponse.json({})); } diff --git a/apps/web/src/app/components/[slug]/page.tsx b/apps/web/src/app/components/[slug]/page.tsx index d5b1575539..58c33526bd 100644 --- a/apps/web/src/app/components/[slug]/page.tsx +++ b/apps/web/src/app/components/[slug]/page.tsx @@ -3,7 +3,7 @@ import { notFound } from 'next/navigation'; import { componentsStructure } from '../../../../components/structure'; import { ComponentsView } from '../../../components/components-view'; import { IconArrowLeft } from '../../../components/icons/icon-arrow-left'; -import PageTransition from '../../../components/page-transition'; +import { PageTransition } from '../../../components/page-transition'; import { slugify } from '../../../utils/slugify'; import { getImportedComponentsFor } from '../get-imported-components-for'; @@ -54,14 +54,16 @@ export const generateMetadata = async ({ }; }; -const ComponentPage: React.FC = async ({ params }) => { +export default async function ComponentPage({ params }: ComponentPageParams) { const { slug: rawSlug } = await params; const slug = decodeURIComponent(rawSlug); const foundCategory = componentsStructure.find( (category) => slugify(category.name) === slug, ); - if (!foundCategory) return

Component category not found.

; + if (!foundCategory) { + return

Component category not found.

; + } const importedComponents = await getImportedComponentsFor(foundCategory); return ( @@ -76,7 +78,7 @@ const ComponentPage: React.FC = async ({ params }) => {
@@ -93,6 +95,4 @@ const ComponentPage: React.FC = async ({ params }) => { ); -}; - -export default ComponentPage; +} diff --git a/apps/web/src/app/components/page.tsx b/apps/web/src/app/components/page.tsx index f1954f8f5e..2702491b60 100644 --- a/apps/web/src/app/components/page.tsx +++ b/apps/web/src/app/components/page.tsx @@ -3,107 +3,98 @@ import type { Metadata } from 'next'; import dynamic from 'next/dynamic'; import Link from 'next/link'; import { componentsStructure } from '../../../components/structure'; -import PageTransition from '../../components/page-transition'; +import { PageTransition } from '../../components/page-transition'; import { Spotlight } from '../../components/spotlight'; import { slugify } from '../../utils/slugify'; -const title = 'Components - React Email'; -const description = - 'Build beautiful emails with pre-built components that you can copy-and-paste into your app.'; - export const metadata: Metadata = { - title, - description, + title: 'Components - React Email', + description: + 'Build beautiful emails with pre-built components that you can copy-and-paste into your app.', openGraph: { - title, - description, - images: [ - { - url: 'https://react.email/static/covers/patterns.png', - }, - ], + images: [{ url: 'https://react.email/static/covers/patterns.png' }], }, alternates: { canonical: '/components', }, }; -const ComponentsPage = async () => ( - <> -
-
-
-
-
-
- -
-

Components

-

- Build beautiful emails with pre-built components that you can - copy-and-paste into your app. -

+export default async function ComponentsPage() { + return ( + <> +
+
+
+
+
-
-
-
- {componentsStructure.map((category, index) => { - const slug = slugify(category.name); - const Illustration = dynamic( - () => - import( - `@/illustrations/${category.name - .toLowerCase() - .replace(/ /g, '-')}` - ), - ); + +
+

Components

+

+ Build beautiful emails with pre-built components that you can + copy-and-paste into your app. +

+
+
+
+
+ {componentsStructure.map((category, index) => { + const slug = slugify(category.name); + const Illustration = dynamic( + () => + import( + `@/illustrations/${category.name + .toLowerCase() + .replace(/ /g, '-')}` + ), + ); - return ( - - -
-
-
- -
-

- {category.name} -

- - {category.components.length} component - {category.components.length > 1 && 's'} - - - - ); - })} -
- - -); - -export default ComponentsPage; + +
+
+
+ +
+

+ {category.name} +

+ + {category.components.length} component + {category.components.length > 1 && 's'} + + + + ); + })} +
+ + + ); +} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index f333c1dcec..943cd93eeb 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -82,7 +82,11 @@ export const viewport = { themeColor: '#25AEBA', }; -const RootLayout = ({ children }: { children: React.ReactNode }) => { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { return ( { ); -}; - -export default RootLayout; +} diff --git a/apps/web/src/app/not-found.tsx b/apps/web/src/app/not-found.tsx index b2dd3a1062..6b3ec203ec 100644 --- a/apps/web/src/app/not-found.tsx +++ b/apps/web/src/app/not-found.tsx @@ -1,4 +1,4 @@ -import PageTransition from '@/components/page-transition'; +import { PageTransition } from '@/components/page-transition'; export const metadata = { title: '404 Not found', @@ -7,29 +7,29 @@ export const metadata = { }, }; -const NotFound = () => ( - <> -
-
-
-
+export default function NotFound() { + return ( + <> +
+
+
+
+
-
- -

- 404
- Not Found -

-
-

This page does not exist.

-

Please check the URL and try again.

-
-
- -); - -export default NotFound; + +

+ 404
+ Not Found +

+
+

This page does not exist.

+

Please check the URL and try again.

+
+
+ + ); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index ba105b156f..1f280bc05f 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -6,51 +6,51 @@ import { Code } from '../components/code'; import { Heading } from '../components/heading'; import { Text } from '../components/text'; -const Home = () => ( - <> - -
-
-
- React Email Logo +export default function Home() { + return ( + <> + +
+
+
+ React Email Logo +
+ + The next generation of writing emails + +
+ + A collection of high-quality, unstyled components for creating + beautiful emails using React and TypeScript. + +
- - The next generation of writing emails - -
- - A collection of high-quality, unstyled components for creating - beautiful emails using React and TypeScript. - +
+ + + npx create-email@latest +
-
-
- - - npx create-email@latest - -
-
- -); - -export default Home; +
+ + ); +} diff --git a/apps/web/src/app/templates/page.tsx b/apps/web/src/app/templates/page.tsx index d01e58cb39..f29ab788ed 100644 --- a/apps/web/src/app/templates/page.tsx +++ b/apps/web/src/app/templates/page.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next'; import Image from 'next/image'; import { Anchor } from '../../components/anchor'; import { Heading } from '../../components/heading'; -import PageTransition from '../../components/page-transition'; +import { PageTransition } from '../../components/page-transition'; import { Template } from '../../components/template'; import { Text } from '../../components/text'; @@ -99,63 +99,59 @@ const items = [ }, ]; -const title = 'Templates — React Email'; const description = 'Open source templates built with React Email'; + export const metadata: Metadata = { - title, + title: 'Templates — React Email', description, - openGraph: { - title, - description, - }, }; -const Templates = () => ( - <> - - -
- - Templates - - - {description}. - - - Recreate an{' '} - - existing email - {' '} - or submit a{' '} - - pull request - {' '} - to add your template here. - -
-
- {items.map((item) => ( -