Files
Greenlens/greenlns-landing/components/SeoCategoryPage.tsx
2026-06-08 20:33:51 +02:00

277 lines
9.5 KiB
TypeScript

import Link from 'next/link'
import Navbar from '@/components/Navbar'
import CTA from '@/components/CTA'
import Footer from '@/components/Footer'
import type { SeoPageProfile } from '@/lib/seoPages'
import { siteConfig, hasIosStoreUrl } from '@/lib/site'
interface SeoCategoryPageProps {
profile: SeoPageProfile
}
export default function SeoCategoryPage({ profile }: SeoCategoryPageProps) {
const labels = {
en: {
heroTag: 'GreenLens',
primaryCta: 'Try GreenLens',
secondaryCta: 'See full comparison',
definition: 'Definition',
updated: 'Last updated:',
tableTag: 'At a glance',
bestFit: 'Best fit',
chooseIf: 'Choose GreenLens if:',
notBestFit: 'Not the best fit',
notRightIf: 'GreenLens is not the right tool if:',
faqTag: 'FAQ',
faqTitle: 'Common questions answered directly.',
related: 'Related',
supportTag: 'Need help?',
supportTitle: 'Talk to GreenLens support',
supportCopy: 'Questions about scans, care plans, billing, or features? Use the support page.',
},
de: {
heroTag: 'GreenLens',
primaryCta: 'GreenLens testen',
secondaryCta: 'Vergleich ansehen',
definition: 'Definition',
updated: 'Aktualisiert:',
tableTag: 'Überblick',
bestFit: 'Passt gut',
chooseIf: 'Wähle GreenLens, wenn:',
notBestFit: 'Nicht ideal',
notRightIf: 'GreenLens ist nicht die richtige Wahl, wenn:',
faqTag: 'FAQ',
faqTitle: 'Häufige Fragen direkt beantwortet.',
related: 'Verwandt',
supportTag: 'Brauchst du Hilfe?',
supportTitle: 'GreenLens Support kontaktieren',
supportCopy: 'Fragen zu Scans, Pflegeplänen, Abrechnung oder Funktionen? Nutze die Support-Seite.',
},
es: {
heroTag: 'GreenLens',
primaryCta: 'Probar GreenLens',
secondaryCta: 'Ver comparación',
definition: 'Definición',
updated: 'Actualizado:',
tableTag: 'Resumen',
bestFit: 'Mejor opción',
chooseIf: 'Elige GreenLens si:',
notBestFit: 'No es ideal',
notRightIf: 'GreenLens no es la herramienta adecuada si:',
faqTag: 'FAQ',
faqTitle: 'Preguntas frecuentes respondidas directamente.',
related: 'Relacionado',
supportTag: '¿Necesitas ayuda?',
supportTitle: 'Contacta con soporte de GreenLens',
supportCopy: '¿Preguntas sobre escaneos, planes de cuidado, facturación o funciones? Usa la página de soporte.',
},
}[profile.locale ?? 'en']
const faqSchema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: profile.faqs.map((item) => ({
'@type': 'Question',
name: item.question,
acceptedAnswer: {
'@type': 'Answer',
text: item.answer,
},
})),
}
const appSchema = profile.includeAppSchema
? {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: siteConfig.name,
operatingSystem: 'iOS, Android',
applicationCategory: 'LifestyleApplication',
description: profile.directAnswer,
...(hasIosStoreUrl && { downloadUrl: siteConfig.iosAppStoreUrl }),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'EUR',
},
}
: null
const breadcrumbSchema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Home',
item: siteConfig.domain,
},
{
'@type': 'ListItem',
position: 2,
name: profile.h1,
item: `${siteConfig.domain}${profile.canonical}`,
},
],
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
/>
{appSchema && (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(appSchema) }}
/>
)}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
/>
<Navbar />
<main className="comparison-page">
{/* Hero */}
<section className="comparison-hero">
<div className="container comparison-hero-grid">
<div className="comparison-hero-copy">
<p className="tag">{labels.heroTag}</p>
<h1>{profile.h1}</h1>
<p className="comparison-lead">{profile.tagline}</p>
<p>{profile.directAnswer}</p>
<div className="comparison-actions">
<a href="#cta" className="btn-primary">{labels.primaryCta}</a>
<a href="#feature-table" className="btn-outline">{labels.secondaryCta}</a>
</div>
</div>
<aside className="comparison-hero-card">
<p className="comparison-card-label">{labels.definition}</p>
<p>{profile.definitionBlock}</p>
<p className="comparison-verified">{labels.updated} {profile.lastUpdated}</p>
</aside>
</div>
</section>
{profile.contentSections && profile.contentSections.length > 0 && (
<section className="comparison-context">
<div className="container comparison-context-grid">
{profile.contentSections.map((section) => (
<article key={section.title} className="comparison-context-card">
<p className="tag">{section.eyebrow}</p>
<h2>{section.title}</h2>
<p>{section.body}</p>
{section.bullets && (
<ul className="comparison-bullet-list comparison-bullet-list--dark">
{section.bullets.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
)}
</article>
))}
</div>
</section>
)}
{/* Feature table */}
<section className="comparison-table-section" id="feature-table">
<div className="container">
<div className="comparison-section-head">
<p className="tag">{labels.tableTag}</p>
<h2>{profile.featureTable.title}</h2>
</div>
<div className="comparison-table">
<div className="comparison-table-header">
<span>Feature</span>
<span>GreenLens</span>
<span>{profile.featureTable.alternativeLabel}</span>
</div>
{profile.featureTable.rows.map((row) => (
<article key={row.feature} className="comparison-row">
<div className="comparison-row-title">{row.feature}</div>
<div className="comparison-cell comparison-cell--greenlens">{row.greenlens}</div>
<div className="comparison-cell comparison-cell--competitor">{row.alternative}</div>
</article>
))}
</div>
</div>
</section>
{/* Fit cards */}
<section className="comparison-fit">
<div className="container comparison-fit-grid">
<article className="comparison-fit-card comparison-fit-card--greenlens">
<p className="tag">{labels.bestFit}</p>
<h2>{labels.chooseIf}</h2>
<ul className="comparison-bullet-list comparison-bullet-list--dark">
{profile.greenLensIf.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</article>
<article className="comparison-fit-card">
<p className="tag">{labels.notBestFit}</p>
<h2>{labels.notRightIf}</h2>
<ul className="comparison-bullet-list comparison-bullet-list--dark">
{profile.notBestIf.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</article>
</div>
</section>
{/* FAQ */}
<section className="comparison-faq">
<div className="container">
<div className="comparison-section-head">
<p className="tag">{labels.faqTag}</p>
<h2>{labels.faqTitle}</h2>
</div>
<div className="comparison-faq-grid">
{profile.faqs.map((item) => (
<article key={item.question} className="comparison-faq-card">
<h3>{item.question}</h3>
<p>{item.answer}</p>
</article>
))}
</div>
</div>
</section>
{/* Related links */}
{profile.relatedLinks.length > 0 && (
<section className="comparison-links">
<div className="container comparison-links-grid">
{profile.relatedLinks.map((link) => (
<Link key={link.href} href={link.href} className="comparison-link-card">
<p className="comparison-mini-label">{labels.related}</p>
<h3>{link.label}</h3>
<p>{link.description}</p>
</Link>
))}
<Link href="/support" className="comparison-link-card comparison-link-card--support">
<p className="comparison-mini-label">{labels.supportTag}</p>
<h3>{labels.supportTitle}</h3>
<p>{labels.supportCopy}</p>
</Link>
</div>
</section>
)}
<CTA />
</main>
<Footer />
</>
)
}