git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 3a294e357e15360aded899e2d83d79b4e4c584ea

Files: 3a294e357e15360aded899e2d83d79b4e4c584ea / modules / page / html / render / profile.js

9106 bytesRaw
1var nest = require('depnest')
2var ref = require('ssb-ref')
3var {h, when, computed, map, send, dictToCollection, resolve} = require('mutant')
4var extend = require('xtend')
5
6exports.needs = nest({
7 'about.obs': {
8 name: 'first',
9 description: 'first',
10 names: 'first',
11 images: 'first',
12 color: 'first'
13 },
14 'blob.sync.url': 'first',
15 'blob.html.input': 'first',
16 'message.async.publish': 'first',
17 'message.html.markdown': 'first',
18 'about.html.image': 'first',
19 'feed.html.rollup': 'first',
20 'feed.pull.profile': 'first',
21 'sbot.async.publish': 'first',
22 'keys.sync.id': 'first',
23 'sheet.display': 'first',
24 'profile.obs.rank': 'first',
25 'profile.sheet.edit': 'first',
26 'app.navigate': 'first',
27 'contact.obs': {
28 followers: 'first',
29 following: 'first'
30 },
31 'intl.sync.i18n': 'first',
32})
33exports.gives = nest('page.html.render')
34
35exports.create = function (api) {
36 const i18n = api.intl.sync.i18n
37 return nest('page.html.render', function profile (id) {
38 if (!ref.isFeed(id)) return
39
40 var name = api.about.obs.name(id)
41 var description = api.about.obs.description(id)
42 var yourId = api.keys.sync.id()
43 var yourFollows = api.contact.obs.following(yourId)
44 var rawFollowers = api.contact.obs.followers(id)
45 var rawFollowing = api.contact.obs.following(id)
46 var friendsLoaded = computed([rawFollowers.sync, rawFollowing.sync], (...x) => x.every(Boolean))
47
48 var friends = computed([rawFollowing, rawFollowers], (following, followers) => {
49 return Array.from(following).filter(follow => followers.includes(follow))
50 })
51
52 var following = computed([rawFollowing, friends], (following, friends) => {
53 return Array.from(following).filter(follow => !friends.includes(follow))
54 })
55
56 var followers = computed([rawFollowers, friends], (followers, friends) => {
57 return Array.from(followers).filter(follower => !friends.includes(follower))
58 })
59
60 var isFriends = computed([friends], function (friends) {
61 return friends.includes(yourId)
62 })
63
64 var followsYou = computed([following], function (followsYou) {
65 return followsYou.includes(yourId)
66 })
67
68 var youFollow = computed([yourFollows], function (youFollow) {
69 return youFollow.includes(id)
70 })
71
72 var names = api.about.obs.names(id)
73 var images = api.about.obs.images(id)
74
75 var namePicker = h('div', {className: 'Picker'}, [
76 map(dictToCollection(names), (item) => {
77 var isSelf = computed(item.value, (ids) => ids.includes(id))
78 var isAssigned = computed(item.value, (ids) => ids.includes(yourId))
79 return h('a.name', {
80 'ev-click': () => {
81 if (!isAssigned()) {
82 assignName(id, resolve(item.key))
83 }
84 },
85 href: '#',
86 classList: [
87 when(isSelf, '-self'),
88 when(isAssigned, '-assigned')
89 ],
90 title: nameList(when(isSelf, i18n('Self Assigned'), i18n('Assigned By')), item.value)
91 }, [
92 item.key
93 ])
94 }),
95 h('a -add', {
96 'ev-click': () => {
97 rename(id)
98 },
99 href: '#',
100 }, ['+'])
101 ])
102
103 var imagePicker = h('div', {className: 'Picker'}, [
104 map(dictToCollection(images), (item) => {
105 var isSelf = computed(item.value, (ids) => ids.includes(id))
106 var isAssigned = computed(item.value, (ids) => ids.includes(yourId))
107 return h('a.name', {
108 'ev-click': () => {
109 if (!isAssigned()) {
110 assignImage(id, resolve(item.key))
111 }
112 },
113 href: '#',
114 classList: [
115 when(isSelf, '-self'),
116 when(isAssigned, '-assigned')
117 ],
118 title: nameList(when(isSelf, i18n('Self Assigned'), i18n('Assigned By')), item.value)
119 }, [
120 h('img', {
121 className: 'Avatar',
122 style: { 'background-color': api.about.obs.color(id) },
123 src: computed(item.key, api.blob.sync.url)
124 })
125 ])
126 }),
127 h('span.add', [
128 api.blob.html.input(file => {
129 assignImage(id, file.link)
130 }, {
131 accept: 'image/*',
132 resize: { width: 500, height: 500 }
133 })
134 ])
135 ])
136
137 var prepend = h('header', {className: 'ProfileHeader'}, [
138 h('div.image', api.about.html.image(id)),
139 h('div.main', [
140 h('div.title', [
141 h('h1', [name]),
142 h('div.meta', [
143 when(id === yourId, [
144 h('button', {'ev-click': api.profile.sheet.edit}, i18n('Edit Your Profile'))
145 ], [
146 when(youFollow,
147 h('a.ToggleButton.-unsubscribe', {
148 'href': '#',
149 'title': i18n('Click to unfollow'),
150 'ev-click': send(unfollow, id)
151 }, when(isFriends, i18n('Friends'), i18n('Following'))),
152 h('a.ToggleButton.-subscribe', {
153 'href': '#',
154 'ev-click': send(follow, id)
155 }, when(followsYou, i18n('Follow Back'), i18n('Follow')))
156 )
157 ])
158 ])
159 ]),
160 h('section -description', [
161 computed(description, (text) => {
162 if (typeof text === 'string') {
163 return api.message.html.markdown(text)
164 }
165 })
166 ]),
167 h('section', [ namePicker, imagePicker ])
168 ])
169 ])
170
171 var feedView = api.feed.html.rollup(api.feed.pull.profile(id), {
172 prepend,
173 displayFilter: (msg) => msg.value.author === id,
174 bumpFilter: (msg) => msg.value.author === id,
175 })
176
177 var container = h('div', {className: 'SplitView'}, [
178 h('div.main', [
179 feedView
180 ]),
181 h('div.side.-right', [
182 h('button PrivateMessageButton', {'ev-click': () => api.app.navigate('/private', {compose: {to: id}})}, i18n('Send Private Message')),
183 when(friendsLoaded,
184 h('div', [
185 renderContactBlock(i18n('Friends'), friends, yourFollows),
186 renderContactBlock(i18n('Followers'), followers, yourFollows),
187 renderContactBlock(i18n('Following'), following, yourFollows)
188 ]),
189 h('div', {className: 'Loading'})
190 )
191 ])
192 ])
193
194 container.pendingUpdates = feedView.pendingUpdates
195 container.reload = feedView.reload
196 return container
197 })
198
199 function renderContactBlock (title, profiles, yourFollows) {
200 profiles = api.profile.obs.rank(profiles)
201 return [
202 when(computed(profiles, x => x.length), h('h2', title)),
203 h('div', {
204 classList: 'ProfileList'
205 }, [
206 map(profiles, (id) => {
207 var following = computed(yourFollows, f => f.includes(id))
208 return h('a.profile', {
209 href: id,
210 classList: [
211 when(following, '-following')
212 ]
213 }, [
214 h('div.avatar', [api.about.html.image(id)]),
215 h('div.main', [
216 h('div.name', [ api.about.obs.name(id) ])
217 ])
218 ])
219 }, {
220 maxTime: 5,
221 idle: true
222 })
223 ])
224 ]
225 }
226
227 function follow (id) {
228 api.sbot.async.publish({
229 type: 'contact',
230 contact: id,
231 following: true
232 })
233 }
234
235 function unfollow (id) {
236 api.sbot.async.publish({
237 type: 'contact',
238 contact: id,
239 following: false
240 })
241 }
242
243 function assignImage (id, image) {
244 api.message.async.publish({
245 type: 'about',
246 about: id,
247 image
248 })
249 }
250
251 function assignName (id, name) {
252 api.message.async.publish({
253 type: 'about',
254 about: id,
255 name
256 })
257 }
258
259 function rename (id) {
260 api.sheet.display(close => {
261 var currentName = api.about.obs.name(id)
262 var input = h('input', {
263 style: {'font-size': '150%'},
264 value: currentName()
265 })
266 setTimeout(() => {
267 input.focus()
268 input.select()
269 }, 5)
270 return {
271 content: h('div', {
272 style: {
273 padding: '20px',
274 'text-align': 'center'
275 }
276 }, [
277 h('h2', {
278 style: {
279 'font-weight': 'normal'
280 }
281 }, [i18n('What whould you like to call '), h('strong', [currentName]), '?']),
282 input
283 ]),
284 footer: [
285 h('button -save', {
286 'ev-click': () => {
287 if (input.value.trim() && input.value !== currentName()) {
288 // no confirm
289 api.sbot.async.publish({
290 type: 'about',
291 about: id,
292 name: input.value.trim()
293 })
294 }
295 close()
296 }
297 }, i18n('Confirm')),
298 h('button -cancel', {
299 'ev-click': close
300 }, i18n('Cancel'))
301 ]
302 }
303 })
304 }
305
306 function nameList (prefix, ids) {
307 var items = map(ids, api.about.obs.name)
308 return computed([prefix, items], (prefix, names) => {
309 return (prefix ? (prefix + '\n') : '') + names.map((n) => `- ${n}`).join('\n')
310 })
311 }
312}
313

Built with git-ssb-web