mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 10:16:26 +00:00
Compare commits
20 Commits
0.4.0-beta
...
0.4.1-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee91daad7e | ||
|
|
ee78c0d33b | ||
|
|
09482ebcf3 | ||
|
|
67424f2d3a | ||
|
|
51f530ffbe | ||
|
|
013f96a754 | ||
|
|
df6a018fb6 | ||
|
|
409eaf54c1 | ||
|
|
7e04fd342c | ||
|
|
1fe15bc6a5 | ||
|
|
ff1bffbb55 | ||
|
|
b28b18a19a | ||
|
|
bbc3c85212 | ||
|
|
26a08fac06 | ||
|
|
da9d7a4336 | ||
|
|
46c6555f94 | ||
|
|
3e980fd2d4 | ||
|
|
fb1462f669 | ||
|
|
41e1630aac | ||
|
|
ef84c4e3da |
@@ -5,33 +5,38 @@ var path = require('path')
|
|||||||
|
|
||||||
var version = app.getVersion()
|
var version = app.getVersion()
|
||||||
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
||||||
|
var versionNotified = false
|
||||||
autoUpdater
|
autoUpdater
|
||||||
.on('error', function (err, message) {
|
.on('error', function (err, message) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
console.error(message)
|
console.error(message)
|
||||||
|
console.log(path.resolve(__dirname, '../resources/favicon-230x230.png'))
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Error! ' + versionText,
|
title: 'Error! ' + versionText,
|
||||||
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
||||||
message: message
|
message: message
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// .on('checking-for-update', function () {
|
// .on('checking-for-update', function () {
|
||||||
// // Connecting
|
// // Connecting
|
||||||
|
// console.log('checking...')
|
||||||
// })
|
// })
|
||||||
.on('update-available', function () {
|
.on('update-available', function () {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Update is available!! ' + versionText,
|
title: 'Update is available!! ' + versionText,
|
||||||
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
||||||
message: 'Download started.. wait for the update ready.'
|
message: 'Download started.. wait for the update ready.'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('update-not-available', function () {
|
.on('update-not-available', function () {
|
||||||
nn.notify({
|
if (!versionNotified) {
|
||||||
title: 'Latest Build!! ' + versionText,
|
nn.notify({
|
||||||
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
title: 'Latest Build!! ' + versionText,
|
||||||
message: 'Hope you to enjoy our app :D'
|
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
||||||
})
|
message: 'Hope you to enjoy our app :D'
|
||||||
|
})
|
||||||
|
versionNotified = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = autoUpdater
|
module.exports = autoUpdater
|
||||||
|
|||||||
@@ -11,7 +11,16 @@ export default class FinderDetail extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className='FinderDetail'>
|
<div className='FinderDetail'>
|
||||||
<div className='header'>
|
<div className='header'>
|
||||||
<ModeIcon mode={activeArticle.mode}/> {activeArticle.title}</div>
|
<div className='left'>
|
||||||
|
<ModeIcon mode={activeArticle.mode}/> {activeArticle.title}
|
||||||
|
</div>
|
||||||
|
<div className='right'>
|
||||||
|
<button onClick={this.props.saveToClipboard} className='clipboardBtn'>
|
||||||
|
<i className='fa fa-clipboard fa-fw'/>
|
||||||
|
<span className='tooltip'>Copy to clipboard (Enter)</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
{activeArticle.mode === 'markdown'
|
{activeArticle.mode === 'markdown'
|
||||||
? <MarkdownPreview content={activeArticle.content}/>
|
? <MarkdownPreview content={activeArticle.content}/>
|
||||||
@@ -30,5 +39,6 @@ export default class FinderDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FinderDetail.propTypes = {
|
FinderDetail.propTypes = {
|
||||||
activeArticle: PropTypes.shape()
|
activeArticle: PropTypes.shape(),
|
||||||
|
saveToClipboard: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<title>CodeXen Popup</title>
|
<title>Boost Finder</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,16 @@ import remote from 'remote'
|
|||||||
var hideFinder = remote.getGlobal('hideFinder')
|
var hideFinder = remote.getGlobal('hideFinder')
|
||||||
import clipboard from 'clipboard'
|
import clipboard from 'clipboard'
|
||||||
|
|
||||||
|
var notifier = require('node-notifier')
|
||||||
|
var path = require('path')
|
||||||
|
function getIconPath () {
|
||||||
|
return path.resolve(global.__dirname, '../../resources/favicon-230x230.png')
|
||||||
|
}
|
||||||
|
|
||||||
require('../styles/finder/index.styl')
|
require('../styles/finder/index.styl')
|
||||||
|
|
||||||
const FOLDER_FILTER = 'FOLDER_FILTER'
|
const FOLDER_FILTER = 'FOLDER_FILTER'
|
||||||
|
const FOLDER_EXACT_FILTER = 'FOLDER_EXACT_FILTER'
|
||||||
const TEXT_FILTER = 'TEXT_FILTER'
|
const TEXT_FILTER = 'TEXT_FILTER'
|
||||||
const TAG_FILTER = 'TAG_FILTER'
|
const TAG_FILTER = 'TAG_FILTER'
|
||||||
|
|
||||||
@@ -45,10 +52,7 @@ class FinderMain extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
let { activeArticle } = this.props
|
this.saveToClipboard()
|
||||||
clipboard.writeText(activeArticle.content)
|
|
||||||
activityRecord.emit('FINDER_COPY')
|
|
||||||
hideFinder()
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
@@ -57,6 +61,19 @@ class FinderMain extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveToClipboard () {
|
||||||
|
let { activeArticle } = this.props
|
||||||
|
clipboard.writeText(activeArticle.content)
|
||||||
|
activityRecord.emit('FINDER_COPY')
|
||||||
|
|
||||||
|
notifier.notify({
|
||||||
|
icon: getIconPath(),
|
||||||
|
'title': 'Saved to Clipboard!',
|
||||||
|
'message': 'Paste it wherever you want!'
|
||||||
|
})
|
||||||
|
hideFinder()
|
||||||
|
}
|
||||||
|
|
||||||
handleSearchChange (e) {
|
handleSearchChange (e) {
|
||||||
let { dispatch } = this.props
|
let { dispatch } = this.props
|
||||||
|
|
||||||
@@ -83,6 +100,7 @@ class FinderMain extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { articles, activeArticle, status, dispatch } = this.props
|
let { articles, activeArticle, status, dispatch } = this.props
|
||||||
|
let saveToClipboard = () => this.saveToClipboard()
|
||||||
return (
|
return (
|
||||||
<div onClick={e => this.handleClick(e)} onKeyDown={e => this.handleKeyDown(e)} className='Finder'>
|
<div onClick={e => this.handleClick(e)} onKeyDown={e => this.handleKeyDown(e)} className='Finder'>
|
||||||
<FinderInput
|
<FinderInput
|
||||||
@@ -98,7 +116,10 @@ class FinderMain extends React.Component {
|
|||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
selectArticle={article => this.selectArticle(article)}
|
selectArticle={article => this.selectArticle(article)}
|
||||||
/>
|
/>
|
||||||
<FinderDetail activeArticle={activeArticle}/>
|
<FinderDetail
|
||||||
|
activeArticle={activeArticle}
|
||||||
|
saveToClipboard={saveToClipboard}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -116,27 +137,47 @@ FinderMain.propTypes = {
|
|||||||
dispatch: PropTypes.func
|
dispatch: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore invalid key
|
||||||
|
function ignoreInvalidKey (key) {
|
||||||
|
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build filter object by key
|
||||||
|
function buildFilter (key) {
|
||||||
|
if (key.match(/^\/\/.+/)) {
|
||||||
|
return {type: FOLDER_EXACT_FILTER, value: key.match(/^\/\/(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
if (key.match(/^\/.+/)) {
|
||||||
|
return {type: FOLDER_FILTER, value: key.match(/^\/(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
if (key.match(/^#(.+)/)) {
|
||||||
|
return {type: TAG_FILTER, value: key.match(/^#(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
return {type: TEXT_FILTER, value: key}
|
||||||
|
}
|
||||||
|
|
||||||
function remap (state) {
|
function remap (state) {
|
||||||
let { articles, folders, status } = state
|
let { articles, folders, status } = state
|
||||||
|
|
||||||
let filters = status.search.split(' ').map(key => key.trim()).filter(key => key.length > 0 && !key.match(/^#$/)).map(key => {
|
let filters = status.search.split(' ')
|
||||||
if (key.match(/^in:.+$/)) {
|
.map(key => key.trim())
|
||||||
return {type: FOLDER_FILTER, value: key.match(/^in:(.+)$/)[1]}
|
.filter(ignoreInvalidKey)
|
||||||
}
|
.map(buildFilter)
|
||||||
if (key.match(/^#(.+)/)) {
|
|
||||||
return {type: TAG_FILTER, value: key.match(/^#(.+)$/)[1]}
|
let folderExactFilters = filters.filter(filter => filter.type === FOLDER_EXACT_FILTER)
|
||||||
}
|
|
||||||
return {type: TEXT_FILTER, value: key}
|
|
||||||
})
|
|
||||||
let folderFilters = filters.filter(filter => filter.type === FOLDER_FILTER)
|
let folderFilters = filters.filter(filter => filter.type === FOLDER_FILTER)
|
||||||
let textFilters = filters.filter(filter => filter.type === TEXT_FILTER)
|
let textFilters = filters.filter(filter => filter.type === TEXT_FILTER)
|
||||||
let tagFilters = filters.filter(filter => filter.type === TAG_FILTER)
|
let tagFilters = filters.filter(filter => filter.type === TAG_FILTER)
|
||||||
|
|
||||||
|
let targetFolders
|
||||||
if (folders != null) {
|
if (folders != null) {
|
||||||
let targetFolders = folders.filter(folder => {
|
let exactTargetFolders = folders.filter(folder => {
|
||||||
return _.findWhere(folderFilters, {value: folder.name})
|
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
|
||||||
})
|
})
|
||||||
status.targetFolders = targetFolders
|
let fuzzyTargetFolders = folders.filter(folder => {
|
||||||
|
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
|
||||||
|
})
|
||||||
|
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
|
||||||
|
|
||||||
if (targetFolders.length > 0) {
|
if (targetFolders.length > 0) {
|
||||||
articles = articles.filter(article => {
|
articles = articles.filter(article => {
|
||||||
@@ -164,6 +205,7 @@ function remap (state) {
|
|||||||
let activeArticle = _.findWhere(articles, {key: status.articleKey})
|
let activeArticle = _.findWhere(articles, {key: status.articleKey})
|
||||||
if (activeArticle == null) activeArticle = articles[0]
|
if (activeArticle == null) activeArticle = articles[0]
|
||||||
|
|
||||||
|
console.log(status.search)
|
||||||
return {
|
return {
|
||||||
articles,
|
articles,
|
||||||
activeArticle,
|
activeArticle,
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ function status (state = initialStatus, action) {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SELECT_ARTICLE:
|
case SELECT_ARTICLE:
|
||||||
state.articleKey = action.data.key
|
state.articleKey = action.data.key
|
||||||
return state
|
return Object.assign({}, state)
|
||||||
case SEARCH_ARTICLE:
|
case SEARCH_ARTICLE:
|
||||||
state.search = action.data.input
|
state.search = action.data.input
|
||||||
return state
|
return Object.assign({}, state)
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { isModalOpen, closeModal } from 'boost/modal'
|
|||||||
|
|
||||||
const TEXT_FILTER = 'TEXT_FILTER'
|
const TEXT_FILTER = 'TEXT_FILTER'
|
||||||
const FOLDER_FILTER = 'FOLDER_FILTER'
|
const FOLDER_FILTER = 'FOLDER_FILTER'
|
||||||
|
const FOLDER_EXACT_FILTER = 'FOLDER_EXACT_FILTER'
|
||||||
const TAG_FILTER = 'TAG_FILTER'
|
const TAG_FILTER = 'TAG_FILTER'
|
||||||
|
|
||||||
class HomePage extends React.Component {
|
class HomePage extends React.Component {
|
||||||
@@ -98,7 +99,7 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { dispatch, status, articles, activeArticle, folders, filters } = this.props
|
let { dispatch, status, articles, allArticles, activeArticle, folders, tags, filters } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='HomePage'>
|
<div className='HomePage'>
|
||||||
@@ -107,6 +108,7 @@ class HomePage extends React.Component {
|
|||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
folders={folders}
|
folders={folders}
|
||||||
status={status}
|
status={status}
|
||||||
|
allArticles={allArticles}
|
||||||
/>
|
/>
|
||||||
<ArticleTopBar
|
<ArticleTopBar
|
||||||
ref='top'
|
ref='top'
|
||||||
@@ -127,6 +129,7 @@ class HomePage extends React.Component {
|
|||||||
activeArticle={activeArticle}
|
activeArticle={activeArticle}
|
||||||
folders={folders}
|
folders={folders}
|
||||||
status={status}
|
status={status}
|
||||||
|
tags={tags}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,6 +137,25 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignore invalid key
|
||||||
|
function ignoreInvalidKey (key) {
|
||||||
|
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build filter object by key
|
||||||
|
function buildFilter (key) {
|
||||||
|
if (key.match(/^\/\/.+/)) {
|
||||||
|
return {type: FOLDER_EXACT_FILTER, value: key.match(/^\/\/(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
if (key.match(/^\/.+/)) {
|
||||||
|
return {type: FOLDER_FILTER, value: key.match(/^\/(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
if (key.match(/^#(.+)/)) {
|
||||||
|
return {type: TAG_FILTER, value: key.match(/^#(.+)$/)[1]}
|
||||||
|
}
|
||||||
|
return {type: TEXT_FILTER, value: key}
|
||||||
|
}
|
||||||
|
|
||||||
function remap (state) {
|
function remap (state) {
|
||||||
let { folders, articles, status } = state
|
let { folders, articles, status } = state
|
||||||
|
|
||||||
@@ -141,26 +163,33 @@ function remap (state) {
|
|||||||
articles.sort((a, b) => {
|
articles.sort((a, b) => {
|
||||||
return new Date(b.updatedAt) - new Date(a.updatedAt)
|
return new Date(b.updatedAt) - new Date(a.updatedAt)
|
||||||
})
|
})
|
||||||
|
let allArticles = articles.slice()
|
||||||
|
|
||||||
|
let tags = _.uniq(allArticles.reduce((sum, article) => {
|
||||||
|
if (!_.isArray(article.tags)) return sum
|
||||||
|
return sum.concat(article.tags)
|
||||||
|
}, []))
|
||||||
|
|
||||||
// Filter articles
|
// Filter articles
|
||||||
let filters = status.search.split(' ').map(key => key.trim()).filter(key => key.length > 0 && !key.match(/^#$/)).map(key => {
|
let filters = status.search.split(' ')
|
||||||
if (key.match(/^in:.+$/)) {
|
.map(key => key.trim())
|
||||||
return {type: FOLDER_FILTER, value: key.match(/^in:(.+)$/)[1]}
|
.filter(ignoreInvalidKey)
|
||||||
}
|
.map(buildFilter)
|
||||||
if (key.match(/^#(.+)/)) {
|
|
||||||
return {type: TAG_FILTER, value: key.match(/^#(.+)$/)[1]}
|
let folderExactFilters = filters.filter(filter => filter.type === FOLDER_EXACT_FILTER)
|
||||||
}
|
|
||||||
return {type: TEXT_FILTER, value: key}
|
|
||||||
})
|
|
||||||
let folderFilters = filters.filter(filter => filter.type === FOLDER_FILTER)
|
let folderFilters = filters.filter(filter => filter.type === FOLDER_FILTER)
|
||||||
let textFilters = filters.filter(filter => filter.type === TEXT_FILTER)
|
let textFilters = filters.filter(filter => filter.type === TEXT_FILTER)
|
||||||
let tagFilters = filters.filter(filter => filter.type === TAG_FILTER)
|
let tagFilters = filters.filter(filter => filter.type === TAG_FILTER)
|
||||||
|
|
||||||
|
let targetFolders
|
||||||
if (folders != null) {
|
if (folders != null) {
|
||||||
let targetFolders = folders.filter(folder => {
|
let exactTargetFolders = folders.filter(folder => {
|
||||||
return _.findWhere(folderFilters, {value: folder.name})
|
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
|
||||||
})
|
})
|
||||||
status.targetFolders = targetFolders
|
let fuzzyTargetFolders = folders.filter(folder => {
|
||||||
|
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
|
||||||
|
})
|
||||||
|
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
|
||||||
|
|
||||||
if (targetFolders.length > 0) {
|
if (targetFolders.length > 0) {
|
||||||
articles = articles.filter(article => {
|
articles = articles.filter(article => {
|
||||||
@@ -202,11 +231,10 @@ function remap (state) {
|
|||||||
// or Change IDLE MODE
|
// or Change IDLE MODE
|
||||||
if (status.mode === CREATE_MODE) {
|
if (status.mode === CREATE_MODE) {
|
||||||
let newArticle = _.findWhere(articles, {status: 'NEW'})
|
let newArticle = _.findWhere(articles, {status: 'NEW'})
|
||||||
let FolderKey = folders[0].key
|
console.log('targetFolders')
|
||||||
if (folderFilters.length > 0) {
|
let FolderKey = targetFolders.length > 0
|
||||||
let targetFolder = _.findWhere(folders, {name: folderFilters[0].value})
|
? targetFolders[0].key
|
||||||
if (targetFolder != null) FolderKey = targetFolder.key
|
: folders[0].key
|
||||||
}
|
|
||||||
|
|
||||||
if (newArticle == null) {
|
if (newArticle == null) {
|
||||||
newArticle = {
|
newArticle = {
|
||||||
@@ -229,8 +257,10 @@ function remap (state) {
|
|||||||
return {
|
return {
|
||||||
folders,
|
folders,
|
||||||
status,
|
status,
|
||||||
|
allArticles,
|
||||||
articles,
|
articles,
|
||||||
activeArticle,
|
activeArticle,
|
||||||
|
tags,
|
||||||
filters: {
|
filters: {
|
||||||
folder: folderFilters,
|
folder: folderFilters,
|
||||||
tag: tagFilters,
|
tag: tagFilters,
|
||||||
@@ -247,6 +277,7 @@ HomePage.propTypes = {
|
|||||||
userId: PropTypes.string
|
userId: PropTypes.string
|
||||||
}),
|
}),
|
||||||
articles: PropTypes.array,
|
articles: PropTypes.array,
|
||||||
|
allArticles: PropTypes.array,
|
||||||
activeArticle: PropTypes.shape(),
|
activeArticle: PropTypes.shape(),
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
folders: PropTypes.array,
|
folders: PropTypes.array,
|
||||||
|
|||||||
@@ -5,7 +5,20 @@ import _ from 'lodash'
|
|||||||
import ModeIcon from 'boost/components/ModeIcon'
|
import ModeIcon from 'boost/components/ModeIcon'
|
||||||
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
||||||
import CodeEditor from 'boost/components/CodeEditor'
|
import CodeEditor from 'boost/components/CodeEditor'
|
||||||
import { IDLE_MODE, CREATE_MODE, EDIT_MODE, switchMode, switchArticle, switchFolder, clearSearch, updateArticle, destroyArticle, NEW } from 'boost/actions'
|
import {
|
||||||
|
IDLE_MODE,
|
||||||
|
CREATE_MODE,
|
||||||
|
EDIT_MODE,
|
||||||
|
switchMode,
|
||||||
|
switchArticle,
|
||||||
|
switchFolder,
|
||||||
|
clearSearch,
|
||||||
|
lockStatus,
|
||||||
|
unlockStatus,
|
||||||
|
updateArticle,
|
||||||
|
destroyArticle,
|
||||||
|
NEW
|
||||||
|
} from 'boost/actions'
|
||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import FolderMark from 'boost/components/FolderMark'
|
import FolderMark from 'boost/components/FolderMark'
|
||||||
import TagLink from 'boost/components/TagLink'
|
import TagLink from 'boost/components/TagLink'
|
||||||
@@ -82,7 +95,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
article: makeInstantArticle(props.activeArticle),
|
article: makeInstantArticle(props.activeArticle),
|
||||||
previewMode: false
|
previewMode: false,
|
||||||
|
isArticleEdited: false,
|
||||||
|
isTagChanged: false,
|
||||||
|
isTitleChanged: false,
|
||||||
|
isContentChanged: false,
|
||||||
|
isModeChanged: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +135,11 @@ export default class ArticleDetail extends React.Component {
|
|||||||
if (isModeChanged) {
|
if (isModeChanged) {
|
||||||
Object.assign(nextState, {
|
Object.assign(nextState, {
|
||||||
openDeleteConfirmMenu: false,
|
openDeleteConfirmMenu: false,
|
||||||
previewMode: false
|
previewMode: false,
|
||||||
|
isArticleEdited: false,
|
||||||
|
isTagChanged: false,
|
||||||
|
isTitleChanged: false,
|
||||||
|
isContentChanged: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +246,8 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
handleCancelButtonClick (e) {
|
handleCancelButtonClick (e) {
|
||||||
let { activeArticle, dispatch } = this.props
|
let { activeArticle, dispatch } = this.props
|
||||||
|
|
||||||
|
dispatch(unlockStatus())
|
||||||
if (activeArticle.status === NEW) dispatch(switchArticle(null))
|
if (activeArticle.status === NEW) dispatch(switchArticle(null))
|
||||||
dispatch(switchMode(IDLE_MODE))
|
dispatch(switchMode(IDLE_MODE))
|
||||||
}
|
}
|
||||||
@@ -236,6 +260,8 @@ export default class ArticleDetail extends React.Component {
|
|||||||
let folder = _.findWhere(folders, {key: article.FolderKey})
|
let folder = _.findWhere(folders, {key: article.FolderKey})
|
||||||
if (folder == null) return false
|
if (folder == null) return false
|
||||||
|
|
||||||
|
dispatch(unlockStatus())
|
||||||
|
|
||||||
delete newArticle.status
|
delete newArticle.status
|
||||||
newArticle.updatedAt = new Date()
|
newArticle.updatedAt = new Date()
|
||||||
if (newArticle.createdAt == null) {
|
if (newArticle.createdAt == null) {
|
||||||
@@ -263,19 +289,85 @@ export default class ArticleDetail extends React.Component {
|
|||||||
this.setState({article: article})
|
this.setState({article: article})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleTitleChange (e) {
|
||||||
|
let { article } = this.state
|
||||||
|
article.title = e.target.value
|
||||||
|
let _isTitleChanged = article.title !== this.props.activeArticle.title
|
||||||
|
|
||||||
|
let { isTagChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
|
||||||
|
let _isArticleEdited = _isTitleChanged || isTagChanged || isContentChanged || isModeChanged
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
article,
|
||||||
|
isTitleChanged: _isTitleChanged,
|
||||||
|
isArticleEdited: _isArticleEdited
|
||||||
|
}, () => {
|
||||||
|
if (isArticleEdited !== _isArticleEdited) {
|
||||||
|
let { dispatch } = this.props
|
||||||
|
if (_isArticleEdited) {
|
||||||
|
console.log('lockit')
|
||||||
|
dispatch(lockStatus())
|
||||||
|
} else {
|
||||||
|
console.log('unlockit')
|
||||||
|
dispatch(unlockStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
handleTagsChange (newTag, tags) {
|
handleTagsChange (newTag, tags) {
|
||||||
let article = this.state.article
|
let article = this.state.article
|
||||||
article.tags = tags
|
article.tags = tags
|
||||||
|
|
||||||
this.setState({article: article})
|
this.setState({article: article})
|
||||||
|
|
||||||
|
let _isTagChanged = _.difference(article.tags, this.props.activeArticle.tags).length > 0 || _.difference(this.props.activeArticle.tags, article.tags).length > 0
|
||||||
|
|
||||||
|
let { isTitleChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
|
||||||
|
let _isArticleEdited = _isTagChanged || isTitleChanged || isContentChanged || isModeChanged
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
article,
|
||||||
|
isTagChanged: _isTagChanged,
|
||||||
|
isArticleEdited: _isArticleEdited
|
||||||
|
}, () => {
|
||||||
|
if (isArticleEdited !== _isArticleEdited) {
|
||||||
|
let { dispatch } = this.props
|
||||||
|
if (_isArticleEdited) {
|
||||||
|
console.log('lockit')
|
||||||
|
dispatch(lockStatus())
|
||||||
|
} else {
|
||||||
|
console.log('unlockit')
|
||||||
|
dispatch(unlockStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModeChange (value) {
|
handleModeChange (value) {
|
||||||
let article = this.state.article
|
let { article } = this.state
|
||||||
article.mode = value
|
article.mode = value
|
||||||
|
let _isModeChanged = article.mode !== this.props.activeArticle.mode
|
||||||
|
|
||||||
|
let { isTagChanged, isContentChanged, isArticleEdited, isTitleChanged } = this.state
|
||||||
|
let _isArticleEdited = _isModeChanged || isTagChanged || isContentChanged || isTitleChanged
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
article: article,
|
article,
|
||||||
previewMode: false
|
previewMode: false,
|
||||||
|
isModeChanged: _isModeChanged,
|
||||||
|
isArticleEdited: _isArticleEdited
|
||||||
|
}, () => {
|
||||||
|
if (isArticleEdited !== _isArticleEdited) {
|
||||||
|
let { dispatch } = this.props
|
||||||
|
if (_isArticleEdited) {
|
||||||
|
console.log('lockit')
|
||||||
|
dispatch(lockStatus())
|
||||||
|
} else {
|
||||||
|
console.log('unlockit')
|
||||||
|
dispatch(unlockStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,9 +378,34 @@ export default class ArticleDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleContentChange (e, value) {
|
handleContentChange (e, value) {
|
||||||
let article = this.state.article
|
let { status } = this.props
|
||||||
|
if (status.mode === IDLE_MODE) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let { article } = this.state
|
||||||
article.content = value
|
article.content = value
|
||||||
this.setState({article: article})
|
let _isContentChanged = article.content !== this.props.activeArticle.content
|
||||||
|
|
||||||
|
let { isTagChanged, isModeChanged, isArticleEdited, isTitleChanged } = this.state
|
||||||
|
let _isArticleEdited = _isContentChanged || isTagChanged || isModeChanged || isTitleChanged
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
article,
|
||||||
|
isContentChanged: _isContentChanged,
|
||||||
|
isArticleEdited: _isArticleEdited
|
||||||
|
}, () => {
|
||||||
|
if (isArticleEdited !== _isArticleEdited) {
|
||||||
|
let { dispatch } = this.props
|
||||||
|
if (_isArticleEdited) {
|
||||||
|
console.log('lockit')
|
||||||
|
dispatch(lockStatus())
|
||||||
|
} else {
|
||||||
|
console.log('unlockit')
|
||||||
|
dispatch(unlockStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTogglePreviewButtonClick (e) {
|
handleTogglePreviewButtonClick (e) {
|
||||||
@@ -303,7 +420,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderEdit () {
|
renderEdit () {
|
||||||
let { folders, status } = this.props
|
let { folders, status, tags } = this.props
|
||||||
|
|
||||||
let folderOptions = folders.map(folder => {
|
let folderOptions = folders.map(folder => {
|
||||||
return (
|
return (
|
||||||
@@ -322,10 +439,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
>
|
>
|
||||||
{folderOptions}
|
{folderOptions}
|
||||||
</select>
|
</select>
|
||||||
|
{this.state.isArticleEdited ? ' (edited)' : ''}
|
||||||
|
|
||||||
<TagSelect
|
<TagSelect
|
||||||
tags={this.state.article.tags}
|
tags={this.state.article.tags}
|
||||||
onChange={(tags, tag) => this.handleTagsChange(tags, tag)}
|
onChange={(tags, tag) => this.handleTagsChange(tags, tag)}
|
||||||
|
suggestTags={tags}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{status.isTutorialOpen ? tagSelectTutorialElement : null}
|
{status.isTutorialOpen ? tagSelectTutorialElement : null}
|
||||||
@@ -346,7 +465,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='detailPanel'>
|
<div className='detailPanel'>
|
||||||
<div className='header'>
|
<div className='header'>
|
||||||
<div className='title'>
|
<div className='title'>
|
||||||
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' valueLink={this.linkState('article.title')}/>
|
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' value={this.state.article.title} onChange={e => this.handleTitleChange(e)}/>
|
||||||
</div>
|
</div>
|
||||||
<ModeSelect
|
<ModeSelect
|
||||||
ref='mode'
|
ref='mode'
|
||||||
@@ -395,6 +514,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
ArticleDetail.propTypes = {
|
ArticleDetail.propTypes = {
|
||||||
status: PropTypes.shape(),
|
status: PropTypes.shape(),
|
||||||
activeArticle: PropTypes.shape(),
|
activeArticle: PropTypes.shape(),
|
||||||
activeUser: PropTypes.shape()
|
activeUser: PropTypes.shape(),
|
||||||
|
dispatch: PropTypes.func
|
||||||
}
|
}
|
||||||
ArticleDetail.prototype.linkState = linkState
|
ArticleDetail.prototype.linkState = linkState
|
||||||
|
|||||||
@@ -88,16 +88,17 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { status, folders } = this.props
|
let { status, folders, allArticles } = this.props
|
||||||
let { targetFolders } = status
|
let { targetFolders } = status
|
||||||
if (targetFolders == null) targetFolders = []
|
if (targetFolders == null) targetFolders = []
|
||||||
|
|
||||||
let folderElememts = folders.map((folder, index) => {
|
let folderElememts = folders.map((folder, index) => {
|
||||||
let isActive = findWhere(targetFolders, {key: folder.key})
|
let isActive = findWhere(targetFolders, {key: folder.key})
|
||||||
|
let articleCount = allArticles.filter(article => article.FolderKey === folder.key).length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button onClick={e => this.handleFolderButtonClick(folder.name)(e)} key={'folder-' + folder.key} className={isActive ? 'active' : ''}>
|
<button onClick={e => this.handleFolderButtonClick(folder.name)(e)} key={'folder-' + folder.key} className={isActive ? 'active' : ''}>
|
||||||
<FolderMark color={folder.color}/> {folder.name}
|
<FolderMark color={folder.color}/> {folder.name} <span className='articleCount'>{articleCount}</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -150,6 +151,7 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
ArticleNavigator.propTypes = {
|
ArticleNavigator.propTypes = {
|
||||||
activeUser: PropTypes.object,
|
activeUser: PropTypes.object,
|
||||||
folders: PropTypes.array,
|
folders: PropTypes.array,
|
||||||
|
allArticles: PropTypes.array,
|
||||||
status: PropTypes.shape({
|
status: PropTypes.shape({
|
||||||
folderId: PropTypes.number
|
folderId: PropTypes.number
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ const searchTutorialElement = (
|
|||||||
<text x='450' y='33' fill={BRAND_COLOR} fontSize='24'>Search some posts!!</text>
|
<text x='450' y='33' fill={BRAND_COLOR} fontSize='24'>Search some posts!!</text>
|
||||||
<text x='450' y='60' fill={BRAND_COLOR} fontSize='18'>{'- Search by tag : #{string}'}</text>
|
<text x='450' y='60' fill={BRAND_COLOR} fontSize='18'>{'- Search by tag : #{string}'}</text>
|
||||||
<text x='450' y='85' fill={BRAND_COLOR} fontSize='18'>
|
<text x='450' y='85' fill={BRAND_COLOR} fontSize='18'>
|
||||||
{'- Search by folder : in:{folder_name}\n'}</text>
|
{'- Search by folder : /{folder_name}\n'}</text>
|
||||||
|
<text x='465' y='105' fill={BRAND_COLOR} fontSize='14'>
|
||||||
|
{'exact match : //{folder_name}'}</text>
|
||||||
|
|
||||||
<svg width='500' height='300'>
|
<svg width='500' height='300'>
|
||||||
<path fill='white' d='M54.5,51.5c-12.4,3.3-27.3-1.4-38.4-7C11.2,42,5,38.1,5.6,31.8c0.7-6.9,8.1-11.2,13.8-13.7
|
<path fill='white' d='M54.5,51.5c-12.4,3.3-27.3-1.4-38.4-7C11.2,42,5,38.1,5.6,31.8c0.7-6.9,8.1-11.2,13.8-13.7
|
||||||
@@ -117,7 +119,7 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
||||||
- Search by tag : #{'{string}'}<br/>
|
- Search by tag : #{'{string}'}<br/>
|
||||||
- Search by folder : in:{'{folder_name}'}
|
- Search by folder : /{'{folder_name}'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ require('../styles/main/index.styl')
|
|||||||
import { openModal } from 'boost/modal'
|
import { openModal } from 'boost/modal'
|
||||||
import Tutorial from 'boost/components/modal/Tutorial'
|
import Tutorial from 'boost/components/modal/Tutorial'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
import ipc from 'ipc'
|
||||||
|
|
||||||
activityRecord.init()
|
activityRecord.init()
|
||||||
|
window.addEventListener('online', function () {
|
||||||
|
ipc.send('check-update', 'check-update')
|
||||||
|
})
|
||||||
|
|
||||||
let routes = (
|
let routes = (
|
||||||
<Route path='/' component={MainPage}>
|
<Route path='/' component={MainPage}>
|
||||||
|
|||||||
@@ -79,6 +79,31 @@ body
|
|||||||
white-space nowrap
|
white-space nowrap
|
||||||
text-overflow ellipsis
|
text-overflow ellipsis
|
||||||
overflow-x hidden
|
overflow-x hidden
|
||||||
|
clearfix()
|
||||||
|
.left
|
||||||
|
float left
|
||||||
|
.right
|
||||||
|
float right
|
||||||
|
button
|
||||||
|
border-radius 16.5px
|
||||||
|
cursor pointer
|
||||||
|
height 33px
|
||||||
|
width 33px
|
||||||
|
border none
|
||||||
|
margin-right 5px
|
||||||
|
font-size 18px
|
||||||
|
color inactiveTextColor
|
||||||
|
background-color transparent
|
||||||
|
padding 0
|
||||||
|
.tooltip
|
||||||
|
tooltip()
|
||||||
|
&.clipboardBtn .tooltip
|
||||||
|
margin-left -160px
|
||||||
|
margin-top 25px
|
||||||
|
&:hover
|
||||||
|
color textColor
|
||||||
|
.tooltip
|
||||||
|
opacity 1
|
||||||
.content
|
.content
|
||||||
position absolute
|
position absolute
|
||||||
top 55px
|
top 55px
|
||||||
|
|||||||
@@ -98,44 +98,66 @@ iptFocusBorderColor = #369DCD
|
|||||||
&:hover
|
&:hover
|
||||||
background-color white
|
background-color white
|
||||||
.TagSelect
|
.TagSelect
|
||||||
white-space nowrap
|
.tags
|
||||||
overflow-x auto
|
white-space nowrap
|
||||||
position relative
|
overflow-x auto
|
||||||
margin-top 5px
|
position relative
|
||||||
noSelect()
|
max-width 350px
|
||||||
z-index 30
|
margin-top 5px
|
||||||
background-color #E6E6E6
|
noSelect()
|
||||||
.tagItem
|
z-index 30
|
||||||
background-color brandColor
|
background-color #E6E6E6
|
||||||
border-radius 2px
|
.tagItem
|
||||||
color white
|
background-color brandColor
|
||||||
margin 0 2px
|
border-radius 2px
|
||||||
padding 0
|
|
||||||
border 1px solid darken(brandColor, 10%)
|
|
||||||
button.tagRemoveBtn
|
|
||||||
color white
|
color white
|
||||||
|
margin 0 2px
|
||||||
|
padding 0
|
||||||
|
border 1px solid darken(brandColor, 10%)
|
||||||
|
button.tagRemoveBtn
|
||||||
|
color white
|
||||||
|
border-radius 2px
|
||||||
|
border none
|
||||||
|
background-color transparent
|
||||||
|
padding 4px 2px
|
||||||
|
border-right 1px solid #E6E6E6
|
||||||
|
font-size 8px
|
||||||
|
line-height 12px
|
||||||
|
transition 0.1s
|
||||||
|
&:hover
|
||||||
|
background-color lighten(brandColor, 10%)
|
||||||
|
.tagLabel
|
||||||
|
padding 4px 4px
|
||||||
|
font-size 12px
|
||||||
|
line-height 12px
|
||||||
|
input.tagInput
|
||||||
|
background-color transparent
|
||||||
|
outline none
|
||||||
|
margin 0 2px
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
border none
|
border none
|
||||||
background-color transparent
|
|
||||||
padding 4px 2px
|
|
||||||
border-right 1px solid #E6E6E6
|
|
||||||
font-size 8px
|
|
||||||
line-height 12px
|
|
||||||
transition 0.1s
|
transition 0.1s
|
||||||
|
height 18px
|
||||||
|
.suggestTags
|
||||||
|
position fixed
|
||||||
|
width 150px
|
||||||
|
max-height 150px
|
||||||
|
background-color white
|
||||||
|
z-index 5
|
||||||
|
border 1px solid borderColor
|
||||||
|
border-radius 5px
|
||||||
|
button
|
||||||
|
width 100%
|
||||||
|
display block
|
||||||
|
padding 0 15px
|
||||||
|
height 33px
|
||||||
|
line-height 33px
|
||||||
|
background-color transparent
|
||||||
|
border none
|
||||||
|
text-align left
|
||||||
|
font-size 14px
|
||||||
&:hover
|
&:hover
|
||||||
background-color lighten(brandColor, 10%)
|
background-color darken(white, 10%)
|
||||||
.tagLabel
|
|
||||||
padding 4px 4px
|
|
||||||
font-size 12px
|
|
||||||
line-height 12px
|
|
||||||
input.tagInput
|
|
||||||
background-color transparent
|
|
||||||
outline none
|
|
||||||
margin 0 2px
|
|
||||||
border-radius 2px
|
|
||||||
border none
|
|
||||||
transition 0.1s
|
|
||||||
height 18px
|
|
||||||
.right
|
.right
|
||||||
button
|
button
|
||||||
cursor pointer
|
cursor pointer
|
||||||
@@ -222,9 +244,6 @@ iptFocusBorderColor = #369DCD
|
|||||||
display inline-block
|
display inline-block
|
||||||
&:hover
|
&:hover
|
||||||
background-color darken(white, 10%)
|
background-color darken(white, 10%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.title
|
.title
|
||||||
absolute left top bottom
|
absolute left top bottom
|
||||||
right 150px
|
right 150px
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
articleNavBgColor = #353535
|
articleNavBgColor = #353535
|
||||||
|
articleCount = #999
|
||||||
|
|
||||||
.ArticleNavigator
|
.ArticleNavigator
|
||||||
background-color articleNavBgColor
|
background-color articleNavBgColor
|
||||||
@@ -149,7 +150,10 @@ articleNavBgColor = #353535
|
|||||||
&:hover
|
&:hover
|
||||||
background-color transparentify(white, 5%)
|
background-color transparentify(white, 5%)
|
||||||
&.active, &:active
|
&.active, &:active
|
||||||
background-color brandColor
|
background-color transparentify(lighten(brandColor, 25%), 70%)
|
||||||
|
.articleCount
|
||||||
|
color articleCount
|
||||||
|
font-size 12px
|
||||||
.members
|
.members
|
||||||
.memberList>div
|
.memberList>div
|
||||||
height 33px
|
height 33px
|
||||||
|
|||||||
@@ -9,3 +9,4 @@
|
|||||||
@require './lib/CreateNewFolder'
|
@require './lib/CreateNewFolder'
|
||||||
@require './lib/Preferences'
|
@require './lib/Preferences'
|
||||||
@require './lib/Tutorial'
|
@require './lib/Tutorial'
|
||||||
|
@require './lib/EditedAlert'
|
||||||
|
|||||||
@@ -34,9 +34,30 @@ iptFocusBorderColor = #369DCD
|
|||||||
border-radius 5px
|
border-radius 5px
|
||||||
border solid 1px borderColor
|
border solid 1px borderColor
|
||||||
outline none
|
outline none
|
||||||
margin 100px auto 25px
|
margin 75px auto 20px
|
||||||
&:focus
|
&:focus
|
||||||
border-color iptFocusBorderColor
|
border-color iptFocusBorderColor
|
||||||
|
.colorSelect
|
||||||
|
text-align center
|
||||||
|
.option
|
||||||
|
cursor pointer
|
||||||
|
font-size 22px
|
||||||
|
height 48px
|
||||||
|
width 48px
|
||||||
|
margin 0 2px
|
||||||
|
border 1px solid transparent
|
||||||
|
border-radius 5px
|
||||||
|
overflow hidden
|
||||||
|
line-height 45px
|
||||||
|
text-align center
|
||||||
|
transition 0.1s
|
||||||
|
display inline-block
|
||||||
|
&:hover
|
||||||
|
border-color borderColor
|
||||||
|
font-size 28px
|
||||||
|
&.active
|
||||||
|
font-size 28px
|
||||||
|
border-color iptFocusBorderColor
|
||||||
.alert
|
.alert
|
||||||
color infoTextColor
|
color infoTextColor
|
||||||
background-color infoBackgroundColor
|
background-color infoBackgroundColor
|
||||||
@@ -44,7 +65,7 @@ iptFocusBorderColor = #369DCD
|
|||||||
padding 15px 15px
|
padding 15px 15px
|
||||||
width 330px
|
width 330px
|
||||||
border-radius 5px
|
border-radius 5px
|
||||||
margin 0 auto
|
margin 15px auto 0
|
||||||
&.error
|
&.error
|
||||||
color errorTextColor
|
color errorTextColor
|
||||||
background-color errorBackgroundColor
|
background-color errorBackgroundColor
|
||||||
|
|||||||
28
browser/styles/main/HomeContainer/lib/EditedAlert.styl
Normal file
28
browser/styles/main/HomeContainer/lib/EditedAlert.styl
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
.EditedAlert.modal
|
||||||
|
width 350px
|
||||||
|
top 100px
|
||||||
|
.title
|
||||||
|
font-size 24px
|
||||||
|
margin-bottom 15px
|
||||||
|
.message
|
||||||
|
font-size 14px
|
||||||
|
margin-bottom 15px
|
||||||
|
.control
|
||||||
|
text-align right
|
||||||
|
button
|
||||||
|
border-radius 5px
|
||||||
|
height 33px
|
||||||
|
padding 0 15px
|
||||||
|
font-size 14px
|
||||||
|
background-color white
|
||||||
|
border 1px solid borderColor
|
||||||
|
border-radius 5px
|
||||||
|
margin-left 5px
|
||||||
|
&:hover
|
||||||
|
background-color darken(white, 10%)
|
||||||
|
&.primary
|
||||||
|
border-color brandColor
|
||||||
|
background-color brandColor
|
||||||
|
color white
|
||||||
|
&:hover
|
||||||
|
background-color lighten(brandColor, 10%)
|
||||||
@@ -440,19 +440,22 @@ iptFocusBorderColor = #369DCD
|
|||||||
padding 5px 0
|
padding 5px 0
|
||||||
&:last-child
|
&:last-child
|
||||||
border-color transparent
|
border-color transparent
|
||||||
|
.folderColor
|
||||||
|
float left
|
||||||
|
margin-left 10px
|
||||||
|
text-align center
|
||||||
|
width 44px
|
||||||
.folderName
|
.folderName
|
||||||
float left
|
float left
|
||||||
width 175px
|
width 175px
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
padding-left 15px
|
|
||||||
.folderPublic
|
|
||||||
float left
|
|
||||||
text-align center
|
|
||||||
width 100px
|
|
||||||
.folderControl
|
.folderControl
|
||||||
float right
|
float right
|
||||||
width 145px
|
width 125px
|
||||||
text-align center
|
text-align center
|
||||||
|
&.folderHeader
|
||||||
|
.folderName
|
||||||
|
padding-left 25px
|
||||||
&.newFolder
|
&.newFolder
|
||||||
.alert
|
.alert
|
||||||
display block
|
display block
|
||||||
@@ -502,6 +505,30 @@ iptFocusBorderColor = #369DCD
|
|||||||
&:hover
|
&:hover
|
||||||
color lighten(brandColor, 10%)
|
color lighten(brandColor, 10%)
|
||||||
&.FolderRow
|
&.FolderRow
|
||||||
|
.sortBtns
|
||||||
|
float left
|
||||||
|
display block
|
||||||
|
height 30px
|
||||||
|
width 30px
|
||||||
|
margin-top 1.5px
|
||||||
|
position absolute
|
||||||
|
button
|
||||||
|
absolute left
|
||||||
|
background-color transparent
|
||||||
|
border none
|
||||||
|
height 15px
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
color stripBtnColor
|
||||||
|
&:first-child
|
||||||
|
top 0
|
||||||
|
&:last-child
|
||||||
|
top 15px
|
||||||
|
&:hover
|
||||||
|
color stripHoverBtnColor
|
||||||
|
&:disabled
|
||||||
|
color lighten(stripBtnColor, 10%)
|
||||||
|
cursor not-allowed
|
||||||
.folderName input
|
.folderName input
|
||||||
height 33px
|
height 33px
|
||||||
border 1px solid borderColor
|
border 1px solid borderColor
|
||||||
@@ -512,16 +539,52 @@ iptFocusBorderColor = #369DCD
|
|||||||
width 150px
|
width 150px
|
||||||
&:focus
|
&:focus
|
||||||
border-color iptFocusBorderColor
|
border-color iptFocusBorderColor
|
||||||
.folderPublic select
|
.folderColor
|
||||||
height 33px
|
.select
|
||||||
border 1px solid borderColor
|
height 33px
|
||||||
background-color white
|
width 33px
|
||||||
outline none
|
border 1px solid borderColor
|
||||||
display block
|
background-color white
|
||||||
margin 0 auto
|
outline none
|
||||||
font-size 14px
|
display block
|
||||||
&:focus
|
margin 0 auto
|
||||||
border-color iptFocusBorderColor
|
font-size 14px
|
||||||
|
border-radius 5px
|
||||||
|
&:focus
|
||||||
|
border-color iptFocusBorderColor
|
||||||
|
.options
|
||||||
|
position absolute
|
||||||
|
background-color white
|
||||||
|
text-align left
|
||||||
|
border 1px solid borderColor
|
||||||
|
border-radius 5px
|
||||||
|
padding 0 5px 5px
|
||||||
|
margin-left 5px
|
||||||
|
margin-top -34px
|
||||||
|
clearfix()
|
||||||
|
.label
|
||||||
|
margin-left 5px
|
||||||
|
line-height 22px
|
||||||
|
font-size 12px
|
||||||
|
button
|
||||||
|
float left
|
||||||
|
border none
|
||||||
|
width 33px
|
||||||
|
height 33px
|
||||||
|
margin-right 5px
|
||||||
|
border 1px solid transparent
|
||||||
|
line-height 29px
|
||||||
|
overflow hidden
|
||||||
|
border-radius 5px
|
||||||
|
background-color transparent
|
||||||
|
outline none
|
||||||
|
transition 0.1s
|
||||||
|
&:hover
|
||||||
|
border-color borderColor
|
||||||
|
&.active
|
||||||
|
border-color iptFocusBorderColor
|
||||||
|
.FolderMark
|
||||||
|
transform scale(1.4)
|
||||||
.folderControl
|
.folderControl
|
||||||
button
|
button
|
||||||
border none
|
border none
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ slideBgColor4 = #00B493
|
|||||||
height 140px
|
height 140px
|
||||||
.slide3
|
.slide3
|
||||||
background-color slideBgColor3
|
background-color slideBgColor3
|
||||||
|
.title
|
||||||
|
margin-bottom 15px
|
||||||
.content
|
.content
|
||||||
font-size 18px
|
font-size 18px
|
||||||
&>img
|
&>img
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
|
|||||||
export const FOLDER_CREATE = 'FOLDER_CREATE'
|
export const FOLDER_CREATE = 'FOLDER_CREATE'
|
||||||
export const FOLDER_UPDATE = 'FOLDER_UPDATE'
|
export const FOLDER_UPDATE = 'FOLDER_UPDATE'
|
||||||
export const FOLDER_DESTROY = 'FOLDER_DESTROY'
|
export const FOLDER_DESTROY = 'FOLDER_DESTROY'
|
||||||
|
export const FOLDER_REPLACE = 'FOLDER_REPLACE'
|
||||||
|
|
||||||
export const SWITCH_FOLDER = 'SWITCH_FOLDER'
|
export const SWITCH_FOLDER = 'SWITCH_FOLDER'
|
||||||
export const SWITCH_MODE = 'SWITCH_MODE'
|
export const SWITCH_MODE = 'SWITCH_MODE'
|
||||||
@@ -11,6 +12,8 @@ export const SWITCH_ARTICLE = 'SWITCH_ARTICLE'
|
|||||||
export const SET_SEARCH_FILTER = 'SET_SEARCH_FILTER'
|
export const SET_SEARCH_FILTER = 'SET_SEARCH_FILTER'
|
||||||
export const SET_TAG_FILTER = 'SET_TAG_FILTER'
|
export const SET_TAG_FILTER = 'SET_TAG_FILTER'
|
||||||
export const CLEAR_SEARCH = 'CLEAR_SEARCH'
|
export const CLEAR_SEARCH = 'CLEAR_SEARCH'
|
||||||
|
export const LOCK_STATUS = 'LOCK_STATUS'
|
||||||
|
export const UNLOCK_STATUS = 'UNLOCK_STATUS'
|
||||||
export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
|
export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
|
||||||
|
|
||||||
// Status - mode
|
// Status - mode
|
||||||
@@ -57,6 +60,16 @@ export function destroyFolder (key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function replaceFolder (a, b) {
|
||||||
|
return {
|
||||||
|
type: FOLDER_REPLACE,
|
||||||
|
data: {
|
||||||
|
a,
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function switchFolder (folderName) {
|
export function switchFolder (folderName) {
|
||||||
return {
|
return {
|
||||||
type: SWITCH_FOLDER,
|
type: SWITCH_FOLDER,
|
||||||
@@ -98,7 +111,19 @@ export function clearSearch () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toggleTutorial() {
|
export function lockStatus () {
|
||||||
|
return {
|
||||||
|
type: LOCK_STATUS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unlockStatus () {
|
||||||
|
return {
|
||||||
|
type: UNLOCK_STATUS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleTutorial () {
|
||||||
return {
|
return {
|
||||||
type: TOGGLE_TUTORIAL
|
type: TOGGLE_TUTORIAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,45 +3,50 @@ import React, { PropTypes } from 'react'
|
|||||||
const BLUE = '#3460C7'
|
const BLUE = '#3460C7'
|
||||||
const LIGHTBLUE = '#2BA5F7'
|
const LIGHTBLUE = '#2BA5F7'
|
||||||
const ORANGE = '#FF8E00'
|
const ORANGE = '#FF8E00'
|
||||||
const YELLOW = '#EAEF31'
|
const YELLOW = '#E8D252'
|
||||||
const GREEN = '#02FF26'
|
const GREEN = '#3FD941'
|
||||||
const DARKGREEN = '#008A59'
|
const DARKGREEN = '#1FAD85'
|
||||||
const RED = '#E10051'
|
const RED = '#E10051'
|
||||||
const PURPLE = '#B013A4'
|
const PURPLE = '#B013A4'
|
||||||
const BRAND_COLOR = '#2BAC8F'
|
|
||||||
|
|
||||||
function getColorByIndex (index) {
|
function getColorByIndex (index) {
|
||||||
switch (index % 8) {
|
switch (index % 8) {
|
||||||
case 0:
|
case 0:
|
||||||
return LIGHTBLUE
|
return RED
|
||||||
case 1:
|
case 1:
|
||||||
return ORANGE
|
return ORANGE
|
||||||
case 2:
|
case 2:
|
||||||
return RED
|
return YELLOW
|
||||||
case 3:
|
case 3:
|
||||||
return GREEN
|
return GREEN
|
||||||
case 4:
|
case 4:
|
||||||
return DARKGREEN
|
return DARKGREEN
|
||||||
case 5:
|
case 5:
|
||||||
return YELLOW
|
return LIGHTBLUE
|
||||||
case 6:
|
case 6:
|
||||||
return BLUE
|
return BLUE
|
||||||
case 7:
|
case 7:
|
||||||
return PURPLE
|
return PURPLE
|
||||||
default:
|
default:
|
||||||
return BRAND_COLOR
|
return DARKGREEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class FolderMark extends React.Component {
|
export default class FolderMark extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
let color = getColorByIndex(this.props.color)
|
let color = getColorByIndex(this.props.color)
|
||||||
|
let className = 'FolderMark fa fa-square fa-fw'
|
||||||
|
if (this.props.className != null) {
|
||||||
|
className += ' active'
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<i className='fa fa-square fa-fw' style={{color: color}}/>
|
<i className={className} style={{color: color}}/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderMark.propTypes = {
|
FolderMark.propTypes = {
|
||||||
color: PropTypes.number
|
color: PropTypes.number,
|
||||||
|
className: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default class ModeSelect extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount (e) {
|
componentDidMount () {
|
||||||
this.blurHandler = e => {
|
this.blurHandler = e => {
|
||||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||||
if (this.state.mode === EDIT_MODE && document.activeElement !== searchElement) {
|
if (this.state.mode === EDIT_MODE && document.activeElement !== searchElement) {
|
||||||
@@ -28,7 +28,7 @@ export default class ModeSelect extends React.Component {
|
|||||||
window.addEventListener('click', this.blurHandler)
|
window.addEventListener('click', this.blurHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount (e) {
|
componentWillUnmount () {
|
||||||
window.removeEventListener('click', this.blurHandler)
|
window.removeEventListener('click', this.blurHandler)
|
||||||
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
let searchElement = ReactDOM.findDOMNode(this.refs.search)
|
||||||
if (searchElement != null && this.searchKeyDownListener != null) {
|
if (searchElement != null && this.searchKeyDownListener != null) {
|
||||||
|
|||||||
@@ -3,23 +3,54 @@ import ReactDOM from 'react-dom'
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
|
|
||||||
|
function isNotEmptyString (str) {
|
||||||
|
return _.isString(str) && str.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
export default class TagSelect extends React.Component {
|
export default class TagSelect extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
input: ''
|
input: '',
|
||||||
|
isInputFocused: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown (e) {
|
componentDidMount () {
|
||||||
if (e.keyCode !== 13) return false
|
this.blurInputBlurHandler = e => {
|
||||||
e.preventDefault()
|
if (ReactDOM.findDOMNode(this.refs.tagInput) !== document.activeElement) {
|
||||||
|
this.setState({isInputFocused: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.addEventListener('click', this.blurInputBlurHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount (e) {
|
||||||
|
window.removeEventListener('click', this.blurInputBlurHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suggestは必ずInputの下に位置するようにする
|
||||||
|
componentDidUpdate () {
|
||||||
|
if (this.shouldShowSuggest()) {
|
||||||
|
let inputRect = ReactDOM.findDOMNode(this.refs.tagInput).getBoundingClientRect()
|
||||||
|
let suggestElement = ReactDOM.findDOMNode(this.refs.suggestTags)
|
||||||
|
if (suggestElement != null) {
|
||||||
|
suggestElement.style.top = inputRect.top + 20 + 'px'
|
||||||
|
suggestElement.style.left = inputRect.left + 'px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldShowSuggest () {
|
||||||
|
return this.state.isInputFocused && isNotEmptyString(this.state.input)
|
||||||
|
}
|
||||||
|
|
||||||
|
addTag (tag, clearInput = true) {
|
||||||
let tags = this.props.tags.slice(0)
|
let tags = this.props.tags.slice(0)
|
||||||
let newTag = this.state.input.trim()
|
let newTag = tag.trim()
|
||||||
|
|
||||||
if (newTag.length === 0) {
|
if (newTag.length === 0 && clearInput) {
|
||||||
this.setState({input: ''})
|
this.setState({input: ''})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -30,13 +61,38 @@ export default class TagSelect extends React.Component {
|
|||||||
if (_.isFunction(this.props.onChange)) {
|
if (_.isFunction(this.props.onChange)) {
|
||||||
this.props.onChange(newTag, tags)
|
this.props.onChange(newTag, tags)
|
||||||
}
|
}
|
||||||
this.setState({input: ''})
|
if (clearInput) this.setState({input: ''})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown (e) {
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
if (this.state.input.length > 0) break
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
let tags = this.props.tags.slice(0)
|
||||||
|
tags.pop()
|
||||||
|
|
||||||
|
this.props.onChange(null, tags)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 13:
|
||||||
|
{
|
||||||
|
e.preventDefault()
|
||||||
|
this.addTag(this.state.input)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleThisClick (e) {
|
handleThisClick (e) {
|
||||||
ReactDOM.findDOMNode(this.refs.tagInput).focus()
|
ReactDOM.findDOMNode(this.refs.tagInput).focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleInputFocus (e) {
|
||||||
|
this.setState({isInputFocused: true})
|
||||||
|
}
|
||||||
|
|
||||||
handleItemRemoveButton (tag) {
|
handleItemRemoveButton (tag) {
|
||||||
return e => {
|
return e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@@ -50,8 +106,16 @@ export default class TagSelect extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSuggestClick (tag) {
|
||||||
|
return e => {
|
||||||
|
this.addTag(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
var tagElements = _.isArray(this.props.tags)
|
let { tags, suggestTags } = this.props
|
||||||
|
|
||||||
|
let tagElements = _.isArray(tags)
|
||||||
? this.props.tags.map(tag => (
|
? this.props.tags.map(tag => (
|
||||||
<span key={tag} className='tagItem'>
|
<span key={tag} className='tagItem'>
|
||||||
<button onClick={e => this.handleItemRemoveButton(tag)(e)} className='tagRemoveBtn'><i className='fa fa-fw fa-times'/></button>
|
<button onClick={e => this.handleItemRemoveButton(tag)(e)} className='tagRemoveBtn'><i className='fa fa-fw fa-times'/></button>
|
||||||
@@ -59,16 +123,37 @@ export default class TagSelect extends React.Component {
|
|||||||
</span>))
|
</span>))
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
let suggestElements = this.shouldShowSuggest() ? suggestTags
|
||||||
|
.filter(tag => {
|
||||||
|
return tag.match(this.state.input)
|
||||||
|
})
|
||||||
|
.map(tag => {
|
||||||
|
return <button onClick={e => this.handleSuggestClick(tag)(e)} key={tag}>{tag}</button>
|
||||||
|
})
|
||||||
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='TagSelect' onClick={e => this.handleThisClick(e)}>
|
<div className='TagSelect' onClick={e => this.handleThisClick(e)}>
|
||||||
{tagElements}
|
<div className='tags'>
|
||||||
<input
|
{tagElements}
|
||||||
type='text'
|
<input
|
||||||
onKeyDown={e => this.handleKeyDown(e)}
|
type='text'
|
||||||
ref='tagInput'
|
onKeyDown={e => this.handleKeyDown(e)}
|
||||||
valueLink={this.linkState('input')}
|
ref='tagInput'
|
||||||
placeholder='Click here to add tags'
|
valueLink={this.linkState('input')}
|
||||||
className='tagInput'/>
|
placeholder='Click here to add tags'
|
||||||
|
className='tagInput'
|
||||||
|
onFocus={e => this.handleInputFocus(e)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{suggestElements != null && suggestElements.length > 0
|
||||||
|
? (
|
||||||
|
<div ref='suggestTags' className='suggestTags'>
|
||||||
|
{suggestElements}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -76,7 +161,8 @@ export default class TagSelect extends React.Component {
|
|||||||
|
|
||||||
TagSelect.propTypes = {
|
TagSelect.propTypes = {
|
||||||
tags: PropTypes.arrayOf(PropTypes.string),
|
tags: PropTypes.arrayOf(PropTypes.string),
|
||||||
onChange: PropTypes.func
|
onChange: PropTypes.func,
|
||||||
|
suggestTags: PropTypes.array
|
||||||
}
|
}
|
||||||
|
|
||||||
TagSelect.prototype.linkState = linkState
|
TagSelect.prototype.linkState = linkState
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { PropTypes } from 'react'
|
|||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import { createFolder } from 'boost/actions'
|
import { createFolder } from 'boost/actions'
|
||||||
import store from 'boost/store'
|
import store from 'boost/store'
|
||||||
|
import FolderMark from 'boost/components/FolderMark'
|
||||||
|
|
||||||
export default class CreateNewFolder extends React.Component {
|
export default class CreateNewFolder extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -9,6 +10,7 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
name: '',
|
name: '',
|
||||||
|
color: Math.round(Math.random() * 7),
|
||||||
alert: null
|
alert: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,9 +22,11 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
handleConfirmButton (e) {
|
handleConfirmButton (e) {
|
||||||
this.setState({alert: null}, () => {
|
this.setState({alert: null}, () => {
|
||||||
let { close } = this.props
|
let { close } = this.props
|
||||||
let name = this.state.name
|
let { name, color } = this.state
|
||||||
|
|
||||||
let input = {
|
let input = {
|
||||||
name
|
name,
|
||||||
|
color
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -38,6 +42,20 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleColorClick (colorIndex) {
|
||||||
|
return e => {
|
||||||
|
this.setState({
|
||||||
|
color: colorIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
this.handleConfirmButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let alert = this.state.alert
|
let alert = this.state.alert
|
||||||
let alertElement = alert != null ? (
|
let alertElement = alert != null ? (
|
||||||
@@ -45,6 +63,20 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
{alert.message}
|
{alert.message}
|
||||||
</p>
|
</p>
|
||||||
) : null
|
) : null
|
||||||
|
let colorIndexes = []
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
colorIndexes.push(i)
|
||||||
|
}
|
||||||
|
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)}>
|
||||||
|
<FolderMark color={index}/>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='CreateNewFolder modal'>
|
<div className='CreateNewFolder modal'>
|
||||||
@@ -52,7 +84,10 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
|
|
||||||
<div className='title'>Create new folder</div>
|
<div className='title'>Create new folder</div>
|
||||||
|
|
||||||
<input className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
<input onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
||||||
|
<div className='colorSelect'>
|
||||||
|
{colorElements}
|
||||||
|
</div>
|
||||||
{alertElement}
|
{alertElement}
|
||||||
|
|
||||||
<button onClick={e => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
<button onClick={e => this.handleConfirmButton(e)} className='confirmBtn'>Create</button>
|
||||||
|
|||||||
35
lib/components/modal/EditedAlert.js
Normal file
35
lib/components/modal/EditedAlert.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { PropTypes } from 'react'
|
||||||
|
import store from 'boost/store'
|
||||||
|
import { unlockStatus } from 'boost/actions'
|
||||||
|
|
||||||
|
export default class EditedAlert extends React.Component {
|
||||||
|
handleNoButtonClick (e) {
|
||||||
|
this.props.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleYesButtonClick (e) {
|
||||||
|
store.dispatch(unlockStatus())
|
||||||
|
store.dispatch(this.props.action)
|
||||||
|
this.props.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className='EditedAlert modal'>
|
||||||
|
<div className='title'>Your article is still editing!</div>
|
||||||
|
|
||||||
|
<div className='message'>Do you really want to leave without finishing?</div>
|
||||||
|
|
||||||
|
<div className='control'>
|
||||||
|
<button onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
|
||||||
|
<button onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditedAlert.propTypes = {
|
||||||
|
action: PropTypes.object,
|
||||||
|
close: PropTypes.func
|
||||||
|
}
|
||||||
@@ -36,12 +36,20 @@ export default class AppSettingTab extends React.Component {
|
|||||||
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSaveButtonClick (e) {
|
submitHotKey () {
|
||||||
ipc.send('hotkeyUpdated', {
|
ipc.send('hotkeyUpdated', {
|
||||||
toggleFinder: this.state.toggleFinder
|
toggleFinder: this.state.toggleFinder
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSaveButtonClick (e) {
|
||||||
|
this.submitHotKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown (e) {
|
||||||
|
this.submitHotKey()
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let alert = this.state.alert
|
let alert = this.state.alert
|
||||||
let alertElement = alert != null ? (
|
let alertElement = alert != null ? (
|
||||||
@@ -56,7 +64,7 @@ export default class AppSettingTab extends React.Component {
|
|||||||
<div className='sectionTitle'>Hotkey</div>
|
<div className='sectionTitle'>Hotkey</div>
|
||||||
<div className='sectionInput'>
|
<div className='sectionInput'>
|
||||||
<label>Toggle Finder(popup)</label>
|
<label>Toggle Finder(popup)</label>
|
||||||
<input valueLink={this.linkState('toggleFinder')} type='text'/>
|
<input onKeyDown={e => this.handleKeyDown(e)} valueLink={this.linkState('toggleFinder')} type='text'/>
|
||||||
</div>
|
</div>
|
||||||
<div className='sectionConfirm'>
|
<div className='sectionConfirm'>
|
||||||
<button onClick={e => this.handleSaveButtonClick(e)}>Save</button>
|
<button onClick={e => this.handleSaveButtonClick(e)}>Save</button>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { PropTypes } from 'react'
|
|||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import FolderMark from 'boost/components/FolderMark'
|
import FolderMark from 'boost/components/FolderMark'
|
||||||
import store from 'boost/store'
|
import store from 'boost/store'
|
||||||
import { updateFolder, destroyFolder } from 'boost/actions'
|
import { updateFolder, destroyFolder, replaceFolder } from 'boost/actions'
|
||||||
|
|
||||||
const IDLE = 'IDLE'
|
const IDLE = 'IDLE'
|
||||||
const EDIT = 'EDIT'
|
const EDIT = 'EDIT'
|
||||||
@@ -17,6 +17,20 @@ export default class FolderRow extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUpClick (e) {
|
||||||
|
let { index } = this.props
|
||||||
|
if (index > 0) {
|
||||||
|
store.dispatch(replaceFolder(index, index - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDownClick (e) {
|
||||||
|
let { index, count } = this.props
|
||||||
|
if (index < count - 1) {
|
||||||
|
store.dispatch(replaceFolder(index, index + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleCancelButtonClick (e) {
|
handleCancelButtonClick (e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
mode: IDLE
|
mode: IDLE
|
||||||
@@ -26,7 +40,9 @@ export default class FolderRow extends React.Component {
|
|||||||
handleEditButtonClick (e) {
|
handleEditButtonClick (e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
mode: EDIT,
|
mode: EDIT,
|
||||||
name: this.props.folder.name
|
name: this.props.folder.name,
|
||||||
|
color: this.props.folder.color,
|
||||||
|
isColorEditing: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,12 +50,34 @@ export default class FolderRow extends React.Component {
|
|||||||
this.setState({mode: DELETE})
|
this.setState({mode: DELETE})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleNameInputKeyDown (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
this.handleSaveButtonClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorSelectClick (e) {
|
||||||
|
this.setState({
|
||||||
|
isColorEditing: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorButtonClick (index) {
|
||||||
|
return e => {
|
||||||
|
this.setState({
|
||||||
|
color: index,
|
||||||
|
isColorEditing: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSaveButtonClick (e) {
|
handleSaveButtonClick (e) {
|
||||||
let { folder, setAlert } = this.props
|
let { folder, setAlert } = this.props
|
||||||
|
|
||||||
setAlert(null, () => {
|
setAlert(null, () => {
|
||||||
let input = {
|
let input = {
|
||||||
name: this.state.name
|
name: this.state.name,
|
||||||
|
color: this.state.color
|
||||||
}
|
}
|
||||||
folder = Object.assign({}, folder, input)
|
folder = Object.assign({}, folder, input)
|
||||||
|
|
||||||
@@ -68,10 +106,40 @@ export default class FolderRow extends React.Component {
|
|||||||
|
|
||||||
switch (this.state.mode) {
|
switch (this.state.mode) {
|
||||||
case EDIT:
|
case EDIT:
|
||||||
|
let colorIndexes = []
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
colorIndexes.push(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorOptions = colorIndexes.map(index => {
|
||||||
|
let className = this.state.color === index
|
||||||
|
? 'active'
|
||||||
|
: null
|
||||||
|
return (
|
||||||
|
<button onClick={e => this.handleColorButtonClick(index)(e)} className={className} key={index}>
|
||||||
|
<FolderMark color={index}/>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='FolderRow edit'>
|
<div className='FolderRow edit'>
|
||||||
|
<div className='folderColor'>
|
||||||
|
<button onClick={e => this.handleColorSelectClick(e)} className='select'>
|
||||||
|
<FolderMark color={this.state.color}/>
|
||||||
|
</button>
|
||||||
|
{this.state.isColorEditing
|
||||||
|
? (
|
||||||
|
<div className='options'>
|
||||||
|
<div className='label'>Color select</div>
|
||||||
|
{colorOptions}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
<div className='folderName'>
|
<div className='folderName'>
|
||||||
<input valueLink={this.linkState('name')} type='text'/>
|
<input onKeyDown={e => this.handleNameInputKeyDown(e)} valueLink={this.linkState('name')} type='text'/>
|
||||||
</div>
|
</div>
|
||||||
<div className='folderControl'>
|
<div className='folderControl'>
|
||||||
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Save</button>
|
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Save</button>
|
||||||
@@ -93,7 +161,12 @@ export default class FolderRow extends React.Component {
|
|||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<div className='FolderRow'>
|
<div className='FolderRow'>
|
||||||
<div className='folderName'><FolderMark color={folder.color}/> {folder.name}</div>
|
<div className='sortBtns'>
|
||||||
|
<button onClick={e => this.handleUpClick(e)}><i className='fa fa-sort-up fa-fw'/></button>
|
||||||
|
<button onClick={e => this.handleDownClick(e)}><i className='fa fa-sort-down fa-fw'/></button>
|
||||||
|
</div>
|
||||||
|
<div className='folderColor'><FolderMark color={folder.color}/></div>
|
||||||
|
<div className='folderName'>{folder.name}</div>
|
||||||
<div className='folderControl'>
|
<div className='folderControl'>
|
||||||
<button onClick={e => this.handleEditButtonClick(e)}><i className='fa fa-fw fa-edit'/></button>
|
<button onClick={e => this.handleEditButtonClick(e)}><i className='fa fa-fw fa-edit'/></button>
|
||||||
<button onClick={e => this.handleDeleteButtonClick(e)}><i className='fa fa-fw fa-close'/></button>
|
<button onClick={e => this.handleDeleteButtonClick(e)}><i className='fa fa-fw fa-close'/></button>
|
||||||
@@ -106,6 +179,8 @@ export default class FolderRow extends React.Component {
|
|||||||
|
|
||||||
FolderRow.propTypes = {
|
FolderRow.propTypes = {
|
||||||
folder: PropTypes.shape(),
|
folder: PropTypes.shape(),
|
||||||
|
index: PropTypes.number,
|
||||||
|
count: PropTypes.number,
|
||||||
setAlert: PropTypes.func
|
setAlert: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ export default class FolderSettingTab extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleNewFolderNameKeyDown (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
this.handleSaveButtonClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleSaveButtonClick (e) {
|
handleSaveButtonClick (e) {
|
||||||
this.setState({alert: null}, () => {
|
this.setState({alert: null}, () => {
|
||||||
if (this.state.name.trim().length === 0) return false
|
if (this.state.name.trim().length === 0) return false
|
||||||
@@ -40,10 +46,16 @@ export default class FolderSettingTab extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { folders } = this.props
|
let { folders } = this.props
|
||||||
let folderElements = folders.map(folder => {
|
let folderElements = folders.map((folder, index) => {
|
||||||
return (
|
return (
|
||||||
<FolderRow key={'folder-' + folder.key} folder={folder} setAlert={(alert, cb) => this.setAlert(alert, cb)}/>
|
<FolderRow
|
||||||
)
|
key={'folder-' + folder.key}
|
||||||
|
folder={folder}
|
||||||
|
index={index}
|
||||||
|
count={folders.length}
|
||||||
|
setAlert={(alert, cb) => this.setAlert(alert, cb)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
let alert = this.state.alert
|
let alert = this.state.alert
|
||||||
@@ -59,13 +71,13 @@ export default class FolderSettingTab extends React.Component {
|
|||||||
<div className='sectionTitle'>Manage folder</div>
|
<div className='sectionTitle'>Manage folder</div>
|
||||||
<div className='folderTable'>
|
<div className='folderTable'>
|
||||||
<div className='folderHeader'>
|
<div className='folderHeader'>
|
||||||
<div className='folderName'>Folder name</div>
|
<div className='folderName'>Folder</div>
|
||||||
<div className='folderControl'>Edit/Delete</div>
|
<div className='folderControl'>Edit/Delete</div>
|
||||||
</div>
|
</div>
|
||||||
{folderElements}
|
{folderElements}
|
||||||
<div className='newFolder'>
|
<div className='newFolder'>
|
||||||
<div className='folderName'>
|
<div className='folderName'>
|
||||||
<input valueLink={this.linkState('name')} type='text' placeholder='New Folder'/>
|
<input onKeyDown={e => this.handleNewFolderNameKeyDown(e)} valueLink={this.linkState('name')} type='text' placeholder='New Folder'/>
|
||||||
</div>
|
</div>
|
||||||
<div className='folderControl'>
|
<div className='folderControl'>
|
||||||
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Add</button>
|
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Add</button>
|
||||||
|
|||||||
@@ -88,10 +88,11 @@ export default class Tutorial extends React.Component {
|
|||||||
return (<div className='slide slide3'>
|
return (<div className='slide slide3'>
|
||||||
<div className='title'>Easy to access with Finder</div>
|
<div className='title'>Easy to access with Finder</div>
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
With Finder, You can search your articles faster.<br/>
|
The Finder helps you organize all of the files and documents.<br/>
|
||||||
You can open Finder by pressing Control + shift + tab<br/>
|
There is a short-cut key [control + shift + tab] to open the Finder.<br/>
|
||||||
To put the content of an article in the clipboard, press Enter.<br/>
|
It is available to save your articles on the Clipboard<br/>
|
||||||
So you can paste it with Cmd(⌘) + V
|
by selecting your file with pressing Enter key,<br/>
|
||||||
|
and to paste the contents of the Clipboard with [Command-V]
|
||||||
|
|
||||||
<img width='480' src='../../resources/finder.png'/>
|
<img width='480' src='../../resources/finder.png'/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,42 @@
|
|||||||
import { combineReducers } from 'redux'
|
import { combineReducers } from 'redux'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, CLEAR_SEARCH, TOGGLE_TUTORIAL, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
|
import {
|
||||||
|
// Status action type
|
||||||
|
SWITCH_FOLDER,
|
||||||
|
SWITCH_MODE,
|
||||||
|
SWITCH_ARTICLE,
|
||||||
|
SET_SEARCH_FILTER,
|
||||||
|
SET_TAG_FILTER,
|
||||||
|
CLEAR_SEARCH,
|
||||||
|
LOCK_STATUS,
|
||||||
|
UNLOCK_STATUS,
|
||||||
|
TOGGLE_TUTORIAL,
|
||||||
|
|
||||||
|
// Article action type
|
||||||
|
ARTICLE_UPDATE,
|
||||||
|
ARTICLE_DESTROY,
|
||||||
|
|
||||||
|
// Folder action type
|
||||||
|
FOLDER_CREATE,
|
||||||
|
FOLDER_UPDATE,
|
||||||
|
FOLDER_DESTROY,
|
||||||
|
FOLDER_REPLACE,
|
||||||
|
|
||||||
|
// view mode
|
||||||
|
IDLE_MODE,
|
||||||
|
CREATE_MODE
|
||||||
|
} from './actions'
|
||||||
import dataStore from 'boost/dataStore'
|
import dataStore from 'boost/dataStore'
|
||||||
import keygen from 'boost/keygen'
|
import keygen from 'boost/keygen'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
import { openModal } from 'boost/modal'
|
||||||
|
import EditedAlert from 'boost/components/modal/EditedAlert'
|
||||||
|
|
||||||
const initialStatus = {
|
const initialStatus = {
|
||||||
mode: IDLE_MODE,
|
mode: IDLE_MODE,
|
||||||
search: '',
|
search: '',
|
||||||
isTutorialOpen: false
|
isTutorialOpen: false,
|
||||||
|
isStatusLocked: false
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = dataStore.getData()
|
let data = dataStore.getData()
|
||||||
@@ -26,12 +54,11 @@ function folders (state = initialFolders, action) {
|
|||||||
Object.assign(newFolder, {
|
Object.assign(newFolder, {
|
||||||
key: keygen(),
|
key: keygen(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date()
|
||||||
// random number (0-7)
|
|
||||||
color: Math.round(Math.random() * 7)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (newFolder.length === 0) throw new Error('Folder name is required')
|
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 = _.findWhere(state, {name: newFolder.name})
|
let conflictFolder = _.findWhere(state, {name: newFolder.name})
|
||||||
if (conflictFolder != null) throw new Error(`${newFolder.name} already exists!`)
|
if (conflictFolder != null) throw new Error(`${newFolder.name} already exists!`)
|
||||||
@@ -48,7 +75,8 @@ function folders (state = initialFolders, action) {
|
|||||||
|
|
||||||
if (!_.isString(folder.name)) throw new Error('Folder name must be a string')
|
if (!_.isString(folder.name)) throw new Error('Folder name must be a string')
|
||||||
folder.name = folder.name.trim().replace(/\s/, '_')
|
folder.name = folder.name.trim().replace(/\s/, '_')
|
||||||
if (folder.length === 0) throw new Error('Folder name is required')
|
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
|
// Folder existence check
|
||||||
if (targetFolder == null) throw new Error('Folder doesnt exist')
|
if (targetFolder == null) throw new Error('Folder doesnt exist')
|
||||||
@@ -80,6 +108,15 @@ function folders (state = initialFolders, action) {
|
|||||||
activityRecord.emit('FOLDER_DESTROY')
|
activityRecord.emit('FOLDER_DESTROY')
|
||||||
return state
|
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)
|
||||||
|
}
|
||||||
|
return state
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@@ -125,13 +162,28 @@ function articles (state = initialArticles, action) {
|
|||||||
|
|
||||||
function status (state = initialStatus, action) {
|
function status (state = initialStatus, action) {
|
||||||
state = Object.assign({}, state)
|
state = Object.assign({}, state)
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case TOGGLE_TUTORIAL:
|
case TOGGLE_TUTORIAL:
|
||||||
state.isTutorialOpen = !state.isTutorialOpen
|
state.isTutorialOpen = !state.isTutorialOpen
|
||||||
return state
|
return state
|
||||||
|
case LOCK_STATUS:
|
||||||
|
state.isStatusLocked = true
|
||||||
|
return state
|
||||||
|
case UNLOCK_STATUS:
|
||||||
|
state.isStatusLocked = false
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
// if status locked, status become unmutable
|
||||||
|
if (state.isStatusLocked) {
|
||||||
|
openModal(EditedAlert, {action})
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
switch (action.type) {
|
||||||
case SWITCH_FOLDER:
|
case SWITCH_FOLDER:
|
||||||
state.mode = IDLE_MODE
|
state.mode = IDLE_MODE
|
||||||
state.search = `in:${action.data} `
|
state.search = `//${action.data} `
|
||||||
|
|
||||||
return state
|
return state
|
||||||
case SWITCH_MODE:
|
case SWITCH_MODE:
|
||||||
|
|||||||
12
main.js
12
main.js
@@ -30,8 +30,8 @@ updater
|
|||||||
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
||||||
nn.notify({
|
nn.notify({
|
||||||
title: 'Ready to Update!! ' + versionText,
|
title: 'Ready to Update!! ' + versionText,
|
||||||
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
|
icon: path.join(__dirname, '/resources/favicon-230x230.png'),
|
||||||
message: 'Click tray icon to update app: ' + releaseName
|
message: 'Click update button on Main window: ' + releaseName
|
||||||
})
|
})
|
||||||
update = quitAndUpdate
|
update = quitAndUpdate
|
||||||
|
|
||||||
@@ -50,6 +50,14 @@ app.on('ready', function () {
|
|||||||
// menu start
|
// menu start
|
||||||
var template = require('./atom-lib/menu-template')
|
var template = require('./atom-lib/menu-template')
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
if (update == null) updater.checkForUpdates()
|
||||||
|
}, 1000 * 60 * 60 * 24)
|
||||||
|
|
||||||
|
ipc.on('check-update', function (event, msg) {
|
||||||
|
if (update == null) updater.checkForUpdates()
|
||||||
|
})
|
||||||
|
|
||||||
ipc.on('update-app', function (event, msg) {
|
ipc.on('update-app', function (event, msg) {
|
||||||
if (update != null) {
|
if (update != null) {
|
||||||
appQuit = true
|
appQuit = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "boost",
|
"name": "boost",
|
||||||
"version": "0.4.0-beta.2",
|
"version": "0.4.1-beta.1",
|
||||||
"description": "Boost App",
|
"description": "Boost App",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
"homepage": "https://github.com/Rokt33r/codexen-app#readme",
|
"homepage": "https://github.com/Rokt33r/codexen-app#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"devicon": "^2.0.0",
|
"devicon": "^2.0.0",
|
||||||
"electron-packager": "^5.1.1",
|
|
||||||
"font-awesome": "^4.3.0",
|
"font-awesome": "^4.3.0",
|
||||||
"fs-jetpack": "^0.7.0",
|
"fs-jetpack": "^0.7.0",
|
||||||
"lodash": "^3.10.1",
|
"lodash": "^3.10.1",
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ var config = {
|
|||||||
'superagent-promise',
|
'superagent-promise',
|
||||||
'lodash',
|
'lodash',
|
||||||
'markdown-it',
|
'markdown-it',
|
||||||
'moment'
|
'moment',
|
||||||
|
'node-notifier'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ module.exports = {
|
|||||||
'superagent-promise',
|
'superagent-promise',
|
||||||
'lodash',
|
'lodash',
|
||||||
'markdown-it',
|
'markdown-it',
|
||||||
'moment'
|
'moment',
|
||||||
|
'node-notifier'
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['', '.js', '.jsx', 'styl']
|
extensions: ['', '.js', '.jsx', 'styl']
|
||||||
|
|||||||
Reference in New Issue
Block a user