git ssb

2+

mixmix / ticktack



Tree: 682cd150893709ec579d59c1835f2c86e1a71029

Files: 682cd150893709ec579d59c1835f2c86e1a71029 / app / html / thread-card.js

3136 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 const leadingMentionsLength = countLeadingMentions(line)
25 const i = line.indexOf(' ', leadingMentionsLength + 80)
26 var sample = line.substring(0, ~i ? i : line.length)
27
28 const ellipsis = (sample.length < line.length) ? '...' : ''
29 return sample + ellipsis
30}
31
32function countLeadingMentions (str) {
33 return str.match(/^(\s*\[@[^\)]+\)\s*)*/)[0].length
34 // matches any number of pattern " [@...) " from start of line
35}
36
37exports.create = function (api) {
38
39 //render the icon for a thread.
40 //it would be more depjecty to split this
41 //into two methods, one in a private plugin
42 //one in a channel plugin
43 function threadIcon (msg) {
44 if(msg.value.private) {
45 const myId = api.keys.sync.id()
46
47 return msg.value.content.recps
48 .map(link => isString(link) ? link : link.link)
49 .filter(link => link !== myId)
50 .map(api.about.html.image)
51 }
52 else if(msg.value.content.channel)
53 return '#'+msg.value.content.channel
54 }
55
56
57 // REFACTOR: move this to a template?
58 function buildRecipientNames (thread) {
59 const myId = api.keys.sync.id()
60
61 return thread.value.content.recps
62 .map(link => isString(link) ? link : link.link)
63 .filter(link => link !== myId)
64 .map(api.about.obs.name)
65 }
66
67 function subject (msg) {
68 const { subject, text } = msg.value.content
69 if(!(subject || text)) return
70 return api.message.html.markdown(firstLine(subject|| text))
71 }
72
73 return {app: {html: {threadCard: function (thread, opts = {}) {
74 var strings = api.translations.sync.strings()
75
76 if(!thread.value) return
77 if(!thread.value.content.text) return
78
79 const subjectEl = h('div.subject', [
80 opts.nameRecipients
81 ? h('div.recps', buildRecipientNames(thread).map(recp => h('div.recp', recp)))
82 : null,
83 subject(thread)
84 ])
85
86 const lastReply = thread.replies && maxBy(thread.replies, r => r.timestamp)
87 const replySample = lastReply ? subject(lastReply) : null
88
89 const onClick = opts.onClick || function () { api.history.sync.push(thread) }
90 const id = `${thread.key.replace(/[^a-z0-9]/gi, '')}` //-${JSON.stringify(opts)}`
91 // id is only here to help morphdom morph accurately
92
93 return h('ThreadCard', { 'ev-click': onClick, id }, [
94 h('div.context', threadIcon(thread)),
95 h('div.content', [
96 subjectEl,
97 replySample ? h('div.reply', [
98 h('div.replySymbol', strings.replySymbol),
99 replySample
100 ]) : null
101 ])
102 ])
103 }}}}
104}
105
106
107

Built with git-ssb-web