mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 09:46:22 +00:00
clean code
This commit is contained in:
@@ -22,7 +22,7 @@ class ModalBase extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className={'ModalBase' + (this.state.isHidden ? ' hide' : '')}>
|
<div className={'ModalBase' + (this.state.isHidden ? ' hide' : '')}>
|
||||||
<div onClick={e => this.close(e)} className='modalBack'/>
|
<div onClick={(e) => this.close(e)} className='modalBack'/>
|
||||||
{this.state.component == null ? null : (
|
{this.state.component == null ? null : (
|
||||||
<this.state.component {...this.state.componentProps} close={this.close}/>
|
<this.state.component {...this.state.componentProps} close={this.close}/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -2,10 +2,6 @@ import React, { PropTypes } from 'react'
|
|||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import {
|
|
||||||
switchFolder,
|
|
||||||
updateArticle
|
|
||||||
} from '../../actions'
|
|
||||||
import linkState from 'browser/lib/linkState'
|
import linkState from 'browser/lib/linkState'
|
||||||
import TagSelect from 'browser/components/TagSelect'
|
import TagSelect from 'browser/components/TagSelect'
|
||||||
import ModeSelect from 'browser/components/ModeSelect'
|
import ModeSelect from 'browser/components/ModeSelect'
|
||||||
@@ -67,25 +63,25 @@ export default class ArticleDetail extends React.Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.deleteHandler = e => {
|
this.deleteHandler = (e) => {
|
||||||
if (isModalOpen()) return true
|
if (isModalOpen()) return true
|
||||||
this.handleDeleteButtonClick()
|
this.handleDeleteButtonClick()
|
||||||
}
|
}
|
||||||
this.uncacheHandler = e => {
|
this.uncacheHandler = (e) => {
|
||||||
if (isModalOpen()) return true
|
if (isModalOpen()) return true
|
||||||
this.handleUncache()
|
this.handleUncache()
|
||||||
}
|
}
|
||||||
this.titleHandler = e => {
|
this.titleHandler = (e) => {
|
||||||
if (isModalOpen()) return true
|
if (isModalOpen()) return true
|
||||||
if (this.refs.title) {
|
if (this.refs.title) {
|
||||||
this.focusTitle()
|
this.focusTitle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.editHandler = e => {
|
this.editHandler = (e) => {
|
||||||
if (isModalOpen()) return true
|
if (isModalOpen()) return true
|
||||||
if (this.refs.editor) this.refs.editor.switchEditMode()
|
if (this.refs.editor) this.refs.editor.switchEditMode()
|
||||||
}
|
}
|
||||||
this.previewHandler = e => {
|
this.previewHandler = (e) => {
|
||||||
if (isModalOpen()) return true
|
if (isModalOpen()) return true
|
||||||
if (this.refs.editor) this.refs.editor.switchPreviewMode()
|
if (this.refs.editor) this.refs.editor.switchPreviewMode()
|
||||||
}
|
}
|
||||||
@@ -100,7 +96,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
||||||
this.shareDropdownInterceptor = e => {
|
this.shareDropdownInterceptor = (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +155,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
|
|
||||||
dispatch(updateArticle(article))
|
// dispatch(updateArticle(article))
|
||||||
|
|
||||||
let targetFolderKey = e.target.value
|
let targetFolderKey = e.target.value
|
||||||
if (status.targetFolders.length > 0) {
|
if (status.targetFolders.length > 0) {
|
||||||
let targetFolder = _.findWhere(folders, {key: targetFolderKey})
|
let targetFolder = _.findWhere(folders, {key: targetFolderKey})
|
||||||
dispatch(switchFolder(targetFolder.name))
|
// dispatch(switchFolder(targetFolder.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +170,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
title: e.target.value,
|
title: e.target.value,
|
||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
dispatch(updateArticle(article))
|
// dispatch(updateArticle(article))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTagsChange (newTag, tags) {
|
handleTagsChange (newTag, tags) {
|
||||||
@@ -184,7 +180,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
|
|
||||||
dispatch(updateArticle(article))
|
// dispatch(updateArticle(article))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModeChange (value) {
|
handleModeChange (value) {
|
||||||
@@ -194,7 +190,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
|
|
||||||
dispatch(updateArticle(article))
|
// dispatch(updateArticle(article))
|
||||||
this.switchEditMode()
|
this.switchEditMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +202,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
|
|
||||||
dispatch(updateArticle(article))
|
// dispatch(updateArticle(article))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +250,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
let { folders, status, tags, activeArticle, modified, user } = this.props
|
let { folders, status, tags, activeArticle, modified, user } = this.props
|
||||||
if (activeArticle == null) return this.renderEmpty()
|
if (activeArticle == null) return this.renderEmpty()
|
||||||
let folderOptions = folders.map(folder => {
|
let folderOptions = folders.map((folder) => {
|
||||||
return (
|
return (
|
||||||
<option key={folder.key} value={folder.key}>{folder.name}</option>
|
<option key={folder.key} value={folder.key}>{folder.name}</option>
|
||||||
)
|
)
|
||||||
@@ -269,7 +265,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<select
|
<select
|
||||||
className='ArticleDetail-info-folder'
|
className='ArticleDetail-info-folder'
|
||||||
value={activeArticle.FolderKey}
|
value={activeArticle.FolderKey}
|
||||||
onChange={e => this.handleFolderKeyChange(e)}
|
onChange={(e) => this.handleFolderKeyChange(e)}
|
||||||
>
|
>
|
||||||
{folderOptions}
|
{folderOptions}
|
||||||
</select>
|
</select>
|
||||||
@@ -282,25 +278,14 @@ export default class ArticleDetail extends React.Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='ArticleDetail-info-control'>
|
<div className='ArticleDetail-info-control'>
|
||||||
{/*<div className={'ArticleDetail-info-control-save' + (!isUnsaved ? ' hide' : '')}>
|
|
||||||
<button
|
|
||||||
onClick={e => this.handleSaveButtonClick(e)}
|
|
||||||
className='ArticleDetail-info-control-save-button'
|
|
||||||
disabled={!isUnsaved}
|
|
||||||
>
|
|
||||||
<i className='fa fa-fw fa-save'/> Save
|
|
||||||
<span className='tooltip' children={`Save Post (${OSX ? '⌘' : '^'} + S)`}/>
|
|
||||||
</button>
|
|
||||||
</div>*/}
|
|
||||||
|
|
||||||
<ShareButton
|
<ShareButton
|
||||||
article={activeArticle}
|
article={activeArticle}
|
||||||
user={user}
|
user={user}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button className='ArticleDetail-info-control-delete-button' onClick={e => this.handleOthersButtonClick(e)}>
|
<button className='ArticleDetail-info-control-delete-button' onClick={(e) => this.handleOthersButtonClick(e)}>
|
||||||
<i className='fa fa-fw fa-trash'/>
|
<i className='fa fa-fw fa-trash'/>
|
||||||
<span className='tooltip' children={`Delete Post (^ + Del)`}/>
|
<span className='tooltip'>Delete Post (^ + Del)</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -319,11 +304,11 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='ArticleDetail-panel-header'>
|
<div className='ArticleDetail-panel-header'>
|
||||||
<div className='ArticleDetail-panel-header-title'>
|
<div className='ArticleDetail-panel-header-title'>
|
||||||
<input
|
<input
|
||||||
onKeyDown={e => this.handleTitleKeyDown(e)}
|
onKeyDown={(e) => this.handleTitleKeyDown(e)}
|
||||||
placeholder='(Untitled)'
|
placeholder='(Untitled)'
|
||||||
ref='title'
|
ref='title'
|
||||||
value={activeArticle.title}
|
value={activeArticle.title}
|
||||||
onChange={e => this.handleTitleChange(e)}
|
onChange={(e) => this.handleTitleChange(e)}
|
||||||
style={{
|
style={{
|
||||||
fontFamily: this.state.fontFamily
|
fontFamily: this.state.fontFamily
|
||||||
}}
|
}}
|
||||||
@@ -331,8 +316,8 @@ export default class ArticleDetail extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<ModeSelect
|
<ModeSelect
|
||||||
ref='mode'
|
ref='mode'
|
||||||
onChange={e => this.handleModeChange(e)}
|
onChange={(e) => this.handleModeChange(e)}
|
||||||
onKeyDown={e => this.handleModeSelectKeyDown(e)}
|
onKeyDown={(e) => this.handleModeSelectKeyDown(e)}
|
||||||
value={activeArticle.mode}
|
value={activeArticle.mode}
|
||||||
className='ArticleDetail-panel-header-mode'
|
className='ArticleDetail-panel-header-mode'
|
||||||
/>
|
/>
|
||||||
@@ -341,7 +326,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<ArticleEditor
|
<ArticleEditor
|
||||||
ref='editor'
|
ref='editor'
|
||||||
article={activeArticle}
|
article={activeArticle}
|
||||||
onChange={content => this.handleContentChange(content)}
|
onChange={(content) => this.handleContentChange(content)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -351,11 +336,6 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
ArticleDetail.propTypes = {
|
ArticleDetail.propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
status: PropTypes.shape(),
|
repositories: PropTypes.array
|
||||||
tags: PropTypes.array,
|
|
||||||
user: PropTypes.shape(),
|
|
||||||
folders: PropTypes.array,
|
|
||||||
modified: PropTypes.array,
|
|
||||||
activeArticle: PropTypes.shape()
|
|
||||||
}
|
}
|
||||||
ArticleDetail.prototype.linkState = linkState
|
ArticleDetail.prototype.linkState = linkState
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
|
|||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import ModeIcon from 'browser/components/ModeIcon'
|
import ModeIcon from 'browser/components/ModeIcon'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { switchArticle } from '../actions'
|
|
||||||
import FolderMark from 'browser/components/FolderMark'
|
import FolderMark from 'browser/components/FolderMark'
|
||||||
import TagLink from './TagLink'
|
import TagLink from './TagLink'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
@@ -15,7 +14,7 @@ export default class ArticleList extends React.Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.focusHandler = e => this.focus()
|
this.focusHandler = (e) => this.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -30,8 +29,8 @@ export default class ArticleList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate () {
|
componentDidUpdate () {
|
||||||
let { articles, activeArticle } = this.props
|
return false
|
||||||
var index = articles.indexOf(activeArticle)
|
var index = articles.indexOf(null)
|
||||||
var el = ReactDOM.findDOMNode(this)
|
var el = ReactDOM.findDOMNode(this)
|
||||||
var li = el.querySelectorAll('.ArticleList>div')[index]
|
var li = el.querySelectorAll('.ArticleList>div')[index]
|
||||||
|
|
||||||
@@ -130,16 +129,12 @@ export default class ArticleList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { articles, modified, activeArticle, folders } = this.props
|
let articles = []
|
||||||
|
let folders = []
|
||||||
let articleElements = articles.map(article => {
|
let articleElements = articles.map((article) => {
|
||||||
let modifiedArticle = _.findWhere(modified, {key: article.key})
|
|
||||||
let originalArticle = article
|
let originalArticle = article
|
||||||
if (modifiedArticle) {
|
|
||||||
article = Object.assign({}, article)
|
|
||||||
}
|
|
||||||
let tagElements = Array.isArray(article.tags) && article.tags.length > 0
|
let tagElements = Array.isArray(article.tags) && article.tags.length > 0
|
||||||
? article.tags.slice().map(tag => {
|
? article.tags.slice().map((tag) => {
|
||||||
return (<TagLink key={tag} tag={tag}/>)
|
return (<TagLink key={tag} tag={tag}/>)
|
||||||
})
|
})
|
||||||
: (<span>Not tagged yet</span>)
|
: (<span>Not tagged yet</span>)
|
||||||
@@ -153,27 +148,21 @@ export default class ArticleList extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={'article-' + article.key}>
|
<div key={'article-' + article.key}>
|
||||||
<div onClick={e => this.handleArticleClick(article)(e)} className={'ArticleList-item' + (activeArticle.key === article.key ? ' active' : '')}>
|
<div onClick={(e) => this.handleArticleClick(article)(e)} className={'ArticleList-item' + (article.key === 'ACTIVE_POST_KEY' ? ' active' : '')}>
|
||||||
<div className='ArticleList-item-top'>
|
<div className='ArticleList-item-top'>
|
||||||
{folder != null
|
{folder != null
|
||||||
? folderChanged
|
? folderChanged
|
||||||
? <span className='folderName'>
|
? <span className='folderName'>
|
||||||
<FolderMark color={originalFolder.color}/>{originalFolder.name}
|
<FolderMark color={originalFolder.color}/>{originalFolder.name}
|
||||||
->
|
->
|
||||||
<FolderMark color={folder.color}/>{folder.name}
|
<FolderMark color={folder.color}/>{folder.name}
|
||||||
</span>
|
</span>
|
||||||
: <span className='folderName'>
|
: <span className='folderName'>
|
||||||
<FolderMark color={folder.color}/>{folder.name}
|
<FolderMark color={folder.color}/>{folder.name}
|
||||||
</span>
|
</span>
|
||||||
: <span><FolderMark color={-1}/>Unknown</span>
|
: <span><FolderMark color={-1}/>Unknown</span>
|
||||||
}
|
}
|
||||||
<span className='updatedAt'
|
<span className='updatedAt'>{moment(article.updatedAt).fromNow()}</span>
|
||||||
children={
|
|
||||||
modifiedArticle != null
|
|
||||||
? <span><span className='unsaved-mark'>●</span> Unsaved</span>
|
|
||||||
: moment(article.updatedAt).fromNow()
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='ArticleList-item-middle'>
|
<div className='ArticleList-item-middle'>
|
||||||
<ModeIcon className='mode' mode={article.mode}/> <div className='title' children={title}/>
|
<ModeIcon className='mode' mode={article.mode}/> <div className='title' children={title}/>
|
||||||
@@ -191,7 +180,7 @@ export default class ArticleList extends React.Component {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex='3' onKeyDown={e => this.handleArticleListKeyDown(e)} className='ArticleList'>
|
<div tabIndex='3' onKeyDown={(e) => this.handleArticleListKeyDown(e)} className='ArticleList'>
|
||||||
{articleElements}
|
{articleElements}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -200,8 +189,5 @@ export default class ArticleList extends React.Component {
|
|||||||
|
|
||||||
ArticleList.propTypes = {
|
ArticleList.propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
folders: PropTypes.array,
|
repositories: PropTypes.array
|
||||||
articles: PropTypes.array,
|
|
||||||
modified: PropTypes.array,
|
|
||||||
activeArticle: PropTypes.shape()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import ExternalLink from 'browser/components/ExternalLink'
|
import ExternalLink from 'browser/components/ExternalLink'
|
||||||
import { setSearchFilter, clearSearch, toggleTutorial, saveArticle, switchFolder } from '../actions'
|
|
||||||
import { isModalOpen } from 'browser/lib/modal'
|
import { isModalOpen } from 'browser/lib/modal'
|
||||||
import keygen from 'browser/lib/keygen'
|
|
||||||
import activityRecord from 'browser/lib/activityRecord'
|
import activityRecord from 'browser/lib/activityRecord'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const remote = electron.remote
|
|
||||||
const ipc = electron.ipcRenderer
|
const ipc = electron.ipcRenderer
|
||||||
|
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
@@ -83,7 +80,7 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
this.setState({isLinksDropdownOpen: true})
|
this.setState({isLinksDropdownOpen: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.linksButton.addEventListener('click', this.showLinksDropdown)
|
// this.linksButton.addEventListener('click', this.showLinksDropdown)
|
||||||
this.hideLinksDropdown = e => {
|
this.hideLinksDropdown = e => {
|
||||||
if (this.state.isLinksDropdownOpen) {
|
if (this.state.isLinksDropdownOpen) {
|
||||||
this.setState({isLinksDropdownOpen: false})
|
this.setState({isLinksDropdownOpen: false})
|
||||||
@@ -118,11 +115,6 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
escape () {
|
escape () {
|
||||||
let { status, dispatch } = this.props
|
|
||||||
if (status.search.length > 0) {
|
|
||||||
dispatch(clearSearch())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
focusInput () {
|
focusInput () {
|
||||||
@@ -136,7 +128,7 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
handleSearchChange (e) {
|
handleSearchChange (e) {
|
||||||
let { dispatch } = this.props
|
let { dispatch } = this.props
|
||||||
|
|
||||||
dispatch(setSearchFilter(e.target.value))
|
// dispatch(setSearchFilter(e.target.value))
|
||||||
this.handleTooltipRequest()
|
this.handleTooltipRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,35 +138,13 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNewPostButtonClick (e) {
|
handleNewPostButtonClick (e) {
|
||||||
let { dispatch, folders, status } = this.props
|
|
||||||
let { targetFolders } = status
|
|
||||||
|
|
||||||
let isFolderFilterApplied = targetFolders.length > 0
|
|
||||||
let FolderKey = isFolderFilterApplied
|
|
||||||
? targetFolders[0].key
|
|
||||||
: folders[0].key
|
|
||||||
|
|
||||||
let newArticle = {
|
|
||||||
key: keygen(),
|
|
||||||
title: '',
|
|
||||||
content: '',
|
|
||||||
mode: 'markdown',
|
|
||||||
tags: [],
|
|
||||||
FolderKey: FolderKey,
|
|
||||||
craetedAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(saveArticle(newArticle.key, newArticle, true))
|
|
||||||
if (isFolderFilterApplied) dispatch(switchFolder(targetFolders[0].name))
|
|
||||||
remote.getCurrentWebContents().send('detail-title')
|
|
||||||
activityRecord.emit('ARTICLE_CREATE')
|
activityRecord.emit('ARTICLE_CREATE')
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTutorialButtonClick (e) {
|
handleTutorialButtonClick (e) {
|
||||||
let { dispatch } = this.props
|
let { dispatch } = this.props
|
||||||
|
|
||||||
dispatch(toggleTutorial())
|
// dispatch(toggleTutorial())
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@@ -186,16 +156,16 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
<i className='fa fa-search fa-fw' />
|
<i className='fa fa-search fa-fw' />
|
||||||
<input
|
<input
|
||||||
ref='searchInput'
|
ref='searchInput'
|
||||||
onFocus={e => this.handleSearchChange(e)}
|
onFocus={(e) => this.handleSearchChange(e)}
|
||||||
onBlur={e => this.handleSearchChange(e)}
|
onBlur={(e) => this.handleSearchChange(e)}
|
||||||
value={this.props.status.search}
|
value={'this.props.status.search'}
|
||||||
onChange={e => this.handleSearchChange(e)}
|
onChange={(e) => this.handleSearchChange(e)}
|
||||||
placeholder='Search'
|
placeholder='Search'
|
||||||
type='text'
|
type='text'
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
this.props.status.search != null && this.props.status.search.length > 0
|
'sadf' > 0
|
||||||
? <button onClick={e => this.handleSearchClearButton(e)} className='ArticleTopBar-left-search-clear-button'><i className='fa fa-times'/></button>
|
? <button onClick={(e) => this.handleSearchClearButton(e)} className='ArticleTopBar-left-search-clear-button'><i className='fa fa-times'/></button>
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
||||||
@@ -207,19 +177,16 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{status.isTutorialOpen ? searchTutorialElement : null}
|
|
||||||
|
|
||||||
<div className={'ArticleTopBar-left-control'}>
|
<div className={'ArticleTopBar-left-control'}>
|
||||||
<button className='ArticleTopBar-left-control-new-post-button' onClick={e => this.handleNewPostButtonClick(e)}>
|
<button className='ArticleTopBar-left-control-new-post-button' onClick={(e) => this.handleNewPostButtonClick(e)}>
|
||||||
<i className='fa fa-plus'/>
|
<i className='fa fa-plus'/>
|
||||||
<span className='tooltip'>New Post ({OSX ? '⌘' : '^'} + n)</span>
|
<span className='tooltip'>New Post ({OSX ? '⌘' : '^'} + n)</span>
|
||||||
</button>
|
</button>
|
||||||
{status.isTutorialOpen ? newPostTutorialElement : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='ArticleTopBar-right'>
|
<div className='ArticleTopBar-right'>
|
||||||
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
|
<button onClick={(e) => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
|
||||||
</button>
|
</button>
|
||||||
<a ref='links' className='ArticleTopBar-right-links-button' href>
|
<a ref='links' className='ArticleTopBar-right-links-button' href>
|
||||||
<img src='../resources/app.png' width='44' height='44'/>
|
<img src='../resources/app.png' width='44' height='44'/>
|
||||||
@@ -240,9 +207,9 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{status.isTutorialOpen ? (
|
{false ? (
|
||||||
<div className='tutorial'>
|
<div className='tutorial'>
|
||||||
<div onClick={e => this.handleTutorialButtonClick(e)} className='clickJammer'/>
|
<div onClick={(e) => this.handleTutorialButtonClick(e)} className='clickJammer'/>
|
||||||
<svg width='500' height='250' className='finder'>
|
<svg width='500' height='250' className='finder'>
|
||||||
<text x='100' y='25' fontSize='32' fill={BRAND_COLOR}>Also, you can open Finder!!</text>
|
<text x='100' y='25' fontSize='32' fill={BRAND_COLOR}>Also, you can open Finder!!</text>
|
||||||
<text x='150' y='55' fontSize='18' fill={BRAND_COLOR} children={'with pressing ' + (OSX ? '`⌘ + Alt + s`' : '`Win + Alt + s`')}/>
|
<text x='150' y='55' fontSize='18' fill={BRAND_COLOR} children={'with pressing ' + (OSX ? '`⌘ + Alt + s`' : '`Win + Alt + s`')}/>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import store from '../store'
|
|
||||||
import { setTagFilter } from '../actions'
|
|
||||||
|
|
||||||
export default class TagLink extends React.Component {
|
export default class TagLink extends React.Component {
|
||||||
handleClick (e) {
|
handleClick (e) {
|
||||||
store.dispatch(setTagFilter(this.props.tag))
|
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<a onClick={e => this.handleClick(e)}>{this.props.tag}</a>
|
<a onClick={(e) => this.handleClick(e)}>{this.props.tag}</a>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import React, { Component, PropTypes } from 'react'
|
|
||||||
import { Link } from 'react-router'
|
|
||||||
import ProfileImage from 'browser/components/ProfileImage'
|
|
||||||
|
|
||||||
export default class UserNavigator extends Component {
|
|
||||||
renderUserList () {
|
|
||||||
if (this.props.users == null) return null
|
|
||||||
|
|
||||||
var users = this.props.users.map((user, index) => (
|
|
||||||
<li key={'user-' + user.id}>
|
|
||||||
<Link to={'/users/' + user.id} activeClassName='active'>
|
|
||||||
<ProfileImage email={user.email} size='44'/>
|
|
||||||
<div className='userTooltip'>{user.name}</div>
|
|
||||||
{index < 9 ? <div className='keyLabel'>{'⌘' + (index + 1)}</div> : null}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ul className='userList'>
|
|
||||||
{users}
|
|
||||||
</ul>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div className='UserNavigator'>
|
|
||||||
{this.renderUserList()}
|
|
||||||
<button className='createTeamBtn'>
|
|
||||||
+
|
|
||||||
<div className='tooltip'>Create a new team</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserNavigator.propTypes = {
|
|
||||||
users: PropTypes.array
|
|
||||||
}
|
|
||||||
@@ -19,26 +19,10 @@ export default class MainContainer extends React.Component {
|
|||||||
ipc.send('update-app', 'Deal with it.')
|
ipc.send('update-app', 'Deal with it.')
|
||||||
}
|
}
|
||||||
|
|
||||||
handleWheel (e) {
|
|
||||||
if (e.ctrlKey && global.process.platform !== 'darwin') {
|
|
||||||
if (window.document.body.style.zoom == null) {
|
|
||||||
window.document.body.style.zoom = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
let zoom = Number(window.document.body.style.zoom)
|
|
||||||
if (e.deltaY > 0 && zoom < 4) {
|
|
||||||
document.body.style.zoom = zoom + 0.05
|
|
||||||
} else if (e.deltaY < 0 && zoom > 0.5) {
|
|
||||||
document.body.style.zoom = zoom - 0.05
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='Main'
|
className='Main'
|
||||||
onWheel={(e) => this.handleWheel(e)}
|
|
||||||
>
|
>
|
||||||
{this.state.updateAvailable ? (
|
{this.state.updateAvailable ? (
|
||||||
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
|
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import MainPage from './MainPage'
|
import Main from './Main'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
@@ -76,7 +76,7 @@ let el = document.getElementById('content')
|
|||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
<div>
|
<div>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<MainPage/>
|
<Main/>
|
||||||
</Provider>
|
</Provider>
|
||||||
</div>
|
</div>
|
||||||
), el, function () {
|
), el, function () {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import linkState from 'browser/lib/linkState'
|
import linkState from 'browser/lib/linkState'
|
||||||
import { createFolder } from '../actions'
|
|
||||||
import store from '../store'
|
import store from '../store'
|
||||||
import FolderMark from 'browser/components/FolderMark'
|
import FolderMark from 'browser/components/FolderMark'
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
color
|
color
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
store.dispatch(createFolder(input))
|
// store.dispatch(createFolder(input))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.setState({alert: {
|
this.setState({alert: {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -47,7 +46,7 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleColorClick (colorIndex) {
|
handleColorClick (colorIndex) {
|
||||||
return e => {
|
return (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
color: colorIndex
|
color: colorIndex
|
||||||
})
|
})
|
||||||
@@ -63,20 +62,20 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
render () {
|
render () {
|
||||||
let alert = this.state.alert
|
let alert = this.state.alert
|
||||||
let alertElement = alert != null ? (
|
let alertElement = alert != null ? (
|
||||||
<p className={`alert ${alert.type}`}>
|
<p className={`alert ${alert.type}`}>
|
||||||
{alert.message}
|
{alert.message}
|
||||||
</p>
|
</p>
|
||||||
) : null
|
) : null
|
||||||
let colorIndexes = []
|
let colorIndexes = []
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
colorIndexes.push(i)
|
colorIndexes.push(i)
|
||||||
}
|
}
|
||||||
let colorElements = colorIndexes.map(index => {
|
let colorElements = colorIndexes.map((index) => {
|
||||||
let className = 'option'
|
let className = 'option'
|
||||||
if (index === this.state.color) className += ' active'
|
if (index === this.state.color) className += ' active'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={className} key={index} onClick={e => this.handleColorClick(index)(e)}>
|
<span className={className} key={index} onClick={(e) => this.handleColorClick(index)(e)}>
|
||||||
<FolderMark color={index}/>
|
<FolderMark color={index}/>
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@@ -84,17 +83,17 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='CreateNewFolder modal'>
|
<div className='CreateNewFolder modal'>
|
||||||
<button onClick={e => this.handleCloseButton(e)} className='closeBtn'><i className='fa fa-fw fa-times'/></button>
|
<button onClick={(e) => this.handleCloseButton(e)} className='closeBtn'><i className='fa fa-fw fa-times'/></button>
|
||||||
|
|
||||||
<div className='title'>Create new folder</div>
|
<div className='title'>Create new folder</div>
|
||||||
|
|
||||||
<input ref='folderName' onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
<input ref='folderName' onKeyDown={(e) => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
||||||
<div className='colorSelect'>
|
<div className='colorSelect'>
|
||||||
{colorElements}
|
{colorElements}
|
||||||
</div>
|
</div>
|
||||||
{alertElement}
|
{alertElement}
|
||||||
|
|
||||||
<button onClick={e => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
<button onClick={(e) => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import store from '../store'
|
import store from '../store'
|
||||||
import { destroyArticle } from '../actions'
|
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const ipc = electron.ipcRenderer
|
const ipc = electron.ipcRenderer
|
||||||
@@ -10,7 +9,7 @@ export default class DeleteArticleModal extends React.Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.confirmHandler = e => this.handleYesButtonClick()
|
this.confirmHandler = (e) => this.handleYesButtonClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -27,7 +26,7 @@ export default class DeleteArticleModal extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleYesButtonClick (e) {
|
handleYesButtonClick (e) {
|
||||||
store.dispatch(destroyArticle(this.props.articleKey))
|
// store.dispatch(destroyArticle(this.props.articleKey))
|
||||||
this.props.close()
|
this.props.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +38,8 @@ export default class DeleteArticleModal extends React.Component {
|
|||||||
<div className='message'>Do you really want to delete?</div>
|
<div className='message'>Do you really want to delete?</div>
|
||||||
|
|
||||||
<div className='control'>
|
<div className='control'>
|
||||||
<button ref='no' onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
|
<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>
|
<button ref='yes' onClick={(e) => this.handleYesButtonClick(e)} className='danger'><i className='fa fa-fw fa-check'/> Yes</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import linkState from 'browser/lib/linkState'
|
import linkState from 'browser/lib/linkState'
|
||||||
import { updateUser } from '../../actions'
|
|
||||||
import fetchConfig from 'browser/lib/fetchConfig'
|
import fetchConfig from 'browser/lib/fetchConfig'
|
||||||
import hljsTheme from 'browser/lib/hljsThemes'
|
import hljsTheme from 'browser/lib/hljsThemes'
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ export default class AppSettingTab extends React.Component {
|
|||||||
message: 'Successfully done!'
|
message: 'Successfully done!'
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
this.handleSettingError = err => {
|
this.handleSettingError = (err) => {
|
||||||
this.setState({keymapAlert: {
|
this.setState({keymapAlert: {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: err.message != null ? err.message : 'Error occurs!'
|
message: err.message != null ? err.message : 'Error occurs!'
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
|
|||||||
import linkState from 'browser/lib/linkState'
|
import linkState from 'browser/lib/linkState'
|
||||||
import FolderMark from 'browser/components/FolderMark'
|
import FolderMark from 'browser/components/FolderMark'
|
||||||
import store from '../../store'
|
import store from '../../store'
|
||||||
import { updateFolder, destroyFolder, replaceFolder } from '../../actions'
|
|
||||||
|
|
||||||
const IDLE = 'IDLE'
|
const IDLE = 'IDLE'
|
||||||
const EDIT = 'EDIT'
|
const EDIT = 'EDIT'
|
||||||
@@ -20,14 +19,14 @@ export default class FolderRow extends React.Component {
|
|||||||
handleUpClick (e) {
|
handleUpClick (e) {
|
||||||
let { index } = this.props
|
let { index } = this.props
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
store.dispatch(replaceFolder(index, index - 1))
|
// store.dispatch(replaceFolder(index, index - 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDownClick (e) {
|
handleDownClick (e) {
|
||||||
let { index, count } = this.props
|
let { index, count } = this.props
|
||||||
if (index < count - 1) {
|
if (index < count - 1) {
|
||||||
store.dispatch(replaceFolder(index, index + 1))
|
// store.dispatch(replaceFolder(index, index + 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ export default class FolderRow extends React.Component {
|
|||||||
folder = Object.assign({}, folder, input)
|
folder = Object.assign({}, folder, input)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
store.dispatch(updateFolder(folder))
|
// store.dispatch(updateFolder(folder))
|
||||||
this.setState({
|
this.setState({
|
||||||
mode: IDLE
|
mode: IDLE
|
||||||
})
|
})
|
||||||
@@ -98,7 +97,7 @@ export default class FolderRow extends React.Component {
|
|||||||
|
|
||||||
handleDeleteConfirmButtonClick (e) {
|
handleDeleteConfirmButtonClick (e) {
|
||||||
let { folder } = this.props
|
let { folder } = this.props
|
||||||
store.dispatch(destroyFolder(folder.key))
|
// store.dispatch(destroyFolder(folder.key))
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
@@ -111,7 +110,7 @@ export default class FolderRow extends React.Component {
|
|||||||
colorIndexes.push(i)
|
colorIndexes.push(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
let colorOptions = colorIndexes.map(index => {
|
let colorOptions = colorIndexes.map((index) => {
|
||||||
let className = this.state.color === index
|
let className = this.state.color === index
|
||||||
? 'active'
|
? 'active'
|
||||||
: null
|
: null
|
||||||
@@ -129,12 +128,10 @@ export default class FolderRow extends React.Component {
|
|||||||
<FolderMark color={this.state.color}/>
|
<FolderMark color={this.state.color}/>
|
||||||
</button>
|
</button>
|
||||||
{this.state.isColorEditing
|
{this.state.isColorEditing
|
||||||
? (
|
? <div className='options'>
|
||||||
<div className='options'>
|
<div className='label'>Color select</div>
|
||||||
<div className='label'>Color select</div>
|
{colorOptions}
|
||||||
{colorOptions}
|
</div>
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import FolderRow from './FolderRow'
|
import FolderRow from './FolderRow'
|
||||||
import linkState from 'browser/lib/linkState'
|
import linkState from 'browser/lib/linkState'
|
||||||
import { createFolder } from '../../actions'
|
|
||||||
|
|
||||||
export default class FolderSettingTab extends React.Component {
|
export default class FolderSettingTab extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -23,9 +22,9 @@ export default class FolderSettingTab extends React.Component {
|
|||||||
let { dispatch } = this.props
|
let { dispatch } = this.props
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dispatch(createFolder({
|
// dispatch(createFolder({
|
||||||
name: this.state.name
|
// name: this.state.name
|
||||||
}))
|
// }))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.setState({alert: {
|
this.setState({alert: {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
|||||||
@@ -1,362 +0,0 @@
|
|||||||
import { combineReducers } from 'redux'
|
|
||||||
import _ from 'lodash'
|
|
||||||
import {
|
|
||||||
// Status action type
|
|
||||||
SWITCH_FOLDER,
|
|
||||||
SWITCH_ARTICLE,
|
|
||||||
SET_SEARCH_FILTER,
|
|
||||||
SET_TAG_FILTER,
|
|
||||||
CLEAR_SEARCH,
|
|
||||||
TOGGLE_TUTORIAL,
|
|
||||||
|
|
||||||
// user
|
|
||||||
USER_UPDATE,
|
|
||||||
|
|
||||||
// Article action type
|
|
||||||
ARTICLE_UPDATE,
|
|
||||||
ARTICLE_DESTROY,
|
|
||||||
ARTICLE_CACHE,
|
|
||||||
ARTICLE_UNCACHE,
|
|
||||||
ARTICLE_UNCACHE_ALL,
|
|
||||||
ARTICLE_SAVE,
|
|
||||||
ARTICLE_SAVE_ALL,
|
|
||||||
|
|
||||||
// Folder action type
|
|
||||||
FOLDER_CREATE,
|
|
||||||
FOLDER_UPDATE,
|
|
||||||
FOLDER_DESTROY,
|
|
||||||
FOLDER_REPLACE
|
|
||||||
} from './actions'
|
|
||||||
import dataStore from 'browser/lib/dataStore'
|
|
||||||
import keygen from 'browser/lib/keygen'
|
|
||||||
import activityRecord from 'browser/lib/activityRecord'
|
|
||||||
|
|
||||||
const initialStatus = {
|
|
||||||
search: '',
|
|
||||||
isTutorialOpen: false
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
articles: [],
|
|
||||||
folders: []
|
|
||||||
}
|
|
||||||
let initialArticles = {
|
|
||||||
data: data && data.articles ? data.articles : [],
|
|
||||||
modified: []
|
|
||||||
}
|
|
||||||
let initialFolders = data && data.folders ? data.folders : []
|
|
||||||
let initialUser = {}
|
|
||||||
|
|
||||||
function user (state = initialUser, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case USER_UPDATE:
|
|
||||||
let updated = Object.assign(state, action.data)
|
|
||||||
dataStore.saveUser(null, updated)
|
|
||||||
return updated
|
|
||||||
default:
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function folders (state = initialFolders, action) {
|
|
||||||
state = state.slice()
|
|
||||||
switch (action.type) {
|
|
||||||
case FOLDER_CREATE:
|
|
||||||
{
|
|
||||||
let newFolder = action.data.folder
|
|
||||||
if (!_.isString(newFolder.name)) throw new Error('Folder name must be a string')
|
|
||||||
newFolder.name = newFolder.name.trim().replace(/\s/g, '_')
|
|
||||||
|
|
||||||
Object.assign(newFolder, {
|
|
||||||
key: keygen(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
})
|
|
||||||
|
|
||||||
if (newFolder.name == null || newFolder.name.length === 0) throw new Error('Folder name is required')
|
|
||||||
if (newFolder.name.match(/\//)) throw new Error('`/` is not available for folder name')
|
|
||||||
|
|
||||||
let conflictFolder = _.find(state, (folder) => folder.name.toLowerCase() === newFolder.name.toLowerCase())
|
|
||||||
if (conflictFolder != null) throw new Error(`${conflictFolder.name} already exists!`)
|
|
||||||
state.push(newFolder)
|
|
||||||
|
|
||||||
dataStore.setFolders(state)
|
|
||||||
activityRecord.emit('FOLDER_CREATE')
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case FOLDER_UPDATE:
|
|
||||||
{
|
|
||||||
let folder = action.data.folder
|
|
||||||
let targetFolder = _.findWhere(state, {key: folder.key})
|
|
||||||
|
|
||||||
if (!_.isString(folder.name)) throw new Error('Folder name must be a string')
|
|
||||||
folder.name = folder.name.trim().replace(/\s/g, '_')
|
|
||||||
if (folder.name.length === 0) throw new Error('Folder name is required')
|
|
||||||
if (folder.name.match(/\//)) throw new Error('`/` is not available for folder name')
|
|
||||||
|
|
||||||
// Folder existence check
|
|
||||||
if (targetFolder == null) throw new Error('Folder doesnt exist')
|
|
||||||
// Name conflict check
|
|
||||||
if (targetFolder.name !== folder.name) {
|
|
||||||
let conflictFolder = _.find(state, (_folder) => {
|
|
||||||
return folder.name.toLowerCase() === _folder.name.toLowerCase() && folder.key !== _folder.key
|
|
||||||
})
|
|
||||||
if (conflictFolder != null) throw new Error('Name conflicted')
|
|
||||||
}
|
|
||||||
Object.assign(targetFolder, folder, {
|
|
||||||
updatedAt: new Date()
|
|
||||||
})
|
|
||||||
|
|
||||||
dataStore.setFolders(state)
|
|
||||||
activityRecord.emit('FOLDER_UPDATE')
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case FOLDER_DESTROY:
|
|
||||||
{
|
|
||||||
if (state.length < 2) throw new Error('Folder must exist more than one')
|
|
||||||
|
|
||||||
let targetKey = action.data.key
|
|
||||||
let targetIndex = _.findIndex(state, (folder) => folder.key === targetKey)
|
|
||||||
if (targetIndex >= 0) {
|
|
||||||
state.splice(targetIndex, 1)
|
|
||||||
}
|
|
||||||
dataStore.setFolders(state)
|
|
||||||
activityRecord.emit('FOLDER_DESTROY')
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case FOLDER_REPLACE:
|
|
||||||
{
|
|
||||||
let { a, b } = action.data
|
|
||||||
let folderA = state[a]
|
|
||||||
let folderB = state[b]
|
|
||||||
state.splice(a, 1, folderB)
|
|
||||||
state.splice(b, 1, folderA)
|
|
||||||
}
|
|
||||||
dataStore.setFolders(state)
|
|
||||||
return state
|
|
||||||
default:
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function compareArticle (original, modified) {
|
|
||||||
var keys = _.keys(_.pick(modified, ['mode', 'title', 'tags', 'content', 'FolderKey']))
|
|
||||||
|
|
||||||
return keys.reduce((sum, key) => {
|
|
||||||
if ((key === 'tags' && !_.isEqual(original[key], modified[key])) || (key !== 'tags' && original[key] !== modified[key])) {
|
|
||||||
if (sum == null) {
|
|
||||||
sum = {
|
|
||||||
key: original.key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sum[key] = modified[key]
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
function articles (state = initialArticles, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case ARTICLE_CACHE:
|
|
||||||
{
|
|
||||||
let modified = action.data.article
|
|
||||||
let targetKey = action.data.key
|
|
||||||
let originalIndex = _.findIndex(state.data, (_article) => targetKey === _article.key)
|
|
||||||
if (originalIndex === -1) return state
|
|
||||||
let modifiedIndex = _.findIndex(state.modified, (_article) => targetKey === _article.key)
|
|
||||||
|
|
||||||
modified = compareArticle(state.data[originalIndex], modified)
|
|
||||||
if (modified == null) {
|
|
||||||
if (modifiedIndex !== -1) state.modified.splice(modifiedIndex, 1)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modifiedIndex === -1) state.modified.push(modified)
|
|
||||||
else Object.assign(state.modified[modifiedIndex], modified)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case ARTICLE_UNCACHE:
|
|
||||||
{
|
|
||||||
let targetKey = action.data.key
|
|
||||||
let modifiedIndex = _.findIndex(state.modified, _article => targetKey === _article.key)
|
|
||||||
if (modifiedIndex >= 0) state.modified.splice(modifiedIndex, 1)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case ARTICLE_UNCACHE_ALL:
|
|
||||||
state.modified = []
|
|
||||||
return state
|
|
||||||
case ARTICLE_SAVE:
|
|
||||||
{
|
|
||||||
let targetKey = action.data.key
|
|
||||||
let override = action.data.article
|
|
||||||
let modifiedIndex = _.findIndex(state.modified, _article => targetKey === _article.key)
|
|
||||||
let modified = modifiedIndex !== -1 ? state.modified.splice(modifiedIndex, 1)[0] : null
|
|
||||||
|
|
||||||
let targetIndex = _.findIndex(state.data, _article => targetKey === _article.key)
|
|
||||||
// Make a new if target article is not found.
|
|
||||||
if (targetIndex === -1) {
|
|
||||||
state.data.push(Object.assign({
|
|
||||||
title: '',
|
|
||||||
content: '',
|
|
||||||
mode: 'markdown',
|
|
||||||
tags: [],
|
|
||||||
craetedAt: new Date()
|
|
||||||
}, modified, override, {key: targetKey, updatedAt: new Date()}))
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(state.data[targetIndex], modified, override, {key: targetKey, updatedAt: new Date()})
|
|
||||||
|
|
||||||
dataStore.setArticles(state.data)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case ARTICLE_SAVE_ALL:
|
|
||||||
if (state.modified.length > 0) {
|
|
||||||
state.modified.forEach(modifiedArticle => {
|
|
||||||
let targetIndex = _.findIndex(state.data, _article => modifiedArticle.key === _article.key)
|
|
||||||
Object.assign(state.data[targetIndex], modifiedArticle, {key: modifiedArticle.key, updatedAt: new Date()})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
state.modified = []
|
|
||||||
dataStore.setArticles(state.data)
|
|
||||||
|
|
||||||
return state
|
|
||||||
case ARTICLE_UPDATE:
|
|
||||||
{
|
|
||||||
let article = action.data.article
|
|
||||||
|
|
||||||
let targetIndex = _.findIndex(state.data, _article => article.key === _article.key)
|
|
||||||
if (targetIndex < 0) state.data.unshift(article)
|
|
||||||
else Object.assign(state.data[targetIndex], article)
|
|
||||||
|
|
||||||
dataStore.setArticles(state.data)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case ARTICLE_DESTROY:
|
|
||||||
{
|
|
||||||
let articleKey = action.data.key
|
|
||||||
|
|
||||||
let targetIndex = _.findIndex(state.data, _article => articleKey === _article.key)
|
|
||||||
if (targetIndex >= 0) state.data.splice(targetIndex, 1)
|
|
||||||
let modifiedIndex = _.findIndex(state.modified, _article => articleKey === _article.key)
|
|
||||||
if (modifiedIndex >= 0) state.modified.splice(modifiedIndex, 1)
|
|
||||||
|
|
||||||
dataStore.setArticles(state.data)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
case FOLDER_DESTROY:
|
|
||||||
{
|
|
||||||
let folderKey = action.data.key
|
|
||||||
|
|
||||||
state.data = state.data.filter(article => article.FolderKey !== folderKey)
|
|
||||||
|
|
||||||
dataStore.setArticles(state.data)
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function status (state = initialStatus, action) {
|
|
||||||
state = Object.assign({}, state)
|
|
||||||
switch (action.type) {
|
|
||||||
case TOGGLE_TUTORIAL:
|
|
||||||
state.isTutorialOpen = !state.isTutorialOpen
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (action.type) {
|
|
||||||
case ARTICLE_SAVE:
|
|
||||||
if (action.data.forceSwitch) {
|
|
||||||
let article = action.data.article
|
|
||||||
state.articleKey = article.key
|
|
||||||
state.search = ''
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
case SWITCH_FOLDER:
|
|
||||||
state.search = `\/\/${action.data} `
|
|
||||||
|
|
||||||
return state
|
|
||||||
case SWITCH_ARTICLE:
|
|
||||||
state.articleKey = action.data.key
|
|
||||||
|
|
||||||
return state
|
|
||||||
case SET_SEARCH_FILTER:
|
|
||||||
state.search = action.data
|
|
||||||
|
|
||||||
return state
|
|
||||||
case SET_TAG_FILTER:
|
|
||||||
state.search = `#${action.data}`
|
|
||||||
|
|
||||||
return state
|
|
||||||
case CLEAR_SEARCH:
|
|
||||||
state.search = ''
|
|
||||||
|
|
||||||
return state
|
|
||||||
default:
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* v0.6.* Reducers
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Repositories
|
|
||||||
* ```
|
|
||||||
* repositories = [{
|
|
||||||
* key: String,
|
|
||||||
* name: String,
|
|
||||||
* path: String, // path of repository
|
|
||||||
* status: String, // status of repository [LOADING, IDLE, ERROR]
|
|
||||||
* folders: {
|
|
||||||
* name: String,
|
|
||||||
* color: String
|
|
||||||
* },
|
|
||||||
* notes: [{
|
|
||||||
* key: String,
|
|
||||||
* title: String,
|
|
||||||
* content: String,
|
|
||||||
* folder: String,
|
|
||||||
* tags: [String],
|
|
||||||
* createdAt: Date,
|
|
||||||
* updatedAt: Date
|
|
||||||
* }]
|
|
||||||
* }]
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
import RepositoryManager from 'browser/lib/RepositoryManager'
|
|
||||||
const initialRepositories = RepositoryManager.getRepos()
|
|
||||||
|
|
||||||
function repositories (state = initialRepositories, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case 'ADD_REPOSITORY':
|
|
||||||
{
|
|
||||||
let repos = state.slice()
|
|
||||||
repos.push(action.data)
|
|
||||||
return repos
|
|
||||||
}
|
|
||||||
case 'REMOVE_REPOSITORY':
|
|
||||||
{
|
|
||||||
let repos = state.slice()
|
|
||||||
let targetIndex = _.findIndex(repos, {key: action.data.key})
|
|
||||||
if (targetIndex > -1) {
|
|
||||||
repos.splice(targetIndex, 1)
|
|
||||||
}
|
|
||||||
return repos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
// v0.6 end
|
|
||||||
|
|
||||||
export default combineReducers({
|
|
||||||
user,
|
|
||||||
folders,
|
|
||||||
articles,
|
|
||||||
status,
|
|
||||||
repositories
|
|
||||||
})
|
|
||||||
@@ -106,48 +106,3 @@ textarea.block-input
|
|||||||
&:hover
|
&:hover
|
||||||
opacity 1
|
opacity 1
|
||||||
background-color lighten(brandColor, 10%)
|
background-color lighten(brandColor, 10%)
|
||||||
.contactButton
|
|
||||||
position fixed
|
|
||||||
z-index 2000
|
|
||||||
bottom 5px
|
|
||||||
right 5px
|
|
||||||
padding 10px 15px
|
|
||||||
border none
|
|
||||||
border-radius 5px
|
|
||||||
background-color brandColor
|
|
||||||
color white
|
|
||||||
opacity 0.7
|
|
||||||
&:hover
|
|
||||||
opacity 1
|
|
||||||
background-color lighten(brandColor, 10%)
|
|
||||||
.tooltip
|
|
||||||
tooltip()
|
|
||||||
margin-top -22px
|
|
||||||
margin-left -107px
|
|
||||||
&:hover .tooltip
|
|
||||||
opacity 1
|
|
||||||
|
|
||||||
.OSSAnnounceModal
|
|
||||||
height 250
|
|
||||||
text-align center
|
|
||||||
.OSSAnnounceModal-title
|
|
||||||
font-size 32px
|
|
||||||
padding 45px 0
|
|
||||||
|
|
||||||
.OSSAnnounceModal-link
|
|
||||||
display block
|
|
||||||
font-size 20px
|
|
||||||
margin 25px 0 65px
|
|
||||||
.OSSAnnounceModal-closeBtn
|
|
||||||
display block
|
|
||||||
margin 0 auto
|
|
||||||
border none
|
|
||||||
border-radius 5px
|
|
||||||
width 150px
|
|
||||||
height 33px
|
|
||||||
background-color brandColor
|
|
||||||
color white
|
|
||||||
opacity 0.7
|
|
||||||
&:hover
|
|
||||||
opacity 1
|
|
||||||
background-color lighten(brandColor, 10%)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user