git ssb

16+

Dominic / patchbay



Commit 1ed42bd9f36becb191c331ca40892cc3262c8e08

initial

Dominic Tarr committed on 5/11/2016, 1:27:27 AM

Files changed

.travis.ymladded
LICENSEadded
README.mdadded
index.jsadded
modules/avatar.jsadded
modules/like.jsadded
modules/message.jsadded
modules/names.jsadded
modules/post.jsadded
modules/timestamp.jsadded
package.jsonadded
util.jsadded
.travis.ymlView
@@ -1,0 +1,4 @@
1+language: node_js
2+node_js:
3+ - 0.6
4+ - 0.8
LICENSEView
@@ -1,0 +1,22 @@
1+Copyright (c) 2016 Dominic Tarr
2+
3+Permission is hereby granted, free of charge,
4+to any person obtaining a copy of this software and
5+associated documentation files (the "Software"), to
6+deal in the Software without restriction, including
7+without limitation the rights to use, copy, modify,
8+merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom
10+the Software is furnished to do so,
11+subject to the following conditions:
12+
13+The above copyright notice and this permission notice
14+shall be included in all copies or substantial portions of the Software.
15+
16+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.mdView
@@ -1,0 +1,76 @@
1+# patchboard
2+
3+Prototype of a pluggable patchwork.
4+
5+Patchboard uses [depject](https://npm.im/depject) to provide
6+a highly composable api. all scripts in the `./modules` directory
7+are loaded and combined using [depject](https://npm.im/depject)
8+
9+This makes in very easy to create say, a renderer for a new message type,
10+or switch to a different method for choosing user names.
11+
12+Currently, this is a proof of concept and only renders the 100 most recent
13+messages. This should obviously be replaced with a module that can
14+scroll properly through a feed, which should plug into another module
15+that gives tabs or something like that.
16+
17+
18+## overview
19+
20+Currently, the main module is `message.js` which plugs into
21+the `message_render` socket, and provides `message_content`, `avatar`,
22+`message_meta` and `message_action` hooks.
23+
24+`avatar.js` plugs into `avatar`, and provides the `avatar_name` socket.
25+it just returns a link to the public key, labled with what it gets back
26+from `avatar_name` socket. this is in turn provided by the `names.js` module.
27+
28+Two modules plug into `message_content`, `post.js` and `like.js`
29+
30+No plugs into the `message_action` socket have been implemented yet,
31+but whatever is returned from this will inserted into the dom at the bottom
32+of the message (by the `message` module) so this would be the plug to
33+use for implementing a like/+1/fav/dig/yup button, or a reply button.
34+
35+## other ideas
36+
37+Editable messages would probably need to plug into several sockets.
38+firstly they would render content differently, so probably use the `message_content` socket.
39+secondly they would need to show edit state, which would probably use `message_meta`
40+and finially they'd need to provide the ability to edit the message!
41+that would use `message_action`
42+
43+Implementing a "events" message type would be easy, just implement another
44+plug for `message_content`, that renders events.
45+
46+Instead of reading all the modules in a directory, it would be better
47+to load these from configuration. Then, modules could be distributed
48+as browserify bundles, and distributed over ssb. Configuration
49+could just be a list of hashes - but you could also disable specific
50+sockets or plugs if necessary (leaving them unconnected).
51+
52+Then, that configuration could be shared over ssb!
53+
54+## higher level ui
55+
56+Instead of just taking the latest 100 messages, what would actually be useful
57+is ways to efficiently view messages, open threads, etc.
58+but if we can create a plug for rendering a stream of messages,
59+we can provide a socket for that in a module that implements tabs, or
60+columns, or whatever.
61+
62+## Running
63+
64+```
65+# assuming that patchwork@2.8 is already running...
66+git clone https://github.com/dominictarr/patchboard.git
67+cd patchboard
68+npm install electro electron-prebuilt -g
69+patchwork plugins.install ssb-links # must have patchwork >=2.8
70+electro index.js
71+```
72+
73+
74+## License
75+
76+MIT
index.jsView
@@ -1,0 +1,37 @@
1+var h = require('hyperscript')
2+var pull = require('pull-stream')
3+var combine = require('depject')
4+var fs = require('fs')
5+var path = require('path')
6+
7+var modules = fs.readdirSync(path.join(__dirname, 'modules'))
8+ .map(function (e) { return require('./modules/'+e) })
9+
10+var renderers = []
11+modules.unshift({message_render: renderers})
12+
13+combine(modules)
14+
15+var u = require('./util')
16+
17+require('ssb-client')(function (err, sbot) {
18+ if(err) throw err
19+ pull(
20+ sbot.createLogStream({reverse: true, limit: 100}),
21+ pull.drain(function (data) {
22+
23+ var el = u.first(renderers, function (render) {
24+ return render(data, sbot)
25+ })
26+
27+ if('string' === typeof el) el = document.createTextNode(el)
28+ if(el) document.body.appendChild(el)
29+ })
30+ )
31+})
32+
33+
34+
35+
36+
37+
modules/avatar.jsView
@@ -1,0 +1,12 @@
1+
2+var h = require('hyperscript')
3+var u = require('../util')
4+
5+exports.avatar = function (author, sbot) {
6+ return h('a', {href:'#'}, u.first(exports.avatar_name, function (plug) {
7+ return plug(author, sbot)
8+ }))
9+}
10+
11+exports.avatar_name = []
12+
modules/like.jsView
@@ -1,0 +1,9 @@
1+
2+var h = require('hyperscript')
3+
4+exports.message_content = function (msg) {
5+ if(msg.value.content && msg.value.content.type === 'vote')
6+ return h('div', msg.value.content.vote.value > 0 ? 'yup' : 'nah',
7+ h('a', {href: '#/msg/'+msg.value.content.vote.link}, msg.key)
8+ )
9+}
modules/message.jsView
@@ -1,0 +1,34 @@
1+var h = require('hyperscript')
2+var u = require('../util')
3+
4+exports.message_render = function (msg, sbot) {
5+ var el = u.first(exports.message_content, function (fn) {
6+ return fn(msg)
7+ })
8+
9+ if(el) console.log(el)
10+
11+ function map (plugs, value) {
12+ return plugs.map(function (plug) {
13+ return plug(value, sbot)
14+ }).filter(Boolean)
15+ }
16+
17+ if(el)
18+ return h('div.message',
19+ h('div.title',
20+ h('div.avatar', map(exports.avatar, msg.value.author)),
21+ h('div.metadata', map(exports.message_meta, msg))
22+ ),
23+ h('div.content', el),
24+ h('div.footer',
25+ h('div.actions', map(exports.message_actions))
26+ )
27+ )
28+}
29+
30+exports.message_content = []
31+exports.avatar = []
32+exports.message_meta = []
33+exports.message_action = []
34+
modules/names.jsView
@@ -1,0 +1,39 @@
1+var h = require('hyperscript')
2+var pull = require('pull-stream')
3+
4+function all(stream, cb) {
5+ pull(stream, pull.collect(cb))
6+}
7+
8+exports.avatar =
9+function name (id, sbot) {
10+ var n = h('span', id.substring(0, 10))
11+ //choose the most popular name for this person.
12+ //for anything like this you'll see I have used sbot.links2
13+ //which is the ssb-links plugin. as you'll see the query interface
14+ //is pretty powerful!
15+ //TODO: "most popular" name is easily gameable.
16+ //must come up with something better than this.
17+ /*
18+ filter(rel: ['mentions', prefix('@')])
19+ .reduce(name: rel[1], value: count())
20+ */
21+
22+ all(
23+ sbot.links2.read({query: [
24+ {$filter: {rel: ['mentions', {$prefix: '@'}], dest: id}},
25+ {$reduce: { name: ['rel', 1], count: {$count: true}
26+ }}
27+ ]}),
28+ function (err, names) {
29+ if(err) throw err
30+ console.log(names)
31+ n.textContent = names.reduce(function (max, item) {
32+ return max.count > item.count ? max : item
33+ }, {name: id.substring(0, 10), count: 0}).name
34+ })
35+
36+ return n
37+
38+}
39+
modules/post.jsView
@@ -1,0 +1,17 @@
1+var markdown = require('ssb-markdown')
2+var h = require('hyperscript')
3+
4+//render a message
5+
6+exports.message_content = function (data, sbot) {
7+ if(data.value.content && data.value.content.text) {
8+ var d = h('div'/*, data.value.root ? */)
9+ d.innerHTML =
10+ markdown.block(data.value.content.text, data.value.content.mentions)
11+ return d
12+ }
13+}
14+
15+
16+
17+
modules/timestamp.jsView
@@ -1,0 +1,6 @@
1+var h = require('hyperscript')
2+var moment = require('moment')
3+
4+exports.message_meta = function (msg) {
5+ return h('a', {href: '#/'+msg.key}, moment(msg.value.timestamp).fromNow())
6+}
package.jsonView
@@ -1,0 +1,24 @@
1+{
2+ "name": "patchboard",
3+ "description": "",
4+ "version": "0.0.0",
5+ "homepage": "https://github.com/dominictarr/patchboard",
6+ "repository": {
7+ "type": "git",
8+ "url": "git://github.com/dominictarr/patchboard.git"
9+ },
10+ "dependencies": {
11+ "hyperscript": "^1.4.7",
12+ "moment": "^2.13.0",
13+ "pull-paramap": "^1.1.6",
14+ "pull-stream": "^3.3.2",
15+ "ssb-client": "^3.0.1",
16+ "ssb-markdown": "^3.0.0"
17+ },
18+ "devDependencies": {},
19+ "scripts": {
20+ "test": "set -e; for t in test/*.js; do node $t; done"
21+ },
22+ "author": "Dominic Tarr <dominic.tarr@gmail.com> (http://dominictarr.com)",
23+ "license": "MIT"
24+}
util.jsView
@@ -1,0 +1,18 @@
1+function first (list, test) {
2+ for(var i in list) {
3+ var value = test(list[i], i, list)
4+ if(value) return value
5+ }
6+}
7+
8+function decorate (list, value, caller) {
9+ caller = caller || function (d,e,v) { return d(e, v) }
10+
11+ return list.reduce(function (element, decorator) {
12+ return caller(decorator, element, value) || element
13+ }, null)
14+}
15+
16+exports.first = first
17+
18+exports.decorate = decorate

Built with git-ssb-web