Skip to content
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Commit d7d43b3

Browse files
committed
set custom 404 page
1 parent 92903e8 commit d7d43b3

File tree

8 files changed

+120
-61
lines changed

8 files changed

+120
-61
lines changed

next.config.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
/** @type {import('next').NextConfig} */
2-
const nextConfig = {};
2+
const nextConfig = {
3+
images: {
4+
dangerouslyAllowSVG: true,
5+
domains: ["firebasestorage.googleapis.com", "flagicons.lipis.dev"],
6+
},
7+
};
38

4-
module.exports = nextConfig;
9+
module.exports = nextConfig;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"use client";
2+
3+
import Container from "@/components/Container";
4+
import Image from "next/image";
5+
6+
export default function NotFound() {
7+
return (
8+
<Container>
9+
<div className="text-center my-20">
10+
<div className="relative w-full min-h-[300px]">
11+
<Image
12+
src="https://firebasestorage.googleapis.com/v0/b/blog-e296e.appspot.com/o/assets%2F404.svg?alt=media&token=2b60f8b0-16b3-4692-8ef3-86e697823942"
13+
alt="404 ilustration"
14+
fill
15+
/>
16+
</div>
17+
</div>
18+
</Container>
19+
);
20+
}

src/app/[lang]/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Props = {
2020
params: { lang: string };
2121
};
2222

