Commit 2f8b5a42a327baeb86c4cc6af56c65848948d0ec
Merge pull request #83 from ticktackim/subscriptions
Subscriptionsmix irving authored on 2/6/2018, 10:23:41 AM
GitHub committed on 2/6/2018, 10:23:41 AM
Parent: e2fb4d766af3a45d510a0558e410b04dd3366e13
Parent: 235b36e740aa5e415143769f66b42154fb4365d2
Files changed
.gitignore | changed |
app/html/channelCard.js | changed |
app/html/sideNav/sideNavDiscovery.js | changed |
app/page/channelShow.js | changed |
app/page/channelSubscriptions.js | changed |
channel/index.js | changed |
channel/sync.js | deleted |
channel/obs.js | added |
translations/en.js | changed |
app/html/channelCard.js | ||
---|---|---|
@@ -1,12 +1,8 @@ | ||
1 | -var nest = require('depnest') | |
2 | -const { h, map, when, Value } = require('mutant') | |
3 | -var isString= require('lodash/isString') | |
4 | -var maxBy= require('lodash/maxBy') | |
5 | -var markdown = require('ssb-markdown') | |
6 | -var ref = require('ssb-ref') | |
7 | -var htmlEscape = require('html-escape') | |
1 | +const nest = require('depnest') | |
2 | +const { h, when } = require('mutant') | |
8 | 3 | |
4 | + | |
9 | 5 | exports.gives = nest('app.html.channelCard') |
10 | 6 | |
11 | 7 | exports.needs = nest({ |
12 | 8 | 'keys.sync.id': 'first', |
@@ -14,46 +10,34 @@ | ||
14 | 10 | 'translations.sync.strings': 'first', |
15 | 11 | 'channel.obs.subscribed': 'first', |
16 | 12 | 'channel.async.subscribe': 'first', |
17 | 13 | 'channel.async.unsubscribe': 'first', |
18 | - 'channel.sync.isSubscribedTo': 'first', | |
14 | + 'channel.obs.isSubscribedTo': 'first', | |
19 | 15 | }) |
20 | 16 | |
21 | 17 | exports.create = function (api) { |
22 | 18 | |
23 | 19 | return nest('app.html.channelCard', (channel) => { |
24 | - var strings = api.translations.sync.strings() | |
25 | - | |
20 | + const strings = api.translations.sync.strings() | |
26 | 21 | const myId = api.keys.sync.id() |
27 | - const { subscribed } = api.channel.obs | |
28 | 22 | const { subscribe, unsubscribe } = api.channel.async |
29 | - const { isSubscribedTo } = api.channel.sync | |
30 | - const myChannels = subscribed(myId) | |
31 | - let cs = myChannels().values() | |
32 | - const youSubscribe = Value(isSubscribedTo(channel, myId)) | |
33 | - | |
34 | - let cb = () => { | |
35 | - youSubscribe.set(isSubscribedTo(channel, myId)) | |
36 | - } | |
23 | + const { isSubscribedTo } = api.channel.obs | |
24 | + const youSubscribe = isSubscribedTo(channel, myId) | |
37 | 25 | |
38 | - const goToChannel = (e, channel) => { | |
39 | - e.stopPropagation() | |
40 | - | |
26 | + const goToChannel = () => { | |
41 | 27 | api.history.sync.push({ page: 'channelShow', channel: channel }) |
42 | 28 | } |
43 | 29 | |
44 | - var b = h('ChannelCard', [ | |
30 | + return h('ChannelCard', [ | |
45 | 31 | h('div.content', [ |
46 | 32 | h('div.text', [ |
47 | - h('h2', {'ev-click': ev => goToChannel(ev, channel)}, channel), | |
33 | + h('h2', {'ev-click': goToChannel}, channel), | |
48 | 34 | when(youSubscribe, |
49 | - h('Button', { 'ev-click': () => unsubscribe(channel, cb) }, strings.channelShow.action.unsubscribe), | |
50 | - h('Button', { 'ev-click': () => subscribe(channel, cb) }, strings.channelShow.action.subscribe) | |
35 | + h('Button', { 'ev-click': () => unsubscribe(channel) }, strings.channelShow.action.unsubscribe), | |
36 | + h('Button', { 'ev-click': () => subscribe(channel) }, strings.channelShow.action.subscribe) | |
51 | 37 | ), |
52 | 38 | ]) |
53 | 39 | ]) |
54 | 40 | ]) |
55 | - | |
56 | - return b | |
57 | 41 | }) |
58 | 42 | } |
59 | 43 |
app/html/sideNav/sideNavDiscovery.js | ||
---|---|---|
@@ -45,8 +45,9 @@ | ||
45 | 45 | if (location.page) { |
46 | 46 | if (location.page.match(/^blog/)) return true |
47 | 47 | if (location.page.match(/^thread/)) return true |
48 | 48 | if (location.page.match(/^user/)) return true |
49 | + if (location.page.match(/^channel/)) return true | |
49 | 50 | } |
50 | 51 | if (location.key) { |
51 | 52 | return true |
52 | 53 | } |
@@ -136,9 +137,9 @@ | ||
136 | 137 | Option({ |
137 | 138 | imageEl: h('i', [ |
138 | 139 | h('img', { src: path.join(__dirname, '../../../assets', 'discover.png') }) |
139 | 140 | ]), |
140 | - label: "My subscriptions", | |
141 | + label: strings.subscriptions.user, | |
141 | 142 | selected: location.page === 'channelSubscriptions' && !location.scope, |
142 | 143 | location: { page: 'channelSubscriptions', scope: 'user' }, |
143 | 144 | }), |
144 | 145 | |
@@ -146,9 +147,9 @@ | ||
146 | 147 | Option({ |
147 | 148 | imageEl: h('i', [ |
148 | 149 | h('img', { src: path.join(__dirname, '../../../assets', 'discover.png') }) |
149 | 150 | ]), |
150 | - label: "Friends subscriptions", | |
151 | + label: strings.subscriptions.friends, | |
151 | 152 | selected: location.page === 'channelSubscriptions' && location.scope === 'friends', |
152 | 153 | location: { page: 'channelSubscriptions', scope: 'friends' }, |
153 | 154 | }) |
154 | 155 | ] |
app/page/channelShow.js | ||
---|---|---|
@@ -10,18 +10,15 @@ | ||
10 | 10 | 'app.html.scroller': 'first', |
11 | 11 | 'app.html.blogCard': 'first', |
12 | 12 | 'channel.obs.recent': 'first', |
13 | 13 | 'feed.pull.channel': 'first', |
14 | - 'feed.pull.public': 'first', | |
15 | 14 | 'history.sync.push': 'first', |
16 | 15 | 'keys.sync.id': 'first', |
17 | - 'message.html.channel': 'first', | |
18 | 16 | 'translations.sync.strings': 'first', |
19 | - 'unread.sync.isUnread': 'first', | |
20 | 17 | 'channel.obs.subscribed': 'first', |
21 | 18 | 'channel.async.subscribe': 'first', |
22 | 19 | 'channel.async.unsubscribe': 'first', |
23 | - 'channel.sync.isSubscribedTo': 'first' | |
20 | + 'channel.obs.isSubscribedTo': 'first' | |
24 | 21 | }) |
25 | 22 | |
26 | 23 | exports.create = (api) => { |
27 | 24 | return nest('app.page.channelShow', channelShow) |
@@ -31,23 +28,12 @@ | ||
31 | 28 | var strings = api.translations.sync.strings() |
32 | 29 | const myId = api.keys.sync.id() |
33 | 30 | const { subscribed } = api.channel.obs |
34 | 31 | const { subscribe, unsubscribe } = api.channel.async |
35 | - const { isSubscribedTo } = api.channel.sync | |
36 | - const myChannels = subscribed(myId) | |
37 | - let cs = myChannels().values() | |
38 | - const youSubscribe = Value(isSubscribedTo(location.channel, myId)) | |
32 | + const { isSubscribedTo } = api.channel.obs | |
33 | + const youSubscribe = isSubscribedTo(location.channel, myId) | |
39 | 34 | |
40 | - let cb = () => { | |
41 | - youSubscribe.set(isSubscribedTo(location.channel, myId)) | |
42 | - } | |
43 | - | |
44 | 35 | var searchVal = resolve(location.channel) |
45 | - var searchResults = computed([api.channel.obs.recent(), searchVal], (channels, val) => { | |
46 | - if (val.length < 2) return [] | |
47 | - | |
48 | - return channels.filter(c => c.toLowerCase().indexOf(val.toLowerCase()) > -1) | |
49 | - }) | |
50 | 36 | |
51 | 37 | |
52 | 38 | |
53 | 39 | createStream = api.feed.pull.channel(location.channel) |
@@ -58,10 +44,10 @@ | ||
58 | 44 | h('section.about', [ |
59 | 45 | h('h1', location.channel), |
60 | 46 | h('div.actions', [ |
61 | 47 | when(youSubscribe, |
62 | - h('Button', { 'ev-click': () => subscribe(location.channel, cb) }, strings.channelShow.action.unsubscribe), | |
63 | - h('Button', { 'ev-click': () => unsubscribe(location.channel, cb) }, strings.channelShow.action.subscribe) | |
48 | + h('Button', { 'ev-click': () => subscribe(location.channel) }, strings.channelShow.action.unsubscribe), | |
49 | + h('Button', { 'ev-click': () => unsubscribe(location.channel) }, strings.channelShow.action.subscribe) | |
64 | 50 | ) |
65 | 51 | ]) |
66 | 52 | ]), |
67 | 53 | ] |
app/page/channelSubscriptions.js | ||
---|---|---|
@@ -1,11 +1,8 @@ | ||
1 | 1 | const nest = require('depnest') |
2 | -const { h, watch, when, computed, Value, Set: MutantSet } = require('mutant') | |
3 | -const pull = require('pull-stream') | |
4 | -const Pushable = require('pull-pushable') | |
5 | -const ref = require('ssb-ref') | |
6 | -const throttle = require('mutant/throttle') | |
7 | -const MutantPullReduce = require('mutant-pull-reduce') | |
2 | +const { h, when, Value, onceTrue, computed, map: mutantMap } = require('mutant') | |
3 | +const sortBy = require('lodash/sortBy') | |
4 | +const map = require("lodash/map") | |
8 | 5 | |
9 | 6 | |
10 | 7 | exports.gives = nest('app.page.channelSubscriptions') |
11 | 8 | |
@@ -13,16 +10,17 @@ | ||
13 | 10 | 'app.html.sideNav': 'first', |
14 | 11 | 'app.html.topNav': 'first', |
15 | 12 | 'app.html.scroller': 'first', |
16 | 13 | 'app.html.channelCard': 'first', |
17 | - | |
18 | 14 | 'history.sync.push': 'first', |
19 | 15 | 'keys.sync.id': 'first', |
20 | 16 | 'channel.obs.subscribed': 'first', |
17 | + 'channel.obs.recent':'first', | |
21 | 18 | 'channel.html.link': 'first', |
22 | 19 | 'translations.sync.strings': 'first', |
23 | 20 | 'sbot.async.friendsGet': 'first', |
24 | - 'sbot.pull.userFeed': 'first' | |
21 | + 'sbot.pull.userFeed': 'first', | |
22 | + 'sbot.obs.connection': 'first' | |
25 | 23 | }) |
26 | 24 | |
27 | 25 | exports.create = (api) => { |
28 | 26 | return nest('app.page.channelSubscriptions', function (location) { |
@@ -32,54 +30,56 @@ | ||
32 | 30 | let myChannels, displaySubscriptions |
33 | 31 | |
34 | 32 | if (location.scope === "user") { |
35 | 33 | myChannels = subscribed(myId) |
36 | - displaySubscriptions = () => [...myChannels().values()].map(c => api.app.html.channelCard(c)) | |
34 | + | |
35 | + const mySubscriptions = computed(myChannels, myChannels => [...myChannels.values()]) | |
37 | 36 | |
38 | 37 | return h('Page -channelSubscriptions', { title: strings.home }, [ |
39 | 38 | api.app.html.sideNav(location), |
40 | 39 | h('div.content', [ |
41 | 40 | //api.app.html.topNav(location), |
42 | - when(myChannels, displaySubscriptions, h("p", "Loading...")) | |
41 | + when(myChannels, | |
42 | + myChannels().size === 0 | |
43 | + ? strings.subscriptions.state.noSubscriptions | |
44 | + :'' | |
45 | + ), | |
46 | + when(myChannels, | |
47 | + mutantMap(mySubscriptions, api.app.html.channelCard), | |
48 | + h("p", strings.loading) | |
49 | + ) | |
43 | 50 | ]) |
44 | 51 | ]) |
45 | 52 | |
46 | 53 | } |
47 | 54 | |
48 | 55 | if (location.scope === "friends") { |
49 | 56 | |
50 | - function createStream() { | |
51 | - var p = Pushable(true) // optionally pass `onDone` after it | |
57 | + myChannels = Value(false) | |
52 | 58 | |
53 | - api.sbot.async.friendsGet({ dest: myId }, (err, friends) => { | |
54 | - for (f in friends) { | |
55 | - var s = subscribed(f) | |
56 | - s(c => [...c].map(x => p.push(x))) | |
57 | - } | |
58 | - }) | |
59 | + onceTrue( | |
60 | + api.sbot.obs.connection, | |
61 | + sbot => { | |
62 | + sbot.channel.get((err, c) => { | |
63 | + if (err) throw err | |
64 | + let b = map(c, (v,k) => {return {channel: k, users: v}}) | |
65 | + b = sortBy(b, o => o.users.length) | |
66 | + let res = b.reverse().slice(0,100) | |
59 | 67 | |
60 | - return p.source | |
61 | - } | |
68 | + myChannels.set(res.map(c => c.channel)) | |
69 | + }) | |
70 | + } | |
71 | + ) | |
62 | 72 | |
63 | - var stream = createStream() | |
64 | - var opts = { | |
65 | - startValue: new Set(), | |
66 | - nextTick: true | |
67 | - } | |
68 | 73 | |
69 | - var channelList = api.app.html.scroller({ | |
70 | - classList: ['content'], | |
71 | - stream: createStream, | |
72 | - render | |
73 | - }) | |
74 | - | |
75 | - function render(channel) { | |
76 | - return api.app.html.channelCard(channel) | |
77 | - } | |
78 | - | |
79 | - return h('Page -channelSubscriptions', { title: strings.home }, [ | |
74 | + return h('Page -channelSubscriptions', { title: strings.home }, [ | |
80 | 75 | api.app.html.sideNav(location), |
81 | - channelList | |
76 | + h('div.content', [ | |
77 | + when(myChannels, | |
78 | + mutantMap(myChannels, api.app.html.channelCard), | |
79 | + h("p", strings.loading) | |
80 | + ) | |
81 | + ]) | |
82 | 82 | ]) |
83 | 83 | } |
84 | 84 | }) |
85 | 85 | } |
channel/index.js | ||
---|---|---|
@@ -1,6 +1,6 @@ | ||
1 | 1 | module.exports = { |
2 | 2 | async: require('./async'), |
3 | - sync: require('./sync') | |
3 | + obs: require('./obs') | |
4 | 4 | } |
5 | 5 | |
6 | 6 |
channel/sync.js | ||
---|---|---|
@@ -1,24 +1,0 @@ | ||
1 | -var nest = require('depnest') | |
2 | -var ref = require('ssb-ref') | |
3 | - | |
4 | -exports.needs = nest({ | |
5 | - 'keys.sync.id': 'first', | |
6 | - 'channel.obs.subscribed': 'first', | |
7 | -}) | |
8 | - | |
9 | -exports.gives = nest('channel.sync.isSubscribedTo') | |
10 | - | |
11 | -exports.create = function (api) { | |
12 | - return nest('channel.sync.isSubscribedTo', isSubscribedTo) | |
13 | - | |
14 | - function isSubscribedTo (channel, id) { | |
15 | - if (!ref.isFeed(id)) { | |
16 | - id = api.keys.sync.id() | |
17 | - } | |
18 | - | |
19 | - const { subscribed } = api.channel.obs | |
20 | - const myChannels = subscribed(id) | |
21 | - let v = myChannels().values() | |
22 | - return [...v].includes(channel) | |
23 | - } | |
24 | -} |
channel/obs.js | ||
---|---|---|
@@ -1,0 +1,24 @@ | ||
1 | +const nest = require('depnest') | |
2 | +const ref = require('ssb-ref') | |
3 | +const computed = require('mutant/computed') | |
4 | + | |
5 | +exports.needs = nest({ | |
6 | + 'keys.sync.id': 'first', | |
7 | + 'channel.obs.subscribed': 'first', | |
8 | +}) | |
9 | + | |
10 | +exports.gives = nest('channel.obs.isSubscribedTo') | |
11 | + | |
12 | +exports.create = function (api) { | |
13 | + return nest('channel.obs.isSubscribedTo', isSubscribedTo) | |
14 | + | |
15 | + function isSubscribedTo (channel, id) { | |
16 | + if (!ref.isFeed(id)) { | |
17 | + id = api.keys.sync.id() | |
18 | + } | |
19 | + | |
20 | + const { subscribed } = api.channel.obs | |
21 | + const myChannels = subscribed(id) | |
22 | + return computed([myChannels], (v) => v.has(channel)) | |
23 | + } | |
24 | +} |
translations/en.js | ||
---|---|---|
@@ -137,8 +137,15 @@ | ||
137 | 137 | subscribe: 'Subscribe', |
138 | 138 | unsubscribe: 'Unsubscribe' |
139 | 139 | } |
140 | 140 | }, |
141 | + subscriptions: { | |
142 | + user: "My subscriptions", | |
143 | + friends: "Friends subscriptions", | |
144 | + state: { | |
145 | + noSubscriptions: 'You have no subscriptions yet' | |
146 | + } | |
147 | + }, | |
141 | 148 | languages: { |
142 | 149 | en: 'English', |
143 | 150 | zh: '中文' |
144 | 151 | } |
Built with git-ssb-web