ui: Polish marketing website
This commit is contained in:
@@ -13,26 +13,21 @@ interface ComparisonTableProps {
|
||||
rows: ComparisonRow[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable comparison table component for competitor pages
|
||||
*/
|
||||
export function ComparisonTable({competitorName, rows}: ComparisonTableProps) {
|
||||
return (
|
||||
<div className={'overflow-hidden rounded-xl border border-neutral-200'}>
|
||||
{/* Header */}
|
||||
<div className={'overflow-hidden rounded-[24px] border border-neutral-200'}>
|
||||
<div className={'grid grid-cols-3 gap-px bg-neutral-200'}>
|
||||
<div className={'bg-white p-6'}>
|
||||
<span className={'text-sm font-semibold text-neutral-900'}>Feature</span>
|
||||
<div className={'bg-neutral-50 p-6'}>
|
||||
<span style={{fontFamily: 'var(--font-mono)'}} className={'text-[11px] uppercase tracking-[0.18em] text-neutral-500'}>Feature</span>
|
||||
</div>
|
||||
<div className={'bg-white p-6 text-center'}>
|
||||
<span className={'text-sm font-semibold text-neutral-900'}>Plunk</span>
|
||||
<div className={'bg-neutral-900 p-6 text-center'}>
|
||||
<span style={{fontFamily: 'var(--font-mono)'}} className={'text-[11px] uppercase tracking-[0.18em] text-white'}>Plunk</span>
|
||||
</div>
|
||||
<div className={'bg-white p-6 text-center'}>
|
||||
<span className={'text-sm font-semibold text-neutral-900'}>{competitorName}</span>
|
||||
<div className={'bg-neutral-50 p-6 text-center'}>
|
||||
<span style={{fontFamily: 'var(--font-mono)'}} className={'text-[11px] uppercase tracking-[0.18em] text-neutral-500'}>{competitorName}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Rows */}
|
||||
<div className={'grid gap-px bg-neutral-200'}>
|
||||
{rows.map((row, index) => (
|
||||
<motion.div
|
||||
@@ -40,7 +35,7 @@ export function ComparisonTable({competitorName, rows}: ComparisonTableProps) {
|
||||
initial={{opacity: 0, y: 10}}
|
||||
whileInView={{opacity: 1, y: 0}}
|
||||
viewport={{once: true}}
|
||||
transition={{duration: 0.5, delay: index * 0.05, ease: [0.22, 1, 0.36, 1]}}
|
||||
transition={{duration: 0.4, delay: index * 0.04, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'grid grid-cols-3 gap-px bg-neutral-200'}
|
||||
>
|
||||
<div className={'bg-white p-6'}>
|
||||
@@ -52,10 +47,10 @@ export function ComparisonTable({competitorName, rows}: ComparisonTableProps) {
|
||||
row.plunk ? (
|
||||
<Check className="h-5 w-5 text-neutral-900" strokeWidth={2} />
|
||||
) : (
|
||||
<X className="h-5 w-5 text-neutral-400" strokeWidth={2} />
|
||||
<X className="h-5 w-5 text-neutral-300" strokeWidth={2} />
|
||||
)
|
||||
) : (
|
||||
<span className={'text-sm text-neutral-900'}>{row.plunk}</span>
|
||||
<span className={'text-sm font-medium text-neutral-900'}>{row.plunk}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,10 +60,10 @@ export function ComparisonTable({competitorName, rows}: ComparisonTableProps) {
|
||||
row.competitor ? (
|
||||
<Check className="h-5 w-5 text-neutral-900" strokeWidth={2} />
|
||||
) : (
|
||||
<X className="h-5 w-5 text-neutral-400" strokeWidth={2} />
|
||||
<X className="h-5 w-5 text-neutral-300" strokeWidth={2} />
|
||||
)
|
||||
) : (
|
||||
<span className={'text-sm text-neutral-900'}>{row.competitor}</span>
|
||||
<span className={'text-sm text-neutral-600'}>{row.competitor}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,6 @@ interface FAQSectionProps {
|
||||
schemaId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable FAQ section component with structured data support
|
||||
*/
|
||||
export function FAQSection({faqs, schemaId = 'faq-schema'}: FAQSectionProps) {
|
||||
return (
|
||||
<>
|
||||
@@ -37,34 +34,44 @@ export function FAQSection({faqs, schemaId = 'faq-schema'}: FAQSectionProps) {
|
||||
}}
|
||||
/>
|
||||
|
||||
<section className={'py-32'}>
|
||||
<motion.div
|
||||
initial={{opacity: 0, y: 20}}
|
||||
whileInView={{opacity: 1, y: 0}}
|
||||
viewport={{once: true}}
|
||||
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'mx-auto max-w-4xl'}
|
||||
>
|
||||
<h2 className={'mb-16 text-center text-5xl font-bold tracking-tight text-neutral-900'}>
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<section className={'border-t border-neutral-200'}>
|
||||
<div className={'mx-auto max-w-[88rem] px-6 py-20 sm:px-10'}>
|
||||
<motion.div
|
||||
initial={{opacity: 0, y: 20}}
|
||||
whileInView={{opacity: 1, y: 0}}
|
||||
viewport={{once: true}}
|
||||
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'mb-16'}
|
||||
>
|
||||
<h2
|
||||
style={{fontFamily: 'var(--font-display)'}}
|
||||
className={'text-[clamp(2rem,5vw,4rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'}
|
||||
>
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
</motion.div>
|
||||
|
||||
<div className={'space-y-8'}>
|
||||
<div className={'mx-auto max-w-3xl divide-y divide-neutral-200'}>
|
||||
{faqs.map((faq, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{opacity: 0, y: 20}}
|
||||
initial={{opacity: 0, y: 16}}
|
||||
whileInView={{opacity: 1, y: 0}}
|
||||
viewport={{once: true}}
|
||||
transition={{duration: 0.5, delay: index * 0.1, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'border-b border-neutral-200 pb-8 last:border-b-0'}
|
||||
transition={{duration: 0.5, delay: index * 0.06, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'py-8'}
|
||||
>
|
||||
<h3 className={'text-xl font-semibold text-neutral-900'}>{faq.question}</h3>
|
||||
<p className={'mt-4 leading-relaxed text-neutral-600'}>{faq.answer}</p>
|
||||
<h3
|
||||
style={{fontFamily: 'var(--font-display)'}}
|
||||
className={'text-lg font-bold tracking-[-0.02em] text-neutral-900'}
|
||||
>
|
||||
{faq.question}
|
||||
</h3>
|
||||
<p className={'mt-3 leading-relaxed text-neutral-600'}>{faq.answer}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function Footer() {
|
||||
return (
|
||||
<>
|
||||
<footer className={'border-t border-neutral-200 bg-white'}>
|
||||
<div className="mx-auto max-w-7xl px-8 py-20 xl:px-0">
|
||||
<div className="mx-auto max-w-[88rem] px-6 py-20 sm:px-10">
|
||||
<div className="grid gap-12 lg:grid-cols-12">
|
||||
{/* Logo and description */}
|
||||
<div className="space-y-6 lg:col-span-3">
|
||||
@@ -59,7 +59,7 @@ export default function Footer() {
|
||||
{/* Links */}
|
||||
<div className="grid grid-cols-2 gap-8 lg:col-span-9 lg:grid-cols-5">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Product</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Product</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/pricing'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
@@ -90,7 +90,7 @@ export default function Footer() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Features</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Features</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/features/email-editor'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
@@ -121,7 +121,7 @@ export default function Footer() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Compare</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Compare</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/vs'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
@@ -162,7 +162,7 @@ export default function Footer() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Community</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Community</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/discord'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
@@ -181,7 +181,7 @@ export default function Footer() {
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 className="mt-8 text-sm font-semibold text-neutral-900">Legal</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="mt-8 text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Legal</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/privacy'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
@@ -202,7 +202,7 @@ export default function Footer() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Guides</h3>
|
||||
<h3 style={{fontFamily: 'var(--font-mono)'}} className="text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">Guides</h3>
|
||||
<ul role="list" className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link href={'/guides/email-deliverability'} className="text-sm text-neutral-600 transition hover:text-neutral-900">
|
||||
|
||||
@@ -47,8 +47,8 @@ export default function Navbar() {
|
||||
const [featuresOpen, setFeaturesOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<header className={'sticky top-0 z-40 w-full border-b border-neutral-100 bg-white/95 backdrop-blur-sm'}>
|
||||
<div className={'relative mx-auto max-w-7xl px-8 xl:px-0'}>
|
||||
<header className={'sticky top-0 z-40 w-full border-b border-neutral-200 bg-white/95 backdrop-blur-sm'}>
|
||||
<div className={'relative mx-auto max-w-[88rem] px-6 sm:px-10'}>
|
||||
<div className={'py-5'}>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-12">
|
||||
@@ -83,14 +83,14 @@ export default function Navbar() {
|
||||
onMouseEnter={() => setFeaturesOpen(true)}
|
||||
onMouseLeave={() => setFeaturesOpen(false)}
|
||||
className={
|
||||
'absolute left-0 top-full z-50 mt-2 w-80 rounded-lg border border-neutral-200 bg-white p-2 shadow-lg'
|
||||
'absolute left-0 top-full z-50 mt-2 w-80 rounded-[16px] border border-neutral-200 bg-white p-2 shadow-lg'
|
||||
}
|
||||
>
|
||||
{featuresMenu.map(feature => (
|
||||
<Link
|
||||
key={feature.href}
|
||||
href={feature.href}
|
||||
className={'flex items-start gap-3 rounded-lg p-3 transition hover:bg-neutral-50'}
|
||||
className={'flex items-start gap-3 rounded-[10px] p-3 transition hover:bg-neutral-50'}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
@@ -166,7 +166,7 @@ export default function Navbar() {
|
||||
whileTap={{scale: 0.98}}
|
||||
href={`${DASHBOARD_URI}/auth/signup`}
|
||||
className={
|
||||
'rounded-lg bg-neutral-900 px-6 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-neutral-800'
|
||||
'rounded-full bg-neutral-900 px-6 py-2.5 text-sm font-semibold text-white transition hover:bg-neutral-800'
|
||||
}
|
||||
>
|
||||
Get started
|
||||
@@ -226,7 +226,7 @@ export default function Navbar() {
|
||||
className="space-y-1 p-4"
|
||||
>
|
||||
<div className="mb-2">
|
||||
<div className="px-4 py-2 text-xs font-semibold uppercase tracking-wider text-neutral-500">
|
||||
<div style={{fontFamily: 'var(--font-mono)'}} className="px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.18em] text-neutral-500">
|
||||
Features
|
||||
</div>
|
||||
{featuresMenu.map(feature => (
|
||||
@@ -293,7 +293,7 @@ export default function Navbar() {
|
||||
</a>
|
||||
<a
|
||||
href={`${DASHBOARD_URI}/auth/signup`}
|
||||
className="mt-2 block rounded-lg bg-neutral-900 px-4 py-3 text-center text-sm font-semibold text-white transition hover:bg-neutral-800"
|
||||
className="mt-2 block rounded-full bg-neutral-900 px-4 py-3 text-center text-sm font-semibold text-white transition hover:bg-neutral-800"
|
||||
>
|
||||
Get started
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import {motion} from 'framer-motion';
|
||||
import React from 'react';
|
||||
|
||||
export function SectionHeader({
|
||||
number,
|
||||
label,
|
||||
title,
|
||||
titleAccent,
|
||||
subtitle,
|
||||
}: {
|
||||
number: string;
|
||||
label: string;
|
||||
title: string;
|
||||
titleAccent?: string;
|
||||
subtitle?: string;
|
||||
}) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{opacity: 0, y: 16}}
|
||||
whileInView={{opacity: 1, y: 0}}
|
||||
viewport={{once: true, margin: '-10%'}}
|
||||
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
|
||||
className={'grid gap-8 lg:grid-cols-12 lg:gap-16'}
|
||||
>
|
||||
<div
|
||||
style={{fontFamily: 'var(--font-mono)'}}
|
||||
className={
|
||||
'flex items-center gap-4 border-t border-neutral-900 pt-4 text-[11px] uppercase tracking-[0.2em] text-neutral-700 lg:col-span-3 lg:self-start'
|
||||
}
|
||||
>
|
||||
<span className={'font-medium text-neutral-900'}>§ {number}</span>
|
||||
<span className={'text-neutral-500'}>{label}</span>
|
||||
</div>
|
||||
<div className={'lg:col-span-9'}>
|
||||
<h2
|
||||
style={{fontFamily: 'var(--font-display)'}}
|
||||
className={
|
||||
'text-[clamp(2.25rem,5.5vw,4.5rem)] font-extrabold leading-[0.95] tracking-[-0.03em] text-neutral-900'
|
||||
}
|
||||
>
|
||||
{title}
|
||||
{titleAccent && <> {titleAccent}</>}
|
||||
</h2>
|
||||
{subtitle && <p className={'mt-6 max-w-2xl text-lg leading-relaxed text-neutral-600'}>{subtitle}</p>}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export function GuideLayout({
|
||||
|
||||
<Navbar />
|
||||
|
||||
<main className={'mx-auto max-w-7xl px-4 sm:px-8 w-full overflow-x-hidden'}>
|
||||
<main className={'mx-auto max-w-[88rem] px-4 sm:px-8 w-full overflow-x-hidden'}>
|
||||
<div className={'flex flex-col lg:flex-row gap-8 lg:gap-12 py-8 sm:py-16 w-full'}>
|
||||
{/* Main Content */}
|
||||
<article className={'flex-1 max-w-full lg:max-w-4xl w-full'}>
|
||||
|
||||
@@ -3,3 +3,4 @@ export * from './Footer';
|
||||
export * from './ComparisonTable';
|
||||
export * from './FAQSection';
|
||||
export * from './CodeBlock';
|
||||
export * from './SectionHeader';
|
||||
|
||||
Reference in New Issue
Block a user