git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: a55c6ee357ae26944dcd50814406be4d91d90804

Files: a55c6ee357ae26944dcd50814406be4d91d90804 / main-window.js

5526 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('div', {
82 classList: `MainWindow -${process.platform}`,
83 events: {
84 click: catchLinks
85 }
86 }, [
87 h('div.top', [
88 h('span.history', [
89 h('a', {
90 'ev-click': goBack,
91 classList: [ when(canGoBack, '-active') ]
92 }, '<'),
93 h('a', {
94 'ev-click': goForward,
95 classList: [ when(canGoForward, '-active') ]
96 }, '>')
97 ]),
98 h('span.nav', [
99 tab('Public', '/public'),
100 tab('Private', '/private')
101 ]),
102 h('span.appTitle', ['Patchwork']),
103 h('span', [ searchBox ]),
104 h('span.nav', [
105 tab('Profile', id),
106 // tab('Mentions', '/notifications')
107 ])
108 ]),
109 mainElement
110 ])
111
112 // scoped
113
114 function catchLinks (ev) {
115 if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.defaultPrevented) {
116 return true
117 }
118
119 var anchor = null
120 for (var n = ev.target; n.parentNode; n = n.parentNode) {
121 if (n.nodeName === 'A') {
122 anchor = n
123 break
124 }
125 }
126 if (!anchor) return true
127
128 var href = anchor.getAttribute('href')
129
130 if (href) {
131 var url = Url.parse(href)
132 if (url.host) {
133 electron.shell.openExternal(href)
134 } else if (href !== '#') {
135 setView(href)
136 }
137 }
138
139 ev.preventDefault()
140 ev.stopPropagation()
141 }
142
143 function tab (name, view) {
144 var instance = views.get(view)
145 lastViewed[view] = true
146 return h('a', {
147 'ev-click': function (ev) {
148 if (instance.pendingUpdates && instance.pendingUpdates() && instance.reload) {
149 instance.reload()
150 }
151 },
152 href: view,
153 classList: [
154 when(selected(view), '-selected')
155 ]
156 }, [
157 name,
158 when(instance.pendingUpdates, [
159 ' (', instance.pendingUpdates, ')'
160 ])
161 ])
162 }
163
164 function goBack () {
165 if (backHistory.length) {
166 canGoForward.set(true)
167 forwardHistory.push(currentView())
168 currentView.set(backHistory.pop())
169 canGoBack.set(backHistory.length > 0)
170 }
171 }
172
173 function goForward () {
174 if (forwardHistory.length) {
175 backHistory.push(currentView())
176 currentView.set(forwardHistory.pop())
177 canGoForward.set(forwardHistory.length > 0)
178 canGoBack.set(true)
179 }
180 }
181
182 function setView (view) {
183 if (!views.has(view)) {
184 views.put(view, renderPage(view))
185 }
186
187 if (lastViewed[view] !== true) {
188 lastViewed[view] = Date.now()
189 }
190
191 if (currentView() && lastViewed[currentView()] !== true) {
192 lastViewed[currentView()] = Date.now()
193 }
194
195 if (view !== currentView()) {
196 canGoForward.set(false)
197 canGoBack.set(true)
198 forwardHistory.length = 0
199 backHistory.push(currentView())
200 currentView.set(view)
201 }
202 }
203
204 function doSearch () {
205 var value = searchBox.value.trim()
206 if (value.startsWith('/') || value.startsWith('?') || value.startsWith('@') || value.startsWith('#') || value.startsWith('%')) {
207 setView(value)
208 } else if (value.trim()) {
209 setView(`?${value.trim()}`)
210 } else {
211 setView('/public')
212 }
213 }
214
215 function selected (view) {
216 return computed([currentView, view], (currentView, view) => {
217 return currentView === view
218 })
219 }
220}
221
222function overrideConfig (config) {
223 return [{
224 gives: nest('config.sync.load'),
225 create: function (api) {
226 return nest('config.sync.load', () => config)
227 }
228 }]
229}
230

Built with git-ssb-web