Use YAML parser
This commit is contained in:
parent
ef1e976eda
commit
49457ff42f
|
@ -153,4 +153,4 @@
|
||||||
|
|
||||||
@section postfooter {
|
@section postfooter {
|
||||||
<img src="/files/help.svg" height="450rem" title="Designed by someone I love, ~fr2">
|
<img src="/files/help.svg" height="450rem" title="Designed by someone I love, ~fr2">
|
||||||
}
|
}
|
|
@ -37,4 +37,4 @@
|
||||||
<a href="https://music.apple.com/gb/album/%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-%E3%83%88%E3%83%A9%E3%83%99%E3%83%AB/1494424249">Apple Music</a>
|
<a href="https://music.apple.com/gb/album/%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-%E3%83%88%E3%83%A9%E3%83%99%E3%83%AB/1494424249">Apple Music</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
|
@ -52,4 +52,4 @@
|
||||||
</div>
|
</div>
|
||||||
<script src="~/js/site.js"></script>
|
<script src="~/js/site.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -1,40 +1,80 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Markdig;
|
using Markdig;
|
||||||
|
using Markdig.Extensions.Yaml;
|
||||||
|
using Markdig.Renderers;
|
||||||
|
using Markdig.Syntax;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
namespace zotanpw_web.Pages.blog;
|
namespace zotanpw_web.Pages.blog;
|
||||||
|
|
||||||
public class BlogModel : PageModel {
|
public class BlogModel : PageModel {
|
||||||
public static readonly List<BlogPost> Posts = new() {
|
public static readonly List<BlogPost> Posts = new();
|
||||||
new BlogPost("adhd-and-notes", "ADHD & Notetaking: an autistic perspective", DateOnly.Parse("2021-08-07")),
|
|
||||||
new BlogPost("ipv6-networking", "IPv6-native networking: a project report", DateOnly.Parse("2021-08-23"))
|
|
||||||
};
|
|
||||||
|
|
||||||
static BlogModel() {
|
static BlogModel() {
|
||||||
|
foreach (var file in Directory.EnumerateFiles("Pages/blog/posts"))
|
||||||
|
Posts.Add(new BlogPost(Path.GetFileNameWithoutExtension(file)));
|
||||||
|
|
||||||
Posts = Posts.OrderByDescending(p => p.PublishedOn).ToList();
|
Posts = Posts.OrderByDescending(p => p.PublishedOn).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnGet() { }
|
public void OnGet() { }
|
||||||
|
|
||||||
public class BlogPost {
|
public class BlogPost {
|
||||||
public readonly DateOnly PublishedOn;
|
public readonly string Shorthand;
|
||||||
public readonly string Shorthand;
|
public string Content = "";
|
||||||
public readonly string Title;
|
|
||||||
public string Content = "";
|
|
||||||
public int ReadTimeMinutes;
|
|
||||||
|
|
||||||
public BlogPost(string shorthand, string title, DateOnly publishedOn) {
|
public DateOnly PublishedOn;
|
||||||
Title = title;
|
public int ReadTimeMinutes;
|
||||||
PublishedOn = publishedOn;
|
public string Title = null!;
|
||||||
Shorthand = shorthand;
|
|
||||||
UpdateContent();
|
public BlogPost(string shorthand) {
|
||||||
|
Shorthand = shorthand;
|
||||||
|
UpdateContentAndMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateContent() {
|
public void UpdateContentAndMetadata() {
|
||||||
var markdownText = System.IO.File.ReadAllText($"Pages/blog/posts/{Shorthand}.md");
|
var markdownText = System.IO.File.ReadAllText($"Pages/blog/posts/{Shorthand}.md");
|
||||||
|
|
||||||
Content = Markdown.ToHtml(markdownText, new MarkdownPipelineBuilder().UseGenericAttributes().Build());
|
var parsed = ParseBlogPost(markdownText);
|
||||||
|
Title = parsed.metadata.Title!;
|
||||||
|
PublishedOn = parsed.metadata.Date;
|
||||||
ReadTimeMinutes = Regex.Matches(markdownText, @"\b\w+\b").Count / 150;
|
ReadTimeMinutes = Regex.Matches(markdownText, @"\b\w+\b").Count / 150;
|
||||||
|
Content = parsed.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (PostMetadata metadata, string html) ParseBlogPost(string markdown) {
|
||||||
|
var yaml = "";
|
||||||
|
|
||||||
|
var pipeline = new MarkdownPipelineBuilder().UseGenericAttributes().UseYamlFrontMatter().Build();
|
||||||
|
var writer = new StringWriter();
|
||||||
|
var renderer = new HtmlRenderer(writer);
|
||||||
|
pipeline.Setup(renderer);
|
||||||
|
|
||||||
|
var document = Markdown.Parse(markdown, pipeline);
|
||||||
|
var yamlBlock = document.Descendants<YamlFrontMatterBlock>().FirstOrDefault();
|
||||||
|
|
||||||
|
if (yamlBlock != null)
|
||||||
|
yaml = markdown.Substring(yamlBlock.Span.Start, yamlBlock.Span.Length);
|
||||||
|
|
||||||
|
renderer.Render(document);
|
||||||
|
writer.Flush();
|
||||||
|
var html = writer.ToString();
|
||||||
|
|
||||||
|
var yamlDeserializer = new DeserializerBuilder().WithNamingConvention(LowerCaseNamingConvention.Instance).Build();
|
||||||
|
var metadata = yamlDeserializer.Deserialize<PostMetadata>(yaml);
|
||||||
|
|
||||||
|
return (metadata, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Local")]
|
||||||
|
private class PostMetadata {
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
public string? Title;
|
||||||
|
public DateOnly Date;
|
||||||
|
#pragma warning restore CS0649
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
ViewData["title"] = "blog";
|
ViewData["title"] = "blog";
|
||||||
ViewData["subtitle"] = post.Shorthand;
|
ViewData["subtitle"] = post.Shorthand;
|
||||||
#if (DEBUG)
|
#if (DEBUG)
|
||||||
post.UpdateContent();
|
post.UpdateContentAndMetadata();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,4 +20,4 @@
|
||||||
<h1 id="post">IPv6-native networking: a project report</h1>
|
<h1 id="post">IPv6-native networking: a project report</h1>
|
||||||
<div align="justify">
|
<div align="justify">
|
||||||
@Html.Raw(post.Content)
|
@Html.Raw(post.Content)
|
||||||
</div>
|
</div>
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
title: "ADHD & Notetaking: an autistic perspective"
|
||||||
|
date: 2021-08-07
|
||||||
|
...
|
||||||
If you are living with ADHD, diagnosed or not, the following things
|
If you are living with ADHD, diagnosed or not, the following things
|
||||||
might sound familiar: *"I forgot to write that down"*, *"I forgot to do
|
might sound familiar: *"I forgot to write that down"*, *"I forgot to do
|
||||||
that"*, *"I don't remember that"*.
|
that"*, *"I don't remember that"*.
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
---
|
||||||
|
title: "IPv6-native networking: a project report"
|
||||||
|
date: 2021-08-23
|
||||||
|
...
|
||||||
If you have reached this post, chances are you already know my [AS211579](https://zotan.network){target="_blank"}
|
If you have reached this post, chances are you already know my [AS211579](https://zotan.network){target="_blank"}
|
||||||
project.
|
project.
|
||||||
This post serves as a summary of the things I learnt and the roadblocks
|
This post serves as a summary of the things I learnt and the roadblocks
|
||||||
|
|
|
@ -38,4 +38,4 @@ public class LogPlayback : Controller {
|
||||||
Response.StatusCode = 403;
|
Response.StatusCode = 403;
|
||||||
return null!;
|
return null!;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,4 +5,4 @@ public class LogPlaybackRequest {
|
||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string? Source { get; set; }
|
public string? Source { get; set; }
|
||||||
public string? Link { get; set; }
|
public string? Link { get; set; }
|
||||||
}
|
}
|
|
@ -42,4 +42,4 @@ app.UseAuthorization();
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
|
@ -18,7 +18,7 @@ public class Travelynx : Controller {
|
||||||
db.InsertWithIdentity(new TravelynxInfo { CheckedIn = false });
|
db.InsertWithIdentity(new TravelynxInfo { CheckedIn = false });
|
||||||
|
|
||||||
var status = db.TravelynxInfo.First();
|
var status = db.TravelynxInfo.First();
|
||||||
status.CheckedIn = rq.Status.CheckedIn;
|
status.CheckedIn = rq.Status!.CheckedIn;
|
||||||
status.Train = $"{rq.Status.Train?.Type} {rq.Status.Train?.No}";
|
status.Train = $"{rq.Status.Train?.Type} {rq.Status.Train?.No}";
|
||||||
status.Destination = rq.Status.ToStation?.Name;
|
status.Destination = rq.Status.ToStation?.Name;
|
||||||
db.Update(status);
|
db.Update(status);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
namespace zotanpw_web.Travelynx;
|
namespace zotanpw_web.Travelynx;
|
||||||
|
|
||||||
public class WebhookRequest {
|
public class WebhookRequest {
|
||||||
public string Reason { get; set; }
|
public string? Reason { get; set; }
|
||||||
public Status Status { get; set; }
|
public Status? Status { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Status {
|
public class Status {
|
||||||
|
@ -38,4 +38,4 @@ public class Train {
|
||||||
public string? Line { get; set; }
|
public string? Line { get; set; }
|
||||||
public string? No { get; set; }
|
public string? No { get; set; }
|
||||||
public string? Id { get; set; }
|
public string? Id { get; set; }
|
||||||
}
|
}
|
|
@ -12,4 +12,4 @@ public class AlbumHistoryEntry {
|
||||||
[Column(Name = "Title"), NotNull] public string Title { get; set; }
|
[Column(Name = "Title"), NotNull] public string Title { get; set; }
|
||||||
[Column(Name = "Source"), NotNull] public string Source { get; set; }
|
[Column(Name = "Source"), NotNull] public string Source { get; set; }
|
||||||
[Column(Name = "Link")] public string Link { get; set; }
|
[Column(Name = "Link")] public string Link { get; set; }
|
||||||
}
|
}
|
|
@ -12,4 +12,4 @@ public class PlaylistHistoryEntry {
|
||||||
[Column(Name = "Title"), NotNull] public string Title { get; set; }
|
[Column(Name = "Title"), NotNull] public string Title { get; set; }
|
||||||
[Column(Name = "Source"), NotNull] public string Source { get; set; }
|
[Column(Name = "Source"), NotNull] public string Source { get; set; }
|
||||||
[Column(Name = "Link")] public string Link { get; set; }
|
[Column(Name = "Link")] public string Link { get; set; }
|
||||||
}
|
}
|
|
@ -8,4 +8,4 @@ public class TravelynxInfo {
|
||||||
[Column(Name = "CheckedIn"), NotNull] public bool CheckedIn { get; set; }
|
[Column(Name = "CheckedIn"), NotNull] public bool CheckedIn { get; set; }
|
||||||
[Column(Name = "Train")] public string? Train { get; set; }
|
[Column(Name = "Train")] public string? Train { get; set; }
|
||||||
[Column(Name = "Destination")] public string? Destination { get; set; }
|
[Column(Name = "Destination")] public string? Destination { get; set; }
|
||||||
}
|
}
|
|
@ -6,4 +6,4 @@ namespace zotanpw_web.well_known;
|
||||||
public class Pronouns : Controller {
|
public class Pronouns : Controller {
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public string Get() => "she/they\n";
|
public string Get() => "she/they\n";
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" width="500mm" height="400mm"
|
<svg xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" width="500mm" height="400mm"
|
||||||
version="1.1" viewBox="0 0 500 400"
|
version="1.1" viewBox="0 0 500 400"
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<metadata>
|
<metadata>
|
||||||
|
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
|
@ -66,6 +66,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.0"/>
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.0"/>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.0"/>
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.0"/>
|
||||||
<PackageReference Include="System.Data.SQLite" Version="1.0.115"/>
|
<PackageReference Include="System.Data.SQLite" Version="1.0.115"/>
|
||||||
|
<PackageReference Include="YamlDotNet" Version="12.0.2"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in a new issue