Commit 36fdd005ea9c7306764cf0040cbb11101156f80a
feature: internal sharing without caption for #117
andre alves garzia committed on 4/23/2018, 6:15:37 PMParent: 8b085af93f89fb77c6d8066e7aeb644f24d174eb
Files changed
app/page/blogShow.js | changed |
message/html/shares.js | added |
message/html/shares.mcss | added |
message/index.js | changed |
message/obs/shares.js | added |
app/page/blogShow.js | ||
---|---|---|
@@ -11,8 +11,9 @@ | ||
11 | 11 | 'app.html.sideNav': 'first', |
12 | 12 | 'contact.html.follow': 'first', |
13 | 13 | 'message.html.channel': 'first', |
14 | 14 | 'message.html.likes': 'first', |
15 | + 'message.html.shares': 'first', | |
15 | 16 | 'message.html.timeago': 'first', |
16 | 17 | 'feed.obs.thread': 'first', |
17 | 18 | 'blog.html.title': 'first', |
18 | 19 | 'blog.html.content': 'first' |
@@ -20,9 +21,9 @@ | ||
20 | 21 | |
21 | 22 | exports.create = (api) => { |
22 | 23 | return nest('app.page.blogShow', blogShow) |
23 | 24 | |
24 | - function blogShow (blogMsg) { | |
25 | + function blogShow(blogMsg) { | |
25 | 26 | // blogMsg = a thread (message, may be decorated with replies) |
26 | 27 | |
27 | 28 | const { author } = blogMsg.value |
28 | 29 | |
@@ -45,9 +46,10 @@ | ||
45 | 46 | h('div.blog-details', [ |
46 | 47 | h('h1', title), |
47 | 48 | timeago(blogMsg), |
48 | 49 | channel(blogMsg), |
49 | - api.message.html.likes(blogMsg) | |
50 | + api.message.html.likes(blogMsg), | |
51 | + api.message.html.shares(blogMsg) | |
50 | 52 | ]), |
51 | 53 | h('div.author', [ |
52 | 54 | h('div.leftCol', api.about.html.avatar(author, 'medium')), |
53 | 55 | h('div.rightCol', [ |
message/html/shares.js | ||
---|---|---|
@@ -1,0 +1,40 @@ | ||
1 | +var { h, computed, when } = require('mutant') | |
2 | +var nest = require('depnest') | |
3 | + | |
4 | +exports.needs = nest({ | |
5 | + 'keys.sync.id': 'first', | |
6 | + 'message.obs.shares': 'first', | |
7 | + 'sbot.async.publish': 'first' | |
8 | +}) | |
9 | + | |
10 | +exports.gives = nest('message.html.shares') | |
11 | + | |
12 | +exports.create = (api) => { | |
13 | + return nest('message.html.shares', function shares(msg) { | |
14 | + var id = api.keys.sync.id() | |
15 | + var shares = api.message.obs.shares(msg.key) | |
16 | + | |
17 | + var iShared = computed(shares, shares => shares.includes(id)) | |
18 | + var count = computed(shares, shares => shares.length ? shares.length : '') | |
19 | + return h('Shares', { 'ev-click': () => publishShare(msg, !iShared()) }, [ | |
20 | + h('i.fa', { className: when(iShared, 'fa-retweet', 'fa-retweet faint') }), | |
21 | + h('div.count', count) | |
22 | + ]) | |
23 | + }) | |
24 | + | |
25 | + function publishShare(msg, status = true) { | |
26 | + if (status) { | |
27 | + var share = { | |
28 | + type: 'share', | |
29 | + share: { link: msg.key, content: "blog", text: '' } | |
30 | + } | |
31 | + if (msg.value.content.recps) { | |
32 | + share.recps = msg.value.content.recps.map(function (e) { | |
33 | + return e && typeof e !== 'string' ? e.link : e | |
34 | + }) | |
35 | + share.private = true | |
36 | + } | |
37 | + api.sbot.async.publish(share) | |
38 | + } | |
39 | + } | |
40 | +} |
message/html/shares.mcss | ||
---|---|---|
@@ -1,0 +1,20 @@ | ||
1 | +Shares { | |
2 | + cursor: pointer | |
3 | + min-width: 2.5rem | |
4 | + | |
5 | + display: flex | |
6 | + align-items: center | |
7 | + | |
8 | + i { | |
9 | + margin-right: .4rem | |
10 | + } | |
11 | + i.fa-retweet { | |
12 | + $colorFontPrimary | |
13 | + } | |
14 | + | |
15 | + i.faint { | |
16 | + color: #b9b9b9 | |
17 | + } | |
18 | + | |
19 | +} | |
20 | + |
message/index.js | ||
---|---|---|
@@ -5,11 +5,15 @@ | ||
5 | 5 | html: { |
6 | 6 | channel: require('./html/channel'), |
7 | 7 | compose: require('./html/compose'), |
8 | 8 | likes: require('./html/likes'), |
9 | + shares: require('./html/shares'), | |
9 | 10 | subject: require('./html/subject'), |
10 | 11 | timeago: require('./html/timeago') |
11 | 12 | }, |
12 | 13 | sync: { |
13 | 14 | getParticipants: require('./sync/getParticipants') |
15 | + }, | |
16 | + obs: { | |
17 | + shares: require('./obs/shares') | |
14 | 18 | } |
15 | 19 | } |
message/obs/shares.js | ||
---|---|---|
@@ -1,0 +1,86 @@ | ||
1 | +var nest = require('depnest') | |
2 | +var ref = require('ssb-ref') | |
3 | +var MutantArray = require('mutant/array') | |
4 | +var concat = require('mutant/concat') | |
5 | + | |
6 | +var { computed } = require('mutant') | |
7 | + | |
8 | +exports.needs = nest({ | |
9 | + 'message.sync.unbox': 'first', | |
10 | + 'backlinks.obs.for': 'first' | |
11 | +}) | |
12 | + | |
13 | +exports.gives = nest({ | |
14 | + 'sbot.hook.publish': true, | |
15 | + 'message.obs.shares': true | |
16 | +}) | |
17 | + | |
18 | +exports.create = function (api) { | |
19 | + var activeShares = new Set() | |
20 | + return nest({ | |
21 | + 'sbot.hook.publish': (msg) => { | |
22 | + if (!(msg && msg.value && msg.value.content)) return | |
23 | + if (typeof msg.value.content === 'string') { | |
24 | + msg = api.message.sync.unbox(msg) | |
25 | + if (!msg) return | |
26 | + } | |
27 | + | |
28 | + var c = msg.value.content | |
29 | + if (c.type !== 'share') return | |
30 | + if (!c.share || !c.share.link) return | |
31 | + | |
32 | + activeShares.forEach((shares) => { | |
33 | + if (shares.id === c.share.link) { | |
34 | + shares.push(msg) | |
35 | + } | |
36 | + }) | |
37 | + }, | |
38 | + 'message.obs.shares': (id) => { | |
39 | + if (!ref.isLink(id)) throw new Error('an id must be specified') | |
40 | + var obs = get(id) | |
41 | + obs.id = id | |
42 | + var result = computed(obs, getShares, { | |
43 | + // allow manual append for simulated realtime | |
44 | + onListen: () => activeShares.add(obs), | |
45 | + onUnlisten: () => activeShares.delete(obs) | |
46 | + }) | |
47 | + result.sync = obs.sync | |
48 | + return result | |
49 | + } | |
50 | + }) | |
51 | + | |
52 | + function get(id) { | |
53 | + var backlinks = api.backlinks.obs.for(id) | |
54 | + var merge = MutantArray() | |
55 | + | |
56 | + var shares = computed([backlinks.sync, concat([backlinks, merge])], (sync, backlinks) => { | |
57 | + if (sync) { | |
58 | + return backlinks.reduce((result, msg) => { | |
59 | + var c = msg.value.content | |
60 | + if (c.type === 'share' && c.share && c.share.link === id) { | |
61 | + var value = result[msg.value.author] | |
62 | + if (!value || value[0] < msg.value.timestamp) { | |
63 | + result[msg.value.author] = [msg.value.timestamp, c.share.text] | |
64 | + } | |
65 | + } | |
66 | + return result | |
67 | + }, {}) | |
68 | + } else { | |
69 | + return {} | |
70 | + } | |
71 | + }) | |
72 | + | |
73 | + shares.push = merge.push | |
74 | + shares.sync = backlinks.sync | |
75 | + return shares | |
76 | + } | |
77 | +} | |
78 | + | |
79 | +function getShares(shares) { | |
80 | + return Object.keys(shares).reduce((result, id) => { | |
81 | + if (shares[id].length >= 1) { | |
82 | + result.push(id) | |
83 | + } | |
84 | + return result | |
85 | + }, []) | |
86 | +} |
Built with git-ssb-web