style: email tweaking

This commit is contained in:
Riccardo
2023-12-19 20:04:32 +01:00
parent c0d6b73aca
commit 3af079a0f5
17 changed files with 155 additions and 110 deletions

View File

@@ -47,7 +47,11 @@ export async function GET(request: Request) {
createdAt: {
gt: new Date(Date.now() - 1000 * 60 * 60 * 24)
}
}
},
orderBy: {
score: 'desc'
},
take: 25
});
const validRankedNews = news

View File

@@ -2,7 +2,7 @@ import { Analytics } from '@vercel/analytics/react';
import type { Metadata } from 'next';
import { Inter as FontSans } from 'next/font/google';
import { Background } from '../components/custom/background/background';
import { cn } from '../utils/utils';
import { cn } from '../utils/ui';
import './globals.css';
export const metadata: Metadata = {

View File

@@ -1,21 +1,30 @@
import { getRandomColor } from '../../../utils/getRandomColor';
export function Footer() {
const background = getRandomColor();
return (
<footer
className='mt-8 bg-blue-200 pt-6 text-black'
style={{ backgroundColor: `${background}` }}
style={{
paddingTop: '1.5rem',
backgroundColor: `#E6F2F2`,
color: 'black'
}}
>
<div
style={{
marginLeft: '2rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
paddingBottom: '2rem'
}}
>
<div className='ml-8 flex items-center justify-between pb-4'>
<div>
<h4 className='text-lg font-semibold'>Contact Us</h4>
<h4 style={{ fontSize: '1.125rem', fontWeight: '600' }}>
Contact Us
</h4>
<p>{process.env.NEXT_PUBLIC_BRAND_NAME}</p>
<p>
Email:{' '}
<a href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}>
Email: {process.env.NEXT_PUBLIC_BRAND_EMAIL}
{process.env.NEXT_PUBLIC_BRAND_EMAIL}
</a>
</p>
</div>

View File

@@ -4,8 +4,15 @@ type NoteProps = {
export function Note({ children }: NoteProps) {
return (
<div className='mt-8 bg-gray-100 px-6 py-4 dark:bg-gray-800'>
<div className='text-sm text-gray-600 dark:text-gray-400'>{children}</div>
<div
style={{
marginTop: '2rem',
padding: '1.5rem 1.5rem',
backgroundColor: '#EBF1F5',
color: '#718096'
}}
>
<div style={{ fontSize: '0.875rem' }}>{children}</div>
</div>
);
}

View File

@@ -1,24 +1,30 @@
import { Link } from '../custom/link';
import { Note } from './components/note';
import Email from './template';
import Template from './template';
export default function ConfirmationTemplate(code: string) {
return {
subject: 'Welcome!',
template: (
<Email
title={'Welcome!'}
<Template
title='Welcome!'
body={
<div className='text-base text-gray-700 dark:text-gray-400'>
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
<p>Dear subscriber,</p>
<p className='mt-2 '>
thank you for subscribing to our newsletter! Please click the
button below to confirm your subscription.
<p style={{ marginTop: '0.5rem' }}>
thank you for subscribing to our newsletter! Please click the link
below to confirm your subscription.
</p>
<div className='my-8 flex justify-center'>
<div
style={{
margin: '2rem 0',
display: 'flex',
justifyContent: 'center'
}}
>
<Link
path={`${process.env.HOME_URL}/confirmation?code=${code}`}
text='Confirm Subscription'
text='Confirm subscription'
/>
</div>
<Note>

View File

@@ -0,0 +1,13 @@
export const sayings = [
'hot off the press',
'straight from the oven',
"straight from the horse's mouth",
'brand spanking new',
'fresh as a daisy',
'straight out of the box',
'straight off the assembly line',
'hot out of the kitchen',
'just minted',
'freshly brewed',
'just off the production line'
];

View File

@@ -1,54 +1,61 @@
import { z } from 'zod';
import { getRandomColor } from '../../utils/getRandomColor';
import { NewsSchema } from '../../utils/schemas';
import Email from './template';
import { sayings } from './helpers/newsletterSayings';
import Template from './template';
export default function NewsletterTemplate(
stories: z.infer<typeof NewsSchema>[]
) {
const sayings = [
'hot off the press',
'straight from the oven',
"straight from the horse's mouth",
'brand spanking new',
'fresh as a daisy',
'straight out of the box',
'straight off the assembly line',
'hot out of the kitchen',
'just minted',
'freshly brewed',
'just off the production line'
];
return {
subject: `What's new from Hackernews?`,
subject: `What's new from the Hackernews forum?`,
template: (
<Email
title='Good day!'
<Template
title={`Here is something
${sayings[Math.floor(Math.random() * sayings.length)]}!`}
body={
<div className='text-base text-gray-700 dark:text-gray-400'>
<p className='flex justify-center'>
Here is something{' '}
{sayings[Math.floor(Math.random() * sayings.length)]}:
</p>
<div>
{stories.map(story => {
const background = getRandomColor();
return (
<div
key={story.id}
className='mt-8 rounded-lg border bg-card text-card-foreground shadow-sm'
style={{
marginTop: '2rem',
marginBottom: '2rem',
borderRadius: '0.5rem',
border: '1px solid #e5e7eb',
backgroundColor: `white`,
color: '#111827',
boxShadow: '0 16px 32px 0 rgba(0, 0, 0, 0.05)'
}}
data-v0-t='card'
style={{ backgroundColor: `${background}` }}
>
<div className='flex flex-col space-y-1.5 px-6 pb-2 pt-6'>
<h2 className='text-2xl font-semibold'>{story.title}</h2>
<p className='italic'>by {story.by}</p>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.375rem',
paddingTop: '1.5rem',
paddingLeft: '1.5rem',
paddingRight: '1.5rem'
}}
>
<h2 style={{ fontSize: '1.5rem', fontWeight: '600' }}>
{story.title}
</h2>
<p style={{ fontSize: '1rem', fontStyle: 'italic' }}>
by {story.by}
</p>
</div>
{story.text && (
<div className='px-6'>
<div
style={{
paddingLeft: '1.5rem',
fontSize: '1rem',
paddingRight: '1.5rem'
}}
>
<p
className='mb-4'
dangerouslySetInnerHTML={{
__html:
story.text.length > 500
@@ -59,7 +66,15 @@ export default function NewsletterTemplate(
</div>
)}
{story.url && (
<div className='p-6 text-right font-bold'>
<div
style={{
paddingBottom: '1.5rem',
paddingLeft: '1.5rem',
paddingRight: '1.5rem',
textAlign: 'right',
fontWeight: 'bold'
}}
>
<a href={story.url}>Read more</a>
</div>
)}

View File

@@ -1,28 +1,34 @@
import { Html } from '@react-email/html';
import { Section } from '@react-email/section';
import { getRandomColor } from '../../utils/getRandomColor';
import { Footer } from './components/footer';
type EmailProps = {
type TemplateProps = {
title: string;
body: JSX.Element;
};
export default function Email({ title, body }: EmailProps) {
const titleBackground = getRandomColor();
export default function Template({ title, body }: TemplateProps) {
return (
<Html>
<Section className='max-w-2xl overflow-hidden rounded-lg bg-white shadow-lg'>
<div
style={{
maxWidth: '720px',
alignContent: 'center',
alignItems: 'center',
backgroundColor: '#F9FBFB',
}}
>
<h1
className='p-8 text-center text-3xl font-bold text-black'
style={{ backgroundColor: `${titleBackground}` }}
style={{
padding: '20px',
textAlign: 'center',
fontSize: '24px',
fontWeight: 'bold',
color: 'white',
backgroundColor: `#8230CC`,
}}
>
{title}
</h1>
<div className='m-8 p-8'>{body}</div>
<div style={{ margin: '20px', padding: '20px' }}>{body}</div>
<Footer />
</Section>
</Html>
</div>
);
}

View File

@@ -1,26 +1,35 @@
import { Link } from '../custom/link';
import { Note } from './components/note';
import Email from './template';
import Template from './template';
export default function UnsubscribeTemplate() {
return {
subject: 'Unsubscribe confirmation',
template: (
<Email
title="We're sad you're leaving :("
<Template
title="We're sad to see you go :("
body={
<div className='text-base text-gray-700 dark:text-gray-400'>
<p className='mt-2 '>
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
<p style={{ marginTop: '0.5rem' }}>
You have been successfully unsubscribed from our newsletter. You
won&apos;t receive any further communications from us unless you
explicitly opt-in again.
</p>
<div className='my-8 flex justify-center'>
<div
style={{
margin: '2rem 0',
display: 'flex',
justifyContent: 'center'
}}
>
<Link path='/' text='Re-subscribe' />
</div>
<Note>
If you have any questions or concerns, please feel free to{' '}
<a className='text-blue-500 underline' href='#'>
<a
style={{ color: '#3b82f6', textDecoration: 'underline' }}
href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}
>
contact us
</a>
.

View File

@@ -1,7 +1,7 @@
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { cn } from '../../utils/utils';
import { cn } from '../../utils/ui';
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { cn } from '../../utils/utils';
import { cn } from '../../utils/ui';
const Card = React.forwardRef<
HTMLDivElement,

View File

@@ -10,7 +10,7 @@ import {
useFormContext
} from 'react-hook-form';
import { Label } from '../../components/ui/label';
import { cn } from '../../utils/utils';
import { cn } from '../../utils/ui';
const Form = FormProvider;

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { cn } from '../../utils/utils';
import { cn } from '../../utils/ui';
const Input = React.forwardRef<
HTMLInputElement,

View File

@@ -3,7 +3,7 @@
import * as LabelPrimitive from '@radix-ui/react-label';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from 'react';
import { cn } from '../../utils/utils';
import { cn } from '../../utils/ui';
const labelVariants = cva(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'

View File

@@ -22,10 +22,6 @@
"@prisma/client": "^5.6.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@react-email/container": "^0.0.10",
"@react-email/html": "^0.0.6",
"@react-email/section": "^0.0.10",
"@react-email/text": "^0.0.6",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@vercel/analytics": "^1.1.1",
"class-variance-authority": "^0.7.0",

View File

@@ -460,16 +460,6 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "1.0.1"
"@react-email/container@^0.0.10":
version "0.0.10"
resolved "https://registry.yarnpkg.com/@react-email/container/-/container-0.0.10.tgz#1f9e883d77cb1b1cbd3cbbe271a545ed1ce622be"
integrity sha512-goishY7ocq+lord0043/LZK268bqvMFW/sxpUt/dSCPJyrrZZNCbpW2t8w8HztU38cYj0qGQLxO5Qvpn/RER3w==
"@react-email/html@^0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@react-email/html/-/html-0.0.6.tgz#a54b51849b21ec131c491b16f7695867bbe7ac81"
integrity sha512-8Fo20VOqxqc087gGEPjT8uos06fTXIC8NSoiJxpiwAkwiKtQnQH/jOdoLv6XaWh5Zt2clj1uokaoklnaM5rY1w==
"@react-email/render@0.0.9":
version "0.0.9"
resolved "https://registry.yarnpkg.com/@react-email/render/-/render-0.0.9.tgz#145d3c3fcbc9c4277234e44a58214bb48e8f79bb"
@@ -480,16 +470,6 @@
react "18.2.0"
react-dom "18.2.0"
"@react-email/section@^0.0.10":
version "0.0.10"
resolved "https://registry.yarnpkg.com/@react-email/section/-/section-0.0.10.tgz#69e0d9956f74a804ad6c5077b7a26e1e8c07edcc"
integrity sha512-x9B2KYFqj+d8I1fK9bgeVm/3mLE4Qgn4mm/GbDtcJeSzKU/G7bTb7/3+BMDk9SARPGkg5XAuZm1XgcqQQutt2A==
"@react-email/text@^0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@react-email/text/-/text-0.0.6.tgz#c28a2b70f3e17de8e93e3fbdf9a18afff3623a29"
integrity sha512-PDUTAD1PjlzXFOIUrR1zuV2xxguL62yne5YLcn1k+u/dVUyzn6iU/5lFShxCfzuh3QDWCf4+JRNnXN9rmV6jzw==
"@rushstack/eslint-patch@^1.3.3":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz#9ab8f811930d7af3e3d549183a50884f9eb83f36"