Skip to content

Commit

Permalink
feat: #134 add modified datetime in blog posts
Browse files Browse the repository at this point in the history
Add modDatetime in blogSchema. Update Datetime component to accept modDatetime. Update sorting logic. Rename datetime to pubDatetime in Datetime component.

Closes: #134
  • Loading branch information
satnaing committed Dec 21, 2023
1 parent 2f602fe commit 8ddd9f5
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface Props {
}

export default function Card({ href, frontmatter, secHeading = true }: Props) {
const { title, pubDatetime, description } = frontmatter;
const { title, pubDatetime, modDatetime, description } = frontmatter;

const headerProps = {
style: { viewTransitionName: slugifyStr(title) },
Expand All @@ -28,7 +28,7 @@ export default function Card({ href, frontmatter, secHeading = true }: Props) {
<h3 {...headerProps}>{title}</h3>
)}
</a>
<Datetime datetime={pubDatetime} />
<Datetime pubDatetime={pubDatetime} modDatetime={modDatetime} />
<p>{description}</p>
</li>
);
Expand Down
40 changes: 29 additions & 11 deletions src/components/Datetime.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,56 @@
import { LOCALE } from "@config";

export interface Props {
datetime: string | Date;
interface DatetimesProps {
pubDatetime: string | Date;
modDatetime: string | Date | undefined;
}

interface Props extends DatetimesProps {
size?: "sm" | "lg";
className?: string;
}

export default function Datetime({ datetime, size = "sm", className }: Props) {
export default function Datetime({
pubDatetime,
modDatetime,
size = "sm",
className,
}: Props) {
return (
<div className={`flex items-center space-x-2 opacity-80 ${className}`}>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`${
size === "sm" ? "scale-90" : "scale-100"
} inline-block h-6 w-6 fill-skin-base`}
} inline-block h-6 w-6 min-w-[1.375rem] fill-skin-base`}
aria-hidden="true"
>
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
<path d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM19 8l.001 12H5V8h14z"></path>
</svg>
<span className="sr-only">Posted on:</span>
{modDatetime ? (
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
Updated:
</span>
) : (
<span className="sr-only">Published:</span>
)}
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
<FormattedDatetime datetime={datetime} />
<FormattedDatetime
pubDatetime={pubDatetime}
modDatetime={modDatetime}
/>
</span>
</div>
);
}

const FormattedDatetime = ({ datetime }: { datetime: string | Date }) => {
const myDatetime = new Date(datetime);
const FormattedDatetime = ({ pubDatetime, modDatetime }: DatetimesProps) => {
const myDatetime = new Date(modDatetime ? modDatetime : pubDatetime);

const date = myDatetime.toLocaleDateString(LOCALE.langTag, {
year: "numeric",
month: "long",
month: "short",
day: "numeric",
});

Expand All @@ -43,10 +61,10 @@ const FormattedDatetime = ({ datetime }: { datetime: string | Date }) => {

return (
<>
{date}
<time dateTime={myDatetime.toISOString()}>{date}</time>
<span aria-hidden="true"> | </span>
<span className="sr-only">&nbsp;at&nbsp;</span>
{time}
<span className="text-nowrap">{time}</span>
</>
);
};
1 change: 1 addition & 0 deletions src/content/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const blog = defineCollection({
z.object({
author: z.string().default(SITE.author),
pubDatetime: z.date(),
modDatetime: z.date().optional(),
title: z.string(),
postSlug: z.string().optional(),
featured: z.boolean().optional(),
Expand Down
35 changes: 25 additions & 10 deletions src/layouts/PostDetails.astro
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@ export interface Props {
const { post } = Astro.props;
const { title, author, description, ogImage, canonicalURL, pubDatetime, tags } =
post.data;
const {
title,
author,
description,
ogImage,
canonicalURL,
pubDatetime,
modDatetime,
tags,
} = post.data;
const { Content } = await post.render();
Expand All @@ -23,15 +31,17 @@ const ogUrl = new URL(
ogImageUrl ?? `/posts/${slugifyStr(title)}.png`,
Astro.url.origin
).href;
const layoutProps = {
title,
author,
description,
canonicalURL,
ogImage: ogUrl,
};
---

<Layout
title={title}
author={author}
description={description}
ogImage={ogUrl}
canonicalURL={canonicalURL}
>
<Layout {...layoutProps}>
<Header />
<div class="mx-auto flex w-full max-w-3xl justify-start px-2">
<button
Expand All @@ -47,7 +57,12 @@ const ogUrl = new URL(
</div>
<main id="main-content">
<h1 transition:name={slugifyStr(title)} class="post-title">{title}</h1>
<Datetime datetime={pubDatetime} size="lg" className="my-2" />
<Datetime
pubDatetime={pubDatetime}
modDatetime={modDatetime}
size="lg"
className="my-2"
/>
<article id="article" role="article" class="prose mx-auto mt-8 max-w-3xl">
<Content />
</article>
Expand Down
13 changes: 9 additions & 4 deletions src/utils/getSortedPosts.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import type { CollectionEntry } from "astro:content";

const getSortedPosts = (posts: CollectionEntry<"blog">[]) =>
posts
const getSortedPosts = (posts: CollectionEntry<"blog">[]) => {
return posts
.filter(({ data }) => !data.draft)
.sort(
(a, b) =>
Math.floor(new Date(b.data.pubDatetime).getTime() / 1000) -
Math.floor(new Date(a.data.pubDatetime).getTime() / 1000)
Math.floor(
new Date(b.data.modDatetime ?? b.data.pubDatetime).getTime() / 1000
) -
Math.floor(
new Date(a.data.modDatetime ?? a.data.pubDatetime).getTime() / 1000
)
);
};

export default getSortedPosts;

0 comments on commit 8ddd9f5

Please sign in to comment.