UNPKG

blogstart

Version:

Automatically setup SEO-optimized blog routes for Next.js projects

122 lines (104 loc) 3.55 kB
import { notFound } from "next/navigation"; import Link from "next/link"; // Fetch blog posts from your JSON endpoint async function getBlogPosts() { try { // For local development and production const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : process.env.NODE_ENV === "development" ? "http://localhost:3000" : ""; const response = await fetch(`${baseUrl}/sample-blog-posts.json`, { next: { revalidate: 3600 }, // Revalidate every hour }); if (!response.ok) { throw new Error("Failed to fetch blog posts"); } const data = await response.json(); return data.posts || []; } catch (error) { console.error("Error fetching blog posts:", error); return []; } } export async function generateMetadata({ params }) { const { slug } = await params; const posts = await getBlogPosts(); const post = posts.find((p) => p.slug === slug); if (!post) return {}; return { title: `${post.title}`, description: post.description, }; } export async function generateStaticParams() { const posts = await getBlogPosts(); return posts.map((post) => ({ slug: post.slug, })); } export default async function BlogPage({ params }) { const { slug } = await params; const posts = await getBlogPosts(); const post = posts.find((p) => p.slug === slug); if (!post) return notFound(); const currentDate = new Date().toISOString(); const estimatedReadingTime = Math.ceil( ((post.content.intro?.length || 0) + (post.content.platformImpact?.length || 0) + (post.content.howWeHelp?.length || post.content.howLayzrHelps?.length || 0)) / 1000 ) || 5; return ( <div className="bg-white"> <main className="max-w-3xl mx-auto px-6 py-20 bg-white"> <h1 className="text-3xl font-bold">{post.title}</h1> <p className="mt-4 text-zinc-600 text-lg">{post.content.intro}</p> <section className="mt-10"> <h2 className="text-2xl font-semibold"> Why This Matters for {post.platform} </h2> <p className="mt-2 text-zinc-600">{post.content.platformImpact}</p> </section> <section className="mt-10"> <h2 className="text-2xl font-semibold"> Common Mistakes on {post.platform} </h2> <ul className="list-disc list-inside mt-2 text-zinc-600 space-y-2"> {post.content.commonMistakes.map((item, idx) => ( <li key={idx}>{item}</li> ))} </ul> </section> <section className="mt-10"> <h2 className="text-2xl font-semibold">How We Help</h2> <p className="mt-2 text-zinc-600"> {post.content.howWeHelp || post.content.howLayzrHelps} </p> </section> <a href="/" className="inline-block mt-10 px-6 py-3 bg-black text-white rounded-xl hover:bg-zinc-800 transition" > {post.cta} </a> {(post.relatedPages?.length || 0) > 0 && ( <section className="mt-12"> <h2 className="text-xl font-semibold mb-4">Related Pages</h2> <ul className="list-disc list-inside space-y-2 text-blue-600"> {post.relatedPages?.map((p) => ( <li key={p.slug}> <Link href={`/blog/${p.slug}`}>{p.title}</Link> </li> ))} </ul> </section> )} </main> </div> ); }