23-
async function RootLayout({ children, params: { lang } }: Props) {
23+
async function RootLayout({ children, params: { lang = "es" } }: Props) {
2424
return (
2525
<html lang={lang} dir={dir(lang)}>
2626
<body
@@ -36,4 +36,4 @@ async function RootLayout({ children, params: { lang } }: Props) {
3636
);
3737
}
3838

39-
export default RootLayout;
39+
export default RootLayout;

src/app/[lang]/posts/[slug]/getPostService.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { getPostBySlug } from "@/lib/getPosts";
22
import markdownToHtml from "@/lib/markdownToHtml";
33

44
async function getPost(slug: string, lang: string) {
5-
const post = getPostBySlug(slug, [
6-
"slug",
7-
"title",
8-
"excerpt",
9-
"date",
10-
"content",
11-
], lang);
5+
const post = getPostBySlug(
6+
slug,
7+
["slug", "title", "excerpt", "date", "content"],
8+
lang,
9+
);
10+
11+
if (!post) return null;
12+
1213
const content = await markdownToHtml(post.content || "");
1314

1415
return {

src/app/[lang]/posts/[slug]/page.tsx

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,56 @@
1+
import { notFound, redirect } from "next/navigation";
2+
13
import Container from "@/components/Container";
24
import { Post } from "@/interfaces/Post";
35
import getPost from "./getPostService";
46

57
type Props = {
6-
params: { slug: string, lang: string; };
8+
params: { slug: string; lang: string };
79
};
810

911
export default async function PostPage({ params: { slug, lang } }: Props) {
10-
const post: Post = await getPost(slug, lang);
12+
const post: Post | null = await getPost(slug, lang);
13+
14+
if (!post) {
15+
redirect("/not-found");
16+
}
1117

1218
return (
1319
<Container>
14-
<div>
15-
<article>
16-
<header>
17-
<h1 className="text-4xl font-bold">{post.title}</h1>
18-
19-
{post.excerpt ? (
20-
<p className="mt-2 text-xl">{post.excerpt}</p>
21-
) : null}
22-
23-
<time className="flex mt-2 text-gray-400">
24-
{post.date && new Date(post.date).toDateString()}
25-
</time>
26-
</header>
27-
28-
<div
29-
className="prose mt-10"
30-
dangerouslySetInnerHTML={{ __html: post.content || "" }}
31-
/>
32-
</article>
33-
</div>
20+
{post && (
21+
<div>
22+
<article>
23+
<header>
24+
<h1 className="text-4xl font-bold">{post.title}</h1>
25+
26+
{post.excerpt ? (
27+
<p className="mt-2 text-xl">{post.excerpt}</p>
28+
) : null}
29+
30+
<time className="flex mt-2 text-gray-400">
31+
{post.date && new Date(post.date).toDateString()}
32+
</time>
33+
</header>
34+
35+
<div
36+
className="prose mt-10"
37+
dangerouslySetInnerHTML={{ __html: post.content || "" }}
38+
/>
39+
</article>
40+
</div>
41+
)}
3442
</Container>
3543
);
3644
}
3745

3846
export async function generateMetadata({ params: { slug, lang } }: Props) {
39-
const post: Post = await getPost(slug, lang);
47+
const post: Post | null = await getPost(slug, lang);
48+
49+
if (!post) {
50+
return {
51+
title: "404 - Not found",
52+
};
53+
}
4054

4155
return {
4256
title: post.title,

src/app/[lang]/posts/page.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@ import { getAllPosts } from "@/lib/getPosts";
55

66
type Props = {
77
params: { lang: string };
8-
}
8+
};
99

10-
export default function Posts({ params: { lang } } : Props) {
10+
export default function Posts({ params: { lang } }: Props) {
1111
const posts = getAllPosts(["slug", "title", "excerpt", "date"], lang);
1212

1313
return (
1414
<div>
1515
{posts.length ? (
16-
posts.map((post) => <PostCard key={post.slug} post={post} />)
16+
posts.map((post) => {
17+
if (post) {
18+
return <PostCard key={post.slug} post={post} />;
19+
} else {
20+
return null;
21+
}
22+
})
1723
) : (
1824
<p>Todavía no se ha publicado ningún artículo</p>
1925
)}

src/lib/getPosts.ts

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,38 @@ export function getPostSlugs(lang: string) {
1010
return fs.readdirSync(`${postsDirectory}/${lang}`);
1111
}
1212

13-
export function getPostBySlug(slug: string, fields: string[] = [], lang: string) {
14-
const realSlug = slug.replace(/\.md$/, "");
15-
const fullPath = join(`${postsDirectory}/${lang}`, `${realSlug}.md`);
16-
const fileContents = fs.readFileSync(fullPath, "utf8");
17-
18-
const { data, content } = matter(fileContents);
19-
20-
const items: Post = {};
21-
22-
// Ensure only the minimal needed data is exposed
23-
fields.forEach((field) => {
24-
if (field === "slug") {
25-
items[field] = realSlug;
26-
}
27-
if (field === "content") {
28-
items[field] = content;
29-
}
30-
31-
if (typeof data[field] !== "undefined") {
32-
items[field] = data[field];
33-
}
34-
});
35-
36-
return items;
13+
export function getPostBySlug(
14+
slug: string,
15+
fields: string[] = [],
16+
lang: string,
17+
) {
18+
try {
19+
const realSlug = slug.replace(/\.md$/, "");
20+
const fullPath = join(`${postsDirectory}/${lang}`, `${realSlug}.md`);
21+
const fileContents = fs.readFileSync(fullPath, "utf8");
22+
23+
const { data, content } = matter(fileContents);
24+
25+
const items: Post = {};
26+
27+
// Ensure only the minimal needed data is exposed
28+
fields.forEach((field) => {
29+
if (field === "slug") {
30+
items[field] = realSlug;
31+
}
32+
if (field === "content") {
33+
items[field] = content;
34+
}
35+
36+
if (typeof data[field] !== "undefined") {
37+
items[field] = data[field];
38+
}
39+
});
40+
41+
return items;
42+
} catch {
43+
return null;
44+
}
3745
}
3846

3947
export function getAllPosts(fields: string[] = [], lang: string) {

src/posts/es/rpcide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: "El RPCIDE"
3+
excerpt: ""
4+
date: "2023-08-26"
5+
---

0 commit comments

Comments
 (0)