Skip to content

Commit 0f1063c

Browse files
committed
➕ADD: Blog design, ghost CMS
1 parent 505110d commit 0f1063c

File tree

7 files changed

+286
-4
lines changed

7 files changed

+286
-4
lines changed

components/Container.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@ export default function Container(props) {
2727
<title>{meta.title}</title>
2828
<meta name="robots" content="follow, index" />
2929
<meta content={meta.description} name="description" />
30-
<meta property="og:url" content={`https://leerob.io${router.asPath}`} />
31-
<link rel="canonical" href={`https://leerob.io${router.asPath}`} />
30+
<meta
31+
property="og:url"
32+
content={`https://manuarora.in${router.asPath}`}
33+
/>
34+
<link rel="canonical" href={`https://manuarora.in${router.asPath}`} />
3235
<meta property="og:type" content={meta.type} />
33-
<meta property="og:site_name" content="Lee Robinson" />
36+
<meta property="og:site_name" content="Manu Arora" />
3437
<meta property="og:description" content={meta.description} />
3538
<meta property="og:title" content={meta.title} />
3639
<meta property="og:image" content={meta.image} />
3740
<meta name="twitter:card" content="summary_large_image" />
38-
<meta name="twitter:site" content="@leeerob" />
41+
<meta name="twitter:site" content="@mannupaaji" />
3942
<meta name="twitter:title" content={meta.title} />
4043
<meta name="twitter:description" content={meta.description} />
4144
<meta name="twitter:image" content={meta.image} />

layouts/blog.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import Image from "next/image";
2+
import { parseISO, format } from "date-fns";
3+
4+
import Container from "@/components/Container";
5+
import Contact from "@/components/Contact";
6+
// import ViewCounter from "@/components/ViewCounter";
7+
8+
export default function BlogLayout({ children, frontMatter }) {
9+
return (
10+
<Container
11+
title={`${frontMatter.title} – Manu Arora`}
12+
description={frontMatter.custom_excerpt}
13+
image={`https://manuarora.in${frontMatter.feature_image}`}
14+
date={new Date(frontMatter.published_at).toISOString()}
15+
type="article"
16+
>
17+
<article className="flex flex-col justify-center items-start max-w-2xl mx-auto mb-16 w-full">
18+
<h1 className="font-bold text-3xl md:text-5xl tracking-tight mb-4 text-black dark:text-white">
19+
{frontMatter.title}
20+
</h1>
21+
<div className="flex flex-col md:flex-row justify-between items-start md:items-center w-full mt-2 mb-8">
22+
<div className="flex items-center">
23+
<Image
24+
alt="Manu Arora"
25+
height={24}
26+
width={24}
27+
src="/avatar.jpg"
28+
className="rounded-full"
29+
/>
30+
<p className="text-sm text-gray-700 dark:text-gray-300 ml-2">
31+
{frontMatter.by}
32+
{"Manu Arora / "}
33+
{format(parseISO(frontMatter.published_at), "MMMM dd, yyyy")}
34+
</p>
35+
</div>
36+
<p className="text-sm text-gray-500 min-w-32 mt-2 md:mt-0">
37+
{frontMatter.readingTime.text}
38+
{` • `}
39+
{/* <ViewCounter slug={frontMatter.slug} /> */}
40+
</p>
41+
</div>
42+
<div className="prose dark:prose-dark max-w-none w-full">
43+
{children}
44+
</div>
45+
<div className="mt-8">
46+
<Contact />
47+
</div>
48+
<div className="text-sm text-gray-700 dark:text-gray-300">
49+
<a
50+
href={discussUrl(frontMatter.slug)}
51+
target="_blank"
52+
rel="noopener noreferrer"
53+
>
54+
{"Discuss on Twitter"}
55+
</a>
56+
{` • `}
57+
<a
58+
href={editUrl(frontMatter.slug)}
59+
target="_blank"
60+
rel="noopener noreferrer"
61+
>
62+
{"Edit on GitHub"}
63+
</a>
64+
</div>
65+
</article>
66+
</Container>
67+
);
68+
}

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"dependencies": {
1111
"comma-number": "^2.0.1",
12+
"date-fns": "^2.19.0",
1213
"next": "10.0.5",
1314
"react": "17.0.1",
1415
"react-dom": "17.0.1",

pages/blog.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { useState } from "react";
2+
3+
import Container from "@/components/Container";
4+
import BlogPost from "@/components/BlogPost";
5+
// import { getAllFilesFrontMatter } from '@/lib/mdx';
6+
7+
export const getStaticProps = async ({ params }) => {
8+
const posts = await getPosts();
9+
10+
return { props: { posts } };
11+
};
12+
13+
async function getPosts() {
14+
const res = await fetch(
15+
`${process.env.BLOG_URL}/ghost/api/v3/content/posts/?key=${process.env.CONTENT_API_KEY}&fields=title,slug,custom_excerpt,reading_time,published_at`
16+
).then((res) => res.json());
17+
18+
const frontMatter = res.posts;
19+
20+
return frontMatter;
21+
}
22+
23+
export default function Blog({ posts }) {
24+
const [searchValue, setSearchValue] = useState("");
25+
const filteredBlogPosts = posts
26+
.sort(
27+
(a, b) =>
28+
Number(new Date(b.published_at)) - Number(new Date(a.published_at))
29+
)
30+
.filter((frontMatter) =>
31+
frontMatter.title.toLowerCase().includes(searchValue.toLowerCase())
32+
);
33+
34+
return (
35+
<Container
36+
title="Blog – Manu Arora"
37+
description="Thoughts on the software industry, programming, tech, videography, music, and my personal life."
38+
>
39+
<div className="flex flex-col justify-center items-start max-w-2xl mx-auto mb-16">
40+
<h1 className="font-bold text-3xl md:text-5xl tracking-tight mb-4 text-black dark:text-white">
41+
Blog
42+
</h1>
43+
<p className="text-gray-600 dark:text-gray-400 mb-4">
44+
{`I've been writing online since 2014, mostly about web development and tech careers.
45+
In total, I've written ${posts.length} articles on this site.
46+
Use the search below to filter by title.`}
47+
</p>
48+
<div className="relative w-full mb-4">
49+
<input
50+
aria-label="Search articles"
51+
type="text"
52+
onChange={(e) => setSearchValue(e.target.value)}
53+
placeholder="Search articles"
54+
className="px-4 py-2 border border-gray-300 dark:border-gray-900 focus:ring-blue-500 focus:border-blue-500 block w-full rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
55+
/>
56+
<svg
57+
className="absolute right-3 top-3 h-5 w-5 text-gray-400 dark:text-gray-300"
58+
xmlns="http://www.w3.org/2000/svg"
59+
fill="none"
60+
viewBox="0 0 24 24"
61+
stroke="currentColor"
62+
>
63+
<path
64+
strokeLinecap="round"
65+
strokeLinejoin="round"
66+
strokeWidth={2}
67+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
68+
/>
69+
</svg>
70+
</div>
71+
{!searchValue && (
72+
<>
73+
<h3 className="font-bold text-2xl md:text-4xl tracking-tight mb-4 mt-8 text-black dark:text-white">
74+
Most Popular
75+
</h3>
76+
<BlogPost
77+
title="Why I started using NextJS in my workflow"
78+
summary="A case study on how I ditched traditional React and started using NextJS along with it's features such as Image optimization & Routing."
79+
slug="why-i-started-using-next-js"
80+
/>
81+
<BlogPost
82+
title="How to design a minimal and beautiful website which actually converts"
83+
summary="Examining the tips and tricks used to make a website design a notch above the rest."
84+
slug="how-to-design-beautiful-websites"
85+
/>
86+
<BlogPost
87+
title="Using real world projects to build better learning habits"
88+
summary="In this guide, you will learn how to take an idea and convert it into a real world application, while learning on the go."
89+
slug="real-world-app-development"
90+
/>
91+
</>
92+
)}
93+
<h3 className="font-bold text-2xl md:text-4xl tracking-tight mb-4 mt-8 text-black dark:text-white">
94+
All Posts
95+
</h3>
96+
{!filteredBlogPosts.length && (
97+
<p className="text-gray-600 dark:text-gray-400 mb-4">
98+
No posts found.
99+
</p>
100+
)}
101+
{filteredBlogPosts.map((frontMatter) => (
102+
<BlogPost
103+
title={frontMatter.title}
104+
key={frontMatter.title}
105+
summary={frontMatter.custom_excerpt}
106+
slug={frontMatter.slug}
107+
/>
108+
))}
109+
</div>
110+
</Container>
111+
);
112+
}

pages/blog/[slug].js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// import hydrate from "next-mdx-remote/hydrate";
2+
import Link from "next/link";
3+
import { useRouter } from "next/router";
4+
import Image from "next/image";
5+
import { parseISO, format } from "date-fns";
6+
7+
// import { getFiles, getFileBySlug } from '@/lib/mdx';
8+
import BlogLayout from "@/layouts/blog";
9+
import Container from "@/components/Container";
10+
import Contact from "@/components/Contact";
11+
// import MDXComponents from '@/components/MDXComponents';
12+
13+
async function getPost(slug) {
14+
const res = await fetch(
15+
`${process.env.BLOG_URL}/ghost/api/v3/content/posts/slug/${slug}?key=${process.env.CONTENT_API_KEY}&fields=title,slug,html,reading_time,published_at,feature_image`
16+
).then((res) => res.json());
17+
18+
const post = res.posts[0];
19+
// console.log(post);
20+
21+
return post;
22+
}
23+
24+
export async function getStaticProps({ params }) {
25+
const post = await getPost(params.slug);
26+
console.log(post);
27+
return { props: { post } };
28+
}
29+
30+
export const getStaticPaths = () => {
31+
return {
32+
paths: [],
33+
fallback: true,
34+
};
35+
};
36+
37+
export default function Blog(props) {
38+
// const content = hydrate(mdxSource, {
39+
// components: MDXComponents,
40+
// });
41+
const { post } = props;
42+
console.log(("PROPS", props));
43+
const router = useRouter();
44+
45+
if (router.isFallback) {
46+
return <h1>Loading...</h1>;
47+
}
48+
49+
return (
50+
<Container
51+
title={`${post.title} – Manu Arora`}
52+
description={post.custom_excerpt}
53+
image={post.feature_image}
54+
date={new Date(post?.published_at).toISOString()}
55+
type="article"
56+
>
57+
<article className="flex flex-col justify-center items-start max-w-2xl mx-auto mb-16 w-full">
58+
<h1 className="font-bold text-3xl md:text-5xl tracking-tight mb-4 text-black dark:text-white">
59+
{post.title}
60+
</h1>
61+
<div className="flex flex-col md:flex-row justify-between items-start md:items-center w-full mt-2 mb-8">
62+
<div className="flex items-center">
63+
<Image
64+
alt="Manu Arora"
65+
height={24}
66+
width={24}
67+
src="/avatar.jpg"
68+
className="rounded-full"
69+
/>
70+
<p className="text-sm text-gray-700 dark:text-gray-300 ml-2">
71+
{/* {frontMatter.by} */}
72+
{"Manu Arora / "}
73+
{format(parseISO(post?.published_at), "MMMM dd, yyyy")}
74+
</p>
75+
</div>
76+
<p className="text-sm text-gray-500 min-w-32 mt-2 md:mt-0">
77+
{post.reading_time + " " + "minutes read"}
78+
{` • `}
79+
{/* <ViewCounter slug={frontMatter.slug} /> */}
80+
</p>
81+
</div>
82+
<div className="prose dark:prose-dark max-w-none w-full text-black blog-content">
83+
<div dangerouslySetInnerHTML={{ __html: post.html }}></div>
84+
</div>
85+
<div className="mt-8">
86+
<Contact />
87+
</div>
88+
</article>
89+
</Container>
90+
);
91+
92+
// return <BlogLayout frontMatter={frontMatter}>{props.post.html}</BlogLayout>;
93+
}

public/avatar.jpg

140 KB
Loading

0 commit comments

Comments
 (0)