Commit e90da2f27b61cf784fcae42a35492b32c3e19af3
profiles: only show top friends/followers/following and provide "View more" with filter
Matt McKegg committed on 2/12/2018, 9:55:25 PMParent: 85d9ae042b27a93cc430e3c2ca805da1d89bd739
Files changed
locales/en.json | changed |
modules/page/html/render/profile.js | changed |
modules/profile/obs/contact.js | changed |
modules/sheet/profiles.js | changed |
styles/dark/profile-list.mcss | changed |
styles/light/profile-list.mcss | changed |
locales/en.json | ||
---|---|---|
@@ -166,6 +166,10 @@ | ||
166 | 166 | "other": "You follow %s people that subscribe to this channel." |
167 | 167 | }, |
168 | 168 | "People you follow that subscribe to this channel": "People you follow that subscribe to this channel", |
169 | 169 | " from your extended network": " from your extended network", |
170 | - "+ Add Gathering": "+ Add Gathering" | |
170 | + "+ Add Gathering": "+ Add Gathering", | |
171 | + "View %s more": { | |
172 | + "one": "View %s more", | |
173 | + "other": "View %s more" | |
174 | + } | |
171 | 175 | } |
modules/page/html/render/profile.js | ||
---|---|---|
@@ -24,8 +24,9 @@ | ||
24 | 24 | 'profile.obs.rank': 'first', |
25 | 25 | 'profile.sheet.edit': 'first', |
26 | 26 | 'app.navigate': 'first', |
27 | 27 | 'profile.obs.contact': 'first', |
28 | + 'profile.obs.recentlyUpdated': 'first', | |
28 | 29 | 'contact.html.followToggle': 'first', |
29 | 30 | 'intl.sync.i18n': 'first', |
30 | 31 | 'intl.sync.i18n_n': 'first', |
31 | 32 | 'sheet.profiles': 'first' |
@@ -40,8 +41,9 @@ | ||
40 | 41 | var yourId = api.keys.sync.id() |
41 | 42 | var name = api.about.obs.name(id) |
42 | 43 | var description = api.about.obs.description(id) |
43 | 44 | var contact = api.profile.obs.contact(id) |
45 | + var recent = api.profile.obs.recentlyUpdated() | |
44 | 46 | |
45 | 47 | var friends = computed([contact.following, contact.followers], (following, followers) => { |
46 | 48 | return Array.from(following).filter(follow => followers.includes(follow)) |
47 | 49 | }) |
@@ -211,11 +213,11 @@ | ||
211 | 213 | h('div.side.-right', [ |
212 | 214 | h('button PrivateMessageButton', {'ev-click': () => api.app.navigate('/private', {compose: {to: id}})}, i18n('Send Private Message')), |
213 | 215 | when(contact.sync, |
214 | 216 | h('div', [ |
215 | - renderContactBlock(i18n('Friends'), friends, contact.yourFollowing), | |
216 | - renderContactBlock(i18n('Followers'), followers, contact.yourFollowing), | |
217 | - renderContactBlock(i18n('Following'), following, contact.yourFollowing), | |
217 | + renderContactBlock(i18n('Friends'), onlyRecent(friends, 10), contact.yourFollowing, friends), | |
218 | + renderContactBlock(i18n('Followers'), onlyFollowing(followers, 10), contact.yourFollowing, followers), | |
219 | + renderContactBlock(i18n('Following'), onlyRecent(following, 10), contact.yourFollowing, following), | |
218 | 220 | renderContactBlock(i18n('Blocked by'), contact.blockingFriends, contact.yourFollowing) |
219 | 221 | ]), |
220 | 222 | h('div', {className: 'Loading'}) |
221 | 223 | ) |
@@ -227,8 +229,36 @@ | ||
227 | 229 | |
228 | 230 | container.pendingUpdates = feedView.pendingUpdates |
229 | 231 | container.reload = feedView.reload |
230 | 232 | return container |
233 | + | |
234 | + // scoped | |
235 | + | |
236 | + function onlyFollowing (ids, max) { | |
237 | + return computed([ids, contact.yourFollowing, recent], (a, b, c) => { | |
238 | + var result = a.filter(x => b.includes(x) && c.includes(x)) | |
239 | + if (result.length === 0 && a.length) { | |
240 | + // fallback to just recent | |
241 | + result = a.filter(x => c.includes(x)) | |
242 | + } | |
243 | + if (max) { | |
244 | + return result.slice(0, max) | |
245 | + } else { | |
246 | + return result | |
247 | + } | |
248 | + }) | |
249 | + } | |
250 | + | |
251 | + function onlyRecent (ids, max) { | |
252 | + return computed([ids, recent], (a, b) => { | |
253 | + var result = a.filter(x => b.includes(x)) | |
254 | + if (max) { | |
255 | + return result.slice(0, max) | |
256 | + } else { | |
257 | + return result | |
258 | + } | |
259 | + }) | |
260 | + } | |
231 | 261 | }) |
232 | 262 | |
233 | 263 | function displayFollowedBy (profiles) { |
234 | 264 | api.sheet.profiles(profiles, i18n('Followed by')) |
@@ -241,12 +271,12 @@ | ||
241 | 271 | function displayBlockingFriends (profiles) { |
242 | 272 | api.sheet.profiles(profiles, i18n('Blocked by')) |
243 | 273 | } |
244 | 274 | |
245 | - function renderContactBlock (title, profiles, yourFollowing) { | |
246 | - profiles = api.profile.obs.rank(profiles) | |
275 | + function renderContactBlock (title, profiles, yourFollowing, fullList) { | |
276 | + var moreCount = computed([profiles, fullList], (a, b) => a && b && a.length < b.length && b.length - a.length) | |
247 | 277 | return [ |
248 | - when(computed(profiles, x => x.length), h('h2', title)), | |
278 | + when(computed([profiles, fullList], (a, b) => a.length || (b && b.length)), h('h2', title)), | |
249 | 279 | h('div', { |
250 | 280 | classList: 'ProfileList' |
251 | 281 | }, [ |
252 | 282 | map(profiles, (id) => { |
@@ -264,9 +294,23 @@ | ||
264 | 294 | ]) |
265 | 295 | }, { |
266 | 296 | maxTime: 5, |
267 | 297 | idle: true |
268 | - }) | |
298 | + }), | |
299 | + when(moreCount, | |
300 | + h('a.profile -more', { | |
301 | + href: '#', | |
302 | + 'ev-click': function () { | |
303 | + api.sheet.profiles(fullList, title) | |
304 | + } | |
305 | + }, [ | |
306 | + h('div.main', [ | |
307 | + h('div.name', computed(moreCount, count => { | |
308 | + return count && plural('View %s more', count) | |
309 | + })) | |
310 | + ]) | |
311 | + ]) | |
312 | + ) | |
269 | 313 | ]) |
270 | 314 | ] |
271 | 315 | } |
272 | 316 |
modules/profile/obs/contact.js | ||
---|---|---|
@@ -30,8 +30,10 @@ | ||
30 | 30 | var youFollow = computed([yourFollowing], function (yourFollowing) { |
31 | 31 | return yourFollowing.includes(id) |
32 | 32 | }) |
33 | 33 | |
34 | + var yourFriends = computed([yourFollowers, yourFollowing], inAllSets) | |
35 | + | |
34 | 36 | var blockingFriends = computed([yourFollowers, yourFollowing, blockers], inAllSets) |
35 | 37 | var mutualFriends = computed([yourFollowers, yourFollowing, followers, following], inAllSets) |
36 | 38 | var outgoingVia = computed([yourFollowers, following], inAllSets) |
37 | 39 | var incomingVia = computed([yourFollowing, followers], inAllSets) |
@@ -68,8 +70,9 @@ | ||
68 | 70 | noIncoming: not(hasIncoming, isYou), |
69 | 71 | yourId, |
70 | 72 | yourFollowing, |
71 | 73 | yourFollowers, |
74 | + yourFriends, | |
72 | 75 | youFollow, |
73 | 76 | youBlock, |
74 | 77 | isYou, |
75 | 78 | notFollowing: not(youFollow, isYou), |
modules/sheet/profiles.js | ||
---|---|---|
@@ -1,5 +1,5 @@ | ||
1 | -var {h, when, map, computed} = require('mutant') | |
1 | +var {h, when, map, computed, Value, lookup} = require('mutant') | |
2 | 2 | var nest = require('depnest') |
3 | 3 | var catchLinks = require('../../lib/catch-links') |
4 | 4 | |
5 | 5 | exports.needs = nest({ |
@@ -18,15 +18,45 @@ | ||
18 | 18 | exports.create = function (api) { |
19 | 19 | const i18n = api.intl.sync.i18n |
20 | 20 | return nest('sheet.profiles', function (ids, title) { |
21 | 21 | api.sheet.display(close => { |
22 | + var currentFilter = Value() | |
23 | + var nameLookup = lookup(ids, (id) => { | |
24 | + return [id, api.about.obs.name(id)] | |
25 | + }) | |
26 | + var filteredIds = computed([ids, nameLookup, currentFilter], (ids, nameLookup, filter) => { | |
27 | + if (filter) { | |
28 | + var result = [] | |
29 | + for (var k in nameLookup) { | |
30 | + if (nameLookup[k] && nameLookup[k].toLowerCase().includes(filter.toLowerCase())) { | |
31 | + result.push(k) | |
32 | + } | |
33 | + } | |
34 | + return result | |
35 | + } else { | |
36 | + return ids | |
37 | + } | |
38 | + }) | |
22 | 39 | var content = h('div', { |
23 | 40 | style: { padding: '20px' } |
24 | 41 | }, [ |
25 | 42 | h('h2', { |
26 | 43 | style: { 'font-weight': 'normal' } |
27 | - }, [title]), | |
28 | - renderContactBlock(ids) | |
44 | + }, [ | |
45 | + title, | |
46 | + h('input', { | |
47 | + type: 'search', | |
48 | + placeholder: 'filter names', | |
49 | + 'ev-input': function (ev) { | |
50 | + currentFilter.set(ev.target.value) | |
51 | + }, | |
52 | + style: { | |
53 | + 'float': 'right', | |
54 | + 'font-size': '100%' | |
55 | + } | |
56 | + }) | |
57 | + ]), | |
58 | + renderContactBlock(filteredIds) | |
29 | 59 | ]) |
30 | 60 | |
31 | 61 | catchLinks(content, (href, external, anchor) => { |
32 | 62 | if (!external) { |
@@ -66,9 +96,9 @@ | ||
66 | 96 | h('div.main', [ |
67 | 97 | h('div.name', [ api.about.obs.name(id) ]) |
68 | 98 | ]) |
69 | 99 | ]) |
70 | - }, { idle: true }) | |
100 | + }, { idle: true, maxTime: 2 }) | |
71 | 101 | ]) |
72 | 102 | ] |
73 | 103 | } |
74 | 104 | } |
Built with git-ssb-web