mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 18:26:26 +00:00
Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2027f60014 | ||
|
|
076edd375f | ||
|
|
ab1aa56059 | ||
|
|
46f7dfdfeb | ||
|
|
fcaa5e21cf | ||
|
|
1e202db50f | ||
|
|
9405b95825 | ||
|
|
f05e256afc | ||
|
|
731ffd4a22 | ||
|
|
8f4566b7e1 | ||
|
|
95aec54f60 | ||
|
|
f14ce0d68e | ||
|
|
cc1c7f3820 | ||
|
|
2df901288a | ||
|
|
821a7c780e | ||
|
|
6e2e48fa64 | ||
|
|
2864ac88f5 | ||
|
|
4a292d6518 | ||
|
|
e934182e86 | ||
|
|
d8fa73287b | ||
|
|
35938c09e8 | ||
|
|
9eaa90c691 | ||
|
|
049835d426 | ||
|
|
af91c40406 | ||
|
|
4940ad6825 | ||
|
|
d02b740300 | ||
|
|
9cb443dc2f | ||
|
|
1c7cba2951 | ||
|
|
473b80710d | ||
|
|
2247c0835d | ||
|
|
b7b715ba3d | ||
|
|
6c43fb2325 | ||
|
|
a6fe3c27d4 | ||
|
|
d47ff96b13 | ||
|
|
a0def654bd | ||
|
|
4873b40e49 | ||
|
|
0a758f20a7 | ||
|
|
5e58d457a3 | ||
|
|
0f745361ad | ||
|
|
bf6cae9a0e | ||
|
|
ab640a7676 | ||
|
|
820171e19e | ||
|
|
f1e9d0ab81 | ||
|
|
0646484c83 | ||
|
|
a27b79c213 | ||
|
|
773a9b4b7f | ||
|
|
07b838ef7b | ||
|
|
85217a7171 | ||
|
|
886d7b7227 | ||
|
|
6987b762dd | ||
|
|
f32ac81f84 | ||
|
|
87ea66bb92 | ||
|
|
ff6fd62932 | ||
|
|
76728448ff | ||
|
|
3b7225e0fa | ||
|
|
d6280f4397 | ||
|
|
8df867046f | ||
|
|
331c822816 | ||
|
|
6219173945 | ||
|
|
6207e02e7f | ||
|
|
537ba537dc | ||
|
|
3e919241e6 | ||
|
|
2324327e7e | ||
|
|
b8374494ea | ||
|
|
a480ca7b55 | ||
|
|
bfd67fb7f1 | ||
|
|
e6bd6a5077 | ||
|
|
350af844ca | ||
|
|
a49d53179a | ||
|
|
e68069fd2f | ||
|
|
a193ba3e6c | ||
|
|
9034b3ab54 | ||
|
|
f39b7594ab | ||
|
|
f79734391e | ||
|
|
e54f516418 | ||
|
|
e86464535d | ||
|
|
e8553caa65 | ||
|
|
044e6b7180 | ||
|
|
0266770657 | ||
|
|
2d6f7c08e8 | ||
|
|
0a27819a7f | ||
|
|
3185c25ee1 | ||
|
|
820802cdc2 | ||
|
|
2c169e6f15 | ||
|
|
49be1320f9 | ||
|
|
6bc4ecce48 | ||
|
|
0290d23832 | ||
|
|
e001c97e01 | ||
|
|
976d1bb4f3 | ||
|
|
dee6495b08 | ||
|
|
4a77f250f1 | ||
|
|
c697f19642 | ||
|
|
f7d1f9e949 | ||
|
|
27b9952f8e | ||
|
|
961dab4a97 | ||
|
|
930b6bc927 | ||
|
|
ed7d8258cf | ||
|
|
762425125f | ||
|
|
03bdf0c653 | ||
|
|
7002026190 | ||
|
|
b35395e6bd | ||
|
|
b74fb76d03 | ||
|
|
72d2df465b | ||
|
|
2592c943f7 | ||
|
|
7b3a3ba200 | ||
|
|
8369832585 | ||
|
|
d94a674343 | ||
|
|
260611ffd6 | ||
|
|
690549b57f | ||
|
|
5d9aeb4c04 | ||
|
|
eddfdea2ca | ||
|
|
a40385f87f | ||
|
|
0123526c98 | ||
|
|
275e3317a3 | ||
|
|
d0b835a825 | ||
|
|
f450260ff8 | ||
|
|
5f7b119e5c | ||
|
|
bb9eb494e9 | ||
|
|
6ea2b5e1d9 | ||
|
|
b21baf1ce5 | ||
|
|
4c3fd461e4 | ||
|
|
8365a60d5d | ||
|
|
804ac1aa96 | ||
|
|
49fd2cfc4d | ||
|
|
2bb2a52f27 | ||
|
|
8d71b28afa | ||
|
|
86eac7054d | ||
|
|
dccb92d72b | ||
|
|
2e628de9c6 | ||
|
|
2d243abc12 | ||
|
|
ae08bf4d7a | ||
|
|
cbff5fb585 | ||
|
|
2650cc2f1c | ||
|
|
ec560ceab1 | ||
|
|
ad17cb8837 | ||
|
|
4f98d9641a | ||
|
|
17535ccd4c | ||
|
|
110c1ea337 | ||
|
|
7e087bfbab | ||
|
|
85e0d4b922 | ||
|
|
265262ccbf | ||
|
|
345008e9b6 | ||
|
|
849aa05d76 | ||
|
|
5ff5ec6a71 | ||
|
|
684c3f64aa | ||
|
|
4ff73ede59 | ||
|
|
7302d83f60 | ||
|
|
f9836fd66e | ||
|
|
c0f05695fe | ||
|
|
e50a1172d6 | ||
|
|
7a4234e73c | ||
|
|
4b9640e5a3 | ||
|
|
4b58054100 | ||
|
|
8951dbf4ed | ||
|
|
5047bc94eb | ||
|
|
75fb29c594 | ||
|
|
bd75f7fd2c | ||
|
|
8b8cb3c9b4 | ||
|
|
b479b21c37 | ||
|
|
525c490704 | ||
|
|
2e3599d005 | ||
|
|
f005bb1e46 | ||
|
|
21f96febdb | ||
|
|
805829be78 | ||
|
|
a7bd3f253f | ||
|
|
81e8a290f0 | ||
|
|
f46a967b6e | ||
|
|
b78d9534aa | ||
|
|
bdefaf7427 | ||
|
|
43550c7dec | ||
|
|
1b07d393f2 | ||
|
|
44fc356775 | ||
|
|
5623c68170 | ||
|
|
d5f82943cf | ||
|
|
96a020341d | ||
|
|
99b5f75763 | ||
|
|
a128ff7cd8 | ||
|
|
59329cc5da | ||
|
|
ecd5daaf55 | ||
|
|
514232d720 | ||
|
|
93abfe3202 | ||
|
|
4d9e0e3bd7 | ||
|
|
75d9bf8e38 | ||
|
|
ccb9752254 | ||
|
|
0f2ca19c6c | ||
|
|
d5a77aade4 | ||
|
|
3c89e6a128 | ||
|
|
a36be79977 | ||
|
|
617f0e0f9c | ||
|
|
0db1a94105 | ||
|
|
f29f97a00f | ||
|
|
032b5a59f2 | ||
|
|
1e5bc395ac | ||
|
|
fef4afe660 | ||
|
|
679ed1eacf | ||
|
|
78a9320017 | ||
|
|
927981bf30 | ||
|
|
70ea2f6c14 | ||
|
|
a6779414ff | ||
|
|
b62fcf523a | ||
|
|
d0bbea5a97 | ||
|
|
212d7027fc | ||
|
|
be1a5b09da | ||
|
|
3de2db4459 | ||
|
|
f2405a5b34 | ||
|
|
94abb8f959 | ||
|
|
2e30db05bc | ||
|
|
c93f3cc5dd | ||
|
|
068f8f2ba9 | ||
|
|
0980c3b012 | ||
|
|
5288d6768f | ||
|
|
34491f4ea4 | ||
|
|
8c73ca8854 | ||
|
|
0786d8eab6 | ||
|
|
209518c815 | ||
|
|
b2753b6457 | ||
|
|
4775a920c0 | ||
|
|
0e94dc8740 | ||
|
|
cf68d202d5 | ||
|
|
d29ba2bf16 | ||
|
|
720686cef5 | ||
|
|
0625c65cf0 | ||
|
|
acaefe22d1 | ||
|
|
df1f083ebf | ||
|
|
5a1dfc2ca9 | ||
|
|
d84894f1bf | ||
|
|
0fdc444c4c | ||
|
|
4d216c6f13 | ||
|
|
1c0af8eede | ||
|
|
f443f9264a | ||
|
|
d9b2981327 | ||
|
|
68e36d2a6d | ||
|
|
68b91bf98c | ||
|
|
b91ddfad05 | ||
|
|
a110cbfb5d | ||
|
|
d69f45b0c9 | ||
|
|
07df26d5c4 | ||
|
|
d24bcb7f86 | ||
|
|
9f383ba491 | ||
|
|
c38a76d587 | ||
|
|
994ca5dd02 | ||
|
|
9281f8f6cb | ||
|
|
324f579474 | ||
|
|
95e7f4f645 |
33
.boostnoterc.sample
Normal file
33
.boostnoterc.sample
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"amaEnabled": true,
|
||||
"editor": {
|
||||
"fontFamily": "Monaco, Consolas",
|
||||
"fontSize": "14",
|
||||
"indentSize": "2",
|
||||
"indentType": "space",
|
||||
"keyMap": "vim",
|
||||
"switchPreview": "BLUR",
|
||||
"theme": "monokai"
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleFinder": "Cmd + Alt + S",
|
||||
"toggleMain": "Cmd + Alt + L"
|
||||
},
|
||||
"isSideNavFolded": false,
|
||||
"listStyle": "DEFAULT",
|
||||
"listWidth": 174,
|
||||
"navWidth": 200,
|
||||
"preview": {
|
||||
"codeBlockTheme": "dracula",
|
||||
"fontFamily": "Lato",
|
||||
"fontSize": "14",
|
||||
"lineNumber": true
|
||||
},
|
||||
"sortBy": "UPDATED_AT",
|
||||
"ui": {
|
||||
"defaultNote": "ALWAYS_ASK",
|
||||
"disableDirectWrite": false,
|
||||
"theme": "default"
|
||||
},
|
||||
"zoom": 1
|
||||
}
|
||||
30
.travis.yml
30
.travis.yml
@@ -1,26 +1,6 @@
|
||||
language: node_js
|
||||
# To fix the npm version in 4.x
|
||||
# refs: https://github.com/travis-ci/travis-ci/issues/4653#issuecomment-194051953
|
||||
before_install: 'if [[ `npm -v` != 4* ]]; then npm i -g npm@4; fi'
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
install:
|
||||
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then yarn; fi'
|
||||
node_js:
|
||||
- 'stable'
|
||||
- 'lts/*'
|
||||
script:
|
||||
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" && ${TRAVIS_NODE_VERSION} = "stable" ]]; then
|
||||
npm run lint;
|
||||
npm run test;
|
||||
./script/e2e-runner.sh;
|
||||
fi'
|
||||
- os: linux
|
||||
node_js:
|
||||
- 'stable'
|
||||
- 'lts/*'
|
||||
script:
|
||||
- 'npm run lint'
|
||||
- 'npm run test'
|
||||
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" && ${TRAVIS_NODE_VERSION} = "stable" ]]; then ./script/e2e-runner.sh; fi'
|
||||
node_js:
|
||||
- 'stable'
|
||||
- 'lts/*'
|
||||
|
||||
script: npm run lint && npm run test
|
||||
|
||||
5
Backers.md
Normal file
5
Backers.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Become a [backer](https://salt.bountysource.com/teams/boostnote) and support Boostnote!
|
||||
You can support Boostnote from $ 5 a month!
|
||||
|
||||
# Backers
|
||||
[Kazu Yokomizo](https://twitter.com/kazup_bot)
|
||||
1
ISSUE_TEMPLATE.md
Normal file
1
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1 @@
|
||||
Please paste some **screenshots** with the **developer tool** open if you report a bug.
|
||||
@@ -84,7 +84,13 @@ export default class CodeEditor extends React.Component {
|
||||
'Cmd-T': function (cm) {
|
||||
// Do nothing
|
||||
},
|
||||
Enter: 'newlineAndIndentContinueMarkdownList'
|
||||
Enter: 'newlineAndIndentContinueMarkdownList',
|
||||
'Ctrl-C': (cm) => {
|
||||
if (cm.getOption('keyMap').substr(0, 3) === 'vim') {
|
||||
document.execCommand('copy')
|
||||
}
|
||||
return CodeMirror.Pass
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -186,15 +192,16 @@ export default class CodeEditor extends React.Component {
|
||||
const imagePath = e.dataTransfer.files[0].path
|
||||
const filename = path.basename(imagePath)
|
||||
|
||||
copyImage(imagePath, this.props.storageKey).then((imagePathInTheStorage) => {
|
||||
const imageMd = ``
|
||||
copyImage(imagePath, this.props.storageKey).then((imagePath) => {
|
||||
const imageMd = `})`
|
||||
this.insertImageMd(imageMd)
|
||||
})
|
||||
}
|
||||
|
||||
insertImageMd (imageMd) {
|
||||
const textarea = this.editor.getInputField()
|
||||
const cm = this.editor
|
||||
cm.setValue(cm.getValue() + imageMd)
|
||||
textarea.value = `${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
@@ -4,6 +4,8 @@ import styles from './MarkdownEditor.styl'
|
||||
import CodeEditor from 'browser/components/CodeEditor'
|
||||
import MarkdownPreview from 'browser/components/MarkdownPreview'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
const _ = require('lodash')
|
||||
|
||||
class MarkdownEditor extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -79,7 +81,6 @@ class MarkdownEditor extends React.Component {
|
||||
if (newStatus === 'CODE') {
|
||||
this.refs.code.focus()
|
||||
} else {
|
||||
this.refs.code.blur()
|
||||
this.refs.preview.focus()
|
||||
}
|
||||
eventEmitter.emit('topbar:togglelockbutton', this.state.status)
|
||||
@@ -162,15 +163,18 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
let { config } = this.props
|
||||
if (this.state.status !== 'CODE') return false
|
||||
const keyPressed = this.state.keyPressed
|
||||
keyPressed.add(e.keyCode)
|
||||
this.setState({ keyPressed })
|
||||
let isNoteHandlerKey = (el) => { return keyPressed.has(el) }
|
||||
// These conditions are for ctrl-e and ctrl-w
|
||||
if (keyPressed.size === this.escapeFromEditor.length &&
|
||||
!this.state.isLocked && this.state.status === 'CODE' &&
|
||||
this.escapeFromEditor.every(isNoteHandlerKey)) {
|
||||
document.activeElement.blur()
|
||||
this.handleContextMenu()
|
||||
if (config.editor.switchPreview === 'BLUR') document.activeElement.blur()
|
||||
}
|
||||
if (keyPressed.size === this.supportMdSelectionBold.length && this.supportMdSelectionBold.every(isNoteHandlerKey)) {
|
||||
this.addMdAroundWord('**')
|
||||
@@ -213,6 +217,8 @@ class MarkdownEditor extends React.Component {
|
||||
let previewStyle = {}
|
||||
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
|
||||
|
||||
const storage = findStorage(storageKey)
|
||||
|
||||
return (
|
||||
<div className={className == null
|
||||
? 'MarkdownEditor'
|
||||
@@ -260,6 +266,7 @@ class MarkdownEditor extends React.Component {
|
||||
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
|
||||
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
|
||||
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
|
||||
storagePath={storage.path}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -108,6 +108,9 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
|
||||
this.saveAsTextHandler = () => this.handleSaveAsText()
|
||||
this.saveAsMdHandler = () => this.handleSaveAsMd()
|
||||
this.printHandler = () => this.handlePrint()
|
||||
|
||||
this.linkClickHandler = this.handlelinkClick.bind(this)
|
||||
}
|
||||
|
||||
handlePreviewAnchorClick (e) {
|
||||
@@ -160,6 +163,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.exportAsDocument('md')
|
||||
}
|
||||
|
||||
handlePrint () {
|
||||
this.refs.root.contentWindow.print()
|
||||
}
|
||||
|
||||
exportAsDocument (fileType) {
|
||||
const options = {
|
||||
filters: [
|
||||
@@ -196,6 +203,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler)
|
||||
eventEmitter.on('export:save-text', this.saveAsTextHandler)
|
||||
eventEmitter.on('export:save-md', this.saveAsMdHandler)
|
||||
eventEmitter.on('print', this.printHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@@ -206,6 +214,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler)
|
||||
eventEmitter.off('export:save-text', this.saveAsTextHandler)
|
||||
eventEmitter.off('export:save-md', this.saveAsMdHandler)
|
||||
eventEmitter.off('print', this.printHandler)
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
@@ -249,7 +258,11 @@ export default class MarkdownPreview extends React.Component {
|
||||
el.removeEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
|
||||
let { value, theme, indentSize, codeBlockTheme } = this.props
|
||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.removeEventListener('click', this.linkClickHandler)
|
||||
})
|
||||
|
||||
let { value, theme, indentSize, codeBlockTheme, storagePath } = this.props
|
||||
|
||||
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
|
||||
|
||||
@@ -273,6 +286,15 @@ export default class MarkdownPreview extends React.Component {
|
||||
el.addEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
|
||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.addEventListener('click', this.linkClickHandler)
|
||||
})
|
||||
|
||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => {
|
||||
if (!/\/:storage/.test(el.src)) return
|
||||
el.src = `file:///${path.join(storagePath, 'images', path.basename(el.src))}`
|
||||
})
|
||||
|
||||
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)
|
||||
? codeBlockTheme
|
||||
: 'default'
|
||||
@@ -373,6 +395,14 @@ export default class MarkdownPreview extends React.Component {
|
||||
return new window.Notification(title, options)
|
||||
}
|
||||
|
||||
handlelinkClick (e) {
|
||||
const noteHash = e.target.href.split('/').pop()
|
||||
const regexIsNoteLink = /^(.{20})-(.{20})$/
|
||||
if (regexIsNoteLink.test(noteHash)) {
|
||||
eventEmitter.emit('list:jump', noteHash)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, style, tabIndex } = this.props
|
||||
return (
|
||||
@@ -394,5 +424,6 @@ MarkdownPreview.propTypes = {
|
||||
onMouseUp: PropTypes.func,
|
||||
onMouseDown: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
value: PropTypes.string
|
||||
value: PropTypes.string,
|
||||
storagePath: PropTypes.string
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { isArray } from 'lodash'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import { getTodoStatus } from 'browser/lib/getTodoStatus'
|
||||
import styles from './NoteItem.styl'
|
||||
import TodoProcess from './TodoProcess'
|
||||
|
||||
/**
|
||||
* @description Tag element component.
|
||||
@@ -39,18 +41,16 @@ const TagElementList = (tags) => {
|
||||
* @param {boolean} isActive
|
||||
* @param {Object} note
|
||||
* @param {Function} handleNoteClick
|
||||
* @param {Function} handleNoteContextMenu
|
||||
* @param {Function} handleDragStart
|
||||
* @param {string} dateDisplay
|
||||
*/
|
||||
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteContextMenu, handleDragStart }) => (
|
||||
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleDragStart }) => (
|
||||
<div styleName={isActive
|
||||
? 'item--active'
|
||||
: 'item'
|
||||
}
|
||||
key={`${note.storage}-${note.key}`}
|
||||
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
||||
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
|
||||
onDragStart={e => handleDragStart(e, note)}
|
||||
draggable='true'
|
||||
>
|
||||
@@ -70,6 +70,10 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont
|
||||
{note.isStarred
|
||||
? <i styleName='item-star' className='fa fa-star' /> : ''
|
||||
}
|
||||
{note.type === 'MARKDOWN_NOTE'
|
||||
? <TodoProcess todoStatus={getTodoStatus(note.content)} />
|
||||
: ''
|
||||
}
|
||||
<div styleName='item-bottom'>
|
||||
<div styleName='item-bottom-tagList'>
|
||||
{note.tags.length > 0
|
||||
@@ -91,10 +95,10 @@ NoteItem.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isrequired,
|
||||
tags: PropTypes.array,
|
||||
isStarred: PropTypes.bool.isRequired
|
||||
isStarred: PropTypes.bool.isRequired,
|
||||
isTrashed: PropTypes.bool.isRequired
|
||||
}),
|
||||
handleNoteClick: PropTypes.func.isRequired,
|
||||
handleNoteContextMenu: PropTypes.func.isRequired,
|
||||
handleDragStart: PropTypes.func.isRequired,
|
||||
handleDragEnd: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ $control-height = 30px
|
||||
.item-wrapper
|
||||
padding 15px 0
|
||||
border-bottom $ui-border
|
||||
position relative
|
||||
|
||||
.item--active
|
||||
@extend .item
|
||||
@@ -66,7 +67,7 @@ $control-height = 30px
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.item-title
|
||||
font-size 13px
|
||||
font-size 14px
|
||||
position relative
|
||||
top -12px
|
||||
left 20px
|
||||
@@ -92,11 +93,12 @@ $control-height = 30px
|
||||
flex 1
|
||||
overflow ellipsis
|
||||
line-height 20px
|
||||
padding-top 2px
|
||||
padding-top 7px
|
||||
padding-left 2px
|
||||
margin-right 27px
|
||||
|
||||
.item-bottom-tagList-item
|
||||
font-size 10px
|
||||
font-size 11px
|
||||
margin-right 8px
|
||||
padding 0
|
||||
height 20px
|
||||
@@ -109,14 +111,14 @@ $control-height = 30px
|
||||
|
||||
.item-bottom-time
|
||||
color $ui-inactive-text-color
|
||||
font-size 10px
|
||||
font-size 11px
|
||||
padding-left 2px
|
||||
padding-bottom 2px
|
||||
|
||||
.item-star
|
||||
position absolute
|
||||
top 34px
|
||||
left 5px
|
||||
right -20px
|
||||
bottom 2px
|
||||
width 34px
|
||||
height 34px
|
||||
color alpha($ui-favorite-star-button-color, 60%)
|
||||
|
||||
@@ -10,17 +10,15 @@ import styles from './NoteItemSimple.styl'
|
||||
* @param {boolean} isActive
|
||||
* @param {Object} note
|
||||
* @param {Function} handleNoteClick
|
||||
* @param {Function} handleNoteContextMenu
|
||||
* @param {Function} handleDragStart
|
||||
*/
|
||||
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenum, handleDragStart }) => (
|
||||
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleDragStart }) => (
|
||||
<div styleName={isActive
|
||||
? 'item-simple--active'
|
||||
: 'item-simple'
|
||||
}
|
||||
key={`${note.storage}-${note.key}`}
|
||||
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
|
||||
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
|
||||
onDragStart={e => handleDragStart(e, note)}
|
||||
draggable='true'
|
||||
>
|
||||
@@ -46,7 +44,6 @@ NoteItemSimple.propTypes = {
|
||||
title: PropTypes.string.isrequired
|
||||
}),
|
||||
handleNoteClick: PropTypes.func.isRequired,
|
||||
handleNoteContextMenu: PropTypes.func.isRequired,
|
||||
handleDragStart: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ $control-height = 30px
|
||||
|
||||
.item-simple
|
||||
position relative
|
||||
padding 0 25px
|
||||
padding 0 20px
|
||||
user-select none
|
||||
cursor pointer
|
||||
background-color $ui-noteList-backgroundColor
|
||||
@@ -40,7 +40,7 @@ $control-height = 30px
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.item-simple-title
|
||||
font-size 12px
|
||||
font-size 13px
|
||||
height 40px
|
||||
box-sizing border-box
|
||||
line-height 24px
|
||||
@@ -48,6 +48,7 @@ $control-height = 30px
|
||||
overflow ellipsis
|
||||
color $ui-inactive-text-color
|
||||
border-bottom $ui-border
|
||||
position relative
|
||||
|
||||
.item-simple-title-icon
|
||||
font-size 12px
|
||||
|
||||
@@ -15,7 +15,7 @@ import styles from './SideNavFilter.styl'
|
||||
*/
|
||||
const SideNavFilter = ({
|
||||
isFolded, isHomeActive, handleAllNotesButtonClick,
|
||||
isStarredActive, handleStarredButtonClick
|
||||
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick
|
||||
}) => (
|
||||
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
|
||||
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
|
||||
@@ -30,6 +30,12 @@ const SideNavFilter = ({
|
||||
<i className='fa fa-star fa-fw' />
|
||||
<span styleName='menu-button-label'>Starred</span>
|
||||
</button>
|
||||
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
|
||||
onClick={handleTrashedButtonClick}
|
||||
>
|
||||
<i className='fa fa-trash fa-fw' />
|
||||
<span styleName='menu-button-label'>Trash</span>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -38,7 +44,9 @@ SideNavFilter.propTypes = {
|
||||
isHomeActive: PropTypes.bool.isRequired,
|
||||
handleAllNotesButtonClick: PropTypes.func.isRequired,
|
||||
isStarredActive: PropTypes.bool.isRequired,
|
||||
handleStarredButtonClick: PropTypes.func.isRequired
|
||||
isTrashedActive: PropTypes.bool.isRequired,
|
||||
handleStarredButtonClick: PropTypes.func.isRequired,
|
||||
handleTrashdButtonClick: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(SideNavFilter, styles)
|
||||
|
||||
33
browser/components/TodoProcess.js
Normal file
33
browser/components/TodoProcess.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @fileoverview Percentage of todo achievement.
|
||||
*/
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TodoProcess.styl'
|
||||
|
||||
const TodoProcess = ({
|
||||
todoStatus: {
|
||||
total: totalTodo,
|
||||
completed: completedTodo
|
||||
}
|
||||
}) => (
|
||||
<div styleName='todo-process' style={{display: totalTodo > 0 ? '' : 'none'}}>
|
||||
<div styleName='todo-process-text'>
|
||||
<i className='fa fa-fw fa-check-square-o' />
|
||||
{completedTodo} of {totalTodo}
|
||||
</div>
|
||||
<div styleName='todo-process-bar'>
|
||||
<div styleName='todo-process-bar--inner' style={{width: parseInt(completedTodo / totalTodo * 100) + '%'}} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
TodoProcess.propTypes = {
|
||||
todoStatus: {
|
||||
total: PropTypes.number.isRequired,
|
||||
completed: PropTypes.number.isRequired
|
||||
}
|
||||
}
|
||||
|
||||
export default CSSModules(TodoProcess, styles)
|
||||
45
browser/components/TodoProcess.styl
Normal file
45
browser/components/TodoProcess.styl
Normal file
@@ -0,0 +1,45 @@
|
||||
.todo-process
|
||||
font-size 12px
|
||||
display flex
|
||||
padding-top 15px
|
||||
width 85%
|
||||
|
||||
.todo-process-text
|
||||
display inline-block
|
||||
padding-right 10px
|
||||
white-space nowrap
|
||||
text-overflow ellipsis
|
||||
color $ui-inactive-text-color
|
||||
i
|
||||
color $ui-inactive-text-color
|
||||
padding-right 5px
|
||||
|
||||
.todo-process-bar
|
||||
display inline-block
|
||||
margin auto
|
||||
height 4px
|
||||
border-radius 10px
|
||||
background-color #DADFE1
|
||||
border-radius 2px
|
||||
flex-grow 1
|
||||
border 1px solid alpha(#6C7A89, 10%)
|
||||
|
||||
.todo-process-bar--inner
|
||||
height 100%
|
||||
border-radius 5px
|
||||
background-color #6C7A89
|
||||
transition 0.3s
|
||||
|
||||
|
||||
body[data-theme="dark"]
|
||||
.todo-process
|
||||
color $ui-dark-text-color
|
||||
|
||||
.todo-process-bar
|
||||
background-color #363A3D
|
||||
|
||||
.todo-process-text
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.todo-process-bar--inner
|
||||
background-color: alpha(#939395, 50%)
|
||||
@@ -64,7 +64,7 @@ $list-width = 250px
|
||||
|
||||
.result-nav-storageList
|
||||
absolute bottom left right
|
||||
top 80px + 32px + 10px + 10px
|
||||
top 110px + 32px + 10px + 10px
|
||||
overflow-y auto
|
||||
|
||||
.result-list
|
||||
|
||||
@@ -5,6 +5,7 @@ import MarkdownPreview from 'browser/components/MarkdownPreview'
|
||||
import MarkdownEditor from 'browser/components/MarkdownEditor'
|
||||
import CodeEditor from 'browser/components/CodeEditor'
|
||||
import CodeMirror from 'codemirror'
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
|
||||
const electron = require('electron')
|
||||
const { clipboard } = electron
|
||||
@@ -106,6 +107,8 @@ class NoteDetail extends React.Component {
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
|
||||
const storage = findStorage(note.storage)
|
||||
|
||||
if (note.type === 'SNIPPET_NOTE') {
|
||||
let tabList = note.snippets.map((snippet, index) => {
|
||||
let isActive = this.state.snippetIndex === index
|
||||
@@ -143,6 +146,7 @@ class NoteDetail extends React.Component {
|
||||
config={config}
|
||||
value={snippet.content}
|
||||
ref={'code-' + index}
|
||||
storageKey={note.storage}
|
||||
/>
|
||||
: <CodeEditor styleName='tabView-content'
|
||||
mode={snippet.mode}
|
||||
@@ -192,6 +196,7 @@ class NoteDetail extends React.Component {
|
||||
lineNumber={config.preview.lineNumber}
|
||||
indentSize={editorIndentSize}
|
||||
value={note.content}
|
||||
storagePath={storage.path}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ class NoteList extends React.Component {
|
||||
dateDisplay={dateDisplay}
|
||||
key={key}
|
||||
handleNoteClick={(e) => this.props.handleNoteClick(e, _index)}
|
||||
handleNoteContextMenu={() => ''}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -95,7 +95,7 @@ class FinderMain extends React.Component {
|
||||
|
||||
if (e.keyCode === 13) {
|
||||
this.refs.detail.saveToClipboard()
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('COPY_FINDER')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('COPY_FINDER')
|
||||
hideFinder()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
21
browser/lib/RcParser.js
Normal file
21
browser/lib/RcParser.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import path from 'path'
|
||||
import sander from 'sander'
|
||||
|
||||
const BOOSTNOTERC = '.boostnoterc'
|
||||
const homePath = global.process.env.HOME || global.process.env.USERPROFILE
|
||||
const _boostnotercPath = path.join(homePath, BOOSTNOTERC)
|
||||
|
||||
export function parse (boostnotercPath = _boostnotercPath) {
|
||||
if (!sander.existsSync(boostnotercPath)) return {}
|
||||
try {
|
||||
return JSON.parse(sander.readFileSync(boostnotercPath).toString())
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
console.warn('Your .boostnoterc is broken so it\'s not used.')
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
parse
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import moment from 'moment'
|
||||
* @param {mixed}
|
||||
* @return {string}
|
||||
*/
|
||||
export function getLastUpdated (date) {
|
||||
export function formatDate (date) {
|
||||
const m = moment(date)
|
||||
if (!m.isValid()) {
|
||||
throw Error('Invalid argument.')
|
||||
|
||||
14
browser/lib/findStorage.js
Normal file
14
browser/lib/findStorage.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const _ = require('lodash')
|
||||
|
||||
export function findStorage (storageKey) {
|
||||
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
const storage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (storage === undefined) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
export default {
|
||||
findStorage
|
||||
}
|
||||
25
browser/lib/getTodoStatus.js
Normal file
25
browser/lib/getTodoStatus.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export function getTodoStatus (content) {
|
||||
let splitted = content.split('\n')
|
||||
let numberOfTodo = 0
|
||||
let numberOfCompletedTodo = 0
|
||||
|
||||
splitted.forEach((line) => {
|
||||
let trimmedLine = line.trim()
|
||||
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
|
||||
numberOfTodo++
|
||||
}
|
||||
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) {
|
||||
numberOfCompletedTodo++
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
total: numberOfTodo,
|
||||
completed: numberOfCompletedTodo
|
||||
}
|
||||
}
|
||||
|
||||
export function getTodoPercentageOfCompleted (content) {
|
||||
const state = getTodoStatus(content)
|
||||
return Math.floor(state.completed / state.total * 100)
|
||||
}
|
||||
@@ -159,7 +159,8 @@ function strip (input) {
|
||||
const markdown = {
|
||||
render: function markdown (content) {
|
||||
if (!_.isString(content)) content = ''
|
||||
return md.render(content)
|
||||
const renderedContent = md.render(content)
|
||||
return md.normalizeLinkText(renderedContent)
|
||||
},
|
||||
strip
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
export default function searchFromNotes (data, search) {
|
||||
let notes = data.noteMap.map((note) => note)
|
||||
export default function searchFromNotes (notes, search) {
|
||||
if (search.trim().length === 0) return []
|
||||
let searchBlocks = search.split(' ')
|
||||
searchBlocks.forEach((block) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.root
|
||||
position relative
|
||||
border solid 1px transparent
|
||||
line-height 34px
|
||||
line-height 26px
|
||||
vertical-align middle
|
||||
border-radius 2px
|
||||
transition 0.15s
|
||||
|
||||
19
browser/main/Detail/InfoButton.js
Normal file
19
browser/main/Detail/InfoButton.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoButton.styl'
|
||||
|
||||
const InfoButton = ({
|
||||
onClick
|
||||
}) => (
|
||||
<button styleName='control-infoButton'
|
||||
onClick={onClick}
|
||||
>
|
||||
<i className='fa fa-info infoButton' styleName='info-button' />
|
||||
</button>
|
||||
)
|
||||
|
||||
InfoButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(InfoButton, styles)
|
||||
21
browser/main/Detail/InfoButton.styl
Normal file
21
browser/main/Detail/InfoButton.styl
Normal file
@@ -0,0 +1,21 @@
|
||||
.control-infoButton
|
||||
float right
|
||||
topBarButtonLight()
|
||||
|
||||
.control-infoPanel
|
||||
position fixed
|
||||
pointer-events none
|
||||
top 50px
|
||||
z-index 200
|
||||
line-height normal
|
||||
border-radius 2px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
.infoButton
|
||||
padding 0px
|
||||
margin 15px 0
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-infoButton
|
||||
topBarButtonDark()
|
||||
79
browser/main/Detail/InfoPanel.js
Normal file
79
browser/main/Detail/InfoPanel.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoPanel.styl'
|
||||
|
||||
const InfoPanel = ({
|
||||
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt
|
||||
}) => (
|
||||
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Storage
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{storageName}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Folder
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{folderName}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Created
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{createdAt}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Updated
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{updatedAt}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Note Link
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input value={noteLink} onClick={(e) => { e.target.select() }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='export-wrap'>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
||||
<i className='fa fa-file-code-o fa-fw' />
|
||||
<p>.md</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
|
||||
<i className='fa fa-file-text-o fa-fw' />
|
||||
<p>.txt</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--unable'>
|
||||
<i className='fa fa-file-pdf-o fa-fw' />
|
||||
<p>.pdf</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
InfoPanel.propTypes = {
|
||||
storageName: PropTypes.string.isRequired,
|
||||
folderName: PropTypes.string.isRequired,
|
||||
noteLink: PropTypes.string.isRequired,
|
||||
updatedAt: PropTypes.string.isRequired,
|
||||
createdAt: PropTypes.string.isRequired,
|
||||
exportAsMd: PropTypes.func.isRequired,
|
||||
exportAsTxt: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(InfoPanel, styles)
|
||||
124
browser/main/Detail/InfoPanel.styl
Normal file
124
browser/main/Detail/InfoPanel.styl
Normal file
@@ -0,0 +1,124 @@
|
||||
.control-infoPanel
|
||||
position fixed
|
||||
pointer-events none
|
||||
top 50px
|
||||
z-index 200
|
||||
line-height normal
|
||||
border-radius 4px
|
||||
opacity 0
|
||||
transition 0.2s
|
||||
|
||||
.control-infoButton-panel
|
||||
z-index 200
|
||||
margin-top 45px
|
||||
margin-left -210px
|
||||
position absolute
|
||||
padding 20px 20px 0 20px
|
||||
width 340px
|
||||
background-color $ui-noteList-backgroundColor
|
||||
border 1px solid $border-color
|
||||
|
||||
.control-infoButton-panel-trash
|
||||
z-index 200
|
||||
margin-top 45px
|
||||
margin-left -230px
|
||||
position absolute
|
||||
padding 20px 20px 0 20px
|
||||
width 320px
|
||||
background-color $ui-noteList-backgroundColor
|
||||
border 1px solid $border-color
|
||||
|
||||
.group-section
|
||||
display flex
|
||||
line-height 30px
|
||||
font-size 13px
|
||||
|
||||
.group-section-label
|
||||
width 70px
|
||||
height 20px
|
||||
text-align left
|
||||
margin-right 50px
|
||||
font-size 13px
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.group-section-control
|
||||
flex 1
|
||||
font-size 13px
|
||||
color $ui-text-color
|
||||
|
||||
.group-section-control input
|
||||
width 160px
|
||||
height 25px
|
||||
|
||||
.group-section-control text
|
||||
color #EA4447
|
||||
font-weight 600
|
||||
font-size 14px
|
||||
width 70px
|
||||
height 25px
|
||||
background-color rgba(226,33,113,0.1)
|
||||
border none
|
||||
outline none
|
||||
border-radius 2px
|
||||
margin-right 5px
|
||||
padding 2px 5px
|
||||
|
||||
[id=export-wrap]
|
||||
height 90px
|
||||
display flex
|
||||
justify-content center
|
||||
margin 20px 0 10px 0
|
||||
button
|
||||
outline none
|
||||
font-size 48px
|
||||
color #A0A0A0
|
||||
background-color transparent
|
||||
border none
|
||||
margin 0 5px
|
||||
border-radius 5px
|
||||
&:hover
|
||||
transition 0.2s
|
||||
background-color alpha($ui-button--hover-backgroundColor, 30%)
|
||||
color $ui-inactive-text-color
|
||||
p
|
||||
font-size 13px
|
||||
color #A0A0A0
|
||||
font-weight light
|
||||
&:hover
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.export--enable
|
||||
cursor pointer
|
||||
|
||||
.export--unable
|
||||
cursor not-allowed
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-infoButton-panel
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
border 1px solid $ui-dark-borderColor
|
||||
|
||||
.control-infoButton-panel-trash
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
border 1px solid $ui-dark-borderColor
|
||||
|
||||
.group-section-label
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.group-section-control
|
||||
color $ui-dark-text-color
|
||||
|
||||
.group-section-control input
|
||||
background-color alpha($ui-dark-borderColor, 80%)
|
||||
color $ui-dark-text-color
|
||||
|
||||
[id=export-wrap]
|
||||
button
|
||||
color $ui-dark-inactive-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-dark-borderColor, 20%)
|
||||
color $ui-dark-text-color
|
||||
p
|
||||
color $ui-dark-inactive-text-color
|
||||
&:hover
|
||||
color $ui-dark-text-color
|
||||
70
browser/main/Detail/InfoPanelTrashed.js
Normal file
70
browser/main/Detail/InfoPanelTrashed.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoPanel.styl'
|
||||
|
||||
const InfoPanelTrashed = ({
|
||||
storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt
|
||||
}) => (
|
||||
<div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Storage
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{storageName}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Folder
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<text>Trash</text>{folderName}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Created
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{createdAt}
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Updated
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
{updatedAt}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='export-wrap'>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
||||
<i className='fa fa-file-code-o fa-fw' />
|
||||
<p>.md</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
|
||||
<i className='fa fa-file-text-o fa-fw' />
|
||||
<p>.txt</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--unable'>
|
||||
<i className='fa fa-file-pdf-o fa-fw' />
|
||||
<p>.pdf</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
InfoPanelTrashed.propTypes = {
|
||||
storageName: PropTypes.string.isRequired,
|
||||
folderName: PropTypes.string.isRequired,
|
||||
updatedAt: PropTypes.string.isRequired,
|
||||
createdAt: PropTypes.string.isRequired,
|
||||
exportAsMd: PropTypes.func.isRequired,
|
||||
exportAsTxt: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(InfoPanelTrashed, styles)
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @fileoverview Component for show updated date of the detail.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import { getLastUpdated } from 'browser/lib/date-formatter'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './LastUpdatedString.styl'
|
||||
|
||||
const LastUpdatedString = ({ date }) => {
|
||||
let text = ''
|
||||
|
||||
try {
|
||||
text = `Last updated at ${getLastUpdated(date)}`
|
||||
} catch (e) {
|
||||
text = ''
|
||||
}
|
||||
|
||||
return (
|
||||
<p styleName='info-right-date'>{text}</p>
|
||||
)
|
||||
}
|
||||
|
||||
LastUpdatedString.propTypes = {
|
||||
date: PropTypes.string
|
||||
}
|
||||
|
||||
export default CSSModules(LastUpdatedString, styles)
|
||||
@@ -1,10 +0,0 @@
|
||||
.info-right-date
|
||||
display inline
|
||||
line-height 24px
|
||||
padding-right 25px
|
||||
font-size 11px
|
||||
color $ui-button-color
|
||||
|
||||
body[data-theme="dark"]
|
||||
.info-right-date
|
||||
color $ui-dark-button-color
|
||||
@@ -14,6 +14,12 @@ import StatusBar from '../StatusBar'
|
||||
import _ from 'lodash'
|
||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import TrashButton from './TrashButton'
|
||||
import InfoButton from './InfoButton'
|
||||
import InfoPanel from './InfoPanel'
|
||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||
import { formatDate } from 'browser/lib/date-formatter'
|
||||
import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus'
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote } = electron
|
||||
@@ -52,7 +58,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
note: Object.assign({}, nextProps.note)
|
||||
}, () => {
|
||||
this.refs.content.reload()
|
||||
this.refs.tags.reset()
|
||||
if (this.refs.tags) this.refs.tags.reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -65,29 +71,11 @@ class MarkdownNoteDetail extends React.Component {
|
||||
ee.off('topbar:togglelockbutton', this.toggleLockButton)
|
||||
}
|
||||
|
||||
getPercentageOfCompleteTodo (noteContent) {
|
||||
let splitted = noteContent.split('\n')
|
||||
let numberOfTodo = 0
|
||||
let numberOfCompletedTodo = 0
|
||||
|
||||
splitted.forEach((line) => {
|
||||
let trimmedLine = line.trim()
|
||||
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
|
||||
numberOfTodo++
|
||||
}
|
||||
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) {
|
||||
numberOfCompletedTodo++
|
||||
}
|
||||
})
|
||||
|
||||
return Math.floor(numberOfCompletedTodo / numberOfTodo * 100)
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
let { note } = this.state
|
||||
|
||||
note.content = this.refs.content.value
|
||||
note.tags = this.refs.tags.value
|
||||
if (this.refs.tags) note.tags = this.refs.tags.value
|
||||
note.title = markdown.strip(findNoteTitle(note.content))
|
||||
note.updatedAt = new Date()
|
||||
|
||||
@@ -117,7 +105,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('EDIT_NOTE')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -156,7 +144,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
handleStarButtonClick (e) {
|
||||
let { note } = this.state
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_STAR')
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
|
||||
|
||||
note.isStarred = !note.isStarred
|
||||
|
||||
@@ -171,14 +159,26 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
handleDeleteButtonClick (e) {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Delete a note',
|
||||
detail: 'This work cannot be undone.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (index === 0) {
|
||||
exportAsMd () {
|
||||
ee.emit('export:save-md')
|
||||
}
|
||||
|
||||
exportAsTxt () {
|
||||
ee.emit('export:save-text')
|
||||
}
|
||||
|
||||
handleTrashButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { isTrashed } = note
|
||||
|
||||
if (isTrashed) {
|
||||
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Confirm note deletion',
|
||||
detail: 'This will permanently remove this note.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (dialogueButtonIndex === 1) return
|
||||
let { note, dispatch } = this.props
|
||||
dataApi
|
||||
.deleteNote(note.storage, note.key)
|
||||
@@ -191,9 +191,31 @@ class MarkdownNoteDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
ee.once('list:moved', dispatchHandler)
|
||||
ee.emit('list:next')
|
||||
})
|
||||
} else {
|
||||
note.isTrashed = true
|
||||
|
||||
this.setState({
|
||||
note
|
||||
}, () => {
|
||||
this.save()
|
||||
})
|
||||
}
|
||||
ee.emit('list:next')
|
||||
}
|
||||
|
||||
handleUndoButtonClick (e) {
|
||||
let { note } = this.state
|
||||
|
||||
note.isTrashed = false
|
||||
|
||||
this.setState({
|
||||
note
|
||||
}, () => {
|
||||
this.save()
|
||||
this.refs.content.reload()
|
||||
ee.emit('list:next')
|
||||
})
|
||||
}
|
||||
|
||||
handleFullScreenButton (e) {
|
||||
@@ -208,7 +230,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
getToggleLockButton () {
|
||||
return this.state.isLocked ? 'fa-lock' : 'fa-unlock-alt'
|
||||
return this.state.isLocked ? 'fa-lock' : 'fa-unlock'
|
||||
}
|
||||
|
||||
handleDeleteKeyDown (e) {
|
||||
@@ -228,76 +250,120 @@ class MarkdownNoteDetail extends React.Component {
|
||||
this.focus()
|
||||
}
|
||||
|
||||
handleInfoButtonClick (e) {
|
||||
const infoPanel = document.querySelector('.infoPanel')
|
||||
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, config } = this.props
|
||||
let { data, config, location } = this.props
|
||||
let { note } = this.state
|
||||
let storageKey = note.storage
|
||||
let folderKey = note.folder
|
||||
|
||||
let options = []
|
||||
data.storageMap.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
options.push({
|
||||
storage: storage,
|
||||
folder: folder
|
||||
})
|
||||
})
|
||||
})
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
const trashTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<i styleName='undo-button'
|
||||
className='fa fa-undo fa-fw'
|
||||
onClick={(e) => this.handleUndoButtonClick(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
<InfoPanelTrashed
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
updatedAt={formatDate(note.updatedAt)}
|
||||
createdAt={formatDate(note.createdAt)}
|
||||
exportAsMd={this.exportAsMd}
|
||||
exportAsTxt={this.exportAsTxt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
data={data}
|
||||
onChange={(e) => this.handleFolderChange(e)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TagSelect
|
||||
ref='tags'
|
||||
value={this.state.note.tags}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
<TodoListPercentage
|
||||
percentageOfTodo={getTodoPercentageOfCompleted(note.content)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
{(() => {
|
||||
const faClassName = `fa ${this.getToggleLockButton()}`
|
||||
const lockButtonComponent =
|
||||
<button styleName='control-lockButton'
|
||||
onFocus={(e) => this.handleFocus(e)}
|
||||
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
||||
>
|
||||
<i className={faClassName} styleName='lock-button' />
|
||||
<span styleName='control-lockButton-tooltip'>
|
||||
{this.state.isLocked ? 'Unlock' : 'Lock'}
|
||||
</span>
|
||||
</button>
|
||||
return (
|
||||
this.state.isLockButtonShown ? lockButtonComponent : ''
|
||||
)
|
||||
})()}
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-expand' styleName='fullScreen-button' />
|
||||
</button>
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
<InfoPanel
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
noteLink={`[${note.title}](${location.query.key})`}
|
||||
updatedAt={formatDate(note.updatedAt)}
|
||||
createdAt={formatDate(note.createdAt)}
|
||||
exportAsMd={this.exportAsMd}
|
||||
exportAsTxt={this.exportAsTxt}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className='NoteDetail'
|
||||
style={this.props.style}
|
||||
styleName='root'
|
||||
>
|
||||
<div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
data={data}
|
||||
onChange={(e) => this.handleFolderChange(e)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TagSelect
|
||||
ref='tags'
|
||||
value={this.state.note.tags}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
<TodoListPercentage
|
||||
percentageOfTodo={this.getPercentageOfCompleteTodo(note.content)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
{(() => {
|
||||
const faClassName = `fa ${this.getToggleLockButton()}`
|
||||
const lockButtonComponent =
|
||||
<button styleName='control-lockButton'
|
||||
onFocus={(e) => this.handleFocus(e)}
|
||||
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
||||
>
|
||||
<i className={faClassName} styleName='lock-button' />
|
||||
<span styleName='control-lockButton-tooltip'>
|
||||
{this.state.isLocked ? 'Unlock' : 'Lock'}
|
||||
</span>
|
||||
</button>
|
||||
return (
|
||||
this.state.isLockButtonShown ? lockButtonComponent : ''
|
||||
)
|
||||
})()}
|
||||
<button styleName='control-trashButton'
|
||||
onClick={(e) => this.handleDeleteButtonClick(e)}
|
||||
>
|
||||
<svg height='14px' id='Capa_1' style={{enableBackground: 'new 0 0 753.23 753.23'}} width='14px' version='1.1' viewBox='0 0 753.23 753.23' x='0px' y='0px' xmlSpace='preserve'>
|
||||
<g>
|
||||
<g id='_x34__19_'>
|
||||
<g>
|
||||
<path d='M494.308,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077c0-12.993-10.545-23.539-23.538-23.539
				s-23.538,10.545-23.538,23.539v282.461C470.77,648.531,481.314,659.077,494.308,659.077z M635.538,94.154h-141.23V47.077
				C494.308,21.067,473.24,0,447.23,0H306c-26.01,0-47.077,21.067-47.077,47.077v47.077h-141.23
				c-26.01,0-47.077,21.067-47.077,47.077v47.077c0,25.986,21.067,47.077,47.077,47.077v423.692
				c0,51.996,42.157,94.153,94.154,94.153h329.539c51.996,0,94.153-42.157,94.153-94.153V235.385
				c26.01,0,47.077-21.091,47.077-47.077V141.23C682.615,115.221,661.548,94.154,635.538,94.154z M306,70.615
				c0-12.993,10.545-23.539,23.538-23.539h94.154c12.993,0,23.538,10.545,23.538,23.539v23.539c-22.809,0-141.23,0-141.23,0V70.615z
				 M588.461,659.077c0,25.986-21.066,47.076-47.076,47.076H211.846c-26.01,0-47.077-21.09-47.077-47.076V235.385h423.692V659.077z
				 M612,188.308H141.23c-12.993,0-23.538-10.545-23.538-23.539s10.545-23.539,23.538-23.539H612
				c12.993,0,23.538,10.545,23.538,23.539S624.993,188.308,612,188.308z M258.923,659.077c12.993,0,23.539-10.546,23.539-23.539
				V353.077c0-12.993-10.545-23.539-23.539-23.539s-23.539,10.545-23.539,23.539v282.461
				C235.384,648.531,245.93,659.077,258.923,659.077z M376.615,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077
				c0-12.993-10.545-23.539-23.538-23.539s-23.539,10.545-23.539,23.539v282.461C353.077,648.531,363.622,659.077,376.615,659.077z' />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-arrows-alt' styleName='fullScreen-button' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{location.pathname === '/trashed' ? trashTopBar : detailTopBar}
|
||||
|
||||
<div styleName='body'>
|
||||
<MarkdownEditor
|
||||
|
||||
@@ -27,12 +27,9 @@
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
.control-trashButton
|
||||
float right
|
||||
topBarButtonLight()
|
||||
|
||||
.control-fullScreenButton
|
||||
float right
|
||||
padding 0 0 2px 0
|
||||
topBarButtonLight()
|
||||
|
||||
.body
|
||||
@@ -57,8 +54,5 @@ body[data-theme="dark"]
|
||||
.control-lockButton-tooltip
|
||||
darkTooltip()
|
||||
|
||||
.control-trashButton
|
||||
topBarButtonDark()
|
||||
|
||||
.control-fullScreenButton
|
||||
topBarButtonDark()
|
||||
|
||||
@@ -15,26 +15,26 @@ $info-margin-under-border = 27px
|
||||
float left
|
||||
padding 0 5px
|
||||
margin 0px 2px
|
||||
|
||||
.info-left-top
|
||||
display inline-block
|
||||
height $info-height
|
||||
line-height $info-height
|
||||
|
||||
.info-left-top-folderSelect
|
||||
display inline-block
|
||||
padding 0 3px
|
||||
height 34px
|
||||
line-height 34px
|
||||
vertical-align middle
|
||||
line-height 26px
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
border-radius 3px
|
||||
|
||||
.info-left-button
|
||||
width 34px
|
||||
height 34px
|
||||
navButtonColor()
|
||||
color $ui-favorite-star-button-color
|
||||
font-size 14px
|
||||
line-height 0
|
||||
margin 13px 2px
|
||||
padding 0
|
||||
border-radius 17px
|
||||
@@ -44,7 +44,7 @@ $info-margin-under-border = 27px
|
||||
border-color $ui-favorite-star-button-color
|
||||
&:active, &:active:hover
|
||||
background-color $ui-favorite-star-button-color
|
||||
color $ui-button--active-color
|
||||
color $ui-button--color
|
||||
|
||||
.info-right
|
||||
position absolute
|
||||
@@ -54,6 +54,27 @@ $info-margin-under-border = 27px
|
||||
bottom 1px
|
||||
padding-left 30px
|
||||
|
||||
.undo-button
|
||||
width 34px
|
||||
height 34px
|
||||
border-radius 17px
|
||||
font-size 14px
|
||||
margin 15px 7px
|
||||
border none
|
||||
color $ui-button-color
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
fill $ui-button-color
|
||||
background-color transparent
|
||||
cursor pointer
|
||||
&:active
|
||||
border-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
||||
.control-lockButton-tooltip
|
||||
opacity 1
|
||||
|
||||
body[data-theme="dark"]
|
||||
.info
|
||||
border-color $ui-dark-borderColor
|
||||
@@ -73,3 +94,6 @@ body[data-theme="dark"]
|
||||
|
||||
.info-right
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
.undo-button
|
||||
topBarButtonDark()
|
||||
@@ -17,6 +17,11 @@ import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import _ from 'lodash'
|
||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import TrashButton from './TrashButton'
|
||||
import InfoButton from './InfoButton'
|
||||
import InfoPanel from './InfoPanel'
|
||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||
import { formatDate } from 'browser/lib/date-formatter'
|
||||
|
||||
function pass (name) {
|
||||
switch (name) {
|
||||
@@ -53,7 +58,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.note.key !== this.props.note.key) {
|
||||
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
|
||||
if (this.saveQueue != null) this.saveNow()
|
||||
let nextNote = Object.assign({
|
||||
description: ''
|
||||
@@ -68,7 +73,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
snippets.forEach((snippet, index) => {
|
||||
this.refs['code-' + index].reload()
|
||||
})
|
||||
this.refs.tags.reset()
|
||||
if (this.refs.tags) this.refs.tags.reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -80,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
handleChange (e) {
|
||||
let { note } = this.state
|
||||
|
||||
note.tags = this.refs.tags.value
|
||||
if (this.refs.tags) note.tags = this.refs.tags.value
|
||||
note.description = this.refs.description.value
|
||||
note.updatedAt = new Date()
|
||||
note.title = findNoteTitle(note.description)
|
||||
@@ -111,7 +116,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('EDIT_NOTE')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -150,7 +155,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
handleStarButtonClick (e) {
|
||||
let { note } = this.state
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_STAR')
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
|
||||
|
||||
note.isStarred = !note.isStarred
|
||||
|
||||
@@ -165,14 +170,18 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
}
|
||||
|
||||
handleDeleteButtonClick (e) {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Delete a note',
|
||||
detail: 'This work cannot be undone.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (index === 0) {
|
||||
handleTrashButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { isTrashed } = note
|
||||
|
||||
if (isTrashed) {
|
||||
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Confirm note deletion',
|
||||
detail: 'This will permanently remove this note.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (dialogueButtonIndex === 1) return
|
||||
let { note, dispatch } = this.props
|
||||
dataApi
|
||||
.deleteNote(note.storage, note.key)
|
||||
@@ -185,9 +194,30 @@ class SnippetNoteDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
ee.once('list:moved', dispatchHandler)
|
||||
ee.emit('list:next')
|
||||
})
|
||||
} else {
|
||||
note.isTrashed = true
|
||||
|
||||
this.setState({
|
||||
note
|
||||
}, () => {
|
||||
this.save()
|
||||
})
|
||||
}
|
||||
ee.emit('list:next')
|
||||
}
|
||||
|
||||
handleUndoButtonClick (e) {
|
||||
let { note } = this.state
|
||||
|
||||
note.isTrashed = false
|
||||
|
||||
this.setState({
|
||||
note
|
||||
}, () => {
|
||||
this.save()
|
||||
ee.emit('list:next')
|
||||
})
|
||||
}
|
||||
|
||||
handleFullScreenButton (e) {
|
||||
@@ -432,10 +462,27 @@ class SnippetNoteDetail extends React.Component {
|
||||
this.refs['code-' + this.state.snippetIndex].focus()
|
||||
}
|
||||
|
||||
handleInfoButtonClick (e) {
|
||||
const infoPanel = document.querySelector('.infoPanel')
|
||||
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
|
||||
}
|
||||
|
||||
showWarning () {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Sorry!',
|
||||
detail: 'md/text import is available only a markdown note.',
|
||||
buttons: ['OK']
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, config } = this.props
|
||||
let { data, config, location } = this.props
|
||||
let { note } = this.state
|
||||
|
||||
let storageKey = note.storage
|
||||
let folderKey = note.folder
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
@@ -473,6 +520,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
onChange={(e) => this.handleCodeChange(index)(e)}
|
||||
ref={'code-' + index}
|
||||
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
|
||||
storageKey={storageKey}
|
||||
/>
|
||||
: <CodeEditor styleName='tabView-content'
|
||||
mode={snippet.mode}
|
||||
@@ -490,54 +538,90 @@ class SnippetNoteDetail extends React.Component {
|
||||
</div>
|
||||
})
|
||||
|
||||
let options = []
|
||||
data.storageMap.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
options.push({
|
||||
storage: storage,
|
||||
folder: folder
|
||||
})
|
||||
})
|
||||
})
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
const trashTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<i styleName='undo-button'
|
||||
className='fa fa-undo fa-fw'
|
||||
onClick={(e) => this.handleUndoButtonClick(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
<InfoPanelTrashed
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
updatedAt={formatDate(note.updatedAt)}
|
||||
createdAt={formatDate(note.createdAt)}
|
||||
exportAsMd={this.showWarning}
|
||||
exportAsTxt={this.showWarning}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
data={data}
|
||||
onChange={(e) => this.handleFolderChange(e)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TagSelect
|
||||
ref='tags'
|
||||
value={this.state.note.tags}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-expand' styleName='fullScreen-button' />
|
||||
</button>
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
<InfoPanel
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
noteLink={`[${note.title}](${location.query.key})`}
|
||||
updatedAt={formatDate(note.updatedAt)}
|
||||
createdAt={formatDate(note.createdAt)}
|
||||
exportAsMd={this.showWarning}
|
||||
exportAsTxt={this.showWarning}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className='NoteDetail'
|
||||
style={this.props.style}
|
||||
styleName='root'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
data={data}
|
||||
onChange={(e) => this.handleFolderChange(e)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TagSelect
|
||||
ref='tags'
|
||||
value={this.state.note.tags}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<button styleName='control-trashButton'
|
||||
onClick={(e) => this.handleDeleteButtonClick(e)}
|
||||
>
|
||||
<svg height='14px' id='Capa_1' style={{enableBackground: 'new 0 0 753.23 753.23'}} width='14px' version='1.1' viewBox='0 0 753.23 753.23' x='0px' y='0px' xmlSpace='preserve'>
|
||||
<g>
|
||||
<g id='_x34__19_'>
|
||||
<g>
|
||||
<path d='M494.308,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077c0-12.993-10.545-23.539-23.538-23.539
				s-23.538,10.545-23.538,23.539v282.461C470.77,648.531,481.314,659.077,494.308,659.077z M635.538,94.154h-141.23V47.077
				C494.308,21.067,473.24,0,447.23,0H306c-26.01,0-47.077,21.067-47.077,47.077v47.077h-141.23
				c-26.01,0-47.077,21.067-47.077,47.077v47.077c0,25.986,21.067,47.077,47.077,47.077v423.692
				c0,51.996,42.157,94.153,94.154,94.153h329.539c51.996,0,94.153-42.157,94.153-94.153V235.385
				c26.01,0,47.077-21.091,47.077-47.077V141.23C682.615,115.221,661.548,94.154,635.538,94.154z M306,70.615
				c0-12.993,10.545-23.539,23.538-23.539h94.154c12.993,0,23.538,10.545,23.538,23.539v23.539c-22.809,0-141.23,0-141.23,0V70.615z
				 M588.461,659.077c0,25.986-21.066,47.076-47.076,47.076H211.846c-26.01,0-47.077-21.09-47.077-47.076V235.385h423.692V659.077z
				 M612,188.308H141.23c-12.993,0-23.538-10.545-23.538-23.539s10.545-23.539,23.538-23.539H612
				c12.993,0,23.538,10.545,23.538,23.539S624.993,188.308,612,188.308z M258.923,659.077c12.993,0,23.539-10.546,23.539-23.539
				V353.077c0-12.993-10.545-23.539-23.539-23.539s-23.539,10.545-23.539,23.539v282.461
				C235.384,648.531,245.93,659.077,258.923,659.077z M376.615,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077
				c0-12.993-10.545-23.539-23.538-23.539s-23.539,10.545-23.539,23.539v282.461C353.077,648.531,363.622,659.077,376.615,659.077z' />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-arrows-alt' styleName='fullScreen-button' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{location.pathname === '/trashed' ? trashTopBar : detailTopBar}
|
||||
|
||||
<div styleName='body'>
|
||||
<div styleName='description'>
|
||||
|
||||
@@ -66,12 +66,9 @@
|
||||
&:active .update-icon
|
||||
color white
|
||||
|
||||
.control-trashButton
|
||||
float right
|
||||
topBarButtonLight()
|
||||
|
||||
.control-fullScreenButton
|
||||
float right
|
||||
padding 0 0 2px 0
|
||||
topBarButtonLight()
|
||||
|
||||
body[data-theme="dark"]
|
||||
@@ -104,8 +101,5 @@ body[data-theme="dark"]
|
||||
transition 0.15s
|
||||
color $ui-dark-text-color
|
||||
|
||||
.control-trashButton
|
||||
topBarButtonDark()
|
||||
|
||||
.control-fullScreenButton
|
||||
topBarButtonDark()
|
||||
|
||||
@@ -57,7 +57,7 @@ class TagSelect extends React.Component {
|
||||
}
|
||||
|
||||
submitTag () {
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_TAG')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
|
||||
let { value } = this.props
|
||||
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.root
|
||||
display inline-block
|
||||
top 19px
|
||||
user-select none
|
||||
height 23px
|
||||
vertical-align middle
|
||||
width 300px
|
||||
overflow-x scroll
|
||||
@@ -14,7 +14,6 @@
|
||||
display inline-block
|
||||
margin 1px 3px
|
||||
padding 0
|
||||
vertical-align middle
|
||||
height 20px
|
||||
background-color alpha($ui-tag-backgroundColor, 10%)
|
||||
border-radius 3px
|
||||
@@ -49,9 +48,9 @@
|
||||
|
||||
.newTag
|
||||
display inline-block
|
||||
margin 0 2px
|
||||
margin 2px 0 15px 2px
|
||||
vertical-align middle
|
||||
height 24px
|
||||
height 18px
|
||||
box-sizing borde-box
|
||||
border none
|
||||
background-color transparent
|
||||
|
||||
19
browser/main/Detail/TrashButton.js
Normal file
19
browser/main/Detail/TrashButton.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TrashButton.styl'
|
||||
|
||||
const TrashButton = ({
|
||||
onClick
|
||||
}) => (
|
||||
<button styleName='control-trashButton'
|
||||
onClick={(e) => onClick(e)}
|
||||
>
|
||||
<i className='fa fa-trash trashButton' styleName='info-button' />
|
||||
</button>
|
||||
)
|
||||
|
||||
TrashButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(TrashButton, styles)
|
||||
11
browser/main/Detail/TrashButton.styl
Normal file
11
browser/main/Detail/TrashButton.styl
Normal file
@@ -0,0 +1,11 @@
|
||||
.control-trashButton
|
||||
float right
|
||||
topBarButtonLight()
|
||||
|
||||
.trashButton
|
||||
padding 0px
|
||||
margin 15px 0
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-trashButton
|
||||
topBarButtonDark()
|
||||
@@ -17,7 +17,7 @@ class Detail extends React.Component {
|
||||
this.refs.root != null && this.refs.root.focus()
|
||||
}
|
||||
this.deleteHandler = () => {
|
||||
this.refs.root != null && this.refs.root.handleDeleteButtonClick()
|
||||
this.refs.root != null && this.refs.root.handleTrashButtonClick()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class Detail extends React.Component {
|
||||
tabIndex='0'
|
||||
>
|
||||
<div styleName='empty'>
|
||||
<div styleName='empty-message'>{OSX ? 'Command(⌘)' : 'Ctrl(^)'} + N<br />to create a new post</div>
|
||||
<div styleName='empty-message'>{OSX ? 'Command(⌘)' : 'Ctrl(^)'} + N<br />to create a new note</div>
|
||||
</div>
|
||||
<StatusBar
|
||||
{..._.pick(this.props, ['config', 'location', 'dispatch'])}
|
||||
|
||||
@@ -12,7 +12,7 @@ import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import modal from 'browser/main/lib/modal'
|
||||
import InitModal from 'browser/main/modals/InitModal'
|
||||
import mixpanel from 'browser/main/lib/mixpanel'
|
||||
import mobileAnalytics from 'browser/main/lib/awsMobileAnalyticsConfig'
|
||||
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
|
||||
function focused () {
|
||||
@@ -160,26 +160,29 @@ class Main extends React.Component {
|
||||
handleFullScreenButton (e) {
|
||||
this.setState({ fullScreen: !this.state.fullScreen }, () => {
|
||||
const noteDetail = document.querySelector('.NoteDetail')
|
||||
const noteList = document.querySelector('.NoteList')
|
||||
const mainBody = document.querySelector('#main-body')
|
||||
|
||||
if (this.state.fullScreen) {
|
||||
this.hideLeftLists(noteDetail, mainBody)
|
||||
this.hideLeftLists(noteDetail, noteList, mainBody)
|
||||
} else {
|
||||
this.showLeftLists(noteDetail, mainBody)
|
||||
this.showLeftLists(noteDetail, noteList, mainBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
hideLeftLists (noteDetail, mainBody) {
|
||||
hideLeftLists (noteDetail, noteList, mainBody) {
|
||||
this.state.noteDetailWidth = noteDetail.style.left
|
||||
this.state.mainBodyWidth = mainBody.style.left
|
||||
noteDetail.style.left = '0px'
|
||||
mainBody.style.left = '0px'
|
||||
noteList.style.display = 'none'
|
||||
}
|
||||
|
||||
showLeftLists (noteDetail, mainBody) {
|
||||
showLeftLists (noteDetail, noteList, mainBody) {
|
||||
noteDetail.style.left = this.state.noteDetailWidth
|
||||
mainBody.style.left = this.state.mainBodyWidth
|
||||
noteList.style.display = 'inline'
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
@@ -17,7 +17,7 @@ $control-height = 30px
|
||||
|
||||
.control-sortBy
|
||||
flex 1
|
||||
padding-left 25px
|
||||
padding-left 22px
|
||||
|
||||
.control-sortBy-select
|
||||
appearance: none;
|
||||
@@ -28,11 +28,14 @@ $control-height = 30px
|
||||
background-color transparent
|
||||
outline none
|
||||
cursor pointer
|
||||
font-size 10px
|
||||
font-size 11px
|
||||
&:hover
|
||||
transition 0.2s
|
||||
color $ui-text-color
|
||||
|
||||
.control-button-area
|
||||
margin-right 12px
|
||||
|
||||
.control-button
|
||||
width 25px
|
||||
padding 0
|
||||
|
||||
@@ -9,6 +9,10 @@ import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import NoteItem from 'browser/components/NoteItem'
|
||||
import NoteItemSimple from 'browser/components/NoteItemSimple'
|
||||
import searchFromNotes from 'browser/lib/search'
|
||||
import fs from 'fs'
|
||||
import { hashHistory } from 'react-router'
|
||||
import markdown from 'browser/lib/markdown'
|
||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { Menu, MenuItem, dialog } = remote
|
||||
@@ -42,10 +46,8 @@ class NoteList extends React.Component {
|
||||
this.alertIfSnippetHandler = () => {
|
||||
this.alertIfSnippet()
|
||||
}
|
||||
|
||||
this.jumpToTopHandler = () => {
|
||||
this.jumpToTop()
|
||||
}
|
||||
this.importFromFileHandler = this.importFromFile.bind(this)
|
||||
this.jumpNoteByHash = this.jumpNoteByHashHandler.bind(this)
|
||||
|
||||
this.state = {
|
||||
}
|
||||
@@ -57,8 +59,8 @@ class NoteList extends React.Component {
|
||||
ee.on('list:prior', this.selectPriorNoteHandler)
|
||||
ee.on('list:focus', this.focusHandler)
|
||||
ee.on('list:isMarkdownNote', this.alertIfSnippetHandler)
|
||||
ee.on('list:top', this.jumpToTopHandler)
|
||||
ee.on('list:jumpToTop', this.jumpToTopHandler)
|
||||
ee.on('import:file', this.importFromFileHandler)
|
||||
ee.on('list:jump', this.jumpNoteByHash)
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
@@ -78,8 +80,8 @@ class NoteList extends React.Component {
|
||||
ee.off('list:prior', this.selectPriorNoteHandler)
|
||||
ee.off('list:focus', this.focusHandler)
|
||||
ee.off('list:isMarkdownNote', this.alertIfSnippetHandler)
|
||||
ee.off('list:top', this.jumpToTopHandler)
|
||||
ee.off('list:jumpToTop', this.jumpToTopHandler)
|
||||
ee.off('import:file', this.importFromFileHandler)
|
||||
ee.off('list:jump', this.jumpNoteByHash)
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
@@ -172,6 +174,31 @@ class NoteList extends React.Component {
|
||||
ee.emit('list:moved')
|
||||
}
|
||||
|
||||
jumpNoteByHashHandler (event, noteHash) {
|
||||
// first argument event isn't used.
|
||||
if (this.notes === null || this.notes.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const { router } = this.context
|
||||
const { location } = this.props
|
||||
|
||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
||||
return note.storage + '-' + note.key === noteHash
|
||||
})
|
||||
|
||||
if (targetIndex < 0) targetIndex = 0
|
||||
|
||||
router.push({
|
||||
pathname: location.pathname,
|
||||
query: {
|
||||
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
|
||||
}
|
||||
})
|
||||
|
||||
ee.emit('list:moved')
|
||||
}
|
||||
|
||||
handleNoteListKeyDown (e) {
|
||||
if (e.metaKey || e.ctrlKey) return true
|
||||
|
||||
@@ -219,7 +246,12 @@ class NoteList extends React.Component {
|
||||
if (searchInputText === '') {
|
||||
router.push('/home')
|
||||
}
|
||||
return searchFromNotes(this.props.data, searchInputText)
|
||||
return searchFromNotes(this.notes, searchInputText)
|
||||
}
|
||||
|
||||
if (location.pathname.match(/\/trashed/)) {
|
||||
return data.trashedSet.toJS()
|
||||
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||
}
|
||||
|
||||
let storageKey = params.storageKey
|
||||
@@ -257,49 +289,6 @@ class NoteList extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleNoteContextMenu (e, uniqueKey) {
|
||||
let menu = new Menu()
|
||||
menu.append(new MenuItem({
|
||||
label: 'Delete Note',
|
||||
click: (e) => this.handleDeleteNote(e, uniqueKey)
|
||||
}))
|
||||
menu.popup()
|
||||
}
|
||||
|
||||
handleDeleteNote (e, uniqueKey) {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Delete a note',
|
||||
detail: 'This work cannot be undone.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (index === 0) {
|
||||
let { dispatch, location } = this.props
|
||||
let splitted = uniqueKey.split('-')
|
||||
let storageKey = splitted.shift()
|
||||
let noteKey = splitted.shift()
|
||||
|
||||
dataApi
|
||||
.deleteNote(storageKey, noteKey)
|
||||
.then((data) => {
|
||||
let dispatchHandler = () => {
|
||||
dispatch({
|
||||
type: 'DELETE_NOTE',
|
||||
storageKey: data.storageKey,
|
||||
noteKey: data.noteKey
|
||||
})
|
||||
}
|
||||
|
||||
if (location.query.key === uniqueKey) {
|
||||
ee.once('list:moved', dispatchHandler)
|
||||
ee.emit('list:next')
|
||||
} else {
|
||||
dispatchHandler()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSortByChange (e) {
|
||||
let { dispatch } = this.props
|
||||
|
||||
@@ -343,28 +332,56 @@ class NoteList extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
jumpToTop () {
|
||||
if (this.notes === null || this.notes.length === 0) {
|
||||
return
|
||||
}
|
||||
let { router } = this.context
|
||||
let { location } = this.props
|
||||
|
||||
const targetIndex = 0
|
||||
|
||||
router.push({
|
||||
pathname: location.pathname,
|
||||
query: {
|
||||
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleDragStart (e, note) {
|
||||
const noteData = JSON.stringify(note)
|
||||
e.dataTransfer.setData('note', noteData)
|
||||
}
|
||||
|
||||
importFromFile () {
|
||||
const { dispatch, location } = this.props
|
||||
|
||||
const options = {
|
||||
filters: [
|
||||
{ name: 'Documents', extensions: ['md', 'txt'] }
|
||||
],
|
||||
properties: ['openFile', 'multiSelections']
|
||||
}
|
||||
|
||||
const targetIndex = _.findIndex(this.notes, (note) => {
|
||||
return note !== null && `${note.storage}-${note.key}` === location.query.key
|
||||
})
|
||||
|
||||
const storageKey = this.notes[targetIndex].storage
|
||||
const folderKey = this.notes[targetIndex].folder
|
||||
|
||||
dialog.showOpenDialog(remote.getCurrentWindow(), options, (filepaths) => {
|
||||
if (filepaths === undefined) return
|
||||
filepaths.forEach((filepath) => {
|
||||
fs.readFile(filepath, (err, data) => {
|
||||
if (err) throw Error('File reading error: ', err)
|
||||
const content = data.toString()
|
||||
const newNote = {
|
||||
content: content,
|
||||
folder: folderKey,
|
||||
title: markdown.strip(findNoteTitle(content)),
|
||||
type: 'MARKDOWN_NOTE'
|
||||
}
|
||||
dataApi.createNote(storageKey, newNote)
|
||||
.then((note) => {
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
hashHistory.push({
|
||||
pathname: location.pathname,
|
||||
query: {key: `${note.storage}-${note.key}`}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
let { location, notes, config, dispatch } = this.props
|
||||
let sortFunc = config.sortBy === 'CREATED_AT'
|
||||
@@ -374,6 +391,10 @@ class NoteList extends React.Component {
|
||||
: sortByUpdatedAt
|
||||
this.notes = notes = this.getNotes()
|
||||
.sort(sortFunc)
|
||||
.filter((note) => {
|
||||
// this is for the trash box
|
||||
if (note.isTrashed !== true || location.pathname === '/trashed') return true
|
||||
})
|
||||
|
||||
let noteList = notes
|
||||
.map(note => {
|
||||
@@ -397,7 +418,6 @@ class NoteList extends React.Component {
|
||||
dateDisplay={dateDisplay}
|
||||
key={key}
|
||||
handleNoteClick={this.handleNoteClick.bind(this)}
|
||||
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
|
||||
handleDragStart={this.handleDragStart.bind(this)}
|
||||
/>
|
||||
)
|
||||
@@ -409,7 +429,6 @@ class NoteList extends React.Component {
|
||||
note={note}
|
||||
key={key}
|
||||
handleNoteClick={this.handleNoteClick.bind(this)}
|
||||
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
|
||||
handleDragStart={this.handleDragStart.bind(this)}
|
||||
/>
|
||||
)
|
||||
@@ -427,27 +446,29 @@ class NoteList extends React.Component {
|
||||
value={config.sortBy}
|
||||
onChange={(e) => this.handleSortByChange(e)}
|
||||
>
|
||||
<option value='UPDATED_AT'>Updated Time</option>
|
||||
<option value='CREATED_AT'>Created Time</option>
|
||||
<option value='ALPHABETICAL'>Alphabetical</option>
|
||||
<option value='UPDATED_AT'>Last Updated</option>
|
||||
<option value='CREATED_AT'>Creation Time</option>
|
||||
<option value='ALPHABETICAL'>Alphabetically</option>
|
||||
</select>
|
||||
</div>
|
||||
<button styleName={config.listStyle === 'DEFAULT'
|
||||
? 'control-button--active'
|
||||
: 'control-button'
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
|
||||
>
|
||||
<i className='fa fa-th-large' />
|
||||
</button>
|
||||
<button styleName={config.listStyle === 'SMALL'
|
||||
? 'control-button--active'
|
||||
: 'control-button'
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
|
||||
>
|
||||
<i className='fa fa-list-ul' />
|
||||
</button>
|
||||
<div styleName='control-button-area'>
|
||||
<button styleName={config.listStyle === 'DEFAULT'
|
||||
? 'control-button--active'
|
||||
: 'control-button'
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
|
||||
>
|
||||
<i className='fa fa-th-large' />
|
||||
</button>
|
||||
<button styleName={config.listStyle === 'SMALL'
|
||||
? 'control-button--active'
|
||||
: 'control-button'
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
|
||||
>
|
||||
<i className='fa fa-list-ul' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='list'
|
||||
ref='list'
|
||||
|
||||
@@ -114,7 +114,7 @@ class StorageItem extends React.Component {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Delete Folder',
|
||||
detail: 'This work will deletes all notes in the folder and can not be undone.',
|
||||
detail: 'This will delete all notes in the folder and can not be undone.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
|
||||
@@ -180,14 +180,20 @@ class StorageItem extends React.Component {
|
||||
|
||||
render () {
|
||||
let { storage, location, isFolded, data, dispatch } = this.props
|
||||
let { folderNoteMap } = data
|
||||
let { folderNoteMap, trashedSet } = data
|
||||
let folderList = storage.folders.map((folder) => {
|
||||
let isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
|
||||
let noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
|
||||
|
||||
let noteCount = noteSet != null
|
||||
? noteSet.size
|
||||
: 0
|
||||
let noteCount = 0
|
||||
if (noteSet) {
|
||||
let trashedNoteCount = 0
|
||||
const noteKeys = noteSet.map(noteKey => { return noteKey })
|
||||
trashedSet.toJS().forEach(trashedKey => {
|
||||
if (noteKeys.some(noteKey => { return noteKey === trashedKey })) trashedNoteCount++
|
||||
})
|
||||
noteCount = noteSet.size - trashedNoteCount
|
||||
}
|
||||
return (
|
||||
<StorageItemChild
|
||||
key={folder.key}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.root
|
||||
width 100%
|
||||
user-select none
|
||||
padding-top 20px
|
||||
|
||||
.header
|
||||
position relative
|
||||
|
||||
@@ -33,12 +33,18 @@ class SideNav extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleTrashedButtonClick (e) {
|
||||
let { router } = this.context
|
||||
router.push('/trashed')
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, location, config, dispatch } = this.props
|
||||
|
||||
let isFolded = config.isSideNavFolded
|
||||
let isHomeActive = !!location.pathname.match(/^\/home$/)
|
||||
let isStarredActive = !!location.pathname.match(/^\/starred$/)
|
||||
let isTrashedActive = !!location.pathname.match(/^\/trashed$/)
|
||||
|
||||
let storageList = data.storageMap.map((storage, key) => {
|
||||
return <StorageItem
|
||||
@@ -62,8 +68,8 @@ class SideNav extends React.Component {
|
||||
<button styleName='top-menu'
|
||||
onClick={(e) => this.handleMenuButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-navicon fa-fw' />
|
||||
<span styleName='top-menu-label'>Menu</span>
|
||||
<i className='fa fa-wrench fa-fw' />
|
||||
<span styleName='top-menu-label'>Preferences</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +78,9 @@ class SideNav extends React.Component {
|
||||
isHomeActive={isHomeActive}
|
||||
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
|
||||
isStarredActive={isStarredActive}
|
||||
isTrashedActive={isTrashedActive}
|
||||
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
|
||||
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
|
||||
/>
|
||||
|
||||
<div styleName='storageList'>
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './StatusBar.styl'
|
||||
import ZoomManager from 'browser/main/lib/ZoomManager'
|
||||
import LastUpdatedString from '../Detail/LastUpdatedString'
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote, ipcRenderer } = electron
|
||||
@@ -68,8 +67,6 @@ class StatusBar extends React.Component {
|
||||
</button>
|
||||
: null
|
||||
}
|
||||
|
||||
<LastUpdatedString date={this.props.date} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,26 +19,25 @@ $control-height = 34px
|
||||
|
||||
.control-search
|
||||
height 32px
|
||||
width 1px
|
||||
flex 1
|
||||
background-color white
|
||||
position relative
|
||||
|
||||
.control-search-icon
|
||||
absolute top bottom left
|
||||
line-height 32px
|
||||
width 35px
|
||||
color $ui-inactive-text-color
|
||||
background-color $ui-noteList-backgroundColor
|
||||
|
||||
.control-search-input
|
||||
display block
|
||||
absolute top bottom right
|
||||
left 30px
|
||||
width 100%
|
||||
padding-left 12px
|
||||
background-color $ui-noteList-backgroundColor
|
||||
input
|
||||
width 100%
|
||||
height 100%
|
||||
outline none
|
||||
border none
|
||||
color $ui-text-color
|
||||
font-size 16px
|
||||
padding-bottom 2px
|
||||
background-color $ui-noteList-backgroundColor
|
||||
|
||||
.control-search-optionList
|
||||
@@ -92,9 +91,7 @@ $control-height = 34px
|
||||
width 32px
|
||||
height $control-height - 2
|
||||
navButtonColor()
|
||||
border $ui-border
|
||||
border-radius 32px
|
||||
font-size 14px
|
||||
font-size 16px
|
||||
line-height 28px
|
||||
padding 0
|
||||
&:active
|
||||
@@ -132,6 +129,7 @@ body[data-theme="dark"]
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
|
||||
.control-search-input
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
input
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
color $ui-dark-text-color
|
||||
|
||||
@@ -9,6 +9,9 @@ import ee from 'browser/main/lib/eventEmitter'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
|
||||
const OSX = window.process.platform === 'darwin'
|
||||
|
||||
class TopBar extends React.Component {
|
||||
@@ -41,7 +44,17 @@ class TopBar extends React.Component {
|
||||
}
|
||||
|
||||
handleNewPostButtonClick (e) {
|
||||
let { config } = this.props
|
||||
let { config, location } = this.props
|
||||
|
||||
if (location.pathname === '/trashed') {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Cannot create new note',
|
||||
detail: 'You cannot create new note in trash box.',
|
||||
buttons: ['OK']
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch (config.ui.defaultNote) {
|
||||
case 'MARKDOWN_NOTE':
|
||||
@@ -205,7 +218,6 @@ class TopBar extends React.Component {
|
||||
>
|
||||
<div styleName='control'>
|
||||
<div styleName='control-search'>
|
||||
<i styleName='control-search-icon' className='fa fa-search fa-fw' />
|
||||
<div styleName='control-search-input'
|
||||
onFocus={(e) => this.handleSearchFocus(e)}
|
||||
onBlur={(e) => this.handleSearchBlur(e)}
|
||||
@@ -232,7 +244,7 @@ class TopBar extends React.Component {
|
||||
</div>
|
||||
<button styleName='control-newPostButton'
|
||||
onClick={(e) => this.handleNewPostButtonClick(e)}>
|
||||
<i className='fa fa-plus' />
|
||||
<i className='fa fa-pencil-square-o' />
|
||||
<span styleName='control-newPostButton-tooltip'>
|
||||
Make a Note {OSX ? '⌘' : '^'} + n
|
||||
</span>
|
||||
|
||||
@@ -23,6 +23,16 @@ document.addEventListener('dragover', function (e) {
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
const className = e.target.className
|
||||
if (!className && typeof (className) !== 'string') return
|
||||
const isInfoButton = className.includes('infoButton')
|
||||
const isInfoPanel = e.target.offsetParent.className.includes('infoPanel')
|
||||
if (isInfoButton || isInfoPanel) return
|
||||
const infoPanel = document.querySelector('.infoPanel')
|
||||
if (infoPanel) infoPanel.style.display = 'none'
|
||||
})
|
||||
|
||||
let el = document.getElementById('content')
|
||||
const history = syncHistoryWithStore(hashHistory, store)
|
||||
|
||||
@@ -51,6 +61,7 @@ ReactDOM.render((
|
||||
<Route path='home' />
|
||||
<Route path='starred' />
|
||||
<Route path='searched' />
|
||||
<Route path='trashed' />
|
||||
<Route path='storages'>
|
||||
<IndexRedirect to='/home' />
|
||||
<Route path=':storageKey'>
|
||||
|
||||
@@ -2,17 +2,19 @@ const AWS = require('aws-sdk')
|
||||
const AMA = require('aws-sdk-mobile-analytics')
|
||||
const ConfigManager = require('browser/main/lib/ConfigManager')
|
||||
|
||||
const mobileAnalyticsClient = new AMA.Manager({
|
||||
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
appTitle: 'xxxxxxxxxx'
|
||||
})
|
||||
|
||||
function initAwsMobileAnalytics () {
|
||||
AWS.config.region = 'us-east-1'
|
||||
AWS.config.region = 'us-east-1'
|
||||
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
|
||||
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
|
||||
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
})
|
||||
const mobileAnalyticsClient = new AMA.Manager({
|
||||
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
appTitle: 'xxxxxxxxxx'
|
||||
})
|
||||
}
|
||||
|
||||
function initAwsMobileAnalytics () {
|
||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||
AWS.config.credentials.get((err) => {
|
||||
if (!err) {
|
||||
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
|
||||
@@ -21,11 +23,13 @@ function initAwsMobileAnalytics () {
|
||||
recordStaticCustomEvent()
|
||||
}
|
||||
|
||||
function recordDynamitCustomEvent (type) {
|
||||
function recordDynamicCustomEvent (type) {
|
||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||
mobileAnalyticsClient.recordEvent(type)
|
||||
}
|
||||
|
||||
function recordStaticCustomEvent () {
|
||||
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
|
||||
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
|
||||
uiColorTheme: ConfigManager.default.get().ui.theme
|
||||
})
|
||||
@@ -33,5 +37,5 @@ function recordStaticCustomEvent () {
|
||||
|
||||
module.exports = {
|
||||
initAwsMobileAnalytics,
|
||||
recordDynamitCustomEvent
|
||||
recordDynamicCustomEvent
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import _ from 'lodash'
|
||||
import RcParser from 'browser/lib/RcParser'
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
const win = global.process.platform === 'win32'
|
||||
const electron = require('electron')
|
||||
const { ipcRenderer } = electron
|
||||
const consts = require('browser/lib/consts')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
let isInitialized = false
|
||||
|
||||
@@ -14,6 +18,7 @@ export const DEFAULT_CONFIG = {
|
||||
navWidth: 200,
|
||||
sortBy: 'UPDATED_AT', // 'CREATED_AT', 'UPDATED_AT', 'APLHABETICAL'
|
||||
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
|
||||
amaEnabled: true,
|
||||
hotkey: {
|
||||
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
|
||||
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
|
||||
@@ -24,18 +29,18 @@ export const DEFAULT_CONFIG = {
|
||||
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
|
||||
},
|
||||
editor: {
|
||||
theme: 'default',
|
||||
theme: 'base16-light',
|
||||
keyMap: 'sublime',
|
||||
fontSize: '14',
|
||||
fontFamily: 'Monaco, Consolas',
|
||||
fontFamily: win ? 'Segoe UI' : 'Monaco, Consolas',
|
||||
indentType: 'space',
|
||||
indentSize: '2',
|
||||
switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR
|
||||
},
|
||||
preview: {
|
||||
fontSize: '14',
|
||||
fontFamily: 'Lato',
|
||||
codeBlockTheme: 'elegant',
|
||||
fontFamily: win ? 'Segoe UI' : 'Lato',
|
||||
codeBlockTheme: 'dracula',
|
||||
lineNumber: true
|
||||
}
|
||||
}
|
||||
@@ -55,17 +60,17 @@ function _save (config) {
|
||||
}
|
||||
|
||||
function get () {
|
||||
let config = window.localStorage.getItem('config')
|
||||
const rawStoredConfig = window.localStorage.getItem('config')
|
||||
const storedConfig = Object.assign({}, DEFAULT_CONFIG, JSON.parse(rawStoredConfig))
|
||||
let config = storedConfig
|
||||
|
||||
try {
|
||||
config = Object.assign({}, DEFAULT_CONFIG, JSON.parse(config))
|
||||
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, config.hotkey)
|
||||
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, config.ui)
|
||||
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, config.editor)
|
||||
config.preview = Object.assign({}, DEFAULT_CONFIG.preview, config.preview)
|
||||
const boostnotercConfig = RcParser.parse()
|
||||
config = assignConfigValues(storedConfig, boostnotercConfig)
|
||||
|
||||
if (!validate(config)) throw new Error('INVALID CONFIG')
|
||||
} catch (err) {
|
||||
console.warn('Boostnote resets the malformed configuration.')
|
||||
console.warn('Boostnote resets the invalid configuration.')
|
||||
config = DEFAULT_CONFIG
|
||||
_save(config)
|
||||
}
|
||||
@@ -124,6 +129,15 @@ function set (updates) {
|
||||
})
|
||||
}
|
||||
|
||||
function assignConfigValues (originalConfig, rcConfig) {
|
||||
let config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig)
|
||||
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey)
|
||||
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui)
|
||||
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor)
|
||||
config.preview = Object.assign({}, DEFAULT_CONFIG.preview, originalConfig.preview, rcConfig.preview)
|
||||
return config
|
||||
}
|
||||
|
||||
export default {
|
||||
get,
|
||||
set,
|
||||
|
||||
@@ -2,6 +2,7 @@ const fs = require('fs')
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
* @description To copy an image and return the path.
|
||||
@@ -12,17 +13,17 @@ const sander = require('sander')
|
||||
function copyImage (filePath, storageKey) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
const storage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (storage === undefined) throw new Error('Target storage doesn\'t exist.')
|
||||
const targetStorage = storage
|
||||
const targetStorage = findStorage(storageKey)
|
||||
|
||||
const inputImage = fs.createReadStream(filePath)
|
||||
const imageName = path.basename(filePath)
|
||||
const outputImage = fs.createWriteStream(path.join(targetStorage.path, 'images', imageName))
|
||||
const imageExt = path.extname(filePath)
|
||||
const imageName = Math.random().toString(36).slice(-16)
|
||||
const basename = `${imageName}${imageExt}`
|
||||
const imageDir = path.join(targetStorage.path, 'images')
|
||||
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
|
||||
const outputImage = fs.createWriteStream(path.join(imageDir, basename))
|
||||
inputImage.pipe(outputImage)
|
||||
resolve(`${encodeURI(targetStorage.path)}/images/${encodeURI(imageName)}`)
|
||||
resolve(basename)
|
||||
} catch (e) {
|
||||
return reject(e)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ const keygen = require('browser/lib/keygen')
|
||||
const path = require('path')
|
||||
const resolveStorageData = require('./resolveStorageData')
|
||||
const CSON = require('@rokt33r/season')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
* @param {String} storageKey
|
||||
@@ -29,11 +30,7 @@ function createFolder (storageKey, input) {
|
||||
if (!_.isString(input.name)) throw new Error('Name must be a string.')
|
||||
if (!_.isString(input.color)) throw new Error('Color must be a string.')
|
||||
|
||||
rawStorages = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(rawStorages, {key: storageKey})
|
||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
targetStorage = findStorage(storageKey)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ const _ = require('lodash')
|
||||
const keygen = require('browser/lib/keygen')
|
||||
const path = require('path')
|
||||
const CSON = require('@rokt33r/season')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
function validateInput (input) {
|
||||
if (!_.isArray(input.tags)) input.tags = []
|
||||
input.tags = input.tags.filter((tag) => _.isString(tag) && tag.trim().length > 0)
|
||||
if (!_.isString(input.title)) input.title = ''
|
||||
input.isStarred = !!input.isStarred
|
||||
input.isTrashed = !!input.isTrashed
|
||||
|
||||
switch (input.type) {
|
||||
case 'MARKDOWN_NOTE':
|
||||
@@ -37,11 +39,7 @@ function createNote (storageKey, input) {
|
||||
input = Object.assign({}, input)
|
||||
validateInput(input)
|
||||
|
||||
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
targetStorage = findStorage(storageKey)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const resolveStorageData = require('./resolveStorageData')
|
||||
const resolveStorageNotes = require('./resolveStorageNotes')
|
||||
const CSON = require('@rokt33r/season')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
* @param {String} storageKey
|
||||
@@ -21,11 +22,7 @@ function deleteFolder (storageKey, folderKey) {
|
||||
let rawStorages
|
||||
let targetStorage
|
||||
try {
|
||||
rawStorages = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(rawStorages, {key: storageKey})
|
||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
targetStorage = findStorage(storageKey)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@ const resolveStorageData = require('./resolveStorageData')
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
function deleteNote (storageKey, noteKey) {
|
||||
let targetStorage
|
||||
try {
|
||||
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
targetStorage = findStorage(storageKey)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ function init () {
|
||||
.then((notes) => {
|
||||
let unknownCount = 0
|
||||
notes.forEach((note) => {
|
||||
if (!storage.folders.some((folder) => note.folder === folder.key)) {
|
||||
if (note && !storage.folders.some((folder) => note.folder === folder.key)) {
|
||||
unknownCount++
|
||||
storage.folders.push({
|
||||
key: note.folder,
|
||||
|
||||
@@ -4,17 +4,13 @@ const path = require('path')
|
||||
const CSON = require('@rokt33r/season')
|
||||
const keygen = require('browser/lib/keygen')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
|
||||
let oldStorage, newStorage
|
||||
try {
|
||||
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Storage doesn\'t exist.')
|
||||
|
||||
oldStorage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (oldStorage == null) throw new Error('Storage doesn\'t exist.')
|
||||
|
||||
newStorage = _.find(cachedStorageList, {key: newStorageKey})
|
||||
oldStorage = findStorage(storageKey)
|
||||
newStorage = findStorage(newStorageKey)
|
||||
if (newStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const _ = require('lodash')
|
||||
const resolveStorageData = require('./resolveStorageData')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
* @param {String} name
|
||||
|
||||
@@ -28,7 +28,6 @@ function resolveStorageNotes (storage) {
|
||||
return data
|
||||
} catch (err) {
|
||||
console.error(notePath)
|
||||
throw err
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ const resolveStorageData = require('./resolveStorageData')
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const CSON = require('@rokt33r/season')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
function validateInput (input) {
|
||||
let validatedInput = {}
|
||||
@@ -21,6 +22,10 @@ function validateInput (input) {
|
||||
validatedInput.isStarred = !!input.isStarred
|
||||
}
|
||||
|
||||
if (input.isTrashed != null) {
|
||||
validatedInput.isTrashed = !!input.isTrashed
|
||||
}
|
||||
|
||||
validatedInput.type = input.type
|
||||
switch (input.type) {
|
||||
case 'MARKDOWN_NOTE':
|
||||
@@ -64,11 +69,7 @@ function updateNote (storageKey, noteKey, input) {
|
||||
if (input == null) throw new Error('No input found.')
|
||||
input = validateInput(input)
|
||||
|
||||
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(cachedStorageList, {key: storageKey})
|
||||
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
|
||||
targetStorage = findStorage(storageKey)
|
||||
} catch (e) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
@@ -101,6 +102,7 @@ function updateNote (storageKey, noteKey, input) {
|
||||
noteData.createdAt = new Date()
|
||||
noteData.updatedAt = new Date()
|
||||
noteData.isStarred = false
|
||||
noteData.isTrashed = false
|
||||
noteData.tags = []
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class CreateFolderModal extends React.Component {
|
||||
}
|
||||
|
||||
confirm () {
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_FOLDER')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
|
||||
if (this.state.name.trim().length > 0) {
|
||||
let { storage } = this.props
|
||||
let input = {
|
||||
|
||||
@@ -103,7 +103,7 @@ class InitModal extends React.Component {
|
||||
} else {
|
||||
return dataApi
|
||||
.createFolder(data.storage.key, {
|
||||
color: '#6AA5E9',
|
||||
color: '#1278BD',
|
||||
name: 'Default'
|
||||
})
|
||||
.then((_data) => {
|
||||
@@ -122,19 +122,6 @@ class InitModal extends React.Component {
|
||||
notes: data.notes
|
||||
})
|
||||
|
||||
let defaultMarkdownNote = dataApi
|
||||
.createNote(data.storage.key, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
folder: data.storage.folders[0].key,
|
||||
title: 'Welcome to Boostnote :)',
|
||||
content: '# Welcome to Boostnote :)\nThis is a markdown note.\n\nClick to edit this note.'
|
||||
})
|
||||
.then((note) => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
})
|
||||
let defaultSnippetNote = dataApi
|
||||
.createNote(data.storage.key, {
|
||||
type: 'SNIPPET_NOTE',
|
||||
@@ -145,12 +132,12 @@ class InitModal extends React.Component {
|
||||
{
|
||||
name: 'example.html',
|
||||
mode: 'html',
|
||||
content: '<html>\n<body>\n<h1 id=\'hello\'>Hello World</h1>\n</body>\n</html>'
|
||||
content: '<html>\n<body>\n<h1 id=\'hello\'>Enjoy Boostnote!</h1>\n</body>\n</html>'
|
||||
},
|
||||
{
|
||||
name: 'example.js',
|
||||
mode: 'javascript',
|
||||
content: 'var html = document.getElementById(\'hello\').innerHTML\n\nconsole.log(html)'
|
||||
content: 'var boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)'
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -160,6 +147,19 @@ class InitModal extends React.Component {
|
||||
note: note
|
||||
})
|
||||
})
|
||||
let defaultMarkdownNote = dataApi
|
||||
.createNote(data.storage.key, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
folder: data.storage.folders[0].key,
|
||||
title: 'Welcome to Boostnote!',
|
||||
content: '# Welcome to Boostnote! \n### _Click to edit this note._\n\n---\n\nBoostnote is an *open source* note-taking app. \nRepository is published on [GitHub](https://github.com/BoostIO/Boostnote), and tweeting everyday on [@Boostnoteapp](https://twitter.com/boostnoteapp)!\n\n## Features \n- [x] No Internet and Registration Required. \n- [ ] Quick search and copy the content of note. `macOS: Cmd + Alt + S / windows: Ctrl + Alt + S` \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
|
||||
})
|
||||
.then((note) => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
})
|
||||
|
||||
return Promise.resolve(defaultSnippetNote)
|
||||
.then(defaultMarkdownNote)
|
||||
|
||||
@@ -24,8 +24,8 @@ class NewNoteModal extends React.Component {
|
||||
}
|
||||
|
||||
handleMarkdownNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_MARKDOWN')
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_ALLNOTE')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
let { storage, folder, dispatch, location } = this.props
|
||||
dataApi
|
||||
.createNote(storage, {
|
||||
@@ -56,8 +56,8 @@ class NewNoteModal extends React.Component {
|
||||
}
|
||||
|
||||
handleSnippetNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_SNIPPET')
|
||||
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_ALLNOTE')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
let { storage, folder, dispatch, location } = this.props
|
||||
|
||||
dataApi
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoTab.styl'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import store from 'browser/main/store'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
|
||||
const electron = require('electron')
|
||||
const { shell, remote } = electron
|
||||
@@ -11,6 +14,7 @@ class InfoTab extends React.Component {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
config: this.props.config
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +23,29 @@ class InfoTab extends React.Component {
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
handleConfigChange (e) {
|
||||
const newConfig = { amaEnabled: this.refs.amaEnabled.checked }
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
let newConfig = {
|
||||
amaEnabled: this.state.config.amaEnabled
|
||||
}
|
||||
|
||||
if (!newConfig.amaEnabled) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
|
||||
}
|
||||
|
||||
ConfigManager.set(newConfig)
|
||||
|
||||
store.dispatch({
|
||||
type: 'SET_CONFIG',
|
||||
config: newConfig
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
@@ -68,6 +95,18 @@ class InfoTab extends React.Component {
|
||||
License: GPL v3
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<div styleName='policy'>Data collection policy</div>
|
||||
<p>We collect only the number of DAU for Boostnote and DO NOT collect any detail information</p>
|
||||
<p>such as your note content. You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</p>
|
||||
<p>These data are only used for Boostnote improvements.</p>
|
||||
<input onChange={(e) => this.handleConfigChange(e)}
|
||||
checked={this.state.config.amaEnabled}
|
||||
ref='amaEnabled'
|
||||
type='checkbox'
|
||||
/>
|
||||
Enable to send analytics to our servers<br />
|
||||
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>Save</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,14 @@
|
||||
a
|
||||
color #4E8EC6
|
||||
text-decoration none
|
||||
|
||||
|
||||
.policy
|
||||
font-size 20px
|
||||
margin-bottom 10px
|
||||
|
||||
.policy-submit
|
||||
margin-top 10px
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
color alpha($tab--dark-text-color, 80%)
|
||||
color alpha($tab--dark-text-color, 80%)
|
||||
|
||||
@@ -298,8 +298,8 @@ class StorageItem extends React.Component {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Unlink Storage',
|
||||
detail: 'This work just detatches a storage from Boostnote. (Any data won\'t be deleted.)',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
detail: 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.',
|
||||
buttons: ['Unlink', 'Cancel']
|
||||
})
|
||||
|
||||
if (index === 0) {
|
||||
|
||||
@@ -192,7 +192,7 @@ class UiTab extends React.Component {
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
Switching Preview
|
||||
Switch to Preview
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.editor.switchPreview}
|
||||
@@ -200,7 +200,7 @@ class UiTab extends React.Component {
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
>
|
||||
<option value='BLUR'>When Editor Blurred</option>
|
||||
<option value='RIGHTCLICK'>When Right Clicking</option>
|
||||
<option value='RIGHTCLICK'>On Right Click</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,7 +218,7 @@ class UiTab extends React.Component {
|
||||
<option value='vim'>vim</option>
|
||||
<option value='emacs'>emacs</option>
|
||||
</select>
|
||||
<span styleName='note-for-keymap'>Please reload boostnote after you change the keymap</span>
|
||||
<span styleName='note-for-keymap'>Please restart boostnote after you change the keymap</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -271,7 +271,7 @@ class UiTab extends React.Component {
|
||||
ref='previewLineNumber'
|
||||
type='checkbox'
|
||||
/>
|
||||
Code block line numbering
|
||||
Show line numbers for preview code blocks
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -44,7 +44,12 @@ class Preferences extends React.Component {
|
||||
|
||||
switch (this.state.currentTab) {
|
||||
case 'INFO':
|
||||
return <InfoTab />
|
||||
return (
|
||||
<InfoTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
/>
|
||||
)
|
||||
case 'HOTKEY':
|
||||
return (
|
||||
<HotkeyTab
|
||||
@@ -116,7 +121,7 @@ class Preferences extends React.Component {
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='top-bar'>
|
||||
<p>Your menu for Boostnote</p>
|
||||
<p>Your preferences for Boostnote</p>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleEscButtonClick(e)} />
|
||||
<div styleName='nav'>
|
||||
|
||||
@@ -11,7 +11,8 @@ function defaultDataMap () {
|
||||
starredSet: new Set(),
|
||||
storageNoteMap: new Map(),
|
||||
folderNoteMap: new Map(),
|
||||
tagNoteMap: new Map()
|
||||
tagNoteMap: new Map(),
|
||||
trashedSet: new Set()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +25,8 @@ function data (state = defaultDataMap(), action) {
|
||||
state.storageMap.set(storage.key, storage)
|
||||
})
|
||||
|
||||
action.notes.forEach((note) => {
|
||||
action.notes.some((note) => {
|
||||
if (note === undefined) return true
|
||||
let uniqueKey = note.storage + '-' + note.key
|
||||
let folderKey = note.storage + '-' + note.folder
|
||||
state.noteMap.set(uniqueKey, note)
|
||||
@@ -33,6 +35,10 @@ function data (state = defaultDataMap(), action) {
|
||||
state.starredSet.add(uniqueKey)
|
||||
}
|
||||
|
||||
if (note.isTrashed) {
|
||||
state.trashedSet.add(uniqueKey)
|
||||
}
|
||||
|
||||
let storageNoteList = state.storageNoteMap.get(note.storage)
|
||||
if (storageNoteList == null) {
|
||||
storageNoteList = new Set(storageNoteList)
|
||||
@@ -77,6 +83,15 @@ function data (state = defaultDataMap(), action) {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldNote == null || oldNote.isTrashed !== note.isTrashed) {
|
||||
state.trashedSet = new Set(state.trashedSet)
|
||||
if (note.isTrashed) {
|
||||
state.trashedSet.add(uniqueKey)
|
||||
} else {
|
||||
state.trashedSet.delete(uniqueKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Update storageNoteMap if oldNote doesn't exist
|
||||
if (oldNote == null) {
|
||||
state.storageNoteMap = new Map(state.storageNoteMap)
|
||||
@@ -162,6 +177,11 @@ function data (state = defaultDataMap(), action) {
|
||||
state.starredSet.delete(originKey)
|
||||
}
|
||||
|
||||
if (originNote.isTrashed) {
|
||||
state.trashedSet = new Set(state.trashedSet)
|
||||
state.trashedSet.delete(originKey)
|
||||
}
|
||||
|
||||
// From storageNoteMap
|
||||
state.storageNoteMap = new Map(state.storageNoteMap)
|
||||
let noteSet = state.storageNoteMap.get(originNote.storage)
|
||||
@@ -198,6 +218,15 @@ function data (state = defaultDataMap(), action) {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldNote == null || oldNote.isTrashed !== note.isTrashed) {
|
||||
state.trashedSet = new Set(state.trashedSet)
|
||||
if (note.isTrashed) {
|
||||
state.trashedSet.add(uniqueKey)
|
||||
} else {
|
||||
state.trashedSet.delete(uniqueKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Update storageNoteMap if oldNote doesn't exist
|
||||
if (oldNote == null) {
|
||||
state.storageNoteMap = new Map(state.storageNoteMap)
|
||||
@@ -282,6 +311,11 @@ function data (state = defaultDataMap(), action) {
|
||||
state.starredSet.delete(uniqueKey)
|
||||
}
|
||||
|
||||
if (targetNote.isTrashed) {
|
||||
state.trashedSet = new Set(state.trashedSet)
|
||||
state.trashedSet.delete(uniqueKey)
|
||||
}
|
||||
|
||||
// From folderNoteMap
|
||||
let folderKey = targetNote.storage + '-' + targetNote.folder
|
||||
state.folderNoteMap = new Map(state.folderNoteMap)
|
||||
@@ -347,6 +381,11 @@ function data (state = defaultDataMap(), action) {
|
||||
state.starredSet.delete(noteKey)
|
||||
}
|
||||
|
||||
if (note.isTrashed) {
|
||||
state.trashedSet = new Set(state.trashedSet)
|
||||
state.trashedSet.delete(noteKey)
|
||||
}
|
||||
|
||||
// Delete key from tag map
|
||||
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||
note.tags.forEach((tag) => {
|
||||
|
||||
@@ -160,8 +160,7 @@ topBarButtonLight()
|
||||
height 34px
|
||||
border-radius 17px
|
||||
font-size 14px
|
||||
margin 13px 7px
|
||||
padding-top 7px
|
||||
margin 15px 7px
|
||||
border none
|
||||
color $ui-button-color
|
||||
fill $ui-button-color
|
||||
@@ -169,7 +168,7 @@ topBarButtonLight()
|
||||
&:active
|
||||
border-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
background-color $ui-button--hover-backgroundColor
|
||||
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
||||
.control-lockButton-tooltip
|
||||
opacity 1
|
||||
|
||||
@@ -182,7 +181,7 @@ $ui-dark-noteDetail-backgroundColor = #2D3033
|
||||
$ui-dark-tag-backgroundColor = #3A404C
|
||||
$dark-background-color = lighten($ui-dark-backgroundColor, 10%)
|
||||
$ui-dark-text-color = #DDDDDD
|
||||
$ui-dark-button--active-color = white
|
||||
$ui-dark-button--active-color = #f4f4f4
|
||||
$ui-dark-button--active-backgroundColor = #3A404C
|
||||
$ui-dark-button--hover-backgroundColor = lighten($ui-dark-backgroundColor, 10%)
|
||||
$ui-dark-button--focus-borderColor = lighten(#369DCD, 25%)
|
||||
@@ -232,10 +231,12 @@ topBarButtonDark()
|
||||
color $ui-dark-topbar-button-color
|
||||
&:hover
|
||||
background-color $dark-default-button-background--hover
|
||||
color $ui-dark-tooltip-text-color
|
||||
&:active
|
||||
border-color $ui-dark-button--focus-borderColor
|
||||
&:active:hover
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
color $ui-dark-tooltip-text-color
|
||||
&:focus
|
||||
border-color $ui-button--focus-borderColor
|
||||
|
||||
|
||||
@@ -1,33 +1,51 @@
|
||||
# Contributing to Boostnote
|
||||
# Contributing to Boostnote (English)
|
||||
|
||||
## When you open an issue of a bug report
|
||||
### When you open an issue of a bug report
|
||||
There are no issue template. But there is a request.
|
||||
|
||||
**Please paste screenshots of Boostnote with developer tool open**
|
||||
|
||||
Thank you for your help in advance.
|
||||
|
||||
## About copyright of Pull Request
|
||||
### About copyright of Pull Request
|
||||
|
||||
If you make a pull request, It means you agree to transfer the copyright of the code changes to MAISIN&CO.
|
||||
If you make a pull request, It means you agree to transfer the copyright of the code changes to Maisin&Co.
|
||||
|
||||
It doesn't mean Boostnote will become a paid app. If we want to earn some money, We will try other way, which is some kind of cloud storage, Mobile app integration or some SPECIAL features.
|
||||
Because GPL v3 is too strict to be compatible with any other License, We thought this is needed to replace the license with much freer one(like BSD, MIT) somewhen.
|
||||
|
||||
---
|
||||
|
||||
# Contributing to Boostnote (Russian)
|
||||
|
||||
### Когда у вас появляется сообщение об ошибке
|
||||
У нас нет шаблона, по которому вы должны описать ошибку. Просто расскажите, как вы получили ее
|
||||
|
||||
**Вставьте скриншот Boostnote с открытым инструментом разработчика (dev tools)**
|
||||
|
||||
Благодарим Вас за помощь!
|
||||
|
||||
### Об авторских правах Pull Request
|
||||
|
||||
Если вы делаете pull request, значит вы согласны передать авторские права на изменения кода в Maisin&Co.
|
||||
|
||||
Это не означает, что Boostnote станет платным приложением. Если мы захотим заработать немного денег, мы найдем другой способ. Например, использование облачного хранилища, интеграцией мобильных приложений или другими специальными функциями.
|
||||
Так как лицензия GPL v3 слишком строгая, чтобы быть совместимой с любой другой лицензией, мы думаем, что нужно заменить лицензию на более свободную (например, BSD, MIT).
|
||||
|
||||
---
|
||||
|
||||
# Contributing to Boostnote (Korean)
|
||||
|
||||
## 버그 리포트를 보고할 때
|
||||
### 버그 리포트를 보고할 때
|
||||
이슈의 양식은 없습니다. 하지만 부탁이 있습니다.
|
||||
|
||||
**개발자 도구를 연 상태의 Boostnote 스크린샷을 첨부해주세요**
|
||||
|
||||
도움을 주셔서 감사합니다.
|
||||
|
||||
## Pull Request의 저작권에 관하여
|
||||
### Pull Request의 저작권에 관하여
|
||||
|
||||
당신이 pull request를 요청하면, 코드 변경에 대한 저작권을 MAISIN&CO에 양도한다는 것에 동의한다는 의미입니다.
|
||||
당신이 pull request를 요청하면, 코드 변경에 대한 저작권을 Maisin&Co에 양도한다는 것에 동의한다는 의미입니다.
|
||||
|
||||
이것은 Boostnote가 유료화가 되는 것을 의미하는 건 아닙니다. 만약 우리가 자금이 필요하다면, 우리는 클라우드 연동, 모바일 앱 통합 혹은 특수한 기능 같은 것을 사용해 수입 창출을 시도할 것입니다.
|
||||
GPL v3 라이센스는 다른 라이센스와 혼합해 사용하기엔 너무 엄격하므로, 우리는 BSD, MIT 라이센스와 같은 더 자유로운 라이센스로 교체하는 것을 생각하고 있습니다.
|
||||
@@ -36,16 +54,16 @@ GPL v3 라이센스는 다른 라이센스와 혼합해 사용하기엔 너무
|
||||
|
||||
# Contributing to Boostnote (Japanese)
|
||||
|
||||
## バグレポートに関してのissueを立てる時
|
||||
### バグレポートに関してのissueを立てる時
|
||||
イシューテンプレートはありませんが、1つお願いがあります。
|
||||
|
||||
**開発者ツールを開いた状態のBoostnoteのスクリーンショットを貼ってください**
|
||||
|
||||
よろしくお願いします。
|
||||
|
||||
## Pull requestの著作権について
|
||||
### Pull requestの著作権について
|
||||
|
||||
Pull requestをすることはその変化分のコードの著作権をMAISIN&CO.に譲渡することに同意することになります。
|
||||
Pull requestをすることはその変化分のコードの著作権をMaisin&Co.に譲渡することに同意することになります。
|
||||
|
||||
アプリケーションのLicenseをいつでも変える選択肢を残したいと思うからです。
|
||||
これはいずれかBoostnoteが有料の商用アプリになる可能性がある話ではありません。
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Testing for Boostnote
|
||||
## e2eテスト
|
||||
Boostnoteには[ava](https://github.com/avajs/ava)と[spectron](https://github.com/electron/spectron)で書かれたe2eテストがあります。
|
||||
|
||||
### 実行方法
|
||||
以下のe2eテストのコマンドがあります。
|
||||
|
||||
```
|
||||
$ yarn run test:e2e
|
||||
```
|
||||
|
||||
もう一つのテストコマンドと分けた理由は、travisCIの都合です。
|
||||
|
||||
### travisCIでは
|
||||
travisCIではmasterブランチで飲みe2eテストを実行するようにしています。もし興味がある方は `.travis.yml`をご覧ください。
|
||||
57
docs/ru/build.md
Normal file
57
docs/ru/build.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Сборка
|
||||
|
||||
## Используемые инструменты
|
||||
* npm: 4.x
|
||||
* node: 7.x
|
||||
|
||||
Вы должны использовать `npm v4.x`, так как `$ grand pre-build` не работает в `v5.x`.
|
||||
|
||||
## Разработка
|
||||
|
||||
Мы используем Webpack HMR при разработке Boostnote.
|
||||
Выполнение следующих команд в корне проекта запустит Boostnote с настройками по умолчанию.
|
||||
|
||||
Установите необходимые пакеты с помощью yarn.
|
||||
|
||||
```
|
||||
$ yarn
|
||||
```
|
||||
|
||||
Соберите и запустите.
|
||||
|
||||
```
|
||||
$ yarn run dev-start
|
||||
```
|
||||
|
||||
Эта команда выполняет `yarn run webpack` и `yarn run hot` параллельно. Результат будет такой же, если вы выполните эти две команды раздельно.
|
||||
|
||||
`Webpack` будет следить за изменениями в коде и будет применять их автоматически.
|
||||
|
||||
Если возникает следующая ошибка: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, пожалуйста, перезапустите Boostnote.
|
||||
|
||||

|
||||
|
||||
> ### Примечание
|
||||
> В некоторых случаях вам необходимо обновить приложение вручную.
|
||||
> 1. При редактировании метода конструктора компонента
|
||||
> 2. При добавлении нового класса CSS (аналогично 1: Класс CSS перезаписывается каждым компонентом. Этот процесс выполняется в методе Constructor.)
|
||||
|
||||
## Деплой
|
||||
|
||||
Мы используем Grunt для автоматического деплоя.
|
||||
Вы можете создать задачу, используя `grunt`. Однако мы не рекомендуем этого делать, так как задача по умолчанию включает в себя код и аутентификацию.
|
||||
|
||||
Мы подготовили отдельный скрипт, который просто создает исполняемый файл:
|
||||
|
||||
```
|
||||
grunt pre-build
|
||||
```
|
||||
|
||||
Вы найдете исполняемый файл в папке `dist`. Обратите внимание: автоматическое обновление не будет работать, потому что приложение не подписано.
|
||||
|
||||
Если вам необходимо, вы можете использовать код или аутентификацию с помощью этого исполняемого файла.
|
||||
|
||||
---
|
||||
|
||||
Special thanks:
|
||||
Translated by @AlexanderBelkevich
|
||||
25
docs/ru/debug.md
Normal file
25
docs/ru/debug.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Как отладить Boostnote (приложение Electron)
|
||||
Boostnote - это программа, сделанная с помощью Electron, поэтому она базируется на Chromium. Разработчики могут использовать `Developer Tools` в Google Chrome для отладки.
|
||||
|
||||
Вы можете переключиться в `Developer Tools` следующим образом:
|
||||

|
||||
|
||||
`Developer Tools` будет выглядеть следующим образом:
|
||||

|
||||
|
||||
Возможные ошибки отображаются во вкладке `console`.
|
||||
|
||||
## Отладка
|
||||
Например, вы можете использовать `debugger`, чтобы установить точку остановы следующим образом:
|
||||
|
||||

|
||||
|
||||
Это всего лишь пример. Вы можете использовать любой свой способ отладки. Тот, который вам будет удобен.
|
||||
|
||||
## Рекомендации
|
||||
* [Официальная документация Google Chrome об отладке](https://developer.chrome.com/devtools)
|
||||
|
||||
---
|
||||
|
||||
Special thanks:
|
||||
Translated by @AlexanderBelkevich
|
||||
@@ -1,15 +0,0 @@
|
||||
# Testing for Boostnote
|
||||
## e2e testing
|
||||
There is e2e tests for Boostnote written in [ava](https://github.com/avajs/ava) and [spectron](https://github.com/electron/spectron).
|
||||
|
||||
### How to run
|
||||
There is a command for e2e testing bellow:
|
||||
|
||||
```
|
||||
$ yarn run test:e2e
|
||||
```
|
||||
|
||||
The reason why I seperate aother test command is because of convenience of travisCI.
|
||||
|
||||
### On travisCI
|
||||
I set e2e tests running on travisCI only master branch. If you're interested in it, please take a look at .travis.yml
|
||||
@@ -92,6 +92,31 @@ const file = {
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Import from',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Plain Text, MarkDown (.txt, .md)',
|
||||
click () {
|
||||
mainWindow.webContents.send('import:file')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Print',
|
||||
accelerator: 'CommandOrControl+P',
|
||||
click () {
|
||||
mainWindow.webContents.send('list:isMarkdownNote')
|
||||
mainWindow.webContents.send('print')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Delete Note',
|
||||
accelerator: macOS ? 'Control+Backspace' : 'Control+Delete',
|
||||
@@ -178,18 +203,11 @@ const view = {
|
||||
},
|
||||
{
|
||||
label: 'Previous Note',
|
||||
accelerator: 'Control+U',
|
||||
accelerator: 'Control+K',
|
||||
click () {
|
||||
mainWindow.webContents.send('list:prior')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Jump to Top',
|
||||
accelerator: 'Control+G',
|
||||
click () {
|
||||
mainWindow.webContents.send('list:jumpToTop')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
||||
<link rel="shortcut icon" href="../resources/favicon.ico">
|
||||
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
|
||||
<link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css">
|
||||
<title>Boostnote</title>
|
||||
|
||||
<style>
|
||||
@@ -19,6 +20,15 @@
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../resources/fonts/Lato-Regular.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
#loadingCover{
|
||||
background-color: #f4f4f4;
|
||||
position: absolute;
|
||||
@@ -64,6 +74,13 @@
|
||||
|
||||
<script src="../node_modules/codemirror/addon/edit/continuelist.js"></script>
|
||||
|
||||
<script src="../node_modules/codemirror/addon/search/search.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/scroll/annotatescrollbar.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/search/matchesonscrollbar.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/search/jump-to-line.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/dialog/dialog.js"></script>
|
||||
|
||||
<script src="../node_modules/raphael/raphael.min.js"></script>
|
||||
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>
|
||||
<script>
|
||||
@@ -87,5 +104,10 @@
|
||||
scriptEl.setAttribute('src', scriptUrl)
|
||||
document.body.appendChild(scriptEl)
|
||||
</script>
|
||||
<style>
|
||||
.ace_search {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "boost",
|
||||
"version": "0.8.10",
|
||||
"version": "0.8.13",
|
||||
"main": "index.js",
|
||||
"description": "Boostnote",
|
||||
"license": "GPL-3.0",
|
||||
@@ -10,7 +10,6 @@
|
||||
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
|
||||
"compile": "grunt compile",
|
||||
"test": "PWD=$(pwd) NODE_ENV=test ava",
|
||||
"test:e2e": "NODE_ENV=test ava tests/e2e/*",
|
||||
"fix": "npm run lint --fix",
|
||||
"lint": "eslint .",
|
||||
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
|
||||
@@ -77,7 +76,6 @@
|
||||
"react-redux": "^4.4.5",
|
||||
"redux": "^3.5.2",
|
||||
"sander": "^0.5.1",
|
||||
"spectron": "^3.6.2",
|
||||
"superagent": "^1.2.0",
|
||||
"superagent-promise": "^1.0.3"
|
||||
},
|
||||
|
||||
40
readme-ja.md
40
readme-ja.md
@@ -1,40 +0,0 @@
|
||||
<h1 align="center">
|
||||
<a href="https://github.com/BoostIO/Boostnote"><img src="./resources/app.png" alt="Boostnote" width="180"></a>
|
||||
<br>
|
||||
Boostnote
|
||||
<br>
|
||||
<br>
|
||||
</h1>
|
||||
<h4 align="center">クールなプログラマーの為の、オープンソースのノートアプリ </h4>
|
||||
<h5 align="center">macOS, Windows, Linuxで利用できます。</h5>
|
||||
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
|
||||
|
||||

|
||||
|
||||
[](https://travis-ci.org/BoostIO/Boostnote)
|
||||
|
||||
## Author & Maintainer
|
||||
- [Rokt33r](https://github.com/rokt33r)
|
||||
- [sota1235](https://github.com/sota1235)
|
||||
- [Kohei TAKATA](https://github.com/kohei-takata)
|
||||
- [asmsuechan](https://github.com/asmsuechan)
|
||||
- [Kazu Yokomizo](https://github.com/kazup01)
|
||||
|
||||
## Contributors
|
||||
[Great contributors](https://github.com/BoostIO/Boostnote/graphs/contributors) :tada:
|
||||
|
||||
## slack group
|
||||
私たちにはslack groupもあります!世界中のプログラマー達と、Boostnoteについてディスカッションをしましょう! <br>
|
||||
[こちらから](https://join.slack.com/boostnote-group/shared_invite/MTkwOTg2NjAzNTUyLTE0OTYzODQ3ODgtMGI4NDZlY2E5OQ)
|
||||
|
||||
## More Information
|
||||
* Website: http://boostnote.io/
|
||||
* Roadmap(upcoming features and bug fixes): https://github.com/BoostIO/Boostnote/wiki/List-of-the-requested-features
|
||||
* Boostnote Shop(Products are shipped to all over the world :+1:): https://boostnote.paintory.com/
|
||||
* Donation: [Bountysource](https://salt.bountysource.com/teams/boostnote)
|
||||
* Development: https://github.com/BoostIO/Boostnote/blob/master/docs/build.md
|
||||
* Copyright (C) 2017 Maisin&Co.
|
||||
|
||||
## License
|
||||
|
||||
[GPL v3](./LICENSE).
|
||||
@@ -6,7 +6,7 @@
|
||||
<br>
|
||||
</h1>
|
||||
<h4 align="center">Note-taking app for programmers. </h4>
|
||||
<h5 align="center">macOS, Windows and Linux</h5>
|
||||
<h5 align="center">macOS, Windows and Linux. Android and iOS apps will be released soon!</h5>
|
||||
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
|
||||
|
||||

|
||||
@@ -25,13 +25,12 @@
|
||||
|
||||
## Slack Group
|
||||
Let's talk about Boostnote's great features, new feature requests and things like Japanese gourmet. 🍣 <br>
|
||||
[Join us](https://join.slack.com/boostnote-group/shared_invite/MTkwOTg2NjAzNTUyLTE0OTYzODQ3ODgtMGI4NDZlY2E5OQ)
|
||||
[Join us](https://join.slack.com/t/boostnote-group/shared_invite/MjE3NDcwODQ3NTkwLTE1MDA4NjQ3ODktM2IxOTk4ZTNjYQ)
|
||||
|
||||
## More Information
|
||||
* [Website](https://boostnote.io)
|
||||
* [Boostnote Shop](https://boostnote.paintory.com/) : Products are shipped to all over the world 🌏
|
||||
* [Donate via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
|
||||
* [GitHub Issues](https://github.com/BoostIO/Boostnote/issues) : We'd love to hear your feedback 🙌
|
||||
* [Boostnote Team](https://boostnote.io/team/) : Boostnote for the creative hacker teams. Share your markdown notes and snippets instantly with your team. **We will release it at August!** 🏃💨
|
||||
* [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
|
||||
* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md) : Development configurations for Boostnote 🚀
|
||||
* Copyright (C) 2017 Maisin&Co.
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
if [[ ${TRAVIS_OS_NAME} = "linux" ]]; then
|
||||
export DISPLAY=:99.0
|
||||
sh -e /etc/init.d/xvfb start;
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
npm install grunt-cli -g
|
||||
grunt pre-build
|
||||
npm run test:e2e
|
||||
@@ -2,11 +2,11 @@
|
||||
* @fileoverview Unit test for browser/lib/date-formatter.js
|
||||
*/
|
||||
const test = require('ava')
|
||||
const { getLastUpdated } = require('browser/lib/date-formatter')
|
||||
const { formatDate } = require('browser/lib/date-formatter')
|
||||
|
||||
test(t => {
|
||||
t.throws(
|
||||
() => getLastUpdated('invalid argument'),
|
||||
() => formatDate('invalid argument'),
|
||||
'Invalid argument.'
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import test from 'ava'
|
||||
import {Application} from 'spectron'
|
||||
import path from 'path'
|
||||
|
||||
test.beforeEach(async t => {
|
||||
const boostnotePath = ((platform) => {
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
return path.join('..', '..', 'dist', 'Boostnote-darwin-x64', 'Boostnote.app', 'Contents', 'MacOS', 'Boostnote')
|
||||
case 'linux':
|
||||
return path.join('..', '..', 'dist', 'Boostnote-linux-x64', 'Boostnote')
|
||||
}
|
||||
})(process.platform)
|
||||
t.context.app = new Application({
|
||||
path: boostnotePath
|
||||
})
|
||||
|
||||
await t.context.app.start()
|
||||
})
|
||||
|
||||
test.afterEach.always(async t => {
|
||||
await t.context.app.stop()
|
||||
})
|
||||
|
||||
test(async t => {
|
||||
const app = t.context.app
|
||||
await app.client.waitUntilWindowLoaded()
|
||||
|
||||
const win = app.browserWindow
|
||||
t.is(await app.client.getWindowCount(), 1)
|
||||
t.false(await win.isMinimized())
|
||||
t.false(await win.isDevToolsOpened())
|
||||
t.true(await win.isVisible())
|
||||
t.true(await win.isFocused())
|
||||
|
||||
const {width, height} = await win.getBounds()
|
||||
t.true(width > 0)
|
||||
t.true(height > 0)
|
||||
})
|
||||
33
tests/lib/boostnoterc/.boostnoterc.all
Normal file
33
tests/lib/boostnoterc/.boostnoterc.all
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"amaEnabled": true,
|
||||
"editor": {
|
||||
"fontFamily": "Monaco, Consolas",
|
||||
"fontSize": "14",
|
||||
"indentSize": "2",
|
||||
"indentType": "space",
|
||||
"keyMap": "vim",
|
||||
"switchPreview": "BLUR",
|
||||
"theme": "monokai"
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleFinder": "Cmd + Alt + S",
|
||||
"toggleMain": "Cmd + Alt + L"
|
||||
},
|
||||
"isSideNavFolded": false,
|
||||
"listStyle": "DEFAULT",
|
||||
"listWidth": 174,
|
||||
"navWidth": 200,
|
||||
"preview": {
|
||||
"codeBlockTheme": "dracula",
|
||||
"fontFamily": "Lato",
|
||||
"fontSize": "14",
|
||||
"lineNumber": true
|
||||
},
|
||||
"sortBy": "UPDATED_AT",
|
||||
"ui": {
|
||||
"defaultNote": "ALWAYS_ASK",
|
||||
"disableDirectWrite": false,
|
||||
"theme": "default"
|
||||
},
|
||||
"zoom": 1
|
||||
}
|
||||
12
tests/lib/boostnoterc/.boostnoterc.invalid
Normal file
12
tests/lib/boostnoterc/.boostnoterc.invalid
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"editor": {
|
||||
"keyMap": "vim",
|
||||
"switchPreview": "BLUR",
|
||||
"theme": "monokai",
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleMain": "Control + L"
|
||||
},
|
||||
"listWidth": 135,
|
||||
"navWidth": 135
|
||||
}
|
||||
12
tests/lib/boostnoterc/.boostnoterc.valid
Normal file
12
tests/lib/boostnoterc/.boostnoterc.valid
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"editor": {
|
||||
"keyMap": "vim",
|
||||
"switchPreview": "BLUR",
|
||||
"theme": "monokai"
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleMain": "Control + L"
|
||||
},
|
||||
"listWidth": 135,
|
||||
"navWidth": 135
|
||||
}
|
||||
32
tests/lib/find-storage-test.js
Normal file
32
tests/lib/find-storage-test.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const test = require('ava')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
global.document = require('jsdom').jsdom('<body></body>')
|
||||
global.window = document.defaultView
|
||||
global.navigator = window.navigator
|
||||
|
||||
const Storage = require('dom-storage')
|
||||
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
|
||||
const path = require('path')
|
||||
const TestDummy = require('../fixtures/TestDummy')
|
||||
const sander = require('sander')
|
||||
const os = require('os')
|
||||
const storagePath = path.join(os.tmpdir(), 'test/find-storage')
|
||||
|
||||
test.beforeEach((t) => {
|
||||
t.context.storage = TestDummy.dummyStorage(storagePath)
|
||||
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
|
||||
})
|
||||
|
||||
// Unit test
|
||||
test('findStorage() should return a correct storage path(string)', t => {
|
||||
const storageKey = t.context.storage.cache.key
|
||||
|
||||
t.is(findStorage(storageKey).key, storageKey)
|
||||
t.is(findStorage(storageKey).path, storagePath)
|
||||
})
|
||||
|
||||
test.after(function after () {
|
||||
localStorage.clear()
|
||||
sander.rimrafSync(storagePath)
|
||||
})
|
||||
23
tests/lib/get-todo-status-test.js
Normal file
23
tests/lib/get-todo-status-test.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const test = require('ava')
|
||||
const { getTodoStatus } = require('browser/lib/getTodoStatus')
|
||||
|
||||
// Unit test
|
||||
test('getTodoStatus should return a correct hash object', t => {
|
||||
// [input, expected]
|
||||
const testCases = [
|
||||
['', { total: 0, completed: 0 }],
|
||||
['* [ ] a\n', { total: 1, completed: 0 }],
|
||||
['* [ ] a\n* [x] a\n', { total: 2, completed: 1 }],
|
||||
['- [ ] a\n', { total: 1, completed: 0 }],
|
||||
['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
|
||||
['+ [ ] a\n', { total: 1, completed: 0 }],
|
||||
['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }]
|
||||
]
|
||||
|
||||
testCases.forEach(testCase => {
|
||||
const [input, expected] = testCase
|
||||
t.is(getTodoStatus(input).total, expected.total, `Test for getTodoStatus() input: ${input} expected: ${expected.total}`)
|
||||
t.is(getTodoStatus(input).completed, expected.completed, `Test for getTodoStatus() input: ${input} expected: ${expected.completed}`)
|
||||
})
|
||||
})
|
||||
|
||||
33
tests/lib/rc-parser-test.js
Normal file
33
tests/lib/rc-parser-test.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const test = require('ava')
|
||||
const path = require('path')
|
||||
const { parse } = require('browser/lib/RcParser')
|
||||
|
||||
// Unit test
|
||||
test('RcParser should return a json object', t => {
|
||||
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
|
||||
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleFinder': 'Cmd + Alt + S', 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
|
||||
|
||||
// [input, expected]
|
||||
const validTestCases = [
|
||||
['.boostnoterc.valid', validJson],
|
||||
['.boostnoterc.all', allJson]
|
||||
]
|
||||
|
||||
const invalidTestCases = [
|
||||
['.boostnoterc.invalid', {}]
|
||||
]
|
||||
|
||||
validTestCases.forEach(validTestCase => {
|
||||
const [input, expected] = validTestCase
|
||||
t.is(parse(filePath(input)).editor.keyMap, expected.editor.keyMap, `Test for getTodoStatus() input: ${input} expected: ${expected.keyMap}`)
|
||||
})
|
||||
|
||||
invalidTestCases.forEach(invalidTestCase => {
|
||||
const [input, expected] = invalidTestCase
|
||||
t.is(parse(filePath(input)).editor, expected.editor, `Test for getTodoStatus() input: ${input} expected: ${expected.editor}`)
|
||||
})
|
||||
})
|
||||
|
||||
function filePath (filename) {
|
||||
return path.join('boostnoterc', filename)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import _ from 'lodash'
|
||||
|
||||
const pickContents = (notes) => notes.map((note) => { return note.content })
|
||||
|
||||
let noteList = { noteMap: [] }
|
||||
let notes = []
|
||||
let note1, note2
|
||||
|
||||
test.before(t => {
|
||||
@@ -14,7 +14,7 @@ test.before(t => {
|
||||
note1 = dummyNote(data1)
|
||||
note2 = dummyNote(data2)
|
||||
|
||||
noteList.noteMap = [note1, note2]
|
||||
notes = [note1, note2]
|
||||
})
|
||||
|
||||
test('it can find notes by tags or words', t => {
|
||||
@@ -30,7 +30,7 @@ test('it can find notes by tags or words', t => {
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
const [input, expectedContents] = testCase
|
||||
const results = searchFromNotes(noteList, input)
|
||||
const results = searchFromNotes(notes, input)
|
||||
t.true(_.isEqual(pickContents(results).sort(), expectedContents.sort()))
|
||||
})
|
||||
})
|
||||
|
||||
408
yarn.lock
408
yarn.lock
@@ -1,5 +1,7 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@rokt33r/markdown-it-math@^4.0.1":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@rokt33r/markdown-it-math/-/markdown-it-math-4.0.2.tgz#87c7172f459833b05e406cfc846e0c0b7ebc24ef"
|
||||
@@ -123,31 +125,6 @@ aproba@^1.0.3:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
|
||||
|
||||
archiver-utils@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174"
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
graceful-fs "^4.1.0"
|
||||
lazystream "^1.0.0"
|
||||
lodash "^4.8.0"
|
||||
normalize-path "^2.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
archiver@~1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/archiver/-/archiver-1.3.0.tgz#4f2194d6d8f99df3f531e6881f14f15d55faaf22"
|
||||
dependencies:
|
||||
archiver-utils "^1.3.0"
|
||||
async "^2.0.0"
|
||||
buffer-crc32 "^0.2.1"
|
||||
glob "^7.0.0"
|
||||
lodash "^4.8.0"
|
||||
readable-stream "^2.0.0"
|
||||
tar-stream "^1.5.0"
|
||||
walkdir "^0.0.11"
|
||||
zip-stream "^1.1.0"
|
||||
|
||||
are-we-there-yet@~1.1.2:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
|
||||
@@ -294,12 +271,6 @@ async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.1, async@^1.5.2:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
|
||||
async@^2.0.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
|
||||
async@~0.1.22:
|
||||
version "0.1.22"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-0.1.22.tgz#0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061"
|
||||
@@ -312,10 +283,6 @@ asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
||||
atob@~1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773"
|
||||
|
||||
autoprefixer@^6.3.1:
|
||||
version "6.7.7"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
|
||||
@@ -1085,7 +1052,7 @@ babel-register@^6.11.6, babel-register@^6.24.1:
|
||||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.2"
|
||||
|
||||
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19, babel-runtime@~6.23.0:
|
||||
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
|
||||
dependencies:
|
||||
@@ -1166,12 +1133,6 @@ binary@^0.3.0:
|
||||
buffers "~0.1.1"
|
||||
chainsaw "~0.1.0"
|
||||
|
||||
bl@^1.0.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e"
|
||||
dependencies:
|
||||
readable-stream "^2.0.5"
|
||||
|
||||
bl@~0.9.0:
|
||||
version "0.9.5"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054"
|
||||
@@ -1250,10 +1211,6 @@ buf-compare@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buf-compare/-/buf-compare-1.0.1.tgz#fef28da8b8113a0a0db4430b0b6467b69730b34a"
|
||||
|
||||
buffer-crc32@^0.2.1:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
|
||||
buffer-equals@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5"
|
||||
@@ -1453,12 +1410,6 @@ cli-cursor@^1.0.1, cli-cursor@^1.0.2:
|
||||
dependencies:
|
||||
restore-cursor "^1.0.1"
|
||||
|
||||
cli-cursor@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
|
||||
dependencies:
|
||||
restore-cursor "^2.0.0"
|
||||
|
||||
cli-spinners@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
|
||||
@@ -1604,15 +1555,6 @@ component-emitter@~1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||
|
||||
compress-commons@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.0.tgz#58587092ef20d37cb58baf000112c9278ff73b9f"
|
||||
dependencies:
|
||||
buffer-crc32 "^0.2.1"
|
||||
crc32-stream "^2.0.0"
|
||||
normalize-path "^2.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
compressible@~2.0.8:
|
||||
version "2.0.10"
|
||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd"
|
||||
@@ -1724,6 +1666,12 @@ cookiejar@2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.6.tgz#0abf356ad00d1c5a219d88d44518046dd026acfe"
|
||||
|
||||
copy-to-clipboard@^3.0.6:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.6.tgz#13c09bfea0408a5dc5bb987fee3b3986518c9d69"
|
||||
dependencies:
|
||||
toggle-selection "^1.0.3"
|
||||
|
||||
core-assert@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/core-assert/-/core-assert-0.2.1.tgz#f85e2cf9bfed28f773cc8b3fa5c5b69bdc02fe3f"
|
||||
@@ -1743,17 +1691,6 @@ core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
crc32-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4"
|
||||
dependencies:
|
||||
crc "^3.4.4"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
crc@^3.4.4:
|
||||
version "3.4.4"
|
||||
resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b"
|
||||
|
||||
create-error-class@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
||||
@@ -1825,12 +1762,6 @@ css-parse@1.7.x:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b"
|
||||
|
||||
css-parse@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4"
|
||||
dependencies:
|
||||
css "^2.0.0"
|
||||
|
||||
css-selector-tokenizer@^0.5.0, css-selector-tokenizer@^0.5.1:
|
||||
version "0.5.4"
|
||||
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.5.4.tgz#139bafd34a35fd0c1428487049e0699e6f6a2c21"
|
||||
@@ -1838,19 +1769,6 @@ css-selector-tokenizer@^0.5.0, css-selector-tokenizer@^0.5.1:
|
||||
cssesc "^0.1.0"
|
||||
fastparse "^1.1.1"
|
||||
|
||||
css-value@~0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea"
|
||||
|
||||
css@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc"
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
source-map "^0.1.38"
|
||||
source-map-resolve "^0.3.0"
|
||||
urix "^0.1.0"
|
||||
|
||||
cssesc@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
|
||||
@@ -2017,10 +1935,6 @@ deep-is@~0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
|
||||
deepmerge@~1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.3.2.tgz#1663691629d4dbfe364fa12a2a4f0aa86aa3a050"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
@@ -2074,10 +1988,6 @@ detect-indent@^4.0.0:
|
||||
dependencies:
|
||||
repeating "^2.0.0"
|
||||
|
||||
dev-null@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818"
|
||||
|
||||
devtron@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/devtron/-/devtron-1.4.0.tgz#b5e748bd6e95bbe70bfcc68aae6fe696119441e1"
|
||||
@@ -2142,17 +2052,6 @@ ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
||||
ejs@~2.5.6:
|
||||
version "2.5.6"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88"
|
||||
|
||||
electron-chromedriver@~1.7.0:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-1.7.1.tgz#008c97976007aa4eb18491ee095e94d17ee47610"
|
||||
dependencies:
|
||||
electron-download "^4.1.0"
|
||||
extract-zip "^1.6.5"
|
||||
|
||||
electron-config@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-config/-/electron-config-0.2.1.tgz#7e12c26412d06bf3ed3896d0479df162986b95ba"
|
||||
@@ -2186,20 +2085,6 @@ electron-download@^3.0.1:
|
||||
semver "^5.3.0"
|
||||
sumchecker "^1.2.0"
|
||||
|
||||
electron-download@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
|
||||
dependencies:
|
||||
debug "^2.2.0"
|
||||
env-paths "^1.0.0"
|
||||
fs-extra "^2.0.0"
|
||||
minimist "^1.2.0"
|
||||
nugget "^2.0.0"
|
||||
path-exists "^3.0.0"
|
||||
rc "^1.1.2"
|
||||
semver "^5.3.0"
|
||||
sumchecker "^2.0.1"
|
||||
|
||||
electron-gh-releases@^2.0.2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-gh-releases/-/electron-gh-releases-2.0.4.tgz#198c07a0970fb8e80fcc67bd0b4198a010923dc3"
|
||||
@@ -2283,12 +2168,6 @@ encoding@^0.1.11:
|
||||
dependencies:
|
||||
iconv-lite "~0.4.13"
|
||||
|
||||
end-of-stream@^1.0.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
enhanced-resolve@~0.9.0:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
|
||||
@@ -2305,10 +2184,6 @@ env-paths@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-0.3.1.tgz#c30ccfcbc30c890943dc08a85582517ef00da463"
|
||||
|
||||
env-paths@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0"
|
||||
|
||||
errno@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
|
||||
@@ -2682,21 +2557,13 @@ extend@3.0.0, extend@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
|
||||
|
||||
external-editor@^2.0.1:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972"
|
||||
dependencies:
|
||||
iconv-lite "^0.4.17"
|
||||
jschardet "^1.4.2"
|
||||
tmp "^0.0.31"
|
||||
|
||||
extglob@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
|
||||
dependencies:
|
||||
is-extglob "^1.0.0"
|
||||
|
||||
extract-zip@^1.0.3, extract-zip@^1.6.5:
|
||||
extract-zip@^1.0.3:
|
||||
version "1.6.5"
|
||||
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.5.tgz#99a06735b6ea20ea9b705d779acffcc87cff0440"
|
||||
dependencies:
|
||||
@@ -2758,12 +2625,6 @@ figures@^1.3.5, figures@^1.4.0:
|
||||
escape-string-regexp "^1.0.5"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
figures@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
|
||||
file-entry-cache@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
|
||||
@@ -2938,13 +2799,6 @@ fs-extra@^0.30.0:
|
||||
path-is-absolute "^1.0.0"
|
||||
rimraf "^2.2.8"
|
||||
|
||||
fs-extra@^2.0.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^2.1.0"
|
||||
|
||||
fs-plus@2.x:
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-plus/-/fs-plus-2.10.1.tgz#3204781d7840611e6364e7b6fb058c96327c5aa5"
|
||||
@@ -2999,12 +2853,6 @@ gauge@~2.7.3:
|
||||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
gaze@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
|
||||
dependencies:
|
||||
globule "^1.0.0"
|
||||
|
||||
generate-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
|
||||
@@ -3099,7 +2947,7 @@ glob@^6.0.1, glob@^6.0.3, glob@^6.0.4:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1:
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
dependencies:
|
||||
@@ -3140,14 +2988,6 @@ globby@^5.0.0:
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
globule@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
|
||||
dependencies:
|
||||
glob "~7.1.1"
|
||||
lodash "~4.16.4"
|
||||
minimatch "~3.0.2"
|
||||
|
||||
got@^5.0.0, got@^5.1.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
|
||||
@@ -3174,7 +3014,7 @@ graceful-fs@^3.0.0, graceful-fs@^3.0.5:
|
||||
dependencies:
|
||||
natives "^1.1.0"
|
||||
|
||||
graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
@@ -3435,14 +3275,10 @@ humanize-plus@^1.8.1:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
|
||||
|
||||
iconv-lite@0.4.13:
|
||||
iconv-lite@0.4.13, iconv-lite@~0.4.13:
|
||||
version "0.4.13"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
|
||||
|
||||
iconv-lite@^0.4.17, iconv-lite@~0.4.13:
|
||||
version "0.4.17"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d"
|
||||
|
||||
iconv-lite@~0.2.11:
|
||||
version "0.2.11"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
|
||||
@@ -3522,24 +3358,6 @@ inquirer@^0.12.0:
|
||||
strip-ansi "^3.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@~3.0.6:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347"
|
||||
dependencies:
|
||||
ansi-escapes "^1.1.0"
|
||||
chalk "^1.0.0"
|
||||
cli-cursor "^2.1.0"
|
||||
cli-width "^2.0.0"
|
||||
external-editor "^2.0.1"
|
||||
figures "^2.0.0"
|
||||
lodash "^4.3.0"
|
||||
mute-stream "0.0.7"
|
||||
run-async "^2.2.0"
|
||||
rx "^4.1.0"
|
||||
string-width "^2.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
interpret@^0.6.4:
|
||||
version "0.6.6"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
|
||||
@@ -3844,10 +3662,6 @@ jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
|
||||
jschardet@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.4.2.tgz#2aa107f142af4121d145659d44f50830961e699a"
|
||||
|
||||
jsdom@^9.4.2:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
|
||||
@@ -3971,12 +3785,6 @@ lazy-req@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
|
||||
|
||||
lazystream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
|
||||
dependencies:
|
||||
readable-stream "^2.0.5"
|
||||
|
||||
lcid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
|
||||
@@ -4075,7 +3883,7 @@ lodash@^3.5.0:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||
|
||||
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1, lodash@^4.8.0:
|
||||
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
@@ -4087,10 +3895,6 @@ lodash@~2.4.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e"
|
||||
|
||||
lodash@~4.16.4:
|
||||
version "4.16.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
|
||||
|
||||
longest@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
@@ -4296,10 +4100,6 @@ mime@1.3.4, mime@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
|
||||
|
||||
mimic-fn@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
|
||||
|
||||
min-document@^2.19.0:
|
||||
version "2.19.0"
|
||||
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
|
||||
@@ -4313,7 +4113,7 @@ minimatch@0.3:
|
||||
lru-cache "2"
|
||||
sigmund "~1.0.0"
|
||||
|
||||
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
|
||||
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
dependencies:
|
||||
@@ -4332,7 +4132,7 @@ minimatch@~0.2.11, minimatch@~0.2.12:
|
||||
lru-cache "2"
|
||||
sigmund "~1.0.0"
|
||||
|
||||
minimist@0.0.8:
|
||||
minimist@0.0.8, minimist@~0.0.1:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
|
||||
@@ -4340,10 +4140,6 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
minimist@~0.0.1:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
|
||||
|
||||
mixpanel@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.4.1.tgz#0e92ee336fb89a164f54830f093c9cae8517fb8f"
|
||||
@@ -4409,10 +4205,6 @@ mute-stream@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
|
||||
|
||||
mute-stream@0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||
|
||||
mv@^2.0.3:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
|
||||
@@ -4541,7 +4333,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
|
||||
semver "2 || 3 || 4 || 5"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
normalize-path@^2.0.0, normalize-path@^2.0.1:
|
||||
normalize-path@^2.0.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
|
||||
dependencies:
|
||||
@@ -4566,10 +4358,6 @@ not-so-shallow@^0.1.3:
|
||||
dependencies:
|
||||
buffer-equals "^1.0.3"
|
||||
|
||||
npm-install-package@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125"
|
||||
|
||||
npmlog@^4.0.2:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
|
||||
@@ -4659,7 +4447,7 @@ on-headers@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
|
||||
|
||||
once@^1.3.0, once@^1.3.3, once@^1.4.0:
|
||||
once@^1.3.0, once@^1.3.3:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
@@ -4669,12 +4457,6 @@ onetime@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
|
||||
|
||||
onetime@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
|
||||
dependencies:
|
||||
mimic-fn "^1.0.0"
|
||||
|
||||
open@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
|
||||
@@ -4729,7 +4511,7 @@ os-locale@^1.4.0:
|
||||
dependencies:
|
||||
lcid "^1.0.0"
|
||||
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
|
||||
@@ -5304,7 +5086,7 @@ punycode@^1.2.4, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
||||
q@^1.1.2, q@~1.5.0:
|
||||
q@^1.1.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
|
||||
|
||||
@@ -5710,7 +5492,7 @@ request@2.55.0:
|
||||
tough-cookie ">=0.12.0"
|
||||
tunnel-agent "~0.4.0"
|
||||
|
||||
request@^2.45.0, request@^2.65.0, request@^2.79.0, request@^2.81.0, request@~2.81.0:
|
||||
request@^2.45.0, request@^2.79.0, request@^2.81.0:
|
||||
version "2.81.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||
dependencies:
|
||||
@@ -5766,10 +5548,6 @@ resolve-from@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
|
||||
|
||||
resolve-url@~0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
|
||||
resolve@^1.1.6:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
|
||||
@@ -5783,17 +5561,6 @@ restore-cursor@^1.0.1:
|
||||
exit-hook "^1.0.0"
|
||||
onetime "^1.0.0"
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||
dependencies:
|
||||
onetime "^2.0.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
rgb2hex@~0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.0.tgz#ccd55f860ae0c5c4ea37504b958e442d8d12325b"
|
||||
|
||||
right-align@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
|
||||
@@ -5826,12 +5593,6 @@ run-async@^0.1.0:
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
|
||||
run-async@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
|
||||
dependencies:
|
||||
is-promise "^2.1.0"
|
||||
|
||||
run-parallel@^1.1.2:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039"
|
||||
@@ -5848,11 +5609,7 @@ rx@2.3.24:
|
||||
version "2.3.24"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7"
|
||||
|
||||
rx@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@~5.0.1:
|
||||
safe-buffer@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
|
||||
|
||||
@@ -5954,7 +5711,7 @@ sigmund@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
|
||||
|
||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
||||
@@ -6014,26 +5771,13 @@ source-list-map@^0.1.4, source-list-map@~0.1.7:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
|
||||
|
||||
source-map-resolve@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761"
|
||||
dependencies:
|
||||
atob "~1.1.0"
|
||||
resolve-url "~0.2.1"
|
||||
source-map-url "~0.3.0"
|
||||
urix "~0.1.0"
|
||||
|
||||
source-map-support@^0.4.0, source-map-support@^0.4.2:
|
||||
version "0.4.15"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1"
|
||||
dependencies:
|
||||
source-map "^0.5.6"
|
||||
|
||||
source-map-url@~0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
|
||||
|
||||
source-map@0.1.x, source-map@^0.1.38:
|
||||
source-map@0.1.x:
|
||||
version "0.1.43"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
|
||||
dependencies:
|
||||
@@ -6073,26 +5817,10 @@ spdx-license-ids@^1.0.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
|
||||
|
||||
spectron@^3.6.2:
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/spectron/-/spectron-3.7.1.tgz#818f68584732187d757da1d7a352adfc89ba136b"
|
||||
dependencies:
|
||||
dev-null "^0.1.1"
|
||||
electron-chromedriver "~1.7.0"
|
||||
request "^2.65.0"
|
||||
split "^1.0.0"
|
||||
webdriverio "^4.0.4"
|
||||
|
||||
speedometer@~0.1.2:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d"
|
||||
|
||||
split@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/split/-/split-1.0.0.tgz#c4395ce683abcd254bc28fe1dabb6e5c27dcffae"
|
||||
dependencies:
|
||||
through "2"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
@@ -6292,12 +6020,6 @@ sumchecker@^1.2.0:
|
||||
debug "^2.2.0"
|
||||
es6-promise "^4.0.5"
|
||||
|
||||
sumchecker@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e"
|
||||
dependencies:
|
||||
debug "^2.2.0"
|
||||
|
||||
superagent-promise@^1.0.3:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/superagent-promise/-/superagent-promise-1.1.0.tgz#baf22d8bbdd439a9b07dd10f8c08f54fe2503533"
|
||||
@@ -6326,7 +6048,7 @@ supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||
|
||||
supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.2.3, supports-color@~3.2.3:
|
||||
supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
||||
dependencies:
|
||||
@@ -6388,15 +6110,6 @@ tar-pack@^3.4.0:
|
||||
tar "^2.2.1"
|
||||
uid-number "^0.0.6"
|
||||
|
||||
tar-stream@^1.5.0:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016"
|
||||
dependencies:
|
||||
bl "^1.0.0"
|
||||
end-of-stream "^1.0.0"
|
||||
readable-stream "^2.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
tar@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
|
||||
@@ -6438,7 +6151,7 @@ through2@~0.2.3:
|
||||
readable-stream "~1.1.9"
|
||||
xtend "~2.1.1"
|
||||
|
||||
through@2, through@^2.3.6:
|
||||
through@^2.3.6:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
|
||||
@@ -6465,12 +6178,6 @@ tinycolor2@^1.1.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
|
||||
|
||||
tmp@^0.0.31:
|
||||
version "0.0.31"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.1"
|
||||
|
||||
to-arraybuffer@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||
@@ -6479,6 +6186,10 @@ to-fast-properties@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||
|
||||
toggle-selection@^1.0.3:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.5.tgz#726c703de607193a73c32c7df49cd24950fc574f"
|
||||
|
||||
touch@0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/touch/-/touch-0.0.3.tgz#51aef3d449571d4f287a5d87c9c8b49181a0db1d"
|
||||
@@ -6664,10 +6375,6 @@ update-notifier@^1.0.0:
|
||||
semver-diff "^2.0.0"
|
||||
xdg-basedir "^2.0.0"
|
||||
|
||||
urix@^0.1.0, urix@~0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
|
||||
url-parse-lax@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
|
||||
@@ -6695,7 +6402,7 @@ url@0.10.3:
|
||||
punycode "1.3.2"
|
||||
querystring "0.2.0"
|
||||
|
||||
url@^0.11.0, url@~0.11.0:
|
||||
url@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
|
||||
dependencies:
|
||||
@@ -6737,10 +6444,6 @@ validate-npm-package-license@^3.0.1:
|
||||
spdx-correct "~1.0.0"
|
||||
spdx-expression-parse "~1.0.0"
|
||||
|
||||
validator@~7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-7.0.0.tgz#c74deb8063512fac35547938e6f0b1504a282fd2"
|
||||
|
||||
vary@~1.1.0, vary@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
|
||||
@@ -6761,10 +6464,6 @@ vm-browserify@0.0.4:
|
||||
dependencies:
|
||||
indexof "0.0.1"
|
||||
|
||||
walkdir@^0.0.11:
|
||||
version "0.0.11"
|
||||
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532"
|
||||
|
||||
warning@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901"
|
||||
@@ -6785,37 +6484,6 @@ watchpack@^0.2.1:
|
||||
chokidar "^1.0.0"
|
||||
graceful-fs "^4.1.2"
|
||||
|
||||
wdio-dot-reporter@~0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.8.tgz#36195576da0d998210c71948cbb65f5bf11bfc65"
|
||||
|
||||
webdriverio@^4.0.4:
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.8.0.tgz#d52929b749080f89967f6e1614051cbc8172d132"
|
||||
dependencies:
|
||||
archiver "~1.3.0"
|
||||
babel-runtime "~6.23.0"
|
||||
css-parse "~2.0.0"
|
||||
css-value "~0.0.1"
|
||||
deepmerge "~1.3.2"
|
||||
ejs "~2.5.6"
|
||||
gaze "~1.1.2"
|
||||
glob "~7.1.1"
|
||||
inquirer "~3.0.6"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mkdirp "~0.5.1"
|
||||
npm-install-package "~2.1.0"
|
||||
optimist "~0.6.1"
|
||||
q "~1.5.0"
|
||||
request "~2.81.0"
|
||||
rgb2hex "~0.1.0"
|
||||
safe-buffer "~5.0.1"
|
||||
supports-color "~3.2.3"
|
||||
url "~0.11.0"
|
||||
validator "~7.0.0"
|
||||
wdio-dot-reporter "~0.0.8"
|
||||
wgxpath "~1.0.0"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
@@ -6888,10 +6556,6 @@ websocket-extensions@>=0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7"
|
||||
|
||||
wgxpath@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690"
|
||||
|
||||
whatwg-encoding@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
|
||||
@@ -7083,13 +6747,3 @@ yauzl@2.4.1:
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
|
||||
dependencies:
|
||||
fd-slicer "~1.0.1"
|
||||
|
||||
zip-stream@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.1.1.tgz#5216b48bbb4d2651f64d5c6e6f09eb4a7399d557"
|
||||
dependencies:
|
||||
archiver-utils "^1.3.0"
|
||||
compress-commons "^1.1.0"
|
||||
lodash "^4.8.0"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user