git ssb

2+

dinoworm 🐛 / ssb-graphviz



Commit 3752a1567791fcb0bffec326af555ae3e16045f5

Srs bizniz refactor (#1)

* re-write everything, just because, not yet working
* it works again!
* update based on feedback from @mixmix, thanks!
Mikey authored on 12/16/2016, 2:19:30 AM
GitHub committed on 12/16/2016, 2:19:30 AM
Parent: 4c04551a3e25f880780438f3d6ba6a54f100d610

Files changed

index.jschanged
package.jsonchanged
graph.jsdeleted
api.jsadded
app.jsadded
output.jsdeleted
assets/api.jsadded
browser.jsadded
renderer.jsdeleted
config.jsadded
graph/actions.jsadded
graph/api.jsadded
graph/app.jsadded
graph/helpers/build-links.jsadded
graph/helpers/build-nodes.jsadded
graph/view.jsadded
profiles/actions.jsadded
profiles/api.jsadded
profiles/app.jsadded
profiles/view.jsadded
server.jsadded
index.jsView
@@ -1,34 +1,57 @@
1-const fromJson = require('ngraph.fromjson')
2-const Renderer = require('./renderer')
3-const Graph = require('./graph')
1 +const http = require('http')
2 +const defaultsDeep = require('lodash/defaultsDeep')
43
5-const config = {
6- physics: {
7- springLength: 80,
8- springCoeff: 0.0001,
9- gravity: -1.4,
10- theta: 0.4,
11- dragCoeff: 0.04
12- },
13- link: (link) => {
14- // if (link.data.hidden) return
15- // makes linkUI element not exist ? => display.getLink doesn't work
4 +const defaultVizConfig = require('./config')
5 +const Api = require('./api')
166
17- return {
18- fromColor: 0x000066,
19- toColor: 0x000066
20- }
7 +var _server
8 +
9 +module.exports = {
10 + name: 'ssb-graphviz',
11 + version: require('./package.json').version,
12 + manifest: {},
13 + init: function (ssb, config, reconnect) {
14 + // close existing server. when scuttlebot plugins get a deinit method, we
15 + // will close it in that instead it
16 + if (_server) _server.close()
17 +
18 + _server = Server(ssb, config, reconnect)
19 + _server.listen()
20 +
21 + return {}
2122 }
2223 }
2324
24-module.exports = function (sbot, cb) {
25- Graph(sbot, (err, data) => {
26- if (err) return cb(err)
27- const str = JSON.stringify(data)
28- var graph = fromJson(str)
29- var display = Renderer(graph, config, sbot)
25 +function Server (ssb, config, reconnect) {
26 + const vizConfig = defaultsDeep(config['ssb-graphviz'], defaultVizConfig)
27 + const { host, port } = parseAddr(config.listenAddr, {
28 + host: vizConfig.host,
29 + port: vizConfig.port
30 + })
3031
31- cb(null, display)
32- })
32 + var server = http.createServer(Api(ssb, config))
33 +
34 + return {
35 + listen,
36 + close
37 + }
38 +
39 + function listen () {
40 + server.listen(port, host, function () {
41 + var hostName = ~host.indexOf(':') ? `[${host}]` : host
42 + console.log(`Listening on http://${hostName}:${port}/`)
43 + })
44 + }
45 +
46 + function close () {
47 + server.close()
48 + }
3349 }
3450
51 +function parseAddr (str, def) {
52 + if (!str) return def
53 + var i = str.lastIndexOf(':')
54 + if (~i) return { host: str.substr(0, i), port: str.substr(i + 1) }
55 + if (isNaN(str)) return { host: str, port: def.port }
56 + return { host: def.host, port: str }
57 +}
package.jsonView
@@ -4,9 +4,10 @@
44 "description": "visualize the ssb network graph",
55 "main": "index.js",
66 "scripts": {
77 "test": "standard",
8- "start": "electro output.js"
8 + "start": "node server",
9 + "start:dev": "node-dev server"
910 },
1011 "repository": {
1112 "type": "git",
1213 "url": " ssb://%hNm67sfnZFtWkD/+1qxH3UfzhXykfpKtOL1C/XbLANA=.sha256"
@@ -18,23 +19,32 @@
1819 "url": "https://git.scuttlebot.io/%25hNm67sfnZFtWkD%2F%2B1qxH3UfzhXykfpKtOL1C%2FXbLANA%3D.sha256/issues"
1920 },
2021 "homepage": "https://git.scuttlebot.io/%25hNm67sfnZFtWkD%2F%2B1qxH3UfzhXykfpKtOL1C%2FXbLANA%3D.sha256#readme",
2122 "devDependencies": {
23 + "inu-log": "^1.0.2",
24 + "node-dev": "^3.1.3",
2225 "standard": "^8.6.0",
2326 "tape": "^4.5.1"
2427 },
2528 "dependencies": {
26- "electro": "^2.0.2",
27- "electron": "^1.4.4",
28- "hyperscript": "^2.0.2",
29- "insert-css": "^1.0.0",
29 + "bankai": "^5.1.3",
30 + "cache-element": "^2.0.0",
31 + "http-routes": "^1.2.3",
3032 "inu": "^3.1.3",
33 + "inux": "^2.1.0",
34 + "lodash": "^4.17.2",
3135 "ngraph.fromjson": "^0.1.8",
32- "ngraph.pixel": "^2.2.0",
36 + "ngraph.pixel": "github:ahdinosaur/ngraph.pixel#sheetify-compatible-styles",
37 + "pull-cont": "0.0.0",
3338 "pull-stream": "^3.4.5",
3439 "run-waterfall": "^1.1.3",
40 + "send-data": "^8.0.0",
3541 "ssb-avatar": "^0.2.0",
3642 "ssb-client": "^4.3.0",
43 + "ssb-config": "^2.2.0",
44 + "ssb-keys": "^7.0.3",
45 + "ssb-reconnect": "^0.1.1",
46 + "stack": "^0.1.0",
3747 "stream-to-pull-stream": "^1.7.2",
38- "yo-yo": "^1.3.1"
48 + "xhr": "^2.3.1"
3949 }
4050 }
graph.jsView
@@ -1,67 +1,0 @@
1-const waterfall = require('run-waterfall')
2-
3-const { keys } = Object
4-
5-module.exports = Graph
6-
7-function Graph (sbot, cb) {
8- waterfall([
9- (cb) => sbot.friends.all(cb),
10- (friends, cb) => {
11- const filteredFriends = friends // activeFriends(friends)
12-
13- cb(null, {
14- nodes: buildNodes(filteredFriends),
15- links: buildLinks(filteredFriends)
16- })
17- }
18- ], cb)
19-}
20-
21-function buildNodes (friends) {
22- return keys(friends).map(id => {
23- return {
24- id,
25- data: {
26- friends: keys(friends[id])
27- }
28- }
29- })
30-}
31-
32-function buildLinks (friends) {
33- return keys(friends).reduce((sofar, friend) => {
34- const friendOfFriends = keys(friends[friend])
35- .filter(id => friends[friend][id] === true)
36-
37- const edges = friendOfFriends.map(friendOfFriend => {
38- return {
39- fromId: friend,
40- toId: friendOfFriend,
41- data: {
42- hidden: true
43- }
44- }
45- })
46-
47- return [
48- ...sofar,
49- ...edges
50- ]
51- }, [])
52-}
53-
54-/*
55-function activeFriends (friends) {
56- return keys(friends)
57- .reduce(
58- (sofar, current) => {
59- if (keys(friends[current]).length < 4) return sofar
60-
61- sofar[current] = friends[current]
62- return sofar
63- },
64- {}
65- )
66-}
67-*/
api.jsView
@@ -1,0 +1,11 @@
1 +const Stack = require('stack')
2 +
3 +module.exports = VizApi
4 +
5 +function VizApi (ssb, config) {
6 + return Stack(...[
7 + require('./graph/api'),
8 + require('./profiles/api'),
9 + require('./assets/api')
10 + ].map(m => m(ssb, config)))
11 +}
app.jsView
@@ -1,0 +1,10 @@
1 +const { App } = require('inux')
2 +
3 +module.exports = VizApp
4 +
5 +function VizApp (config) {
6 + return App([
7 + require('./graph/app')(config),
8 + require('./profiles/app')(config)
9 + ])
10 +}
output.jsView
@@ -1,31 +1,0 @@
1-const insertCss = require('insert-css')
2-const Sbot = require('ssb-client')
3-const waterfall = require('run-waterfall')
4-
5-const Viz = require('./')
6-
7-insertCss(`
8- html, body {
9- width: 100%;
10- height: 100%;
11- position: absolute;
12- overflow: hidden;
13- padding: 0;
14- margin: 0;
15- }
16-
17- .avatar {
18- position: fixed;
19- left: 10px;
20- bottom: 10px;
21- color: #fff;
22- }
23-
24- .avatar .image {
25- max-height: 160px;
26- }
27-`)
28-
29-waterfall([Sbot, Viz], (err) => {
30- if (err) throw err
31-})
assets/api.jsView
@@ -1,0 +1,37 @@
1 +const { join } = require('path')
2 +const pull = require('pull-stream')
3 +const toPull = require('stream-to-pull-stream')
4 +const Assets = require('bankai')
5 +const Routes = require('http-routes')
6 +
7 +module.exports = AssetsApi
8 +
9 +function AssetsApi (ssb, config) {
10 + const clientPath = join(__dirname, '../browser.js')
11 + const assets = Assets(clientPath)
12 +
13 + return Routes([
14 + ['/', (req, res, next) => {
15 + assets.html(req, res).pipe(res)
16 + }],
17 + ['/bundle.js', (req, res, next) => {
18 + assets.js(req, res).pipe(res)
19 + }],
20 + ['/bundle.css', (req, res, next) => {
21 + assets.css(req, res).pipe(res)
22 + }],
23 + ['/blobs/:blobId(.*)', {
24 + get: (req, res, next) => {
25 + sendBlob(req.params.blobId, req, res)
26 + }
27 + }]
28 + ])
29 +
30 + function sendBlob (id, req, res) {
31 + pull(getBlob(id), toPull(res))
32 + }
33 +
34 + function getBlob (id) {
35 + return ssb.blobs.get(id)
36 + }
37 +}
browser.jsView
@@ -1,0 +1,33 @@
1 +const css = require('sheetify')
2 +const { start, html, pull } = require('inu')
3 +const log = require('inu-log')
4 +
5 +const config = require('./config')
6 +const App = require('./app')
7 +
8 +css`
9 + html, body, .main, .graph {
10 + width: 100%;
11 + height: 100%;
12 + position: absolute;
13 + overflow: hidden;
14 + padding: 0;
15 + margin: 0;
16 + }
17 +`
18 +
19 +var app = App(config)
20 +if (process.env.NODE_ENV !== 'production') {
21 + app = log(app)
22 +}
23 +const { views } = start(app)
24 +const main = document.createElement('div')
25 +main.className = 'main'
26 +document.body.appendChild(main)
27 +
28 +pull(
29 + views(),
30 + pull.drain(view => {
31 + html.update(main, view)
32 + })
33 +)
renderer.jsView
@@ -1,72 +1,0 @@
1-const Renderer = require('ngraph.pixel')
2-const avatar = require('ssb-avatar')
3-const html = require('yo-yo')
4-
5-module.exports = createRenderer
6-
7-function createRenderer (graph, config, sbot) {
8- var avatarEl = html`<div class="avatar" />`
9- document.body.appendChild(avatarEl)
10-
11- var display = Renderer(graph, config)
12-
13- display.on('nodehover', handleNodeHover)
14-
15- return display
16-
17- function handleNodeHover (node) {
18- if (node === undefined) return
19-
20- avatar(sbot, node.id, node.id, (err, { name, image }) => {
21- // handle this error!
22- if (err) throw err
23-
24- const imgSrc = image ? `http://localhost:7777/${image}` : ''
25-
26- const newAvatarEl = html`
27- <div class="avatar">
28- <img class="image" src=${imgSrc} />
29- <div class="name">${name}</div>
30- </div>
31- `
32-
33- html.update(avatarEl, newAvatarEl)
34- })
35-
36- display.forEachLink(linkUI => {
37- const { from, to } = linkUI
38- const friends = node.data.friends
39-
40- const isFromTarget = node.id === from.id
41- const isToTarget = node.id === to.id
42-
43- const isFromFriend = friends.indexOf(from.id) > -1
44- const isToFriend = friends.indexOf(to.id) > -1
45- const involvesFoaF = isFromFriend || isToTarget
46-
47- var fromColor = 0x000066
48- var toColor = 0x000066
49-
50- const close = 0xffffff
51- const mid = 0xa94caf
52- const far = 0x000066
53-
54- if (isFromTarget) {
55- fromColor = close
56- toColor = mid
57- } else if (isToTarget) {
58- fromColor = mid
59- toColor = close
60- } else if (involvesFoaF && isFromFriend) {
61- fromColor = mid
62- toColor = far
63- } else if (involvesFoaF && isToFriend) {
64- fromColor = far
65- toColor = mid
66- }
67-
68- linkUI.fromColor = fromColor
69- linkUI.toColor = toColor
70- })
71- }
72-}
config.jsView
@@ -1,0 +1,22 @@
1 +const config = {
2 + host: 'localhost',
3 + port: 7781,
4 + physics: {
5 + springLength: 80,
6 + springCoeff: 0.0001,
7 + gravity: -1.4,
8 + theta: 0.4,
9 + dragCoeff: 0.04
10 + },
11 + link: (link) => {
12 + // if (link.data.hidden) return
13 + // makes linkUI element not exist ? => display.getLink doesn't work
14 +
15 + return {
16 + fromColor: 0x000066,
17 + toColor: 0x000066
18 + }
19 + }
20 +}
21 +
22 +module.exports = config
graph/actions.jsView
@@ -1,0 +1,22 @@
1 +const { Action } = require('inux')
2 +
3 +const SET = Symbol('set')
4 +const SET_HOVER = Symbol('setHover')
5 +const FETCH = Symbol('fetch')
6 +const HOVER = Symbol('hover')
7 +
8 +const set = Action(SET)
9 +const setHover = Action(SET_HOVER)
10 +const fetch = Action(FETCH)
11 +const hover = Action(HOVER)
12 +
13 +module.exports = {
14 + SET,
15 + SET_HOVER,
16 + FETCH,
17 + HOVER,
18 + set,
19 + setHover,
20 + fetch,
21 + hover
22 +}
graph/api.jsView
@@ -1,0 +1,41 @@
1 +const waterfall = require('run-waterfall')
2 +const sendJson = require('send-data/json')
3 +const sendError = require('send-data/error')
4 +const Routes = require('http-routes')
5 +
6 +const buildLinks = require('./helpers/build-links')
7 +const buildNodes = require('./helpers/build-nodes')
8 +
9 +module.exports = GraphApi
10 +
11 +function GraphApi (ssb, config) {
12 + return Routes([
13 + ['/api/graph', {
14 + get: (req, res, next) => {
15 + sendGraph(req, res)
16 + }
17 + }]
18 + ])
19 +
20 + function sendGraph (req, res) {
21 + getGraph((err, graph) => {
22 + if (err) {
23 + sendError(req, res, { body: err })
24 + } else {
25 + sendJson(req, res, { body: graph })
26 + }
27 + })
28 + }
29 +
30 + function getGraph (cb) {
31 + waterfall([
32 + ssb.friends.all,
33 + (friends, cb) => {
34 + cb(null, {
35 + nodes: buildNodes(friends),
36 + links: buildLinks(friends)
37 + })
38 + }
39 + ], cb)
40 + }
41 +}
graph/app.jsView
@@ -1,0 +1,68 @@
1 +const { assign } = Object
2 +const xhr = require('xhr')
3 +const { Domain, run } = require('inux')
4 +const pullContinuable = require('pull-cont')
5 +const html = require('inu/html')
6 +const pull = require('pull-stream')
7 +
8 +const { SET, SET_HOVER, FETCH, HOVER, set, setHover, fetch } = require('./actions')
9 +const GraphView = require('./view')
10 +const { fetchOne: fetchProfile } = require('../profiles/actions')
11 +const ProfileView = require('../profiles/view')
12 +
13 +module.exports = GraphApp
14 +
15 +function GraphApp (config) {
16 + const graphView = GraphView(config)
17 + const profileView = ProfileView(config)
18 +
19 + return Domain({
20 + name: 'graph',
21 + init: () => ({
22 + model: {
23 + nodes: [],
24 + links: []
25 + },
26 + effect: fetch()
27 + }),
28 + update: {
29 + [SET]: (model, graph) => ({ model: graph }),
30 + [SET_HOVER]: (model, hover) => ({
31 + model: assign({}, model, { hover })
32 + })
33 + },
34 + run: {
35 + [FETCH]: () => {
36 + return pullContinuable(cb => {
37 + xhr({
38 + url: '/api/graph',
39 + json: true
40 + }, (err, resp, { body } = {}) => {
41 + if (err) return cb(err)
42 + cb(null, pull.values([set(body)]))
43 + })
44 + })
45 + },
46 + [HOVER]: (id) => {
47 + return pull.values([
48 + setHover(id),
49 + run(fetchProfile(id))
50 + ])
51 + }
52 + },
53 + routes: [
54 + ['/', (params, model, dispatch) => {
55 + const { graph, profiles } = model
56 + const { hover } = graph
57 + const hoveredProfile = hover ? profiles[hover] : undefined
58 +
59 + return html`
60 + <div class='main'>
61 + ${graphView(graph, dispatch)}
62 + ${profileView(hoveredProfile, dispatch)}
63 + </div>
64 + `
65 + }]
66 + ]
67 + })
68 +}
graph/helpers/build-links.jsView
@@ -1,0 +1,25 @@
1 +const { keys } = Object
2 +
3 +module.exports = buildLinks
4 +
5 +function buildLinks (friends) {
6 + return keys(friends).reduce((sofar, friend) => {
7 + const friendOfFriends = keys(friends[friend])
8 + .filter(id => friends[friend][id] === true)
9 +
10 + const edges = friendOfFriends.map(friendOfFriend => {
11 + return {
12 + fromId: friend,
13 + toId: friendOfFriend,
14 + data: {
15 + hidden: true
16 + }
17 + }
18 + })
19 +
20 + return [
21 + ...sofar,
22 + ...edges
23 + ]
24 + }, [])
25 +}
graph/helpers/build-nodes.jsView
@@ -1,0 +1,15 @@
1 +const { keys } = Object
2 +
3 +module.exports = buildNodes
4 +
5 +function buildNodes (friends) {
6 + return keys(friends).map(id => {
7 + return {
8 + id,
9 + data: {
10 + friends: keys(friends[id])
11 + }
12 + }
13 + })
14 +}
15 +
graph/view.jsView
@@ -1,0 +1,102 @@
1 +const { assign } = Object
2 +const Renderer = require('ngraph.pixel')
3 +const html = require('inu/html')
4 +const { run } = require('inux')
5 +const Widget = require('cache-element/widget')
6 +
7 +const fromJson = require('ngraph.fromjson')
8 +
9 +const { hover } = require('./actions')
10 +
11 +module.exports = GraphView
12 +
13 +function GraphView (config) {
14 + var ngraph
15 + var display
16 +
17 + return Widget({
18 + render: function (graph, dispatch) {
19 + return html`<div class='graph'></div>`
20 + },
21 + onupdate: function (el, graph, dispatch) {
22 + if (!display) {
23 + ngraph = fromJson(graph)
24 + display = Display(el)
25 + display.on('nodehover', NodeHoverHandler(dispatch))
26 + } else {
27 + // TODO a better way to update the graph
28 + // updateGraph(graph)
29 + // display.off('nodehover')
30 + // display.on('nodehover', NodeHoverHandler(dispatch))
31 + }
32 + }
33 + })
34 +
35 + /*
36 + function updateGraph ({ nodes, links }) {
37 + ngraph.beginUpdate()
38 + ngraph.forEachLink(link => {
39 + ngraph.removeLink(link)
40 + })
41 + ngraph.forEachNode(node => {
42 + ngraph.removeNode(node)
43 + })
44 + nodes.forEach(node => {
45 + ngraph.addNode(node.id, node.data)
46 + })
47 + links.forEach(link => {
48 + ngraph.addLink(link.fromId, link.toId, link.data)
49 + })
50 + ngraph.endUpdate()
51 + }
52 + */
53 +
54 + function Display (node) {
55 + const ngraphConfig = assign({ container: node }, config)
56 + return Renderer(ngraph, ngraphConfig)
57 + }
58 +
59 + function NodeHoverHandler (dispatch) {
60 + return (node) => {
61 + if (node === undefined) return
62 +
63 + dispatch(run(hover(node.id)))
64 +
65 + display.forEachLink(linkUI => {
66 + const { from, to } = linkUI
67 + const friends = node.data.friends
68 +
69 + const isFromTarget = node.id === from.id
70 + const isToTarget = node.id === to.id
71 +
72 + const isFromFriend = friends.indexOf(from.id) > -1
73 + const isToFriend = friends.indexOf(to.id) > -1
74 + const involvesFoaF = isFromFriend || isToTarget
75 +
76 + var fromColor = 0x000066
77 + var toColor = 0x000066
78 +
79 + const close = 0xffffff
80 + const mid = 0xa94caf
81 + const far = 0x000066
82 +
83 + if (isFromTarget) {
84 + fromColor = close
85 + toColor = mid
86 + } else if (isToTarget) {
87 + fromColor = mid
88 + toColor = close
89 + } else if (involvesFoaF && isFromFriend) {
90 + fromColor = mid
91 + toColor = far
92 + } else if (involvesFoaF && isToFriend) {
93 + fromColor = far
94 + toColor = mid
95 + }
96 +
97 + linkUI.fromColor = fromColor
98 + linkUI.toColor = toColor
99 + })
100 + }
101 + }
102 +}
profiles/actions.jsView
@@ -1,0 +1,14 @@
1 +const { Action } = require('inux')
2 +
3 +const SET_ONE = Symbol('setOne')
4 +const FETCH_ONE = Symbol('fetchOne')
5 +
6 +const setOne = Action(SET_ONE)
7 +const fetchOne = Action(FETCH_ONE)
8 +
9 +module.exports = {
10 + SET_ONE,
11 + FETCH_ONE,
12 + setOne,
13 + fetchOne
14 +}
profiles/api.jsView
@@ -1,0 +1,34 @@
1 +const Avatar = require('ssb-avatar')
2 +const sendJson = require('send-data/json')
3 +const sendError = require('send-data/error')
4 +const Routes = require('http-routes')
5 +
6 +module.exports = ProfilesApi
7 +
8 +function ProfilesApi (ssb, config) {
9 + return Routes([
10 + ['/api/profiles/:profileId(.*)', {
11 + get: (req, res, next) => {
12 + sendProfile(req.params.profileId, req, res)
13 + }
14 + }]
15 + ])
16 +
17 + function sendProfile (id, req, res) {
18 + getProfile(id, (err, profile) => {
19 + if (err) {
20 + sendError(req, res, { body: err })
21 + } else {
22 + sendJson(req, res, { body: profile })
23 + }
24 + })
25 + }
26 +
27 + function getProfile (id, cb) {
28 + Avatar(ssb, id, id, (err, { name, image } = {}) => {
29 + if (err) return cb(err)
30 + const imgSrc = image ? `/blobs/${image}` : null
31 + cb(null, { id, name, image: imgSrc })
32 + })
33 + }
34 +}
profiles/app.jsView
@@ -1,0 +1,48 @@
1 +const { assign } = Object
2 +const { Domain } = require('inux')
3 +const pull = require('pull-stream')
4 +const pullContinuable = require('pull-cont')
5 +const xhr = require('xhr')
6 +
7 +const { SET_ONE, FETCH_ONE, setOne } = require('./actions')
8 +
9 +module.exports = ProfilesApp
10 +
11 +function ProfilesApp (config) {
12 + return Domain({
13 + name: 'profiles',
14 + init: () => ({
15 + model: {}
16 + }),
17 + update: {
18 + [SET_ONE]: (model, profile) => ({
19 + model: assign({}, model, { [profile.id]: profile })
20 + })
21 + },
22 + run: {
23 + [FETCH_ONE]: (profileId, sources) => {
24 + // don't fetch profile if already have it
25 + var hasProfile
26 + pull(
27 + sources.models(),
28 + pull.take(1),
29 + pull.drain(({ profiles }) => {
30 + hasProfile = !!profiles[profileId]
31 + })
32 + )
33 + if (hasProfile) return
34 +
35 + return pullContinuable(cb => {
36 + xhr({
37 + url: `/api/profiles/${profileId}`,
38 + json: true
39 + }, (err, resp, { body } = {}) => {
40 + if (err) return cb(err)
41 + if (!body) return
42 + cb(null, pull.values([setOne(body)]))
43 + })
44 + })
45 + }
46 + }
47 + })
48 +}
profiles/view.jsView
@@ -1,0 +1,30 @@
1 +const html = require('inu/html')
2 +const css = require('sheetify')
3 +
4 +module.exports = ProfileView
5 +
6 +css`
7 + .profile {
8 + position: fixed;
9 + left: 10px;
10 + bottom: 10px;
11 + color: #fff;
12 + }
13 +
14 + .profile .image {
15 + max-height: 160px;
16 + }
17 +`
18 +
19 +function ProfileView (config) {
20 + return (profile = {}, dispatch) => {
21 + const { name, image } = profile
22 +
23 + return html`
24 + <div id='profile' class='profile'>
25 + ${image && html`<img class='image' src=${image} />`}
26 + <div class='name'>${name}</div>
27 + </div>
28 + `
29 + }
30 +}
server.jsView
@@ -1,0 +1,21 @@
1 +#!/bin/sh
2 +':' // ; exec "$(command -v node || command -v nodejs)" "$0" "$@"
3 +// http://unix.stackexchange.com/questions/65235/universal-node-js-shebang
4 +// vi: ft=javascript
5 +
6 +const appName = process.env.appName
7 +const config = require('ssb-config/inject')(appName)
8 +const ssbClient = require('ssb-client')
9 +const keys = require('ssb-keys')
10 + .loadOrCreateSync(require('path').join(config.path, 'secret'))
11 +const Viz = require('.')
12 +
13 +config.listenAddr = config._[1]
14 +config.appName = appName
15 +
16 +require('ssb-reconnect')(function (cb) {
17 + ssbClient(keys, config, cb)
18 +}, function (err, ssb, reconnect) {
19 + if (err) throw err
20 + Viz.init(ssb, config, reconnect)
21 +})

Built with git-ssb-web