git ssb

0+

dangerousbeans / patchbay-bootstrap



Commit a5f729cb625d55f9a6700f99041f3adc9c2e8ffc

merged

Joran Kikke committed on 8/26/2016, 3:12:30 AM
Parent: f85f37c151d6d11cc3e80091cb726206fc100d4a
Parent: 3e6a0dc32fcfbe12e6fe6d56679d8bd4687ca841

Files changed

README.mdchanged
index.jschanged
modules/app.jschanged
modules/avatar-image.jschanged
modules/avatar-profile.jschanged
modules/avatar.jschanged
modules/compose.jschanged
modules/private.jschanged
modules/public.jschanged
modules/tabs.jschanged
modules/avatar-link.jsadded
modules/network.jsadded
modules/query.jsadded
modules/theme.jsadded
modules/versions.jsadded
package.jsonchanged
sbot-api.jschanged
README.mdView
@@ -65,14 +65,15 @@
6565 sbot plugins.install ssb-query
6666 sbot plugins.install ssb-ws
6767 # restart sbot server (go back to previous tab and kill it)
6868 ```
69-now clone and run patchboard.
69 +now clone and run patchbay.
7070 ```
7171 git clone https://github.com/dominictarr/patchbay.git
7272 cd patchbay
7373 npm install
7474 npm install electro electron-prebuilt -g
75 +npm run build
7576 electro index.js
7677 ```
7778
7879 ## modules
@@ -85,5 +86,4 @@
8586
8687 ## License
8788
8889 MIT
89-
index.jsView
@@ -13,8 +13,10 @@
1313 var fs = require('fs')
1414 var path = require('path')
1515 var SbotApi = require('./sbot-api')
1616
17 +document.head.appendChild(h('style', require('./style.css.json')))
18 +
1719 var modules = require('./modules')
1820
1921 var u = require('./util')
2022
@@ -35,6 +37,5 @@
3537 document.head.appendChild(
3638 h('style', fs.readFileSync('./css/bootstrap_theme.css', 'utf8')
3739 ))
3840
39-
4041 document.body.appendChild(modules['app.js'].app())
modules/app.jsView
@@ -1,11 +1,21 @@
11 var plugs = require('../plugs')
22 var h = require('hyperscript')
33
44 var screen_view = plugs.first(exports.screen_view = [])
5 +var menu_items = plugs.map(exports.menu_items = [])
56
67 var status = h('div.status.error') //start off disconnected
8 +var list = h('div.column', {style: 'display: none;'})
79
10 +var menu = h('div.menu.row', list, status, {
11 + onmouseover: function (e) {
12 + list.style.display = 'flex'
13 + }, onmouseout: function () {
14 + list.style.display = 'none'
15 + }
16 +})
17 +
818 exports.connection_status = function (err) {
919 if(err) status.classList.add('error')
1020 else status.classList.remove('error')
1121 }
@@ -16,18 +26,23 @@
1626 }
1727
1828 var view = screen_view(hash() || 'tabs')
1929
20- var screen = h('div.screen.column', status, view)
30 + var screen = h('div.screen.column', menu, view)
2131
32 + menu_items().forEach(function (el) {
33 + list.appendChild(el)
34 + })
35 +
2236 window.onhashchange = function (ev) {
2337 var _view = view
2438 view = screen_view(hash() || 'tabs')
2539
2640 if(_view) screen.replaceChild(view, _view)
2741 else document.body.appendChild(view)
2842 }
2943
44 +
3045 return screen
3146
3247 }
3348
@@ -49,4 +64,9 @@
4964
5065
5166
5267
68 +
69 +
70 +
71 +
72 +
modules/avatar-image.jsView
@@ -26,9 +26,10 @@
2626
2727 var last = 0
2828
2929 //blah blah
30-setTimeout(function () {
30 +exports.connection_status = function (err) {
31 + if (err) return
3132 pull(
3233 sbot_query({
3334 query: [{
3435 $filter: {
@@ -70,9 +71,9 @@
7071 avatars[a.id] = a
7172
7273 })
7374 )
74-})
75 +}
7576
7677 exports.avatar_image = function (author, classes) {
7778 classes = classes || ''
7879 if(classes && 'string' === typeof classes) classes = '.avatar--'+classes
modules/avatar-profile.jsView
@@ -1,10 +1,9 @@
11 var h = require('hyperscript')
22 var plugs = require('../plugs')
33 var pull = require('pull-stream')
44
5-var avatar_image = plugs.first(exports.avatar_image = [])
6-var avatar_name = plugs.first(exports.avatar_name = [])
5 +var avatar_image_link = plugs.first(exports.avatar_image_link = [])
76 var avatar_action = plugs.map(exports.avatar_action = [])
87 var avatar_edit = plugs.first(exports.avatar_edit = [])
98
109 var follows = plugs.first(exports.follows = [])
@@ -20,9 +19,9 @@
2019 return el
2120 }
2221
2322 function image_link (id) {
24- return h('a', {href:'#'+id}, avatar_image(id, 'thumbnail'))
23 + return avatar_image_link(id, 'thumbnail')
2524 }
2625
2726 exports.avatar_profile = function (id) {
2827 return h('div.column.profile',
@@ -47,4 +46,8 @@
4746 )
4847 )
4948 }
5049
50 +
51 +
52 +
53 +
modules/avatar.jsView
@@ -1,14 +1,22 @@
11 var h = require('hyperscript')
22 var u = require('../util')
3 +var plugs = require('../plugs')
34
4-
5-var plugs = require('../plugs')
65 var avatar_name = plugs.first(exports.avatar_name = [])
76 var avatar_image = plugs.first(exports.avatar_image = [])
7 +var avatar_link = plugs.first(exports.avatar_link = [])
88
99 exports.avatar = function (author, classes) {
10- return h('a.avatar',
11- {href:'#'+author},
12- avatar_image(author, classes)
13- )
10 + return exports.avatar_image_name_link(author, classes)
1411 }
12 +
13 +exports.avatar_image_name_link = function (author, classes) {
14 + return avatar_link(author, [
15 + avatar_image(author, classes),
16 + avatar_name(author)
17 + ])
18 +}
19 +
20 +exports.avatar_image_link = function (author, classes) {
21 + return avatar_link(author, avatar_image(author, classes))
22 +}
modules/compose.jsView
@@ -46,17 +46,26 @@
4646 if(ev.keyCode === 13 && ev.ctrlKey) publish()
4747 })
4848
4949 var files = []
50 + var filesById = {}
5051
5152 function publish() {
5253 publishBtn.disabled = true
5354 var content
5455 try {
5556 content = JSON.parse(ta.value)
5657 } catch (err) {
5758 meta.text = ta.value
58- meta.mentions = mentions(ta.value).concat(files)
59 + meta.mentions = mentions(ta.value).map(function (mention) {
60 + // merge markdown-detected mention with file info
61 + var file = filesById[mention.link]
62 + if (file) {
63 + if (file.type) mention.type = file.type
64 + if (file.size) mention.size = file.size
65 + }
66 + return mention
67 + })
5968 try {
6069 meta = prepublish(meta)
6170 } catch (err) {
6271 publishBtn.disabled = false
@@ -84,8 +93,9 @@
8493 //hidden until you focus the textarea
8594 {disabled: true},
8695 file_input(function (file) {
8796 files.push(file)
97 + filesById[file.link] = file
8898
8999 var embed = file.type.indexOf('image/') === 0 ? '!' : ''
90100 ta.value += embed + '['+file.name+']('+file.link+')'
91101 console.log('added:', file)
modules/private.jsView
@@ -10,8 +10,9 @@
1010 var message_render = plugs.first(exports.message_render = [])
1111 var message_compose = plugs.first(exports.message_compose = [])
1212 var message_unbox = plugs.first(exports.message_unbox = [])
1313 var sbot_log = plugs.first(exports.sbot_log = [])
14 +var avatar_image_link = plugs.first(exports.avatar_image_link = [])
1415
1516 function unbox () {
1617 return pull(
1718 pull.filter(function (msg) {
@@ -66,9 +67,15 @@
6667 return div
6768 }
6869 }
6970
71 +function map(ary, iter) {
72 + if(Array.isArray(ary)) return ary.map(iter)
73 +}
74 +
7075 exports.message_meta = function (msg) {
7176 if(msg.value.private)
72- return h('span', 'PRIVATE')
77 + return h('span.row', 'PRIVATE', map(msg.value.content.recps, function (id) {
78 + return avatar_image_link('string' == typeof id ? id : id.link, 'thumbnail')
79 + }))
7380 }
7481
modules/public.jsView
@@ -8,10 +8,8 @@
88 var message_render = plugs.first(exports.message_render = [])
99 var message_compose = plugs.first(exports.message_compose = [])
1010 var sbot_log = plugs.first(exports.sbot_log = [])
1111
12-var HighWatermark = require('pull-high-watermark')
13-
1412 exports.screen_view = function (path, sbot) {
1513 if(path === '/public') {
1614
1715 var content = h('div.column.scroller__content')
@@ -29,9 +27,8 @@
2927 )
3028
3129 pull(
3230 u.next(sbot_log, {reverse: true, limit: 100, live: false}),
33-// HighWatermark(100),
3431 Scroller(div, content, message_render, false, false)
3532 )
3633
3734 return div
@@ -55,4 +52,6 @@
5552
5653
5754
5855
56 +
57 +
modules/tabs.jsView
@@ -60,9 +60,9 @@
6060
6161 // tabs.select(sessionStorage.selectedTab || saved[0] || '/public')
6262 tabs.select('/public')
6363
64- tabs.onclick = function (ev) {
64 + window.onclick = function (ev) {
6565 var link = ancestor(ev.target)
6666 if(!link) return
6767 var path = link.hash.substring(1)
6868
@@ -103,9 +103,9 @@
103103 return tabs.selectedTab.scroll(-1)
104104
105105 // close a tab
106106 case 88: // x
107- if (tabs.selected && tabs.selected[0] !== '/') {
107 + if (tabs.selected/* && tabs.selected[0] !== '/'*/) {
108108 var sel = tabs.selected
109109 tabs.selectRelative(-1)
110110 tabs.remove(sel)
111111 // localStorage.openTabs = JSON.stringify(tabs.tabs)
modules/avatar-link.jsView
@@ -1,0 +1,18 @@
1 +var h = require('hyperscript')
2 +var plugs = require('../plugs')
3 +var avatar_name = plugs.first(exports.avatar_name = [])
4 +
5 +var signifier = require('../plugs').first(exports.signifier = [])
6 +
7 +exports.avatar_link = function (id, element) {
8 +
9 + var link = h('a.avatar', {href: "#"+id, title: id}, element)
10 +
11 + signifier(id, function (_, names) {
12 + if(names.length)
13 + link.title = names[0].name + '\n '+id
14 + })
15 +
16 + return link
17 +}
18 +
modules/network.jsView
@@ -1,0 +1,78 @@
1 +var isVisible = require('is-visible').isVisible
2 +var h = require('hyperscript')
3 +var plugs = require('../plugs')
4 +
5 +var avatar = plugs.first(exports.avatar = [])
6 +var sbot_gossip_peers = plugs.first(exports.sbot_gossip_peers = [])
7 +//sbot_gossip_connect
8 +//sbot_gossip_add
9 +
10 +var human = require('human-time')
11 +
12 +function legacyToMultiServer(addr) {
13 + return 'net:'+addr.host + ':'+addr.port + '~shs:'+addr.key.substring(1).replace('.ed25519','')
14 +}
15 +
16 +exports.menu_items = function () {
17 + return h('a', {href: '#/network'}, '/network')
18 +}
19 +
20 +exports.screen_view = function (path) {
21 +
22 + if(path !== '/network') return
23 +
24 + var ol = h('ol.network')
25 +
26 + var states = {
27 + connected: 3,
28 + connecting: 2,
29 + disconnecting: 1
30 + }
31 +
32 + ;(function poll () {
33 +
34 + //if this tab isn't open, don't update.
35 + //todo: make a better way to do this...
36 + if(!isVisible(ol))
37 + return setTimeout(poll, 1000)
38 +
39 + sbot_gossip_peers(function (err, list) {
40 + ol.innerHTML = ''
41 + list.sort(function (a, b) {
42 + return (states[b.state] || 0) - (states[a.state] || 0) || b.stateChange - a.stateChange
43 + }).forEach(function (peer) {
44 + ol.appendChild(h('li',
45 + avatar(peer.key, 'thumbnail'),
46 + h('div',
47 + peer.state || 'not connected',
48 + ' ',
49 + h('label',
50 + {title: new Date(peer.stateChange).toString()},
51 + peer.stateChange && ('(' + human(new Date(peer.stateChange))) + ')')
52 + ),
53 + 'source:'+peer.source,
54 + h('pre', legacyToMultiServer(peer))
55 + )
56 + )
57 + })
58 +
59 + setTimeout(poll, 5000)
60 + })
61 +
62 + })()
63 +
64 + return h('div.column.scroll-y', ol)
65 +
66 +}
67 +
68 +
69 +
70 +
71 +
72 +
73 +
74 +
75 +
76 +
77 +
78 +
modules/query.jsView
@@ -1,0 +1,56 @@
1 +var h = require('hyperscript')
2 +var pull = require('pull-stream')
3 +var HJSON = require('hjson')
4 +
5 +var sbot_query = require('../plugs').first(exports.sbot_query = [])
6 +
7 +exports.menu_items = function () {
8 + return h('a', {href:'#/query'}, '/query')
9 +}
10 +
11 +exports.screen_view = function (path) {
12 + if(path != '/query') return
13 + var output, status, editor, stream, query
14 +
15 + function parse () {
16 + try {
17 + query = HJSON.parse(editor.value)
18 + } catch (err) {
19 + return status.textContent = err.message
20 + }
21 + status.textContent = 'okay'
22 + }
23 +
24 + return h('div.column.scroll',
25 + editor = h('textarea', {style: 'min-height:100px;', oninput: parse, onkeydown: function (e) {
26 + if(!(e.keyCode === 13 && e.ctrlKey)) return
27 +
28 + status.textContent = 'running...'
29 + parse()
30 + output.innerHTML = ''
31 + if(stream) stream.abort()
32 +
33 + console.log(query)
34 +
35 + stream = pull(
36 + sbot_query({query: query, limit: 100}),
37 + pull.drain(function (data) {
38 + output.appendChild(h('pre.query__data',
39 + JSON.stringify(data, null, 2)
40 + ))
41 + }, function (err) {
42 + if(err) status.textContent = err.stack
43 + })
44 + )
45 + }}),
46 + status = h('div.query__status'),
47 + output = h('div.column.query__output', {style: 'overflow-y: scroll;'})
48 + )
49 +}
50 +
51 +
52 +
53 +
54 +
55 +
56 +
modules/theme.jsView
@@ -1,0 +1,143 @@
1 +var h = require('hyperscript')
2 +var pull = require('pull-stream')
3 +var plugs = require('../plugs')
4 +var cat = require('pull-cat')
5 +
6 +var sbot_links2 = plugs.first(exports.sbot_links2 = [])
7 +var avatar_name = plugs.first(exports.avatar_name = [])
8 +var blob_url = require('../plugs').first(exports.blob_url = [])
9 +
10 +var defaultTheme = {
11 + id: '&JFa42U6HtPm9k+s+AmpDIAoTJJI/PzoRC/J/WCfduDY=.sha256',
12 + name: 'patchbay-minimal.css'
13 +}
14 +
15 +var next = 'undefined' === typeof setImmediate ? setTimeout : setImmediate
16 +
17 +var link = document.head.appendChild(h('link', {rel: 'stylesheet'}))
18 +var activeTheme
19 +
20 +function useTheme(id) {
21 + activeTheme = id
22 + link.href = id ? blob_url(id) : ''
23 + var forms = [].slice.call(document.querySelectorAll('.themes__form'))
24 + forms.forEach(updateForm)
25 +
26 + var radios = [].slice.call(document.querySelectorAll('input[type=radio]'))
27 + radios.forEach(function (radio) {
28 + radio.checked = (radio.value === activeTheme)
29 + })
30 +}
31 +
32 +function useSavedTheme() {
33 + useTheme(localStorage.themeId || defaultTheme.id)
34 +}
35 +
36 +next(useSavedTheme)
37 +
38 +function themes() {
39 + return cat([
40 + pull.values([
41 + {
42 + id: '',
43 + name: 'none',
44 + feed: ''
45 + },
46 + defaultTheme,
47 + ]),
48 + pull(
49 + sbot_links2({
50 + query: [
51 + {$filter: {rel: ['mentions', {$prefix: 'patchbay-'}, {$gt: null}]}},
52 + {$filter: {dest: {$prefix: '&'}}},
53 + {$map: {id: 'dest', feed: 'source', name: ['rel', 1]}}
54 + ],
55 + live: true,
56 + sync: false,
57 + }),
58 + pull.filter(function (link) {
59 + return /\.css$/.test(link.name)
60 + })
61 + )
62 + ])
63 +}
64 +
65 +function onRadioClick(e) {
66 + if (this.checked) useTheme(this.value)
67 +}
68 +
69 +function updateForm(form) {
70 + var same = localStorage.themeId === activeTheme
71 + form.querySelector('.themes__id').value = activeTheme
72 + form.querySelector('.themes__reset').disabled = same
73 + form.querySelector('.themes__submit').disabled = same
74 + return form
75 +}
76 +
77 +function renderTheme(link) {
78 + return h('div.theme',
79 + h('input', {type: 'radio', name: 'theme',
80 + value: link.id, onclick: onRadioClick,
81 + checked: link.id === activeTheme
82 + }),
83 + link.id ? h('a', {href: '#'+link.id}, link.name) : link.name, ' ',
84 + link.feed ? h('a', {href: '#'+link.feed}, avatar_name(link.feed)) : ''
85 + )
86 +}
87 +
88 +function theme_view() {
89 + var themeInput
90 + var themesList = h('form.themes__list')
91 + var themesByKey = {}
92 +
93 + pull(
94 + themes(),
95 + pull.unique('id'),
96 + pull.drain(function (theme) {
97 + // replace old versions of themes in the list
98 + var key = theme.feed + theme.name
99 + var oldTheme = themesByKey[key]
100 + theme.el = renderTheme(theme)
101 + themesByKey[key] = theme
102 + if (!oldTheme) {
103 + themesList.appendChild(theme.el)
104 + } else if (oldTheme.id === localStorage.themeId
105 + || oldTheme.id === activeTheme) {
106 + // show old version because the user is still using it
107 + oldTheme.el.appendChild(document.createTextNode(' (old)'))
108 + themesList.appendChild(theme.el)
109 + } else {
110 + themesList.replaceChild(theme.el, oldTheme.el)
111 + }
112 + }, function (err) {
113 + if (err) console.error(err)
114 + })
115 + )
116 +
117 + return h('div.column.scroll-y', h('div',
118 + updateForm(h('form.themes__form', {onsubmit: onsubmit, onreset: onreset},
119 + themeInput = h('input.themes__id', {placeholder: 'theme id',
120 + value: link.href}), ' ',
121 + h('input.themes__reset', {type: 'reset'}), ' ',
122 + h('input.themes__submit', {type: 'submit', value: 'Save'}))),
123 + themesList
124 + ))
125 +
126 + function onsubmit(e) {
127 + e.preventDefault()
128 + useTheme(localStorage.themeId = themeInput.value)
129 + }
130 +
131 + function onreset(e) {
132 + e.preventDefault()
133 + useSavedTheme()
134 + }
135 +}
136 +
137 +exports.menu_items = function () {
138 + return h('a', {href:'#/theme'}, '/theme')
139 +}
140 +
141 +exports.screen_view = function (path) {
142 + if(path === '/theme') return theme_view()
143 +}
modules/versions.jsView
@@ -1,0 +1,36 @@
1 +var h = require('hyperscript')
2 +
3 +exports.menu_items = function () {
4 + return h('a', {href: '#/versions'}, '/versions')
5 +}
6 +
7 +exports.screen_view = function (path) {
8 + if(path !== '/versions') return
9 +
10 + if('undefined' === typeof WebBoot)
11 + return h('h1', 'must run with web-boot enabled enviroment')
12 +
13 + var content = h('div.column')
14 +
15 + WebBoot.versions(function (err, log) {
16 + log.forEach(function (e, i) {
17 + content.appendChild(
18 + h('div.row',
19 + h('a', {
20 + href: '#/run:'+e.value,
21 + onclick: function () {
22 + WebBoot.run(e.value, function () {
23 + console.log('rebooting to:', e.value)
24 + })
25 + }
26 + }, ' ', e.value, ' ', new Date(e.ts)),
27 + !i && h('label', '(current)')
28 + )
29 + )
30 + })
31 +
32 + })
33 +
34 + return content
35 +}
36 +
package.jsonView
@@ -1,8 +1,8 @@
11 {
22 "name": "patchbay",
33 "description": "a pluggable patchwork",
4- "version": "2.2.0",
4 + "version": "2.5.2",
55 "homepage": "https://github.com/dominictarr/patchbay",
66 "repository": {
77 "type": "git",
88 "url": "git://github.com/dominictarr/patchbay.git"
@@ -10,15 +10,17 @@
1010 "dependencies": {
1111 "cont": "^1.0.3",
1212 "dataurl-": "^0.1.0",
1313 "depject": "^1.0.1",
14 + "hjson": "^2.0.3",
1415 "human-time": "0.0.1",
1516 "hypercrop": "^1.0.1",
1617 "hyperfile": "^1.1.0",
1718 "hyperlightbox": "^0.1.3",
1819 "hyperprogress": "0.1.0",
1920 "hyperscript": "^1.4.7",
2021 "hypertabs": "^1.2.0",
22 + "is-visible": "^2.0.4",
2123 "map-filter-reduce": "^3.0.1",
2224 "mime-types": "^2.1.11",
2325 "moment": "^2.13.0",
2426 "open-external": "^0.1.1",
@@ -38,9 +40,9 @@
3840 "ssb-feed": "^2.2.1",
3941 "ssb-keys": "^6.1.0",
4042 "ssb-markdown": "^3.0.0",
4143 "ssb-mentions": "^0.1.0",
42- "ssb-sort": "0.0.0",
44 + "ssb-sort": "^1.0.0",
4345 "suggest-box": "^2.2.1",
4446 "text-node-searcher": "^1.1.0"
4547 },
4648 "devDependencies": {
sbot-api.jsView
@@ -117,13 +117,16 @@
117117 return sbot.createUserStream(opts)
118118 }),
119119 sbot_get: rec.async(function (key, cb) {
120120 if(CACHE[key]) cb(null, CACHE[key])
121- sbot.get(key, function (err, value) {
121 + else sbot.get(key, function (err, value) {
122122 if(err) return cb(err)
123123 cb(null, CACHE[key] = value)
124124 })
125125 }),
126 + sbot_gossip_peers: rec.async(function (cb) {
127 + sbot.gossip.peers(cb)
128 + }),
126129 sbot_publish: rec.async(function (content, cb) {
127130 if(content.recps)
128131 content = ssbKeys.box(content, content.recps.map(function (e) {
129132 return ref.isFeed(e) ? e : e.link
@@ -150,4 +153,9 @@
150153 }
151154
152155
153156
157 +
158 +
159 +
160 +
161 +

Built with git-ssb-web