git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 2d3be0b71fb114fe7815f6d65ae8c25ba8337ae4

Files: 2d3be0b71fb114fe7815f6d65ae8c25ba8337ae4 / main-window.js

6627 bytesRaw
1var combine = require('depject')
2var entry = require('depject/entry')
3var electron = require('electron')
4var h = require('mutant/h')
5var when = require('mutant/when')
6var onceTrue = require('mutant/once-true')
7var computed = require('mutant/computed')
8var catchLinks = require('./lib/catch-links')
9var insertCss = require('insert-css')
10var nest = require('depnest')
11var LatestUpdate = require('./lib/latest-update')
12var ref = require('ssb-ref')
13var setupContextMenuAndSpellCheck = require('./lib/context-menu-and-spellcheck')
14var watch = require('mutant/watch')
15
16module.exports = function (config) {
17 var sockets = combine(
18 overrideConfig(config),
19 addCommand('app.navigate', setView),
20 require('./modules'),
21 require('./plugs'),
22 require('patchcore'),
23 require('./overrides')
24 )
25
26 var api = entry(sockets, nest({
27 'config.sync.load': 'first',
28 'keys.sync.id': 'first',
29 'sbot.obs.connection': 'first',
30 'sbot.async.get': 'first',
31 'blob.sync.url': 'first',
32 'page.html.render': 'first',
33 'app.html.search': 'first',
34 'app.html.channels': 'first',
35 'app.views': 'first',
36 'app.sync.externalHandler': 'first',
37 'app.html.progressNotifier': 'first',
38 'profile.sheet.edit': 'first',
39 'app.navigate': 'first',
40 'channel.obs.subscribed': 'first'
41 }))
42
43 setupContextMenuAndSpellCheck(api.config.sync.load())
44
45 var id = api.keys.sync.id()
46 var latestUpdate = LatestUpdate()
47 var subscribedChannels = api.channel.obs.subscribed(id)
48
49 // prompt to setup profile on first use
50 onceTrue(api.sbot.obs.connection, (sbot) => {
51 sbot.latestSequence(sbot.id, (_, key) => {
52 if (key == null) {
53 api.profile.sheet.edit()
54 }
55 })
56 })
57
58 var views = api.app.views(api.page.html.render, [
59 '/public', '/private', id, '/mentions'
60 ])
61
62 var pendingCount = views.get('/mentions').pendingUpdates
63
64 watch(pendingCount, count => {
65 electron.remote.app.setBadgeCount(count)
66 })
67
68 insertCss(require('./styles'))
69
70 var container = h(`MainWindow -${process.platform}`, [
71 h('div.top', [
72 h('span.history', [
73 h('a', {
74 'ev-click': views.goBack,
75 classList: [ when(views.canGoBack, '-active') ]
76 }),
77 h('a', {
78 'ev-click': views.goForward,
79 classList: [ when(views.canGoForward, '-active') ]
80 })
81 ]),
82 h('span.nav', [
83 tab('Public', '/public'),
84 tab('Private', '/private'),
85 dropTab('More', [
86 getSubscribedChannelMenu,
87 ['Gatherings', '/gatherings'],
88 ['Extended Network', '/all']
89 ])
90 ]),
91 h('span.appTitle', [
92 h('span.title', 'Patchwork'),
93 api.app.html.progressNotifier()
94 ]),
95 h('span', [ api.app.html.search(api.app.navigate) ]),
96 h('span.nav', [
97 tab('Profile', id),
98 tab('Mentions', '/mentions')
99 ])
100 ]),
101 when(latestUpdate,
102 h('div.info', [
103 h('a.message -update', { href: 'https://github.com/ssbc/patchwork/releases' }, [
104 h('strong', ['Patchwork ', latestUpdate, ' has been released.']), ' Click here to download and view more info!',
105 h('a.ignore', {'ev-click': latestUpdate.ignore}, 'X')
106 ])
107 ])
108 ),
109 views.html
110 ])
111
112 catchLinks(container, (href, external) => {
113 if (external) {
114 electron.shell.openExternal(href)
115 } else if (ref.isBlob(href)) {
116 electron.shell.openExternal(api.blob.sync.url(href))
117 } else if (ref.isMsg(href)) {
118 getExternalHandler(href, (err, handler) => {
119 if (err) throw err
120 if (handler) {
121 handler(href)
122 } else {
123 api.app.navigate(href)
124 }
125 })
126 } else {
127 api.app.navigate(href)
128 }
129 })
130
131 return container
132
133 // scoped
134
135 function getSubscribedChannelMenu () {
136 var channels = Array.from(subscribedChannels()).sort(localeCompare)
137
138 if (channels.length) {
139 return {
140 label: 'Channels',
141 submenu: [
142 { label: 'Browse All',
143 click () {
144 setView('/channels')
145 }
146 },
147 {type: 'separator'}
148 ].concat(channels.map(channel => {
149 return {
150 label: `#${channel}`,
151 click () {
152 setView(`#${channel}`)
153 }
154 }
155 }))
156 }
157 } else {
158 return {
159 label: 'Browse Channels',
160 click () {
161 setView('/channels')
162 }
163 }
164 }
165 }
166
167 function dropTab (title, items) {
168 var element = h('a -drop', {
169 'ev-click': (ev) => {
170 var rects = element.getBoundingClientRect()
171 electron.remote.getCurrentWindow().webContents.getZoomFactor((factor) => {
172 var menu = electron.remote.Menu.buildFromTemplate(items.map(item => {
173 if (typeof item === 'function') {
174 return item()
175 } else {
176 return {
177 label: item[0],
178 click () {
179 setView(item[1])
180 }
181 }
182 }
183 }))
184 menu.popup(electron.remote.getCurrentWindow(), {
185 x: Math.round(rects.left * factor),
186 y: Math.round(rects.bottom * factor) + 4,
187 async: true
188 })
189 })
190 }
191 }, title)
192 return element
193 }
194
195 function setView (href) {
196 views.setView(href)
197 }
198
199 function getExternalHandler (key, cb) {
200 api.sbot.async.get(key, function (err, value) {
201 if (err) return cb(err)
202 cb(null, api.app.sync.externalHandler({key, value}))
203 })
204 }
205
206 function tab (name, view) {
207 var instance = views.get(view)
208 return h('a', {
209 'ev-click': function (ev) {
210 if (instance.pendingUpdates && instance.pendingUpdates() && instance.reload) {
211 instance.reload()
212 }
213 },
214 href: view,
215 classList: [
216 when(selected(view), '-selected')
217 ]
218 }, [
219 name,
220 when(instance.pendingUpdates, [
221 ' (', instance.pendingUpdates, ')'
222 ])
223 ])
224 }
225
226 function selected (view) {
227 return computed([views.currentView, view], (currentView, view) => {
228 return currentView === view
229 })
230 }
231}
232
233function overrideConfig (config) {
234 return {
235 'patchwork/config': {
236 gives: nest('config.sync.load'),
237 create: function (api) {
238 return nest('config.sync.load', () => config)
239 }
240 }
241 }
242}
243
244function addCommand (id, cb) {
245 return {
246 [`patchwork/command/${id}`]: {
247 gives: nest(id),
248 create: function (api) {
249 return nest(id, cb)
250 }
251 }
252 }
253}
254
255function localeCompare (a, b) {
256 return a.localeCompare(b)
257}
258

Built with git-ssb-web