(legacyComments.OrderByDescending(c => c.CreatedAt));
+
+ @("legacy comment".ToQuantity(commentCount))
+
+
+ Legacy comments are comments that were posted using a commenting system that I no longer use. This exists for posterity.
+
+
+ while (commentStack.Count > 0)
+ {
+ ILegacyComment comment = commentStack.Pop();
+ foreach (ILegacyComment reply in BlogPostService.GetLegacyReplies(comment).OrderByDescending(c => c.CreatedAt))
+ {
+ if (nestLevelMap.TryGetValue(comment, out int currentLevel))
+ {
+ nestLevelMap[reply] = currentLevel + 1;
+ }
+ else
+ {
+ nestLevelMap[reply] = 1;
+ }
+
+ commentStack.Push(reply);
+ }
+
+ int padding = 0;
+ if (nestLevelMap.TryGetValue(comment, out int nestLevel))
+ {
+ padding = 50 * nestLevel;
+ }
+
+
+ }
+ }
}
else
{
diff --git a/OliverBooth/Pages/Tutorials/Article.cshtml b/OliverBooth/Pages/Tutorials/Article.cshtml
index 7919c37..2970273 100644
--- a/OliverBooth/Pages/Tutorials/Article.cshtml
+++ b/OliverBooth/Pages/Tutorials/Article.cshtml
@@ -1,10 +1,13 @@
@page "/tutorial/{**slug}"
@using Humanizer
+@using Markdig
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using OliverBooth.Data
+@using OliverBooth.Data.Blog
@using OliverBooth.Data.Web
@using OliverBooth.Services
@inject ITutorialService TutorialService
+@inject MarkdownPipeline MarkdownPipeline
@model Article
@if (Model.CurrentArticle is not { } article)
@@ -117,6 +120,57 @@
async>
}
+
+ int commentCount = TutorialService.GetLegacyCommentCount(article);
+ if (commentCount > 0)
+ {
+
+
+ var nestLevelMap = new Dictionary();
+ IReadOnlyList legacyComments = TutorialService.GetLegacyComments(article);
+ var commentStack = new Stack(legacyComments.OrderByDescending(c => c.CreatedAt));
+
+ @("legacy comment".ToQuantity(commentCount))
+
+
+ Legacy comments are comments that were posted using a commenting system that I no longer use. This exists for posterity.
+
+
+ while (commentStack.Count > 0)
+ {
+ ILegacyComment comment = commentStack.Pop();
+ foreach (ILegacyComment reply in TutorialService.GetLegacyReplies(comment).OrderByDescending(c => c.CreatedAt))
+ {
+ if (nestLevelMap.TryGetValue(comment, out int currentLevel))
+ {
+ nestLevelMap[reply] = currentLevel + 1;
+ }
+ else
+ {
+ nestLevelMap[reply] = 1;
+ }
+
+ commentStack.Push(reply);
+ }
+
+ int padding = 0;
+ if (nestLevelMap.TryGetValue(comment, out int nestLevel))
+ {
+ padding = 50 * nestLevel;
+ }
+
+
+ }
+ }
}
else
{
diff --git a/OliverBooth/Services/BlogPostService.cs b/OliverBooth/Services/BlogPostService.cs
index 049cd6e..38985d3 100644
--- a/OliverBooth/Services/BlogPostService.cs
+++ b/OliverBooth/Services/BlogPostService.cs
@@ -67,6 +67,27 @@ internal sealed class BlogPostService : IBlogPostService
.ToArray().Select(CacheAuthor).ToArray();
}
+ ///
+ public int GetLegacyCommentCount(IBlogPost post)
+ {
+ using BlogContext context = _dbContextFactory.CreateDbContext();
+ return context.LegacyComments.Count(c => c.PostId == post.Id);
+ }
+
+ ///
+ public IReadOnlyList GetLegacyComments(IBlogPost post)
+ {
+ using BlogContext context = _dbContextFactory.CreateDbContext();
+ return context.LegacyComments.Where(c => c.PostId == post.Id && c.ParentComment == null).ToArray();
+ }
+
+ ///
+ public IReadOnlyList GetLegacyReplies(ILegacyComment comment)
+ {
+ using BlogContext context = _dbContextFactory.CreateDbContext();
+ return context.LegacyComments.Where(c => c.ParentComment == comment.Id).ToArray();
+ }
+
///
public IBlogPost? GetNextPost(IBlogPost blogPost)
{
diff --git a/OliverBooth/Services/IBlogPostService.cs b/OliverBooth/Services/IBlogPostService.cs
index bcb48ee..5947f19 100644
--- a/OliverBooth/Services/IBlogPostService.cs
+++ b/OliverBooth/Services/IBlogPostService.cs
@@ -34,6 +34,27 @@ public interface IBlogPostService
/// A collection of blog posts.
IReadOnlyList GetBlogPosts(int page, int pageSize = 10);
+ ///
+ /// Returns the number of legacy comments for the specified post.
+ ///
+ /// The post whose legacy comments to count.
+ /// The total number of legacy comments.
+ int GetLegacyCommentCount(IBlogPost post);
+
+ ///
+ /// Returns the collection of legacy comments for the specified post.
+ ///
+ /// The post whose legacy comments to retrieve.
+ /// A read-only view of the legacy comments.
+ IReadOnlyList GetLegacyComments(IBlogPost post);
+
+ ///
+ /// Returns the collection of replies to the specified legacy comment.
+ ///
+ /// The comment whose replies to retrieve.
+ /// A read-only view of the replies.
+ IReadOnlyList GetLegacyReplies(ILegacyComment comment);
+
///
/// Returns the next blog post from the specified blog post.
///
diff --git a/OliverBooth/Services/ITutorialService.cs b/OliverBooth/Services/ITutorialService.cs
index a5bd547..1366172 100644
--- a/OliverBooth/Services/ITutorialService.cs
+++ b/OliverBooth/Services/ITutorialService.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using OliverBooth.Data;
+using OliverBooth.Data.Blog;
using OliverBooth.Data.Web;
namespace OliverBooth.Services;
@@ -60,6 +61,27 @@ public interface ITutorialService
/// is .
string GetFullSlug(ITutorialArticle article);
+ ///
+ /// Returns the number of legacy comments for the specified article.
+ ///
+ /// The article whose legacy comments to count.
+ /// The total number of legacy comments.
+ int GetLegacyCommentCount(ITutorialArticle article);
+
+ ///
+ /// Returns the collection of legacy comments for the specified article.
+ ///
+ /// The article whose legacy comments to retrieve.
+ /// A read-only view of the legacy comments.
+ IReadOnlyList GetLegacyComments(ITutorialArticle article);
+
+ ///
+ /// Returns the collection of replies to the specified legacy comment.
+ ///
+ /// The comment whose replies to retrieve.
+ /// A read-only view of the replies.
+ IReadOnlyList GetLegacyReplies(ILegacyComment comment);
+
///
/// Renders the body of the specified article.
///
diff --git a/OliverBooth/Services/TutorialService.cs b/OliverBooth/Services/TutorialService.cs
index c6e1f7d..3fd21ed 100644
--- a/OliverBooth/Services/TutorialService.cs
+++ b/OliverBooth/Services/TutorialService.cs
@@ -4,24 +4,30 @@ using Humanizer;
using Markdig;
using Microsoft.EntityFrameworkCore;
using OliverBooth.Data;
+using OliverBooth.Data.Blog;
using OliverBooth.Data.Web;
namespace OliverBooth.Services;
internal sealed class TutorialService : ITutorialService
{
+ private readonly IDbContextFactory _blogContextFactory;
private readonly IDbContextFactory _dbContextFactory;
private readonly MarkdownPipeline _markdownPipeline;
///
/// Initializes a new instance of the class.
///
- /// The .
+ /// The factory.
+ /// The factory.
/// The .
- public TutorialService(IDbContextFactory dbContextFactory, MarkdownPipeline markdownPipeline)
+ public TutorialService(IDbContextFactory dbContextFactory,
+ IDbContextFactory blogContextFactory,
+ MarkdownPipeline markdownPipeline)
{
_dbContextFactory = dbContextFactory;
_markdownPipeline = markdownPipeline;
+ _blogContextFactory = blogContextFactory;
}
///
@@ -103,6 +109,37 @@ internal sealed class TutorialService : ITutorialService
return $"{GetFullSlug(folder)}/{article.Slug}";
}
+ ///
+ public int GetLegacyCommentCount(ITutorialArticle article)
+ {
+ if (article.RedirectFrom is not { } postId)
+ {
+ return 0;
+ }
+
+ using BlogContext context = _blogContextFactory.CreateDbContext();
+ return context.LegacyComments.Count(c => c.PostId == postId);
+ }
+
+ ///
+ public IReadOnlyList GetLegacyComments(ITutorialArticle article)
+ {
+ if (article.RedirectFrom is not { } postId)
+ {
+ return ArraySegment.Empty;
+ }
+
+ using BlogContext context = _blogContextFactory.CreateDbContext();
+ return context.LegacyComments.Where(c => c.PostId == postId && c.ParentComment == null).ToArray();
+ }
+
+ ///
+ public IReadOnlyList GetLegacyReplies(ILegacyComment comment)
+ {
+ using BlogContext context = _blogContextFactory.CreateDbContext();
+ return context.LegacyComments.Where(c => c.ParentComment == comment.Id).ToArray();
+ }
+
///
public string RenderArticle(ITutorialArticle article)
{
diff --git a/src/scss/app.scss b/src/scss/app.scss
index ce9f79c..3833241 100644
--- a/src/scss/app.scss
+++ b/src/scss/app.scss
@@ -429,6 +429,38 @@ td.trim-p p:last-child {
}
}
+.legacy-comment {
+ font-size: 14px !important;
+
+ .blog-author-icon {
+ height: 28px;
+ }
+
+ margin-bottom: 20px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .comment {
+ font-size: 14px !important;
+ margin-left: 30px;
+ background: #1d1d1d;
+ padding: 10px;
+ border-radius: 5px;
+
+ p:last-child {
+ margin-bottom: 0;
+ }
+
+ blockquote.blockquote {
+ font-size: 14px !important;
+ border-left: 3px solid #687a86;
+ padding-left: 15px;
+ }
+ }
+}
+
.mastodon-update-card.card {
background-color: desaturate(darken(#6364FF, 50%), 50%);
margin-bottom: 50px;