diff --git a/Wave/Components/ArticleLink.razor b/Wave/Components/ArticleLink.razor new file mode 100644 index 0000000..26b81ad --- /dev/null +++ b/Wave/Components/ArticleLink.razor @@ -0,0 +1,23 @@ +@using Wave.Data +@using System.Net +@using System.Web + + + @ChildContent + + +@code { + [Parameter] + public required Article Article { get; set; } + [Parameter] + public RenderFragment? ChildContent { get; set; } + + private string TitleEncoded => Uri.EscapeDataString(Article.Title.ToLowerInvariant()).Replace("-", "+").Replace("%20", "-"); + private string Link => + Article.PublishDate.Year >= 9999 + ? $"/article/{Article.Id}" + : $"/{Article.PublishDate.Year}/{Article.PublishDate.Month:D2}/{Article.PublishDate.Day:D2}/{TitleEncoded}"; + + [Parameter(CaptureUnmatchedValues = true)] + public Dictionary? AdditionalAttributes { get; set; } +} diff --git a/Wave/Components/ArticleTile.razor b/Wave/Components/ArticleTile.razor index dd7881b..b2eda89 100644 --- a/Wave/Components/ArticleTile.razor +++ b/Wave/Components/ArticleTile.razor @@ -1,16 +1,16 @@ @using Wave.Data - -
-
-

@Article.Title

- By @Article.Author.Name -

- @Article.Body -

-
-
-
+ +
+
+

@Article.Title

+ By @Article.Author.Name +

+ @Article.Body +

+
+
+
@code { [Parameter] diff --git a/Wave/Components/Pages/ArticleView.razor b/Wave/Components/Pages/ArticleView.razor index 2e0bd3f..d0c5762 100644 --- a/Wave/Components/Pages/ArticleView.razor +++ b/Wave/Components/Pages/ArticleView.razor @@ -1,11 +1,14 @@ @page "/article/{id:guid}" +@page "/{year:int:min(1)}/{month:int:range(1,12)}/{day:int:range(1,31)}/{titleEncoded}" @using Microsoft.EntityFrameworkCore @using Wave.Data @using System.Security.Claims @using System.Diagnostics.CodeAnalysis +@using System.Net +@using System.Web @using Microsoft.Extensions.Options -@inject IDbContextFactory ContextFactory; +@inject IDbContextFactory ContextFactory @inject NavigationManager Navigation @inject IOptions Customizations @inject IStringLocalizer Localizer @@ -71,9 +74,27 @@ [CascadingParameter(Name = "TitlePrefix")] private string TitlePrefix { get; set; } = default!; + #region Route Parameters + + [Parameter] + public Guid? Id { get; set; } + [Parameter] + public int? Year { get; set; } + [Parameter] + public int? Month { get; set; } + [Parameter] + public int? Day { get; set; } [Parameter] - public Guid Id { get; set; } - private Article? Article { get; set; } = default!; + public string? TitleEncoded { get; set; } + + private DateTimeOffset? Date => + Year is {} y && Month is {} m && Day is {} d + ? new DateTimeOffset(new DateTime(y, m, d)) : + null; + private string? Title => TitleEncoded is null ? null : Uri.UnescapeDataString(TitleEncoded.Replace("-", "%20").Replace("+", "-")); + + #endregion + private Article? Article { get; set; } private Article GetArticlePublic() { if (Article is null) throw new ApplicationException("Article not found."); @@ -111,13 +132,21 @@ } protected override void OnInitialized() { - // We need blocking calls here, bc otherwise Blazor will execute Render in parallel, - // running into a null pointer on the Article property and panicking - using var context = ContextFactory.CreateDbContext(); - Article = context.Set
() - .Include(a => a.Author) - .Include(a => a.Reviewer) - .FirstOrDefault(a => a.Id == Id); + // We need blocking calls here, bc otherwise Blazor will execute Render in parallel, + // running into a null pointer on the Article property and panicking + if (Id is not null) { + using var context = ContextFactory.CreateDbContext(); + Article = context.Set
() + .Include(a => a.Author) + .Include(a => a.Reviewer) + .FirstOrDefault(a => a.Id == Id); + } else if (Date is { } date && Title is { } title) { + using var context = ContextFactory.CreateDbContext(); + Article = context.Set
() + .Include(a => a.Author) + .Include(a => a.Reviewer) + .FirstOrDefault(a => a.PublishDate.Date == date.Date && a.Title.ToLower() == title); + } } private async Task SubmitForReview() { diff --git a/Wave/Components/Pages/Home.razor b/Wave/Components/Pages/Home.razor index 0d57411..cb0fcdf 100644 --- a/Wave/Components/Pages/Home.razor +++ b/Wave/Components/Pages/Home.razor @@ -20,26 +20,26 @@ } else { @if (Articles.FirstOrDefault() is {} featured) { - +
+ +
+
+
+

+ @featured.Title
+

+

+ @featured.PublishDate.ToString("g")
+ @featured.Body[..Math.Min(1000, featured.Body.Length)] +

+
+ +
+
+
+
+
+
} else {

@Localizer["NoArticles_Title"]

@Localizer["NoArticles_Message"]