import React from 'react' import Image from 'next/image' import Link from 'next/link' import SeoNavbar from '@/components/seo/SeoNavbar' import SeoFooter from '@/components/seo/SeoFooter' import { BlogPost } from '@/lib/blogPosts' const SITE = 'https://greenlenspro.com' const blogUiCopy = { en: { home: 'Home', blog: 'Blog', quickAnswer: 'Quick Botanical Answer', tableOfContents: 'Table of Contents', updated: 'Updated', actionPlan: 'Action Plan', stepByStepGuide: 'Step-by-Step Action Guide', questionsAndAnswers: 'Questions & Answers', faqHeading: 'Frequently Asked Questions', relatedGuides: 'Related Guides', ctaEyebrow: 'Instant AI Health Diagnosis', ctaTitle: 'Unsure what is wrong with your plant?', ctaBody: 'Scan your plant leaf with GreenLens AI for an immediate disease check, pest identification, and custom care plan.', ctaButton: 'Start Free Scan ➔', appEyebrow: 'GreenLens Pro iOS App', appTitle: 'Identify Any Plant & Get Custom Care Plans', appBody: 'Scan your houseplants in seconds, diagnose leaf diseases, and get automatic watering reminders tailored to your space.', appButton: 'Start First Scan Free — No Account Needed', howCompiled: 'How this guide was compiled', sources: 'Sources', published: 'Published', lastUpdated: 'Last updated', writtenBy: 'Written by', }, de: { home: 'Start', blog: 'Blog', quickAnswer: 'Kurze Antwort', tableOfContents: 'Inhaltsverzeichnis', updated: 'Aktualisiert am', actionPlan: 'Handlungsplan', stepByStepGuide: 'Schritt-für-Schritt-Anleitung', questionsAndAnswers: 'Fragen & Antworten', faqHeading: 'Häufig gestellte Fragen', relatedGuides: 'Weitere Ratgeber', ctaEyebrow: 'Sofortige KI-Gesundheitsanalyse', ctaTitle: 'Unsicher, was mit deiner Pflanze los ist?', ctaBody: 'Scanne ein Blatt deiner Pflanze mit GreenLens AI für eine sofortige Diagnose, Schädlingserkennung und einen individuellen Pflegeplan.', ctaButton: 'Kostenlosen Scan starten ➔', appEyebrow: 'GreenLens Pro iOS App', appTitle: 'Jede Pflanze erkennen & individuelle Pflegepläne erhalten', appBody: 'Scanne deine Zimmerpflanzen in Sekunden, diagnostiziere Blattkrankheiten und erhalte automatische Gießerinnerungen, abgestimmt auf deinen Standort.', appButton: 'Ersten Scan gratis starten — ohne Anmeldung', howCompiled: 'Wie dieser Ratgeber entstanden ist', sources: 'Quellen', published: 'Veröffentlicht am', lastUpdated: 'Zuletzt aktualisiert am', writtenBy: 'Verfasst von', }, es: { home: 'Inicio', blog: 'Blog', quickAnswer: 'Respuesta rápida', tableOfContents: 'Índice de contenidos', updated: 'Actualizado', actionPlan: 'Plan de acción', stepByStepGuide: 'Guía paso a paso', questionsAndAnswers: 'Preguntas y respuestas', faqHeading: 'Preguntas frecuentes', relatedGuides: 'Guías relacionadas', ctaEyebrow: 'Diagnóstico instantáneo con IA', ctaTitle: '¿No sabes qué le pasa a tu planta?', ctaBody: 'Escanea una hoja de tu planta con GreenLens AI para un diagnóstico inmediato, detección de plagas y un plan de cuidado personalizado.', ctaButton: 'Iniciar escaneo gratis ➔', appEyebrow: 'GreenLens Pro para iOS', appTitle: 'Identifica cualquier planta y recibe planes de cuidado personalizados', appBody: 'Escanea tus plantas de interior en segundos, diagnostica enfermedades de las hojas y recibe recordatorios de riego automáticos adaptados a tu espacio.', appButton: 'Haz tu primer escaneo gratis — sin cuenta', howCompiled: 'Cómo se elaboró esta guía', sources: 'Fuentes', published: 'Publicado el', lastUpdated: 'Última actualización', writtenBy: 'Escrito por', }, } as const /** * JSON-LD für Blogposts. BlogPosting liefert Autor und Datum, FAQPage und HowTo * sind die beiden Formate, aus denen AI-Antwortsysteme direkt extrahieren. * Ohne diese Blöcke bleibt der Beitrag für sie unstrukturierter Fließtext. */ function buildBlogSchema(post: BlogPost) { const graph: Record[] = [ { '@type': 'BlogPosting', '@id': `${SITE}${post.canonical}#article`, headline: post.title, description: post.metaDescription, image: `${SITE}${post.heroImage}`, datePublished: post.publishedAtIso, dateModified: post.updatedAtIso || post.publishedAtIso, inLanguage: post.locale, mainEntityOfPage: { '@type': 'WebPage', '@id': `${SITE}${post.canonical}` }, author: { '@type': 'Person', name: post.author.name, jobTitle: post.author.role, }, publisher: { '@type': 'Organization', name: 'GreenLens', url: SITE, }, ...(post.sources?.length ? { citation: post.sources.map((source) => ({ '@type': 'CreativeWork', name: source.title, url: source.url })) } : {}), }, ] if (post.faqs?.length) { graph.push({ '@type': 'FAQPage', '@id': `${SITE}${post.canonical}#faq`, mainEntity: post.faqs.map((faq) => ({ '@type': 'Question', name: faq.question, acceptedAnswer: { '@type': 'Answer', text: faq.answer }, })), }) } if (post.howToSteps?.length) { graph.push({ '@type': 'HowTo', '@id': `${SITE}${post.canonical}#howto`, name: post.howToName || post.title, step: post.howToSteps.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name.replace(/^\d+\.\s*/, ''), text: step.text, })), }) } return { '@context': 'https://schema.org', '@graph': graph } } function renderFormattedText(text: string) { if (!text) return null const regex = /\[([^\]]+)\]\(([^)]+)\)/g const parts: React.ReactNode[] = [] let lastIndex = 0 let match: RegExpExecArray | null while ((match = regex.exec(text)) !== null) { if (match.index > lastIndex) { parts.push(text.substring(lastIndex, match.index)) } const linkText = match[1] const url = match[2] const isExternal = url.startsWith('http') if (isExternal) { parts.push( {linkText} ) } else { parts.push( {linkText} ) } lastIndex = regex.lastIndex } if (lastIndex < text.length) { parts.push(text.substring(lastIndex)) } return parts.length > 0 ? parts : text } export function BlogPostTemplate({ post }: { post: BlogPost }) { const t = blogUiCopy[post.locale] ?? blogUiCopy.en return (