Files: bc3baa90f43110f56698bc1c3de13714835c9d08 / app / html / context.js
5816 bytesRaw
1 | const nest = require('depnest') |
2 | const { h, computed, map, when, Dict, dictToCollection, Array: MutantArray, resolve } = require('mutant') |
3 | const pull = require('pull-stream') |
4 | const next = require('pull-next-step') |
5 | const get = require('lodash/get') |
6 | const isEmpty = require('lodash/isEmpty') |
7 | |
8 | exports.gives = nest('app.html.context') |
9 | |
10 | exports.needs = nest({ |
11 | 'app.html.scroller': 'first', |
12 | 'about.html.avatar': 'first', |
13 | 'about.obs.name': 'first', |
14 | 'feed.pull.private': 'first', |
15 | 'feed.pull.rollup': 'first', |
16 | 'keys.sync.id': 'first', |
17 | 'history.sync.push': 'first', |
18 | 'message.html.subject': 'first', |
19 | 'sbot.obs.localPeers': 'first', |
20 | 'translations.sync.strings': 'first', |
21 | }) |
22 | |
23 | |
24 | exports.create = (api) => { |
25 | return nest('app.html.context', (location) => { |
26 | |
27 | const strings = api.translations.sync.strings() |
28 | const myKey = api.keys.sync.id() |
29 | |
30 | var nearby = api.sbot.obs.localPeers() |
31 | var recentMsgLog = Dict () |
32 | function updateRecentMsgLog (msg) { |
33 | const { author, timestamp } = msg.value |
34 | |
35 | if (!recentMsgLog.has(author)) { |
36 | recentMsgLog.put(author, msg) |
37 | return |
38 | } |
39 | |
40 | const currentWinner = recentMsgLog.get(author) |
41 | if (timestamp > currentWinner.value.timestamp) { |
42 | recentMsgLog.put(author, msg) |
43 | } |
44 | } |
45 | function isLatestMsg (msg) { |
46 | const { author, timestamp } = msg.value |
47 | return recentMsgLog.get(author).value.timestamp === timestamp |
48 | } |
49 | |
50 | return h('Context -feed', [ |
51 | LevelOneContext(), |
52 | LevelTwoContext() |
53 | ]) |
54 | |
55 | function LevelOneContext () { |
56 | function isDiscoverContext (loc) { |
57 | const PAGES_UNDER_DISCOVER = ['blogIndex', 'blogShow', 'home'] |
58 | |
59 | return PAGES_UNDER_DISCOVER.includes(location.page) |
60 | || get(location, 'value.private') === undefined |
61 | } |
62 | |
63 | const prepend = [ |
64 | // Nearby |
65 | computed(nearby, n => !isEmpty(n) ? h('header', strings.peopleNearby) : null), |
66 | map(nearby, feedId => Option({ |
67 | notifications: Math.random() > 0.7 ? Math.floor(Math.random()*9+1) : 0, // TODO |
68 | imageEl: api.about.html.avatar(feedId, 'small'), |
69 | label: api.about.obs.name(feedId), |
70 | selected: location.feed === feedId, |
71 | location: computed(recentMsgLog, recent => { |
72 | const lastMsg = recent[feedId] |
73 | return lastMsg |
74 | ? Object.assign(lastMsg, { feed: feedId }) |
75 | : { page: 'threadNew', feed: feedId } |
76 | }), |
77 | }), { comparer: (a, b) => a === b }), |
78 | |
79 | // --------------------- |
80 | computed(nearby, n => !isEmpty(n) ? h('hr') : null), |
81 | |
82 | // Discover |
83 | Option({ |
84 | notifications: Math.floor(Math.random()*5+1), |
85 | imageEl: h('i.fa.fa-binoculars'), |
86 | label: strings.blogIndex.title, |
87 | selected: isDiscoverContext(location), |
88 | location: { page: 'blogIndex' }, |
89 | }) |
90 | ] |
91 | |
92 | return api.app.html.scroller({ |
93 | classList: [ 'level', '-one' ], |
94 | prepend, |
95 | stream: api.feed.pull.private, |
96 | filter: pull( |
97 | pull.filter(msg => msg.value.content.type === 'post'), // TODO is this the best way to protect against votes? |
98 | pull.filter(msg => msg.value.author != myKey), |
99 | pull.filter(msg => msg.value.content.recps), |
100 | pull.through(updateRecentMsgLog), |
101 | pull.filter(isLatestMsg) |
102 | //pull.through( // trim exisiting from content up Top case) // do this with new updateTop in mutant-scroll |
103 | ), |
104 | render: (msg) => { |
105 | const { author } = msg.value |
106 | if (nearby.has(author)) return |
107 | |
108 | return Option({ |
109 | notifications: Math.random() > 0.7 ? Math.floor(Math.random()*9+1) : 0, // TODO |
110 | imageEl: api.about.html.avatar(author), |
111 | label: api.about.obs.name(author), |
112 | selected: location.feed === author, |
113 | location: Object.assign({}, msg, { feed: author }) // TODO make obs? |
114 | }) |
115 | } |
116 | }) |
117 | } |
118 | |
119 | function LevelTwoContext () { |
120 | const { key, value, feed: targetUser, page } = location |
121 | const root = get(value, 'content.root', key) |
122 | if (!targetUser) return |
123 | |
124 | var threads = MutantArray() |
125 | |
126 | pull( |
127 | next(api.feed.pull.private, {reverse: true, limit: 100, live: false}, ['value', 'timestamp']), |
128 | pull.filter(msg => msg.value.content.recps), |
129 | pull.filter(msg => msg.value.content.recps |
130 | .map(recp => typeof recp === 'object' ? recp.link : recp) |
131 | .some(recp => recp === targetUser) |
132 | ), |
133 | api.feed.pull.rollup(), |
134 | pull.drain(thread => threads.push(thread)) |
135 | ) |
136 | |
137 | return h('div.level.-two', [ |
138 | Option({ |
139 | selected: page === 'threadNew', |
140 | location: {page: 'threadNew', feed: targetUser}, |
141 | label: h('Button', strings.threadNew.action.new), |
142 | }), |
143 | map(threads, thread => { |
144 | return Option({ |
145 | label: api.message.html.subject(thread), |
146 | selected: thread.key === root, |
147 | location: Object.assign(thread, { feed: targetUser }), |
148 | }) |
149 | }, { comparer: (a, b) => a === b }) |
150 | ]) |
151 | } |
152 | |
153 | function Option ({ notifications = 0, imageEl, label, location, selected }) { |
154 | const className = selected ? '-selected' : '' |
155 | const goToLocation = (e) => { |
156 | e.preventDefault() |
157 | e.stopPropagation() |
158 | api.history.sync.push(resolve(location)) |
159 | } |
160 | |
161 | if (!imageEl) { |
162 | return h('Option', { className, 'ev-click': goToLocation }, [ |
163 | h('div.label', label) |
164 | ]) |
165 | } |
166 | |
167 | return h('Option', { className }, [ |
168 | h('div.circle', [ |
169 | when(notifications, h('div.alert', notifications)), |
170 | imageEl |
171 | ]), |
172 | h('div.label', { 'ev-click': goToLocation }, label) |
173 | ]) |
174 | } |
175 | }) |
176 | } |
177 | |
178 |
Built with git-ssb-web