mirror of
https://github.com/BoostIo/Boostnote
synced 2026-01-07 14:09:21 +00:00
rewite whole code
add dataApi renew PreferencesModal
This commit is contained in:
@@ -128,7 +128,7 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
nextOption () {
|
||||
let { folders } = this.props
|
||||
let { storages } = this.props
|
||||
let { optionIndex } = this.state
|
||||
|
||||
optionIndex++
|
||||
@@ -184,25 +184,41 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, folders, value } = this.props
|
||||
let currentFolder = _.find(folders, {key: value})
|
||||
let optionList = folders.map((folder, index) => {
|
||||
return (
|
||||
<div styleName={index === this.state.optionIndex
|
||||
? 'search-optionList-item--active'
|
||||
: 'search-optionList-item'
|
||||
}
|
||||
key={folder.key}
|
||||
onClick={(e) => this.handleOptionClick(folder.key)(e)}
|
||||
>
|
||||
<i style={{color: folder.color}}
|
||||
className='fa fa-fw fa-cube'
|
||||
/>
|
||||
{folder.name}
|
||||
</div>
|
||||
)
|
||||
let { className, storages, value } = this.props
|
||||
let splitted = value.split('-')
|
||||
let storageKey = splitted.shift()
|
||||
let folderKey = splitted.shift()
|
||||
let options = []
|
||||
storages.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
options.push({
|
||||
storage: storage,
|
||||
folder: folder
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
let optionList = options
|
||||
.map((option, index) => {
|
||||
return (
|
||||
<div styleName={index === this.state.optionIndex
|
||||
? 'search-optionList-item--active'
|
||||
: 'search-optionList-item'
|
||||
}
|
||||
key={option.storage.key + '-' + option.folder.key}
|
||||
onClick={(e) => this.handleOptionClick(option.folder.key)(e)}
|
||||
>
|
||||
<span styleName='search-optionList-item-name'
|
||||
style={{borderColor: option.folder.color}}
|
||||
>
|
||||
{option.storage.name}/{option.folder.name}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={_.isString(className)
|
||||
? 'FolderSelect ' + className
|
||||
@@ -239,10 +255,11 @@ class FolderSelect extends React.Component {
|
||||
</div>
|
||||
: <div styleName='idle'>
|
||||
<div styleName='idle-label'>
|
||||
<i style={{color: currentFolder.color}}
|
||||
className='fa fa-fw fa-cube'
|
||||
/>
|
||||
{currentFolder.name}
|
||||
<span styleName='idle-label-name'
|
||||
style={{borderColor: currentOption.folder.color}}
|
||||
>
|
||||
{currentOption.storage.name}/{currentOption.folder.name}
|
||||
</span>
|
||||
</div>
|
||||
<i styleName='idle-caret' className='fa fa-fw fa-caret-down'/>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
border solid 1px transparent
|
||||
line-height 34px
|
||||
vertical-align middle
|
||||
border-radius 5px
|
||||
border-radius 2px
|
||||
transition 0.15s
|
||||
user-select none
|
||||
&:hover
|
||||
@@ -27,6 +27,10 @@
|
||||
right 20px
|
||||
overflow ellipsis
|
||||
|
||||
.idle-label-name
|
||||
border-left solid 4px transparent
|
||||
padding 2px 5px
|
||||
|
||||
.idle-caret
|
||||
absolute right top
|
||||
height 34px
|
||||
@@ -53,11 +57,11 @@
|
||||
border $ui-border
|
||||
z-index 200
|
||||
background-color white
|
||||
border-radius 5px
|
||||
border-radius 2px
|
||||
|
||||
.search-optionList-item
|
||||
height 34px
|
||||
width 120px
|
||||
width 250px
|
||||
box-sizing border-box
|
||||
padding 0 5px
|
||||
overflow ellipsis
|
||||
@@ -72,3 +76,6 @@
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
.search-optionList-item-name
|
||||
border-left solid 4px transparent
|
||||
padding 2px 5px
|
||||
|
||||
@@ -2,19 +2,26 @@ import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NoteDetail.styl'
|
||||
import MarkdownEditor from 'browser/components/MarkdownEditor'
|
||||
import queue from 'browser/main/lib/queue'
|
||||
import StarButton from './StarButton'
|
||||
import TagSelect from './TagSelect'
|
||||
import FolderSelect from './FolderSelect'
|
||||
import Repository from 'browser/lib/Repository'
|
||||
import Commander from 'browser/main/lib/Commander'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote } = electron
|
||||
const Menu = remote.Menu
|
||||
const MenuItem = remote.MenuItem
|
||||
|
||||
class NoteDetail extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
note: Object.assign({}, props.note),
|
||||
note: Object.assign({
|
||||
title: '',
|
||||
content: ''
|
||||
}, props.note),
|
||||
isDispatchQueued: false
|
||||
}
|
||||
this.dispatchTimer = null
|
||||
@@ -84,86 +91,74 @@ class NoteDetail extends React.Component {
|
||||
|
||||
note.content = this.refs.content.value
|
||||
note.tags = this.refs.tags.value
|
||||
note.folder = this.refs.folder.value
|
||||
note.title = this.findTitle(note.content)
|
||||
note.updatedAt = new Date()
|
||||
|
||||
this.setState({
|
||||
note,
|
||||
isDispatchQueued: true
|
||||
note
|
||||
}, () => {
|
||||
this.queueDispatch()
|
||||
this.save()
|
||||
})
|
||||
}
|
||||
|
||||
cancelDispatchQueue () {
|
||||
if (this.dispatchTimer != null) {
|
||||
window.clearTimeout(this.dispatchTimer)
|
||||
this.dispatchTimer = null
|
||||
}
|
||||
}
|
||||
save () {
|
||||
let { note, dispatch } = this.props
|
||||
|
||||
queueDispatch () {
|
||||
this.cancelDispatchQueue()
|
||||
|
||||
this.dispatchTimer = window.setTimeout(() => {
|
||||
this.dispatch()
|
||||
this.setState({
|
||||
isDispatchQueued: false
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
|
||||
dispatch () {
|
||||
let { note } = this.state
|
||||
note = Object.assign({}, note)
|
||||
let repoKey = note._repository.key
|
||||
note.title = this.findTitle(note.content)
|
||||
|
||||
let { dispatch } = this.props
|
||||
dispatch({
|
||||
type: 'SAVE_NOTE',
|
||||
repository: repoKey,
|
||||
note: note
|
||||
type: 'UPDATE_NOTE',
|
||||
note: this.state.note
|
||||
})
|
||||
queue.save(repoKey, note)
|
||||
|
||||
dataApi
|
||||
.updateNote(note.storage, note.folder, note.key, this.state.note)
|
||||
}
|
||||
|
||||
handleFolderChange (e) {
|
||||
|
||||
}
|
||||
|
||||
handleStarButtonClick (e) {
|
||||
let { note } = this.state
|
||||
let { dispatch } = this.props
|
||||
|
||||
let isStarred = note._repository.starred.some((starredKey) => starredKey === note.key)
|
||||
note.isStarred = !note.isStarred
|
||||
|
||||
if (isStarred) {
|
||||
Repository
|
||||
.find(note._repository.key)
|
||||
.then((repo) => {
|
||||
return repo.unstarNote(note.key)
|
||||
})
|
||||
this.setState({
|
||||
note
|
||||
}, () => {
|
||||
this.save()
|
||||
})
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'UNSTAR_NOTE',
|
||||
repository: note._repository.key,
|
||||
note: note.key
|
||||
})
|
||||
} else {
|
||||
Repository
|
||||
.find(note._repository.key)
|
||||
.then((repo) => {
|
||||
return repo.starNote(note.key)
|
||||
})
|
||||
exportAsFile () {
|
||||
|
||||
dispatch({
|
||||
type: 'STAR_NOTE',
|
||||
repository: note._repository.key,
|
||||
note: note.key
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleShareButtonClick (e) {
|
||||
let menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Export as a File',
|
||||
click: (e) => this.handlePreferencesButtonClick(e)
|
||||
}))
|
||||
menu.append(new MenuItem({
|
||||
label: 'Export to Web',
|
||||
disabled: true,
|
||||
click: (e) => this.handlePreferencesButtonClick(e)
|
||||
}))
|
||||
menu.popup(remote.getCurrentWindow())
|
||||
}
|
||||
|
||||
handleContextButtonClick (e) {
|
||||
let menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Delete',
|
||||
click: (e) => this.handlePreferencesButtonClick(e)
|
||||
}))
|
||||
menu.popup(remote.getCurrentWindow())
|
||||
}
|
||||
|
||||
render () {
|
||||
let { storages, config } = this.props
|
||||
let { note } = this.state
|
||||
let isStarred = note._repository.starred.some((starredKey) => starredKey === note.key)
|
||||
let folders = note._repository.folders
|
||||
|
||||
return (
|
||||
<div className='NoteDetail'
|
||||
@@ -174,15 +169,11 @@ class NoteDetail extends React.Component {
|
||||
<div styleName='info-left'>
|
||||
|
||||
<div styleName='info-left-top'>
|
||||
<StarButton styleName='info-left-top-starButton'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={isStarred}
|
||||
/>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.folder}
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
folders={folders}
|
||||
onChange={() => this.handleChange()}
|
||||
storages={storages}
|
||||
onChange={(e) => this.handleFolderChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-left-bottom'>
|
||||
@@ -195,13 +186,18 @@ class NoteDetail extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<button styleName='info-right-button'>
|
||||
<i className='fa fa-clipboard fa-fw'/>
|
||||
</button>
|
||||
<button styleName='info-right-button'>
|
||||
<StarButton styleName='info-right-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleShareButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-share-alt fa-fw'/>
|
||||
</button>
|
||||
<button styleName='info-right-button'>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleContextButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-ellipsis-v'/>
|
||||
</button>
|
||||
</div>
|
||||
@@ -210,6 +206,7 @@ class NoteDetail extends React.Component {
|
||||
<MarkdownEditor
|
||||
ref='content'
|
||||
styleName='body-noteEditor'
|
||||
config={config}
|
||||
value={this.state.note.content}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
|
||||
|
||||
@@ -14,22 +14,16 @@ $info-height = 75px
|
||||
|
||||
.info-left
|
||||
float left
|
||||
padding 0 5px
|
||||
|
||||
.info-left-top
|
||||
height 40px
|
||||
line-height 40px
|
||||
|
||||
.info-left-top-starButton
|
||||
display inline-block
|
||||
height 40px
|
||||
width 40px
|
||||
line-height 40px
|
||||
vertical-align top
|
||||
|
||||
.info-left-top-folderSelect
|
||||
display inline-block
|
||||
height 34px
|
||||
width 120px
|
||||
width 200px
|
||||
vertical-align middle
|
||||
|
||||
.info-left-bottom
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
.root
|
||||
position relative
|
||||
color $ui-inactive-text-color
|
||||
font-size 18px
|
||||
text-align center
|
||||
background-color transparent
|
||||
border none
|
||||
padding 0
|
||||
transition transform 0.15s
|
||||
&:focus
|
||||
color $ui-active-color
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
transform rotate(-72deg)
|
||||
|
||||
.root--active
|
||||
@extend .root
|
||||
color $ui-active-color
|
||||
transform rotate(-72deg)
|
||||
&:hover
|
||||
color $ui-active-color
|
||||
|
||||
@@ -35,7 +35,9 @@ class TagSelect extends React.Component {
|
||||
removeLastTag () {
|
||||
let { value } = this.props
|
||||
|
||||
value = value.slice()
|
||||
value = _.isArray(value)
|
||||
? value.slice()
|
||||
: []
|
||||
value.pop()
|
||||
value = _.uniq(value)
|
||||
|
||||
@@ -60,7 +62,9 @@ class TagSelect extends React.Component {
|
||||
return
|
||||
}
|
||||
|
||||
value = value.slice()
|
||||
value = _.isArray(value)
|
||||
? value.slice()
|
||||
: []
|
||||
value.push(newTag)
|
||||
value = _.uniq(value)
|
||||
|
||||
@@ -93,20 +97,22 @@ class TagSelect extends React.Component {
|
||||
render () {
|
||||
let { value, className } = this.props
|
||||
|
||||
let tagList = value.map((tag) => {
|
||||
return (
|
||||
<span styleName='tag'
|
||||
key={tag}
|
||||
>
|
||||
<button styleName='tag-removeButton'
|
||||
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
|
||||
let tagList = _.isArray(value)
|
||||
? value.map((tag) => {
|
||||
return (
|
||||
<span styleName='tag'
|
||||
key={tag}
|
||||
>
|
||||
<i className='fa fa-times fa-fw'/>
|
||||
</button>
|
||||
<span styleName='tag-label'>{tag}</span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
<button styleName='tag-removeButton'
|
||||
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
|
||||
>
|
||||
<i className='fa fa-times fa-fw'/>
|
||||
</button>
|
||||
<span styleName='tag-label'>{tag}</span>
|
||||
</span>
|
||||
)
|
||||
})
|
||||
: []
|
||||
|
||||
return (
|
||||
<div className={_.isString(className)
|
||||
@@ -134,7 +140,7 @@ class TagSelect extends React.Component {
|
||||
|
||||
TagSelect.propTypes = {
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
value: PropTypes.arrayOf(PropTypes.string),
|
||||
onChange: PropTypes.func
|
||||
|
||||
}
|
||||
|
||||
@@ -13,23 +13,25 @@ class Detail extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { repositories, location } = this.props
|
||||
let { storages, location, notes, config } = this.props
|
||||
let note = null
|
||||
if (location.query.key != null) {
|
||||
let splitted = location.query.key.split('-')
|
||||
let repoKey = splitted.shift()
|
||||
let storageKey = splitted.shift()
|
||||
let folderKey = splitted.shift()
|
||||
let noteKey = splitted.shift()
|
||||
let repo = _.find(repositories, {key: repoKey})
|
||||
if (_.isObject(repo) && _.isArray(repo.notes)) {
|
||||
note = _.find(repo.notes, {key: noteKey})
|
||||
}
|
||||
|
||||
note = _.find(notes, {
|
||||
storage: storageKey,
|
||||
folder: folderKey,
|
||||
key: noteKey
|
||||
})
|
||||
}
|
||||
|
||||
if (note == null) {
|
||||
return (
|
||||
<div className='Detail'
|
||||
<div styleName='root'
|
||||
style={this.props.style}
|
||||
styleName='root'
|
||||
tabIndex='0'
|
||||
>
|
||||
<div styleName='empty'>
|
||||
@@ -42,9 +44,10 @@ class Detail extends React.Component {
|
||||
return (
|
||||
<NoteDetail
|
||||
note={note}
|
||||
config={config}
|
||||
{..._.pick(this.props, [
|
||||
'dispatch',
|
||||
'repositories',
|
||||
'storages',
|
||||
'style',
|
||||
'ignorePreviewPointerEvents'
|
||||
])}
|
||||
@@ -55,7 +58,7 @@ class Detail extends React.Component {
|
||||
|
||||
Detail.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
repositories: PropTypes.array,
|
||||
storages: PropTypes.array,
|
||||
style: PropTypes.shape({
|
||||
left: PropTypes.number
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user