git ssb

10+

Matt McKegg / patchwork



Tree: 9a819a51f9e714d07b90b34130d7c67671c60e38

Files: 9a819a51f9e714d07b90b34130d7c67671c60e38 / modules / page / html / render / profile.js

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

Built with git-ssb-web