git ssb

2+

mixmix / ticktack



Tree: 567e4d92c4e33c4df6f3dbaee5e7a29e2e93eebb

Files: 567e4d92c4e33c4df6f3dbaee5e7a29e2e93eebb / app / html / thread-card.js

3027 bytesRaw
1var h = require('mutant/h')
2var isString= require('lodash/isString')
3var maxBy= require('lodash/maxBy')
4var nest = require('depnest')
5
6exports.gives = nest('app.html.threadCard', true)
7
8exports.needs = nest({
9 'keys.sync.id': 'first',
10 'history.sync.push': 'first',
11 'about.obs.name': 'first',
12 'about.html.image': 'first',
13 'message.html.markdown': 'first',
14 'translations.sync.strings': 'first'
15})
16
17function firstLine (text) {
18 if(text.length < 80 && !~text.indexOf('\n')) return text
19
20 //get the first non-empty line
21 var line = text.trim().split('\n').shift().trim()
22
23 //always break on a space, so that links are preserved.
24 var i = line.indexOf(' ', 80)
25 var sample = line.substring(0, ~i ? i : line.length)
26
27 const ellipsis = (sample.length < line.length) ? '...' : ''
28 return sample + ellipsis
29}
30
31// function trimLeadingMentions (str) {
32// return str.replace(/^(\s*\[@[^\)]+\)\s*)*/, '')
33// // deletes any number of pattern " [@...) " from start of line
34// }
35
36exports.create = function (api) {
37
38 //render the icon for a thread.
39 //it would be more depjecty to split this
40 //into two methods, one in a private plugin
41 //one in a channel plugin
42 function threadIcon (msg) {
43 if(msg.value.private) {
44 const myId = api.keys.sync.id()
45
46 return msg.value.content.recps
47 .map(link => isString(link) ? link : link.link)
48 .filter(link => link !== myId)
49 .map(api.about.html.image)
50 }
51 else if(msg.value.content.channel)
52 return '#'+msg.value.content.channel
53 }
54
55
56 // REFACTOR: move this to a template?
57 function buildRecipientNames (thread) {
58 const myId = api.keys.sync.id()
59
60 return thread.value.content.recps
61 .map(link => isString(link) ? link : link.link)
62 .filter(link => link !== myId)
63 .map(api.about.obs.name)
64 }
65
66 function subject (msg) {
67 const { subject, text } = msg.value.content
68 if(!(subject || text)) return
69 return api.message.html.markdown(firstLine(subject|| text))
70 }
71
72 return {app: {html: {threadCard: function (thread, opts = {}) {
73 var strings = api.translations.sync.strings()
74
75 if(!thread.value) return
76 if(!thread.value.content.text) return
77
78 const subjectEl = h('div.subject', [
79 opts.nameRecipients
80 ? h('div.recps', buildRecipientNames(thread).map(recp => h('div.recp', recp)))
81 : null,
82 subject(thread)
83 ])
84
85 const lastReply = thread.replies && maxBy(thread.replies, r => r.timestamp)
86 const replySample = lastReply ? subject(lastReply) : null
87
88 const onClick = opts.onClick || function () { api.history.sync.push(thread) }
89 const id = `${thread.key}-${JSON.stringify(opts)}`
90 // id is only here to help morphdom morph accurately
91
92 return h('ThreadCard', { 'ev-click': onClick, id }, [
93 h('div.context', threadIcon(thread)),
94 h('div.content', [
95 subjectEl,
96 replySample ? h('div.reply', [
97 h('div.replySymbol', strings.replySymbol),
98 replySample
99 ]) : null
100 ])
101 ])
102 }}}}
103}
104
105
106

Built with git-ssb-web