feat: add prev/next links at the bottom of blog post (#372)

* feat: add prev/next links at the bottom of blog post
* fix: update and rerun scripts in post details page after swap

Resolves #358
This commit is contained in:
Sat Naing
2024-09-16 20:43:54 +07:00
committed by GitHub
parent 08b1676cdd
commit 29eff36794
2 changed files with 106 additions and 15 deletions
+101 -14
View File
@@ -11,9 +11,10 @@ import { SITE } from "@config";
export interface Props { export interface Props {
post: CollectionEntry<"blog">; post: CollectionEntry<"blog">;
posts: CollectionEntry<"blog">[];
} }
const { post } = Astro.props; const { post, posts } = Astro.props;
const { const {
title, title,
@@ -44,6 +45,19 @@ const layoutProps = {
ogImage: ogUrl, ogImage: ogUrl,
scrollSmooth: true, scrollSmooth: true,
}; };
/* ========== Prev/Next Posts ========== */
const allPosts = posts.map(({ data: { title }, slug }) => ({
slug,
title,
}));
const currentPostIndex = allPosts.findIndex(a => a.slug === post.slug);
const prevPost = currentPostIndex !== 0 ? allPosts[currentPostIndex - 1] : null;
const nextPost =
currentPostIndex !== allPosts.length ? allPosts[currentPostIndex + 1] : null;
--- ---
<Layout {...layoutProps}> <Layout {...layoutProps}>
@@ -94,6 +108,72 @@ const layoutProps = {
<ShareLinks /> <ShareLinks />
</div> </div>
<hr class="my-6 border-dashed" />
<!-- Previous/Next Post Buttons -->
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
{
prevPost && (
<a
href={`/posts/${prevPost.slug}`}
class="flex w-full gap-1 hover:opacity-75"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-left flex-none"
>
<>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M15 6l-6 6l6 6" />
</>
</svg>
<div>
<span>Previous Post</span>
<div class="text-sm text-skin-accent/85">{prevPost.title}</div>
</div>
</a>
)
}
{
nextPost && (
<a
href={`/posts/${nextPost.slug}`}
class="flex w-full justify-end gap-1 text-right hover:opacity-75 sm:col-start-2"
>
<div>
<span>Next Post</span>
<div class="text-sm text-skin-accent/85">{nextPost.title}</div>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-chevron-right flex-none"
>
<>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 6l6 6l-6 6" />
</>
</svg>
</a>
)
}
</div>
</main> </main>
<Footer /> <Footer />
</Layout> </Layout>
@@ -107,7 +187,7 @@ const layoutProps = {
} }
</style> </style>
<script is:inline> <script is:inline data-astro-rerun>
/** Create a progress indicator /** Create a progress indicator
* at the top */ * at the top */
function createProgressBar() { function createProgressBar() {
@@ -132,20 +212,22 @@ const layoutProps = {
/** Update the progress bar /** Update the progress bar
* when user scrolls */ * when user scrolls */
function updateScrollProgress() { function updateScrollProgress() {
const winScroll = document.addEventListener("scroll", () => {
document.body.scrollTop || document.documentElement.scrollTop; const winScroll =
const height = document.body.scrollTop || document.documentElement.scrollTop;
document.documentElement.scrollHeight - const height =
document.documentElement.clientHeight; document.documentElement.scrollHeight -
const scrolled = (winScroll / height) * 100; document.documentElement.clientHeight;
if (document) { const scrolled = (winScroll / height) * 100;
const myBar = document.getElementById("myBar"); if (document) {
if (myBar) { const myBar = document.getElementById("myBar");
myBar.style.width = scrolled + "%"; if (myBar) {
myBar.style.width = scrolled + "%";
}
} }
} });
} }
document.addEventListener("scroll", updateScrollProgress); updateScrollProgress();
/** Attaches links to headings in the document, /** Attaches links to headings in the document,
* allowing sharing of sections easily */ * allowing sharing of sections easily */
@@ -220,4 +302,9 @@ const layoutProps = {
}); });
} }
backToTop(); backToTop();
/* Go to page start after page swap */
document.addEventListener("astro:after-swap", () =>
window.scrollTo({ left: 0, top: 0, behavior: "instant" })
);
</script> </script>
+5 -1
View File
@@ -1,6 +1,7 @@
--- ---
import { type CollectionEntry, getCollection } from "astro:content"; import { type CollectionEntry, getCollection } from "astro:content";
import PostDetails from "@layouts/PostDetails.astro"; import PostDetails from "@layouts/PostDetails.astro";
import getSortedPosts from "@utils/getSortedPosts";
export interface Props { export interface Props {
post: CollectionEntry<"blog">; post: CollectionEntry<"blog">;
@@ -18,6 +19,9 @@ export async function getStaticPaths() {
} }
const { post } = Astro.props; const { post } = Astro.props;
const posts = await getCollection("blog");
const sortedPosts = getSortedPosts(posts);
--- ---
<PostDetails post={post} /> <PostDetails post={post} posts={sortedPosts} />