1
0
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:
SuenagaRyota
2017-08-14 11:45:37 +09:00
committed by GitHub
4 changed files with 187 additions and 195 deletions

View 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()

View 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)

View File

@@ -2,12 +2,9 @@ import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TopBar.styl' import styles from './TopBar.styl'
import _ from 'lodash' import _ from 'lodash'
import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal' import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import ee from 'browser/main/lib/eventEmitter' import ee from 'browser/main/lib/eventEmitter'
import ConfigManager from 'browser/main/lib/ConfigManager' import NewNoteButton from 'browser/main/NewNoteButton'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron') const { remote } = require('electron')
const { dialog } = remote const { dialog } = remote
@@ -24,81 +21,19 @@ class TopBar extends React.Component {
isSearching: false isSearching: false
} }
this.newNoteHandler = () => {
this.handleNewPostButtonClick()
}
this.focusSearchHandler = () => { this.focusSearchHandler = () => {
this.handleOnSearchFocus() this.handleOnSearchFocus()
} }
} }
componentDidMount () { componentDidMount () {
ee.on('top:new-note', this.newNoteHandler)
ee.on('top:focus-search', this.focusSearchHandler) ee.on('top:focus-search', this.focusSearchHandler)
} }
componentWillUnmount () { componentWillUnmount () {
ee.off('top:new-note', this.newNoteHandler)
ee.off('top:focus-search', this.focusSearchHandler) 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) { handleSearchChange (e) {
let { router } = this.context let { router } = this.context
router.push('/searched') 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) { handleSearchFocus (e) {
this.setState({ this.setState({
isSearching: true 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 () { handleOnSearchFocus () {
if (this.state.isSearching) { if (this.state.isSearching) {
this.refs.search.childNodes[0].blur() this.refs.search.childNodes[0].blur()
@@ -210,7 +75,7 @@ class TopBar extends React.Component {
} }
render () { render () {
let { config, style, data } = this.props let { config, style, data, location } = this.props
return ( return (
<div className='TopBar' <div className='TopBar'
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'} styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
@@ -242,14 +107,17 @@ class TopBar extends React.Component {
} }
</div> </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> </div>
{location.pathname === '/trashed' ? ''
: <NewNoteButton
{..._.pick(this.props, [
'dispatch',
'data',
'config',
'params',
'location'
])}
/>}
</div> </div>
) )
} }

View File

@@ -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
}