git ssb

16+

Dominic / patchbay



Commit 930e266beb35562806c1081330831a203ab75c66

Merge pull request #180 from ssbc/tabs

add reconbot shortcuts!
mix irving authored on 2/17/2018, 6:46:39 AM
GitHub committed on 2/17/2018, 6:46:39 AM
Parent: 4d3d556ad7d85bcca74606933b74757af9fc4454
Parent: a20d5059cc43f723aefd7fe6e3a79aa751ded3a9

Files changed

README.mdchanged
app/html/app.jschanged
app/html/tabs.jschanged
app/sync/initialise/electronState.jsadded
app/sync/initialise/errorCatcher.jsadded
app/sync/initialise/styles.jsadded
app/sync/initialise/userActionListeners.jsadded
index.jschanged
README.mdView
@@ -7,9 +7,8 @@
77 Patchbay is built using [patchcore](https://github.com/ssbc/patchcore) + [depject](https://github.com/dominictarr/depject). The goal is to make it easier to develop new features, and enable or disable features. This has so far been quite successful!
88
99 This makes in very easy to create say, a renderer for a new message type, or switch to a different method for choosing user names.
1010
11-
1211 ## Setup
1312
1413 Libsodium has some build dependencies. On ubuntu systems the following might help:
1514
@@ -99,8 +98,16 @@
9998 # from the patchbay repo folder
10099 npm run dev
101100 ```
102101
102 +## Keyboard shortcuts
103 +`CmdOrCtrl` is the `command` key on Apple keyboards or the `ctrl` key on PC keyboards.
104 +
105 +### Tabs and Window
106 +- `CmdOrCtrl+Shift+]` and `CmdOrCtrl+Shift+[` will cycle the tabs left and right
107 +- `CmdOrCtrl+w` will close the current tab
108 +- `CmdOrCtrl+Shift+w` will close the current window
109 +
103110 ## How to add a feature
104111
105112 To add a new message type, add add a js to `./modules/` that exports a function named `message_content` (it should return an HTML element). To add a new tab, export a function named `screen_view` (returns an html element).
106113
app/html/app.jsView
@@ -1,23 +1,18 @@
11 const nest = require('depnest')
22 const { h } = require('mutant')
3-const insertCss = require('insert-css')
4-const electron = require('electron')
53
64 exports.gives = nest('app.html.app')
75
86 exports.needs = nest({
9- 'app.async.catchLinkClick': 'first',
107 'app.html.tabs': 'first',
118 'app.page.errors': 'first',
12- 'app.sync.catchKeyboardShortcut': 'first',
139 'app.sync.goTo': 'first',
1410 'app.sync.initialise': 'first',
1511 'app.sync.window': 'reduce',
1612 'history.obs.location': 'first',
1713 'history.sync.push': 'first',
1814 'router.sync.router': 'first',
19- 'styles.css': 'reduce',
2015 'settings.sync.get': 'first',
2116 'settings.sync.set': 'first'
2217 })
2318
@@ -26,60 +21,18 @@
2621
2722 function app () {
2823 console.log('STARTING app')
2924
30- api.app.sync.initialise()
31-
3225 window = api.app.sync.window(window)
3326
34- const css = values(api.styles.css()).join('\n')
35- insertCss(css)
27 + const initialTabs = ['/public', '/inbox', '/notifications'] // NB router converts these to { page: '/public' }
28 + const App = h('App', api.app.html.tabs(initialTabs))
3629
37- const initialTabs = ['/public', '/inbox', '/notifications']
38- // NB router converts these to { page: '/public' }
39- const tabs = api.app.html.tabs(initialTabs)
30 + api.app.sync.initialise(App)
31 + // runs all the functions in app/sync/initialise
4032
41- const App = h('App', tabs)
42-
43- // Catch user actions
44- api.app.sync.catchKeyboardShortcut(window, { tabs })
45- api.app.async.catchLinkClick(App)
46-
4733 api.history.obs.location()(loc => api.app.sync.goTo(loc || {}))
4834
49- // Catch errors
50- var { container: errorPage, addError } = api.router.sync.router('/errors')
51- window.addEventListener('error', ev => {
52- if (!tabs.has('/errors')) tabs.add(errorPage, true)
53-
54- addError(ev.error || ev)
55- })
56-
57- /// /// TODO - extract this to keep patch-lite isolated from electron
58- const { getCurrentWebContents, getCurrentWindow } = electron.remote
59- window.addEventListener('resize', () => {
60- var wc = getCurrentWebContents()
61- wc && wc.getZoomFactor((zf) => {
62- api.settings.sync.set({
63- electron: {
64- zoomFactor: zf,
65- windowBounds: getCurrentWindow().getBounds()
66- }
67- })
68- })
69- })
70-
71- var zoomFactor = api.settings.sync.get('electron.zoomFactor')
72- if (zoomFactor) { getCurrentWebContents().setZoomFactor(zoomFactor) }
73-
74- var bounds = api.settings.sync.get('electron.windowBounds')
75- if (bounds) { getCurrentWindow().setBounds(bounds) }
76- /// ///
77-
7835 return App
7936 }
8037 }
8138
82-function values (object) {
83- const keys = Object.keys(object)
84- return keys.map(k => object[k])
85-}
app/html/tabs.jsView
@@ -51,9 +51,15 @@
5151 onSelect,
5252 onClose,
5353 append: h('div.navExtra', [ search, menu ])
5454 })
55- _tabs.currentPage = () => _tabs.get(_tabs.selected[0]).firstChild
55 + _tabs.currentPage = () => {
56 + const currentPage = _tabs.get(_tabs.selected[0])
57 + return currentPage && currentPage.firstChild
58 + }
59 + _tabs.nextTab = () => _tabs.currentPage() && _tabs.selectRelative(1)
60 + _tabs.previousTab = () => _tabs.currentPage() && _tabs.selectRelative(-1)
61 + _tabs.closeCurrentTab = () => _tabs.currentPage() && _tabs.remove(_tabs.selected[0])
5662
5763 // # TODO: review - this works but is strange
5864 initialTabs.forEach(p => api.app.sync.goTo(p))
5965 api.app.sync.goTo(initialTabs[0])
app/sync/initialise/electronState.jsView
@@ -1,0 +1,38 @@
1 +const nest = require('depnest')
2 +const electron = require('electron')
3 +
4 +exports.gives = nest('app.sync.initialise')
5 +
6 +exports.needs = nest({
7 + 'settings.sync.get': 'first',
8 + 'settings.sync.set': 'first',
9 +})
10 +
11 +exports.create = function (api) {
12 + return nest('app.sync.initialise', errorCatcher)
13 +
14 + function errorCatcher () {
15 + /// /// TODO - extract this to keep patch-lite isolated from electron
16 + const { getCurrentWebContents, getCurrentWindow } = electron.remote
17 + window.addEventListener('resize', () => {
18 + var wc = getCurrentWebContents()
19 + wc && wc.getZoomFactor((zf) => {
20 + api.settings.sync.set({
21 + electron: {
22 + zoomFactor: zf,
23 + windowBounds: getCurrentWindow().getBounds()
24 + }
25 + })
26 + })
27 + })
28 +
29 + var zoomFactor = api.settings.sync.get('electron.zoomFactor')
30 + if (zoomFactor) { getCurrentWebContents().setZoomFactor(zoomFactor) }
31 +
32 + var bounds = api.settings.sync.get('electron.windowBounds')
33 + if (bounds) { getCurrentWindow().setBounds(bounds) }
34 + /// ///
35 + }
36 +}
37 +
38 +
app/sync/initialise/errorCatcher.jsView
@@ -1,0 +1,24 @@
1 +const nest = require('depnest')
2 +
3 +exports.gives = nest('app.sync.initialise')
4 +
5 +exports.needs = nest({
6 + 'router.sync.router': 'first',
7 + 'app.html.tabs': 'first'
8 +})
9 +
10 +exports.create = function (api) {
11 + return nest('app.sync.initialise', errorCatcher)
12 +
13 + function errorCatcher () {
14 + const tabs = api.app.html.tabs()
15 +
16 + var { container: errorPage, addError } = api.router.sync.router('/errors')
17 + window.addEventListener('error', ev => {
18 + if (!tabs.has('/errors')) tabs.add(errorPage, true)
19 +
20 + addError(ev.error || ev)
21 + })
22 + }
23 +}
24 +
app/sync/initialise/styles.jsView
@@ -1,0 +1,24 @@
1 +const nest = require('depnest')
2 +const insertCss = require('insert-css')
3 +
4 +exports.gives = nest('app.sync.initialise')
5 +
6 +exports.needs = nest({
7 + 'styles.css': 'reduce',
8 +})
9 +
10 +
11 +exports.create = function (api) {
12 + return nest('app.sync.initialise', styles)
13 +
14 + function styles () {
15 + const css = values(api.styles.css()).join('\n')
16 + insertCss(css)
17 + }
18 +}
19 +
20 +function values (object) {
21 + const keys = Object.keys(object)
22 + return keys.map(k => object[k])
23 +}
24 +
app/sync/initialise/userActionListeners.jsView
@@ -1,0 +1,35 @@
1 +const nest = require('depnest')
2 +
3 +exports.gives = nest('app.sync.initialise')
4 +
5 +exports.needs = nest({
6 + 'app.async.catchLinkClick': 'first',
7 + 'app.sync.catchKeyboardShortcut': 'first',
8 + 'app.html.tabs': 'first',
9 +})
10 +
11 +
12 +exports.create = function (api) {
13 + return nest('app.sync.initialise', userActionListeners)
14 +
15 + function userActionListeners (App) {
16 + const tabs = api.app.html.tabs()
17 +
18 + api.app.sync.catchKeyboardShortcut(window)
19 + api.app.async.catchLinkClick(App)
20 +
21 + electron.ipcRenderer.on('nextTab', () => {
22 + tabs.nextTab()
23 + })
24 +
25 + electron.ipcRenderer.on('previousTab', () => {
26 + tabs.previousTab()
27 + })
28 +
29 + electron.ipcRenderer.on('closeTab', () => {
30 + tabs.closeCurrentTab()
31 + })
32 +
33 + }
34 +}
35 +
index.jsView
@@ -21,18 +21,38 @@
2121 { role: 'zoomout' },
2222 { type: 'separator' },
2323 { role: 'togglefullscreen' }
2424 ]
25- if (process.platform === 'darwin') {
26- var win = menu.find(x => x.label === 'Window')
27- win.submenu = [
28- { role: 'minimize' },
29- { role: 'zoom' },
30- { role: 'close', label: 'Close' },
31- { type: 'separator' },
32- { role: 'front' }
33- ]
34- }
25 + var win = menu.find(x => x.label === 'Window')
26 + win.submenu = [
27 + { role: 'minimize' },
28 + { role: 'zoom' },
29 + { role: 'close', label: 'Close Window', accelerator: 'CmdOrCtrl+Shift+W' },
30 + { type: 'separator' },
31 + {
32 + label: 'Close Tab',
33 + accelerator: 'CmdOrCtrl+W',
34 + click() {
35 + windows.main.webContents.send('closeTab')
36 + }
37 + },
38 + {
39 + label: 'Select Next Tab',
40 + accelerator: 'CmdOrCtrl+Shift+]',
41 + click() {
42 + windows.main.webContents.send('nextTab')
43 + }
44 + },
45 + {
46 + label: 'Select Previous Tab',
47 + accelerator: 'CmdOrCtrl+Shift+[',
48 + click() {
49 + windows.main.webContents.send('previousTab')
50 + }
51 + },
52 + { type: 'separator' },
53 + { role: 'front' }
54 + ]
3555
3656 Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
3757
3858 startBackgroundProcess()

Built with git-ssb-web