Commit 896d9cb98b2e5f5c21d03292502be08b22a16f1a
Merge branch 'master' into hashrouter
Dominic Tarr committed on 7/25/2016, 11:32:13 PMParent: 635ea39199988640e918cccefadd0bac2abfdf36
Parent: 2b5c84eb99803edd36a6454033c6011d16b42479
Files changed
.gitignore | changed |
README.md | changed |
index.js | changed |
modules/about.js | changed |
modules/avatar-image.js | changed |
modules/avatar-profile.js | changed |
modules/avatar.js | changed |
modules/follow.js | changed |
modules/index.js | changed |
modules/invite.js | changed |
modules/message-confirm.js | changed |
modules/message.js | changed |
modules/suggest-mentions.js | changed |
modules/audio-mp3.js | added |
modules/avatar-edit.js | added |
modules/git.js | added |
modules/meta-image.js | added |
modules/music-release-cc.js | added |
modules/music-release.js | added |
modules/relationships.js | added |
package.json | changed |
sbot-api.js | changed |
style.css | changed |
README.md | ||
---|---|---|
@@ -69,8 +69,9 @@ | ||
69 | 69 … | now clone and run patchboard. |
70 | 70 … | ``` |
71 | 71 … | git clone https://github.com/dominictarr/patchbay.git |
72 | 72 … | cd patchbay |
73 … | +npm install | |
73 | 74 … | npm install electro electron-prebuilt -g |
74 | 75 … | electro index.js |
75 | 76 … | ``` |
76 | 77 … |
index.js | ||
---|---|---|
@@ -1,5 +1,13 @@ | ||
1 | 1 … | var h = require('hyperscript') |
2 … | + | |
3 … | +window.addEventListener('error', function onError(e) { | |
4 … | + document.body.appendChild(h('div.error', | |
5 … | + h('h1', e.message), | |
6 … | + h('big', h('code', e.filename + ':' + e.lineno)), | |
7 … | + h('pre', e.error ? (e.error.stack || e.error.toString()) : e.toString()))) | |
8 … | +}) | |
9 … | + | |
2 | 10 … | var u = require('./util') |
3 | 11 … | var pull = require('pull-stream') |
4 | 12 … | var combine = require('depject') |
5 | 13 … | var fs = require('fs') |
modules/about.js | ||
---|---|---|
@@ -26,9 +26,9 @@ | ||
26 | 26 … | ' as ', |
27 | 27 … | h('a', {href:"#"+about.about}, |
28 | 28 … | about.name || null, |
29 | 29 … | about.image |
30 | - ? h('img', {src: blob_url(about.image)}) | |
30 … | + ? h('img.avatar--fullsize', {src: blob_url(about.image)}) | |
31 | 31 … | : null |
32 | 32 … | ) |
33 | 33 … | ) |
34 | 34 … |
modules/avatar-image.js | ||
---|---|---|
@@ -10,10 +10,13 @@ | ||
10 | 10 … | var id = require('../keys').id |
11 | 11 … | |
12 | 12 … | var default_avatar = '&qjeAs8+uMXLlyovT4JnEpMwTNDx/QXHfOl2nv2u0VCM=.sha256' |
13 | 13 … | |
14 | -exports.avatar_image = function (author) { | |
15 | - var img = h('img', {src: blob_url(default_avatar)}) | |
14 … | +exports.avatar_image = function (author, classes) { | |
15 … | + classes = classes || '' | |
16 … | + if(classes && 'string' === typeof classes) classes = '.avatar--'+classes | |
17 … | + | |
18 … | + var img = h('img'+classes, {src: blob_url(default_avatar)}) | |
16 | 19 … | getAvatar({links: sbot_links}, id, author, function (err, avatar) { |
17 | 20 … | if (err) return console.error(err) |
18 | 21 … | if(ref.isBlob(avatar.image)) |
19 | 22 … | img.src = blob_url(avatar.image) |
modules/avatar-profile.js | ||
---|---|---|
@@ -1,13 +1,50 @@ | ||
1 | 1 … | var h = require('hyperscript') |
2 | 2 … | var plugs = require('../plugs') |
3 … | +var pull = require('pull-stream') | |
3 | 4 … | |
4 | 5 … | var avatar_image = plugs.first(exports.avatar_image = []) |
6 … | +var avatar_name = plugs.first(exports.avatar_name = []) | |
5 | 7 … | var avatar_action = plugs.map(exports.avatar_action = []) |
8 … | +var avatar_edit = plugs.first(exports.avatar_edit = []) | |
6 | 9 … | |
10 … | +var follows = plugs.first(exports.follows = []) | |
11 … | +var followers = plugs.first(exports.followers = []) | |
12 … | + | |
13 … | +function streamToList(stream, el) { | |
14 … | + pull( | |
15 … | + stream, | |
16 … | + pull.drain(function (item) { | |
17 … | + if(item) el.appendChild(item) | |
18 … | + }) | |
19 … | + ) | |
20 … | + return el | |
21 … | +} | |
22 … | + | |
23 … | +function image_link (id) { | |
24 … | + return h('a', {href:'#'+id}, avatar_image(id, 'thumbnail')) | |
25 … | +} | |
26 … | + | |
7 | 27 … | exports.avatar_profile = function (id) { |
28 … | + return h('div.column.profile', | |
29 … | + avatar_edit(id), | |
30 … | + avatar_action(id), | |
8 | 31 … | |
9 | - return h('div.row.profile', | |
10 | - avatar_image(id), | |
11 | - h('div.column', avatar_action(id)) | |
32 … | + h('div.profile__relationships.column', | |
33 … | + | |
34 … | + h('strong', 'follows'), | |
35 … | + streamToList(pull( | |
36 … | + follows(id), | |
37 … | + pull.unique(), | |
38 … | + pull.map(image_link) | |
39 … | + ), h('div.profile__follows.wrap')), | |
40 … | + | |
41 … | + h('strong', 'followers'), | |
42 … | + streamToList(pull( | |
43 … | + followers(id), | |
44 … | + pull.unique(), | |
45 … | + pull.map(image_link) | |
46 … | + ), h('div.profile__followers.wrap')) | |
47 … | + ) | |
12 | 48 … | ) |
13 | 49 … | } |
50 … | + |
modules/avatar.js | ||
---|---|---|
@@ -5,12 +5,12 @@ | ||
5 | 5 … | var plugs = require('../plugs') |
6 | 6 … | var avatar_name = plugs.first(exports.avatar_name = []) |
7 | 7 … | var avatar_image = plugs.first(exports.avatar_image = []) |
8 | 8 … | |
9 | -exports.avatar = function (author) { | |
9 … | +exports.avatar = function (author, classes) { | |
10 | 10 … | return h('a.avatar', |
11 | 11 … | {href:'#'+author}, |
12 | - avatar_image(author), | |
12 … | + avatar_image(author, classes), | |
13 | 13 … | avatar_name(author) |
14 | 14 … | ) |
15 | 15 … | } |
16 | 16 … |
modules/follow.js | ||
---|---|---|
@@ -5,15 +5,19 @@ | ||
5 | 5 … | var plugs = require('../plugs') |
6 | 6 … | |
7 | 7 … | //render a message when someone follows someone, |
8 | 8 … | //so you see new users |
9 … | +function isRelated(value, name) { | |
10 … | + return value ? name : value === false ? 'un'+name : '' | |
11 … | +} | |
12 … | + | |
9 | 13 … | exports.message_content = function (msg) { |
10 | 14 … | |
11 | - if(msg.value.content.type == 'contact' && msg.value.content.contact) { | |
12 | - return h('div.contact', | |
13 | - 'follows', | |
14 | - avatar(msg.value.content.contact) | |
15 | - ) | |
15 … | + var content = msg.value.content | |
16 … | + if(content.type == 'contact' && content.contact) { | |
17 … | + var relation = isRelated(content.following, 'follows') | |
18 … | + if(content.blocking) relation = 'blocks' | |
19 … | + return h('div.contact', relation, avatar(msg.value.content.contact, 'thumbnail')) | |
16 | 20 … | } |
17 | 21 … | } |
18 | 22 … | |
19 | 23 … | var sbot_links2 = plugs.first(exports.sbot_links2 = []) |
@@ -81,4 +85,26 @@ | ||
81 | 85 … | }}, h('br'), label) |
82 | 86 … | ) |
83 | 87 … | } |
84 | 88 … | |
89 … | + | |
90 … | + | |
91 … | + | |
92 … | + | |
93 … | + | |
94 … | + | |
95 … | + | |
96 … | + | |
97 … | + | |
98 … | + | |
99 … | + | |
100 … | + | |
101 … | + | |
102 … | + | |
103 … | + | |
104 … | + | |
105 … | + | |
106 … | + | |
107 … | + | |
108 … | + | |
109 … | + | |
110 … | + |
modules/index.js | ||
---|---|---|
@@ -1,8 +1,10 @@ | ||
1 | 1 … | module.exports = { |
2 | 2 … | "_screen_view.js": require('./_screen_view.js'), |
3 | 3 … | "about.js": require('./about.js'), |
4 | 4 … | "app.js": require('./app.js'), |
5 … | + "avatar-edit.js": require('./avatar-edit.js'), | |
6 … | + "audio-mp3.js": require('./audio-mp3.js'), | |
5 | 7 … | "avatar-image.js": require('./avatar-image.js'), |
6 | 8 … | "avatar-profile.js": require('./avatar-profile.js'), |
7 | 9 … | "avatar.js": require('./avatar.js'), |
8 | 10 … | "blob-url.js": require('./blob-url.js'), |
@@ -11,15 +13,20 @@ | ||
11 | 13 … | "crypto.js": require('./crypto.js'), |
12 | 14 … | "feed.js": require('./feed.js'), |
13 | 15 … | "file-input.js": require('./file-input.js'), |
14 | 16 … | "follow.js": require('./follow.js'), |
17 … | + "relationships.js": require('./relationships.js'), | |
18 … | + "git.js": require('./git.js'), | |
15 | 19 … | "invite.js": require('./invite.js'), |
16 | 20 … | "like.js": require('./like.js'), |
17 | 21 … | "markdown.js": require('./markdown.js'), |
18 | 22 … | "message-confirm.js": require('./message-confirm.js'), |
19 | 23 … | "message-link.js": require('./message-link.js'), |
20 | 24 … | "message-name.js": require('./message-name.js'), |
21 | 25 … | "message.js": require('./message.js'), |
26 … | + "meta-image.js": require('./meta-image.js'), | |
27 … | + "music-release-cc.js": require('./music-release-cc.js'), | |
28 … | + "music-release.js": require('./music-release.js'), | |
22 | 29 … | "names.js": require('./names.js'), |
23 | 30 … | "notifications.js": require('./notifications.js'), |
24 | 31 … | "post.js": require('./post.js'), |
25 | 32 … | "private.js": require('./private.js'), |
@@ -32,4 +39,13 @@ | ||
32 | 39 … | "tabs.js": require('./tabs.js'), |
33 | 40 … | "thread.js": require('./thread.js'), |
34 | 41 … | "timestamp.js": require('./timestamp.js') |
35 | 42 … | } |
43 … | + | |
44 … | + | |
45 … | + | |
46 … | + | |
47 … | + | |
48 … | + | |
49 … | + | |
50 … | + | |
51 … | + |
modules/invite.js | ||
---|---|---|
@@ -3,91 +3,83 @@ | ||
3 | 3 … | var ssbClient = require('ssb-client') |
4 | 4 … | var id = require('../keys').id |
5 | 5 … | var h = require('hyperscript') |
6 | 6 … | |
7 … | +var Progress = require('hyperprogress') | |
8 … | + | |
7 | 9 … | var plugs = require('../plugs') |
8 | 10 … | var sbot_publish = plugs.first(exports.sbot_publish = []) |
9 | 11 … | |
10 | 12 … | |
11 | -exports.screen_view = function (invite) { | |
12 | - | |
13 | - //check that invite is | |
14 | - // ws:...~shs:key:seed | |
15 | - | |
13 … | +//check that invite is | |
14 … | +// ws:...~shs:key:seed | |
15 … | +function parseMultiServerInvite (invite) { | |
16 | 16 … | var parts = invite.split('~') |
17 | 17 … | .map(function (e) { return e.split(':') }) |
18 | 18 … | |
19 | 19 … | if(parts.length !== 2) return null |
20 | 20 … | if(!/^(net|wss?)$/.test(parts[0][0])) return null |
21 | 21 … | if(parts[1][0] !== 'shs') return null |
22 | 22 … | if(parts[1].length !== 3) return null |
23 … | + var p2 = invite.split(':') | |
24 … | + p2.pop() | |
23 | 25 … | |
26 … | + return { | |
27 … | + invite: invite, | |
28 … | + remote: p2.join(':'), | |
29 … | + } | |
30 … | +} | |
31 … | + | |
32 … | +exports.screen_view = function (invite) { | |
33 … | + | |
34 … | + var data = parseMultiServerInvite(invite) | |
35 … | + if(!data) return | |
36 … | + | |
37 … | + var progress = Progress(4) | |
38 … | + | |
24 | 39 … | //connect to server |
25 | 40 … | //request follow |
26 | 41 … | //post pub announce |
27 | 42 … | //post follow pub |
28 | - var progress = h('h1') | |
29 | - var status = h('pre') | |
30 | - var div = h('div', | |
31 | - progress, status, | |
32 | - h('a', 'accept', {href: '#', onclick: function (ev) { | |
33 | - ev.preventDefault() | |
34 | - ev.stopPropagation() | |
35 | - attempt() | |
36 | - return false | |
37 | - }}) | |
43 … | + var div = h('div.column', | |
44 … | + h('div', | |
45 … | + "invite to:", h('br'), | |
46 … | + h('code', invite), | |
47 … | + h('button', 'accept', {onclick: function (ev) { | |
48 … | + attempt() | |
49 … | + }}) | |
50 … | + ), | |
51 … | + progress | |
38 | 52 … | ) |
39 | 53 … | |
40 | 54 … | function attempt () { |
41 | - progress.textContent = '*' | |
42 | - status.textContent = 'connecting...' | |
55 … | + progress.reset().next('connecting...') | |
43 | 56 … | |
44 | - console.log("CONNECT", invite) | |
45 | 57 … | ssbClient(null, { |
46 | 58 … | remote: invite, |
47 | 59 … | manifest: { invite: {use: 'async'}, getAddress: 'async' } |
48 | 60 … | }, function (err, sbot) { |
49 | - console.log("ERR?", err, sbot) | |
50 | - if(err) { | |
51 | - progress.textContent = '*!' | |
52 | - status.textContent = err.stack | |
53 | - return | |
54 | - } | |
55 | - progress.textContent = '**' | |
56 | - status.textContent = 'requesting follow...' + id | |
61 … | + if(err) return progress.fail(err) | |
62 … | + progress.next('requesting follow...') | |
57 | 63 … | |
58 | 64 … | sbot.invite.use({feed: id}, function (err, msg) { |
59 | - if(err) { | |
60 | - progress.textContent = '**!' | |
61 | - status.textContent = err.stack | |
62 | - return | |
63 | - } | |
64 | - progress.textContent = '***' | |
65 | - status.textContent = 'following...' | |
66 | - | |
65 … | + if(err) return progress.fail(err) | |
66 … | + progress.next('following...') | |
67 … | + | |
67 | 68 … | //remove the seed from the shs address. |
68 | 69 … | //then it's correct address. |
69 | 70 … | //this should make the browser connect to this as remote. |
70 | 71 … | //we don't want to do this if when using this locally, though. |
71 | - if(process.title === 'browser') { | |
72 | - var p2 = invite.split(':') | |
73 | - p2.pop() | |
74 | - localStorage.remote = p2.join(':') | |
75 | - } | |
72 … | + if(process.title === 'browser') | |
73 … | + localStorage.remote = data.remote | |
76 | 74 … | |
77 | 75 … | sbot_publish({ |
78 | 76 … | type: 'contact', |
79 | 77 … | contact: sbot.id, |
80 | - following: true | |
78 … | + following: true, | |
81 | 79 … | }, function (err) { |
82 | - if(err) { | |
83 | - progress.textContent = '***!' | |
84 | - status.textContent = err.stack | |
85 | - return | |
86 | - } | |
87 | - progress.textContent = '****' | |
88 | - status.textContent = 'READY!' | |
89 | - | |
80 … | + if(err) return progress.fail(err) | |
81 … | + progress.complete() | |
90 | 82 … | }) |
91 | 83 … | |
92 | 84 … | }) |
93 | 85 … | }) |
@@ -95,5 +87,4 @@ | ||
95 | 87 … | |
96 | 88 … | return div |
97 | 89 … | } |
98 | 90 … | |
99 | - |
modules/message-confirm.js | ||
---|---|---|
@@ -15,9 +15,10 @@ | ||
15 | 15 … | var lb = lightbox() |
16 | 16 … | document.body.appendChild(lb) |
17 | 17 … | |
18 | 18 … | var okay = h('button', 'okay', {onclick: function () { |
19 | - publish(content); lb.remove(); cb(null, content) | |
19 … | + lb.remove() | |
20 … | + publish(content, cb) | |
20 | 21 … | }}) |
21 | 22 … | |
22 | 23 … | var cancel = h('button', 'cancel', {onclick: function () { |
23 | 24 … | lb.remove() |
modules/message.js | ||
---|---|---|
@@ -32,9 +32,9 @@ | ||
32 | 32 … | ) |
33 | 33 … | |
34 | 34 … | var msg = h('div.message', |
35 | 35 … | h('div.title.row', |
36 | - h('div.avatar', avatar(msg.value.author)), | |
36 … | + h('div.avatar', avatar(msg.value.author, 'thumbnail')), | |
37 | 37 … | h('div.message_meta.row', message_meta(msg)) |
38 | 38 … | ), |
39 | 39 … | h('div.message_content', el), |
40 | 40 … | h('div.message_actions.row', |
modules/suggest-mentions.js | ||
---|---|---|
@@ -4,8 +4,9 @@ | ||
4 | 4 … | return /\.(gif|jpg|png|svg)$/i.test(filename) |
5 | 5 … | } |
6 | 6 … | |
7 | 7 … | var sbot_links2 = require('../plugs').first(exports.sbot_links2 = []) |
8 … | +var blob_url = require('../plugs').first(exports.blob_url = []) | |
8 | 9 … | |
9 | 10 … | exports.suggest = cont.to(function (word, cb) { |
10 | 11 … | if(!/^[@%&!]/.test(word[0])) return cb() |
11 | 12 … | if(word.length < 2) return cb() |
@@ -32,12 +33,13 @@ | ||
32 | 33 … | return { |
33 | 34 … | title: e.name + ': ' + e.id.substring(0,10)+' ('+e.rank+')', |
34 | 35 … | value: embed+'['+e.name+']('+e.id+')', |
35 | 36 … | rank: e.rank, |
36 | - image: isImage(e.name) ? 'http://localhost:7777/'+e.id : undefined | |
37 … | + image: isImage(e.name) ? blob_url(e.id) : undefined | |
37 | 38 … | } |
38 | 39 … | }) |
39 | 40 … | cb(null, ary) |
40 | 41 … | }) |
41 | 42 … | ) |
42 | 43 … | }) |
43 | 44 … | |
45 … | + |
modules/audio-mp3.js | ||
---|---|---|
@@ -1,0 +1,51 @@ | ||
1 … | +var markdown = require('ssb-markdown'); | |
2 … | +var h = require('hyperscript'); | |
3 … | +var u = require('../util'); | |
4 … | +var ref = require('ssb-ref'); | |
5 … | + | |
6 … | +//render a message | |
7 … | + | |
8 … | +var plugs = require('../plugs'); | |
9 … | +var message_link = plugs.first(exports.message_link = []); | |
10 … | +var message_confirm = plugs.first(exports.message_confirm = []); | |
11 … | +var sbot_links = plugs.first(exports.sbot_links = []); | |
12 … | +var blob_url = plugs.first(exports.blob_url = []); | |
13 … | + | |
14 … | +exports.message_content = function(msg, sbot) { | |
15 … | + if (msg.value.content.type !== 'audio-mp3') | |
16 … | + return; | |
17 … | + | |
18 … | + var v = msg.value.content; | |
19 … | + return h('div', | |
20 … | + h('h2', "(" + v.Track + ") " + v.Title), | |
21 … | + // h('img', { "src" : blob_url(v.cover) }), | |
22 … | + h('audio', { | |
23 … | + "controls" : true, | |
24 … | + "src" : blob_url(v.link) | |
25 … | + })) | |
26 … | + // h('dl', | |
27 … | + // Object.keys(v).map(function(k) { | |
28 … | + // return [ | |
29 … | + // h("dt", k), | |
30 … | + // h("dd", v[k]), | |
31 … | + // ] | |
32 … | + // }))) | |
33 … | + | |
34 … | + // "Album": "the fall of", | |
35 … | + // "Crc32": "038becab", | |
36 … | + // "Creator": "bleupulp", | |
37 … | + // "Format": "VBR MP3", | |
38 … | + // "Height": "0", | |
39 … | + // "Length": "375.23", | |
40 … | + // "Md5": "2c517c8e813da5f940c8c7e77d4b7f3f", | |
41 … | + // "Mtime": "1399498698", | |
42 … | + // "Name": "2_bleupulp_-_clouds.mp3", | |
43 … | + // "Sha1": "9f6a96a3d5571ed1ec2a7da38ffebdcd5f181482", | |
44 … | + // "Size": "15009000", | |
45 … | + | |
46 … | + // "Title": "clouds", | |
47 … | + // "Track": "2", | |
48 … | + // "Width": "0", | |
49 … | + | |
50 … | +} | |
51 … | + |
modules/avatar-edit.js | ||
---|---|---|
@@ -1,0 +1,147 @@ | ||
1 … | +var dataurl = require('dataurl') | |
2 … | +var hyperfile = require('hyperfile') | |
3 … | +var hypercrop = require('hypercrop') | |
4 … | +var hyperlightbox = require('hyperlightbox') | |
5 … | +var h = require('hyperscript') | |
6 … | +var pull = require('pull-stream') | |
7 … | +var getAvatar = require('ssb-avatar') | |
8 … | +var plugs = require('../plugs') | |
9 … | +var ref = require('ssb-ref') | |
10 … | + | |
11 … | +var self_id = require('../keys').id | |
12 … | +var default_avatar = '&qjeAs8+uMXLlyovT4JnEpMwTNDx/QXHfOl2nv2u0VCM=.sha256' | |
13 … | + | |
14 … | +var confirm = plugs.first(exports.message_confirm = []) | |
15 … | +var sbot_blobs_add = plugs.first(exports.sbot_blobs_add = []) | |
16 … | +var blob_url = plugs.first(exports.blob_url = []) | |
17 … | +var sbot_links = plugs.first(exports.sbot_links = []) | |
18 … | +var avatar_name = plugs.first(exports.avatar_name = []) | |
19 … | + | |
20 … | +function crop (d, cb) { | |
21 … | + var data | |
22 … | + var canvas = hypercrop(h('img', {src: d})) | |
23 … | + | |
24 … | + return h('div.column.avatar_pic', | |
25 … | + canvas, | |
26 … | + //canvas.selection, | |
27 … | + h('div.row.avatar_pic__controls', | |
28 … | + h('button', 'okay', {onclick: function () { | |
29 … | + cb(null, canvas.selection.toDataURL()) | |
30 … | + }}), | |
31 … | + h('button', 'cancel', {onclick: function () { | |
32 … | + cb(new Error('canceled')) | |
33 … | + }}) | |
34 … | + ) | |
35 … | + ) | |
36 … | +} | |
37 … | + | |
38 … | +exports.avatar_edit = function (id) { | |
39 … | + | |
40 … | + var img = h('img.avatar--large', {src: blob_url(default_avatar)}) | |
41 … | + var lb = hyperlightbox() | |
42 … | + var name_input = h('input', {placeholder: 'rename'}) | |
43 … | + var name = avatar_name(id) | |
44 … | + var selected = null, selected_data = null | |
45 … | + | |
46 … | + getAvatar({links: sbot_links}, self_id, id, function (err, avatar) { | |
47 … | + if (err) return console.error(err) | |
48 … | + //don't show user has already selected an avatar. | |
49 … | + if(selected) return | |
50 … | + if(ref.isBlob(avatar.image)) | |
51 … | + img.src = blob_url(avatar.image) | |
52 … | + }) | |
53 … | + | |
54 … | + var also_pictured = h('div.profile__alsopicturedas.wrap') | |
55 … | + | |
56 … | + pull( | |
57 … | + sbot_links({dest: id, rel: 'about', values: true}), | |
58 … | + pull.map(function (e) { | |
59 … | + return e.value.content.image | |
60 … | + }), | |
61 … | + pull.filter(function (e) { | |
62 … | + return e && 'string' == typeof e.link | |
63 … | + }), | |
64 … | + pull.unique('link'), | |
65 … | + pull.drain(function (image) { | |
66 … | + also_pictured.appendChild( | |
67 … | + h('a', {href:'#', onclick: function (ev) { | |
68 … | + ev.stopPropagation() | |
69 … | + ev.preventDefault() | |
70 … | + selected = image | |
71 … | + img.src = blob_url(image.link || image) | |
72 … | + }}, | |
73 … | + h('img.avatar--thumbnail', {src: blob_url(image)}) | |
74 … | + ) | |
75 … | + ) | |
76 … | + }) | |
77 … | + ) | |
78 … | + | |
79 … | + return h('div.row.profile', | |
80 … | + lb, | |
81 … | + img, | |
82 … | + h('div.column.profile__info', | |
83 … | + h('strong', name), | |
84 … | + name_input, | |
85 … | + | |
86 … | + hyperfile.asDataURL(function (data) { | |
87 … | + var el = crop(data, function (err, data) { | |
88 … | + if(data) { | |
89 … | + img.src = data | |
90 … | + pull( | |
91 … | + pull.once(dataurl.parse(data)), | |
92 … | + sbot_blobs_add(function (err, hash) { | |
93 … | + //TODO. Alerts are EVIL. | |
94 … | + //I use them only in a moment of weakness. | |
95 … | + | |
96 … | + if(err) return alert(err.stack) | |
97 … | + selected = { | |
98 … | + link: hash, | |
99 … | + size: selected.data.length, | |
100 … | + type: selected.mimetype, | |
101 … | + width: 512, | |
102 … | + height: 512 | |
103 … | + } | |
104 … | + | |
105 … | + }) | |
106 … | + ) | |
107 … | + } | |
108 … | + lb.close() | |
109 … | + }) | |
110 … | + lb.show(el) | |
111 … | + }), | |
112 … | + h('button', 'update', {onclick: function () { | |
113 … | + if(name_input.value) | |
114 … | + name.textContent = name_input.value | |
115 … | + | |
116 … | + if(selected) | |
117 … | + confirm({ | |
118 … | + type: 'about', | |
119 … | + about: id, | |
120 … | + name: name_input.value || undefined, | |
121 … | + image: selected | |
122 … | + }) | |
123 … | + else if(name_input.value) //name only | |
124 … | + confirm({ | |
125 … | + type: 'about', | |
126 … | + about: id, | |
127 … | + name: name_input.value || undefined, | |
128 … | + }) | |
129 … | + else | |
130 … | + //another moment of weakness | |
131 … | + alert('must select a name or image') | |
132 … | + }}), | |
133 … | + also_pictured | |
134 … | + ) | |
135 … | + ) | |
136 … | +} | |
137 … | + | |
138 … | + | |
139 … | + | |
140 … | + | |
141 … | + | |
142 … | + | |
143 … | + | |
144 … | + | |
145 … | + | |
146 … | + | |
147 … | + |
modules/git.js | ||
---|---|---|
@@ -1,0 +1,250 @@ | ||
1 … | +var h = require('hyperscript') | |
2 … | +var pull = require('pull-stream') | |
3 … | +var paramap = require('pull-paramap') | |
4 … | +var moment = require('moment') | |
5 … | + | |
6 … | +var plugs = require('../plugs') | |
7 … | +var message_link = plugs.first(exports.message_link = []) | |
8 … | +var sbot_links = plugs.first(exports.sbot_links = []) | |
9 … | +var sbot_links2 = plugs.first(exports.sbot_links2 = []) | |
10 … | +var sbot_get = plugs.first(exports.sbot_get = []) | |
11 … | +var getAvatar = require('ssb-avatar') | |
12 … | +var avatar_name = plugs.first(exports.avatar_name = []) | |
13 … | +var markdown = plugs.first(exports.markdown = []) | |
14 … | + | |
15 … | +var self_id = require('../keys').id | |
16 … | + | |
17 … | +function shortRefName(ref) { | |
18 … | + return ref.replace(/^refs\/(heads|tags)\//, '') | |
19 … | +} | |
20 … | + | |
21 … | +function repoLink(id) { | |
22 … | + var el = h('a', {href: '#'+id}, id.substr(0, 10) + '…') | |
23 … | + getAvatar({links: sbot_links}, self_id, id, function (err, avatar) { | |
24 … | + if(err) return console.error(err) | |
25 … | + el.textContent = avatar.name | |
26 … | + }) | |
27 … | + return el | |
28 … | +} | |
29 … | + | |
30 … | +function getIssueState(id, cb) { | |
31 … | + pull( | |
32 … | + sbot_links({dest: id, rel: 'issues', values: true}), | |
33 … | + pull.map(function (msg) { | |
34 … | + var issues = msg.value.content.issues | |
35 … | + if (!Array.isArray(issues)) return | |
36 … | + return issues.filter(function (issue) { | |
37 … | + return issue.link === id | |
38 … | + }).map(function (issue) { | |
39 … | + return { | |
40 … | + ts: msg.value.timestamp, | |
41 … | + open: issue.open, | |
42 … | + merged: issue.merged, | |
43 … | + } | |
44 … | + }) | |
45 … | + }), | |
46 … | + pull.flatten(), | |
47 … | + pull.collect(function (err, updates) { | |
48 … | + if (err) return cb(err) | |
49 … | + var open = true, merged = false | |
50 … | + updates.sort(function (a, b) { | |
51 … | + return b.ts - a.ts | |
52 … | + }).forEach(function (update) { | |
53 … | + if (update.open != null) | |
54 … | + open = update.open | |
55 … | + if (update.merged != null) | |
56 … | + merged = update.merged | |
57 … | + }) | |
58 … | + cb(null, open ? 'open' : merged ? 'merged' : 'closed') | |
59 … | + }) | |
60 … | + ) | |
61 … | +} | |
62 … | + | |
63 … | +function messageTimestampLink(msg) { | |
64 … | + var m = moment(msg.value.timestamp) | |
65 … | + return h('a.timestamp', { | |
66 … | + timestamp: m, | |
67 … | + title: m.format('LLLL'), | |
68 … | + href: '#'+msg.key | |
69 … | + }, m.fromNow()) | |
70 … | +} | |
71 … | + | |
72 … | +function tableRows(headerRow) { | |
73 … | + var thead = h('thead'), tbody = h('tbody') | |
74 … | + var first = true | |
75 … | + var t = [thead, tbody] | |
76 … | + t.append = function (row) { | |
77 … | + if (first) { | |
78 … | + first = false | |
79 … | + thead.appendChild(headerRow) | |
80 … | + } | |
81 … | + tbody.appendChild(row) | |
82 … | + } | |
83 … | + return t | |
84 … | +} | |
85 … | + | |
86 … | +function repoName(id, link) { | |
87 … | + var el = link | |
88 … | + ? h('a', {href: '#'+id}, id.substr(0, 8) + '…') | |
89 … | + : h('ins', id.substr(0, 8) + '…') | |
90 … | + getAvatar({links: sbot_links}, self_id, id, function (err, avatar) { | |
91 … | + if(err) return console.error(err) | |
92 … | + el.textContent = avatar.name | |
93 … | + }) | |
94 … | + return el | |
95 … | +} | |
96 … | + | |
97 … | +exports.message_content = function (msg, sbot) { | |
98 … | + var c = msg.value.content | |
99 … | + | |
100 … | + if(c.type === 'git-repo') { | |
101 … | + var nameEl | |
102 … | + var branchesT, tagsT, openIssuesT, closedIssuesT, openPRsT, closedPRsT | |
103 … | + var div = h('div', | |
104 … | + h('p', 'git repo ', repoName(msg.key)), | |
105 … | + c.upstream ? h('p', 'fork of ', repoName(c.upstream, true)) : '', | |
106 … | + h('p', h('code', 'ssb://' + msg.key)), | |
107 … | + h('div.git-table-wrapper', {style: {'max-height': '12em'}}, | |
108 … | + h('table', | |
109 … | + branchesT = tableRows(h('tr', | |
110 … | + h('th', 'branch'), | |
111 … | + h('th', 'commit'), | |
112 … | + h('th', 'last update'))), | |
113 … | + tagsT = tableRows(h('tr', | |
114 … | + h('th', 'tag'), | |
115 … | + h('th', 'commit'), | |
116 … | + h('th', 'last update'))))), | |
117 … | + h('div.git-table-wrapper', {style: {'max-height': '16em'}}, | |
118 … | + h('table', | |
119 … | + openIssuesT = tableRows(h('tr', | |
120 … | + h('th', 'open issues'))), | |
121 … | + closedIssuesT = tableRows(h('tr', | |
122 … | + h('th', 'closed issues'))))), | |
123 … | + h('div.git-table-wrapper', {style: {'max-height': '16em'}}, | |
124 … | + h('table', | |
125 … | + openPRsT = tableRows(h('tr', | |
126 … | + h('th', 'open pull requests'))), | |
127 … | + closedPRsT = tableRows(h('tr', | |
128 … | + h('th', 'closed pull requests')))))) | |
129 … | + | |
130 … | + // compute refs | |
131 … | + var refs = {} | |
132 … | + pull( | |
133 … | + sbot_links({ | |
134 … | + reverse: true, | |
135 … | + source: msg.value.author, | |
136 … | + dest: msg.key, | |
137 … | + rel: 'repo', | |
138 … | + values: true | |
139 … | + }), | |
140 … | + pull.drain(function (link) { | |
141 … | + var refUpdates = link.value.content.refs | |
142 … | + for (var ref in refUpdates) { | |
143 … | + if (refs[ref]) continue | |
144 … | + refs[ref] = true | |
145 … | + var rev = refUpdates[ref] | |
146 … | + if (!rev) continue | |
147 … | + var parts = /^refs\/(heads|tags)\/(.*)$/.exec(ref) || [] | |
148 … | + var t | |
149 … | + if (parts[1] === 'heads') t = branchesT | |
150 … | + else if (parts[1] === 'tags') t = tagsT | |
151 … | + if (t) t.append(h('tr', | |
152 … | + h('td', parts[2]), | |
153 … | + h('td', h('code', rev)), | |
154 … | + h('td', messageTimestampLink(link)))) | |
155 … | + } | |
156 … | + }, function (err) { | |
157 … | + if (err) console.error(err) | |
158 … | + }) | |
159 … | + ) | |
160 … | + | |
161 … | + // list issues and pull requests | |
162 … | + pull( | |
163 … | + sbot_links({ | |
164 … | + reverse: true, | |
165 … | + dest: msg.key, | |
166 … | + rel: 'project', | |
167 … | + values: true | |
168 … | + }), | |
169 … | + paramap(function (link, cb) { | |
170 … | + getIssueState(link.key, function (err, state) { | |
171 … | + if(err) return cb(err) | |
172 … | + link.state = state | |
173 … | + cb(null, link) | |
174 … | + }) | |
175 … | + }), | |
176 … | + pull.drain(function (link) { | |
177 … | + var c = link.value.content | |
178 … | + // TODO: support renamed issues | |
179 … | + var title = c.title || (c.text ? c.text.length > 30 | |
180 … | + ? c.text.substr(0, 30) + '…' | |
181 … | + : c.text : link.key) | |
182 … | + var author = link.value.author | |
183 … | + var t = c.type === 'pull-request' | |
184 … | + ? link.state === 'open' ? openPRsT : closedPRsT | |
185 … | + : link.state === 'open' ? openIssuesT : closedIssuesT | |
186 … | + t.append(h('tr', | |
187 … | + h('td', | |
188 … | + h('a', {href: '#'+link.key}, title), h('br'), | |
189 … | + h('small', | |
190 … | + 'opened ', messageTimestampLink(link), | |
191 … | + ' by ', h('a', {href: '#'+author}, avatar_name(author)))))) | |
192 … | + }, function (err) { | |
193 … | + if (err) console.error(err) | |
194 … | + }) | |
195 … | + ) | |
196 … | + | |
197 … | + return div | |
198 … | + } | |
199 … | + | |
200 … | + if(c.type === 'git-update') { | |
201 … | + return h('p', | |
202 … | + 'pushed to ', | |
203 … | + repoLink(c.repo), | |
204 … | + c.refs ? h('ul', Object.keys(c.refs).map(function (ref) { | |
205 … | + var rev = c.refs[ref] | |
206 … | + return h('li', | |
207 … | + shortRefName(ref) + ': ', | |
208 … | + rev ? h('code', rev) : h('em', 'deleted')) | |
209 … | + })) : null, | |
210 … | + Array.isArray(c.issues) ? c.issues.map(function (issue) { | |
211 … | + if (issue.merged === true) | |
212 … | + return ['Merged ', message_link(issue.link), ' in ', | |
213 … | + h('code', issue.object), ' ', h('q', issue.label)] | |
214 … | + if (issue.open === false) | |
215 … | + return ['Closed ', message_link(issue.link), ' in ', | |
216 … | + h('code', issue.object), ' ', h('q', issue.label)] | |
217 … | + }) : null | |
218 … | + ) | |
219 … | + } | |
220 … | + | |
221 … | + if (c.type === 'issue') { | |
222 … | + return h('div', | |
223 … | + h('p', 'opened issue on ', repoLink(c.project)), | |
224 … | + c.title ? h('h4', c.title) : '', | |
225 … | + markdown(c) | |
226 … | + ) | |
227 … | + } | |
228 … | + | |
229 … | + if (c.type === 'pull-request') { | |
230 … | + return h('div', | |
231 … | + h('p', 'opened pull-request ', | |
232 … | + 'to ', repoLink(c.repo), ':', c.branch, ' ', | |
233 … | + 'from ', repoLink(c.head_repo), ':', c.head_branch), | |
234 … | + c.title ? h('h4', c.title) : '', | |
235 … | + markdown(c) | |
236 … | + ) | |
237 … | + } | |
238 … | +} | |
239 … | + | |
240 … | +exports.message_meta = function (msg, sbot) { | |
241 … | + var type = msg.value.content.type | |
242 … | + if (type == 'issue' || type == 'pull-request') { | |
243 … | + var el = h('em', '...') | |
244 … | + getIssueState(msg.key, function (err, state) { | |
245 … | + if (err) return console.error(err) | |
246 … | + el.textContent = state | |
247 … | + }) | |
248 … | + return el | |
249 … | + } | |
250 … | +} |
modules/meta-image.js | ||
---|---|---|
@@ -1,0 +1,48 @@ | ||
1 … | +var markdown = require('ssb-markdown'); | |
2 … | +var h = require('hyperscript'); | |
3 … | +var u = require('../util'); | |
4 … | +var ref = require('ssb-ref'); | |
5 … | + | |
6 … | +//render a message | |
7 … | + | |
8 … | +var plugs = require('../plugs'); | |
9 … | +var message_link = plugs.first(exports.message_link = []); | |
10 … | +var message_confirm = plugs.first(exports.message_confirm = []); | |
11 … | +var sbot_links = plugs.first(exports.sbot_links = []); | |
12 … | +var blob_url = plugs.first(exports.blob_url = []); | |
13 … | + | |
14 … | +exports.message_content = function(msg, sbot) { | |
15 … | + if (msg.value.content.type !== 'meta-image') | |
16 … | + return; | |
17 … | + | |
18 … | + var v = msg.value.content; | |
19 … | + return h('div', | |
20 … | + // h('h2', "(" + v.Track + ") " + v.Title), | |
21 … | + h('img', { "src" : blob_url(v.link) })) | |
22 … | + | |
23 … | + // h('dl', | |
24 … | + // Object.keys(v).map(function(k) { | |
25 … | + // return [ | |
26 … | + // h("dt", k), | |
27 … | + // h("dd", v[k]), | |
28 … | + // ] | |
29 … | + // }))) | |
30 … | + | |
31 … | + // "Album": "the fall of", | |
32 … | + // "Crc32": "038becab", | |
33 … | + // "Creator": "bleupulp", | |
34 … | + // "Format": "VBR MP3", | |
35 … | + // "Height": "0", | |
36 … | + // "Length": "375.23", | |
37 … | + // "Md5": "2c517c8e813da5f940c8c7e77d4b7f3f", | |
38 … | + // "Mtime": "1399498698", | |
39 … | + // "Name": "2_bleupulp_-_clouds.mp3", | |
40 … | + // "Sha1": "9f6a96a3d5571ed1ec2a7da38ffebdcd5f181482", | |
41 … | + // "Size": "15009000", | |
42 … | + | |
43 … | + // "Title": "clouds", | |
44 … | + // "Track": "2", | |
45 … | + // "Width": "0", | |
46 … | + | |
47 … | +} | |
48 … | + |
modules/music-release-cc.js | ||
---|---|---|
@@ -1,0 +1,80 @@ | ||
1 … | +var markdown = require('ssb-markdown'); | |
2 … | +var h = require('hyperscript'); | |
3 … | +var u = require('../util'); | |
4 … | +var ref = require('ssb-ref'); | |
5 … | + | |
6 … | +//render a message | |
7 … | + | |
8 … | +var plugs = require('../plugs'); | |
9 … | +var message_link = plugs.first(exports.message_link = []); | |
10 … | +var message_confirm = plugs.first(exports.message_confirm = []); | |
11 … | +var sbot_links = plugs.first(exports.sbot_links = []); | |
12 … | +var blob_url = plugs.first(exports.blob_url = []); | |
13 … | + | |
14 … | +exports.message_content = function(msg, sbot) { | |
15 … | + if (msg.value.content.type !== 'music-release-cc') | |
16 … | + return; | |
17 … | + | |
18 … | + var tracks = msg.value.content.tracks; | |
19 … | + return h('div', | |
20 … | + h('img', { "src" : blob_url(msg.value.content.cover) }), | |
21 … | + h('h1', msg.value.content.title), | |
22 … | + h('ol', | |
23 … | + Object.keys(tracks).map(function(k) { | |
24 … | + var t = tracks[k]; | |
25 … | + return h('li', t.fname, | |
26 … | + h("br"), | |
27 … | + h('audio', { | |
28 … | + "controls" : true, | |
29 … | + "src" : blob_url(t.link) | |
30 … | + })) | |
31 … | + })), | |
32 … | + h('p', | |
33 … | + "More info:", h('a', { href : msg.value.content.archivedotorg }, "archive.org"), | |
34 … | + h("br"), | |
35 … | + "License:", h('a', { href : msg.value.content.license }, "Link"))) | |
36 … | +} | |
37 … | + | |
38 … | +// copied from like.js | |
39 … | + | |
40 … | +// inspiration for waveform range selection | |
41 … | + | |
42 … | +// idea: handout invite codes for upload of tracks to be cached by the pub | |
43 … | + | |
44 … | +// exports.message_meta = function (msg, sbot) { | |
45 … | + | |
46 … | +// var yupps = h('a') | |
47 … | + | |
48 … | +// pull( | |
49 … | +// sbot_links({dest: msg.key, rel: 'vote'}), | |
50 … | +// pull.collect(function (err, votes) { | |
51 … | +// if(votes.length === 1) | |
52 … | +// yupps.textContent = ' 1 yup' | |
53 … | +// if(votes.length) | |
54 … | +// yupps.textContent = ' ' + votes.length + ' yupps' | |
55 … | +// }) | |
56 … | +// ) | |
57 … | + | |
58 … | +// return yupps | |
59 … | +// } | |
60 … | + | |
61 … | +// exports.message_action = function (msg, sbot) { | |
62 … | +// if(msg.value.content.type !== 'vote') | |
63 … | +// return h('a', {href: '#', onclick: function () { | |
64 … | +// var yup = { | |
65 … | +// type: 'vote', | |
66 … | +// vote: { link: msg.key, value: 1, expression: 'yup' } | |
67 … | +// } | |
68 … | +// if(msg.value.content.recps) { | |
69 … | +// yup.recps = msg.value.content.recps.map(function (e) { | |
70 … | +// return e && typeof e !== 'string' ? e.link : e | |
71 … | +// }) | |
72 … | +// yup.private = true | |
73 … | +// } | |
74 … | +// //TODO: actually publish... | |
75 … | + | |
76 … | +// message_confirm(yup) | |
77 … | +// }}, 'yup') | |
78 … | + | |
79 … | +// } | |
80 … | + |
modules/music-release.js | ||
---|---|---|
@@ -1,0 +1,41 @@ | ||
1 … | +var markdown = require('ssb-markdown'); | |
2 … | +var h = require('hyperscript'); | |
3 … | +var u = require('../util'); | |
4 … | +var ref = require('ssb-ref'); | |
5 … | + | |
6 … | +//render a message | |
7 … | + | |
8 … | +var plugs = require('../plugs'); | |
9 … | +var message_link = plugs.first(exports.message_link = []); | |
10 … | +var message_confirm = plugs.first(exports.message_confirm = []); | |
11 … | +var sbot_links = plugs.first(exports.sbot_links = []); | |
12 … | + | |
13 … | +exports.message_content = function(msg, sbot) { | |
14 … | + if (msg.value.content.type !== 'music-release') | |
15 … | + return; | |
16 … | + | |
17 … | + var v = msg.value.content; | |
18 … | + return h('div', | |
19 … | + // h('img', { "src" : "http://localhost:7777/" + encodeURIComponent(v.cover) }), | |
20 … | + h('h1', v.Title), | |
21 … | + h("p", v.Description), | |
22 … | + h("dl", | |
23 … | + | |
24 … | + h("dt", "Creator"), | |
25 … | + h("dd", v.Creator), | |
26 … | + | |
27 … | + h("dt", "Identifier"), | |
28 … | + h("dd", v.Identifier), | |
29 … | + | |
30 … | + h("dt", "Published"), | |
31 … | + h("dd", v.Publicdate), | |
32 … | + | |
33 … | + h("dt", "Runtime"), | |
34 … | + h("dd", v.Runtime), | |
35 … | + | |
36 … | + h("dt", "Source"), | |
37 … | + h("dd", v.Source), | |
38 … | + | |
39 … | + h("dt", "License"), | |
40 … | + h("dd", h('a', { href : v.Licenseurl }, "Link")))) | |
41 … | +} |
modules/relationships.js | ||
---|---|---|
@@ -1,0 +1,23 @@ | ||
1 … | + | |
2 … | +var plugs = require('../plugs') | |
3 … | + | |
4 … | +var sbot_links2 = plugs.first(exports.sbot_links2 = []) | |
5 … | + | |
6 … | +//this is a bit crude, and doesn't actually show unfollows yet. | |
7 … | + | |
8 … | +exports.follows = function (id, cb) { | |
9 … | + return sbot_links2({query: [ | |
10 … | + {"$filter": {"source": id, "rel": ["contact", true, false] }}, | |
11 … | + {"$map": "dest"} | |
12 … | + ]}) | |
13 … | +} | |
14 … | + | |
15 … | +exports.followers = function (id) { | |
16 … | + return sbot_links2({query: [ | |
17 … | + {"$filter": {"dest": id, "rel": ["contact", true, false] }}, | |
18 … | + {"$map": "source"} | |
19 … | + ]}) | |
20 … | +} | |
21 … | + | |
22 … | + | |
23 … | + |
package.json | ||
---|---|---|
@@ -1,22 +1,27 @@ | ||
1 | 1 … | { |
2 | 2 … | "name": "patchbay", |
3 | 3 … | "description": "a pluggable patchwork", |
4 | - "version": "1.8.4", | |
4 … | + "version": "1.13.3", | |
5 | 5 … | "homepage": "https://github.com/dominictarr/patchbay", |
6 | 6 … | "repository": { |
7 | 7 … | "type": "git", |
8 | 8 … | "url": "git://github.com/dominictarr/patchbay.git" |
9 | 9 … | }, |
10 | 10 … | "dependencies": { |
11 | 11 … | "cont": "^1.0.3", |
12 … | + "dataurl": "^0.1.0", | |
12 | 13 … | "depject": "^1.0.1", |
13 | - "hyperlightbox": "^0.1.0", | |
14 … | + "hypercrop": "^1.0.1", | |
15 … | + "hyperfile": "^1.1.0", | |
16 … | + "hyperlightbox": "^0.1.1", | |
17 … | + "hyperprogress": "0.1.0", | |
14 | 18 … | "hyperscript": "^1.4.7", |
15 | 19 … | "hypertabs": "^1.2.0", |
16 | 20 … | "mime-types": "^2.1.11", |
17 | 21 … | "moment": "^2.13.0", |
18 | 22 … | "open-external": "^0.1.1", |
23 … | + "peaks.js": "^0.4.7", | |
19 | 24 … | "pull-cat": "^1.1.9", |
20 | 25 … | "pull-next": "0.0.0", |
21 | 26 … | "pull-paramap": "^1.1.6", |
22 | 27 … | "pull-reconnect": "^0.0.3", |
sbot-api.js | ||
---|---|---|
@@ -75,9 +75,22 @@ | ||
75 | 75 … | return { |
76 | 76 … | connection_status: connection_status, |
77 | 77 … | sbot_blobs_add: rec.sink(function (cb) { |
78 | 78 … | return pull( |
79 | - Hash(cb), | |
79 … | + Hash(function (err, id) { | |
80 … | + if(err) return cb(err) | |
81 … | + //completely UGLY hack to tell when the blob has been sucessfully written... | |
82 … | + var start = Date.now(), n = 5 | |
83 … | + ;(function next () { | |
84 … | + setTimeout(function () { | |
85 … | + sbot.blobs.has(id, function (err, has) { | |
86 … | + if(has) return cb(null, id) | |
87 … | + if(n--) next() | |
88 … | + else cb(new Error('write failed')) | |
89 … | + }) | |
90 … | + }, Date.now() - start) | |
91 … | + })() | |
92 … | + }), | |
80 | 93 … | sbot.blobs.add() |
81 | 94 … | ) |
82 | 95 … | }), |
83 | 96 … | sbot_links: rec.source(function (query) { |
@@ -102,8 +115,16 @@ | ||
102 | 115 … | if(content.recps) |
103 | 116 … | content = ssbKeys.box(content, content.recps.map(function (e) { |
104 | 117 … | return ref.isFeed(e) ? e : e.link |
105 | 118 … | })) |
119 … | + else if(content.mentions) | |
120 … | + content.mentions.forEach(function (mention) { | |
121 … | + if(ref.isBlob(mention.link)) { | |
122 … | + sbot.blobs.push(mention.link, function (err) { | |
123 … | + if(err) console.error(err) | |
124 … | + }) | |
125 … | + } | |
126 … | + }) | |
106 | 127 … | |
107 | 128 … | feed.add(content, function (err, msg) { |
108 | 129 … | if(err) console.error(err) |
109 | 130 … | else if(!cb) console.log(msg) |
style.css | ||
---|---|---|
@@ -1,8 +1,10 @@ | ||
1 | 1 … | body { |
2 | 2 … | font-family: "Source Sans Pro", sans-serif; |
3 | 3 … | } |
4 | 4 … | |
5 … | +p { margin-top: .35ex;} | |
6 … | + | |
5 | 7 … | .screen { |
6 | 8 … | position: absolute; |
7 | 9 … | top: 0px; bottom: 0px; |
8 | 10 … | left: 0px; right: 0px; |
@@ -20,8 +22,14 @@ | ||
20 | 22 … | display: flex; |
21 | 23 … | flex-direction: row; |
22 | 24 … | } |
23 | 25 … | |
26 … | +.wrap { | |
27 … | + display: flex; | |
28 … | + flex-direction: row; | |
29 … | + flex-wrap: wrap; | |
30 … | +} | |
31 … | + | |
24 | 32 … | .stretch { |
25 | 33 … | flex-basis: 0; |
26 | 34 … | } |
27 | 35 … | |
@@ -44,9 +52,9 @@ | ||
44 | 52 … | overflow-x: hidden; |
45 | 53 … | } |
46 | 54 … | |
47 | 55 … | |
48 | -img { | |
56 … | +.message img { | |
49 | 57 … | max-width: 100%; |
50 | 58 … | display: block; |
51 | 59 … | } |
52 | 60 … | |
@@ -125,9 +133,9 @@ | ||
125 | 133 … | /* messages */ |
126 | 134 … | |
127 | 135 … | .message { |
128 | 136 … | border: 1px solid #eee; |
129 | - padding: 5px; | |
137 … | + padding: 7px; | |
130 | 138 … | margin-top: .5em; |
131 | 139 … | background: white; |
132 | 140 … | display: block; |
133 | 141 … | flex-basis: 0; |
@@ -203,26 +211,34 @@ | ||
203 | 211 … | .avatar { |
204 | 212 … | display: flex; |
205 | 213 … | flex-direction: row; |
206 | 214 … | } |
207 | -.avatar img { | |
215 … | + | |
216 … | +.avatar--large { | |
217 … | + width: 256px; | |
218 … | + height: 256px; | |
219 … | + border: 1px solid #eee; | |
220 … | +} | |
221 … | + | |
222 … | +.avatar--thumbnail { | |
208 | 223 … | width: 40px; |
209 | 224 … | height: 40px; |
210 | 225 … | margin-right: 3px; |
211 | 226 … | border: 1px solid #ccc; |
212 | 227 … | } |
213 | 228 … | |
229 … | +.avatar--fullsize { | |
230 … | + width: 100%; | |
231 … | +} | |
232 … | + | |
214 | 233 … | .profile { |
215 | 234 … | background: #fff; |
235 … | + padding: .5em; | |
216 | 236 … | border: 1px solid #eee; |
217 | 237 … | } |
218 | 238 … | |
219 | -.profile img { | |
220 | - width: 150px; | |
221 | - height: 150px; | |
222 | - margin-right: 1em; | |
223 | - margin-bottom: 1em; | |
224 | - border: 1px solid #ccc; | |
239 … | +.profile__info { | |
240 … | + margin-left: .5em; | |
225 | 241 … | } |
226 | 242 … | |
227 | 243 … | /* lightbox - used in message-confirm */ |
228 | 244 … | |
@@ -278,6 +294,35 @@ | ||
278 | 294 … | .error { |
279 | 295 … | background: red; |
280 | 296 … | } |
281 | 297 … | |
298 … | +/* avatar editor */ | |
282 | 299 … | |
300 … | +.hypercrop__canvas { | |
301 … | + width: 100%; | |
302 … | +} | |
283 | 303 … | |
304 … | +/* gitssb */ | |
305 … | + | |
306 … | +.git-table-wrapper { | |
307 … | + max-height: 12em; | |
308 … | + overflow: auto; | |
309 … | + word-break: break-all; | |
310 … | + margin: 1em 0; | |
311 … | +} | |
312 … | + | |
313 … | +.git-table-wrapper table { | |
314 … | + width: 100%; | |
315 … | +} | |
316 … | + | |
317 … | +/* invite codes */ | |
318 … | + | |
319 … | +.hyperprogress__liquid { | |
320 … | + height: 1px; | |
321 … | + background: blue; | |
322 … | +} | |
323 … | + | |
324 … | + | |
325 … | + | |
326 … | + | |
327 … | + | |
328 … | + |
Built with git-ssb-web