SEO
This commit is contained in:
@@ -9,60 +9,60 @@ const faqs = [
|
||||
question: {
|
||||
en: 'How does GreenLens identify a plant?',
|
||||
de: 'Wie erkennt GreenLens eine Pflanze?',
|
||||
es: 'Como identifica GreenLens una planta?'
|
||||
es: '¿Cómo identifica GreenLens una planta?'
|
||||
},
|
||||
answer: {
|
||||
en: 'GreenLens analyzes the plant photo and combines that with app-side care guidance so you can move from scan to next steps faster.',
|
||||
de: 'GreenLens analysiert das Pflanzenfoto und verbindet das Ergebnis mit Pflegehinweisen in der App, damit du schneller zu klaren nächsten Schritten kommst.',
|
||||
es: 'GreenLens analiza la foto de la planta y combina el resultado con indicaciones de cuidado dentro de la app para que avances mas rapido.'
|
||||
es: 'GreenLens analiza la foto de la planta y combina el resultado con indicaciones de cuidado dentro de la app para que avances más rápido.'
|
||||
}
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'Is GreenLens free to use?',
|
||||
de: 'Ist GreenLens kostenlos?',
|
||||
es: 'Es GreenLens gratuito?'
|
||||
es: '¿Es GreenLens gratuito?'
|
||||
},
|
||||
answer: {
|
||||
en: 'GreenLens includes free functionality plus paid options such as subscriptions and credit top-ups for advanced AI features.',
|
||||
de: 'GreenLens bietet kostenlose Funktionen und zusätzlich kostenpflichtige Optionen wie Abos und Credit-Top-ups für erweiterte KI-Funktionen.',
|
||||
es: 'GreenLens incluye funciones gratuitas y tambien opciones de pago como suscripciones y creditos para funciones de IA mas umfangreiche.'
|
||||
es: 'GreenLens incluye funciones gratuitas y también opciones de pago como suscripciones y créditos para funciones de IA más amplias.'
|
||||
}
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'Can I use GreenLens offline?',
|
||||
de: 'Kann ich GreenLens offline nutzen?',
|
||||
es: 'Puedo usar GreenLens sin conexion?'
|
||||
es: '¿Puedo usar GreenLens sin conexión?'
|
||||
},
|
||||
answer: {
|
||||
en: 'Plant identification and health checks require an internet connection. Your saved collection, care notes, and watering reminders are available offline.',
|
||||
de: 'Pflanzenidentifikation und Gesundheitscheck benötigen eine Internetverbindung. Deine gespeicherte Sammlung, Pflegenotizen und Gieß-Erinnerungen sind offline verfügbar.',
|
||||
es: 'La identificacion de plantas y el control de salud requieren conexion a internet. Tu coleccion guardada, notas de cuidado y recordatorios de riego estan disponibles sin conexion.'
|
||||
es: 'La identificación de plantas y el control de salud requieren conexión a internet. Tu colección guardada, notas de cuidado y recordatorios de riego están disponibles sin conexión.'
|
||||
}
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'What kind of plants can I use GreenLens for?',
|
||||
de: 'Für welche Pflanzen kann ich GreenLens nutzen?',
|
||||
es: 'Para que tipo de plantas puedo usar GreenLens?'
|
||||
es: '¿Para qué tipo de plantas puedo usar GreenLens?'
|
||||
},
|
||||
answer: {
|
||||
en: 'GreenLens covers 450+ plant species including houseplants, garden plants, and succulents. It is built for everyday plant owners who want identification and care guidance in one place.',
|
||||
de: 'GreenLens umfasst über 450 Pflanzenarten, darunter Zimmerpflanzen, Gartenpflanzen und Sukkulenten. Die App richtet sich an Pflanzenbesitzer, die Identifikation und Pflege an einem Ort wollen.',
|
||||
es: 'GreenLens cubre mas de 450 especies de plantas, incluyendo plantas de interior, de jardin y suculentas. Esta pensada para quienes quieren identificacion y cuidado en un solo lugar.'
|
||||
es: 'GreenLens cubre más de 450 especies de plantas, incluyendo plantas de interior, de jardín y suculentas. Está pensada para quienes quieren identificación y cuidado en un solo lugar.'
|
||||
}
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'How do I start my plant collection?',
|
||||
de: 'Wie starte ich meine Pflanzensammlung?',
|
||||
es: 'Como empiezo mi coleccion de plantas?'
|
||||
es: '¿Cómo empiezo mi colección de plantas?'
|
||||
},
|
||||
answer: {
|
||||
en: 'Start with a scan, review the result, and save the plant to your collection to keep notes, reminders, and follow-up care in one place.',
|
||||
de: 'Starte mit einem Scan, prüfe das Ergebnis und speichere die Pflanze in deiner Sammlung, damit Notizen, Erinnerungen und Pflege an einem Ort bleiben.',
|
||||
es: 'Empieza con un escaneo, revisa el resultado y guarda la planta en tu coleccion para mantener notas, recordatorios y cuidado en un solo lugar.'
|
||||
es: 'Empieza con un escaneo, revisa el resultado y guarda la planta en tu colección para mantener notas, recordatorios y cuidado en un solo lugar.'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -25,24 +25,24 @@ const PILL_KEYS = [
|
||||
const PILL_TEXT = {
|
||||
de: [
|
||||
{ title: 'Smarte Erinnerungen', desc: 'Vergiss nie mehr das Gießen – personalisiert für jede Pflanze.' },
|
||||
{ title: 'Diagnose & Hilfe', desc: 'KI erkennt Krankheiten und Schädlinge sofort.' },
|
||||
{ title: 'Gesundheitscheck & Hilfe', desc: 'KI ordnet sichtbare Symptome ein und zeigt mögliche nächste Schritte.' },
|
||||
{ title: 'Standort-Tipps', desc: 'Pflegehinweise basierend auf deinem Klima und Licht.' },
|
||||
],
|
||||
en: [
|
||||
{ title: 'Smart Reminders', desc: 'Never forget watering again – personalized for every plant.' },
|
||||
{ title: 'Diagnosis & Help', desc: 'AI detects diseases and pests instantly.' },
|
||||
{ title: 'Health Check & Help', desc: 'AI assesses visible symptoms and suggests possible next steps.' },
|
||||
{ title: 'Location Tips', desc: 'Care advice based on your climate and light conditions.' },
|
||||
],
|
||||
es: [
|
||||
{ title: 'Recordatorios inteligentes', desc: 'Nunca olvides regar – personalizado para cada planta.' },
|
||||
{ title: 'Diagnóstico y ayuda', desc: 'La IA detecta enfermedades y plagas al instante.' },
|
||||
{ title: 'Chequeo de salud y ayuda', desc: 'La IA evalúa síntomas visibles y propone posibles pasos siguientes.' },
|
||||
{ title: 'Consejos por ubicación', desc: 'Consejos basados en tu clima y condiciones de luz.' },
|
||||
],
|
||||
}
|
||||
|
||||
const CARD_TEXT = {
|
||||
de: {
|
||||
chip1: 'KI Scan', h3a: 'Scan it.', pa: 'Richte die Kamera auf jede Pflanze – GreenLens erkennt sie in Sekundenbruchteilen und liefert alle Infos.',
|
||||
chip1: 'KI Scan', h3a: 'Scan it.', pa: 'Richte die Kamera auf eine Pflanze – GreenLens analysiert das Foto und liefert einen Artvorschlag mit Pflegehinweisen.',
|
||||
chip2: 'Tracking', h3b: 'Track it.', pb: 'Gießplan, Lichtbedarf und Wachstum – alles in einer Timeline.',
|
||||
chip3: 'Sammlung', h3c: 'Grow it.', pc: 'Baue deine digitale Pflanzenbibliothek auf – mit Fotos und Notizen.',
|
||||
altA: 'Person scannt eine Pflanze mit der GreenLens App',
|
||||
@@ -50,7 +50,7 @@ const CARD_TEXT = {
|
||||
altC: 'Pflanzensammlung im Urban Jungle Stil',
|
||||
},
|
||||
en: {
|
||||
chip1: 'AI Scan', h3a: 'Scan it.', pa: 'Point your camera at any plant – GreenLens identifies it in milliseconds and delivers all the info.',
|
||||
chip1: 'AI Scan', h3a: 'Scan it.', pa: 'Point your camera at a plant – GreenLens analyzes the photo and returns a suggested match with care guidance.',
|
||||
chip2: 'Tracking', h3b: 'Track it.', pb: 'Watering schedule, light needs and growth – all in one timeline.',
|
||||
chip3: 'Collection', h3c: 'Grow it.', pc: 'Build your digital plant library – with photos and notes.',
|
||||
altA: 'Person scanning a plant with the GreenLens app',
|
||||
@@ -58,7 +58,7 @@ const CARD_TEXT = {
|
||||
altC: 'Plant collection in urban jungle style',
|
||||
},
|
||||
es: {
|
||||
chip1: 'Escaneo IA', h3a: 'Escanéala.', pa: 'Apunta la cámara a cualquier planta – GreenLens la identifica en milisegundos y entrega toda la información.',
|
||||
chip1: 'Escaneo IA', h3a: 'Escanéala.', pa: 'Apunta la cámara a una planta – GreenLens analiza la foto y devuelve una coincidencia sugerida con consejos de cuidado.',
|
||||
chip2: 'Seguimiento', h3b: 'Monitoréala.', pb: 'Plan de riego, necesidades de luz y crecimiento – todo en una línea de tiempo.',
|
||||
chip3: 'Colección', h3c: 'Hazla crecer.', pc: 'Construye tu biblioteca digital de plantas – con fotos y notas.',
|
||||
altA: 'Persona escaneando una planta con la app GreenLens',
|
||||
|
||||
@@ -67,7 +67,7 @@ const cards: Record<Lang, GuideCard[]> = {
|
||||
href: '/plant-identifier-app',
|
||||
tag: 'Identify',
|
||||
title: 'Plant Identifier App',
|
||||
description: 'Scan any plant, get the species instantly, and move straight to care guidance.',
|
||||
description: 'Scan a plant, review the suggested species, and move straight to care guidance.',
|
||||
},
|
||||
{
|
||||
href: '/identify-plant-photo',
|
||||
@@ -79,7 +79,7 @@ const cards: Record<Lang, GuideCard[]> = {
|
||||
href: '/plant-scanner',
|
||||
tag: 'Scanner',
|
||||
title: 'Plant Scanner',
|
||||
description: 'Point your camera at any plant and get name, care plan, and health check.',
|
||||
description: 'Point your camera at a plant, review the suggested match, and continue with care guidance.',
|
||||
},
|
||||
{
|
||||
href: '/plant-disease-identifier',
|
||||
|
||||
@@ -6,19 +6,19 @@ import { useLang } from '@/context/LangContext'
|
||||
const STEPS = {
|
||||
de: [
|
||||
{ num: '01', title: 'Pflanze fotografieren', desc: 'Öffne die App, richte die Kamera auf deine Pflanze und tippe auf Scan. Das war\'s schon.' },
|
||||
{ num: '02', title: 'KI identifiziert sofort', desc: 'In unter einer Sekunde erhältst du den genauen Namen, die Art und alle wichtigen Eckdaten.' },
|
||||
{ num: '02', title: 'KI analysiert das Foto', desc: 'Du erhältst zügig einen Artvorschlag und die wichtigsten Eckdaten zur Pflanze.' },
|
||||
{ num: '03', title: 'Pflegeplan erhalten', desc: 'GreenLens erstellt automatisch einen personalisierten Pflegeplan passend zu deiner Pflanze und deinem Standort.' },
|
||||
{ num: '04', title: 'Wachstum verfolgen', desc: 'Dokumentiere Fotos, tracke das Gießen und lass dich an wichtige Pflegetermine erinnern.' },
|
||||
],
|
||||
en: [
|
||||
{ num: '01', title: 'Photograph your plant', desc: 'Open the app, point the camera at your plant and tap Scan. That\'s it.' },
|
||||
{ num: '02', title: 'AI identifies instantly', desc: 'In under a second you get the exact name, species and all key details.' },
|
||||
{ num: '02', title: 'AI analyzes the photo', desc: 'You quickly receive a suggested match and the key details about the plant.' },
|
||||
{ num: '03', title: 'Receive care plan', desc: 'GreenLens automatically creates a personalized care plan for your plant and location.' },
|
||||
{ num: '04', title: 'Track growth', desc: 'Document photos, track watering and get reminded of important care dates.' },
|
||||
],
|
||||
es: [
|
||||
{ num: '01', title: 'Fotografía tu planta', desc: 'Abre la app, apunta la cámara a tu planta y toca Escanear. Eso es todo.' },
|
||||
{ num: '02', title: 'La IA identifica al instante', desc: 'En menos de un segundo obtienes el nombre exacto, la especie y todos los datos clave.' },
|
||||
{ num: '02', title: 'La IA analiza la foto', desc: 'Recibes rápidamente una coincidencia sugerida y los datos principales de la planta.' },
|
||||
{ num: '03', title: 'Recibe el plan de cuidado', desc: 'GreenLens crea automáticamente un plan de cuidado personalizado para tu planta y ubicación.' },
|
||||
{ num: '04', title: 'Seguimiento del crecimiento', desc: 'Documenta fotos, registra el riego y recibe recordatorios de citas de cuidado importantes.' },
|
||||
],
|
||||
|
||||
@@ -10,8 +10,9 @@ export default function Navbar() {
|
||||
const [scrolled, setScrolled] = useState(false)
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const pathname = usePathname()
|
||||
const { t } = useLang()
|
||||
const homeHref = (hash: string) => (pathname === '/' ? hash : `/${hash}`)
|
||||
const { lang, t } = useLang()
|
||||
const localeHome = lang === 'de' ? '/' : `/${lang}`
|
||||
const homeHref = (hash: string) => (pathname === localeHome ? hash : `${localeHome}${hash}`)
|
||||
|
||||
useEffect(() => {
|
||||
const onScroll = () => setScrolled(window.scrollY > 40)
|
||||
@@ -22,7 +23,7 @@ export default function Navbar() {
|
||||
return (
|
||||
<nav className={`navbar${scrolled ? ' scrolled' : ''}`} id="navbar" role="navigation" aria-label="Main navigation">
|
||||
<div className="container">
|
||||
<Link href="/" className="nav-logo" aria-label="GreenLens Home">
|
||||
<Link href={localeHome} className="nav-logo" aria-label="GreenLens Home">
|
||||
GREENLENS
|
||||
</Link>
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ interface SeoCategoryPageProps {
|
||||
export default function SeoCategoryPage({ profile }: SeoCategoryPageProps) {
|
||||
const locale = profile.locale ?? 'en'
|
||||
const copy = seoTemplateCopy[locale]
|
||||
const templateIntent = profile.templateIntent ?? 'identification'
|
||||
const usesPhotoAnalysis = templateIntent === 'identification' || templateIntent === 'diagnosis'
|
||||
const showsCareInsights = templateIntent === 'care' || templateIntent === 'watering'
|
||||
|
||||
const faqSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
@@ -88,7 +91,7 @@ export default function SeoCategoryPage({ profile }: SeoCategoryPageProps) {
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
|
||||
/>
|
||||
|
||||
<SeoNavbar locale={locale} />
|
||||
<SeoNavbar locale={locale} methodologyHref={usesPhotoAnalysis ? '#methodology' : '#comparison'} />
|
||||
|
||||
<main className="pt-[72px] relative overflow-hidden bg-[#fdfbf6]">
|
||||
{/* Dekorative Farb-Blobs */}
|
||||
@@ -98,17 +101,21 @@ export default function SeoCategoryPage({ profile }: SeoCategoryPageProps) {
|
||||
<div className="absolute top-[40%] left-[15%] w-[40vw] h-[40vw] max-w-[500px] max-h-[500px] bg-[#e5f0cb] blur-[100px] rounded-full mix-blend-multiply opacity-70"></div>
|
||||
</div>
|
||||
|
||||
<SeoHero profile={profile} copy={copy} />
|
||||
<SeoAdvantage profile={profile} copy={copy} />
|
||||
<SeoMethodology copy={copy} />
|
||||
<SeoComparison profile={profile} copy={copy} />
|
||||
<SeoHero
|
||||
profile={profile}
|
||||
copy={copy}
|
||||
secondaryHref={usesPhotoAnalysis ? '#methodology' : '#comparison'}
|
||||
/>
|
||||
<SeoAdvantage profile={profile} copy={copy} showInsights={showsCareInsights} />
|
||||
<SeoContentSections profile={profile} />
|
||||
{usesPhotoAnalysis && <SeoMethodology copy={copy} intent={templateIntent} />}
|
||||
<SeoComparison profile={profile} copy={copy} intent={templateIntent} />
|
||||
<SeoBestFit profile={profile} copy={copy} />
|
||||
<SeoFaq profile={profile} copy={copy} />
|
||||
<SeoRelated profile={profile} copy={copy} />
|
||||
</main>
|
||||
|
||||
<SeoFooter locale={locale} />
|
||||
<SeoFooter locale={locale} showMethodology={usesPhotoAnalysis} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
export default function Ticker() {
|
||||
const items = [
|
||||
'Scan it',
|
||||
'Track it',
|
||||
'Live Design',
|
||||
'Urban Jungle',
|
||||
'Botanical KI',
|
||||
'Pflege-Tipps',
|
||||
'Scan it',
|
||||
'Track it',
|
||||
'Live Design',
|
||||
'Urban Jungle',
|
||||
'Botanical KI',
|
||||
'Pflege-Tipps',
|
||||
]
|
||||
'use client'
|
||||
|
||||
import { useLang } from '@/context/LangContext'
|
||||
|
||||
const ITEMS = {
|
||||
de: [
|
||||
'Scan it',
|
||||
'Track it',
|
||||
'Live Design',
|
||||
'Urban Jungle',
|
||||
'Botanical KI',
|
||||
'Pflege-Tipps',
|
||||
],
|
||||
en: ['Scan it', 'Track it', 'Live Design', 'Urban Jungle', 'Botanical AI', 'Care Tips'],
|
||||
es: ['Escanéala', 'Regístrala', 'Diseño vivo', 'Jardín urbano', 'IA botánica', 'Consejos de cuidado'],
|
||||
}
|
||||
|
||||
export default function Ticker() {
|
||||
const { lang } = useLang()
|
||||
const items = ITEMS[lang]
|
||||
|
||||
return (
|
||||
<div className="ticker-wrap" aria-hidden="true">
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import Link from 'next/link'
|
||||
import type { Lang } from '@/lib/i18n'
|
||||
import { englishSeoPageSlugs, germanSeoPageSlugs, getSeoPageBySlug } from '@/lib/seoPages'
|
||||
import { getSeoPageBySlug } from '@/lib/seoPages'
|
||||
import { spanishSeoPageProfiles } from '@/lib/spanishSeoPages'
|
||||
import { seoTemplateCopy } from '@/lib/seoTemplateCopy'
|
||||
import { siteConfig, hasIosStoreUrl, hasAndroidStoreUrl } from '@/lib/site'
|
||||
|
||||
interface SeoFooterProps {
|
||||
locale: Lang
|
||||
showMethodology?: boolean
|
||||
}
|
||||
|
||||
function slugLinks(slugs: readonly string[]) {
|
||||
@@ -16,21 +17,50 @@ function slugLinks(slugs: readonly string[]) {
|
||||
.map((profile) => ({ href: profile.canonical, label: profile.h1 }))
|
||||
}
|
||||
|
||||
export default function SeoFooter({ locale }: SeoFooterProps) {
|
||||
const copy = seoTemplateCopy[locale].footer
|
||||
const primarySlugs: Record<Exclude<Lang, 'es'>, readonly string[]> = {
|
||||
de: [
|
||||
'pflanzen-erkennen-app',
|
||||
'pflanzen-bestimmen',
|
||||
'pflanzen-krankheiten-erkennen',
|
||||
'pflanzen-pflege-app',
|
||||
'giess-erinnerung-app',
|
||||
'pflanzen-erkennen-kostenlos',
|
||||
],
|
||||
en: [
|
||||
'plant-identifier-app',
|
||||
'identify-plant-photo',
|
||||
'plant-disease-identifier',
|
||||
'plant-care-app',
|
||||
'plant-health-app',
|
||||
'best-plant-identification-app',
|
||||
],
|
||||
}
|
||||
|
||||
const useCaseLinks = [
|
||||
...slugLinks(englishSeoPageSlugs),
|
||||
{ href: '/vs/picturethis', label: 'vs PictureThis' },
|
||||
{ href: '/vs/plantum', label: 'vs Plantum' },
|
||||
{ href: '/vs/inaturalist', label: 'vs iNaturalist' },
|
||||
{ href: '/vs/google-lens', label: 'vs Google Lens' },
|
||||
]
|
||||
const germanLinks = slugLinks(germanSeoPageSlugs)
|
||||
const spanishLinks = Object.values(spanishSeoPageProfiles).map((profile) => ({
|
||||
href: profile.canonical,
|
||||
label: profile.h1,
|
||||
}))
|
||||
const languageHubs = [
|
||||
{ href: '/', label: 'Deutsch' },
|
||||
{ href: '/en', label: 'English' },
|
||||
{ href: '/es', label: 'Español' },
|
||||
]
|
||||
|
||||
const languageTitles: Record<Lang, string> = {
|
||||
de: 'Sprachen',
|
||||
en: 'Languages',
|
||||
es: 'Idiomas',
|
||||
}
|
||||
|
||||
export default function SeoFooter({ locale, showMethodology = true }: SeoFooterProps) {
|
||||
const copy = seoTemplateCopy[locale].footer
|
||||
const primaryLinks = locale === 'es'
|
||||
? Object.values(spanishSeoPageProfiles).map((profile) => ({
|
||||
href: profile.canonical,
|
||||
label: profile.h1,
|
||||
}))
|
||||
: slugLinks(primarySlugs[locale])
|
||||
const primaryTitle = locale === 'de'
|
||||
? copy.germanTitle
|
||||
: locale === 'es'
|
||||
? copy.spanishTitle
|
||||
: copy.useCasesTitle
|
||||
|
||||
return (
|
||||
<footer className="bg-ink-deep text-white pt-24 pb-8 font-body overflow-hidden" id="download">
|
||||
@@ -95,7 +125,7 @@ export default function SeoFooter({ locale }: SeoFooterProps) {
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{copy.productTitle}</h4>
|
||||
<ul className="space-y-4 text-xs text-white/80">
|
||||
<li><a href="#advantage" className="hover:text-white">{seoTemplateCopy[locale].nav.features}</a></li>
|
||||
<li><a href="#methodology" className="hover:text-white">{seoTemplateCopy[locale].nav.tech}</a></li>
|
||||
{showMethodology && <li><a href="#methodology" className="hover:text-white">{seoTemplateCopy[locale].nav.tech}</a></li>}
|
||||
<li><a href="#download" className="hover:text-white">{seoTemplateCopy[locale].nav.download}</a></li>
|
||||
<li><Link href="/support" className="hover:text-white">{copy.supportLabel}</Link></li>
|
||||
</ul>
|
||||
@@ -103,7 +133,7 @@ export default function SeoFooter({ locale }: SeoFooterProps) {
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{copy.companyTitle}</h4>
|
||||
<ul className="space-y-4 text-xs text-white/80">
|
||||
<li><a href="#methodology" className="hover:text-white">{seoTemplateCopy[locale].nav.how}</a></li>
|
||||
{showMethodology && <li><a href="#methodology" className="hover:text-white">{seoTemplateCopy[locale].nav.how}</a></li>}
|
||||
<li><a href="#faq" className="hover:text-white">FAQ</a></li>
|
||||
<li><Link href="/support" className="hover:text-white">{copy.supportLabel}</Link></li>
|
||||
</ul>
|
||||
@@ -119,11 +149,11 @@ export default function SeoFooter({ locale }: SeoFooterProps) {
|
||||
</div>
|
||||
|
||||
{/* SEO-Link-Spalten (interne Verlinkung) */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-12 mb-24">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 mb-24">
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{copy.useCasesTitle}</h4>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{primaryTitle}</h4>
|
||||
<ul className="space-y-3 text-xs text-white/70">
|
||||
{useCaseLinks.map((link) => (
|
||||
{primaryLinks.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link href={link.href} className="hover:text-white">{link.label}</Link>
|
||||
</li>
|
||||
@@ -131,19 +161,9 @@ export default function SeoFooter({ locale }: SeoFooterProps) {
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{copy.germanTitle}</h4>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{languageTitles[locale]}</h4>
|
||||
<ul className="space-y-3 text-xs text-white/70">
|
||||
{germanLinks.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link href={link.href} className="hover:text-white">{link.label}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-[10px] font-bold tracking-widest text-primary-fixed mb-6 uppercase">{copy.spanishTitle}</h4>
|
||||
<ul className="space-y-3 text-xs text-white/70">
|
||||
{spanishLinks.map((link) => (
|
||||
{languageHubs.map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link href={link.href} className="hover:text-white">{link.label}</Link>
|
||||
</li>
|
||||
|
||||
@@ -10,17 +10,18 @@ import { seoTemplateCopy } from '@/lib/seoTemplateCopy'
|
||||
|
||||
interface SeoNavbarProps {
|
||||
locale: Lang
|
||||
methodologyHref?: '#methodology' | '#comparison'
|
||||
}
|
||||
|
||||
export default function SeoNavbar({ locale }: SeoNavbarProps) {
|
||||
export default function SeoNavbar({ locale, methodologyHref = '#methodology' }: SeoNavbarProps) {
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const copy = seoTemplateCopy[locale]
|
||||
|
||||
const links = [
|
||||
{ href: '#advantage', label: copy.nav.features },
|
||||
{ href: '#methodology', label: copy.nav.tech },
|
||||
{ href: methodologyHref, label: copy.nav.tech },
|
||||
{ href: '#faq', label: copy.nav.faq },
|
||||
{ href: '#methodology', label: copy.nav.how },
|
||||
{ href: methodologyHref, label: copy.nav.how },
|
||||
{ href: '/support', label: copy.nav.support },
|
||||
]
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@ interface SectionProps {
|
||||
copy: SeoTemplateCopy
|
||||
}
|
||||
|
||||
export function SeoHero({ profile, copy }: SectionProps) {
|
||||
export function SeoHero({
|
||||
profile,
|
||||
copy,
|
||||
secondaryHref = '#methodology',
|
||||
}: SectionProps & { secondaryHref?: string }) {
|
||||
return (
|
||||
<section className="max-w-[1200px] mx-auto px-6 py-16 grid grid-cols-1 lg:grid-cols-12 gap-12 items-start mt-8">
|
||||
<div className="lg:col-span-6 z-10 flex flex-col justify-center pt-8">
|
||||
@@ -29,7 +33,7 @@ export function SeoHero({ profile, copy }: SectionProps) {
|
||||
</a>
|
||||
<a
|
||||
className="inline-flex justify-center items-center px-8 py-3 bg-transparent border-2 border-ink text-ink rounded-full font-bold hover:bg-ink hover:text-white transition-colors duration-300"
|
||||
href="#methodology"
|
||||
href={secondaryHref}
|
||||
>
|
||||
{copy.hero.ctaSecondary}
|
||||
</a>
|
||||
@@ -62,20 +66,30 @@ export function SeoHero({ profile, copy }: SectionProps) {
|
||||
)
|
||||
}
|
||||
|
||||
export function SeoAdvantage({ profile, copy }: SectionProps) {
|
||||
export function SeoAdvantage({
|
||||
profile,
|
||||
copy,
|
||||
showInsights = false,
|
||||
}: SectionProps & { showInsights?: boolean }) {
|
||||
const reviewedAt = {
|
||||
de: 'Juli 2026',
|
||||
en: 'July 2026',
|
||||
es: 'Julio 2026',
|
||||
}[profile.locale ?? 'en']
|
||||
|
||||
return (
|
||||
<section className="max-w-[1200px] mx-auto px-6 py-16 grid grid-cols-1 lg:grid-cols-3 gap-12 border-t border-surface-container-high" id="advantage">
|
||||
<div className="lg:col-span-2">
|
||||
<section className={`max-w-[1200px] mx-auto px-6 py-16 grid grid-cols-1 ${showInsights ? 'lg:grid-cols-3' : ''} gap-12 border-t border-surface-container-high`} id="advantage">
|
||||
<div className={showInsights ? 'lg:col-span-2' : ''}>
|
||||
<div className="mb-8">
|
||||
<span className="text-xs font-semibold tracking-[0.1em] uppercase text-primary">{copy.advantage.eyebrow}</span>
|
||||
</div>
|
||||
<h2 className="font-display font-semibold text-[32px] leading-[1.3] text-primary mb-6">{copy.advantage.heading}</h2>
|
||||
<p className="font-body text-lg text-on-surface-variant mb-6">{profile.definitionBlock}</p>
|
||||
<div className="text-xs font-semibold tracking-[0.1em] uppercase text-on-surface-variant">
|
||||
{copy.advantage.updated}: {profile.lastUpdated}
|
||||
{copy.advantage.updated}: {reviewedAt}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-surface-container rounded-xl p-8 seo-card">
|
||||
{showInsights && <div className="bg-surface-container rounded-xl p-8 seo-card">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<SeoIcon name="psychology" className="w-8 h-8 text-primary" />
|
||||
<h3 className="font-display font-semibold text-2xl text-primary">{copy.didYouKnow.title}</h3>
|
||||
@@ -88,22 +102,30 @@ export function SeoAdvantage({ profile, copy }: SectionProps) {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export function SeoMethodology({ copy }: { copy: SeoTemplateCopy }) {
|
||||
export function SeoMethodology({
|
||||
copy,
|
||||
intent = 'identification',
|
||||
}: {
|
||||
copy: SeoTemplateCopy
|
||||
intent?: 'identification' | 'diagnosis'
|
||||
}) {
|
||||
const methodology = intent === 'diagnosis' ? copy.diagnosisMethodology : copy.methodology
|
||||
|
||||
return (
|
||||
<section className="bg-surface-container-low py-16 md:py-[120px]" id="methodology">
|
||||
<div className="max-w-[1200px] mx-auto px-6">
|
||||
<div className="text-center mb-16">
|
||||
<span className="text-xs font-semibold tracking-[0.1em] uppercase text-primary block mb-4">{copy.methodology.eyebrow}</span>
|
||||
<h2 className="font-display font-semibold text-[32px] md:text-[40px] leading-[1.2] text-primary">{copy.methodology.title}</h2>
|
||||
<p className="font-body text-on-surface-variant max-w-2xl mx-auto mt-4">{copy.methodology.lead}</p>
|
||||
<span className="text-xs font-semibold tracking-[0.1em] uppercase text-primary block mb-4">{methodology.eyebrow}</span>
|
||||
<h2 className="font-display font-semibold text-[32px] md:text-[40px] leading-[1.2] text-primary">{methodology.title}</h2>
|
||||
<p className="font-body text-on-surface-variant max-w-2xl mx-auto mt-4">{methodology.lead}</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{copy.methodology.steps.map((step, index) => (
|
||||
{methodology.steps.map((step, index) => (
|
||||
<div key={step.title} className="bg-surface p-8 rounded-xl shadow-sm border border-surface-container-high seo-card">
|
||||
<div className="w-12 h-12 bg-primary-container text-on-primary-container rounded-full flex items-center justify-center font-display font-semibold text-xl mb-6">
|
||||
{index + 1}
|
||||
@@ -120,7 +142,11 @@ export function SeoMethodology({ copy }: { copy: SeoTemplateCopy }) {
|
||||
|
||||
const comparisonIcons: SeoIconName[] = ['check_circle', 'calendar', 'healing', 'sun']
|
||||
|
||||
export function SeoComparison({ profile, copy }: SectionProps) {
|
||||
export function SeoComparison({
|
||||
profile,
|
||||
copy,
|
||||
intent = 'identification',
|
||||
}: SectionProps & { intent?: 'identification' | 'diagnosis' | 'care' | 'watering' }) {
|
||||
const tipLink = profile.relatedLinks[0]
|
||||
|
||||
return (
|
||||
@@ -130,7 +156,7 @@ export function SeoComparison({ profile, copy }: SectionProps) {
|
||||
<div className="lg:sticky lg:top-32">
|
||||
<span className="text-xs font-semibold tracking-[0.1em] uppercase text-primary block mb-4">{copy.comparison.eyebrow}</span>
|
||||
<h2 className="font-display font-semibold text-[32px] leading-[1.3] text-primary mb-6">{profile.featureTable.title}</h2>
|
||||
<p className="font-body text-on-surface-variant mb-8">{copy.comparison.lead}</p>
|
||||
<p className="font-body text-on-surface-variant mb-8">{copy.comparison.intentLead[intent]}</p>
|
||||
{tipLink && (
|
||||
<div className="bg-primary-container/20 p-6 rounded-lg border border-primary-container/30">
|
||||
<h4 className="font-display font-semibold text-base text-primary mb-2">{copy.comparison.tipTitle}</h4>
|
||||
|
||||
Reference in New Issue
Block a user