feat: use Handlebars to render template excerpt card
This commit is contained in:
parent
3868fcbaa8
commit
217c1d660e
@ -1,9 +1,5 @@
|
||||
@page
|
||||
@using Humanizer
|
||||
@using OliverBooth.Data.Blog
|
||||
@using OliverBooth.Services
|
||||
@model OliverBooth.Pages.Blog.Index
|
||||
@inject BlogService BlogService
|
||||
|
||||
<div id="all-blog-posts">
|
||||
<div id="blog-loading-spinner" class="d-flex justify-content-center">
|
||||
@ -13,67 +9,33 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach (BlogPost post in ArraySegment<BlogPost>.Empty /*BlogService.AllPosts*/)
|
||||
{
|
||||
BlogService.TryGetAuthor(post, out Author? author);
|
||||
DateTimeOffset published = post.Published;
|
||||
DateTimeOffset timestamp = post.Updated ?? published;
|
||||
bool isUpdated = post.Updated.HasValue;
|
||||
var year = published.ToString("yyyy");
|
||||
var month = published.ToString("MM");
|
||||
var day = published.ToString("dd");
|
||||
<script id="blog-post-template" type="text/x-handlebars-template">
|
||||
<div class="card-body">
|
||||
<h2>
|
||||
<a href="{{post.url}}"> {{post.title}}</a>
|
||||
</h2>
|
||||
|
||||
<div class="card blog-card" style="margin-bottom: 50px;">
|
||||
<div class="card-body">
|
||||
<h2>
|
||||
<a asp-page="/blog/article"
|
||||
asp-route-year="@year"
|
||||
asp-route-month="@month"
|
||||
asp-route-day="@day"
|
||||
asp-route-slug="@post.Slug">
|
||||
@post.Title
|
||||
<p class="text-muted">
|
||||
<img class="blog-author-icon" src="{{author.avatar}}" alt="{{author.name}}">
|
||||
<span>{{author.name}}<span>
|
||||
<span> • </span>
|
||||
<span title="{{ post.date }}">{{ post.date_humanized }}</span>
|
||||
{{#if post.enable_comments}}
|
||||
<span> • </span>
|
||||
<a href="{{post.url}}#disqus_thread" data-disqus-identifier="{{post.disqus_identifier}}">
|
||||
0 Comments
|
||||
</a>
|
||||
</h2>
|
||||
{{/if}}
|
||||
</p>
|
||||
|
||||
<p class="text-muted">
|
||||
<img class="blog-author-icon" src="https://gravatar.com/avatar/@author?.AvatarHash?s=28" alt="@author?.Name">
|
||||
@author?.Name •
|
||||
<p>{{{post.excerpt}}}</p>
|
||||
|
||||
<abbr data-bs-toggle="tooltip" data-bs-title="@timestamp.ToString("f")">
|
||||
@(isUpdated ? "Updated" : "Published") @timestamp.Humanize()
|
||||
</abbr>
|
||||
|
||||
@if (post.EnableComments)
|
||||
{
|
||||
<span> •</span>
|
||||
<a asp-page="/blog/article"
|
||||
asp-fragment="disqus_thread"
|
||||
asp-route-year="@year"
|
||||
asp-route-month="@month"
|
||||
asp-route-day="@day"
|
||||
asp-route-slug="@post.Slug"
|
||||
data-disqus-identifier="@post.GetDisqusIdentifier()">
|
||||
0 Comments
|
||||
</a>
|
||||
}
|
||||
{{#if post.trimmed}}
|
||||
<p>
|
||||
<a href="{{post.url}}">
|
||||
Read more...
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>@Html.Raw(BlogService.GetExcerpt(post, out bool trimmed))</p>
|
||||
|
||||
@if (trimmed)
|
||||
{
|
||||
<p>
|
||||
<a asp-page="/blog/article"
|
||||
asp-route-year="@year"
|
||||
asp-route-month="@month"
|
||||
asp-route-day="@day"
|
||||
asp-route-slug="@post.Slug">
|
||||
Read more...
|
||||
</a>
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<script id="dsq-count-scr" src="https://oliverbooth-dev.disqus.com/count.js" async></script>
|
||||
}
|
||||
</script>
|
@ -2,6 +2,10 @@
|
||||
public static get blogPostContainer(): HTMLDivElement {
|
||||
return document.querySelector("#all-blog-posts");
|
||||
}
|
||||
|
||||
public static get blogPostTemplate(): HTMLDivElement {
|
||||
return document.querySelector("#blog-post-template");
|
||||
}
|
||||
}
|
||||
|
||||
export default UI;
|
@ -4,10 +4,12 @@ import UI from "./UI";
|
||||
|
||||
declare const bootstrap: any;
|
||||
declare const katex: any;
|
||||
declare const Handlebars: any;
|
||||
|
||||
(() => {
|
||||
const blogPostContainer = UI.blogPostContainer;
|
||||
if (blogPostContainer) {
|
||||
const template = Handlebars.compile(UI.blogPostTemplate.innerHTML);
|
||||
API.getBlogPostCount().then(async (count) => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
const posts = await API.getBlogPosts(i, 5);
|
||||
@ -21,63 +23,23 @@ declare const katex: any;
|
||||
card.classList.add("animate__fadeIn");
|
||||
card.style.marginBottom = "50px";
|
||||
|
||||
const cardBody = document.createElement("div");
|
||||
cardBody.classList.add("card-body");
|
||||
card.appendChild(cardBody);
|
||||
|
||||
const postTitle = document.createElement("h2");
|
||||
postTitle.classList.add("card-title");
|
||||
cardBody.appendChild(postTitle);
|
||||
|
||||
const titleLink = document.createElement("a");
|
||||
titleLink.href = post.url;
|
||||
titleLink.innerText = post.title;
|
||||
postTitle.appendChild(titleLink);
|
||||
|
||||
const metadata = document.createElement("p");
|
||||
metadata.classList.add("text-muted");
|
||||
cardBody.appendChild(metadata);
|
||||
|
||||
const authorIcon = document.createElement("img");
|
||||
authorIcon.classList.add("blog-author-icon");
|
||||
authorIcon.src = `https://gravatar.com/avatar/${author.avatarHash}?s=28`;
|
||||
authorIcon.alt = author.name;
|
||||
metadata.appendChild(authorIcon);
|
||||
|
||||
const authorName = document.createElement("span");
|
||||
authorName.innerHTML = ` ${author.name} • `;
|
||||
metadata.appendChild(authorName);
|
||||
|
||||
const postDate = document.createElement("span");
|
||||
if (post.updated) {
|
||||
postDate.innerHTML = `Updated ${TimeUtility.formatRelativeTimestamp(post.updated)}`;
|
||||
} else {
|
||||
postDate.innerHTML = `Published ${TimeUtility.formatRelativeTimestamp(post.published)}`;
|
||||
}
|
||||
metadata.appendChild(postDate);
|
||||
|
||||
if (post.commentsEnabled) {
|
||||
const bullet = document.createElement("span");
|
||||
bullet.innerHTML = " • ";
|
||||
metadata.appendChild(bullet);
|
||||
|
||||
const commentCount = document.createElement("a");
|
||||
commentCount.href = post.url + "#disqus_thread";
|
||||
commentCount.innerHTML = "0 Comments";
|
||||
commentCount.setAttribute("data-disqus-identifier", post.identifier);
|
||||
metadata.appendChild(commentCount);
|
||||
}
|
||||
|
||||
const postExcerpt = document.createElement("p");
|
||||
postExcerpt.innerHTML = post.excerpt;
|
||||
cardBody.appendChild(postExcerpt);
|
||||
|
||||
if (post.trimmed) {
|
||||
const readMoreLink = document.createElement("a");
|
||||
readMoreLink.href = post.url;
|
||||
readMoreLink.innerHTML = "Read more …";
|
||||
cardBody.appendChild(readMoreLink);
|
||||
}
|
||||
const body = template({
|
||||
post: {
|
||||
title: post.title,
|
||||
excerpt: post.excerpt,
|
||||
url: post.url,
|
||||
date: TimeUtility.formatRelativeTimestamp(post.published),
|
||||
date_humanized: `${post.updated ? "Updated" : "Published"} ${post.humanizedTimestamp}`,
|
||||
enable_comments: post.commentsEnabled,
|
||||
disqus_identifier: post.identifier,
|
||||
trimmed: post.trimmed,
|
||||
},
|
||||
author: {
|
||||
name: author.name,
|
||||
avatar: `https://gravatar.com/avatar/${author.avatarHash}?s=28`,
|
||||
}
|
||||
});
|
||||
card.innerHTML = body.trim();
|
||||
|
||||
blogPostContainer.appendChild(card);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user