Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 6a2e5be

Browse files
Preload blog posts on current page
1 parent 5c88a2e commit 6a2e5be

14 files changed

Lines changed: 152 additions & 29 deletions

File tree

.github/dependabot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ updates:
66
schedule:
77
interval: "daily"
88
groups:
9-
web:
9+
nuget:
1010
patterns:
1111
- "*"
1212
- package-ecosystem: "github-actions"
1313
directory: "/"
1414
schedule:
1515
interval: "daily"
1616
groups:
17-
pipeline:
17+
actions:
1818
patterns:
1919
- "*"

Home/App.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
</div>
1919
<br />
2020
<div style="display: flex; justify-content: space-around;">
21-
<Button OnClick="() => NavigateHome()">Return home</Button>
21+
<LinkButton Href="/">Return home</LinkButton>
2222
</div>
2323
</Box>
2424
</Row>

Home/App.razor.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
using System;
2-
using Microsoft.AspNetCore.Components;
3-
41
namespace Home;
52

6-
public partial class App(NavigationManager navManager)
7-
{
8-
private void NavigateHome()
9-
{
10-
navManager.NavigateTo("/");
11-
}
12-
}
3+
public partial class App;

Home/Components/Box.razor.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ namespace Home.Components;
55

66
public partial class Box : ComponentBase
77
{
8+
/// <summary>
9+
/// The title of the box, by default rendered as an H2 element.
10+
/// </summary>
811
[Parameter]
912
public required string Title { get; set; }
1013

Home/Components/Button.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<a @onclick="OnClick" class="button @(Disabled ? "disabled" : string.Empty)">
1+
<button @onmousedown="OnMouseDownAsync" class="button @(Disabled ? "disabled" : string.Empty)">
22
@ChildContent
3-
</a>
3+
</button>

Home/Components/Button.razor.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
21
using Microsoft.AspNetCore.Components;
2+
using Microsoft.AspNetCore.Components.Web;
33

44
namespace Home.Components;
55

@@ -9,8 +9,26 @@ public partial class Button : ComponentBase
99
public required RenderFragment ChildContent { get; set; }
1010

1111
[Parameter]
12-
public required EventCallback OnClick { get; set; }
12+
public required EventCallback OnLeftClickCallback { get; set; }
13+
14+
[Parameter]
15+
public EventCallback OnMiddleClickCallback { get; set; } = new();
1316

1417
[Parameter]
1518
public bool Disabled { get; set; } = false;
19+
20+
private async Task OnMouseDownAsync(EventArgs e)
21+
{
22+
if (!Disabled && e is MouseEventArgs mouseEventArgs)
23+
{
24+
Task task = mouseEventArgs.Button switch
25+
{
26+
0 => OnLeftClickCallback.InvokeAsync(), // Left
27+
1 => OnMiddleClickCallback.InvokeAsync(), // Middle
28+
_ => Task.CompletedTask
29+
};
30+
31+
await task;
32+
}
33+
}
1634
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using Microsoft.AspNetCore.Components;
3+
using Microsoft.JSInterop;
4+
5+
namespace Home.Components;
6+
7+
public partial class LinkButton : Button
8+
{
9+
/// <summary>
10+
/// The URL to navigate to when the button is clicked.
11+
/// </summary>
12+
[Parameter]
13+
[Url(ErrorMessage = "Must be a valid URL.")]
14+
public required string Href { get; set; }
15+
16+
private readonly NavigationManager navManager;
17+
private readonly IJSRuntime jSRuntime;
18+
19+
public LinkButton(NavigationManager navManager, IJSRuntime jSRuntime)
20+
{
21+
this.navManager = navManager;
22+
this.jSRuntime = jSRuntime;
23+
24+
OnLeftClickCallback = EventCallback.Factory.Create(this, OnClick);
25+
OnMiddleClickCallback = EventCallback.Factory.Create(this, OnMiddleClickAsync);
26+
}
27+
28+
protected void OnClick()
29+
{
30+
if (!Disabled)
31+
{
32+
navManager.NavigateTo(Href);
33+
}
34+
}
35+
36+
protected async Task OnMiddleClickAsync()
37+
{
38+
if (!Disabled)
39+
{
40+
await jSRuntime.InvokeVoidAsync("open", Href, "_blank");
41+
}
42+
}
43+
}

Home/Models/BlogPostMetaData.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ public class BlogPostMetaData
1616
public DateTimeOffset LastUpdatedDate { get; set; }
1717

1818
public string? ImageUrl { get; set; }
19+
20+
public Dictionary<DateOnly, string>? Edits { get; set; }
1921
}

