feat: add individual post page (#4)
* chore: add markdown lint to ignore no h1 heading in markdown files * chore: update example settings * chore: update example development env file * fix: remove fixed 100% height on container * feat: add individual post page * chore: update README.md * feat: add links to headings in post and add copy button to code blocks * tests: add tests for get post async method * tests: remove heading for test blogs * fix: only add links to headings in markdown body * tests: add tests for post page * tests: add test to check for blog content * docs: add jsdoc comments * chore: fix incorrect env variable format in example * fix: don't render anything if blog post is null * fix: don't render anything until posts are fetched * chore: add docker compose file for prod
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
@page "/{slug:nonfile}"
|
||||
@implements IAsyncDisposable
|
||||
@inject IPostService PostService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject ILogger<Post> Logger
|
||||
|
||||
@if (BlogPost is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
<PageTitle>@BlogPost.Title - journal</PageTitle>
|
||||
|
||||
<HeadContent>
|
||||
<meta name="description" content="@BlogPost.Lead">
|
||||
<link rel="stylesheet" href="markdown.css">
|
||||
<link rel="stylesheet" href="prism.css">
|
||||
<script src="prism.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js"></script>
|
||||
</HeadContent>
|
||||
|
||||
<article>
|
||||
<div class="heading-container">
|
||||
<h2>@BlogPost.Title</h2>
|
||||
<p>@BlogPost.PublishedAt.ToString("MMMM d, yyyy")</p>
|
||||
</div>
|
||||
<div class="markdown-body">
|
||||
@((MarkupString)BlogPost.Content)
|
||||
</div>
|
||||
</article>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string Slug { get; set; } = string.Empty;
|
||||
private PostWithContent? BlogPost;
|
||||
private IJSObjectReference? module;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var post = await PostService.GetPostAsync(Slug);
|
||||
|
||||
if (post is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("/Error/404");
|
||||
return;
|
||||
}
|
||||
|
||||
BlogPost = post;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Components/Pages/Post.razor.js");
|
||||
await module.InvokeVoidAsync("addAnchors");
|
||||
await module.InvokeVoidAsync("addClipboard");
|
||||
}
|
||||
}
|
||||
|
||||
async ValueTask IAsyncDisposable.DisposeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (module is not null)
|
||||
{
|
||||
await module.DisposeAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is JSDisconnectedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error disposing of the module");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user