this.handleArticleListKeyDown(e)} className='ArticleList'>
{articleElements}
)
diff --git a/browser/main/HomePage/ArticleNavigator.js b/browser/main/HomePage/ArticleNavigator.js
index 1e77d7cb..cde86851 100644
--- a/browser/main/HomePage/ArticleNavigator.js
+++ b/browser/main/HomePage/ArticleNavigator.js
@@ -1,12 +1,14 @@
import React, { PropTypes } from 'react'
import { findWhere } from 'lodash'
import { setSearchFilter, switchFolder, saveArticle } from '../actions'
-import { openModal } from 'browser/lib/modal'
+import { openModal, isModalOpen } from 'browser/lib/modal'
import FolderMark from 'browser/components/FolderMark'
import Preferences from '../modal/Preferences'
import CreateNewFolder from '../modal/CreateNewFolder'
import keygen from 'browser/lib/keygen'
+const ipc = require('electron').ipcRenderer
+
const BRAND_COLOR = '#18AF90'
const preferenceTutorialElement = (
@@ -58,6 +60,28 @@ c-3.4-6.1-8.2-11.3-13.8-15.4C50.2,11.6,31,10.9,15.3,19C13.6,19.8,15.1,22.4,16.8,
)
export default class ArticleNavigator extends React.Component {
+ constructor (props) {
+ super(props)
+ this.newPostHandler = e => {
+ if (isModalOpen()) return true
+ this.handleNewPostButtonClick(e)
+ }
+ this.newFolderHandler = e => {
+ if (isModalOpen()) return true
+ this.handleNewFolderButton(e)
+ }
+ }
+
+ componentDidMount () {
+ ipc.on('nav-new-post', this.newPostHandler)
+ ipc.on('nav-new-folder', this.newFolderHandler)
+ }
+
+ componentWillUnmount () {
+ ipc.removeListener('nav-new-post', this.newPostHandler)
+ ipc.removeListener('nav-new-folder', this.newFolderHandler)
+ }
+
handlePreferencesButtonClick (e) {
openModal(Preferences)
}
@@ -136,7 +160,7 @@ export default class ArticleNavigator extends React.Component {
{status.isTutorialOpen ? newPostTutorialElement : null}
@@ -148,7 +172,7 @@ export default class ArticleNavigator extends React.Component {
Folders
{status.isTutorialOpen ? newFolderTutorialElement : null}
diff --git a/browser/main/HomePage/ArticleTopBar.js b/browser/main/HomePage/ArticleTopBar.js
index f0f2fb21..0b235123 100644
--- a/browser/main/HomePage/ArticleTopBar.js
+++ b/browser/main/HomePage/ArticleTopBar.js
@@ -3,11 +3,13 @@ import ReactDOM from 'react-dom'
import ExternalLink from 'browser/components/ExternalLink'
import { setSearchFilter, clearSearch, toggleOnlyUnsavedFilter, toggleTutorial, saveAllArticles, switchArticle } from '../actions'
import store from '../store'
+import { isModalOpen } from 'browser/lib/modal'
const electron = require('electron')
const remote = electron.remote
const Menu = remote.Menu
const MenuItem = remote.MenuItem
+const ipc = electron.ipcRenderer
const OSX = process.platform === 'darwin'
@@ -64,6 +66,15 @@ export default class ArticleTopBar extends React.Component {
constructor (props) {
super(props)
+ this.saveAllHandler = e => {
+ if (isModalOpen()) return true
+ this.handleSaveAllButtonClick(e)
+ }
+ this.focusSearchHandler = e => {
+ if (isModalOpen()) return true
+ this.focusInput(e)
+ }
+
this.state = {
isTooltipHidden: true,
isLinksDropdownOpen: false
@@ -87,11 +98,17 @@ export default class ArticleTopBar extends React.Component {
}
}
document.addEventListener('click', this.hideLinksDropdown)
+
+ ipc.on('top-save-all', this.saveAllHandler)
+ ipc.on('top-focus-search', this.focusSearchHandler)
}
componentWillUnmount () {
document.removeEventListener('click', this.hideLinksDropdown)
this.linksButton.removeEventListener('click', this.showLinksDropdown())
+
+ ipc.removeListener('top-save-all', this.saveAllHandler)
+ ipc.removeListener('top-focus-search', this.focusSearchHandler)
}
handleTooltipRequest (e) {
@@ -112,10 +129,10 @@ export default class ArticleTopBar extends React.Component {
dispatch(clearSearch())
return
}
- this.blurInput()
}
focusInput () {
+ console.log('focinp')
this.searchInput.focus()
}
@@ -145,6 +162,7 @@ export default class ArticleTopBar extends React.Component {
let { dispatch } = this.props
dispatch(saveAllArticles())
+ remote.getCurrentWebContents().send('list-focus')
}
handleSaveMenuButtonClick (e) {
diff --git a/browser/main/HomePage/index.js b/browser/main/HomePage/index.js
index f747c5ca..f2f5de5d 100644
--- a/browser/main/HomePage/index.js
+++ b/browser/main/HomePage/index.js
@@ -1,5 +1,6 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
+import ReactDOM from 'react-dom'
import { toggleTutorial } from '../actions'
import ArticleNavigator from './ArticleNavigator'
import ArticleTopBar from './ArticleTopBar'
@@ -26,15 +27,14 @@ class HomePage extends React.Component {
}
handleKeyDown (e) {
- let cmdOrCtrl = process.platform === 'darwin' ? e.metaKey : e.ctrlKey
-
if (isModalOpen()) {
if (e.keyCode === 27) closeModal()
return
}
let { status, dispatch } = this.props
- let { nav, top, list, detail } = this.refs
+ let { top, list } = this.refs
+ let listElement = ReactDOM.findDOMNode(list)
if (status.isTutorialOpen) {
dispatch(toggleTutorial())
@@ -42,28 +42,24 @@ class HomePage extends React.Component {
return
}
- // Search inputがfocusされていたら大体のキー入力は無視される。
- if (top.isInputFocused() && !(e.metaKey || e.ctrlKey)) {
- if (e.keyCode === 13 || e.keyCode === 27) top.escape()
+ if (e.keyCode === 13 && top.isInputFocused()) {
+ listElement.focus()
+ return
+ }
+ if (e.keyCode === 27 && top.isInputFocused()) {
+ if (status.search.length > 0) top.escape()
+ else listElement.focus()
return
}
- // `detail`の`openDeleteConfirmMenu`が`true`なら呼ばれない。
- if (e.keyCode === 27 || (e.keyCode === 70 && cmdOrCtrl)) {
- top.focusInput()
- }
-
- if (e.keyCode === 38) {
- list.selectPriorArticle()
- }
-
- if (e.keyCode === 40) {
- list.selectNextArticle()
- }
-
- if (e.keyCode === 78 && cmdOrCtrl) {
- nav.handleNewPostButtonClick()
- e.preventDefault()
+ // Search inputがfocusされていたら大体のキー入力は無視される。
+ if (e.keyCode === 27) {
+ if (document.activeElement !== listElement) {
+ listElement.focus()
+ } else {
+ top.focusInput()
+ }
+ return
}
}
diff --git a/browser/styles/main/ArticleDetail.styl b/browser/styles/main/ArticleDetail.styl
index ffe48f21..7c8626eb 100644
--- a/browser/styles/main/ArticleDetail.styl
+++ b/browser/styles/main/ArticleDetail.styl
@@ -1,5 +1,4 @@
noTagsColor = #999
-iptFocusBorderColor = #369DCD
infoButton()
display inline-block
@@ -7,14 +6,17 @@ infoButton()
cursor pointer
height 33px
width 33px
- border none
margin-right 5px
font-size 18px
color inactiveTextColor
background-color white
padding 0
+ border 1px solid white
+ &:focus
+ border-color focusBorderColor
&:hover
color inherit
+
.ArticleDetail
absolute right bottom
top 60px
@@ -55,7 +57,7 @@ infoButton()
&:hover
background-color white
&:focus
- border-color iptFocusBorderColor
+ border-color focusBorderColor
&>.tutorial
position fixed
z-index 35
@@ -124,11 +126,15 @@ infoButton()
border-top solid 1px darken(brandColor, 5%)
border-bottom solid 1px darken(brandColor, 5%)
border-left solid 1px darken(brandColor, 5%)
+ border-right solid 1px transparent
border-radius left 2px
background-color brandColor
&:hover
background-color lighten(brandColor, 10%)
border-color lighten(brandColor, 10%)
+ &:focus
+ background-color lighten(brandColor, 10%)
+ border-color focusBorderColor
.TagSelect-tags-item-label
background-color brandColor
float left
@@ -142,12 +148,13 @@ infoButton()
input.TagSelect-input
background-color transparent
border none
+ border-bottom 1px solid transparent
outline none
margin 0 2px
transition 0.15s
height 18px
&:focus
- font-size 13px
+ border-color focusBorderColor
.TagSelect-suggest
position fixed
width 150px
@@ -208,7 +215,7 @@ infoButton()
padding 0 5px
line-height 33px
&.edit
- border-color iptFocusBorderColor
+ border-color focusBorderColor
input
width 120px
line-height 31px
diff --git a/browser/styles/main/ArticleList.styl b/browser/styles/main/ArticleList.styl
index 820b5334..ee0da8c1 100644
--- a/browser/styles/main/ArticleList.styl
+++ b/browser/styles/main/ArticleList.styl
@@ -8,6 +8,8 @@ articleItemColor = #777
width 250px
border-top 1px solid borderColor
border-right 1px solid borderColor
+ &:focus
+ border-color focusBorderColor
overflow-y auto
noSelect()
&>div
diff --git a/browser/styles/main/ArticleTopBar.styl b/browser/styles/main/ArticleTopBar.styl
index e147c0ba..8f2daa76 100644
--- a/browser/styles/main/ArticleTopBar.styl
+++ b/browser/styles/main/ArticleTopBar.styl
@@ -137,6 +137,11 @@ infoBtnActiveBgColor = #3A3A3A
&:active
color inherit
background-color lighten(topBarBtnBgColor, 15%)
+ &:disabled
+ color inactiveTextColor
+ background transparent
+ &:focus
+ color focusBorderColor
&.ArticleTopBar-left-unsaved-save-button
position relative
.ArticleTopBar-left-unsaved-save-button-count
@@ -175,8 +180,10 @@ infoBtnActiveBgColor = #3A3A3A
background-color infoBtnBgColor
color bgColor
border-radius 11px
- border none
+ border 1px solid bgColor
transition 0.1s
+ &:focus
+ border-color focusBorderColor
.tooltip
tooltip()
margin-left -50px
@@ -192,6 +199,12 @@ infoBtnActiveBgColor = #3A3A3A
top 8px
right 15px
opacity 0.7
+ border-radius 23px
+ height 46px
+ width 46px
+ border 1px solid transparent
+ &:focus
+ border-color focusBorderColor
&:hover
opacity 1
.tooltip
diff --git a/browser/styles/main/modal/DeleteArticleModal.styl b/browser/styles/main/modal/DeleteArticleModal.styl
index b28d1b14..741224a8 100644
--- a/browser/styles/main/modal/DeleteArticleModal.styl
+++ b/browser/styles/main/modal/DeleteArticleModal.styl
@@ -1,5 +1,5 @@
.DeleteArticleModal.modal
- width 350px
+ width 350px !important
top 100px
user-select none
.title
@@ -21,9 +21,13 @@
margin-left 5px
&:hover
background-color darken(white, 10%)
+ &:focus
+ border-color focusBorderColor
&.danger
border-color #E9432A
background-color #E9432A
color white
&:hover
background-color lighten(#E9432A, 15%)
+ &:focus
+ background-color lighten(#E9432A, 15%)
diff --git a/browser/styles/vars.styl b/browser/styles/vars.styl
index c24dca04..66aac4c8 100644
--- a/browser/styles/vars.styl
+++ b/browser/styles/vars.styl
@@ -3,6 +3,8 @@ highlightenBorderColor = darken(borderColor, 20%)
invBorderColor = #404849
brandBorderColor = #3FB399
+focusBorderColor = #369DCD
+
buttonBorderColor = #4C4C4C
lightButtonColor = #898989
diff --git a/lib/finder-app.js b/lib/finder-app.js
index 4e0f82c1..5ae68823 100755
--- a/lib/finder-app.js
+++ b/lib/finder-app.js
@@ -9,7 +9,7 @@ app.on('ready', function () {
app.dock.hide()
}
- var template = require('./menu-template')
+ var template = require('./finder-menu')
var menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
diff --git a/lib/finder-menu.js b/lib/finder-menu.js
new file mode 100644
index 00000000..65a1d32c
--- /dev/null
+++ b/lib/finder-menu.js
@@ -0,0 +1,94 @@
+const electron = require('electron')
+const BrowserWindow = electron.BrowserWindow
+
+const OSX = process.platform === 'darwin'
+const WIN = process.platform === 'win32'
+
+var edit = {
+ label: 'Edit',
+ submenu: [
+ {
+ label: 'Undo',
+ accelerator: 'Command+Z',
+ selector: 'undo:'
+ },
+ {
+ label: 'Redo',
+ accelerator: 'Shift+Command+Z',
+ selector: 'redo:'
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Cut',
+ accelerator: 'Command+X',
+ selector: 'cut:'
+ },
+ {
+ label: 'Copy',
+ accelerator: 'Command+C',
+ selector: 'copy:'
+ },
+ {
+ label: 'Paste',
+ accelerator: 'Command+V',
+ selector: 'paste:'
+ },
+ {
+ label: 'Select All',
+ accelerator: 'Command+A',
+ selector: 'selectAll:'
+ }
+ ]
+}
+
+var view = {
+ label: 'View',
+ submenu: [
+ {
+ label: 'Focus Search',
+ accelerator: 'Control + Alt + F',
+ click: function () {
+ console.log('focus find')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Toggle Markdown Preview',
+ accelerator: OSX ? 'Command + P' : 'Ctrl + P',
+ click: function () {
+ console.log('markdown')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Reload',
+ accelerator: (function () {
+ if (process.platform === 'darwin') return 'Command+R'
+ else return 'Ctrl+R'
+ })(),
+ click: function () {
+ BrowserWindow.getFocusedWindow().reload()
+ }
+ },
+ {
+ label: 'Toggle Developer Tools',
+ accelerator: (function () {
+ if (process.platform === 'darwin') return 'Alt+Command+I'
+ else return 'Ctrl+Shift+I'
+ })(),
+ click: function (item, focusedWindow) {
+ if (focusedWindow) BrowserWindow.getFocusedWindow().toggleDevTools()
+ }
+ }
+ ]
+}
+
+module.exports = process.platform === 'darwin'
+ ? [edit, view]
+ : [view]
diff --git a/lib/main-app.js b/lib/main-app.js
index 54baf77a..f00d9c96 100644
--- a/lib/main-app.js
+++ b/lib/main-app.js
@@ -227,7 +227,7 @@ app.on('ready', function () {
if (finderProcess) finderProcess.kill()
})
- var template = require('./menu-template')
+ var template = require('./main-menu')
if (process.platform === 'win32') {
template.unshift({
label: 'Boostnote',
diff --git a/lib/menu-template.js b/lib/main-menu.js
similarity index 64%
rename from lib/menu-template.js
rename to lib/main-menu.js
index 5a327023..478580b8 100644
--- a/lib/menu-template.js
+++ b/lib/main-menu.js
@@ -1,6 +1,10 @@
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const shell = electron.shell
+const mainWindow = require('./main-window')
+
+const OSX = process.platform === 'darwin'
+const WIN = process.platform === 'win32'
var boost = {
label: 'Boostnote',
@@ -12,13 +16,6 @@ var boost = {
{
type: 'separator'
},
- {
- label: 'Services',
- submenu: []
- },
- {
- type: 'separator'
- },
{
label: 'Hide Boostnote',
accelerator: 'Command+H',
@@ -44,6 +41,53 @@ var boost = {
]
}
+var file = {
+ label: 'File',
+ submenu: [
+ {
+ label: 'New Post',
+ accelerator: OSX ? 'Command + N' : 'Control + N',
+ click: function () {
+ mainWindow.webContents.send('nav-new-post')
+ }
+ },
+ {
+ label: 'New Folder',
+ accelerator: OSX ? 'Command + Shift + N' : 'Control + Shift + N',
+ click: function () {
+ mainWindow.webContents.send('nav-new-folder')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Save Post',
+ accelerator: OSX ? 'Command + S' : 'Control + S',
+ click: function () {
+ mainWindow.webContents.send('detail-save')
+ }
+ },
+ {
+ label: 'Save All Posts',
+ accelerator: OSX ? 'Command + Shift + S' : 'Control + Shift + S',
+ click: function () {
+ mainWindow.webContents.send('top-save-all')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Delete Post',
+ accelerator: OSX ? 'Control + Backspace' : 'Control + Delete',
+ click: function () {
+ mainWindow.webContents.send('detail-delete')
+ }
+ }
+ ]
+}
+
var edit = {
label: 'Edit',
submenu: [
@@ -86,6 +130,26 @@ var edit = {
var view = {
label: 'View',
submenu: [
+ {
+ label: 'Focus Search',
+ accelerator: 'Control + Alt + F',
+ click: function () {
+ mainWindow.webContents.send('top-focus-search')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Toggle Markdown Preview',
+ accelerator: OSX ? 'Command + P' : 'Ctrl + P',
+ click: function () {
+ mainWindow.webContents.send('detail-toggle-preview')
+ }
+ },
+ {
+ type: 'separator'
+ },
{
label: 'Reload',
accelerator: (function () {
@@ -156,5 +220,5 @@ var help = {
}
module.exports = process.platform === 'darwin'
- ? [boost, edit, view, window, help]
- : [view, help]
+ ? [boost, file, edit, view, window, help]
+ : [file, view, help]
diff --git a/lib/main-window.js b/lib/main-window.js
index 5ab63a6c..0f04552f 100644
--- a/lib/main-window.js
+++ b/lib/main-window.js
@@ -21,6 +21,16 @@ mainWindow.webContents.on('new-window', function (e) {
e.preventDefault()
})
+mainWindow.webContents.sendInputEvent({
+ type: 'keyDown',
+ keyCode: '\u0008'
+})
+
+mainWindow.webContents.sendInputEvent({
+ type: 'keyUp',
+ keyCode: '\u0008'
+})
+
app.on('activate', function () {
if (mainWindow == null) return null
mainWindow.show()