git ssb

10+

Matt McKegg / patchwork



Tree: 1a1dfa987b784a002e626f97e18aeaf2164d1299

Files: 1a1dfa987b784a002e626f97e18aeaf2164d1299 / modules / page / html / render / public.js

7005 bytesRaw
1var nest = require('depnest')
2var extend = require('xtend')
3var pull = require('pull-stream')
4var normalizeChannel = require('../../../../lib/normalize-channel')
5var { h, send, when, computed, map } = require('mutant')
6
7var appRoot = require('app-root-path');
8var i18n = require(appRoot + '/lib/i18n').i18n
9
10
11exports.needs = nest({
12 sbot: {
13 obs: {
14 connectedPeers: 'first',
15 localPeers: 'first'
16 }
17 },
18 'sbot.pull.stream': 'first',
19 'feed.pull.public': 'first',
20 'about.html.image': 'first',
21 'about.obs.name': 'first',
22 'invite.sheet': 'first',
23
24 'message.html.compose': 'first',
25 'message.async.publish': 'first',
26 'progress.html.peer': '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 'settings.obs.get': 'first'
37})
38
39exports.gives = nest({
40 'page.html.render': true
41})
42
43exports.create = function (api) {
44 return nest('page.html.render', page)
45
46 function page (path) {
47 if (path !== '/public') return // "/" is a sigil for "page"
48
49 var id = api.keys.sync.id()
50 var following = api.contact.obs.following(id)
51 var subscribedChannels = api.channel.obs.subscribed(id)
52 var recentChannels = api.channel.obs.recent()
53 var loading = computed([subscribedChannels.sync, recentChannels.sync], (...args) => !args.every(Boolean))
54 var channels = computed(recentChannels, items => items.slice(0, 8), {comparer: arrayEq})
55 var connectedPeers = api.sbot.obs.connectedPeers()
56 var localPeers = api.sbot.obs.localPeers()
57 var connectedPubs = computed([connectedPeers, localPeers], (c, l) => c.filter(x => !l.includes(x)))
58
59 var prepend = [
60 api.message.html.compose({ meta: { type: 'post' }, placeholder: i18n.__('Write a public message') })
61 ]
62
63 var getStream = (opts) => {
64 if (opts.lt != null && !opts.lt.marker) {
65 // if an lt has been specified that is not a marker, assume stream is finished
66 return pull.empty()
67 } else {
68 return api.sbot.pull.stream(sbot => sbot.patchwork.roots(extend(opts, { ids: [id] })))
69 }
70 }
71
72 var filters = api.settings.obs.get('filters')
73 var feedView = api.feed.html.rollup(getStream, {
74 prepend,
75 updateStream: api.sbot.pull.stream(sbot => sbot.patchwork.latest({ids: [id]})),
76 bumpFilter: function (msg) {
77 if (msg.value && msg.value.content && typeof msg.value.content === 'object') {
78 var type = msg.value.content.type
79 if (type === 'vote') return false
80
81 var author = msg.value.author
82 var channel = normalizeChannel(msg.value.content.channel)
83 var isSubscribed = channel ? subscribedChannels().has(channel) : false
84 return isSubscribed || id === author || following().includes(author)
85 }
86 },
87 rootFilter: function (msg) {
88 if (!filters()) return true
89 return !(filters().following && getType(msg) === 'contact')
90 },
91 waitFor: computed([
92 following.sync,
93 subscribedChannels.sync
94 ], (...x) => x.every(Boolean))
95 })
96
97 // call reload whenever filters changes (equivalent to the refresh from inside rollup)
98 filters(feedView.reload)
99
100 var result = h('div.SplitView', [
101 h('div.side', [
102 getSidebar()
103 ]),
104 h('div.main', feedView)
105 ])
106
107 result.pendingUpdates = feedView.pendingUpdates
108 result.reload = feedView.reload
109
110 return result
111
112 function getSidebar () {
113 var whoToFollow = computed([following, api.profile.obs.recentlyUpdated(), localPeers], (following, recent, peers) => {
114 return recent.filter(x => x !== id && !following.includes(x) && !peers.includes(x)).slice(0, 10)
115 })
116 return [
117 h('button -pub -full', {
118 'ev-click': api.invite.sheet
119 }, i18n.__('+ Join Pub')),
120 when(loading, [ h(i18n.__("Loading")) ], [
121 when(computed(channels, x => x.length), h('h2', i18n.__("Active Channels"))),
122 h('div', {
123 classList: 'ChannelList',
124 hidden: loading
125 }, [
126 map(channels, (channel) => {
127 var subscribed = subscribedChannels.has(channel)
128 return h('a.channel', {
129 href: `#${channel}`,
130 classList: [
131 when(subscribed, '-subscribed')
132 ]
133 }, [
134 h('span.name', '#' + channel),
135 when(subscribed,
136 h('a.-unsubscribe', {
137 'ev-click': send(unsubscribe, channel)
138 }, i18n.__('Unsubscribe')),
139 h('a.-subscribe', {
140 'ev-click': send(subscribe, channel)
141 }, i18n.__('Subscribe'))
142 )
143 ])
144 }, {maxTime: 5}),
145 h('a.channel -more', {href: '/channels'}, i18n.__('More Channels...'))
146 ])
147 ]),
148
149 PeerList(localPeers, i18n.__('Local')),
150 PeerList(connectedPubs, i18n.__('Connected Pubs')),
151
152 when(computed(whoToFollow, x => x.length), h('h2', i18n.__('Who to follow'))),
153 when(following.sync,
154 h('div', {
155 classList: 'ProfileList'
156 }, [
157 map(whoToFollow, (id) => {
158 return h('a.profile', {
159 href: id
160 }, [
161 h('div.avatar', [api.about.html.image(id)]),
162 h('div.main', [
163 h('div.name', [ api.about.obs.name(id) ])
164 ])
165 ])
166 })
167 ])
168 )
169 ]
170 }
171
172 function PeerList (ids, title) {
173 return [
174 when(computed(ids, x => x.length), h('h2', title)),
175 h('div', {
176 classList: 'ProfileList'
177 }, [
178 map(ids, (id) => {
179 var connected = computed([connectedPeers, id], (peers, id) => peers.includes(id))
180 return h('a.profile', {
181 classList: [
182 when(connected, '-connected')
183 ],
184 href: id
185 }, [
186 h('div.avatar', [api.about.html.image(id)]),
187 h('div.main', [
188 h('div.name', [ api.about.obs.name(id) ])
189 ]),
190 h('div.progress', [
191 api.progress.html.peer(id)
192 ])
193 ])
194 })
195 ])
196 ]
197 }
198
199 function subscribe (id) {
200 api.message.async.publish({
201 type: 'channel',
202 channel: id,
203 subscribed: true
204 })
205 }
206
207 function unsubscribe (id) {
208 api.message.async.publish({
209 type: 'channel',
210 channel: id,
211 subscribed: false
212 })
213 }
214 }
215}
216
217function getType (msg) {
218 return msg && msg.value && msg.value.content && msg.value.content.type
219}
220
221function arrayEq (a, b) {
222 if (Array.isArray(a) && Array.isArray(b) && a.length === b.length && a !== b) {
223 return a.every((value, i) => value === b[i])
224 }
225}
226

Built with git-ssb-web