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 () {
|
||||
return (
|
||||
<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 {...this.state.componentProps} close={this.close}/>
|
||||
)}
|
||||
|
||||
@@ -2,10 +2,6 @@ import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import moment from 'moment'
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
switchFolder,
|
||||
updateArticle
|
||||
} from '../../actions'
|
||||
import linkState from 'browser/lib/linkState'
|
||||
import TagSelect from 'browser/components/TagSelect'
|
||||
import ModeSelect from 'browser/components/ModeSelect'
|
||||
@@ -67,25 +63,25 @@ export default class ArticleDetail extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.deleteHandler = e => {
|
||||
this.deleteHandler = (e) => {
|
||||
if (isModalOpen()) return true
|
||||
this.handleDeleteButtonClick()
|
||||
}
|
||||
this.uncacheHandler = e => {
|
||||
this.uncacheHandler = (e) => {
|
||||
if (isModalOpen()) return true
|
||||
this.handleUncache()
|
||||
}
|
||||
this.titleHandler = e => {
|
||||
this.titleHandler = (e) => {
|
||||
if (isModalOpen()) return true
|
||||
if (this.refs.title) {
|
||||
this.focusTitle()
|
||||
}
|
||||
}
|
||||
this.editHandler = e => {
|
||||
this.editHandler = (e) => {
|
||||
if (isModalOpen()) return true
|
||||
if (this.refs.editor) this.refs.editor.switchEditMode()
|
||||
}
|
||||
this.previewHandler = e => {
|
||||
this.previewHandler = (e) => {
|
||||
if (isModalOpen()) return true
|
||||
if (this.refs.editor) this.refs.editor.switchPreviewMode()
|
||||
}
|
||||
@@ -100,7 +96,7 @@ export default class ArticleDetail extends React.Component {
|
||||
|
||||
componentDidMount () {
|
||||
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
||||
this.shareDropdownInterceptor = e => {
|
||||
this.shareDropdownInterceptor = (e) => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
@@ -159,12 +155,12 @@ export default class ArticleDetail extends React.Component {
|
||||
updatedAt: new Date()
|
||||
})
|
||||
|
||||
dispatch(updateArticle(article))
|
||||
// dispatch(updateArticle(article))
|
||||
|
||||
let targetFolderKey = e.target.value
|
||||
if (status.targetFolders.length > 0) {
|
||||
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,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
dispatch(updateArticle(article))
|
||||
// dispatch(updateArticle(article))
|
||||
}
|
||||
|
||||
handleTagsChange (newTag, tags) {
|
||||
@@ -184,7 +180,7 @@ export default class ArticleDetail extends React.Component {
|
||||
updatedAt: new Date()
|
||||
})
|
||||
|
||||
dispatch(updateArticle(article))
|
||||
// dispatch(updateArticle(article))
|
||||
}
|
||||
|
||||
handleModeChange (value) {
|
||||
@@ -194,7 +190,7 @@ export default class ArticleDetail extends React.Component {
|
||||
updatedAt: new Date()
|
||||
})
|
||||
|
||||
dispatch(updateArticle(article))
|
||||
// dispatch(updateArticle(article))
|
||||
this.switchEditMode()
|
||||
}
|
||||
|
||||
@@ -206,7 +202,7 @@ export default class ArticleDetail extends React.Component {
|
||||
updatedAt: new Date()
|
||||
})
|
||||
|
||||
dispatch(updateArticle(article))
|
||||
// dispatch(updateArticle(article))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +250,7 @@ export default class ArticleDetail extends React.Component {
|
||||
render () {
|
||||
let { folders, status, tags, activeArticle, modified, user } = this.props
|
||||
if (activeArticle == null) return this.renderEmpty()
|
||||
let folderOptions = folders.map(folder => {
|
||||
let folderOptions = folders.map((folder) => {
|
||||
return (
|
||||
<option key={folder.key} value={folder.key}>{folder.name}</option>
|
||||
)
|
||||
@@ -269,7 +265,7 @@ export default class ArticleDetail extends React.Component {
|
||||
<select
|
||||
className='ArticleDetail-info-folder'
|
||||
value={activeArticle.FolderKey}
|
||||
onChange={e => this.handleFolderKeyChange(e)}
|
||||
onChange={(e) => this.handleFolderKeyChange(e)}
|
||||
>
|
||||
{folderOptions}
|
||||
</select>
|
||||
@@ -282,25 +278,14 @@ export default class ArticleDetail extends React.Component {
|
||||
/>
|
||||
|
||||
<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
|
||||
article={activeArticle}
|
||||
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'/>
|
||||
<span className='tooltip' children={`Delete Post (^ + Del)`}/>
|
||||
<span className='tooltip'>Delete Post (^ + Del)</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -319,11 +304,11 @@ export default class ArticleDetail extends React.Component {
|
||||
<div className='ArticleDetail-panel-header'>
|
||||
<div className='ArticleDetail-panel-header-title'>
|
||||
<input
|
||||
onKeyDown={e => this.handleTitleKeyDown(e)}
|
||||
onKeyDown={(e) => this.handleTitleKeyDown(e)}
|
||||
placeholder='(Untitled)'
|
||||
ref='title'
|
||||
value={activeArticle.title}
|
||||
onChange={e => this.handleTitleChange(e)}
|
||||
onChange={(e) => this.handleTitleChange(e)}
|
||||
style={{
|
||||
fontFamily: this.state.fontFamily
|
||||
}}
|
||||
@@ -331,8 +316,8 @@ export default class ArticleDetail extends React.Component {
|
||||
</div>
|
||||
<ModeSelect
|
||||
ref='mode'
|
||||
onChange={e => this.handleModeChange(e)}
|
||||
onKeyDown={e => this.handleModeSelectKeyDown(e)}
|
||||
onChange={(e) => this.handleModeChange(e)}
|
||||
onKeyDown={(e) => this.handleModeSelectKeyDown(e)}
|
||||
value={activeArticle.mode}
|
||||
className='ArticleDetail-panel-header-mode'
|
||||
/>
|
||||
@@ -341,7 +326,7 @@ export default class ArticleDetail extends React.Component {
|
||||
<ArticleEditor
|
||||
ref='editor'
|
||||
article={activeArticle}
|
||||
onChange={content => this.handleContentChange(content)}
|
||||
onChange={(content) => this.handleContentChange(content)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -351,11 +336,6 @@ export default class ArticleDetail extends React.Component {
|
||||
|
||||
ArticleDetail.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
status: PropTypes.shape(),
|
||||
tags: PropTypes.array,
|
||||
user: PropTypes.shape(),
|
||||
folders: PropTypes.array,
|
||||
modified: PropTypes.array,
|
||||
activeArticle: PropTypes.shape()
|
||||
repositories: PropTypes.array
|
||||
}
|
||||
ArticleDetail.prototype.linkState = linkState
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import ModeIcon from 'browser/components/ModeIcon'
|
||||
import moment from 'moment'
|
||||
import { switchArticle } from '../actions'
|
||||
import FolderMark from 'browser/components/FolderMark'
|
||||
import TagLink from './TagLink'
|
||||
import _ from 'lodash'
|
||||
@@ -15,7 +14,7 @@ export default class ArticleList extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.focusHandler = e => this.focus()
|
||||
this.focusHandler = (e) => this.focus()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@@ -30,8 +29,8 @@ export default class ArticleList extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
let { articles, activeArticle } = this.props
|
||||
var index = articles.indexOf(activeArticle)
|
||||
return false
|
||||
var index = articles.indexOf(null)
|
||||
var el = ReactDOM.findDOMNode(this)
|
||||
var li = el.querySelectorAll('.ArticleList>div')[index]
|
||||
|
||||
@@ -130,16 +129,12 @@ export default class ArticleList extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { articles, modified, activeArticle, folders } = this.props
|
||||
|
||||
let articleElements = articles.map(article => {
|
||||
let modifiedArticle = _.findWhere(modified, {key: article.key})
|
||||
let articles = []
|
||||
let folders = []
|
||||
let articleElements = articles.map((article) => {
|
||||
let originalArticle = article
|
||||
if (modifiedArticle) {
|
||||
article = Object.assign({}, article)
|
||||
}
|
||||
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}/>)
|
||||
})
|
||||
: (<span>Not tagged yet</span>)
|
||||
@@ -153,7 +148,7 @@ export default class ArticleList extends React.Component {
|
||||
|
||||
return (
|
||||
<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'>
|
||||
{folder != null
|
||||
? folderChanged
|
||||
@@ -167,13 +162,7 @@ export default class ArticleList extends React.Component {
|
||||
</span>
|
||||
: <span><FolderMark color={-1}/>Unknown</span>
|
||||
}
|
||||
<span className='updatedAt'
|
||||
children={
|
||||
modifiedArticle != null
|
||||
? <span><span className='unsaved-mark'>●</span> Unsaved</span>
|
||||
: moment(article.updatedAt).fromNow()
|
||||
}
|
||||
/>
|
||||
<span className='updatedAt'>{moment(article.updatedAt).fromNow()}</span>
|
||||
</div>
|
||||
<div className='ArticleList-item-middle'>
|
||||
<ModeIcon className='mode' mode={article.mode}/> <div className='title' children={title}/>
|
||||
@@ -191,7 +180,7 @@ export default class ArticleList extends React.Component {
|
||||
})
|
||||
|
||||
return (
|
||||
<div tabIndex='3' onKeyDown={e => this.handleArticleListKeyDown(e)} className='ArticleList'>
|
||||
<div tabIndex='3' onKeyDown={(e) => this.handleArticleListKeyDown(e)} className='ArticleList'>
|
||||
{articleElements}
|
||||
</div>
|
||||
)
|
||||
@@ -200,8 +189,5 @@ export default class ArticleList extends React.Component {
|
||||
|
||||
ArticleList.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
folders: PropTypes.array,
|
||||
articles: PropTypes.array,
|
||||
modified: PropTypes.array,
|
||||
activeArticle: PropTypes.shape()
|
||||
repositories: PropTypes.array
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import ExternalLink from 'browser/components/ExternalLink'
|
||||
import { setSearchFilter, clearSearch, toggleTutorial, saveArticle, switchFolder } from '../actions'
|
||||
import { isModalOpen } from 'browser/lib/modal'
|
||||
import keygen from 'browser/lib/keygen'
|
||||
import activityRecord from 'browser/lib/activityRecord'
|
||||
|
||||
const electron = require('electron')
|
||||
const remote = electron.remote
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
@@ -83,7 +80,7 @@ export default class ArticleTopBar extends React.Component {
|
||||
this.setState({isLinksDropdownOpen: true})
|
||||
}
|
||||
}
|
||||
this.linksButton.addEventListener('click', this.showLinksDropdown)
|
||||
// this.linksButton.addEventListener('click', this.showLinksDropdown)
|
||||
this.hideLinksDropdown = e => {
|
||||
if (this.state.isLinksDropdownOpen) {
|
||||
this.setState({isLinksDropdownOpen: false})
|
||||
@@ -118,11 +115,6 @@ export default class ArticleTopBar extends React.Component {
|
||||
}
|
||||
|
||||
escape () {
|
||||
let { status, dispatch } = this.props
|
||||
if (status.search.length > 0) {
|
||||
dispatch(clearSearch())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
focusInput () {
|
||||
@@ -136,7 +128,7 @@ export default class ArticleTopBar extends React.Component {
|
||||
handleSearchChange (e) {
|
||||
let { dispatch } = this.props
|
||||
|
||||
dispatch(setSearchFilter(e.target.value))
|
||||
// dispatch(setSearchFilter(e.target.value))
|
||||
this.handleTooltipRequest()
|
||||
}
|
||||
|
||||
@@ -146,35 +138,13 @@ export default class ArticleTopBar extends React.Component {
|
||||
}
|
||||
|
||||
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')
|
||||
}
|
||||
|
||||
handleTutorialButtonClick (e) {
|
||||
let { dispatch } = this.props
|
||||
|
||||
dispatch(toggleTutorial())
|
||||
// dispatch(toggleTutorial())
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -186,16 +156,16 @@ export default class ArticleTopBar extends React.Component {
|
||||
<i className='fa fa-search fa-fw' />
|
||||
<input
|
||||
ref='searchInput'
|
||||
onFocus={e => this.handleSearchChange(e)}
|
||||
onBlur={e => this.handleSearchChange(e)}
|
||||
value={this.props.status.search}
|
||||
onChange={e => this.handleSearchChange(e)}
|
||||
onFocus={(e) => this.handleSearchChange(e)}
|
||||
onBlur={(e) => this.handleSearchChange(e)}
|
||||
value={'this.props.status.search'}
|
||||
onChange={(e) => this.handleSearchChange(e)}
|
||||
placeholder='Search'
|
||||
type='text'
|
||||
/>
|
||||
{
|
||||
this.props.status.search != null && this.props.status.search.length > 0
|
||||
? <button onClick={e => this.handleSearchClearButton(e)} className='ArticleTopBar-left-search-clear-button'><i className='fa fa-times'/></button>
|
||||
'sadf' > 0
|
||||
? <button onClick={(e) => this.handleSearchClearButton(e)} className='ArticleTopBar-left-search-clear-button'><i className='fa fa-times'/></button>
|
||||
: null
|
||||
}
|
||||
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
||||
@@ -207,19 +177,16 @@ export default class ArticleTopBar extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{status.isTutorialOpen ? searchTutorialElement : null}
|
||||
|
||||
<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'/>
|
||||
<span className='tooltip'>New Post ({OSX ? '⌘' : '^'} + n)</span>
|
||||
</button>
|
||||
{status.isTutorialOpen ? newPostTutorialElement : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<a ref='links' className='ArticleTopBar-right-links-button' href>
|
||||
<img src='../resources/app.png' width='44' height='44'/>
|
||||
@@ -240,9 +207,9 @@ export default class ArticleTopBar extends React.Component {
|
||||
}
|
||||
</div>
|
||||
|
||||
{status.isTutorialOpen ? (
|
||||
{false ? (
|
||||
<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'>
|
||||
<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`')}/>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import store from '../store'
|
||||
import { setTagFilter } from '../actions'
|
||||
|
||||
export default class TagLink extends React.Component {
|
||||
handleClick (e) {
|
||||
store.dispatch(setTagFilter(this.props.tag))
|
||||
}
|
||||
render () {
|
||||
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.')
|
||||
}
|
||||
|
||||
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 () {
|
||||
return (
|
||||
<div
|
||||
className='Main'
|
||||
onWheel={(e) => this.handleWheel(e)}
|
||||
>
|
||||
{this.state.updateAvailable ? (
|
||||
<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 MainPage from './MainPage'
|
||||
import Main from './Main'
|
||||
import store from './store'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
@@ -76,7 +76,7 @@ let el = document.getElementById('content')
|
||||
ReactDOM.render((
|
||||
<div>
|
||||
<Provider store={store}>
|
||||
<MainPage/>
|
||||
<Main/>
|
||||
</Provider>
|
||||
</div>
|
||||
), el, function () {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import linkState from 'browser/lib/linkState'
|
||||
import { createFolder } from '../actions'
|
||||
import store from '../store'
|
||||
import FolderMark from 'browser/components/FolderMark'
|
||||
|
||||
@@ -34,7 +33,7 @@ export default class CreateNewFolder extends React.Component {
|
||||
color
|
||||
}
|
||||
try {
|
||||
store.dispatch(createFolder(input))
|
||||
// store.dispatch(createFolder(input))
|
||||
} catch (e) {
|
||||
this.setState({alert: {
|
||||
type: 'error',
|
||||
@@ -47,7 +46,7 @@ export default class CreateNewFolder extends React.Component {
|
||||
}
|
||||
|
||||
handleColorClick (colorIndex) {
|
||||
return e => {
|
||||
return (e) => {
|
||||
this.setState({
|
||||
color: colorIndex
|
||||
})
|
||||
@@ -71,12 +70,12 @@ export default class CreateNewFolder extends React.Component {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
colorIndexes.push(i)
|
||||
}
|
||||
let colorElements = colorIndexes.map(index => {
|
||||
let colorElements = colorIndexes.map((index) => {
|
||||
let className = 'option'
|
||||
if (index === this.state.color) className += ' active'
|
||||
|
||||
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}/>
|
||||
</span>
|
||||
)
|
||||
@@ -84,17 +83,17 @@ export default class CreateNewFolder extends React.Component {
|
||||
|
||||
return (
|
||||
<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>
|
||||
|
||||
<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'>
|
||||
{colorElements}
|
||||
</div>
|
||||
{alertElement}
|
||||
|
||||
<button onClick={e => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
||||
<button onClick={(e) => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import store from '../store'
|
||||
import { destroyArticle } from '../actions'
|
||||
|
||||
const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
@@ -10,7 +9,7 @@ export default class DeleteArticleModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.confirmHandler = e => this.handleYesButtonClick()
|
||||
this.confirmHandler = (e) => this.handleYesButtonClick()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@@ -27,7 +26,7 @@ export default class DeleteArticleModal extends React.Component {
|
||||
}
|
||||
|
||||
handleYesButtonClick (e) {
|
||||
store.dispatch(destroyArticle(this.props.articleKey))
|
||||
// store.dispatch(destroyArticle(this.props.articleKey))
|
||||
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='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>
|
||||
<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>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import linkState from 'browser/lib/linkState'
|
||||
import { updateUser } from '../../actions'
|
||||
import fetchConfig from 'browser/lib/fetchConfig'
|
||||
import hljsTheme from 'browser/lib/hljsThemes'
|
||||
|
||||
@@ -38,7 +37,7 @@ export default class AppSettingTab extends React.Component {
|
||||
message: 'Successfully done!'
|
||||
}})
|
||||
}
|
||||
this.handleSettingError = err => {
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : 'Error occurs!'
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
|
||||
import linkState from 'browser/lib/linkState'
|
||||
import FolderMark from 'browser/components/FolderMark'
|
||||
import store from '../../store'
|
||||
import { updateFolder, destroyFolder, replaceFolder } from '../../actions'
|
||||
|
||||
const IDLE = 'IDLE'
|
||||
const EDIT = 'EDIT'
|
||||
@@ -20,14 +19,14 @@ export default class FolderRow extends React.Component {
|
||||
handleUpClick (e) {
|
||||
let { index } = this.props
|
||||
if (index > 0) {
|
||||
store.dispatch(replaceFolder(index, index - 1))
|
||||
// store.dispatch(replaceFolder(index, index - 1))
|
||||
}
|
||||
}
|
||||
|
||||
handleDownClick (e) {
|
||||
let { index, count } = this.props
|
||||
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)
|
||||
|
||||
try {
|
||||
store.dispatch(updateFolder(folder))
|
||||
// store.dispatch(updateFolder(folder))
|
||||
this.setState({
|
||||
mode: IDLE
|
||||
})
|
||||
@@ -98,7 +97,7 @@ export default class FolderRow extends React.Component {
|
||||
|
||||
handleDeleteConfirmButtonClick (e) {
|
||||
let { folder } = this.props
|
||||
store.dispatch(destroyFolder(folder.key))
|
||||
// store.dispatch(destroyFolder(folder.key))
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -111,7 +110,7 @@ export default class FolderRow extends React.Component {
|
||||
colorIndexes.push(i)
|
||||
}
|
||||
|
||||
let colorOptions = colorIndexes.map(index => {
|
||||
let colorOptions = colorIndexes.map((index) => {
|
||||
let className = this.state.color === index
|
||||
? 'active'
|
||||
: null
|
||||
@@ -129,12 +128,10 @@ export default class FolderRow extends React.Component {
|
||||
<FolderMark color={this.state.color}/>
|
||||
</button>
|
||||
{this.state.isColorEditing
|
||||
? (
|
||||
<div className='options'>
|
||||
? <div className='options'>
|
||||
<div className='label'>Color select</div>
|
||||
{colorOptions}
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import FolderRow from './FolderRow'
|
||||
import linkState from 'browser/lib/linkState'
|
||||
import { createFolder } from '../../actions'
|
||||
|
||||
export default class FolderSettingTab extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -23,9 +22,9 @@ export default class FolderSettingTab extends React.Component {
|
||||
let { dispatch } = this.props
|
||||
|
||||
try {
|
||||
dispatch(createFolder({
|
||||
name: this.state.name
|
||||
}))
|
||||
// dispatch(createFolder({
|
||||
// name: this.state.name
|
||||
// }))
|
||||
} catch (e) {
|
||||
this.setState({alert: {
|
||||
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
|
||||
opacity 1
|
||||
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