git ssb

1+

Daan Patchwork / patchwork



Tree: 2aba282967b6a030aeb637a4592a0572ac1451b7

Files: 2aba282967b6a030aeb637a4592a0572ac1451b7 / lib / depject / message / html / layout / default.js

4925 bytesRaw
1const { h, computed, Value, when } = require('mutant')
2const nest = require('depnest')
3const ref = require('ssb-ref')
4const ExpanderHook = require('../../../../expander-hook')
5const timestamp = require('../../../../message/html/timestamp')
6
7exports.needs = nest({
8 'profile.html.person': 'first',
9 'contact.obs.following': 'first',
10 'keys.sync.id': 'first',
11 'message.html': {
12 link: 'first',
13 metas: 'first',
14 actions: 'first',
15 references: 'first',
16 forks: 'first'
17 },
18 'about.html.image': 'first',
19 'intl.sync.i18n': 'first'
20})
21
22exports.gives = nest('message.html.layout')
23
24exports.create = function (api) {
25 const i18n = api.intl.sync.i18n
26 let yourFollows = null
27
28 // to get sync follows
29 setImmediate(() => {
30 const yourId = api.keys.sync.id()
31 yourFollows = api.contact.obs.following(yourId)
32 })
33
34 return nest('message.html.layout', layout)
35
36 function layout (msg, { layout, priority, content, includeReferences = false, includeForks = true, compact = false, hooks, forkedFrom, outOfContext }) {
37 if (!(layout === undefined || layout === 'default')) return
38
39 const classList = ['Message']
40 let replyInfo = null
41
42 const needsExpand = Value(false)
43 const expanded = Value(false)
44
45 // new message previews shouldn't contract
46 if (!msg.key) expanded.set(true)
47
48 if (msg.value.content.root) {
49 classList.push('-reply')
50 if (forkedFrom) {
51 replyInfo = h('span', [i18n('forked from parent thread '), api.message.html.link(forkedFrom)])
52 } else if (outOfContext) {
53 replyInfo = h('span', [i18n('in reply to '), api.message.html.link(msg.value.content.root)])
54 }
55 } else if (msg.value.content.project) {
56 replyInfo = h('span', [i18n('on '), api.message.html.link(msg.value.content.project)])
57 }
58
59 if (yourFollows && yourFollows().includes(msg.value.author)) {
60 classList.push('-following')
61 }
62
63 if (compact) {
64 classList.push('-compact')
65 }
66
67 if (priority === 2) {
68 classList.push('-new')
69 }
70
71 if (priority === 1) {
72 classList.push('-unread')
73 }
74
75 let cw = msg.value.content.contentWarning
76 if (typeof cw !== 'string' || cw.length === 0) {
77 cw = undefined
78 } else {
79 // TODO: emoji shortcodes?
80 // TODO: truncate very long content warning, maybe use max-height?
81 classList.push('-hasContentWarning')
82 }
83
84 return h('div', {
85 classList,
86 hooks
87 }, [
88 messageHeader(msg, { replyInfo, priority }),
89 cw
90 ? h('a.contentWarning',
91 {
92 href: '#',
93 'ev-click': toggleAndTrack(expanded)
94 },
95 cw
96 )
97 : undefined,
98 h('section.content', {
99 classList: [when(expanded, '-expanded')],
100 hooks: [ExpanderHook(needsExpand)]
101 }, content),
102 computed(msg.key, (key) => {
103 if (ref.isMsg(key)) {
104 return h('footer', [
105 when(needsExpand, h('div.expander', {
106 classList: when(expanded, null, '-truncated')
107 }, [
108 h('a', {
109 href: '#',
110 'ev-click': toggleAndTrack(expanded)
111 }, when(expanded, i18n('See less'), i18n('See more')))
112 ])),
113 h('div.actions', [
114 api.message.html.actions(msg)
115 ])
116 ])
117 }
118 }),
119 includeReferences ? api.message.html.references(msg) : null,
120 includeForks ? api.message.html.forks(msg) : null
121 ])
122
123 // scoped
124
125 function messageHeader (msg, { replyInfo, priority }) {
126 const yourId = api.keys.sync.id()
127 const additionalMeta = []
128 if (priority === 2) {
129 additionalMeta.push(h('span.flag -new', { title: i18n('New Message') }))
130 } else if (priority === 1) {
131 additionalMeta.push(h('span.flag -unread', { title: i18n('Unread Message') }))
132 }
133
134 return h('header', [
135 h('div.main', [
136 h('a.avatar', { href: `${msg.value.author}` }, [
137 api.about.html.image(msg.value.author)
138 ]),
139 h('div.main', [
140 h('div.name', [
141 api.profile.html.person(msg.value.author),
142 msg.value.author === yourId ? [' ', h('span.you', {}, i18n('(you)'))] : null
143 ]),
144 h('div.meta', [
145 timestamp(msg), ' ',
146 replyInfo
147 ])
148 ])
149 ]),
150 h('div.meta', [
151 additionalMeta,
152 api.message.html.metas(msg)
153 ])
154 ])
155 }
156 }
157}
158
159function toggleAndTrack (param) {
160 return {
161 handleEvent: handleToggle,
162 param
163 }
164}
165
166function handleToggle (ev) {
167 this.param.set(!this.param())
168 if (!this.param()) {
169 ev.target.scrollIntoViewIfNeeded()
170
171 // HACK: due to a browser bug, sometimes the body gets affected!?
172 // Why not just hack it!!!
173 if (document.body.scrollTop > 0) {
174 document.body.scrollTop = 0
175 }
176 }
177}
178

Built with git-ssb-web