Files: 0f55f6590b4fcc68e74c2910f6437b56f946b331 / modules / profile / async / suggest.js
3030 bytesRaw
1 | var nest = require('depnest') |
2 | var {Struct, map, computed, watch} = require('mutant') |
3 | |
4 | exports.needs = nest({ |
5 | 'profile.obs.recentlyUpdated': 'first', |
6 | 'contact.obs.following': 'first', |
7 | 'about.obs.name': 'first', |
8 | 'about.obs.imageUrl': 'first', |
9 | 'keys.sync.id': 'first' |
10 | }) |
11 | |
12 | exports.gives = nest('profile.async.suggest') |
13 | |
14 | exports.create = function (api) { |
15 | var suggestions = null |
16 | var recentSuggestions = null |
17 | var following = null |
18 | |
19 | return nest('profile.async.suggest', function () { |
20 | loadSuggestions() |
21 | return function (word, defaultItems) { |
22 | var defaultSuggestions = Array.isArray(defaultItems) && defaultItems.length ? suggestions().filter((item) => { |
23 | return matches(item.title, word) && defaultItems.includes(item.id) |
24 | }) : null |
25 | |
26 | if (!word) { |
27 | return defaultSuggestions || recentSuggestions() |
28 | } else { |
29 | var result = defaultSuggestions || [] |
30 | |
31 | // prioritize people you follow |
32 | suggestions().forEach((item) => { |
33 | if (following().includes(item.id) && matches(item.title, word) && !result.some(v => v.id === item.id)) { |
34 | result.push(item) |
35 | } |
36 | }) |
37 | |
38 | // next most recently active profiles |
39 | recentSuggestions().forEach((item) => { |
40 | if (matches(item.title, word) && !result.some(v => v.id === item.id)) { |
41 | result.push(item) |
42 | } |
43 | }) |
44 | |
45 | // fallback to everyone |
46 | suggestions().forEach((item) => { |
47 | if (matches(item.title, word) && !result.some(v => v.id === item.id)) { |
48 | result.push(item) |
49 | } |
50 | }) |
51 | return result |
52 | } |
53 | } |
54 | }) |
55 | |
56 | function loadSuggestions () { |
57 | if (!suggestions) { |
58 | var id = api.keys.sync.id() |
59 | following = api.contact.obs.following(id) |
60 | var recentlyUpdated = api.profile.obs.recentlyUpdated() |
61 | var contacts = computed([following, recentlyUpdated], function (a, b) { |
62 | var result = Array.from(a) |
63 | b.forEach((item, i) => { |
64 | if (!result.includes(item)) { |
65 | result.push(item) |
66 | } |
67 | }) |
68 | return result |
69 | }) |
70 | |
71 | recentSuggestions = map(computed(recentlyUpdated, (items) => Array.from(items).slice(0, 40)), suggestion, {idle: true}) |
72 | suggestions = map(contacts, suggestion, {idle: true}) |
73 | watch(recentSuggestions) |
74 | watch(suggestions) |
75 | } |
76 | } |
77 | |
78 | function suggestion (id) { |
79 | var name = api.about.obs.name(id) |
80 | return Struct({ |
81 | title: name, |
82 | id, |
83 | subtitle: id.substring(0, 10), |
84 | value: computed([name, id], mention, {idle: true}), |
85 | cls: computed([id, following], followingClass, {idle: true}), |
86 | image: api.about.obs.imageUrl(id), |
87 | showBoth: true |
88 | }) |
89 | } |
90 | } |
91 | |
92 | function mention (name, id) { |
93 | return `[@${name}](${id})` |
94 | } |
95 | |
96 | function followingClass (id, following) { |
97 | if (following.includes(id)) { |
98 | return 'following' |
99 | } |
100 | } |
101 | |
102 | function matches (text, startsWith) { |
103 | return text.slice(0, startsWith.length).localeCompare(startsWith, 'default', {sensitivity: 'base'}) === 0 |
104 | } |
105 |
Built with git-ssb-web