From c0c8a65c5d655a54b509d97a999adc57def49149 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Sun, 15 Jun 2025 12:28:27 +0200 Subject: [PATCH] feat: New layout/design for the create or update blog post page --- .../ReadingTimeCalculator.cs | 8 +- .../Components/CreateNewBlogPost.razor | 353 +++++++++++++----- .../Components/CreateNewModel.cs | 4 +- 3 files changed, 262 insertions(+), 103 deletions(-) diff --git a/src/LinkDotNet.Blog.Domain/ReadingTimeCalculator.cs b/src/LinkDotNet.Blog.Domain/ReadingTimeCalculator.cs index 58459b99..40dca900 100644 --- a/src/LinkDotNet.Blog.Domain/ReadingTimeCalculator.cs +++ b/src/LinkDotNet.Blog.Domain/ReadingTimeCalculator.cs @@ -18,10 +18,7 @@ public static int CalculateReadingTime(string content) return (int)Math.Ceiling(readTimeWords + readTimeImages); } - [GeneratedRegex(@"!\[.*?\]\((.*?)\)")] - private static partial Regex ImageRegex(); - - private static int GetWordCount(ReadOnlySpan content) + public static int GetWordCount(ReadOnlySpan content) { var wordCount = 0; for (var i = 0; i < content.Length; i++) @@ -34,4 +31,7 @@ private static int GetWordCount(ReadOnlySpan content) return wordCount; } + + [GeneratedRegex(@"!\[.*?\]\((.*?)\)")] + private static partial Regex ImageRegex(); } diff --git a/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor b/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor index ad217d01..3866cd45 100644 --- a/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor +++ b/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor @@ -3,6 +3,7 @@ @using LinkDotNet.Blog.Infrastructure.Persistence @using LinkDotNet.Blog.Web.Features.Services @using NCronJob +@using System.Threading @inject IJSRuntime JSRuntime @inject ICacheInvalidator CacheInvalidator @inject IInstantJobRegistry InstantJobRegistry @@ -10,107 +11,236 @@ Creating new Blog Post -
-

@Title

- - -
- - - -
-
- - -
-
- - - -
- - -
-
-
- - - The primary image which will be used. - -
-
- - - - Optional: Used as a fallback if the preview image can't be used by the browser. -
For example using a jpg or png as fallback for avif which is not supported in Safari or Edge. -
- -
-
- - - - If set the blog post will be published at the given date. - A blog post with a schedule date can't be set to published. - All dates are stored in UTC internally. - - -
-
- -
- If this blog post is only draft or it will be scheduled, uncheck the box. - -
-
- - -
- @if (BlogPost is not null && !IsScheduled) - { -
- -
- - If set the publish date is set to now, - otherwise its original date. - -
- } -
- -
- The first page of the blog is cached. Therefore, the blog post is not immediately visible. - Head over to settings to invalidate the cache or enable the checkmark. -
- The option should be enabled if you want to publish the blog post immediately and it should be visible on the first page. -
-
- -
+
+ + + + + +
+
+
+
+
Content
+
+
+
+
+ + +
+ +
+ +
+ + + +
+ +
+ + + + +
+
+ + +
+
+
+
+
+
+ +
+
+
+
Quick Actions
+
+
+
+ +
+
+
+ +
+
+
Tags
+
+
+
+ + +
+ + Add relevant tags to improve content discoverability and SEO. Use specific, searchable terms that describe your content. + + @if (!string.IsNullOrWhiteSpace(model.Tags)) + { +
+ @foreach (var tag in model.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries)) + { + @tag.Trim() + } +
+ } +
+
+ +
+
+
Publishing & Visibility
+
+
+
+ + + + @(model.IsPublished ? "Visible to everyone" : "Only visible to you") + +
+ + +
+ +
+ + +
+ @if (IsScheduled) + { +
+ Will be published on @model.ScheduledPublishDate?.ToString("MMMM dd, yyyy 'at' HH:mm") +
+ } + +
+ + @if (BlogPost is not null && !IsScheduled) + { +
+ + + + Update the post's publication date to now + +
+ } +
+
+ +
+
+
Featured Image
+
+
+
+
+ + +
+ +
+
+
+ + +
+ +
+ + The fallback image ensures compatibility across all platforms. Use JPG or PNG format for maximum support when your primary image is WebP or AVIF. + +
+
+ +
+
+
Cache Management
+
+
+
+ + + + Make this post visible immediately on the homepage + +
+
+ Enable this to make your post immediately visible on the homepage after publishing. +
+
+
+
+
@@ -118,6 +248,7 @@ + @code { [Parameter] public BlogPost? BlogPost { get; set; } @@ -160,6 +291,34 @@ model = CreateNewModel.FromBlogPost(BlogPost); } + private string GetStatusText() + { + if (BlogPost != null) + { + return "Editing"; + } + + if (model.IsPublished) + { + return "Ready to Publish"; + } + + if (IsScheduled) + { + return "Scheduled"; + } + + return "Draft"; + } + + private int GetEstimatedReadTime() + { + if (string.IsNullOrWhiteSpace(model.Content)) + return 1; + + return ReadingTimeCalculator.CalculateReadingTime(model.Content); + } + private async Task OnValidBlogPostCreatedAsync() { canSubmit = false; diff --git a/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewModel.cs b/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewModel.cs index 0a71e1ff..d574c320 100644 --- a/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewModel.cs +++ b/src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewModel.cs @@ -67,8 +67,8 @@ public bool ShouldUpdateDate [FutureDateValidation] public DateTime? ScheduledPublishDate { - get => scheduledPublishDate?.ToLocalTime(); - set => SetProperty(out scheduledPublishDate, value?.ToUniversalTime()); + get => scheduledPublishDate; + set => SetProperty(out scheduledPublishDate, value); } public string Tags