Home/Pages/Blog/Index.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<Box Title="@post.Title" Date="@post.PublishedDate">
3333
<p>@((MarkupString)post.Excerpt)</p>
3434

35-
<Button OnClick="() => NavigateToPost(post.Slug)">Read More</Button>
35+
<LinkButton Href="@GetPostUrlFromSlug(post.Slug)">Read More</LinkButton>
3636
</Box>
3737
</Row>
3838
}
@@ -42,10 +42,10 @@
4242
@if (BlogPosts != null && BlogPosts.Count() > PostsPerPage)
4343
{
4444
<Row>
45-
<Button OnClick="NavigateToPreviousPage" Disabled="CurrentPage <= 0">Prev</Button>
45+
<Button OnLeftClickCallback="NavigateToPreviousPage" Disabled="CurrentPage <= 0">Prev</Button>
4646

4747
<!-- TODO: Add page selection here -->
4848

49-
<Button OnClick="NavigateToNextPage" Disabled="CurrentPage >= TotalPages - 1">Next</Button>
49+
<Button OnLeftClickCallback="NavigateToNextPage" Disabled="CurrentPage >= TotalPages - 1">Next</Button>
5050
</Row>
5151
}

Home/Pages/Blog/Index.razor.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,22 @@ public partial class Index(NavigationManager navManager, BlogPostService blogPos
1818

1919
protected IOrderedEnumerable<BlogPostMetaData>? BlogPosts { get; set; }
2020

21-
protected override async void OnInitialized()
21+
protected override async Task OnInitializedAsync()
2222
{
2323
BlogPosts = await blogPostService.GetPosts();
24+
await PreloadCurrentPagePosts();
2425

2526
await InvokeAsync(StateHasChanged);
2627
base.OnInitialized();
2728
}
2829

30+
protected override async Task OnParametersSetAsync()
31+
{
32+
await PreloadCurrentPagePosts();
33+
34+
await base.OnParametersSetAsync();
35+
}
36+
2937
public void NavigateToPage(int page)
3038
{
3139
if (page < TotalPages || page > 0)
@@ -50,8 +58,22 @@ public void NavigateToPreviousPage()
5058
}
5159
}
5260

53-
public void NavigateToPost(string slug)
61+
public static string GetPostUrlFromSlug(string slug)
5462
{
55-
navManager.NavigateTo(SiteUrls.BlogPost.Replace(SiteUrls.POST_SLUG_PARAM, slug));
63+
return SiteUrls.BlogPost.Replace(SiteUrls.POST_SLUG_PARAM, slug);
64+
}
65+
66+
private async Task PreloadCurrentPagePosts()
67+
{
68+
if (BlogPosts is null)
69+
{
70+
return;
71+
}
72+
73+
int startIndex = CurrentPage * PostsPerPage;
74+
int endIndex = Math.Min(startIndex + PostsPerPage, BlogPosts.Count());
75+
76+
IEnumerable<string> slugsToPreload = BlogPosts.Skip(startIndex).Take(endIndex - startIndex).Select(x => x.Slug);
77+
await blogPostService.PreloadPostMarkdown(slugsToPreload);
5678
}
5779
}

0 commit comments

Comments
 (0)