git ssb

2+

mixmix / ticktack



Commit 3d4eca03f309655578710ab4453f309c514268d1

refactor id-importing, style interface

mix irving committed on 5/29/2018, 5:25:37 AM
Parent: af8e9b0bc28f9eb27558912de8569872ffa19022

Files changed

app/html/header.jschanged
app/page/splash.jschanged
ftu/app.jschanged
ftu/index.jschanged
ftu/app.mcssdeleted
ftu/observeSequence.jsadded
ftu/styles.jsadded
index.jschanged
package-lock.jsonchanged
package.jsonchanged
translations/en.jschanged
windowControls.jsadded
app/html/header.jsView
@@ -1,8 +1,8 @@
11 const nest = require('depnest')
22 const { h, computed, when } = require('mutant')
33 const path = require('path')
4-const { remote } = require('electron')
4+const windowControls = require('../../windowControls')
55
66 exports.gives = nest('app.html.header')
77 exports.needs = nest({
88 'app.obs.pluginsOk': 'first'
@@ -64,35 +64,8 @@
6464 })
6565 ])
6666 ])
6767 })
68-
69- function windowControls () {
70- if (process.platform === 'darwin') return
71-
72- const window = remote.getCurrentWindow()
73- const minimize = () => window.minimize()
74- const maximize = () => {
75- if (!window.isMaximized()) window.maximize()
76- else window.unmaximize()
77- }
78- const close = () => window.close()
79-
80- return h('div.window-controls', [
81- h('img.min', {
82- src: assetPath('minimize.png'),
83- 'ev-click': minimize
84- }),
85- h('img.max', {
86- src: assetPath('maximize.png'),
87- 'ev-click': maximize
88- }),
89- h('img.close', {
90- src: assetPath('close.png'),
91- 'ev-click': close
92- })
93- ])
94- }
9568 }
9669
9770 function assetPath (name) {
9871 return path.join(__dirname, '../../assets', name)
app/page/splash.jsView
@@ -16,9 +16,8 @@
1616
1717 const strings = api.translations.sync.strings()
1818
1919 const svg = assetPath('splash.svg')
20- console.log(svg)
2120
2221 const style = {
2322 'background': require('../../assets/splash-svg.js'),
2423 'background-repeat': 'no-repeat',
ftu/app.jsView
@@ -1,19 +1,20 @@
1-const { h, Value, when, resolve, computed, Struct, watch, throttle } = require('mutant')
1+const { h, Value, when, computed, Struct, watch, throttle } = require('mutant')
22 const nest = require('depnest')
33 const path = require('path')
44 const fs = require('fs')
5-const { remote } = require('electron')
6-const insertCss = require('insert-css')
7-const values = require('lodash/values')
8-const get = require('lodash/get')
95 const electron = require('electron')
10-const { dialog } = require('electron').remote
116 const os = require('os')
127 const progress = require('progress-string')
8+const values = require('lodash/values')
139
10+const observeSequence = require('./observeSequence')
11+const windowControls = require('../windowControls')
12+const ftuCss = require('./styles')
13+
1414 const appName = process.env.SSB_APPNAME || 'ssb'
15-const configFolder = path.join(os.homedir(), `.${appName}`)
15+const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`)
16+const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json')
1617
1718 var isBusy = Value(false)
1819 var isPresentingOptions = Value(true)
1920 var checkerTimeout
@@ -36,43 +37,11 @@
3637 return nest({
3738 'ftu.app': function app () {
3839 const strings = api.translations.sync.strings()
3940
40- const css = values(api.styles.css()).join('\n')
41- insertCss(css)
41+ const css = [...values(api.styles.css()), ftuCss].join('\n')
42+ document.head.appendChild(h('style', { innerHTML: css }))
4243
43- var actionButtons = h('section', [
44- h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, strings.backup.ftu.importAction)),
45- h('div.right', h('Button', { 'ev-click': () => actionCreateNewOne() }, strings.backup.ftu.createAction))
46- ])
47-
48- var busyMessage = h('p', strings.backup.ftu.busyMessage)
49-
50- var initialOptions = h('Page -ftu', [
51- h('div.content', [
52- h('h1', strings.backup.ftu.welcomeHeader),
53- h('p', strings.backup.ftu.welcomeMessage),
54- when(isBusy, busyMessage, actionButtons)
55- ])
56- ])
57-
58- var importProgress = h('Page -ftu', [
59- h('div.content', [
60- h('h1', strings.backup.import.header),
61- h('p', [strings.backup.import.synchronizeMessage]),
62- h('pre', computed(state, s => {
63- return progress({
64- width: 42,
65- total: s.latestSequence,
66- style: function (complete, incomplete) {
67- // add an arrow at the head of the completed part
68- return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})`
69- }
70- })(s.currentSequence)
71- }))
72- ])
73- ])
74-
7544 // This watcher is responsible for switching from FTU to Ticktack main app
7645 watch(throttle(state, 500), s => {
7746 if (s.currentSequence >= s.latestSequence && s.confirmedRemotely) {
7847 console.log('all imported')
@@ -80,9 +49,9 @@
8049 electron.ipcRenderer.send('import-completed')
8150 }
8251 })
8352
84- if (fs.existsSync(path.join(configFolder, 'secret'))) {
53+ if (fs.existsSync(path.join(CONFIG_FOLDER, 'secret'))) {
8554 // somehow the FTU started but the identity is already in place.
8655 // treat it as a failed import and start importing...
8756 console.log('resuming import')
8857 let previousData = getImportData()
@@ -95,50 +64,93 @@
9564 } else {
9665 state.latestSequence.set(previousData.latestSequence)
9766 state.currentSequence.set(previousData.currentSequence)
9867 isPresentingOptions.set(false)
99- observeSequence()
68+ observeSequence({ state, timeout: checkerTimeout })
10069 }
10170 }
10271
10372 var app = h('App', [
10473 h('Header', [
74+ h('img.logoName', { src: assetPath('logo_and_name.png') }),
10575 windowControls()
10676 ]),
107- when(isPresentingOptions, initialOptions, importProgress)
77+ when(isPresentingOptions, InitialOptions(), ImportProgress())
10878 ])
10979
11080 return app
81+
82+ function InitialOptions () {
83+ const { welcomeHeader, welcomeMessage, busyMessage, importAction, createAction } = strings.backup.ftu
84+
85+ return h('Page', [
86+ h('div.content', [
87+ h('section.welcome', [
88+ h('h1', welcomeHeader),
89+ h('div', welcomeMessage)
90+ ]),
91+ when(isBusy,
92+ h('p', busyMessage),
93+ h('section.actionButtons', [
94+ h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, importAction)),
95+ h('div.right', h('Button -strong', { 'ev-click': () => actionCreateNewOne() }, createAction))
96+ ])
97+ )
98+ ])
99+ ])
100+ }
101+
102+ function ImportProgress () {
103+ const { header, synchronizeMessage, details } = strings.backup.import
104+
105+ return h('Page', [
106+ h('div.content', [
107+ h('h1', header),
108+ h('p', synchronizeMessage),
109+ h('pre', computed(state, s => {
110+ return progress({
111+ width: 42,
112+ total: s.latestSequence,
113+ style: function (complete, incomplete) {
114+ // add an arrow at the head of the completed part
115+ return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})`
116+ }
117+ })(s.currentSequence)
118+ })),
119+ h('p', details)
120+ ])
121+ ])
122+ }
111123 }
112124 })
113125 }
114126
115-electron.ipcRenderer.on('import-started', function (ev, c) {
127+electron.ipcRenderer.on('import-resumed', function (ev, c) {
116128 console.log('background process is running, begin observing')
117129
118- observeSequence()
130+ observeSequence({ state, timeout: checkerTimeout })
119131 })
120132
121133 function actionCreateNewOne () {
122134 isBusy.set(true)
123135 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json')))
124- const manifestFile = path.join(configFolder, 'manifest.json')
125- if (!fs.existsSync(configFolder)) {
126- fs.mkdirSync(configFolder)
136+ const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json')
137+ if (!fs.existsSync(CONFIG_FOLDER)) {
138+ fs.mkdirSync(CONFIG_FOLDER)
127139 }
128140 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
129141
130142 electron.ipcRenderer.send('create-new-identity')
131143 }
132144
133145 function actionImportIdentity (strings) {
134- const peersFile = path.join(configFolder, 'gossip.json')
135- const secretFile = path.join(configFolder, 'secret')
146+ const peersFile = path.join(CONFIG_FOLDER, 'gossip.json')
147+ const secretFile = path.join(CONFIG_FOLDER, 'secret')
136148 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json')))
137- const manifestFile = path.join(configFolder, 'manifest.json')
149+ const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json')
138150
139151 // place the other files first
140- dialog.showOpenDialog(
152+ electron.remote.dialog.showOpenDialog(
141153 {
142154 title: strings.backup.import.dialog.title,
143155 butttonLabel: strings.backup.import.dialog.label,
144156 defaultPath: 'ticktack-identity.backup',
@@ -148,10 +160,10 @@
148160 if (typeof filenames !== 'undefined') {
149161 let filename = filenames[0]
150162 let data = JSON.parse(fs.readFileSync(filename))
151163 if (data.hasOwnProperty('secret') && data.hasOwnProperty('peers') && data.hasOwnProperty('latestSequence')) {
152- if (!fs.existsSync(configFolder)) {
153- fs.mkdirSync(configFolder)
164+ if (!fs.existsSync(CONFIG_FOLDER)) {
165+ fs.mkdirSync(CONFIG_FOLDER)
154166 }
155167
156168 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
157169 fs.writeFileSync(peersFile, JSON.stringify(data.peers), 'utf8')
@@ -175,124 +187,20 @@
175187 }
176188 )
177189 }
178190
179-function windowControls () {
180- if (process.platform === 'darwin') return
181-
182- const window = remote.getCurrentWindow()
183- const minimize = () => window.minimize()
184- const maximize = () => {
185- if (!window.isMaximized()) window.maximize()
186- else window.unmaximize()
187- }
188- const close = () => window.close()
189-
190- return h('div.window-controls', [
191- h('img.min', {
192- src: assetPath('minimize.png'),
193- 'ev-click': minimize
194- }),
195- h('img.max', {
196- src: assetPath('maximize.png'),
197- 'ev-click': maximize
198- }),
199- h('img.close', {
200- src: assetPath('close.png'),
201- 'ev-click': close
202- })
203- ])
204-}
205-
206191 function assetPath (name) {
207192 return path.join(__dirname, '../assets', name)
208193 }
209194
210195 function getImportData () {
211- var importFile = path.join(configFolder, 'importing.json')
212- if (fs.existsSync(importFile)) {
213- let data = JSON.parse(fs.readFileSync(importFile))
196+ if (fs.existsSync(IMPORT_FILE)) {
197+ let data = JSON.parse(fs.readFileSync(IMPORT_FILE))
214198 return data || false
215199 } else {
216200 return false
217201 }
218202 }
219203
220204 function setImportData (data) {
221- var importFile = path.join(configFolder, 'importing.json')
222- fs.writeFileSync(importFile, JSON.stringify(data))
205+ fs.writeFileSync(IMPORT_FILE, JSON.stringify(data))
223206 }
224-
225-function observeSequence () {
226- const pull = require('pull-stream')
227- const Client = require('ssb-client')
228- const config = require('../config').create().config.sync.load()
229-
230- Client(config.keys, config, (err, ssbServer) => {
231- if (err) return console.error('problem starting client', err)
232-
233- console.log('> sbot running!!!!')
234-
235- ssbServer.gossip.peers((err, peers) => {
236- if (err) return console.error(err)
237-
238- connectToPeers(peers)
239- checkPeers()
240- })
241-
242- // start listening to the my seq, and update the state
243- pull(
244- ssbServer.createUserStream({ live: true, id: ssbServer.id }),
245- pull.drain((msg) => {
246- let seq = get(msg, 'value.sequence', false)
247- if (seq) {
248- state.currentSequence.set(seq)
249- }
250- })
251- )
252-
253- function connectToPeers (peers) {
254- if (peers.length > 10) {
255- const lessPeers = peers.filter(p => !p.error)
256- if (lessPeers.length > 10) peers = lessPeers
257- }
258-
259- peers.forEach(({ host, port, key }) => {
260- if (host && port && key) {
261- ssbServer.gossip.connect({ host, port, key }, (err, v) => {
262- if (err) console.log('error connecting to ', host, err)
263- else console.log('connected to ', host)
264- })
265- }
266- })
267- }
268- function checkPeers () {
269- ssbServer.ebt.peerStatus(ssbServer.id, (err, data) => {
270- if (err) {
271- checkerTimeout = setTimeout(checkPeers, 5000)
272- return
273- }
274-
275- const latest = resolve(state.latestSequence)
276-
277- const remoteSeqs = Object.keys(data.peers)
278- .map(p => data.peers[p].seq) // get my seq reported by each peer
279- .filter(s => s >= latest) // only keep remote seq that confirm or update backup seq
280- .sort((a, b) => a > b ? -1 : 1) // order them
281-
282- console.log(remoteSeqs)
283-
284- const newLatest = remoteSeqs[0]
285- if (newLatest) {
286- state.latestSequence.set(newLatest)
287-
288- // if this value is confirmed remotely twice, assume safe
289- if (remoteSeqs.filter(s => s === newLatest).length >= 2) {
290- state.confirmedRemotely.set(true)
291- }
292- }
293-
294- checkerTimeout = setTimeout(checkPeers, 5000)
295- })
296- }
297- })
298-}
ftu/index.jsView
@@ -1,9 +1,8 @@
11 const combine = require('depject')
22 const entry = require('depject/entry')
33 const nest = require('depnest')
44
5-
65 // polyfills
76 require('setimmediate')
87
98 // add inspect right click menu
@@ -12,11 +11,11 @@
1211 // from more specialized to more general
1312 const sockets = combine(
1413 // need some modules first
1514 {
16- styles: require('../styles'),
1715 settings: require('patch-settings'),
1816 translations: require('../translations/sync'),
17+ styles: require('../styles')
1918 },
2019 {
2120 app: require('./app')
2221 }
ftu/app.mcssView
@@ -1,56 +1,0 @@
1-App {
2- overflow: hidden
3- position: fixed
4- top: 0
5- bottom: 0
6- right: 0
7- left: 0
8-}
9-
10-Page -ftu {
11- margin-top: 0
12- height: calc(100%)
13-
14- div.content {
15- section {
16- display: flex
17- align-content: center
18-
19- div {
20- padding: .5rem
21-
22- display: flex
23- align-items: center
24- }
25-
26- div.left {
27- flex-basis: 40%
28- justify-content: flex-end
29- }
30- div.right {
31- flex-basis: 60%
32- justify-content: flex-start
33- }
34- }
35- }
36-}
37-
38-Header {
39- div.window-controls {
40- position: fixed
41- right: 0
42- z-index: 100
43-
44- display: flex
45-
46- img {
47- padding: .5rem
48- cursor: pointer
49- :hover {
50- filter: drop-shadow(rgba(255, 255, 255, .5) 0 0 2px)
51- }
52- }
53- }
54-}
55-
56-
ftu/observeSequence.jsView
@@ -1,0 +1,80 @@
1+const get = require('lodash/get')
2+const pull = require('pull-stream')
3+const Client = require('ssb-client')
4+const { resolve } = require('mutant')
5+
6+function observeSequence ({ state, timeout }) {
7+ const config = require('../config').create().config.sync.load()
8+
9+ Client(config.keys, config, (err, ssbServer) => {
10+ if (err) return console.error('problem starting client', err)
11+
12+ console.log('> sbot running!!!!')
13+
14+ ssbServer.gossip.peers((err, peers) => {
15+ if (err) return console.error(err)
16+
17+ connectToPeers(peers)
18+ checkPeers()
19+ })
20+
21+ // start listening to the my seq, and update the state
22+ pull(
23+ ssbServer.createUserStream({ live: true, id: ssbServer.id }),
24+ pull.drain((msg) => {
25+ let seq = get(msg, 'value.sequence', false)
26+ if (seq) {
27+ state.currentSequence.set(seq)
28+ }
29+ })
30+ )
31+
32+ function connectToPeers (peers) {
33+ if (peers.length > 10) {
34+ const lessPeers = peers.filter(p => !p.error)
35+ if (lessPeers.length > 10) peers = lessPeers
36+ }
37+
38+ peers.forEach(({ host, port, key }) => {
39+ if (host && port && key) {
40+ ssbServer.gossip.connect({ host, port, key }, (err, v) => {
41+ if (err) console.log('error connecting to ', host, err)
42+ else console.log('connected to ', host)
43+ })
44+ }
45+ })
46+ }
47+
48+ function checkPeers () {
49+ ssbServer.ebt.peerStatus(ssbServer.id, (err, data) => {
50+ if (err) {
51+ timeout = setTimeout(checkPeers, 5000)
52+ return
53+ }
54+
55+ const latest = resolve(state.latestSequence)
56+
57+ const remoteSeqs = Object.keys(data.peers)
58+ .map(p => data.peers[p].seq) // get my seq reported by each peer
59+ .filter(s => s >= latest) // only keep remote seq that confirm or update backup seq
60+ .sort((a, b) => a > b ? -1 : 1) // order them
61+
62+ // console.log(remoteSeqs)
63+
64+ const newLatest = remoteSeqs[0]
65+ if (newLatest) {
66+ state.latestSequence.set(newLatest)
67+
68+ // if this value is confirmed remotely twice, assume safe
69+ if (remoteSeqs.filter(s => s === newLatest).length >= 2) {
70+ state.confirmedRemotely.set(true)
71+ }
72+ }
73+
74+ timeout = setTimeout(checkPeers, 5000)
75+ })
76+ }
77+ })
78+}
79+
80+module.exports = observeSequence
ftu/styles.jsView
@@ -1,0 +1,69 @@
1+const compile = require('micro-css')
2+
3+const styles = `
4+App {
5+ overflow: hidden
6+ position: fixed
7+ top: 0
8+ bottom: 0
9+ right: 0
10+ left: 0
11+}
12+
13+Page {
14+ padding-top: 6.5rem
15+ margin-top: 0
16+ height: calc(100%)
17+
18+ div.content {
19+ max-width: 35rem
20+ padding: 2rem
21+ section {
22+ display: flex
23+ align-items: center
24+ justify-content: center
25+
26+ div {
27+ padding: .5rem
28+
29+ display: flex
30+ align-items: center
31+ }
32+ }
33+
34+ section.welcome {
35+ flex-direction: column
36+ }
37+ }
38+}
39+
40+Header {
41+ height: 6.5rem
42+ background-color: #2f5ea1
43+
44+ display: initial
45+
46+ img.logoName {
47+ margin: 1rem
48+ }
49+
50+ div.window-controls {
51+ position: fixed
52+ top: 0
53+ right: 0
54+ z-index: 100
55+
56+ display: flex
57+
58+ img {
59+ padding: .5rem
60+ cursor: pointer
61+ :hover {
62+ filter: drop-shadow(rgba(255, 255, 255, .5) 0 0 2px)
63+ }
64+ }
65+ }
66+}
67+`
68+
69+module.exports = compile(styles)
index.jsView
@@ -8,10 +8,10 @@
88 const fs = require('fs')
99 const path = require('path')
1010 const os = require('os')
1111 const appName = process.env.SSB_APPNAME || 'ssb'
12-const configFolder = path.join(os.homedir(), `.${appName}`)
13-const isInstalled = fs.existsSync(Path.join(configFolder, 'secret'))
12+const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`)
13+const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json')
1414
1515 var windows = {}
1616 var quitting = false
1717
@@ -40,9 +40,9 @@
4040 }
4141
4242 Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
4343
44- if (!isInstalled) {
44+ if (!fs.existsSync(Path.join(CONFIG_FOLDER, 'secret'))) {
4545 console.log('Ticktack or SSB not installed, run FTU')
4646 openFTUWindow()
4747 } else {
4848 startBackgroundProcess()
@@ -54,9 +54,9 @@
5454 setImportRunningFlag(false)
5555 startBackgroundProcess()
5656 })
5757
58- // FTU told app to import some identity, need to start sbot and keep FTU running
58+ // FTU told app to import some identity, need to start sbot and keep FTU running
5959 electron.ipcMain.once('import-identity', function (ev) {
6060 console.log('import identity')
6161 setImportRunningFlag(true)
6262 startBackgroundProcess()
@@ -72,15 +72,15 @@
7272 // wait until server has started before opening main window
7373 electron.ipcMain.once('server-started', function (ev, config) {
7474 let keepFTURunning = getImportRunningFlag(false)
7575 if (!keepFTURunning) {
76- console.log("> Opening main window")
76+ console.log('> Opening main window')
7777 openMainWindow()
7878 } else {
7979 // sbot started but we're importing an older identity, need
8080 // to tell FTU to wait for sync.
8181 openFTUWindow()
82- windows.ftu.webContents.send('import-started')
82+ windows.ftu.webContents.send('import-resumed')
8383 }
8484 })
8585
8686 electron.app.on('before-quit', function () {
@@ -94,9 +94,9 @@
9494 }
9595 })
9696 })
9797
98-function startBackgroundProcess() {
98+function startBackgroundProcess () {
9999 if (!windows.background) {
100100 windows.background = openWindow(Path.join(__dirname, 'background-process.js'), {
101101 connect: false,
102102 center: true,
@@ -114,9 +114,9 @@
114114 })
115115 }
116116 }
117117
118-function openMainWindow() {
118+function openMainWindow () {
119119 if (!windows.main) {
120120 var windowState = WindowState({
121121 defaultWidth: 1024,
122122 defaultHeight: 768
@@ -153,9 +153,9 @@
153153 }
154154 }
155155 }
156156
157-function openFTUWindow() {
157+function openFTUWindow () {
158158 if (!windows.ftu) {
159159 var windowState = WindowState({
160160 defaultWidth: 1024,
161161 defaultHeight: 768
@@ -188,9 +188,9 @@
188188 })
189189 }
190190 }
191191
192-function openWindow(path, opts) {
192+function openWindow (path, opts) {
193193 var window = new electron.BrowserWindow(opts)
194194 window.webContents.on('dom-ready', function () {
195195 window.webContents.executeJavaScript(`
196196 var electron = require('electron')
@@ -217,25 +217,23 @@
217217 window.loadURL('file://' + Path.join(__dirname, 'assets', 'base.html'))
218218 return window
219219 }
220220
221-function getImportRunningFlag(defaultValue) {
222- var importFile = Path.join(configFolder, 'importing.json')
223- if (fs.existsSync(importFile)) {
224- let data = JSON.parse(fs.readFileSync(importFile))
221+function getImportRunningFlag (defaultValue) {
222+ if (fs.existsSync(IMPORT_FILE)) {
223+ let data = JSON.parse(fs.readFileSync(IMPORT_FILE))
225224 return data.importing || defaultValue
226225 } else {
227226 return defaultValue
228227 }
229228 }
230229
231-function setImportRunningFlag(v) {
230+function setImportRunningFlag (v) {
232231 let data = {}
233- var importFile = Path.join(configFolder, 'importing.json')
234- if (fs.existsSync(importFile)) {
235- data = JSON.parse(fs.readFileSync(importFile))
232+ if (fs.existsSync(IMPORT_FILE)) {
233+ data = JSON.parse(fs.readFileSync(IMPORT_FILE))
236234 }
237235
238236 data.importing = v
239237
240- fs.writeFileSync(importFile, JSON.stringify(data))
241-}
238+ fs.writeFileSync(IMPORT_FILE, JSON.stringify(data))
239+}
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 283352 bytes
New file size: 283162 bytes
package.jsonView
@@ -32,9 +32,8 @@
3232 "html-escape": "^2.0.0",
3333 "human-time": "0.0.1",
3434 "hyper-nav": "^2.0.0",
3535 "hypermore": "^2.0.0",
36- "insert-css": "^2.0.0",
3736 "libnested": "^1.2.1",
3837 "lodash": "^4.17.4",
3938 "markdown-summary": "^1.0.3",
4039 "medium-editor": "^5.23.3",
translations/en.jsView
@@ -212,50 +212,18 @@
212212 title: 'Export Identity'
213213 }
214214 },
215215 import: {
216- header: 'Import identity',
217216 importAction: 'Import Identity',
218- synchronizeMessage: 'Synchronizing feed: ',
217+ header: 'Importing identity',
218+ synchronizeMessage: 'Progress',
219219 dialog: {
220220 label: 'Import Identity',
221221 title: 'Import Identity'
222- }
222+ },
223+ details: 'Reconstructing your identity will take some time. Ticktack will launch once your identity is synchoronized, but it will take some time to gather your friends data, so some message and blogs will arrive later. You can safely close this window and Ticktack will resume sync next time you open it.'
223224 }
224225 },
225- backup: {
226- sectionName: 'Backup',
227- ftu: {
228- importAction: 'Import identity',
229- createAction: 'Create new identity',
230- busyMessage: 'Processing...',
231- welcomeHeader: 'Welcome to Ticktack',
232- welcomeMessage: 'Do you want to create a new identity or import one?'
233- },
234- export: {
235- header: 'Export identity',
236- message: [
237- 'Please backup your private key file very carefully.',
238- 'If your private key is hacked, all your private messages will be retrieved by third party, and your identity will be faked on the network'
239- ],
240- passwordPlaceholder: 'Please enter password to protect export file',
241- cancelAction: 'Cancel',
242- exportAction: 'Export Identity',
243- dialog: {
244- label: 'Export Identity',
245- title: 'Export Identity'
246- }
247- },
248- import: {
249- header: 'Import identity',
250- importAction: 'Import Identity',
251- synchronizeMessage: 'Synchronizing feed: ',
252- dialog: {
253- label: 'Import Identity',
254- title: 'Import Identity'
255- }
256- }
257- },
258226 languages: {
259227 en: 'English',
260228 zh: '中文'
261229 }
windowControls.jsView
@@ -1,0 +1,36 @@
1+const { h } = require('mutant')
2+const { remote } = require('electron')
3+const path = require('path')
4+
5+function windowControls () {
6+ if (process.platform === 'darwin') return
7+
8+ const window = remote.getCurrentWindow()
9+ const minimize = () => window.minimize()
10+ const maximize = () => {
11+ if (!window.isMaximized()) window.maximize()
12+ else window.unmaximize()
13+ }
14+ const close = () => window.close()
15+
16+ return h('div.window-controls', [
17+ h('img.min', {
18+ src: assetPath('minimize.png'),
19+ 'ev-click': minimize
20+ }),
21+ h('img.max', {
22+ src: assetPath('maximize.png'),
23+ 'ev-click': maximize
24+ }),
25+ h('img.close', {
26+ src: assetPath('close.png'),
27+ 'ev-click': close
28+ })
29+ ])
30+}
31+
32+module.exports = windowControls
33+
34+function assetPath (name) {
35+ return path.join(__dirname, 'assets', name)
36+}

Built with git-ssb-web