blog post page

This commit is contained in:
m5r
2021-08-28 00:08:38 +08:00
parent 9248e5fbbe
commit c75ed023a1
12 changed files with 455 additions and 153 deletions

View File

@ -0,0 +1,12 @@
import Image from "next/image";
export default function Avatar({ name, picture }: any) {
return (
<div className="flex items-center">
<div className="w-12 h-12 relative mr-4">
<Image src={picture.url} layout="fill" className="rounded-full" alt={name} />
</div>
<div className="text-xl font-bold">{name}</div>
</div>
);
}

View File

@ -0,0 +1,28 @@
import { Image } from "react-datocms";
import clsx from "clsx";
import Link from "next/link";
export default function CoverImage({ title, responsiveImage, slug }: any) {
const image = (
<Image
data={{
...responsiveImage,
alt: `Cover Image for ${title}`,
}}
className={clsx("shadow-small", {
"hover:shadow-medium transition-shadow duration-200": slug,
})}
/>
);
return (
<div className="sm:mx-0">
{slug ? (
<Link href={`/posts/${slug}`}>
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
);
}

View File

@ -0,0 +1,10 @@
const formatter = Intl.DateTimeFormat("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
});
export default function DateComponent({ dateString }: any) {
const date = new Date(dateString);
return <time dateTime={dateString}>{formatter.format(date)}</time>;
}

View File

@ -0,0 +1,82 @@
import { Link, Routes } from "blitz";
import PostPreview from "./post-preview";
import type { Post } from "../../../integrations/datocms";
type Props = {
posts: Post[];
};
const formatter = Intl.DateTimeFormat("en-US", {
day: "2-digit",
month: "short",
year: "numeric",
});
export default function MoreStories({ posts }: Props) {
return (
<aside>
<div className="relative max-w-6xl mx-auto px-4 sm:px-6">
<div className="pb-12 md:pb-20">
<div className="max-w-3xl mx-auto">
<h4 className="h4 font-mackinac mb-8">Related articles</h4>
{/* Articles container */}
<div className="grid gap-4 sm:gap-6 sm:grid-cols-2">
{posts.map((post) => (
<article key={post.slug} className="relative group p-6 text-white">
<figure>
<img
className="absolute inset-0 w-full h-full object-cover opacity-50 group-hover:opacity-75 transition duration-700 ease-out"
src={post.coverImage.responsiveImage.src}
width="372"
height="182"
alt="Related post"
/>
<div
className="absolute inset-0 bg-primary-500 opacity-75 group-hover:opacity-50 transition duration-700 ease-out"
aria-hidden="true"
/>
</figure>
<div className="relative flex flex-col h-full">
<header className="flex-grow">
<Link href={Routes.PostPage({ slug: post.slug })}>
<a className="hover:underline">
<h3 className="text-lg font-mackinac font-bold tracking-tight mb-2">
{post.title}
</h3>
</a>
</Link>
<div className="text-sm opacity-80">
{formatter.format(new Date(post.date))}
</div>
</header>
<footer>
{/* Author meta */}
<div className="flex items-center text-sm mt-5">
<a href="#0">
<img
className="rounded-full flex-shrink-0 mr-3"
src={post.author.picture.url}
width="32"
height="32"
alt={post.author.name}
/>
</a>
<div>
<span className="opacity-75">By </span>
<span className="font-medium hover:underline">
{post.author.name}
</span>
</div>
</div>
</footer>
</div>
</article>
))}
</div>
</div>
</div>
</div>
</aside>
);
}

View File

@ -0,0 +1,16 @@
import styles from "../styles/post-body.module.css";
type Props = {
content: string;
};
export default function PostBody({ content }: Props) {
return (
<div className="max-w-2xl mx-auto">
<div
className={`prose prose-lg prose-blue ${styles.markdown}`}
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
);
}

View File

@ -0,0 +1,25 @@
import Link from "next/link";
import Avatar from "./avatar";
import Date from "./date";
import CoverImage from "./cover-image";
export default function PostPreview({ title, coverImage, date, excerpt, author, slug }: any) {
return (
<div>
<div className="mb-5">
<CoverImage slug={slug} title={title} responsiveImage={coverImage.responsiveImage} />
</div>
<h3 className="text-3xl mb-3 leading-snug">
<Link href={`/posts/${slug}`}>
<a className="hover:underline">{title}</a>
</Link>
</h3>
<div className="text-lg mb-4">
<Date dateString={date} />
</div>
<p className="text-lg leading-relaxed mb-4">{excerpt}</p>
<Avatar name={author.name} picture={author.picture} />
</div>
);
}

View File

@ -0,0 +1,3 @@
export default function SectionSeparator() {
return <hr className="border-accent-2 mt-28 mb-24" />;
}