95eb362bfc
QuantumLab template converted to Next.js 16 + React 19 + TypeScript: - 8 page routes (home, about, blog, contact, careers, team-members, coming-soon, 404) - Dynamic routes for blog posts, career positions, and team members - GSAP animations (marquee, counters, button hovers) - IntersectionObserver-based scroll reveal (blur-to-clear transitions) - Dark mode with next-themes - React Hook Form + Zod contact form - Framer Motion page transitions - Lottie animations via lottie-web Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
106 lines
5.0 KiB
TypeScript
106 lines
5.0 KiB
TypeScript
import type { Metadata } from "next"
|
|
import Image from "next/image"
|
|
import Link from "next/link"
|
|
import { notFound } from "next/navigation"
|
|
import { BLOG_POSTS } from "@/lib/blog-data"
|
|
|
|
interface Props {
|
|
params: Promise<{ slug: string }>
|
|
}
|
|
|
|
export async function generateStaticParams() {
|
|
return BLOG_POSTS.map((post) => ({ slug: post.slug }))
|
|
}
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params
|
|
const post = BLOG_POSTS.find((p) => p.slug === slug)
|
|
if (!post) return { title: "Post Not Found" }
|
|
return {
|
|
title: post.title,
|
|
description: post.excerpt,
|
|
openGraph: {
|
|
title: post.title,
|
|
description: post.excerpt,
|
|
images: [{ url: post.image }],
|
|
},
|
|
}
|
|
}
|
|
|
|
export default async function BlogPostPage({ params }: Props) {
|
|
const { slug } = await params
|
|
const post = BLOG_POSTS.find((p) => p.slug === slug)
|
|
if (!post) notFound()
|
|
|
|
return (
|
|
<main>
|
|
<section className="section-small top overflow-hidden">
|
|
<div className="w-layout-blockcontainer container-default w-container">
|
|
<div className="inner-container _650px center">
|
|
<div className="text-center">
|
|
<div className="blog-details-wrapper" style={{ justifyContent: "center" }}>
|
|
<div className="item-details">{post.date}</div>
|
|
<div className="item-details-divider">·</div>
|
|
<div className="item-details">{post.category}</div>
|
|
</div>
|
|
<div className="mg-top-4x-extra-small">
|
|
<h1>{post.title}</h1>
|
|
</div>
|
|
<div className="mg-top-4x-extra-small">
|
|
<p>{post.excerpt}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="corner-gradient-container">
|
|
<div className="border-wrapper" style={{ position: "relative", aspectRatio: "16/9" }}>
|
|
<Image
|
|
src={post.image}
|
|
alt={post.imageAlt}
|
|
fill
|
|
style={{ objectFit: "cover", borderRadius: 12 }}
|
|
priority
|
|
/>
|
|
</div>
|
|
<div className="corner-gradient-wrapper">
|
|
<div className="corner-gradient-horizontal top-left" />
|
|
<div className="corner-gradient-horizontal bottom-left" />
|
|
<div className="corner-gradient-horizontal top-right" />
|
|
<div className="corner-gradient-horizontal bottom-right" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="inner-container _650px center">
|
|
<div className="blog-post-rich-text w-richtext">
|
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.</p>
|
|
<h2>Key Insights</h2>
|
|
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.</p>
|
|
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.</p>
|
|
<h2>Looking Ahead</h2>
|
|
<p>Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="inner-container _650px center text-center">
|
|
<Link href="/blog" className="primary-button w-inline-block">
|
|
<div className="button-content">
|
|
<div>Back to all articles</div>
|
|
<div className="button-icon-wrapper primary">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 17 17" fill="none" className="squared-icon">
|
|
<path d="M6.25391 3.45312L10.7458 8.01563L6.25391 12.5781" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square" />
|
|
</svg>
|
|
<div className="button-icon-bg" />
|
|
<div className="button-icon-bg-inside" />
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
)
|
|
}
|