2019-07-28 20:49:01 +00:00
|
|
|
'use strict'
|
2019-06-27 20:36:43 +00:00
|
|
|
const {
|
|
|
|
a,
|
|
|
|
abbr,
|
2019-08-13 20:53:11 +00:00
|
|
|
article,
|
|
|
|
button,
|
|
|
|
details,
|
2019-06-29 17:55:43 +00:00
|
|
|
div,
|
2019-08-13 20:53:11 +00:00
|
|
|
footer,
|
|
|
|
form,
|
2019-06-27 20:36:43 +00:00
|
|
|
header,
|
|
|
|
img,
|
|
|
|
section,
|
|
|
|
span,
|
2019-08-14 02:20:10 +00:00
|
|
|
summary,
|
|
|
|
pre
|
2019-06-27 20:36:43 +00:00
|
|
|
} = require('hyperaxe')
|
|
|
|
|
2019-08-14 02:20:10 +00:00
|
|
|
const highlightJs = require('highlight.js')
|
2019-06-28 20:55:05 +00:00
|
|
|
const lodash = require('lodash')
|
|
|
|
|
2019-06-27 20:36:43 +00:00
|
|
|
module.exports = ({ msg }) => {
|
2019-06-28 20:55:05 +00:00
|
|
|
const encoded = {
|
|
|
|
key: encodeURIComponent(msg.key),
|
|
|
|
author: encodeURIComponent(msg.value.author),
|
|
|
|
parent: encodeURIComponent(msg.value.content.root)
|
|
|
|
}
|
|
|
|
|
2019-06-27 20:36:43 +00:00
|
|
|
const url = {
|
2019-06-28 20:55:05 +00:00
|
|
|
author: `/author/${encoded.author}`,
|
|
|
|
likeForm: `/like/${encoded.key}`,
|
|
|
|
context: `/thread/${encoded.key}#${encoded.key}`,
|
|
|
|
parent: `/thread/${encoded.parent}#${encoded.parent}`,
|
2019-06-27 20:36:43 +00:00
|
|
|
avatar: msg.value.meta.author.avatar.url,
|
2019-08-07 02:44:09 +00:00
|
|
|
raw: `/raw/${encoded.key}`,
|
2019-08-07 14:47:21 +00:00
|
|
|
reply: `/reply/${encoded.key}`
|
2019-06-27 20:36:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const isPrivate = Boolean(msg.value.meta.private)
|
2019-06-29 19:06:45 +00:00
|
|
|
const isThreadTarget = Boolean(lodash.get(msg, 'value.meta.thread.target', false))
|
2019-06-27 20:36:43 +00:00
|
|
|
|
|
|
|
const name = msg.value.meta.author.name
|
2019-06-28 20:55:05 +00:00
|
|
|
const timeAgo = msg.value.meta.timestamp.received.since
|
|
|
|
|
2019-06-29 19:06:45 +00:00
|
|
|
const depth = lodash.get(msg, 'value.meta.thread.depth', 0)
|
2019-06-27 20:36:43 +00:00
|
|
|
|
|
|
|
const markdownContent = msg.value.meta.md.block()
|
|
|
|
|
2019-08-13 20:53:11 +00:00
|
|
|
const hasContentWarning = typeof msg.value.content.contentWarning === 'string'
|
|
|
|
|
2019-06-28 20:55:05 +00:00
|
|
|
const likeButton = msg.value.meta.voted
|
|
|
|
? { value: 0, class: 'liked' }
|
|
|
|
: { value: 1, class: null }
|
2019-06-27 20:36:43 +00:00
|
|
|
|
|
|
|
const likeCount = msg.value.meta.votes.length
|
|
|
|
|
2019-06-28 20:55:05 +00:00
|
|
|
const parentLink = msg.value.content.root != null
|
|
|
|
? a({ href: url.parent }, 'parent')
|
|
|
|
: null
|
|
|
|
|
2019-06-29 19:06:45 +00:00
|
|
|
const messageClasses = ['message']
|
|
|
|
|
|
|
|
if (isPrivate) {
|
|
|
|
messageClasses.push('private')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isThreadTarget) {
|
|
|
|
messageClasses.push('thread-target')
|
|
|
|
}
|
|
|
|
|
2019-08-07 14:47:21 +00:00
|
|
|
if (depth > 0) {
|
|
|
|
messageClasses.push('reply')
|
|
|
|
}
|
|
|
|
|
2019-08-14 02:20:10 +00:00
|
|
|
const emptyContent = '<p>undefined</p>\n'
|
|
|
|
const articleElement = markdownContent === emptyContent
|
|
|
|
? article({ class: 'content' }, pre({
|
|
|
|
innerHTML: highlightJs.highlight('json', JSON.stringify(msg, null, 2)).value
|
|
|
|
}))
|
|
|
|
: article({ class: 'content', innerHTML: markdownContent })
|
2019-08-13 20:53:11 +00:00
|
|
|
|
|
|
|
const articleContent = hasContentWarning
|
|
|
|
? details(
|
|
|
|
summary(msg.value.content.contentWarning),
|
|
|
|
articleElement
|
|
|
|
)
|
|
|
|
: articleElement
|
|
|
|
|
2019-06-27 20:36:43 +00:00
|
|
|
const fragment =
|
2019-06-28 20:55:05 +00:00
|
|
|
section({
|
|
|
|
id: msg.key,
|
2019-06-29 19:06:45 +00:00
|
|
|
class: messageClasses.join(' '),
|
2019-06-28 20:55:05 +00:00
|
|
|
style: `margin-left: ${depth * 1.5}rem`
|
|
|
|
},
|
2019-07-03 03:52:49 +00:00
|
|
|
header({ class: 'metadata' },
|
2019-06-27 20:36:43 +00:00
|
|
|
a({ href: url.author },
|
2019-06-30 19:59:32 +00:00
|
|
|
img({ class: 'avatar', src: url.avatar, alt: 'profile image' })
|
2019-06-27 20:36:43 +00:00
|
|
|
),
|
|
|
|
span({ class: 'text' },
|
|
|
|
span({ class: 'author' },
|
|
|
|
a({ href: url.author }, name)
|
|
|
|
),
|
2019-06-30 20:56:27 +00:00
|
|
|
span({ class: 'timestamp' }, ` ${timeAgo} ago`),
|
2019-06-27 20:36:43 +00:00
|
|
|
isPrivate ? abbr({ title: 'Private' }, '🔒') : null
|
|
|
|
)
|
|
|
|
),
|
2019-08-13 20:53:11 +00:00
|
|
|
articleContent,
|
2019-06-29 17:55:43 +00:00
|
|
|
|
|
|
|
// HACK: centered-footer
|
|
|
|
//
|
|
|
|
// Here we create an empty div with an anchor tag that can be linked to.
|
|
|
|
// In our CSS we ensure that this gets centered on the screen when we
|
|
|
|
// link to this anchor tag.
|
|
|
|
//
|
|
|
|
// This is used for redirecting users after they like a post, when we
|
|
|
|
// want the like button that they just clicked to remain close-ish to
|
|
|
|
// where it was before they clicked the button.
|
|
|
|
div({ id: `centered-footer-${encoded.key}`, class: 'centered-footer' }),
|
|
|
|
|
2019-08-07 14:47:21 +00:00
|
|
|
footer(
|
|
|
|
form({ action: url.likeForm, method: 'post' },
|
|
|
|
button({
|
|
|
|
name: 'voteValue',
|
|
|
|
type: 'submit',
|
|
|
|
value: likeButton.value,
|
|
|
|
class: likeButton.class
|
|
|
|
},
|
|
|
|
`❤ ${likeCount}`
|
|
|
|
)
|
|
|
|
),
|
|
|
|
a({ href: url.reply }, 'reply'),
|
|
|
|
a({ href: url.context }, 'context'),
|
|
|
|
parentLink,
|
|
|
|
a({ href: url.raw }, 'raw')
|
|
|
|
)
|
2019-06-28 20:55:05 +00:00
|
|
|
)
|
2019-06-27 20:36:43 +00:00
|
|
|
|
|
|
|
return fragment
|
|
|
|
}
|