git ssb

10+

Matt McKegg / patchwork



Tree: 66eb3aded58d22467d641cb52da1353212e8219a

Files: 66eb3aded58d22467d641cb52da1353212e8219a / main-window.js

5503 bytesRaw
1var combine = require('depject')
2var entry = require('depject/entry')
3var electron = require('electron')
4var h = require('mutant/h')
5var Value = require('mutant/value')
6var when = require('mutant/when')
7var computed = require('mutant/computed')
8var toCollection = require('mutant/dict-to-collection')
9var MutantDict = require('mutant/dict')
10var MutantMap = require('mutant/map')
11var Url = require('url')
12var insertCss = require('insert-css')
13var nest = require('depnest')
14
15module.exports = function (config) {
16 var sockets = combine(
17 overrideConfig(config),
18 require('./modules'),
19 require('./plugs'),
20 require('patchcore')
21 )
22 var api = entry(sockets, nest({
23 'page.html.render': 'first'
24 }))
25
26 var renderPage = api.page.html.render
27
28 var searchTimer = null
29 var searchBox = h('input.search', {
30 type: 'search',
31 placeholder: 'word, @key, #channel'
32 })
33
34 searchBox.oninput = function () {
35 clearTimeout(searchTimer)
36 searchTimer = setTimeout(doSearch, 500)
37 }
38
39 searchBox.onfocus = function () {
40 if (searchBox.value) {
41 doSearch()
42 }
43 }
44
45 var forwardHistory = []
46 var backHistory = []
47
48 var views = MutantDict({
49 // preload tabs (and subscribe to update notifications)
50 '/public': renderPage('/public'),
51 '/private': renderPage('/private'),
52 // [ssbClient.id]: renderPage(ssbClient.id),
53 // '/notifications': renderPage('/notifications')
54 })
55
56 var lastViewed = {}
57
58 // delete cached view after 30 mins of last seeing
59 setInterval(() => {
60 views.keys().forEach((view) => {
61 if (lastViewed[view] !== true && Date.now() - lastViewed[view] > (30 * 60e3) && view !== currentView()) {
62 views.delete(view)
63 }
64 })
65 }, 60e3)
66
67 var canGoForward = Value(false)
68 var canGoBack = Value(false)
69 var currentView = Value('/public')
70
71 var mainElement = h('div.main', MutantMap(toCollection(views), (item) => {
72 return h('div.view', {
73 hidden: computed([item.key, currentView], (a, b) => a !== b)
74 }, [ item.value ])
75 }))
76
77 insertCss(require('./styles'))
78
79 return h('div', {
80 classList: `MainWindow -${process.platform}`,
81 events: {
82 click: catchLinks
83 }
84 }, [
85 h('div.top', [
86 h('span.history', [
87 h('a', {
88 'ev-click': goBack,
89 classList: [ when(canGoBack, '-active') ]
90 }, '<'),
91 h('a', {
92 'ev-click': goForward,
93 classList: [ when(canGoForward, '-active') ]
94 }, '>')
95 ]),
96 h('span.nav', [
97 tab('Public', '/public'),
98 tab('Private', '/private')
99 ]),
100 h('span.appTitle', ['Patchwork']),
101 h('span', [ searchBox ]),
102 h('span.nav', [
103 // tab('Profile', ssbClient.id),
104 // tab('Mentions', '/notifications')
105 ])
106 ]),
107 mainElement
108 ])
109
110 // scoped
111
112 function catchLinks (ev) {
113 if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.defaultPrevented) {
114 return true
115 }
116
117 var anchor = null
118 for (var n = ev.target; n.parentNode; n = n.parentNode) {
119 if (n.nodeName === 'A') {
120 anchor = n
121 break
122 }
123 }
124 if (!anchor) return true
125
126 var href = anchor.getAttribute('href')
127
128 if (href) {
129 var url = Url.parse(href)
130 if (url.host) {
131 electron.shell.openExternal(href)
132 } else if (href !== '#') {
133 setView(href)
134 }
135 }
136
137 ev.preventDefault()
138 ev.stopPropagation()
139 }
140
141 function tab (name, view) {
142 var instance = views.get(view)
143 lastViewed[view] = true
144 return h('a', {
145 'ev-click': function (ev) {
146 if (instance.pendingUpdates && instance.pendingUpdates() && instance.reload) {
147 instance.reload()
148 }
149 },
150 href: view,
151 classList: [
152 when(selected(view), '-selected')
153 ]
154 }, [
155 name,
156 when(instance.pendingUpdates, [
157 ' (', instance.pendingUpdates, ')'
158 ])
159 ])
160 }
161
162 function goBack () {
163 if (backHistory.length) {
164 canGoForward.set(true)
165 forwardHistory.push(currentView())
166 currentView.set(backHistory.pop())
167 canGoBack.set(backHistory.length > 0)
168 }
169 }
170
171 function goForward () {
172 if (forwardHistory.length) {
173 backHistory.push(currentView())
174 currentView.set(forwardHistory.pop())
175 canGoForward.set(forwardHistory.length > 0)
176 canGoBack.set(true)
177 }
178 }
179
180 function setView (view) {
181 if (!views.has(view)) {
182 views.put(view, renderPage(view))
183 }
184
185 if (lastViewed[view] !== true) {
186 lastViewed[view] = Date.now()
187 }
188
189 if (currentView() && lastViewed[currentView()] !== true) {
190 lastViewed[currentView()] = Date.now()
191 }
192
193 if (view !== currentView()) {
194 canGoForward.set(false)
195 canGoBack.set(true)
196 forwardHistory.length = 0
197 backHistory.push(currentView())
198 currentView.set(view)
199 }
200 }
201
202 function doSearch () {
203 var value = searchBox.value.trim()
204 if (value.startsWith('/') || value.startsWith('?') || value.startsWith('@') || value.startsWith('#') || value.startsWith('%')) {
205 setView(value)
206 } else if (value.trim()) {
207 setView(`?${value.trim()}`)
208 } else {
209 setView('/public')
210 }
211 }
212
213 function selected (view) {
214 return computed([currentView, view], (currentView, view) => {
215 return currentView === view
216 })
217 }
218}
219
220function overrideConfig (config) {
221 return [{
222 gives: nest('config.sync.load'),
223 create: function (api) {
224 return nest('config.sync.load', () => config)
225 }
226 }]
227}
228

Built with git-ssb-web