Implement basic Chorus comment rendering for blog posts

This commit is contained in:
Garrett Mills 2025-01-04 05:02:05 -05:00
parent eed21b9097
commit d6ada9a222
5 changed files with 183 additions and 1 deletions

View File

@ -15,6 +15,10 @@ export default {
forceSsl: env('SERVER_FORCE_SSL', false),
chorus: {
baseUrl: env('CHORUS_BASE_URL'),
},
session: {
/* The implementation of @extollo/lib.Session that serves as the session backend. */
driver: ORMSession,

View File

@ -1,4 +1,4 @@
import {Controller, view, Inject, Injectable, collect, plaintext} from '@extollo/lib'
import {Controller, view, Inject, Injectable, collect, plaintext, Config} from '@extollo/lib'
import {Home} from './Home.controller'
import {Blog as BlogService} from '../../services/Blog.service'
import {BlogPost} from '../../services/blog/AbstractBlog.service'
@ -13,6 +13,9 @@ export class Blog extends Controller {
@Inject()
protected readonly blog!: BlogService
@Inject()
protected readonly config!: Config
public async index() {
const home = <Home> this.make(Home)
const posts = await this.blog.getAllPosts()
@ -37,6 +40,7 @@ export class Blog extends Controller {
})
}
// FIXME: set chorusThread here
return view('blog:post', {
...home.getThemeCSS(),
...this.getBlogData(),
@ -128,7 +132,11 @@ export class Blog extends Controller {
}
public getBlogData(): any {
let chorusUrl = String(this.config.get('server.chorus.baseUrl') || '')
if ( chorusUrl && !chorusUrl.endsWith('/') ) chorusUrl += '/'
return {
chorusUrl,
blogUrl: (post: BlogPost): string => this.blog.getUrl(post),
blogDate: (date: Date): string => {
const year = date.getFullYear()

View File

@ -0,0 +1,106 @@
if ( !window.Chorus ) window.Chorus = {}
Chorus.processThreadData = function(threadData) {
threadData.refresh.date = new Date(threadData.refresh.date)
for ( const comment of threadData.comments ) {
comment.date = new Date(comment.date)
}
threadData.comments = threadData.comments
.sort((a, b) => b.date.getTime() - a.date.getTime())
return threadData
};
Chorus.init = async function(selector) {
const el = document.querySelector(selector)
if ( !el ) {
console.warn('[Chorus] Could not init: could not find element with selector: ' + selector)
return
}
let baseUrl = el.getAttribute('data-chorus-url')
if ( !baseUrl ) {
console.warn('[Chorus] Could not init: host element is missing data-chorus-url attribute')
return
}
if ( !baseUrl.endsWith('/') ) {
baseUrl += '/'
}
const threadId = el.getAttribute('data-chorus-thread')
if ( !threadId ) {
console.warn('[Chorus] Could not init: host element is missing data-chorus-thread attribute')
return
}
const threadDataUrl = `${baseUrl}threads/${threadId}.json`
const response = await fetch(threadDataUrl)
if ( response.status === 404 ) {
// fixme
}
if ( !response.ok ) {
console.error('[Chorus] Failed to load thread data')
return
}
const threadData = Chorus.processThreadData(await response.json())
Chorus.renderSummary(el, threadData)
const commentsDiv = document.createElement('div')
commentsDiv.classList.add('chorus-comments-list')
for ( const comment of threadData.comments ) {
Chorus.renderComment(commentsDiv, comment)
}
el.appendChild(commentsDiv)
console.log(threadData)
};
Chorus.renderComment = function(commentsDiv, comment) {
const commentDiv = document.createElement('div')
commentDiv.classList.add('chorus-comment')
commentsDiv.appendChild(commentDiv)
const authorEl = document.createElement('h2')
authorEl.classList.add('chorus-byline')
authorEl.innerText = comment.user.name
authorEl.title = 'User ID: ' + comment.user.mailId + '\nDomain ID: ' + comment.user.domainId
commentDiv.appendChild(authorEl)
const statusEl = document.createElement('p')
statusEl.classList.add('chorus-status')
statusEl.innerText = comment.date.toLocaleString()
commentDiv.appendChild(statusEl)
if ( comment.subject ) {
const subjectEl = document.createElement('h3')
subjectEl.innerText = comment.subject
commentDiv.appendChild(subjectEl)
}
const contentEl = document.createElement('p')
contentEl.innerHTML = comment.rendered
commentDiv.appendChild(contentEl)
};
Chorus.renderSummary = function(el, threadData) {
const summaryDiv = document.createElement('div')
summaryDiv.classList.add('chorus-summary')
el.appendChild(summaryDiv)
const summaryUl = document.createElement('ul')
summaryDiv.appendChild(summaryUl)
const countLi = document.createElement('li')
countLi.innerText = `${threadData.comments.length} comment${threadData.comments.length === 1 ? '' : 's'}`
summaryUl.appendChild(countLi)
const lastRefreshLi = document.createElement('li')
lastRefreshLi.innerText = `Last refreshed: ${threadData.refresh.date.toLocaleString()}`
summaryUl.appendChild(lastRefreshLi)
};

View File

@ -893,3 +893,50 @@ section#auth h3 {
padding: 3px 7px;
font-size: 1.2em;
}
.comments-container {
margin-top: 100px;
}
.comments-container > h1 {
font-size: 3em;
}
.comments .chorus-summary ul {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
}
.comments .chorus-summary ul li:first-of-type {
flex: 1;
}
.comments .chorus-comment {
background-color: var(--c-background-offset);
border-left: 3px solid var(--c-hero);
padding: 1px 20px;
margin: 50px 20px;
}
.comments .chorus-comment .chorus-byline {
font-size: 1.5em;
padding-top: 10px;
}
.comments .chorus-comment .chorus-status {
font-size: 1.0em;
margin-top: 0;
}
.comments .chorus-comment > h3 {
font-family: "Lora", serif;
font-weight: bold;
font-size: 1.5em;
margin: 0;
padding: 10px 0 0;
color: var(--c-font);
background-color: var(--c-font);
}

View File

@ -29,6 +29,10 @@ block append script
script(src=asset('highlight/highlight.min.js'))
script.
hljs.highlightAll();
if chorusUrl && chorusThread
script(src=asset('chorus.js'))
script.
Chorus?.init('#chorus-container')
block blog_content
h2.post-title #{post.title}
@ -40,3 +44,16 @@ block blog_content
a.button(href=named('blog')+'/tag/'+tag) ##{tag}
.post-content !{renderedPost}
if chorusUrl && chorusThread
.section-border
.section-border-inner-1
.section-border-inner-2
.comments-container
h1 Comments
p Thanks for reading! I'd love to hear your thoughts and questions.
p My blog uses an email-based comments system: <a href="#">Submit a Comment</a>
p You can also <a href="mailto:shout@garrettmills.dev">email me</a> directly.
hr
div.comments#chorus-container(data-chorus-url=chorusUrl data-chorus-thread=chorusThread)