Skip to content

Commit 8c55a2a

Browse files
committed
Preliminarily finished Category and Tags pages. Spiced the post list up a bit.
1 parent 61f989e commit 8c55a2a

10 files changed

Lines changed: 86 additions & 24 deletions

File tree

Source/Dove.Blog.Data/Models/PostSummary.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public class PostSummary
55
public required string Title { get; set; }
66
public required string Slug { get; set; }
77
public string? Summary { get; set; }
8+
public string[]? Categories { get; set; }
89
public required string Author { get; set; }
910
public required DateTimeOffset Posted { get; set; }
1011
public DateTimeOffset? Updated { get; set; }

Source/Dove.Blog.Logic/BlogProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ public async Task<IEnumerable<PostSummary>> GetPosts(string? category = null, pa
9999
.ToList();
100100
}
101101

102-
if (tags.Length > 0)
102+
if (tags.Where(x => !string.IsNullOrEmpty(x)).Any())
103103
{
104-
posts = posts.Where(p => p.Tags!.Any(t => tags.Contains(t)))
104+
posts = posts.Where(p => p.Tags?.Any(t => tags.Contains(t)) ?? false)
105105
.ToList();
106106
}
107107

@@ -115,7 +115,8 @@ public async Task<IEnumerable<PostSummary>> GetPosts(string? category = null, pa
115115
Summary = p.Summary ?? _htmlRegex.Replace(brief + " ...", string.Empty),
116116
Author = p.Author,
117117
Posted = p.Posted,
118-
Updated = p.Updated
118+
Updated = p.Updated,
119+
Categories = p.Categories
119120
};
120121
});
121122

Source/Dove.Blog.WebApp/Components/Layout/MainLayout.razor

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@inject IHostEnvironment HostEnvironment
12
@inherits LayoutComponentBase
23

34
<div class="page">
@@ -31,7 +32,14 @@
3132
</div>
3233

3334
<div id="blazor-error-ui" data-nosnippet>
34-
An unhandled error has occurred.
35+
@if (HostEnvironment.IsProduction())
36+
{
37+
<span>An error has occurred.</span>
38+
}
39+
else
40+
{
41+
<span>An unhandled exception occurred.</span>
42+
}
3543
<a href="." class="reload">Reload</a>
3644
<span class="dismiss">🗙</span>
3745
</div>

Source/Dove.Blog.WebApp/Components/Pages/Blog.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ else
2424
}
2525
else
2626
{
27-
<BlogPostList Posts="@Posts" />
27+
<BlogPostList ListTitle="@ListTitle" Posts="@Posts" />
2828
}
2929
</div>
3030

Source/Dove.Blog.WebApp/Components/Pages/Blog.razor.cs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class BlogPage : ComponentBase
1919
public string? PreviousSlug { get; set; } = null;
2020
public string? NextSlug { get; set; } = null;
2121
public string? Title { get; private set; }
22+
public string? ListTitle { get; private set; }
2223
public MarkupString? PageContent { get; private set; }
2324
public Post? CurrentPost { get; set; }
2425

@@ -31,6 +32,8 @@ protected override async Task OnInitializedAsync()
3132
IsLoading = true;
3233
try
3334
{
35+
NavigationManager.LocationChanged += NavigationManager_LocationChanged;
36+
3437
Categories = (await BlogProvider.GetCategories());
3538
Tags = await BlogProvider.GetTags();
3639

@@ -49,6 +52,11 @@ protected override async Task OnInitializedAsync()
4952
await base.OnInitializedAsync();
5053
}
5154

