git ssb

2+

mixmix / ticktack



Tree: 35e506868ea54929c5978b29572a923888e2518d

Files: 35e506868ea54929c5978b29572a923888e2518d / app / html / blog-card.js

3941 bytesRaw
1var nest = require('depnest')
2var h = require('mutant/h')
3var isString= require('lodash/isString')
4var maxBy= require('lodash/maxBy')
5var humanTime = require('human-time')
6var marksum = require('markdown-summary')
7var markdown = require('ssb-markdown')
8var ref = require('ssb-ref')
9var htmlEscape = require('html-escape')
10
11function renderEmoji (emoji, url) {
12 if (!url) return ':' + emoji + ':'
13 return `
14 <img
15 src="${htmlEscape(url)}"
16 alt=":${htmlEscape(emoji)}:"
17 title=":${htmlEscape(emoji)}:"
18 class="emoji"
19 >
20 `
21}
22
23exports.gives = nest('app.html.blogCard', true)
24
25exports.needs = nest({
26 'keys.sync.id': 'first',
27 'history.sync.push': 'first',
28 'about.obs.name': 'first',
29 'about.html.avatar': 'first',
30 'translations.sync.strings': 'first',
31 'unread.sync.isUnread': 'first',
32 'message.html.markdown': 'first',
33 'blob.sync.url': 'first',
34 'emoji.sync.url': 'first'
35})
36
37exports.create = function (api) {
38
39 //render markdown, but don't support patchwork@2 style mentions or custom emoji right now.
40 function render (source) {
41 return markdown.block(source, {
42 emoji: (emoji) => {
43 return renderEmoji(emoji, api.emoji.sync.url(emoji))
44 },
45 toUrl: (id) => {
46 if (ref.isBlob(id)) return api.blob.sync.url(id)
47 return id
48 },
49 imageLink: (id) => id
50 })
51 }
52
53
54 //render the icon for a thread.
55 //it would be more depjecty to split this
56 //into two methods, one in a private plugin
57 //one in a channel plugin
58 function threadIcon (msg) {
59 if(msg.value.private) {
60 const myId = api.keys.sync.id()
61
62 return msg.value.content.recps
63 .map(link => isString(link) ? link : link.link)
64 .filter(link => link !== myId)
65 .map(api.about.html.avatar)
66 }
67 else if(msg.value.content.channel)
68 return '#'+msg.value.content.channel
69 }
70
71
72 // REFACTOR: move this to a template?
73 function buildRecipientNames (thread) {
74 const myId = api.keys.sync.id()
75
76 return thread.value.content.recps
77 .map(link => isString(link) ? link : link.link)
78 .filter(link => link !== myId)
79 .map(api.about.obs.name)
80 }
81
82 return nest('app.html.blogCard', (thread, opts = {}) => {
83 var strings = api.translations.sync.strings()
84 const { subject } = api.message.html
85
86 if(!thread.value) return
87 if('string' !== typeof thread.value.content.text) return
88
89 const lastReply = thread.replies && maxBy(thread.replies, r => r.timestamp)
90
91 const onClick = opts.onClick || function () { api.history.sync.push(thread) }
92 const id = `${thread.key.replace(/[^a-z0-9]/gi, '')}` //-${JSON.stringify(opts)}`
93 // id is only here to help morphdom morph accurately
94
95 const { content, author, timestamp } = thread.value
96
97 var img = h('Thumbnail')
98 var m = /\!\[[^]+\]\(([^\)]+)\)/.exec(marksum.image(content.text))
99 if(m) {
100 //Hey this works! fit an image into a specific size (see thread-card.mcss)
101 //centered, and scaled to fit the square (works with both landscape and portrait!)
102 //This is functional css not opinionated css, so all embedded.
103 img.style = 'background-image: url("'+api.blob.sync.url(m[1])+'"); background-position:center; background-size: cover;'
104 }
105
106 const title = render(marksum.title(content.text))
107 const summary = render(marksum.summary(content.text))
108
109 const className = thread.unread ? '-unread': ''
110
111 return h('BlogCard', { id, className }, [
112 h('div.context', [
113 api.about.html.avatar(author),
114 h('div.name', api.about.obs.name(author)),
115 h('div.timeago', humanTime(new Date(timestamp))),
116 ]),
117 h('div.content', {'ev-click': onClick}, [
118 img,
119 h('div.text', [
120 h('h2', {innerHTML: title}),
121 content.channel
122 ? h('Button -channel', '#'+content.channel)
123 : '',
124 h('div.summary', {innerHTML: summary})
125 ])
126 ])
127 ])
128 })
129}
130
131

Built with git-ssb-web