diff --git a/OliverBooth/Pages/Blog/Article.cshtml b/OliverBooth/Pages/Blog/Article.cshtml
index 0cd7b79..798a4c1 100644
--- a/OliverBooth/Pages/Blog/Article.cshtml
+++ b/OliverBooth/Pages/Blog/Article.cshtml
@@ -1,6 +1,8 @@
@page "/blog/{year:int}/{month:int}/{day:int}/{slug}"
@using Humanizer
@using OliverBooth.Data.Blog
+@using OliverBooth.Services
+@inject IBlogPostService BlogPostService
@model Article
@if (Model.Post is not { } post)
@@ -54,6 +56,41 @@
+
+
+ @if (BlogPostService.GetPreviousPost(post) is { } previousPost)
+ {
+
Previous Post
+
+
+ @previousPost.Title
+
+
+ }
+
+
+ @if (BlogPostService.GetNextPost(post) is { } nextPost)
+ {
+
Next Post
+
+
+ @nextPost.Title
+
+
+ }
+
+
+
+
+
@if (post.EnableComments)
{
diff --git a/OliverBooth/Services/BlogPostService.cs b/OliverBooth/Services/BlogPostService.cs
index 77da54a..aa2a4a1 100644
--- a/OliverBooth/Services/BlogPostService.cs
+++ b/OliverBooth/Services/BlogPostService.cs
@@ -66,6 +66,26 @@ internal sealed class BlogPostService : IBlogPostService
.ToArray().Select(CacheAuthor).ToArray();
}
+ ///
+ public IBlogPost? GetNextPost(IBlogPost blogPost)
+ {
+ using BlogContext context = _dbContextFactory.CreateDbContext();
+ return context.BlogPosts
+ .Where(p => p.Visibility == BlogPostVisibility.Published)
+ .OrderBy(post => post.Published)
+ .FirstOrDefault(post => post.Published > blogPost.Published);
+ }
+
+ ///
+ public IBlogPost? GetPreviousPost(IBlogPost blogPost)
+ {
+ using BlogContext context = _dbContextFactory.CreateDbContext();
+ return context.BlogPosts
+ .Where(p => p.Visibility == BlogPostVisibility.Published)
+ .OrderByDescending(post => post.Published)
+ .FirstOrDefault(post => post.Published < blogPost.Published);
+ }
+
///
public string RenderExcerpt(IBlogPost post, out bool wasTrimmed)
{
diff --git a/OliverBooth/Services/IBlogPostService.cs b/OliverBooth/Services/IBlogPostService.cs
index a7ac372..bcb48ee 100644
--- a/OliverBooth/Services/IBlogPostService.cs
+++ b/OliverBooth/Services/IBlogPostService.cs
@@ -34,6 +34,20 @@ public interface IBlogPostService
/// A collection of blog posts.
IReadOnlyList GetBlogPosts(int page, int pageSize = 10);
+ ///
+ /// Returns the next blog post from the specified blog post.
+ ///
+ /// The blog post whose next post to return.
+ /// The next blog post from the specified blog post.
+ IBlogPost? GetNextPost(IBlogPost blogPost);
+
+ ///
+ /// Returns the previous blog post from the specified blog post.
+ ///
+ /// The blog post whose previous post to return.
+ /// The previous blog post from the specified blog post.
+ IBlogPost? GetPreviousPost(IBlogPost blogPost);
+
///
/// Renders the excerpt of the specified blog post.
///