git ssb

10+

Matt McKegg / patchwork



Tree: dada655d48da0b7c97d7025d424cad81f4649e60

Files: dada655d48da0b7c97d7025d424cad81f4649e60 / modules / page / html / render / public.js

6916 bytesRaw
1var nest = require('depnest')
2var { h, send, when, computed, map } = require('mutant')
3var extend = require('xtend')
4var pull = require('pull-stream')
5
6exports.gives = nest({
7 'page.html.render': true
8})
9
10exports.needs = nest({
11 sbot: {
12 pull: {
13 log: 'first',
14 feed: 'first',
15 userFeed: 'first'
16 },
17 async: {
18 publish: 'first'
19 },
20 obs: {
21 connectedPeers: 'first',
22 localPeers: 'first'
23 }
24 },
25 'about.html.image': 'first',
26 'about.obs.name': 'first',
27
28 'feed.html.rollup': 'first',
29 'profile.obs.recentlyUpdated': 'first',
30 'contact.obs.following': 'first',
31 'channel.obs': {
32 subscribed: 'first',
33 recent: 'first'
34 },
35 'keys.sync.id': 'first'
36})
37
38exports.create = function (api) {
39 return nest('page.html.render', page)
40
41 function page (path) {
42 if (path !== '/public') return // "/" is a sigil for "page"
43
44 var id = api.keys.sync.id()
45 var following = api.contact.obs.following(id)
46 var subscribedChannels = api.channel.obs.subscribed(id)
47 var loading = computed(subscribedChannels.sync, x => !x)
48 var channels = computed(api.channel.obs.recent(), items => items.slice(0, 8), {comparer: arrayEq})
49 var connectedPeers = api.sbot.obs.connectedPeers()
50 var localPeers = api.sbot.obs.localPeers()
51 var connectedPubs = computed([connectedPeers, localPeers], (c, l) => c.filter(x => !l.includes(x)))
52
53 var oldest = Date.now() - (2 * 24 * 60 * 60e3)
54 getFirstMessage(id, (_, msg) => {
55 if (msg) {
56 // fall back to timestamp stream before this, give 48 hrs for feeds to stabilize
57 if (msg.value.timestamp > oldest) {
58 oldest = Date.now()
59 }
60 }
61 })
62
63 var feedView = api.feed.html.rollup(getFeed, {
64 waitUntil: computed([
65 following.sync,
66 subscribedChannels.sync
67 ], (...x) => x.every(Boolean)),
68 windowSize: 500,
69 filter: (item) => {
70 return !item.boxed && (
71 id === item.author ||
72 following().has(item.author) ||
73 subscribedChannels().has(item.channel) ||
74 (item.repliesFrom && item.repliesFrom.has(id)) ||
75 item.digs && item.digs.has(id)
76 )
77 },
78 bumpFilter: (msg, group) => {
79 if (!group.message) {
80 return (
81 isMentioned(id, msg.value.content.mentions) ||
82 msg.value.author === id || (
83 fromDay(msg, group.fromTime) && (
84 following().has(msg.value.author) ||
85 group.repliesFrom.has(id)
86 )
87 )
88 )
89 }
90 return true
91 }
92 })
93
94 var result = h('div.SplitView', [
95 h('div.side', [
96 getSidebar()
97 ]),
98 h('div.main', feedView)
99 ])
100
101 result.pendingUpdates = feedView.pendingUpdates
102
103 return result
104
105 function getSidebar () {
106 var whoToFollow = computed([following, api.profile.obs.recentlyUpdated(200)], (following, recent) => {
107 return Array.from(recent).filter(x => x !== id && !following.has(x)).slice(0, 10)
108 })
109 return [
110 h('h2', 'Active Channels'),
111 when(loading, [ h('Loading') ]),
112 h('div', {
113 classList: 'ChannelList',
114 hidden: loading
115 }, [
116 map(channels, (channel) => {
117 var subscribed = subscribedChannels.has(channel.id)
118 return h('a.channel', {
119 href: `#${channel.id}`,
120 classList: [
121 when(subscribed, '-subscribed')
122 ]
123 }, [
124 h('span.name', '#' + channel.id),
125 when(subscribed,
126 h('a.-unsubscribe', {
127 'ev-click': send(unsubscribe, channel.id)
128 }, 'Unsubscribe'),
129 h('a.-subscribe', {
130 'ev-click': send(subscribe, channel.id)
131 }, 'Subscribe')
132 )
133 ])
134 }, {maxTime: 5})
135 ]),
136
137 when(computed(localPeers, x => x.length), h('h2', 'Local')),
138 h('div', {
139 classList: 'ProfileList'
140 }, [
141 map(localPeers, (id) => {
142 return h('a.profile', {
143 classList: [
144 when(computed([connectedPeers, id], (p, id) => p.includes(id)), '-connected')
145 ],
146 href: id
147 }, [
148 h('div.avatar', [api.about.html.image(id)]),
149 h('div.main', [
150 h('div.name', [ '@', api.about.obs.name(id) ])
151 ])
152 ])
153 })
154 ]),
155
156 when(computed(whoToFollow, x => x.length), h('h2', 'Who to follow')),
157 when(following.sync,
158 h('div', {
159 classList: 'ProfileList'
160 }, [
161 map(whoToFollow, (id) => {
162 return h('a.profile', {
163 href: id
164 }, [
165 h('div.avatar', [api.about.html.image(id)]),
166 h('div.main', [
167 h('div.name', [ '@', api.about.obs.name(id) ])
168 ])
169 ])
170 })
171 ]),
172 h('div', {classList: 'Loading'})
173 ),
174
175 when(computed(connectedPubs, x => x.length), h('h2', 'Connected Pubs')),
176 h('div', {
177 classList: 'ProfileList'
178 }, [
179 map(connectedPubs, (id) => {
180 return h('a.profile', {
181 classList: [ '-connected' ],
182 href: id
183 }, [
184 h('div.avatar', [api.about.html.image(id)]),
185 h('div.main', [
186 h('div.name', [ '@', api.about.obs.name(id) ])
187 ])
188 ])
189 })
190 ])
191 ]
192 }
193
194 function getFeed (opts) {
195 if (opts.lt && opts.lt < oldest) {
196 opts = extend(opts, {lt: parseInt(opts.lt, 10)})
197 return pull(
198 api.sbot.pull.feed(opts),
199 pull.map((msg) => {
200 if (msg.sync) {
201 return msg
202 } else {
203 return {key: msg.key, value: msg.value, timestamp: msg.value.timestamp}
204 }
205 })
206 )
207 } else {
208 return api.sbot.pull.log(opts)
209 }
210 }
211
212 function getFirstMessage (feedId, cb) {
213 api.sbot.pull.userFeed({id: feedId, gte: 0, limit: 1})(null, cb)
214 }
215
216 function subscribe (id) {
217 api.sbot.async.publish({
218 type: 'channel',
219 channel: id,
220 subscribed: true
221 })
222 }
223
224 function unsubscribe (id) {
225 api.sbot.async.publish({
226 type: 'channel',
227 channel: id,
228 subscribed: false
229 })
230 }
231 }
232}
233
234function isMentioned (id, list) {
235 if (Array.isArray(list)) {
236 return list.includes(id)
237 } else {
238 return false
239 }
240}
241
242function fromDay (msg, fromTime) {
243 return (fromTime - msg.timestamp) < (24 * 60 * 60e3)
244}
245
246function arrayEq (a, b) {
247 if (Array.isArray(a) && Array.isArray(b) && a.length === b.length && a !== b) {
248 return a.every((value, i) => value === b[i])
249 }
250}
251

Built with git-ssb-web