-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from suryanshsingh2001/blog-section
[Feature Request] Blogs Section
- Loading branch information
Showing
19 changed files
with
1,970 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { siteConfig } from "@/config/config"; | ||
import { getPost } from "@/lib/blog"; | ||
import { formatDate, calculateReadTime } from "@/lib/utils"; | ||
import type { Metadata } from "next"; | ||
import { notFound } from "next/navigation"; | ||
import { Suspense } from "react"; | ||
import { Clock, Calendar, ArrowLeft } from "lucide-react"; | ||
import Image from "next/image"; | ||
import { Button } from "@/components/ui/button"; | ||
import Link from "next/link"; | ||
import { Avatar, AvatarImage } from "@/components/ui/avatar"; | ||
|
||
|
||
|
||
export async function generateMetadata({ | ||
params, | ||
}: { | ||
params: { | ||
slug: string; | ||
}; | ||
}): Promise<Metadata | undefined> { | ||
const post = await getPost(params.slug); | ||
|
||
const { | ||
title, | ||
publishedAt: publishedTime, | ||
summary: description, | ||
image, | ||
} = post.metadata; | ||
|
||
return { | ||
title, | ||
description, | ||
openGraph: { | ||
title, | ||
description, | ||
type: "article", | ||
publishedTime, | ||
url: `${siteConfig.url}/blog/${post.slug}`, | ||
images: [ | ||
{ | ||
url: siteConfig.ogImage, | ||
}, | ||
], | ||
}, | ||
twitter: { | ||
card: "summary_large_image", | ||
title, | ||
description, | ||
images: [siteConfig.ogImage], | ||
}, | ||
}; | ||
} | ||
|
||
export default async function Blog({ | ||
params, | ||
}: { | ||
params: { | ||
slug: string; | ||
}; | ||
}) { | ||
const post = await getPost(params.slug); | ||
|
||
|
||
|
||
|
||
if (!post) { | ||
notFound(); | ||
} | ||
|
||
const readTime = calculateReadTime(post.source); | ||
|
||
return ( | ||
<div className="min-h-screen py-12 px-4 sm:px-6 lg:px-8"> | ||
<article className="max-w-4xl mx-auto"> | ||
<div className="mb-8"> | ||
|
||
<Link href={"/"}> | ||
|
||
<Button variant="ghost" className="flex items-center text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white"> | ||
<ArrowLeft className="mr-2 h-4 w-4" /> | ||
Go Back | ||
</Button> | ||
</Link> | ||
</div> | ||
|
||
<div className="relative h-96 w-full mb-8"> | ||
<Image | ||
src={post.metadata.image} | ||
alt={post.metadata.title} | ||
layout="fill" | ||
objectFit="cover" | ||
className="rounded-lg" | ||
/> | ||
</div> | ||
|
||
<header className="mb-8"> | ||
<h1 className="text-4xl font-extrabold tracking-tight text-gray-900 dark:text-white sm:text-5xl mb-4"> | ||
{post.metadata.title} | ||
</h1> | ||
|
||
<div className="flex items-center justify-between flex-wrap gap-4"> | ||
<div className="flex items-center space-x-4"> | ||
<Avatar> | ||
<AvatarImage src={siteConfig.authorImage} alt={siteConfig.author} /> | ||
</Avatar> | ||
<div> | ||
<p className="text-sm font-medium text-gray-900 dark:text-white">{siteConfig.author}</p> | ||
<p className="text-sm text-gray-500 dark:text-gray-400">{"Owner and Maintainer"}</p> | ||
</div> | ||
</div> | ||
|
||
<div className="flex items-center space-x-4 text-sm text-gray-500 dark:text-gray-400"> | ||
<div className="flex items-center space-x-2"> | ||
<Calendar className="w-4 h-4" /> | ||
<time dateTime={post.metadata.publishedAt}> | ||
{formatDate(post.metadata.publishedAt)} | ||
</time> | ||
</div> | ||
<div className="flex items-center space-x-2"> | ||
<Clock className="w-4 h-4" /> | ||
<span>{readTime} min read</span> | ||
</div> | ||
</div> | ||
</div> | ||
</header> | ||
|
||
<div className="prose dark:prose-invert max-w-none"> | ||
<div dangerouslySetInnerHTML={{ __html: post.source }} /> | ||
</div> | ||
</article> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import LandingHeader from "@/components/layout/LandingHeader"; | ||
|
||
|
||
|
||
interface RootLayoutProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
export default function RootLayout({ children }: RootLayoutProps) { | ||
return ( | ||
<> | ||
{children} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { getBlogPosts } from "@/lib/blog"; | ||
import { formatDate } from "@/lib/utils"; | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
import { ArrowRight } from "lucide-react"; | ||
import { Button } from "@/components/ui/button"; | ||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | ||
|
||
export const metadata = { | ||
title: "Blog", | ||
description: "My thoughts on software development, life, and more.", | ||
}; | ||
|
||
export default async function BlogPage() { | ||
const posts = await getBlogPosts(); | ||
|
||
return ( | ||
<section className="min-h-screen py-12 px-4 sm:px-6 lg:px-8"> | ||
<div className="max-w-2xl mx-auto"> | ||
<h1 className="text-3xl font-semibold text-gray-900 dark:text-white mb-2"> | ||
Mockly Blog | ||
</h1> | ||
<p className="text-xl text-gray-600 dark:text-gray-300 mb-12"> | ||
Blogs about Mockly and more. | ||
</p> | ||
|
||
<div className="space-y-12"> | ||
{posts | ||
.sort( | ||
(a, b) => | ||
new Date(b.metadata.publishedAt).getTime() - | ||
new Date(a.metadata.publishedAt).getTime() | ||
) | ||
.map((post) => ( | ||
<article | ||
key={post.slug} | ||
className="border-b border-gray-200 dark:border-gray-700 pb-8 last:border-b-0" | ||
> | ||
<Link href={`/blogs/${post.slug}`}> | ||
<Image | ||
src={post.metadata.image} | ||
alt={post.metadata.title} | ||
width={800} | ||
height={400} | ||
className="rounded-lg w-full h-48 object-cover mb-4" | ||
/> | ||
<h2 className="text-xl font-medium text-gray-900 dark:text-white mb-2"> | ||
{post.metadata.title} | ||
</h2> | ||
<p className="text-base text-gray-600 dark:text-gray-300 mb-2"> | ||
{post.metadata.summary} | ||
</p> | ||
<time className="text-sm text-gray-500 dark:text-gray-400"> | ||
{formatDate(post.metadata.publishedAt)} | ||
</time> | ||
</Link> | ||
</article> | ||
))} | ||
</div> | ||
</div> | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"use client" | ||
|
||
import * as React from "react" | ||
import * as AvatarPrimitive from "@radix-ui/react-avatar" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
const Avatar = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Root>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Root | ||
ref={ref} | ||
className={cn( | ||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
)) | ||
Avatar.displayName = AvatarPrimitive.Root.displayName | ||
|
||
const AvatarImage = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Image>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Image | ||
ref={ref} | ||
className={cn("aspect-square h-full w-full", className)} | ||
{...props} | ||
/> | ||
)) | ||
AvatarImage.displayName = AvatarPrimitive.Image.displayName | ||
|
||
const AvatarFallback = React.forwardRef< | ||
React.ElementRef<typeof AvatarPrimitive.Fallback>, | ||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> | ||
>(({ className, ...props }, ref) => ( | ||
<AvatarPrimitive.Fallback | ||
ref={ref} | ||
className={cn( | ||
"flex h-full w-full items-center justify-center rounded-full bg-muted", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
)) | ||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName | ||
|
||
export { Avatar, AvatarImage, AvatarFallback } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.