1
0
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:
Dick Choi
2016-07-14 13:58:14 +09:00
parent 9ff70c4aef
commit 44f270f408
50 changed files with 2572 additions and 2496 deletions

View File

@@ -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'
/>&nbsp;
{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'
/>&nbsp;
{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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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