Compare commits
1 Commits
pagination
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c521907512 |
33
app/blog/[slug]/layout.tsx
Normal file
33
app/blog/[slug]/layout.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { ProjectProvider } from "@/app/context/ProjectContext";
|
||||||
|
import { getBlogDetails, BLOG_POSTS } from "@/data/content";
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): 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} | Blog`, description: post.description };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout for all paths caught under blog/[slug].
|
||||||
|
* Mirrors app/project/[slug]/layout.tsx: the rendered markdown is resolved
|
||||||
|
* here on the server and handed to the client page via the shared context.
|
||||||
|
* (ProjectContext is a generic `any` context despite its name; its value
|
||||||
|
* contract is `string | null` = rendered HTML.)
|
||||||
|
*/
|
||||||
|
export default async function BlogSlugLayout({ children, params }: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
params: Promise<{ slug: string }>;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const { slug } = await params;
|
||||||
|
const postData = await getBlogDetails(slug);
|
||||||
|
return (
|
||||||
|
<ProjectProvider value={postData}>
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</ProjectProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
76
app/blog/[slug]/page.tsx
Normal file
76
app/blog/[slug]/page.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
'use client'
|
||||||
|
import { use } from 'react'
|
||||||
|
|
||||||
|
import { notFound } from 'next/navigation'
|
||||||
|
import { useSharedData } from '@/app/context/ProjectContext';
|
||||||
|
import { useMountTransition } from '@/hooks/useAnimations';
|
||||||
|
import "../../../styles/markdown-container.css";
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { BLOG_POSTS } from '@/data/content';
|
||||||
|
import SimpleGallery from '@/components/SimpleGallery';
|
||||||
|
|
||||||
|
export default function BlogPostPage({params}: { params: Promise<{ slug: string }> })
|
||||||
|
{
|
||||||
|
|
||||||
|
const mounted = useMountTransition(50)
|
||||||
|
const { slug } = use(params);
|
||||||
|
|
||||||
|
const hasValidPost = BLOG_POSTS.find((v)=>v.slug == slug);
|
||||||
|
if (!slug || !hasValidPost) notFound();
|
||||||
|
|
||||||
|
const hasValidDetails = hasValidPost.details
|
||||||
|
const postDetails = useSharedData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="blog-markdown-container"
|
||||||
|
className={"markdown-container"}
|
||||||
|
style={{
|
||||||
|
opacity: mounted ? 1 : 0,
|
||||||
|
transition: "all 0.5s ease",
|
||||||
|
translate: mounted ? "0 2em" : "0 0"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
{
|
||||||
|
hasValidDetails ?
|
||||||
|
(
|
||||||
|
<main dangerouslySetInnerHTML={{ __html: postDetails }}>
|
||||||
|
</main>
|
||||||
|
) : (
|
||||||
|
<p>No post details available.</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{hasValidPost.images && hasValidPost.images.length > 0 && (
|
||||||
|
<section className="project-details-gallery">
|
||||||
|
<h2>Gallery</h2>
|
||||||
|
<SimpleGallery images={hasValidPost.images} title={hasValidPost.title} gallerySize="large"/>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
<div style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: "1em",
|
||||||
|
marginBottom: "2em"
|
||||||
|
}}>
|
||||||
|
<Link onClick={(e)=>{
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
|
||||||
|
className="expand-on-hover-button"
|
||||||
|
href={"#"}>Back To Top</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
className="expand-on-hover-button"
|
||||||
|
href={"/blog"}>All Posts</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
57
app/blog/layout.tsx
Normal file
57
app/blog/layout.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Nav from "@/components/Nav";
|
||||||
|
import Footer from "@/components/Footer";
|
||||||
|
|
||||||
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
|
return {
|
||||||
|
title: "Blog",
|
||||||
|
description: "Notes, write-ups and behind-the-scenes from Hunter",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function BlogLayout({children}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ minHeight: "100vh", paddingBottom: 36 }}>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
maxWidth: 880,
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "0 24px",
|
||||||
|
transition: "all 0.5s cubic-bezier(0.16, 1, 0.3, 1)",
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<header
|
||||||
|
style={{
|
||||||
|
padding: "24px 0 0",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontFamily: "var(--mono)",
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 700,
|
||||||
|
color: "var(--accent)",
|
||||||
|
letterSpacing: "-0.02em",
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<Nav section={"blog"} />
|
||||||
|
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
app/blog/page.tsx
Normal file
11
app/blog/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import BlogList from "@/components/BlogList";
|
||||||
|
|
||||||
|
export default function Blog() {
|
||||||
|
return (
|
||||||
|
<main>
|
||||||
|
<BlogList />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user