I’ve a problem to get a nested page in my nextjs website.
Here my folder structure :
- _post
- services
- folder 1
- .MD file
- .MD file2
Here my page structure :
- page
- services
- [slug].tsx
- [slug]
- [page].tsx
api.tsx
import fs from "fs";
import { join } from "path";
import matter from "gray-matter";
export function getPostSlugs(folder: string) {
const postsDirectory = join(process.cwd(), folder);
return fs.readdirSync(postsDirectory);
}
export function getPostBySlug(
slug: string,
fields: string[] = [],
postsDirectory: string
) {
const realSlug = slug.replace(/.md$/, "");
const fullPath = join(postsDirectory, `${realSlug}.md`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data, content } = matter(fileContents);
type Items = {
[key: string]: string;
};
const items: Items = {};
// Ensure only the minimal needed data is exposed
fields.forEach((field) => {
if (field === "slug") {
items[field] = realSlug;
}
if (field === "content") {
items[field] = content;
}
if (typeof data[field] !== "undefined") {
items[field] = data[field];
}
});
return items;
}
export function getAllPosts(fields: string[] = [], folder: string) {
const slugs = fs.readdirSync(join(process.cwd(), folder)).filter((slug) => {
return slug.endsWith(".md");
});
const posts = slugs.map((slug: string) =>
getPostBySlug(slug, fields, folder)
);
return posts;
}
[slug].tsx
import { useRouter } from "next/router";
import ErrorPage from "next/error";
import Container from "../../components/Container";
import PostBody from "../../components/PostBody";
import Layout from "../../components/Layout";
import PostTitle from "../../components/PostTitle";
import PostType from "../../types/post";
import { useEffect } from "react";
import AOS from "aos";
import Contact from "../../components/Contact";
import MoreStories from "../../components/MoreStories";
import TwoColumnsLayout from "../../components/TwoColumnsLayout";
import ActiveLink from "../../components/Link";
import { getAllPosts, getPostBySlug } from "../../lib/api";
import markdownToHtml from "../../lib/markdownToHtml";
import OtherStories from "../../components/OtherStories";
type Props = {
post: PostType;
allPosts: PostType[];
postsSuite: PostType[];
preview?: boolean;
};
const Post = ({ allPosts, postsSuite, post, preview }: Props) => {
const otherPosts = allPosts?.filter((p) => p.slug !== post.slug);
const morePosts = postsSuite;
useEffect(() => {
AOS.init({ once: false, offset: -70, delay: 100, duration: 400 });
}, []);
const router = useRouter();
if (!router.isFallback && !post?.slug) {
return <ErrorPage statusCode={404} />;
}
return (
<Layout preview={preview}>
{router.isFallback ? (
<PostTitle>Loading…</PostTitle>
) : (
<>
<Container>
<section className="items-center md:justify-between mb-20">
<div className="hero-container">
<div className="environment"></div>
<h4 className="text-center text-lg">{post.subtitle}</h4>
<h1 className="hero glitch layers" data-text="gifted">
<span>
<h1>{post.title}</h1>
</span>
</h1>
<div className="wrapper container">
<p className="small">{post.summary}</p>
</div>
</div>
<div className="wrapper container">
<ActiveLink
href={"../contact"}
className="m-auto bg-black hover:bg-white hover:text-black border border-white text-white font-bold py-3 px-12 lg:px-8 duration-200 transition-colors lg:mb-0"
activeClassName={""}
>
Nous contacter
</ActiveLink>
</div>
</section>
<TwoColumnsLayout
title="Introduction"
paragraph={post.introduction}
/>
<div className="wrapper container">
<PostBody content={post.content} />
</div>
{morePosts?.length > 0 && (
<MoreStories
posts={morePosts}
h1Title={`${post.title} : En savoir plus`}
/>
)}
{otherPosts?.length > 0 && (
<OtherStories
posts={otherPosts}
h1Title="Découvrir nos autres services en développement web, pentesting et
audit web"
/>
)}
</Container>
<Contact />
</>
)}
<style jsx>{`
.wrapper {
max-width: 900px;
align-items: center;
display: flex;
flex-direction: column;
margin: auto;
}
h1 {
margin-top: 0.2em;
margin-bottom: 0;
align-self: center;
text-align: center;
}
h2.small {
margin-top: 2em;
}
p {
margin: 0;
margin-bottom: 7em;
margin-top: 7em;
}
p.small {
margin: 0;
margin-bottom: 5em;
margin-top: 2em;
}
h4 {
margin-bottom: 0;
}
h4.small {
margin-bottom: 8em;
}
figure {
margin: 0;
}
.elgif {
min-height: 300px;
}
.elgif img {
width: 50%;
margin: 0 auto;
z-index: 3;
}
.elgif:before,
.elgif:after {
position: absolute;
content: "";
width: 100%;
display: block;
}
.elgif:before {
z-index: 2;
top: 11px;
right: 11px;
}
.elgif:after {
z-index: 1;
top: 25px;
right: 23px;
}
@media (min-width: 300px) {
.elgif {
min-height: 300px;
}
}
`}</style>
</Layout>
);
};
export default Post;
type Params = {
params: {
slug: string;
};
};
export async function getStaticProps({ params }: Params) {
const post = getPostBySlug(
params.slug,
[
"title",
"slug",
"content",
"ogImage",
"coverImage",
"introduction",
"subtitle",
"summary",
],
"_posts/services"
);
const postsSuite = getAllPosts(
["title", "slug", "coverImage", "excerpt"],
`_posts/services/${post.slug}`
);
const allPosts = getAllPosts(
["title", "slug", "coverImage", "excerpt"],
`_posts/services`
);
const content = await markdownToHtml(post.content || "");
return {
props: {
post: {
...post,
content,
},
postsSuite,
allPosts,
},
};
}
export async function getStaticPaths() {
const posts = getAllPosts(["slug"], "_posts/services");
return {
paths: posts.map((post) => {
return {
params: {
slug: post.slug,
},
};
}),
fallback: false,
};
}
But I don’t know how to get props and paths for my [page].tsx file. I’ve tried to get multiple params to have an url like../[slug]/[page] but it doesn’t work
Could you help me please?