mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
Merge pull request #800 from asmsuechan/componentnize-NewNoteButton
Componentnize NewNoteButton
This commit is contained in:
68
browser/main/NewNoteButton/NewNoteButton.styl
Normal file
68
browser/main/NewNoteButton/NewNoteButton.styl
Normal file
@@ -0,0 +1,68 @@
|
||||
.root
|
||||
position relative
|
||||
background-color $ui-noteList-backgroundColor
|
||||
height $topBar-height - 1
|
||||
margin-left: auto;
|
||||
width: 64px;
|
||||
margin-right: -15px;
|
||||
|
||||
.root--expanded
|
||||
@extend .root
|
||||
|
||||
$control-height = 34px
|
||||
|
||||
.control
|
||||
position absolute
|
||||
top 13px
|
||||
left 8px
|
||||
right 8px
|
||||
height $control-height
|
||||
overflow hidden
|
||||
display flex
|
||||
|
||||
.control-newNoteButton
|
||||
display block
|
||||
width 32px
|
||||
height $control-height - 2
|
||||
navButtonColor()
|
||||
font-size 16px
|
||||
line-height 28px
|
||||
padding 0
|
||||
&:active
|
||||
border-color $ui-button--active-backgroundColor
|
||||
&:hover .control-newNoteButton-tooltip
|
||||
opacity 1
|
||||
|
||||
.control-newNoteButton-tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
pointer-events none
|
||||
top 50px
|
||||
left 433px
|
||||
z-index 200
|
||||
padding 5px
|
||||
line-height normal
|
||||
border-radius 2px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root, .root--expanded
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
|
||||
.control
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
.control-newNoteButton
|
||||
color $ui-inactive-text-color
|
||||
border-color $ui-dark-borderColor
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
&:hover
|
||||
transition 0.15s
|
||||
color $ui-dark-text-color
|
||||
&:active
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
border-color $ui-dark-button--active-backgroundColor
|
||||
|
||||
.control-newNoteButton-tooltip
|
||||
darkTooltip()
|
||||
107
browser/main/NewNoteButton/index.js
Normal file
107
browser/main/NewNoteButton/index.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NewNoteButton.styl'
|
||||
import _ from 'lodash'
|
||||
import modal from 'browser/main/lib/modal'
|
||||
import NewNoteModal from 'browser/main/modals/NewNoteModal'
|
||||
import { hashHistory } from 'react-router'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
|
||||
const OSX = window.process.platform === 'darwin'
|
||||
|
||||
class NewNoteButton extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
}
|
||||
|
||||
this.newNoteHandler = () => {
|
||||
this.handleNewNoteButtonClick()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
eventEmitter.on('top:new-note', this.newNoteHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
eventEmitter.off('top:new-note', this.newNoteHandler)
|
||||
}
|
||||
|
||||
handleNewNoteButtonClick (e) {
|
||||
const { config, location, dispatch } = this.props
|
||||
const { storage, folder } = this.resolveTargetFolder()
|
||||
|
||||
modal.open(NewNoteModal, {
|
||||
storage: storage.key,
|
||||
folder: folder.key,
|
||||
dispatch,
|
||||
location
|
||||
})
|
||||
}
|
||||
|
||||
resolveTargetFolder () {
|
||||
const { data, params } = this.props
|
||||
let storage = data.storageMap.get(params.storageKey)
|
||||
|
||||
// Find first storage
|
||||
if (storage == null) {
|
||||
for (let kv of data.storageMap) {
|
||||
storage = kv[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (storage == null) this.showMessageBox('No storage to create a note')
|
||||
let folder = storage.folders[0]
|
||||
folder = _.find(storage.folders, {key: params.folderKey})
|
||||
if (folder == null) this.showMessageBox('No folder to create a note')
|
||||
|
||||
return {
|
||||
storage,
|
||||
folder
|
||||
}
|
||||
}
|
||||
|
||||
showMessageBox (message) {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: message,
|
||||
buttons: ['OK']
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { config, style } = this.props
|
||||
return (
|
||||
<div className='NewNoteButton'
|
||||
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
|
||||
style={style}
|
||||
>
|
||||
<div styleName='control'>
|
||||
<button styleName='control-newNoteButton'
|
||||
onClick={(e) => this.handleNewNoteButtonClick(e)}>
|
||||
<i className='fa fa-pencil-square-o' />
|
||||
<span styleName='control-newNoteButton-tooltip'>
|
||||
Make a Note {OSX ? '⌘' : '^'} + n
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NewNoteButton.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
config: PropTypes.shape({
|
||||
isSideNavFolded: PropTypes.bool
|
||||
})
|
||||
}
|
||||
|
||||
export default CSSModules(NewNoteButton, styles)
|
||||
@@ -2,12 +2,9 @@ import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TopBar.styl'
|
||||
import _ from 'lodash'
|
||||
import modal from 'browser/main/lib/modal'
|
||||
import NewNoteModal from 'browser/main/modals/NewNoteModal'
|
||||
import { hashHistory } from 'react-router'
|
||||
import ee from 'browser/main/lib/eventEmitter'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import NewNoteButton from 'browser/main/NewNoteButton'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
@@ -24,81 +21,19 @@ class TopBar extends React.Component {
|
||||
isSearching: false
|
||||
}
|
||||
|
||||
this.newNoteHandler = () => {
|
||||
this.handleNewPostButtonClick()
|
||||
}
|
||||
|
||||
this.focusSearchHandler = () => {
|
||||
this.handleOnSearchFocus()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
ee.on('top:new-note', this.newNoteHandler)
|
||||
ee.on('top:focus-search', this.focusSearchHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
ee.off('top:new-note', this.newNoteHandler)
|
||||
ee.off('top:focus-search', this.focusSearchHandler)
|
||||
}
|
||||
|
||||
handleNewPostButtonClick (e) {
|
||||
let { config, location } = this.props
|
||||
|
||||
if (location.pathname === '/trashed') {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Cannot create new note',
|
||||
detail: 'You cannot create new note in trash box.',
|
||||
buttons: ['OK']
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch (config.ui.defaultNote) {
|
||||
case 'MARKDOWN_NOTE':
|
||||
this.createNote('MARKDOWN_NOTE')
|
||||
break
|
||||
case 'SNIPPET_NOTE':
|
||||
this.createNote('SNIPPET_NOTE')
|
||||
break
|
||||
case 'ALWAYS_ASK':
|
||||
default:
|
||||
let { dispatch, location } = this.props
|
||||
let { storage, folder } = this.resolveTargetFolder()
|
||||
|
||||
modal.open(NewNoteModal, {
|
||||
storage: storage.key,
|
||||
folder: folder.key,
|
||||
dispatch,
|
||||
location
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resolveTargetFolder () {
|
||||
let { data, params } = this.props
|
||||
let storage = data.storageMap.get(params.storageKey)
|
||||
|
||||
// Find first storage
|
||||
if (storage == null) {
|
||||
for (let kv of data.storageMap) {
|
||||
storage = kv[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (storage == null) window.alert('No storage to create a note')
|
||||
let folder = _.find(storage.folders, {key: params.folderKey})
|
||||
if (folder == null) folder = storage.folders[0]
|
||||
if (folder == null) window.alert('No folder to create a note')
|
||||
|
||||
return {
|
||||
storage,
|
||||
folder
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchChange (e) {
|
||||
let { router } = this.context
|
||||
router.push('/searched')
|
||||
@@ -107,22 +42,6 @@ class TopBar extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleOptionClick (uniqueKey) {
|
||||
return (e) => {
|
||||
this.setState({
|
||||
isSearching: false
|
||||
}, () => {
|
||||
let { location } = this.props
|
||||
hashHistory.push({
|
||||
pathname: location.pathname,
|
||||
query: {
|
||||
key: uniqueKey
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchFocus (e) {
|
||||
this.setState({
|
||||
isSearching: true
|
||||
@@ -147,60 +66,6 @@ class TopBar extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
createNote (noteType) {
|
||||
let { dispatch, location } = this.props
|
||||
if (noteType !== 'MARKDOWN_NOTE' && noteType !== 'SNIPPET_NOTE') throw new Error('Invalid note type.')
|
||||
|
||||
let { storage, folder } = this.resolveTargetFolder()
|
||||
|
||||
let newNote = noteType === 'MARKDOWN_NOTE'
|
||||
? {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
folder: folder.key,
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
: {
|
||||
type: 'SNIPPET_NOTE',
|
||||
folder: folder.key,
|
||||
title: '',
|
||||
description: '',
|
||||
snippets: [{
|
||||
name: '',
|
||||
mode: 'text',
|
||||
content: ''
|
||||
}]
|
||||
}
|
||||
|
||||
dataApi
|
||||
.createNote(storage.key, newNote)
|
||||
.then((note) => {
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
hashHistory.push({
|
||||
pathname: location.pathname,
|
||||
query: {key: note.storage + '-' + note.key}
|
||||
})
|
||||
ee.emit('detail:focus')
|
||||
})
|
||||
}
|
||||
|
||||
setDefaultNote (defaultNote) {
|
||||
let { config, dispatch } = this.props
|
||||
let ui = Object.assign(config.ui)
|
||||
ui.defaultNote = defaultNote
|
||||
ConfigManager.set({
|
||||
ui
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'SET_UI',
|
||||
config: ConfigManager.get()
|
||||
})
|
||||
}
|
||||
|
||||
handleOnSearchFocus () {
|
||||
if (this.state.isSearching) {
|
||||
this.refs.search.childNodes[0].blur()
|
||||
@@ -210,7 +75,7 @@ class TopBar extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { config, style, data } = this.props
|
||||
let { config, style, data, location } = this.props
|
||||
return (
|
||||
<div className='TopBar'
|
||||
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
|
||||
@@ -242,14 +107,17 @@ class TopBar extends React.Component {
|
||||
}
|
||||
|
||||
</div>
|
||||
<button styleName='control-newPostButton'
|
||||
onClick={(e) => this.handleNewPostButtonClick(e)}>
|
||||
<i className='fa fa-pencil-square-o' />
|
||||
<span styleName='control-newPostButton-tooltip'>
|
||||
Make a Note {OSX ? '⌘' : '^'} + n
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
{location.pathname === '/trashed' ? ''
|
||||
: <NewNoteButton
|
||||
{..._.pick(this.props, [
|
||||
'dispatch',
|
||||
'data',
|
||||
'config',
|
||||
'params',
|
||||
'location'
|
||||
])}
|
||||
/>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
export default class DeleteArticleModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.confirmHandler = (e) => this.handleYesButtonClick()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
ReactDOM.findDOMNode(this.refs.no).focus()
|
||||
ipc.on('modal-confirm', this.confirmHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
ipc.removeListener('modal-confirm', this.confirmHandler)
|
||||
}
|
||||
|
||||
handleNoButtonClick (e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleYesButtonClick (e) {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='DeleteArticleModal modal'>
|
||||
<div className='title'><i className='fa fa-fw fa-trash' /> Delete an article.</div>
|
||||
|
||||
<div className='message'>Do you really want to delete?</div>
|
||||
|
||||
<div className='control'>
|
||||
<button ref='no' onClick={(e) => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close' /> No</button>
|
||||
<button ref='yes' onClick={(e) => this.handleYesButtonClick(e)} className='danger'><i className='fa fa-fw fa-check' /> Yes</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DeleteArticleModal.propTypes = {
|
||||
action: PropTypes.object,
|
||||
articleKey: PropTypes.string,
|
||||
close: PropTypes.func
|
||||
}
|
||||
Reference in New Issue
Block a user