git ssb

10+

Matt McKegg / patchwork



Tree: 48efe837d32d477c096a7c5e8969aa19bc51a25f

Files: 48efe837d32d477c096a7c5e8969aa19bc51a25f / main-window.js

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

Built with git-ssb-web