style: complete redo of the email layouts (#20)

This commit is contained in:
Riccardo Senica
2024-11-21 19:12:26 +01:00
committed by GitHub
parent aa7296e93b
commit fb53883866
12 changed files with 1087 additions and 785 deletions

View File

@@ -1,3 +1,4 @@
import React from 'react';
import Note from './components/Note';
import Template from './Template';
@@ -8,21 +9,32 @@ export default function ConfirmationTemplate(code: string) {
<Template
title='Welcome!'
body={
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
<div style={{ color: '#4A5568' }}>
<p>Dear subscriber,</p>
<p style={{ marginTop: '0.5rem' }}>
thank you for subscribing to our newsletter! Please click the link
<p style={{ marginTop: '16px' }}>
Thank you for subscribing to our newsletter! Please click the link
below to confirm your subscription.
</p>
<div
style={{
margin: '2rem 0',
display: 'flex',
justifyContent: 'center'
margin: '32px 0',
textAlign: 'center'
}}
>
<a href={`${process.env.HOME_URL}/confirmation?code=${code}`}>
{'Confirm subscription'}
<a
href={`${process.env.HOME_URL}/confirmation?code=${code}`}
style={{
display: 'inline-block',
padding: '12px 24px',
backgroundColor: '#9333EA',
color: 'white',
textDecoration: 'none',
borderRadius: '6px',
fontWeight: '500',
border: 'none'
}}
>
Confirm subscription
</a>
</div>
<Note>

View File

@@ -1,13 +1,15 @@
import { getSayings } from '@utils/getSayings';
import React from 'react';
import { summirize } from '@utils/summarize';
import { NewsType } from '@utils/validationSchemas';
import createDOMPurify from 'isomorphic-dompurify';
import Template from './Template';
import extractMainTopic from '@utils/extractMainTopic';
export default async function NewsletterTemplate(stories: NewsType[]) {
const summary = await summirize(stories);
const sanitizedSummary = createDOMPurify.sanitize(summary, {
USE_PROFILES: { html: true }
USE_PROFILES: { html: true },
ADD_ATTR: ['target', 'rel', 'style']
});
if (!sanitizedSummary) {
@@ -15,17 +17,51 @@ export default async function NewsletterTemplate(stories: NewsType[]) {
throw new Error('Failed to sanitize summary');
}
const topic = extractMainTopic(sanitizedSummary);
return {
subject: `What's new from the Hackernews forum?`,
subject: topic,
template: (
<Template
title={`Here is something
${getSayings[Math.floor(Math.random() * getSayings.length)]}!`}
variant='newsletter'
title='Your Daily Tech Updates'
body={
<div
style={{ fontSize: '1rem', color: '#4a5568' }}
dangerouslySetInnerHTML={{ __html: sanitizedSummary }}
/>
style={{
color: '#374151',
fontSize: '16px',
lineHeight: 1.6
}}
>
<style>
{`
.what-to-watch {
margin-top: 32px;
padding: 24px;
background: linear-gradient(135deg, rgba(186,27,88,0.03) 0%, rgba(245,161,98,0.03) 100%);
border-left: 3px solid #BA1B58;
border-radius: 4px;
}
.what-to-watch h3 {
margin: 0 0 16px 0;
color: #BA1B58;
font-size: 18px;
font-weight: 600;
letter-spacing: -0.02em;
}
.what-to-watch p {
margin: 0;
color: #4A5568;
}
.what-to-watch a {
color: #9333EA !important;
text-decoration: none;
font-weight: 500;
}
`}
</style>
<div dangerouslySetInnerHTML={{ __html: sanitizedSummary }} />
</div>
}
/>
)

View File

@@ -1,31 +1,76 @@
import React from 'react';
import Footer from './components/Footer';
interface TemplateProps {
title: string;
body: JSX.Element;
variant?: string;
}
export default function Template({ title, body }: TemplateProps) {
export default function Template({
title,
body,
variant = 'default'
}: TemplateProps) {
const isNewsletter = variant === 'newsletter';
return (
<div
style={{
maxWidth: '720px',
alignContent: 'center',
alignItems: 'center',
backgroundColor: '#F9FBFB'
margin: '0 auto',
fontFamily: 'system-ui, -apple-system, sans-serif',
backgroundColor: '#ffffff'
}}
>
<h2
<div
style={{
padding: '20px',
textAlign: 'center',
color: 'white',
backgroundColor: `#8230CC`
background: 'linear-gradient(135deg, #9333EA 0%, #F5A162 100%)',
padding: '28px 24px',
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px'
}}
>
{title}
</h2>
<div style={{ margin: '20px', padding: '20px' }}>{body}</div>
<p
style={{
margin: '0 0 8px 0',
fontSize: '12px',
textTransform: 'uppercase',
color: 'rgba(255, 255, 255, 0.9)',
textAlign: 'center'
}}
>
Hackernews + newsletter
</p>
<h2
style={{
fontSize: '24px',
textAlign: 'center',
color: 'white',
fontWeight: '600',
margin: '0',
letterSpacing: '-0.02em'
}}
>
{title}
</h2>
</div>
<div
style={{
backgroundColor: '#ffffff',
padding: '32px 24px'
}}
>
<div
style={{
color: '#374151',
fontSize: isNewsletter ? '16px' : '14px',
lineHeight: '1.6'
}}
>
{body}
</div>
</div>
<Footer />
</div>
);

View File

@@ -1,3 +1,4 @@
import React from 'react';
import Note from './components/Note';
import Template from './Template';
@@ -6,27 +7,43 @@ export default function UnsubscribeTemplate() {
subject: 'Unsubscribe confirmation',
template: (
<Template
title="We're sad to see you go :("
title="We're sad to see you go"
body={
<div style={{ fontSize: '1rem', color: '#4a5568' }}>
<p style={{ marginTop: '0.5rem' }}>
<div style={{ color: '#4A5568' }}>
<p style={{ marginTop: '16px' }}>
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
style={{
margin: '2rem 0',
display: 'flex',
justifyContent: 'center'
margin: '32px 0',
textAlign: 'center'
}}
>
<a href={`${process.env.HOME_URL}/`}>{'Re-subscribe'}</a>
<a
href={`${process.env.HOME_URL}/`}
style={{
display: 'inline-block',
padding: '12px 24px',
backgroundColor: '#9333EA',
color: 'white',
textDecoration: 'none',
borderRadius: '6px',
fontWeight: '500',
border: 'none'
}}
>
Re-subscribe
</a>
</div>
<Note>
If you have any questions or concerns, please feel free to{' '}
<a
style={{ color: '#3b82f6', textDecoration: 'underline' }}
style={{
color: '#386FA4',
textDecoration: 'none'
}}
href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}
>
contact us

View File

@@ -1,35 +1,167 @@
import {
User,
Building2,
Mail,
LogOut,
LayoutGrid,
Shield,
Home
} from 'lucide-react';
export default function Footer() {
return (
<footer
style={{
background: 'linear-gradient(180deg, #F8FAFC 0%, #F1F4F9 100%)',
paddingTop: '1.5rem',
backgroundColor: `#E6F2F2`,
color: 'black'
borderBottomLeftRadius: '8px',
borderBottomRightRadius: '8px',
borderLeft: '1px solid #E5E9F0',
borderRight: '1px solid #E5E9F0',
borderBottom: '1px solid #E5E9F0'
}}
>
<div
style={{
marginLeft: '2rem',
margin: '0 2rem',
paddingBottom: '2rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
paddingBottom: '2rem'
justifyContent: 'space-between'
}}
>
<div>
<h4 style={{ fontSize: '1.125rem', fontWeight: '600' }}>
<h4
style={{
fontSize: '14px',
fontWeight: '600',
marginBottom: '1rem',
marginTop: '0',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#2F4858',
textTransform: 'uppercase',
letterSpacing: '0.05em'
}}
>
<User size={16} color='#386FA4' />
Contact Us
</h4>
<p>{process.env.NEXT_PUBLIC_BRAND_NAME}</p>
<p>
Email:{' '}
<a href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}>
<p
style={{
margin: '0.5rem 0',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#4A5568'
}}
>
<Building2 size={14} color='#386FA4' />
{process.env.NEXT_PUBLIC_BRAND_NAME}
</p>
<p
style={{
margin: '0.5rem 0',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#4A5568'
}}
>
<Mail size={14} color='#386FA4' />
<a
href={`mailto:${process.env.NEXT_PUBLIC_BRAND_EMAIL}`}
style={{ color: '#386FA4', textDecoration: 'none' }}
>
{process.env.NEXT_PUBLIC_BRAND_EMAIL}
</a>
</p>
<p>
Click <a href={`${process.env.HOME_URL}/unsubscribe`}>here</a> to
unsubscribe.
<p
style={{
margin: '0.5rem 0',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#4A5568'
}}
>
<LogOut size={14} color='#386FA4' />
<span>
Click{' '}
<a
href={`${process.env.HOME_URL}/unsubscribe`}
style={{ color: '#386FA4', textDecoration: 'none' }}
>
here
</a>{' '}
to unsubscribe
</span>
</p>
</div>
<div
style={{
width: '1px',
background: 'linear-gradient(180deg, #E5E9F0 0%, transparent 100%)',
alignSelf: 'stretch',
height: 'auto'
}}
/>
<div>
<h4
style={{
fontSize: '14px',
fontWeight: '600',
marginBottom: '1rem',
marginTop: '0',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#2F4858',
textTransform: 'uppercase',
letterSpacing: '0.05em'
}}
>
<LayoutGrid size={16} color='#386FA4' />
Quick Links
</h4>
<p
style={{
margin: '0.5rem 0',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#4A5568'
}}
>
<Shield size={14} color='#386FA4' />
<a
href={`${process.env.HOME_URL}/privacy`}
style={{ color: '#386FA4', textDecoration: 'none' }}
>
Privacy Policy
</a>
</p>
<p
style={{
margin: '0.5rem 0',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
gap: '8px',
color: '#4A5568'
}}
>
<Home size={14} color='#386FA4' />
<a
href={process.env.HOME_URL}
style={{ color: '#386FA4', textDecoration: 'none' }}
>
Visit Website
</a>
</p>
</div>
</div>

View File

@@ -4,15 +4,8 @@ interface NoteProps {
export default function Note({ children }: NoteProps) {
return (
<div
style={{
marginTop: '2rem',
padding: '1.5rem 1.5rem',
backgroundColor: '#EBF1F5',
color: '#718096'
}}
>
<div style={{ fontSize: '0.875rem' }}>{children}</div>
<div className='mt-6 rounded-md bg-gray-50 p-4 text-sm text-gray-600'>
{children}
</div>
);
}