Implement basic Chorus comment rendering for blog posts
This commit is contained in:
parent
eed21b9097
commit
d6ada9a222
@ -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,
|
||||
|
@ -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()
|
||||
|
106
src/app/resources/assets/chorus.js
Normal file
106
src/app/resources/assets/chorus.js
Normal 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)
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user