git ssb

10+

Matt McKegg / patchwork



Commit 168a44f801f80b2e597db0f95879065823d1d9df

add link previews for channels and show following subscribers

also remove old channel subscribe hover links since not needed with
preview
Matt McKegg committed on 2/12/2018, 2:44:00 AM
Parent: 6d887637d16d755298b8177960c699201a62b831

Files changed

locales/en.jsonchanged
modules/app/link-preview.jschanged
modules/channel/obs/subscribers.jsadded
modules/channel/html/preview.jsadded
modules/channel/html/subscribe-toggle.jsadded
modules/page/html/render/channel.jschanged
modules/page/html/render/channels.jschanged
modules/page/html/render/public.jschanged
sbot/subscriptions.jschanged
locales/en.jsonView
@@ -33,9 +33,9 @@
3333 "other": "You share %s mutual friends with this person."
3434 },
3535 "Followed by": "Followed by",
3636 "You follow %s people that follow this person.": {
37- "one": "You follow %s people that follow this person.",
37+ "one": "You follow %s person that follows this person.",
3838 "other": "You follow %s people that follow this person."
3939 },
4040 "Send Private Message": "Send Private Message",
4141 "Friends": "Friends",
@@ -159,6 +159,11 @@
159159 " via ": " via ",
160160 "The author of this message could be outside of your follow range or they may be blocked.": "The author of this message could be outside of your follow range or they may be blocked.",
161161 "Close": "Close",
162162 " referenced this message:": " referenced this message:",
163- "on ": "on "
164-}
163+ "on ": "on ",
164+ "You follow %s people that subscribe to this channel.": {
165+ "one": "You follow %s person that subscribes to this channel.",
166+ "other": "You follow %s people that subscribe to this channel."
167+ },
168+ "People you follow that subscribe to this channel": "People you follow that subscribe to this channel"
169+}
modules/app/link-preview.jsView
@@ -5,9 +5,10 @@
@@ -52,8 +53,10 @@
modules/channel/obs/subscribers.jsView
@@ -1,0 +1,32 @@
1+var nest = require('depnest')
2+var MutantPullReduce = require('mutant-pull-reduce')
3+
4+exports.needs = nest({
5+ 'keys.sync.id': 'first',
6+ 'sbot.pull.stream': 'first'
7+})
8+
9+exports.gives = nest('channel.obs.subscribers')
10+
11+exports.create = function (api) {
12+ return nest('channel.obs.subscribers', function (channel) {
13+ var stream = api.sbot.pull.stream(sbot => sbot.patchwork.subscriptions({live: true, channel}))
14+ return MutantPullReduce(stream, (state, msg) => {
15+ if (msg.value) {
16+ if (!state.includes(msg.from)) {
17+ state.push(msg.from)
18+ }
19+ } else {
20+ var index = state.indexOf(msg.from)
21+ if (index >= 0) {
22+ state.splice(index, 1)
23+ }
24+ }
25+ return state
26+ }, {
27+ startValue: [],
28+ nextTick: true,
29+ sync: true
30+ })
31+ })
32+}
modules/channel/html/preview.jsView
@@ -1,0 +1,70 @@
1+var nest = require('depnest')
2+var h = require('mutant/h')
3+var map = require('mutant/map')
4+var when = require('mutant/when')
5+var computed = require('mutant/computed')
6+var send = require('mutant/send')
7+
8+exports.needs = nest({
9+ 'about.obs.name': 'first',
10+ 'about.html.image': 'first',
11+ 'keys.sync.id': 'first',
12+ 'sheet.display': 'first',
13+ 'app.navigate': 'first',
14+ 'intl.sync.i18n': 'first',
15+ 'intl.sync.i18n_n': 'first',
16+ 'sheet.profiles': 'first',
17+ 'channel.html.subscribeToggle': 'first',
18+ 'channel.sync.normalize': 'first',
19+ 'channel.obs.subscribers': 'first',
20+ 'contact.obs.following': 'first'
21+})
22+
23+exports.gives = nest('channel.html.preview')
24+
25+exports.create = function (api) {
26+ const i18n = api.intl.sync.i18n
27+ const plural = api.intl.sync.i18n_n
28+
29+ return nest('channel.html.preview', function (id) {
30+ var yourId = api.keys.sync.id()
31+ var channel = api.channel.sync.normalize(id)
32+ var href = '#' + channel
33+ var subscribers = api.channel.obs.subscribers(id)
34+ var following = api.contact.obs.following(yourId)
35+ var followingSubscribers = computed([subscribers, following], (a, b) => {
36+ return a.filter(v => b.includes(v))
37+ })
38+ var followingSubscriberCount = computed(followingSubscribers, x => x.length)
39+
40+ return h('ProfilePreview', [
41+ h('header', [
42+ h('div.main', [
43+ h('div.title', [
44+ h('h1', [
45+ h('a', {href, 'ev-click': () => api.app.navigate(href)}, [href])
46+ ]),
47+ h('div.meta', [
48+ api.channel.html.subscribeToggle(channel)
49+ ])
50+ ])
51+ ])
52+ ]),
53+
54+ when(followingSubscriberCount,
55+ h('section -mutualFriends', [
56+ h('a', {
57+ href: '#',
58+ 'ev-click': send(displaySubscribingFriends, followingSubscribers)
59+ }, [
60+ '๐Ÿ‘ฅ ', computed(['You follow %s people that subscribe to this channel.', followingSubscriberCount], plural)
61+ ])
62+ ])
63+ )
64+ ])
65+ })
66+
67+ function displaySubscribingFriends (profiles) {
68+ api.sheet.profiles(profiles, i18n('People you follow that subscribe to this channel'))
69+ }
70+}
modules/channel/html/subscribe-toggle.jsView
@@ -1,0 +1,48 @@
1+var nest = require('depnest')
2+var { h, when, send } = require('mutant')
3+
4+exports.gives = nest('channel.html.subscribeToggle')
5+exports.needs = nest({
6+ 'intl.sync.i18n': 'first',
7+ 'keys.sync.id': 'first',
8+ 'message.async.publish': 'first',
9+ 'channel.obs.subscribed': 'first'
10+})
11+
12+exports.create = function (api) {
13+ var i18n = api.intl.sync.i18n
14+ return nest('channel.html.subscribeToggle', function (channel, opts) {
15+ var yourId = api.keys.sync.id()
16+ var subscribedChannels = api.channel.obs.subscribed(yourId)
17+
18+ return when(subscribedChannels.has(channel),
19+ h('a.ToggleButton.-unsubscribe', {
20+ 'href': '#',
21+ 'title': i18n('Click to unsubscribe'),
22+ 'ev-click': send(unsubscribe, channel)
23+ }, i18n('Subscribed')),
24+ h('a.ToggleButton.-subscribe', {
25+ 'href': '#',
26+ 'ev-click': send(subscribe, channel)
27+ }, i18n('Subscribe'))
28+ )
29+ })
30+
31+ function subscribe (id) {
32+ // confirm
33+ api.message.async.publish({
34+ type: 'channel',
35+ channel: id,
36+ subscribed: true
37+ })
38+ }
39+
40+ function unsubscribe (id) {
41+ // confirm
42+ api.message.async.publish({
43+ type: 'channel',
44+ channel: id,
45+ subscribed: false
46+ })
47+ }
48+}
modules/page/html/render/channel.jsView
@@ -1,11 +1,11 @@
1-var { h, when, send } = require('mutant')
1+var { h } = require('mutant')
22 var nest = require('depnest')
33
44 exports.needs = nest({
5- 'channel.obs.subscribed': 'first',
65 'message.html.compose': 'first',
76 'channel.sync.normalize': 'first',
7+ 'channel.html.subscribeToggle': 'first',
88 'feed.html.rollup': 'first',
99 'feed.html.followWarning': 'first',
1010 'feed.pull.channel': 'first',
1111 'sbot.pull.log': 'first',
@@ -23,29 +23,17 @@
2323 return nest('page.html.render', function channel (path) {
2424 if (path[0] !== '#') return
2525
2626 var id = api.keys.sync.id()
27+ var contact = api.profile.obs.contact(id)
2728
2829 var channel = api.channel.sync.normalize(path.substr(1))
29- var subscribedChannels = api.channel.obs.subscribed(id)
3030
31- var contact = api.profile.obs.contact(id)
32-
3331 var prepend = [
3432 h('PageHeading', [
3533 h('h1', `#${channel}`),
3634 h('div.meta', [
37- when(subscribedChannels.has(channel),
38- h('a.ToggleButton.-unsubscribe', {
39- 'href': '#',
40- 'title': i18n('Click to unsubscribe'),
41- 'ev-click': send(unsubscribe, channel)
42- }, i18n('Subscribed')),
43- h('a.ToggleButton.-subscribe', {
44- 'href': '#',
45- 'ev-click': send(subscribe, channel)
46- }, i18n('Subscribe'))
47- )
35+ api.channel.html.subscribeToggle(channel)
4836 ])
4937 ]),
5038 api.message.html.compose({
5139 meta: {type: 'post', channel},
@@ -102,23 +90,5 @@
10290 var warning = i18n('You may not be able to see new channel content until you follow some users or pubs.')
10391 return api.feed.html.followWarning(contact.isNotFollowingAnybody, warning)
10492 }
10593 })
106-
107- function subscribe (id) {
108- // confirm
109- api.message.async.publish({
110- type: 'channel',
111- channel: id,
112- subscribed: true
113- })
114- }
115-
116- function unsubscribe (id) {
117- // confirm
118- api.message.async.publish({
119- type: 'channel',
120- channel: id,
121- subscribed: false
122- })
123- }
12494 }
modules/page/html/render/channels.jsView
@@ -36,17 +36,9 @@
3636 classList: [
3737 when(subscribed, '-subscribed')
3838 ]
3939 }, [
40- h('span.name', '#' + channel),
41- when(subscribed,
42- h('a.-unsubscribe', {
43- 'ev-click': send(unsubscribe, channel)
44- }, i18n('Unsubscribe')),
45- h('a.-subscribe', {
46- 'ev-click': send(subscribe, channel)
47- }, i18n('Subscribe'))
48- )
40+ h('span.name', '#' + channel)
4941 ])
5042 }, {maxTime: 5, idle: true})
5143 ])
5244 ])
modules/page/html/render/public.jsView
@@ -201,17 +201,9 @@
201201 classList: [
202202 when(subscribed, '-subscribed')
203203 ]
204204 }, [
205- h('span.name', '#' + channel),
206- when(subscribed,
207- h('a.-unsubscribe', {
208- 'ev-click': send(unsubscribe, channel)
209- }, i18n('Unsubscribe')),
210- h('a.-subscribe', {
211- 'ev-click': send(subscribe, channel)
212- }, i18n('Subscribe'))
213- )
205+ h('span.name', '#' + channel)
214206 ])
215207 }, {maxTime: 5}),
216208 h('a.channel -more', {href: '/channels'}, i18n('More Channels...'))
217209 ])
sbot/subscriptions.jsView
@@ -1,9 +1,34 @@
11 var FlumeReduce = require('flumeview-reduce')
22 var normalizeChannel = require('ssb-ref').normalizeChannel
3+var FlatMap = require('pull-flatmap')
4+var pull = require('pull-stream')
35
46 module.exports = function (ssb, config) {
5- return ssb._flumeUse('patchwork-subscriptions', FlumeReduce(3, reduce, map))
7+ var index = ssb._flumeUse('patchwork-subscriptions', FlumeReduce(3, reduce, map))
8+ return {
9+ stream: function (opts) {
10+ var channel = normalizeChannel(opts.channel)
11+ return pull(
12+ index.stream({live: opts.live}),
13+ FlatMap(items => {
14+ var result = []
15+
16+ if (items) {
17+ Object.keys(items).forEach(key => {
18+ var parts = getParts(key)
19+ if (parts && (!channel || parts[1] === channel)) {
20+ result.push({from: parts[0], to: parts[1], value: items[key][1], ts: items[key][0]})
21+ }
22+ })
23+ }
24+
25+ return result
26+ })
27+ )
28+ },
29+ get: index.get
30+ }
631 }
732
833 function reduce (result, item) {
934 if (!result) result = {}
@@ -16,8 +41,15 @@
1641 }
1742 return result
1843 }
1944
45+function getParts (value) {
46+ var splitIndex = value.indexOf(':')
47+ if (splitIndex > 50) { // HACK: yup
48+ return [value.slice(0, splitIndex), value.slice(splitIndex + 1)]
49+ }
50+}
51+
2052 function map (msg) {
2153 if (msg.value.content && msg.value.content.type === 'channel') {
2254 if (typeof msg.value.content.subscribed === 'boolean') {
2355 var channel = normalizeChannel(msg.value.content.channel)

Built with git-ssb-web