git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 58d09b546019da27320afef34de21bd46d0d03cf

Files: 58d09b546019da27320afef34de21bd46d0d03cf / modules / page / html / render / public.js

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

Built with git-ssb-web