55+
private void NavigationManager_LocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
56+
{
57+
Logger.LogInformation(e.Location);
58+
}
59+
5260
protected MarkupString GetCategories()
5361
{
5462
var categories = CurrentPost?.Categories?.Select(x => $"<a href=\"/Blog/Categories/{x}\">{x}</a>") ?? Enumerable.Empty<string>();
@@ -86,8 +94,22 @@ protected override async Task OnParametersSetAsync()
8694
private async Task LoadPageData()
8795
{
8896
PageContent = null;
89-
Posts = await BlogProvider.GetPosts();
97+
Posts = await BlogProvider.GetPosts(Category, Tag!);
9098
Posts = Posts.OrderByDescending(x => x.Posted);
99+
100+
if (!string.IsNullOrEmpty(Category))
101+
{
102+
ListTitle = $"Posts by category '{Category}'";
103+
}
104+
else if (!string.IsNullOrEmpty(Tag))
105+
{
106+
ListTitle = $"Posts by tag '{Tag}'";
107+
}
108+
else
109+
{
110+
ListTitle = "All Posts";
111+
}
112+
91113
if (!string.IsNullOrEmpty(Slug))
92114
{
93115
try
@@ -97,17 +119,17 @@ private async Task LoadPageData()
97119
Title = CurrentPost.Title;
98120
CurrentSlug = Slug;
99121

100-
var index = 0;
122+
var index = 0;
101123
var indexedPosts = Posts.ToDictionary(x => index++, x => x);
102124
var currentPost = indexedPosts.FirstOrDefault(x => x.Value.Slug.Equals(Slug, StringComparison.InvariantCultureIgnoreCase));
103125
var currentIndex = currentPost.Key;
104126

105127
PreviousSlug = currentIndex < Posts.Count() - 1 && currentIndex >= 0 ? indexedPosts[currentIndex + 1].Slug : null;
106-
NextSlug = currentIndex > 0 ? indexedPosts[currentIndex - 1].Slug : null;
128+
NextSlug = currentIndex > 0 ? indexedPosts[currentIndex - 1].Slug : null;
107129
}
108130
catch (FileNotFoundException ex)
109131
{
110-
Console.WriteLine(ex.Message);
132+
Logger.LogError(ex, "LoadPageData");
111133
NavigationManager.NavigateTo("/");
112134
}
113135
}

Source/Dove.Blog.WebApp/Components/Parts/BlogPostList.razor

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
11
@inherits BlogPostListBase
22

3-
<h2>Latest Blog Posts</h2>
3+
<h2>@ListTitle</h2>
4+
45
@foreach (var post in Posts.Take(10))
56
{
6-
<div class="card mb-3 shadow p-2">
7-
<h3><a href="/Blog/@post.Slug">@post.Title</a></h3>
8-
<p>@post.Summary</p>
9-
<a href="/Blog/@post.Slug">Read more...</a>
7+
<div class="card shadow mb-3">
8+
9+
<div class="row g-0">
10+
11+
<div class="col-2">
12+
<div class="rounded-start bg-info-subtle p-3 h-100">
13+
<p><b>Posted on:</b><br /> @post.Posted.ToString("d")</p>
14+
<p><b>Posted by:</b><br /> @post.Author</p>
15+
<p><b>Categories:</b><br /> @(string.Join(", ", post.Categories))</p>
16+
</div>
17+
</div>
18+
19+
<div class="col-10 p-2">
20+
<h3 class="card-title"><a href="/Blog/@post.Slug">@post.Title</a></h3>
21+
<div class="card-body">
22+
<p>@post.Summary</p>
23+
<p><a href="/Blog/@post.Slug">Read more...</a></p>
24+
</div>
25+
</div>
26+
</div>
1027
</div>
1128
}
1229

Source/Dove.Blog.WebApp/Components/Parts/BlogPostList.razor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
namespace Dove.Blog.WebApp.Components.Parts;
55
public partial class BlogPostListBase : ComponentBase
66
{
7+
[Parameter] public string ListTitle { get; set; } = string.Empty;
78
[Parameter] public IEnumerable<PostSummary> Posts { get; set; } = null!;
89
}

Source/Dove.Blog.WebApp/Dove.Blog.WebApp.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.3" />
11+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
1212
<PackageReference Include="Serilog" Version="4.2.0" />
1313
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
1414
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.1" />
1515
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
16-
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
17-
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.0" />
16+
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
17+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" />
1818
<PackageReference Include="Westwind.AspNetCore.Markdown" Version="3.23.0" />
1919
</ItemGroup>
2020

Source/Dove.Blog.WebApp/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010

1111
Log.Logger = new LoggerConfiguration()
1212
.WriteTo.Console()
13+
.WriteTo.File("Data/Logs/log.txt", Serilog.Events.LogEventLevel.Verbose, rollingInterval: RollingInterval.Day)
1314
.CreateLogger();
1415

1516
try
1617
{
1718
var builder = WebApplication.CreateBuilder(args);
18-
1919
builder.Services.AddSerilog();
2020

2121
// Bind configuration section to MySettings and register it as a singleton service
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
{
2-
"Logging": {
3-
"LogLevel": {
4-
"Default": "Information",
5-
"Microsoft.AspNetCore": "Warning"
2+
"Serilog": {
3+
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
4+
"MinimumLevel": "Debug",
5+
"WriteTo": [
6+
{ "Name": "Console" },
7+
{
8+
"Name": "File",
9+
"Args": { "path": "Data/Logs/log.txt" }
10+
}
11+
],
12+
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
13+
},
14+
15+
"AllowedHosts": "*",
16+
17+
"CacheSettings": {
18+
"SizeLimit": 100,
19+
"ExpirationScanFrequency": "00:00:30"
620
}
7-
},
8-
"AllowedHosts": "*"
921
}

0 commit comments

Comments
 (0)