mirror of
https://github.com/ChenQihan666/MyBlog-Next.git
synced 2026-08-14 11:29:33 +08:00
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:
+101
-14
@@ -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>
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
Reference in New Issue
Block a user