Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 101 additions & 14 deletions src/layouts/PostDetails.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import { SITE } from "@config";

export interface Props {
post: CollectionEntry<"blog">;
posts: CollectionEntry<"blog">[];
}

const { post } = Astro.props;
const { post, posts } = Astro.props;

const {
title,
Expand Down Expand Up @@ -44,6 +45,19 @@ const layoutProps = {
ogImage: ogUrl,
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}>
Expand Down Expand Up @@ -94,6 +108,72 @@ const layoutProps = {

<ShareLinks />
</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>
<Footer />
</Layout>
Expand All @@ -107,7 +187,7 @@ const layoutProps = {
}
</style>

<script is:inline>
<script is:inline data-astro-rerun>
/** Create a progress indicator
* at the top */
function createProgressBar() {
Expand All @@ -132,20 +212,22 @@ const layoutProps = {
/** Update the progress bar
* when user scrolls */
function updateScrollProgress() {
const winScroll =
document.body.scrollTop || document.documentElement.scrollTop;
const height =
document.documentElement.scrollHeight -
document.documentElement.clientHeight;
const scrolled = (winScroll / height) * 100;
if (document) {
const myBar = document.getElementById("myBar");
if (myBar) {
myBar.style.width = scrolled + "%";
document.addEventListener("scroll", () => {
const winScroll =
document.body.scrollTop || document.documentElement.scrollTop;
const height =
document.documentElement.scrollHeight -
document.documentElement.clientHeight;
const scrolled = (winScroll / height) * 100;
if (document) {
const myBar = document.getElementById("myBar");
if (myBar) {
myBar.style.width = scrolled + "%";
}
}
}
});
}
document.addEventListener("scroll", updateScrollProgress);
updateScrollProgress();

/** Attaches links to headings in the document,
* allowing sharing of sections easily */
Expand Down Expand Up @@ -220,4 +302,9 @@ const layoutProps = {
});
}
backToTop();

/* Go to page start after page swap */
document.addEventListener("astro:after-swap", () =>
window.scrollTo({ left: 0, top: 0, behavior: "instant" })
);
</script>
6 changes: 5 additions & 1 deletion src/pages/posts/[slug]/index.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
import { type CollectionEntry, getCollection } from "astro:content";
import PostDetails from "@layouts/PostDetails.astro";
import getSortedPosts from "@utils/getSortedPosts";

export interface Props {
post: CollectionEntry<"blog">;
Expand All @@ -18,6 +19,9 @@ export async function getStaticPaths() {
}

const { post } = Astro.props;

const posts = await getCollection("blog");
const sortedPosts = getSortedPosts(posts);
---

<PostDetails post={post} />
<PostDetails post={post} posts={sortedPosts} />