1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-16 11:15:12 +00:00

Compare commits

..

57 Commits

Author SHA1 Message Date
Kohei TAKATA
a7a5b789fa Merge pull request #1230 from BoostIO/feature-v0-8-18
v0.8.18
2017-12-03 11:51:11 +09:00
Kohei TAKATA
10b7d58dc6 v0.8.18 2017-12-03 11:08:06 +09:00
Kazz Yokomizo
16f0e95e32 Merge pull request #1226 from BoostIO/add-newsletter
Add newsletter link to preference modal
2017-12-02 15:45:36 +09:00
Kazu Yokomizo
55395d3a2d Add newsletter link to preference modal 2017-12-02 15:41:43 +09:00
Kazz Yokomizo
4e0fa63fad Merge pull request #1225 from BoostIO/fix-finder-layout
Fix finder layout
2017-12-02 15:33:55 +09:00
Kazu Yokomizo
b9ea7696d8 Fix finder layout 2017-12-02 15:20:16 +09:00
Kazz Yokomizo
7de3308f52 Merge pull request #1223 from BoostIO/fixbug-cannot-open-finder
fix bug cannot open finder.
2017-12-02 15:07:19 +09:00
Kazz Yokomizo
b2b2373c7b Merge pull request #1218 from PaulRosset/fixbug-react-code-mirror
Fixbug react code mirror
2017-12-02 15:03:19 +09:00
Sosuke Suzuki
1c54f40a28 require ipcClient 2017-12-02 14:07:11 +09:00
Paul Rosset
4735992835 Fix 2017-12-01 17:24:28 +00:00
Paul Rosset
cba3519458 Fix 2017-12-01 17:19:21 +00:00
Paul Rosset
c64a5e1cca Correction eslint purpose 2017-12-01 17:10:04 +00:00
Paul Rosset
47ee8b8ce7 Fix bug on UI Tab in relation to React CodeMirror 2017-12-01 16:56:43 +00:00
Kazz Yokomizo
455b424429 Merge pull request #1211 from yosmoc/tagconfirm_onblur
confirm tag at onBlur event
2017-12-01 15:11:47 +09:00
Kazz Yokomizo
7d67ac3f12 Merge pull request #1212 from PaulRosset/correct-notification-area
Correction Notification top-left
2017-12-01 15:04:40 +09:00
Paul Rosset
34f377eb5c Correction Notification top-left 2017-11-30 21:32:28 +00:00
yosmoc
b7f4af8c78 confirm tag at onBlur event
When user inputs the tag and leave the tag input box without fixing(enter or tab key), tag string is still there, but it is not stored as a tag.

This changes solved this problem. When the cursol is out of the tag input, it registers the input as a tag.
2017-11-30 22:04:56 +01:00
Kazz Yokomizo
a6c7dde194 Merge pull request #1202 from BoostIO/fix-folded-layout
Fix folded layout
2017-11-29 16:51:28 +09:00
Kazu Yokomizo
43ebe4ecfd FIx folded layout 2017-11-29 16:43:26 +09:00
Kazz Yokomizo
1d38f1abb4 Merge pull request #1197 from BoostIO/fix-initialmodal-layout
Fix layout at initial modal
2017-11-28 16:44:07 +09:00
Kazu Yokomizo
061a0cd219 Fix layout at initial modal 2017-11-28 16:27:12 +09:00
Kazz Yokomizo
f0ed20ee2c Merge pull request #1184 from cormoran/fix/SideNavFoldEmoji
Fix surrogate pairs garbling on folded SideNav
2017-11-28 12:42:41 +09:00
Kazz Yokomizo
edfc8d95c8 Merge pull request #1070 from voidsatisfaction/feature/add_multiselect_notes_delete
Feature multiselect notes delete and move to another folder
2017-11-28 12:39:12 +09:00
voidSatisfaction
c33f9d8307 fix: from let to const 2017-11-27 14:31:11 +09:00
voidSatisfaction
eee212f5b8 Merge with master resolve conflict 2017-11-27 14:05:26 +09:00
Kazz Yokomizo
b690147b0b Merge pull request #1187 from BoostIO/fix-note-list
Fix note list layout
2017-11-27 11:26:27 +09:00
Kazu Yokomizo
10879d0f67 Fix note list layout 2017-11-27 11:22:21 +09:00
Kazz Yokomizo
b48b8f39fc Merge pull request #1144 from whizark/store-window-size-on-linux
store correct window size on Linux
2017-11-27 11:06:56 +09:00
cormoran
3d0b3e759b Fix surrogate pairs garbling on folded SideNav 2017-11-27 06:04:24 +09:00
Kazz Yokomizo
3e7f4a41e2 Merge pull request #1183 from BoostIO/update-backers
Update Backers
2017-11-27 03:03:57 +09:00
Kazz Yokomizo
b89b888129 Update Backers 2017-11-27 02:57:17 +09:00
Kazz Yokomizo
cba9afc9ba Merge pull request #1180 from romainwn/fix/SideNavFilter-Hover
SideNavItem: add background when hover
2017-11-26 19:33:16 +09:00
Unknown
a66a11b81e SideNavItem: add background when hover 2017-11-26 11:21:49 +01:00
Kazz Yokomizo
22cc2791b6 Merge pull request #1179 from BoostIO/fix-margin-notedetail
Fix Margin at Note Detail
2017-11-26 16:24:36 +09:00
Kazu Yokomizo
369cf16b68 Fix Margin at Note Detail 2017-11-26 16:14:52 +09:00
Kazz Yokomizo
0d38baf194 Merge pull request #1176 from yosmoc/initmodal_exit_fix
fix anykey can close the initmodal window issue
2017-11-26 16:05:38 +09:00
Kazz Yokomizo
5b63c95f40 Merge pull request #1178 from BoostIO/fix-typo
Fix typo
2017-11-26 15:57:36 +09:00
Kazu Yokomizo
52497999a0 Fix typo 2017-11-26 15:50:45 +09:00
Kohei TAKATA
6bab108a35 Merge pull request #1113 from yosmoc/react_proptypes_deprecated
React.PropTypes is deprecated from React 15.5
2017-11-26 09:22:38 +09:00
yosmoc
eec22e6b7d fix anykey can close the initmodal issue
this change makes only ESC key can close the initmodal window.
2017-11-25 23:39:59 +01:00
yosmoc
edaa0713e8 React.PropTypes is deprecated from React 15.5
Migrated by react-codemod + minor fix by hand.
2017-11-25 22:27:04 +01:00
Kohei TAKATA
6b6a415dd5 Merge pull request #1170 from mslourens/reduce-lint-errors
fixed eslint warnings
2017-11-25 17:43:13 +09:00
Maurits Lourens
3fbc749395 fixed eslint warnings 2017-11-24 17:00:03 +01:00
Whizark
460437397f store window size on Linux 2017-11-19 21:10:53 +09:00
voidSatisfaction
a36e779980 refactor: add new function and fix problems from feedbacks 2017-11-15 23:19:47 +09:00
voidSatisfaction
84f18ced47 fix: pintotop error 2017-11-07 23:07:39 +09:00
voidSatisfaction
037ff2e749 Merge branch 'master' into feature/add_multiselect_notes_delete 2017-11-07 22:53:14 +09:00
voidSatisfaction
f0f23ede3d Merge branch 'master' into feature/add_multiselect_notes_delete 2017-11-07 22:48:50 +09:00
voidSatisfaction
c8763063c0 resolve conflict with master 2017-11-07 22:47:08 +09:00
voidSatisfaction
e57fef2413 refactor: add utils 2017-11-07 22:38:28 +09:00
voidSatisfaction
9095fe934d add multi selection with arrow short cut 2017-11-07 00:01:50 +09:00
voidSatisfaction
9139495f02 feat: add multiple pin to top and rename activateNote to focusNote 2017-11-06 21:53:31 +09:00
voidSatisfaction
bcb1fb4331 feat multi drag and drop for changing folder 2017-11-05 21:18:39 +09:00
voidSatisfaction
70b69a3bc9 refactor: inner codes 2017-11-05 19:22:55 +09:00
voidSatisfaction
a7e458b784 feat change name and add deletion logic 2017-11-05 19:00:03 +09:00
voidSatisfaction
a504a45d99 fix up and down key rendering problems 2017-11-05 18:45:09 +09:00
voidSatisfaction
2d0e14c1cc feat: add shiftkey multiselect notes and delete 2017-11-05 18:11:08 +09:00
102 changed files with 860 additions and 615 deletions

View File

@@ -12,5 +12,10 @@
"react/no-find-dom-node": "warn", "react/no-find-dom-node": "warn",
"react/no-render-return-value": "warn", "react/no-render-return-value": "warn",
"react/no-deprecated": "warn" "react/no-deprecated": "warn"
},
"globals": {
"FileReader": true,
"localStorage": true,
"fetch": true
} }
} }

View File

@@ -1,27 +1,50 @@
<h1 align="center">Sponsors &amp; Backers</h1> <h1 align="center">Sponsors &amp; Backers</h1>
Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider: Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome backers. If you'd like to join them, please consider:
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio) - [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
--- ---
## Backers via OpenCollective ## Backers via OpenCollective
<a href="https://opencollective.com/boostnoteio#backers" target="_blank"><img src="https://opencollective.com/boostnoteio/backers.svg?width=890"></a>
- [Ralph03](https://opencollective.com/ralph03) - $24 ### [Gold Sponsors / $1,000 per month](https://opencollective.com/boostnoteio/order/2259)
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
- [Nikolas Dan](https://opencollective.com/nikolas-dan) - $20 ### [Silver Sponsors / $250 per month](https://opencollective.com/boostnoteio/order/2257)
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
- [tatoosh11](https://twitter.com/ta11) - $10 ### [Bronze Sponsors / $50 per month](https://opencollective.com/boostnoteio/order/2258)
- Get your name and Url (or E-mail) on Readme.md on GitHub.
- [Alexander Borovkov](https://opencollective.com/alexander-borovkov) - $10 ### [Backers3 / $10 per month](https://opencollective.com/boostnoteio/order/2176)
- [Ralph03](https://opencollective.com/ralph03)
- [Yeojong Kim](https://twitter.com/yeojoy) - $5 - [Nikolas Dan](https://opencollective.com/nikolas-dan)
- [Scotia Draven](https://opencollective.com/scotia-draven) - $5 ### [Backers2 / $5 per month](https://opencollective.com/boostnoteio/order/2175)
- [Yeojong Kim](https://twitter.com/yeojoy)
- [spoonhoop](https://opencollective.com/spoonhoop) - $5 - [Scotia Draven](https://opencollective.com/scotia-draven)
- [A. J. Vargas](https://opencollective.com/aj-vargas)
### [Backers1](https://opencollective.com/boostnoteio/order/2563) and One-time sponsors
- Ryosuke Tamura - $30
- tatoosh11 - $10
- Alexander Borovkov - $10
- spoonhoop - $5
- Drew Williams - $2
- Andy Shaw - $2
- mysafesky -$2
---
## Backers via Bountysource ## Backers via Bountysource
https://salt.bountysource.com/teams/boostnote https://salt.bountysource.com/teams/boostnote

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import _ from 'lodash' import _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import path from 'path' import path from 'path'
@@ -103,7 +104,7 @@ export default class CodeEditor extends React.Component {
this.editor.on('change', this.changeHandler) this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler) this.editor.on('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.addEventListener('load', this.loadStyleHandler) editorTheme.addEventListener('load', this.loadStyleHandler)
CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor) CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor)
@@ -121,7 +122,7 @@ export default class CodeEditor extends React.Component {
this.editor.off('blur', this.blurHandler) this.editor.off('blur', this.blurHandler)
this.editor.off('change', this.changeHandler) this.editor.off('change', this.changeHandler)
this.editor.off('paste', this.pasteHandler) this.editor.off('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler) editorTheme.removeEventListener('load', this.loadStyleHandler)
} }
@@ -197,7 +198,7 @@ export default class CodeEditor extends React.Component {
} }
setValue (value) { setValue (value) {
let cursor = this.editor.getCursor() const cursor = this.editor.getCursor()
this.editor.setValue(value) this.editor.setValue(value)
this.editor.setCursor(cursor) this.editor.setCursor(cursor)
} }
@@ -222,7 +223,7 @@ export default class CodeEditor extends React.Component {
if (!dataTransferItem.type.match('image')) return if (!dataTransferItem.type.match('image')) return
const blob = dataTransferItem.getAsFile() const blob = dataTransferItem.getAsFile()
let reader = new FileReader() const reader = new FileReader()
let base64data let base64data
reader.readAsDataURL(blob) reader.readAsDataURL(blob)
@@ -242,7 +243,8 @@ export default class CodeEditor extends React.Component {
} }
render () { render () {
let { className, fontFamily, fontSize } = this.props const { className, fontSize } = this.props
let fontFamily = this.props.className
fontFamily = _.isString(fontFamily) && fontFamily.length > 0 fontFamily = _.isString(fontFamily) && fontFamily.length > 0
? [fontFamily].concat(defaultEditorFontFamily) ? [fontFamily].concat(defaultEditorFontFamily)
: defaultEditorFontFamily : defaultEditorFontFamily

View File

@@ -1,11 +1,11 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './MarkdownEditor.styl' import styles from './MarkdownEditor.styl'
import CodeEditor from 'browser/components/CodeEditor' import CodeEditor from 'browser/components/CodeEditor'
import MarkdownPreview from 'browser/components/MarkdownPreview' import MarkdownPreview from 'browser/components/MarkdownPreview'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import { findStorage } from 'browser/lib/findStorage' import { findStorage } from 'browser/lib/findStorage'
const _ = require('lodash')
class MarkdownEditor extends React.Component { class MarkdownEditor extends React.Component {
constructor (props) { constructor (props) {
@@ -70,9 +70,9 @@ class MarkdownEditor extends React.Component {
} }
handleContextMenu (e) { handleContextMenu (e) {
let { config } = this.props const { config } = this.props
if (config.editor.switchPreview === 'RIGHTCLICK') { if (config.editor.switchPreview === 'RIGHTCLICK') {
let newStatus = this.state.status === 'PREVIEW' const newStatus = this.state.status === 'PREVIEW'
? 'CODE' ? 'CODE'
: 'PREVIEW' : 'PREVIEW'
this.setState({ this.setState({
@@ -91,9 +91,9 @@ class MarkdownEditor extends React.Component {
handleBlur (e) { handleBlur (e) {
if (this.state.isLocked) return if (this.state.isLocked) return
this.setState({ keyPressed: new Set() }) this.setState({ keyPressed: new Set() })
let { config } = this.props const { config } = this.props
if (config.editor.switchPreview === 'BLUR') { if (config.editor.switchPreview === 'BLUR') {
let cursorPosition = this.refs.code.editor.getCursor() const cursorPosition = this.refs.code.editor.getCursor()
this.setState({ this.setState({
status: 'PREVIEW' status: 'PREVIEW'
}, () => { }, () => {
@@ -109,7 +109,7 @@ class MarkdownEditor extends React.Component {
} }
handlePreviewMouseUp (e) { handlePreviewMouseUp (e) {
let { config } = this.props const { config } = this.props
if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) { if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) {
this.setState({ this.setState({
status: 'CODE' status: 'CODE'
@@ -123,15 +123,15 @@ class MarkdownEditor extends React.Component {
handleCheckboxClick (e) { handleCheckboxClick (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let idMatch = /checkbox-([0-9]+)/ const idMatch = /checkbox-([0-9]+)/
let checkedMatch = /\[x\]/i const checkedMatch = /\[x\]/i
let uncheckedMatch = /\[ \]/ const uncheckedMatch = /\[ \]/
if (idMatch.test(e.target.getAttribute('id'))) { if (idMatch.test(e.target.getAttribute('id'))) {
let lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1 const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
let lines = this.refs.code.value const lines = this.refs.code.value
.split('\n') .split('\n')
let targetLine = lines[lineIndex] const targetLine = lines[lineIndex]
if (targetLine.match(checkedMatch)) { if (targetLine.match(checkedMatch)) {
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]') lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
@@ -163,12 +163,12 @@ class MarkdownEditor extends React.Component {
} }
handleKeyDown (e) { handleKeyDown (e) {
let { config } = this.props const { config } = this.props
if (this.state.status !== 'CODE') return false if (this.state.status !== 'CODE') return false
const keyPressed = this.state.keyPressed const keyPressed = this.state.keyPressed
keyPressed.add(e.keyCode) keyPressed.add(e.keyCode)
this.setState({ keyPressed }) this.setState({ keyPressed })
let isNoteHandlerKey = (el) => { return keyPressed.has(el) } const isNoteHandlerKey = (el) => { return keyPressed.has(el) }
// These conditions are for ctrl-e and ctrl-w // These conditions are for ctrl-e and ctrl-w
if (keyPressed.size === this.escapeFromEditor.length && if (keyPressed.size === this.escapeFromEditor.length &&
!this.state.isLocked && this.state.status === 'CODE' && !this.state.isLocked && this.state.status === 'CODE' &&
@@ -207,14 +207,14 @@ class MarkdownEditor extends React.Component {
} }
render () { render () {
let { className, value, config, storageKey } = this.props const { className, value, config, storageKey } = this.props
let editorFontSize = parseInt(config.editor.fontSize, 10) let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10) let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4 if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let previewStyle = {} const previewStyle = {}
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none' if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
const storage = findStorage(storageKey) const storage = findStorage(storageKey)

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import markdown from 'browser/lib/markdown' import markdown from 'browser/lib/markdown'
import _ from 'lodash' import _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
@@ -126,10 +127,10 @@ export default class MarkdownPreview extends React.Component {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let anchor = e.target.closest('a') const anchor = e.target.closest('a')
let href = anchor.getAttribute('href') const href = anchor.getAttribute('href')
if (_.isString(href) && href.match(/^#/)) { if (_.isString(href) && href.match(/^#/)) {
let targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length)) const targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length))
if (targetElement != null) { if (targetElement != null) {
this.getWindow().scrollTo(0, targetElement.offsetTop) this.getWindow().scrollTo(0, targetElement.offsetTop)
} }
@@ -251,7 +252,8 @@ export default class MarkdownPreview extends React.Component {
} }
applyStyle () { applyStyle () {
let { fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props const { fontSize, lineNumber, codeBlockTheme } = this.props
let { fontFamily, codeBlockFontFamily } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0 fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? [fontFamily].concat(defaultFontFamily) ? [fontFamily].concat(defaultFontFamily)
: defaultFontFamily : defaultFontFamily
@@ -284,7 +286,8 @@ export default class MarkdownPreview extends React.Component {
el.removeEventListener('click', this.linkClickHandler) el.removeEventListener('click', this.linkClickHandler)
}) })
let { value, theme, indentSize, codeBlockTheme, showCopyNotification, storagePath } = this.props const { theme, indentSize, showCopyNotification, storagePath } = this.props
let { value, codeBlockTheme } = this.props
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme) this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
@@ -327,7 +330,7 @@ export default class MarkdownPreview extends React.Component {
let syntax = CodeMirror.findModeByName(el.className) let syntax = CodeMirror.findModeByName(el.className)
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
CodeMirror.requireMode(syntax.mode, () => { CodeMirror.requireMode(syntax.mode, () => {
let content = htmlTextHelper.decodeEntities(el.innerHTML) const content = htmlTextHelper.decodeEntities(el.innerHTML)
const copyIcon = document.createElement('i') const copyIcon = document.createElement('i')
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>' copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
copyIcon.onclick = (e) => { copyIcon.onclick = (e) => {
@@ -352,7 +355,7 @@ export default class MarkdownPreview extends React.Component {
}) })
}) })
}) })
let opts = {} const opts = {}
// if (this.props.theme === 'dark') { // if (this.props.theme === 'dark') {
// opts['font-color'] = '#DDD' // opts['font-color'] = '#DDD'
// opts['line-color'] = '#DDD' // opts['line-color'] = '#DDD'
@@ -362,7 +365,7 @@ export default class MarkdownPreview extends React.Component {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.flowchart'), (el) => { _.forEach(this.refs.root.contentWindow.document.querySelectorAll('.flowchart'), (el) => {
Raphael.setWindow(this.getWindow()) Raphael.setWindow(this.getWindow())
try { try {
let diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML)) const diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML))
el.innerHTML = '' el.innerHTML = ''
diagram.drawSVG(el, opts) diagram.drawSVG(el, opts)
_.forEach(el.querySelectorAll('a'), (el) => { _.forEach(el.querySelectorAll('a'), (el) => {
@@ -378,7 +381,7 @@ export default class MarkdownPreview extends React.Component {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.sequence'), (el) => { _.forEach(this.refs.root.contentWindow.document.querySelectorAll('.sequence'), (el) => {
Raphael.setWindow(this.getWindow()) Raphael.setWindow(this.getWindow())
try { try {
let diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML)) const diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML))
el.innerHTML = '' el.innerHTML = ''
diagram.drawSVG(el, {theme: 'simple'}) diagram.drawSVG(el, {theme: 'simple'})
_.forEach(el.querySelectorAll('a'), (el) => { _.forEach(el.querySelectorAll('a'), (el) => {
@@ -401,11 +404,11 @@ export default class MarkdownPreview extends React.Component {
} }
scrollTo (targetRow) { scrollTo (targetRow) {
let blocks = this.getWindow().document.querySelectorAll('body>[data-line]') const blocks = this.getWindow().document.querySelectorAll('body>[data-line]')
for (let index = 0; index < blocks.length; index++) { for (let index = 0; index < blocks.length; index++) {
let block = blocks[index] let block = blocks[index]
let row = parseInt(block.getAttribute('data-line')) const row = parseInt(block.getAttribute('data-line'))
if (row > targetRow || index === blocks.length - 1) { if (row > targetRow || index === blocks.length - 1) {
block = blocks[index - 1] block = blocks[index - 1]
block != null && this.getWindow().scrollTo(0, block.offsetTop) block != null && this.getWindow().scrollTo(0, block.offsetTop)
@@ -435,7 +438,7 @@ export default class MarkdownPreview extends React.Component {
} }
render () { render () {
let { className, style, tabIndex } = this.props const { className, style, tabIndex } = this.props
return ( return (
<iframe className={className != null <iframe className={className != null
? 'MarkdownPreview ' + className ? 'MarkdownPreview ' + className

View File

@@ -1,4 +1,5 @@
import React, {PropTypes} from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './ModalEscButton.styl' import styles from './ModalEscButton.styl'

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Micro component for toggle SideNav * @fileoverview Micro component for toggle SideNav
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import styles from './NavToggleButton.styl' import styles from './NavToggleButton.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Note item component. * @fileoverview Note item component.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import { isArray } from 'lodash' import { isArray } from 'lodash'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import { getTodoStatus } from 'browser/lib/getTodoStatus' import { getTodoStatus } from 'browser/lib/getTodoStatus'

View File

@@ -73,6 +73,7 @@ $control-height = 30px
position relative position relative
font-size 12px font-size 12px
color $ui-inactive-text-color color $ui-inactive-text-color
top 2px
.item-title .item-title
font-size 15px font-size 15px
@@ -80,8 +81,8 @@ $control-height = 30px
position relative position relative
top -12px top -12px
left 20px left 20px
padding-right 15px padding 0px 15px 0px 0px
padding-bottom 4px margin-bottom 4px
overflow ellipsis overflow ellipsis
color $ui-inactive-text-color color $ui-inactive-text-color

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Note item component with simple display mode. * @fileoverview Note item component with simple display mode.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './NoteItemSimple.styl' import styles from './NoteItemSimple.styl'

View File

@@ -1,4 +1,4 @@
import React, { PropTypes } from 'react' import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './RealtimeNotification.styl' import styles from './RealtimeNotification.styl'

View File

@@ -1,11 +1,8 @@
.notification-area .notification-area
z-index 1000 z-index 1000
font-size 12px font-size 12px
position absolute position: relative
bottom 20px top: 12px
width 100%
float left
height 30px
background-color none background-color none
.notification-link .notification-link

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Filter for all notes. * @fileoverview Filter for all notes.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './SideNavFilter.styl' import styles from './SideNavFilter.styl'

View File

@@ -57,9 +57,13 @@
@extend .menu @extend .menu
.menu-button, .menu-button--active .menu-button, .menu-button--active
text-align center text-align center
padding 0 12px
&:hover .menu-button-label &:hover .menu-button-label
transition opacity 0.15s transition opacity 0.15s
opacity 1 opacity 1
color $ui-tooltip-text-color
background-color $ui-tooltip-backgroundColor
.menu-button-label .menu-button-label
position fixed position fixed

View File

@@ -86,7 +86,7 @@ class SnippetTab extends React.Component {
} }
render () { render () {
let { isActive, snippet, isDeletable } = this.props const { isActive, snippet, isDeletable } = this.props
return ( return (
<div styleName={isActive <div styleName={isActive
? 'root--active' ? 'root--active'

View File

@@ -1,10 +1,11 @@
/** /**
* @fileoverview Micro component for showing storage. * @fileoverview Micro component for showing storage.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import styles from './StorageItem.styl' import styles from './StorageItem.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import { isNumber } from 'lodash' import _ from 'lodash'
/** /**
* @param {boolean} isActive * @param {boolean} isActive
@@ -36,9 +37,9 @@ const StorageItem = ({
<span styleName={isFolded <span styleName={isFolded
? 'folderList-item-name--folded' : 'folderList-item-name' ? 'folderList-item-name--folded' : 'folderList-item-name'
}> }>
<text style={{color: folderColor, paddingRight: '10px'}}>{isActive ? <i className='fa fa-folder-open-o' /> : <i className='fa fa-folder-o' />}</text>{isFolded ? folderName.substring(0, 1) : folderName} <text style={{color: folderColor, paddingRight: '10px'}}>{isActive ? <i className='fa fa-folder-open-o' /> : <i className='fa fa-folder-o' />}</text>{isFolded ? _.truncate(folderName, {length: 1, omission: ''}) : folderName}
</span> </span>
{(!isFolded && isNumber(noteCount)) && {(!isFolded && _.isNumber(noteCount)) &&
<span styleName='folderList-item-noteCount'>{noteCount}</span> <span styleName='folderList-item-noteCount'>{noteCount}</span>
} }
{isFolded && {isFolded &&

View File

@@ -68,9 +68,9 @@
.folderList-item-name--folded .folderList-item-name--folded
@extend .folderList-item-name @extend .folderList-item-name
padding-left 17px padding-left 7px
text text
display none font-size 9px
body[data-theme="white"] body[data-theme="white"]
.folderList-item .folderList-item

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Micro component for showing StorageList * @fileoverview Micro component for showing StorageList
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import styles from './StorageList.styl' import styles from './StorageList.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Micro component for showing TagList. * @fileoverview Micro component for showing TagList.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import styles from './TagListItem.styl' import styles from './TagListItem.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'

View File

@@ -2,7 +2,8 @@
* @fileoverview Percentage of todo achievement. * @fileoverview Percentage of todo achievement.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TodoListPercentage.styl' import styles from './TodoListPercentage.styl'

View File

@@ -2,7 +2,8 @@
* @fileoverview Percentage of todo achievement. * @fileoverview Percentage of todo achievement.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TodoProcess.styl' import styles from './TodoProcess.styl'

View File

@@ -56,7 +56,7 @@ class NoteDetail extends React.Component {
} }
selectPriorSnippet () { selectPriorSnippet () {
let { note } = this.props const { note } = this.props
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) { if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
this.setState({ this.setState({
snippetIndex: (this.state.snippetIndex + note.snippets.length - 1) % note.snippets.length snippetIndex: (this.state.snippetIndex + note.snippets.length - 1) % note.snippets.length
@@ -65,7 +65,7 @@ class NoteDetail extends React.Component {
} }
selectNextSnippet () { selectNextSnippet () {
let { note } = this.props const { note } = this.props
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) { if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
this.setState({ this.setState({
snippetIndex: (this.state.snippetIndex + 1) % note.snippets.length snippetIndex: (this.state.snippetIndex + 1) % note.snippets.length
@@ -74,7 +74,7 @@ class NoteDetail extends React.Component {
} }
saveToClipboard () { saveToClipboard () {
let { note } = this.props const { note } = this.props
if (note.type === 'MARKDOWN_NOTE') { if (note.type === 'MARKDOWN_NOTE') {
clipboard.writeText(note.content) clipboard.writeText(note.content)
@@ -95,7 +95,7 @@ class NoteDetail extends React.Component {
} }
render () { render () {
let { note, config } = this.props const { note, config } = this.props
if (note == null) { if (note == null) {
return ( return (
<div styleName='root' /> <div styleName='root' />
@@ -110,8 +110,8 @@ class NoteDetail extends React.Component {
const storage = findStorage(note.storage) const storage = findStorage(note.storage)
if (note.type === 'SNIPPET_NOTE') { if (note.type === 'SNIPPET_NOTE') {
let tabList = note.snippets.map((snippet, index) => { const tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
return <div styleName={isActive return <div styleName={isActive
? 'tabList-item--active' ? 'tabList-item--active'
: 'tabList-item' : 'tabList-item'
@@ -131,8 +131,8 @@ class NoteDetail extends React.Component {
</div> </div>
}) })
let viewList = note.snippets.map((snippet, index) => { const viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode)) let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')

View File

@@ -3,8 +3,7 @@
.root .root
absolute top bottom left right absolute top bottom left right
bottom 30px bottom 30px
left $note-detail-left-margin margin 0 25px
right $note-detail-right-margin
height 100% height 100%
width 365px width 365px
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor

View File

@@ -18,18 +18,18 @@ class NoteList extends React.Component {
} }
componentDidUpdate () { componentDidUpdate () {
let { index } = this.props const { index } = this.props
if (index > -1) { if (index > -1) {
let list = this.refs.root const list = this.refs.root
let item = list.childNodes[index] const item = list.childNodes[index]
if (item == null) return null if (item == null) return null
let overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0 const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
if (overflowBelow) { if (overflowBelow) {
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
} }
let overflowAbove = list.scrollTop > item.offsetTop const overflowAbove = list.scrollTop > item.offsetTop
if (overflowAbove) { if (overflowAbove) {
list.scrollTop = item.offsetTop list.scrollTop = item.offsetTop
} }
@@ -44,7 +44,7 @@ class NoteList extends React.Component {
} }
handleScroll (e) { handleScroll (e) {
let { notes } = this.props const { notes } = this.props
if (e.target.offsetHeight + e.target.scrollTop > e.target.scrollHeight - 100 && notes.length > this.state.range * 10 + 10) { if (e.target.offsetHeight + e.target.scrollTop > e.target.scrollHeight - 100 && notes.length > this.state.range * 10 + 10) {
this.setState({ this.setState({
@@ -54,9 +54,9 @@ class NoteList extends React.Component {
} }
render () { render () {
let { notes, index } = this.props const { notes, index } = this.props
let notesList = notes const notesList = notes
.slice(0, 10 + 10 * this.state.range) .slice(0, 10 + 10 * this.state.range)
.map((note, _index) => { .map((note, _index) => {
const isActive = (index === _index) const isActive = (index === _index)

View File

@@ -19,18 +19,18 @@ class StorageSection extends React.Component {
} }
handleHeaderClick (e) { handleHeaderClick (e) {
let { storage } = this.props const { storage } = this.props
this.props.handleStorageButtonClick(e, storage.key) this.props.handleStorageButtonClick(e, storage.key)
} }
handleFolderClick (e, folder) { handleFolderClick (e, folder) {
let { storage } = this.props const { storage } = this.props
this.props.handleFolderButtonClick(e, storage.key, folder.key) this.props.handleFolderButtonClick(e, storage.key, folder.key)
} }
render () { render () {
let { storage, filter } = this.props const { storage, filter } = this.props
let folderList = storage.folders const folderList = storage.folders
.map(folder => ( .map(folder => (
<StorageItem <StorageItem
key={folder.key} key={folder.key}

View File

@@ -1,8 +1,8 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { connect, Provider } from 'react-redux' import { connect, Provider } from 'react-redux'
import _ from 'lodash' import _ from 'lodash'
import ipc from './ipcClient'
import store from './store' import store from './store'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './FinderMain.styl' import styles from './FinderMain.styl'
@@ -13,13 +13,14 @@ import SideNavFilter from 'browser/components/SideNavFilter'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
require('!!style!css!stylus?sourceMap!../main/global.styl') require('!!style!css!stylus?sourceMap!../main/global.styl')
require('../lib/customMeta') require('../lib/customMeta')
require('./ipcClient.js')
const electron = require('electron') const electron = require('electron')
const { remote } = electron const { remote } = electron
const { Menu } = remote const { Menu } = remote
function hideFinder () { function hideFinder () {
let finderWindow = remote.getCurrentWindow() const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'win32') { if (global.process.platform === 'win32') {
finderWindow.blur() finderWindow.blur()
finderWindow.hide() finderWindow.hide()
@@ -136,7 +137,7 @@ class FinderMain extends React.Component {
} }
handleOnlySnippetCheckboxChange (e) { handleOnlySnippetCheckboxChange (e) {
let { filter } = this.state const { filter } = this.state
filter.includeSnippet = e.target.checked filter.includeSnippet = e.target.checked
this.setState({ this.setState({
filter: filter, filter: filter,
@@ -147,7 +148,7 @@ class FinderMain extends React.Component {
} }
handleOnlyMarkdownCheckboxChange (e) { handleOnlyMarkdownCheckboxChange (e) {
let { filter } = this.state const { filter } = this.state
filter.includeMarkdown = e.target.checked filter.includeMarkdown = e.target.checked
this.refs.list.resetScroll() this.refs.list.resetScroll()
this.setState({ this.setState({
@@ -159,7 +160,7 @@ class FinderMain extends React.Component {
} }
handleAllNotesButtonClick (e) { handleAllNotesButtonClick (e) {
let { filter } = this.state const { filter } = this.state
filter.type = 'ALL' filter.type = 'ALL'
this.refs.list.resetScroll() this.refs.list.resetScroll()
this.setState({ this.setState({
@@ -171,7 +172,7 @@ class FinderMain extends React.Component {
} }
handleStarredButtonClick (e) { handleStarredButtonClick (e) {
let { filter } = this.state const { filter } = this.state
filter.type = 'STARRED' filter.type = 'STARRED'
this.refs.list.resetScroll() this.refs.list.resetScroll()
this.setState({ this.setState({
@@ -183,7 +184,7 @@ class FinderMain extends React.Component {
} }
handleStorageButtonClick (e, storage) { handleStorageButtonClick (e, storage) {
let { filter } = this.state const { filter } = this.state
filter.type = 'STORAGE' filter.type = 'STORAGE'
filter.storage = storage filter.storage = storage
this.refs.list.resetScroll() this.refs.list.resetScroll()
@@ -196,7 +197,7 @@ class FinderMain extends React.Component {
} }
handleFolderButtonClick (e, storage, folder) { handleFolderButtonClick (e, storage, folder) {
let { filter } = this.state const { filter } = this.state
filter.type = 'FOLDER' filter.type = 'FOLDER'
filter.storage = storage filter.storage = storage
filter.folder = folder filter.folder = folder
@@ -218,12 +219,12 @@ class FinderMain extends React.Component {
} }
render () { render () {
let { data, config } = this.props const { data, config } = this.props
let { filter, search } = this.state const { filter, search } = this.state
let storageList = [] const storageList = []
for (let key in data.storageMap) { for (const key in data.storageMap) {
let storage = data.storageMap[key] const storage = data.storageMap[key]
let item = ( const item = (
<StorageSection <StorageSection
filter={filter} filter={filter}
storage={storage} storage={storage}
@@ -252,7 +253,7 @@ class FinderMain extends React.Component {
notes.push(data.noteMap[id]) notes.push(data.noteMap[id])
}) })
} else { } else {
for (let key in data.noteMap) { for (const key in data.noteMap) {
notes.push(data.noteMap[key]) notes.push(data.noteMap[key])
} }
} }
@@ -264,13 +265,13 @@ class FinderMain extends React.Component {
} }
if (search.trim().length > 0) { if (search.trim().length > 0) {
let needle = new RegExp(_.escapeRegExp(search.trim()), 'i') const needle = new RegExp(_.escapeRegExp(search.trim()), 'i')
notes = notes.filter((note) => note.title.match(needle)) notes = notes.filter((note) => note.title.match(needle))
} }
notes = notes notes = notes
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt)) .sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
let activeNote = notes[this.state.index] const activeNote = notes[this.state.index]
this.noteCount = notes.length this.noteCount = notes.length
return ( return (

View File

@@ -10,7 +10,7 @@ nodeIpc.config.retry = 1500
nodeIpc.config.silent = true nodeIpc.config.silent = true
function killFinder () { function killFinder () {
let finderWindow = remote.getCurrentWindow() const finderWindow = remote.getCurrentWindow()
finderWindow.removeAllListeners() finderWindow.removeAllListeners()
if (global.process.platform === 'darwin') { if (global.process.platform === 'darwin') {
// Only OSX has another app process. // Only OSX has another app process.
@@ -21,7 +21,7 @@ function killFinder () {
} }
function toggleFinder () { function toggleFinder () {
let finderWindow = remote.getCurrentWindow() const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'darwin') { if (global.process.platform === 'darwin') {
if (finderWindow.isVisible()) { if (finderWindow.isVisible()) {
finderWindow.hide() finderWindow.hide()

View File

@@ -2,7 +2,7 @@ import { combineReducers, createStore } from 'redux'
import { routerReducer } from 'react-router-redux' import { routerReducer } from 'react-router-redux'
import { DEFAULT_CONFIG } from 'browser/main/lib/ConfigManager' import { DEFAULT_CONFIG } from 'browser/main/lib/ConfigManager'
let defaultData = { const defaultData = {
storageMap: {}, storageMap: {},
noteMap: {}, noteMap: {},
starredSet: [], starredSet: [],
@@ -40,12 +40,12 @@ function config (state = DEFAULT_CONFIG, action) {
return state return state
} }
let reducer = combineReducers({ const reducer = combineReducers({
data, data,
config, config,
routing: routerReducer routing: routerReducer
}) })
let store = createStore(reducer) const store = createStore(reducer)
export default store export default store

View File

@@ -38,15 +38,15 @@ class MutableMap {
} }
map (cb) { map (cb) {
let result = [] const result = []
for (let [key, value] of this._map) { for (const [key, value] of this._map) {
result.push(cb(value, key)) result.push(cb(value, key))
} }
return result return result
} }
toJS () { toJS () {
let result = {} const result = {}
for (let [key, value] of this._map) { for (let [key, value] of this._map) {
if (value instanceof MutableSet || value instanceof MutableMap) { if (value instanceof MutableSet || value instanceof MutableMap) {
value = value.toJS() value = value.toJS()
@@ -85,7 +85,7 @@ class MutableSet {
} }
map (cb) { map (cb) {
let result = [] const result = []
this._set.forEach(function (value, key) { this._set.forEach(function (value, key) {
result.push(cb(value, key)) result.push(cb(value, key))
}) })

View File

@@ -1,11 +1,11 @@
export function findNoteTitle (value) { export function findNoteTitle (value) {
let splitted = value.split('\n') const splitted = value.split('\n')
let title = null let title = null
let isInsideCodeBlock = false let isInsideCodeBlock = false
splitted.some((line, index) => { splitted.some((line, index) => {
let trimmedLine = line.trim() const trimmedLine = line.trim()
let trimmedNextLine = splitted[index + 1] === undefined ? '' : splitted[index + 1].trim() const trimmedNextLine = splitted[index + 1] === undefined ? '' : splitted[index + 1].trim()
if (trimmedLine.match('```')) { if (trimmedLine.match('```')) {
isInsideCodeBlock = !isInsideCodeBlock isInsideCodeBlock = !isInsideCodeBlock
} }

View File

@@ -1,10 +1,10 @@
export function getTodoStatus (content) { export function getTodoStatus (content) {
let splitted = content.split('\n') const splitted = content.split('\n')
let numberOfTodo = 0 let numberOfTodo = 0
let numberOfCompletedTodo = 0 let numberOfCompletedTodo = 0
splitted.forEach((line) => { splitted.forEach((line) => {
let trimmedLine = line.trim() const trimmedLine = line.trim()
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) { if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
numberOfTodo++ numberOfTodo++
} }

View File

@@ -7,8 +7,8 @@ import _ from 'lodash'
const katex = window.katex const katex = window.katex
function createGutter (str) { function createGutter (str) {
let lc = (str.match(/\n/g) || []).length const lc = (str.match(/\n/g) || []).length
let lines = [] const lines = []
for (let i = 1; i <= lc; i++) { for (let i = 1; i <= lc; i++) {
lines.push('<span class="CodeMirror-linenumber">' + i + '</span>') lines.push('<span class="CodeMirror-linenumber">' + i + '</span>')
} }
@@ -76,8 +76,8 @@ md.use(require('markdown-it-plantuml'))
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) { md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token let content, terminate, i, l, token
let nextLine = startLine + 1 let nextLine = startLine + 1
let terminatorRules = state.md.block.ruler.getRules('paragraph') const terminatorRules = state.md.block.ruler.getRules('paragraph')
let endLine = state.lineMax const endLine = state.lineMax
// jump line-by-line until empty one or EOF // jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
@@ -107,7 +107,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
token.map = [ startLine, state.line ] token.map = [ startLine, state.line ]
if (state.parentType === 'list') { if (state.parentType === 'list') {
let match = content.match(/^\[( |x)\] ?(.+)/i) const match = content.match(/^\[( |x)\] ?(.+)/i)
if (match) { if (match) {
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>` content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>`
} }
@@ -124,7 +124,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
}) })
// Add line number attribute for scrolling // Add line number attribute for scrolling
let originalRender = md.renderer.render const originalRender = md.renderer.render
md.renderer.render = function render (tokens, options, env) { md.renderer.render = function render (tokens, options, env) {
tokens.forEach((token) => { tokens.forEach((token) => {
switch (token.type) { switch (token.type) {
@@ -135,7 +135,7 @@ md.renderer.render = function render (tokens, options, env) {
token.attrPush(['data-line', token.map[0]]) token.attrPush(['data-line', token.map[0]])
} }
}) })
let result = originalRender.call(md.renderer, tokens, options, env) const result = originalRender.call(md.renderer, tokens, options, env)
return result return result
} }
// FIXME We should not depend on global variable. // FIXME We should not depend on global variable.

View File

@@ -16,7 +16,7 @@ export default function searchFromNotes (notes, search) {
function findByTag (notes, block) { function findByTag (notes, block) {
const tag = block.match(/#(.+)/)[1] const tag = block.match(/#(.+)/)[1]
let regExp = new RegExp(_.escapeRegExp(tag), 'i') const regExp = new RegExp(_.escapeRegExp(tag), 'i')
return notes.filter((note) => { return notes.filter((note) => {
if (!_.isArray(note.tags)) return false if (!_.isArray(note.tags)) return false
return note.tags.some((_tag) => { return note.tags.some((_tag) => {
@@ -26,7 +26,7 @@ function findByTag (notes, block) {
} }
function findByWord (notes, block) { function findByWord (notes, block) {
let regExp = new RegExp(_.escapeRegExp(block), 'i') const regExp = new RegExp(_.escapeRegExp(block), 'i')
return notes.filter((note) => { return notes.filter((note) => {
if (_.isArray(note.tags) && note.tags.some((_tag) => { if (_.isArray(note.tags) && note.tags.some((_tag) => {
return _tag.match(regExp) return _tag.match(regExp)

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './FolderSelect.styl' import styles from './FolderSelect.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -73,8 +74,8 @@ class FolderSelect extends React.Component {
case 9: case 9:
if (e.shiftKey) { if (e.shiftKey) {
e.preventDefault() e.preventDefault()
let tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])') const tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])')
let previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1] const previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1]
if (previousEl != null) previousEl.focus() if (previousEl != null) previousEl.focus()
} }
} }
@@ -89,9 +90,9 @@ class FolderSelect extends React.Component {
} }
handleSearchInputChange (e) { handleSearchInputChange (e) {
let { folders } = this.props const { folders } = this.props
let search = this.refs.search.value const search = this.refs.search.value
let optionIndex = search.length > 0 const optionIndex = search.length > 0
? _.findIndex(folders, (folder) => { ? _.findIndex(folders, (folder) => {
return folder.name.match(new RegExp('^' + _.escapeRegExp(search), 'i')) return folder.name.match(new RegExp('^' + _.escapeRegExp(search), 'i'))
}) })
@@ -129,7 +130,7 @@ class FolderSelect extends React.Component {
nextOption () { nextOption () {
let { optionIndex } = this.state let { optionIndex } = this.state
let { folders } = this.props const { folders } = this.props
optionIndex++ optionIndex++
if (optionIndex >= folders.length) optionIndex = 0 if (optionIndex >= folders.length) optionIndex = 0
@@ -140,7 +141,7 @@ class FolderSelect extends React.Component {
} }
previousOption () { previousOption () {
let { folders } = this.props const { folders } = this.props
let { optionIndex } = this.state let { optionIndex } = this.state
optionIndex-- optionIndex--
@@ -152,10 +153,10 @@ class FolderSelect extends React.Component {
} }
selectOption () { selectOption () {
let { folders } = this.props const { folders } = this.props
let optionIndex = this.state.optionIndex const optionIndex = this.state.optionIndex
let folder = folders[optionIndex] const folder = folders[optionIndex]
if (folder != null) { if (folder != null) {
this.setState({ this.setState({
status: 'FOCUS' status: 'FOCUS'
@@ -184,10 +185,10 @@ class FolderSelect extends React.Component {
} }
render () { render () {
let { className, data, value } = this.props const { className, data, value } = this.props
let splitted = value.split('-') const splitted = value.split('-')
let storageKey = splitted.shift() const storageKey = splitted.shift()
let folderKey = splitted.shift() const folderKey = splitted.shift()
let options = [] let options = []
data.storageMap.forEach((storage, index) => { data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => { storage.folders.forEach((folder) => {
@@ -198,14 +199,14 @@ class FolderSelect extends React.Component {
}) })
}) })
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0] const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
if (this.state.search.trim().length > 0) { if (this.state.search.trim().length > 0) {
let filter = new RegExp('^' + _.escapeRegExp(this.state.search), 'i') const filter = new RegExp('^' + _.escapeRegExp(this.state.search), 'i')
options = options.filter((option) => filter.test(option.folder.name)) options = options.filter((option) => filter.test(option.folder.name))
} }
let optionList = options const optionList = options
.map((option, index) => { .map((option, index) => {
return ( return (
<div styleName={index === this.state.optionIndex <div styleName={index === this.state.optionIndex

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoButton.styl' import styles from './InfoButton.styl'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './MarkdownNoteDetail.styl' import styles from './MarkdownNoteDetail.styl'
import MarkdownEditor from 'browser/components/MarkdownEditor' import MarkdownEditor from 'browser/components/MarkdownEditor'
@@ -25,7 +26,7 @@ import striptags from 'striptags'
const electron = require('electron') const electron = require('electron')
const { remote } = electron const { remote } = electron
const { Menu, MenuItem, dialog } = remote const { dialog } = remote
class MarkdownNoteDetail extends React.Component { class MarkdownNoteDetail extends React.Component {
constructor (props) { constructor (props) {
@@ -74,7 +75,7 @@ class MarkdownNoteDetail extends React.Component {
} }
handleChange (e) { handleChange (e) {
let { note } = this.state const { note } = this.state
note.content = this.refs.content.value note.content = this.refs.content.value
if (this.refs.tags) note.tags = this.refs.tags.value if (this.refs.tags) note.tags = this.refs.tags.value
@@ -96,7 +97,7 @@ class MarkdownNoteDetail extends React.Component {
} }
saveNow () { saveNow () {
let { note, dispatch } = this.props const { note, dispatch } = this.props
clearTimeout(this.saveQueue) clearTimeout(this.saveQueue)
this.saveQueue = null this.saveQueue = null
@@ -112,11 +113,11 @@ class MarkdownNoteDetail extends React.Component {
} }
handleFolderChange (e) { handleFolderChange (e) {
let { note } = this.state const { note } = this.state
let value = this.refs.folder.value const value = this.refs.folder.value
let splitted = value.split('-') const splitted = value.split('-')
let newStorageKey = splitted.shift() const newStorageKey = splitted.shift()
let newFolderKey = splitted.shift() const newFolderKey = splitted.shift()
dataApi dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey) .moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -125,7 +126,7 @@ class MarkdownNoteDetail extends React.Component {
isMovingNote: true, isMovingNote: true,
note: Object.assign({}, newNote) note: Object.assign({}, newNote)
}, () => { }, () => {
let { dispatch, location } = this.props const { dispatch, location } = this.props
dispatch({ dispatch({
type: 'MOVE_NOTE', type: 'MOVE_NOTE',
originNote: note, originNote: note,
@@ -145,7 +146,7 @@ class MarkdownNoteDetail extends React.Component {
} }
handleStarButtonClick (e) { handleStarButtonClick (e) {
let { note } = this.state const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR') if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred note.isStarred = !note.isStarred
@@ -170,22 +171,22 @@ class MarkdownNoteDetail extends React.Component {
} }
handleTrashButtonClick (e) { handleTrashButtonClick (e) {
let { note } = this.state const { note } = this.state
const { isTrashed } = note const { isTrashed } = note
if (isTrashed) { if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Confirm note deletion', message: 'Confirm note deletion',
detail: 'This will permanently remove this note.', detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel'] buttons: ['Confirm', 'Cancel']
}) })
if (dialogueButtonIndex === 1) return if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props const { note, dispatch } = this.props
dataApi dataApi
.deleteNote(note.storage, note.key) .deleteNote(note.storage, note.key)
.then((data) => { .then((data) => {
let dispatchHandler = () => { const dispatchHandler = () => {
dispatch({ dispatch({
type: 'DELETE_NOTE', type: 'DELETE_NOTE',
storageKey: data.storageKey, storageKey: data.storageKey,
@@ -207,7 +208,7 @@ class MarkdownNoteDetail extends React.Component {
} }
handleUndoButtonClick (e) { handleUndoButtonClick (e) {
let { note } = this.state const { note } = this.state
note.isTrashed = false note.isTrashed = false
@@ -262,12 +263,12 @@ class MarkdownNoteDetail extends React.Component {
} }
render () { render () {
let { data, config, location } = this.props const { data, config, location } = this.props
let { note } = this.state const { note } = this.state
let storageKey = note.storage const storageKey = note.storage
let folderKey = note.folder const folderKey = note.folder
let options = [] const options = []
data.storageMap.forEach((storage, index) => { data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => { storage.folders.forEach((folder) => {
options.push({ options.push({
@@ -276,7 +277,7 @@ class MarkdownNoteDetail extends React.Component {
}) })
}) })
}) })
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0] const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const trashTopBar = <div styleName='info'> const trashTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>

View File

@@ -30,8 +30,7 @@
right 0 right 0
top $info-height + $info-margin-under-border top $info-height + $info-margin-under-border
bottom $statusBar-height bottom $statusBar-height
max-width 600px margin 0 45px
margin 0 auto
.body-noteEditor .body-noteEditor
absolute top bottom left right absolute top bottom left right

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TrashButton.styl' import styles from './TrashButton.styl'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './SnippetNoteDetail.styl' import styles from './SnippetNoteDetail.styl'
import CodeEditor from 'browser/components/CodeEditor' import CodeEditor from 'browser/components/CodeEditor'
@@ -61,7 +62,7 @@ class SnippetNoteDetail extends React.Component {
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) { if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
if (this.saveQueue != null) this.saveNow() if (this.saveQueue != null) this.saveNow()
let nextNote = Object.assign({ const nextNote = Object.assign({
description: '' description: ''
}, nextProps.note, { }, nextProps.note, {
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet)) snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
@@ -70,7 +71,7 @@ class SnippetNoteDetail extends React.Component {
snippetIndex: 0, snippetIndex: 0,
note: nextNote note: nextNote
}, () => { }, () => {
let { snippets } = this.state.note const { snippets } = this.state.note
snippets.forEach((snippet, index) => { snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload() this.refs['code-' + index].reload()
}) })
@@ -84,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleChange (e) { handleChange (e) {
let { note } = this.state const { note } = this.state
if (this.refs.tags) note.tags = this.refs.tags.value if (this.refs.tags) note.tags = this.refs.tags.value
note.description = this.refs.description.value note.description = this.refs.description.value
@@ -106,7 +107,7 @@ class SnippetNoteDetail extends React.Component {
} }
saveNow () { saveNow () {
let { note, dispatch } = this.props const { note, dispatch } = this.props
clearTimeout(this.saveQueue) clearTimeout(this.saveQueue)
this.saveQueue = null this.saveQueue = null
@@ -122,11 +123,11 @@ class SnippetNoteDetail extends React.Component {
} }
handleFolderChange (e) { handleFolderChange (e) {
let { note } = this.state const { note } = this.state
let value = this.refs.folder.value const value = this.refs.folder.value
let splitted = value.split('-') const splitted = value.split('-')
let newStorageKey = splitted.shift() const newStorageKey = splitted.shift()
let newFolderKey = splitted.shift() const newFolderKey = splitted.shift()
dataApi dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey) .moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -135,7 +136,7 @@ class SnippetNoteDetail extends React.Component {
isMovingNote: true, isMovingNote: true,
note: Object.assign({}, newNote) note: Object.assign({}, newNote)
}, () => { }, () => {
let { dispatch, location } = this.props const { dispatch, location } = this.props
dispatch({ dispatch({
type: 'MOVE_NOTE', type: 'MOVE_NOTE',
originNote: note, originNote: note,
@@ -155,7 +156,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleStarButtonClick (e) { handleStarButtonClick (e) {
let { note } = this.state const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR') if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred note.isStarred = !note.isStarred
@@ -172,22 +173,22 @@ class SnippetNoteDetail extends React.Component {
} }
handleTrashButtonClick (e) { handleTrashButtonClick (e) {
let { note } = this.state const { note } = this.state
const { isTrashed } = note const { isTrashed } = note
if (isTrashed) { if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Confirm note deletion', message: 'Confirm note deletion',
detail: 'This will permanently remove this note.', detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel'] buttons: ['Confirm', 'Cancel']
}) })
if (dialogueButtonIndex === 1) return if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props const { note, dispatch } = this.props
dataApi dataApi
.deleteNote(note.storage, note.key) .deleteNote(note.storage, note.key)
.then((data) => { .then((data) => {
let dispatchHandler = () => { const dispatchHandler = () => {
dispatch({ dispatch({
type: 'DELETE_NOTE', type: 'DELETE_NOTE',
storageKey: data.storageKey, storageKey: data.storageKey,
@@ -209,7 +210,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleUndoButtonClick (e) { handleUndoButtonClick (e) {
let { note } = this.state const { note } = this.state
note.isTrashed = false note.isTrashed = false
@@ -238,7 +239,7 @@ class SnippetNoteDetail extends React.Component {
handleTabDeleteButtonClick (e, index) { handleTabDeleteButtonClick (e, index) {
if (this.state.note.snippets.length > 1) { if (this.state.note.snippets.length > 1) {
if (this.state.note.snippets[index].content.trim().length > 0) { if (this.state.note.snippets[index].content.trim().length > 0) {
let dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), { const dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Delete a snippet', message: 'Delete a snippet',
detail: 'This work cannot be undone.', detail: 'This work cannot be undone.',
@@ -288,7 +289,7 @@ class SnippetNoteDetail extends React.Component {
handleModeOptionClick (index, name) { handleModeOptionClick (index, name) {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() const snippets = this.state.note.snippets.slice()
snippets[index].mode = name snippets[index].mode = name
this.setState({note: Object.assign(this.state.note, {snippets: snippets})}) this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
@@ -306,7 +307,7 @@ class SnippetNoteDetail extends React.Component {
handleCodeChange (index) { handleCodeChange (index) {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() const snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value snippets[index].content = this.refs['code-' + index].value
this.setState({note: Object.assign(this.state.note, {snippets: snippets})}) this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({ this.setState({
@@ -333,7 +334,7 @@ class SnippetNoteDetail extends React.Component {
break break
case 76: case 76:
{ {
let isSuper = global.process.platform === 'darwin' const isSuper = global.process.platform === 'darwin'
? e.metaKey ? e.metaKey
: e.ctrlKey : e.ctrlKey
if (isSuper) { if (isSuper) {
@@ -344,7 +345,7 @@ class SnippetNoteDetail extends React.Component {
break break
case 84: case 84:
{ {
let isSuper = global.process.platform === 'darwin' const isSuper = global.process.platform === 'darwin'
? e.metaKey ? e.metaKey
: e.ctrlKey : e.ctrlKey
if (isSuper) { if (isSuper) {
@@ -357,7 +358,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleModeButtonClick (e, index) { handleModeButtonClick (e, index) {
let menu = new Menu() const menu = new Menu()
CodeMirror.modeInfo.forEach((mode) => { CodeMirror.modeInfo.forEach((mode) => {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: mode.name, label: mode.name,
@@ -398,8 +399,8 @@ class SnippetNoteDetail extends React.Component {
} }
handleIndentSizeItemClick (e, indentSize) { handleIndentSizeItemClick (e, indentSize) {
let { config, dispatch } = this.props const { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, { const editor = Object.assign({}, config.editor, {
indentSize indentSize
}) })
ConfigManager.set({ ConfigManager.set({
@@ -414,8 +415,8 @@ class SnippetNoteDetail extends React.Component {
} }
handleIndentTypeItemClick (e, indentType) { handleIndentTypeItemClick (e, indentType) {
let { config, dispatch } = this.props const { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, { const editor = Object.assign({}, config.editor, {
indentType indentType
}) })
ConfigManager.set({ ConfigManager.set({
@@ -434,14 +435,14 @@ class SnippetNoteDetail extends React.Component {
} }
addSnippet () { addSnippet () {
let { note } = this.state const { note } = this.state
note.snippets = note.snippets.concat([{ note.snippets = note.snippets.concat([{
name: '', name: '',
mode: 'Plain Text', mode: 'Plain Text',
content: '' content: ''
}]) }])
let snippetIndex = note.snippets.length - 1 const snippetIndex = note.snippets.length - 1
this.setState({ this.setState({
note, note,
@@ -487,19 +488,19 @@ class SnippetNoteDetail extends React.Component {
} }
render () { render () {
let { data, config, location } = this.props const { data, config, location } = this.props
let { note } = this.state const { note } = this.state
let storageKey = note.storage const storageKey = note.storage
let folderKey = note.folder const folderKey = note.folder
let editorFontSize = parseInt(config.editor.fontSize, 10) let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10) let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4 if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let tabList = note.snippets.map((snippet, index) => { const tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
return <SnippetTab return <SnippetTab
key={index} key={index}
@@ -513,8 +514,8 @@ class SnippetNoteDetail extends React.Component {
/> />
}) })
let viewList = note.snippets.map((snippet, index) => { const viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode)) let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
@@ -548,7 +549,7 @@ class SnippetNoteDetail extends React.Component {
</div> </div>
}) })
let options = [] const options = []
data.storageMap.forEach((storage, index) => { data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => { storage.folders.forEach((folder) => {
options.push({ options.push({
@@ -557,7 +558,7 @@ class SnippetNoteDetail extends React.Component {
}) })
}) })
}) })
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0] const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const trashTopBar = <div styleName='info'> const trashTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './StarButton.styl' import styles from './StarButton.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -31,7 +32,7 @@ class StarButton extends React.Component {
} }
render () { render () {
let { className } = this.props const { className } = this.props
return ( return (
<button className={_.isString(className) <button className={_.isString(className)

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TagSelect.styl' import styles from './TagSelect.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -37,6 +38,10 @@ class TagSelect extends React.Component {
} }
} }
handleNewTagBlur (e) {
this.submitTag()
}
removeLastTag () { removeLastTag () {
let { value } = this.props let { value } = this.props
@@ -59,7 +64,7 @@ class TagSelect extends React.Component {
submitTag () { submitTag () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
let { value } = this.props let { value } = this.props
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_') const newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
if (newTag.length <= 0) { if (newTag.length <= 0) {
this.setState({ this.setState({
@@ -101,9 +106,9 @@ class TagSelect extends React.Component {
} }
render () { render () {
let { value, className } = this.props const { value, className } = this.props
let tagList = _.isArray(value) const tagList = _.isArray(value)
? value.map((tag) => { ? value.map((tag) => {
return ( return (
<span styleName='tag' <span styleName='tag'
@@ -134,6 +139,7 @@ class TagSelect extends React.Component {
placeholder='Add tag...' placeholder='Add tag...'
onChange={(e) => this.handleNewTagInputChange(e)} onChange={(e) => this.handleNewTagInputChange(e)}
onKeyDown={(e) => this.handleNewTagInputKeyDown(e)} onKeyDown={(e) => this.handleNewTagInputKeyDown(e)}
onBlur={(e) => this.handleNewTagBlur(e)}
/> />
</div> </div>
) )

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TrashButton.styl' import styles from './TrashButton.styl'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './Detail.styl' import styles from './Detail.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -32,12 +33,12 @@ class Detail extends React.Component {
} }
render () { render () {
let { location, data, config } = this.props const { location, data, config } = this.props
let note = null let note = null
if (location.query.key != null) { if (location.query.key != null) {
let splitted = location.query.key.split('-') const splitted = location.query.key.split('-')
let storageKey = splitted.shift() const storageKey = splitted.shift()
let noteKey = splitted.shift() const noteKey = splitted.shift()
note = data.noteMap.get(storageKey + '-' + noteKey) note = data.noteMap.get(storageKey + '-' + noteKey)
} }

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './Main.styl' import styles from './Main.styl'
import { connect } from 'react-redux' import { connect } from 'react-redux'
@@ -23,7 +24,7 @@ class Main extends React.Component {
mobileAnalytics.initAwsMobileAnalytics() mobileAnalytics.initAwsMobileAnalytics()
} }
let { config } = props const { config } = props
this.state = { this.state = {
isRightSliderFocused: false, isRightSliderFocused: false,
@@ -39,7 +40,7 @@ class Main extends React.Component {
} }
getChildContext () { getChildContext () {
let { status, config } = this.props const { status, config } = this.props
return { return {
status, status,
@@ -48,7 +49,7 @@ class Main extends React.Component {
} }
componentDidMount () { componentDidMount () {
let { dispatch, config } = this.props const { dispatch, config } = this.props
if (config.ui.theme === 'dark') { if (config.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark') document.body.setAttribute('data-theme', 'dark')
@@ -99,8 +100,8 @@ class Main extends React.Component {
this.setState({ this.setState({
isRightSliderFocused: false isRightSliderFocused: false
}, () => { }, () => {
let { dispatch } = this.props const { dispatch } = this.props
let newListWidth = this.state.listWidth const newListWidth = this.state.listWidth
// TODO: ConfigManager should dispatch itself. // TODO: ConfigManager should dispatch itself.
ConfigManager.set({listWidth: newListWidth}) ConfigManager.set({listWidth: newListWidth})
dispatch({ dispatch({
@@ -115,8 +116,8 @@ class Main extends React.Component {
this.setState({ this.setState({
isLeftSliderFocused: false isLeftSliderFocused: false
}, () => { }, () => {
let { dispatch } = this.props const { dispatch } = this.props
let navWidth = this.state.navWidth const navWidth = this.state.navWidth
// TODO: ConfigManager should dispatch itself. // TODO: ConfigManager should dispatch itself.
ConfigManager.set({ navWidth }) ConfigManager.set({ navWidth })
dispatch({ dispatch({
@@ -129,7 +130,7 @@ class Main extends React.Component {
handleMouseMove (e) { handleMouseMove (e) {
if (this.state.isRightSliderFocused) { if (this.state.isRightSliderFocused) {
let offset = this.refs.body.getBoundingClientRect().left const offset = this.refs.body.getBoundingClientRect().left
let newListWidth = e.pageX - offset let newListWidth = e.pageX - offset
if (newListWidth < 10) { if (newListWidth < 10) {
newListWidth = 10 newListWidth = 10
@@ -182,7 +183,7 @@ class Main extends React.Component {
} }
render () { render () {
let { config } = this.props const { config } = this.props
// the width of the navigation bar when it is folded/collapsed // the width of the navigation bar when it is folded/collapsed
const foldedNavigationWidth = 44 const foldedNavigationWidth = 44

View File

@@ -1,12 +1,11 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './NewNoteButton.styl' import styles from './NewNoteButton.styl'
import _ from 'lodash' import _ from 'lodash'
import modal from 'browser/main/lib/modal' import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal' import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron') const { remote } = require('electron')
const { dialog } = remote const { dialog } = remote
@@ -34,7 +33,7 @@ class NewNoteButton extends React.Component {
} }
handleNewNoteButtonClick (e) { handleNewNoteButtonClick (e) {
const { config, location, dispatch } = this.props const { location, dispatch } = this.props
const { storage, folder } = this.resolveTargetFolder() const { storage, folder } = this.resolveTargetFolder()
modal.open(NewNoteModal, { modal.open(NewNoteModal, {
@@ -51,7 +50,7 @@ class NewNoteButton extends React.Component {
// Find first storage // Find first storage
if (storage == null) { if (storage == null) {
for (let kv of data.storageMap) { for (const kv of data.storageMap) {
storage = kv[1] storage = kv[1]
break break
} }

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './NoteList.styl' import styles from './NoteList.styl'
import moment from 'moment' import moment from 'moment'
@@ -13,8 +14,8 @@ import fs from 'fs'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
import markdown from 'browser/lib/markdown' import markdown from 'browser/lib/markdown'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import stripgtags from 'striptags'
import store from 'browser/main/store' import store from 'browser/main/store'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
const { remote } = require('electron') const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote const { Menu, MenuItem, dialog } = remote
@@ -31,6 +32,18 @@ function sortByUpdatedAt (a, b) {
return new Date(b.updatedAt) - new Date(a.updatedAt) return new Date(b.updatedAt) - new Date(a.updatedAt)
} }
function findNoteByKey (notes, noteKey) {
return notes.find((note) => `${note.storage}-${note.key}` === noteKey)
}
function findNotesByKeys (notes, noteKeys) {
return notes.filter((note) => noteKeys.includes(getNoteKey(note)))
}
function getNoteKey (note) {
return `${note.storage}-${note.key}`
}
class NoteList extends React.Component { class NoteList extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -50,8 +63,16 @@ class NoteList extends React.Component {
} }
this.importFromFileHandler = this.importFromFile.bind(this) this.importFromFileHandler = this.importFromFile.bind(this)
this.jumpNoteByHash = this.jumpNoteByHashHandler.bind(this) this.jumpNoteByHash = this.jumpNoteByHashHandler.bind(this)
this.handleNoteListKeyUp = this.handleNoteListKeyUp.bind(this)
this.getNoteKeyFromTargetIndex = this.getNoteKeyFromTargetIndex.bind(this)
this.deleteNote = this.deleteNote.bind(this)
this.focusNote = this.focusNote.bind(this)
this.pinToTop = this.pinToTop.bind(this)
// TODO: not Selected noteKeys but SelectedNote(for reusing)
this.state = { this.state = {
shiftKeyDown: false,
selectedNoteKeys: []
} }
this.contextNotes = [] this.contextNotes = []
@@ -89,10 +110,10 @@ class NoteList extends React.Component {
} }
componentDidUpdate (prevProps) { componentDidUpdate (prevProps) {
let { location } = this.props const { location } = this.props
if (this.notes.length > 0 && location.query.key == null) { if (this.notes.length > 0 && location.query.key == null) {
let { router } = this.context const { router } = this.context
if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes() if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes()
router.replace({ router.replace({
pathname: location.pathname, pathname: location.pathname,
@@ -107,16 +128,16 @@ class NoteList extends React.Component {
if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) { if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) {
const targetIndex = this.getTargetIndex() const targetIndex = this.getTargetIndex()
if (targetIndex > -1) { if (targetIndex > -1) {
let list = this.refs.list const list = this.refs.list
let item = list.childNodes[targetIndex] const item = list.childNodes[targetIndex]
if (item == null) return false if (item == null) return false
let overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0 const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
if (overflowBelow) { if (overflowBelow) {
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
} }
let overflowAbove = list.scrollTop > item.offsetTop const overflowAbove = list.scrollTop > item.offsetTop
if (overflowAbove) { if (overflowAbove) {
list.scrollTop = item.offsetTop list.scrollTop = item.offsetTop
} }
@@ -124,12 +145,35 @@ class NoteList extends React.Component {
} }
} }
focusNote (selectedNoteKeys, noteKey) {
const { router } = this.context
const { location } = this.props
this.setState({
selectedNoteKeys
})
router.push({
pathname: location.pathname,
query: {
key: noteKey
}
})
}
getNoteKeyFromTargetIndex (targetIndex) {
const note = Object.assign({}, this.notes[targetIndex])
const noteKey = getNoteKey(note)
return noteKey
}
selectPriorNote () { selectPriorNote () {
if (this.notes == null || this.notes.length === 0) { if (this.notes == null || this.notes.length === 0) {
return return
} }
let { router } = this.context let { router } = this.context
let { location } = this.props let { location } = this.props
let { selectedNoteKeys, shiftKeyDown } = this.state
let targetIndex = this.getTargetIndex() let targetIndex = this.getTargetIndex()
@@ -137,14 +181,18 @@ class NoteList extends React.Component {
return return
} }
targetIndex-- targetIndex--
if (targetIndex < 0) targetIndex = 0
router.push({ if (!shiftKeyDown) { selectedNoteKeys = [] }
pathname: location.pathname, const priorNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
query: { if (selectedNoteKeys.includes(priorNoteKey)) {
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key selectedNoteKeys.pop()
} } else {
}) selectedNoteKeys.push(priorNoteKey)
}
this.focusNote(selectedNoteKeys, priorNoteKey)
ee.emit('list:moved')
} }
selectNextNote () { selectNextNote () {
@@ -153,23 +201,31 @@ class NoteList extends React.Component {
} }
let { router } = this.context let { router } = this.context
let { location } = this.props let { location } = this.props
let { selectedNoteKeys, shiftKeyDown } = this.state
let targetIndex = this.getTargetIndex() let targetIndex = this.getTargetIndex()
const isTargetLastNote = targetIndex === this.notes.length - 1
if (targetIndex === this.notes.length - 1) { if (isTargetLastNote && shiftKeyDown) {
return
} else if (isTargetLastNote) {
targetIndex = 0 targetIndex = 0
} else { } else {
targetIndex++ targetIndex++
if (targetIndex < 0) targetIndex = 0 if (targetIndex < 0) targetIndex = 0
else if (targetIndex > this.notes.length - 1) targetIndex === this.notes.length - 1 else if (targetIndex > this.notes.length - 1) targetIndex = this.notes.length - 1
} }
router.push({ if (!shiftKeyDown) { selectedNoteKeys = [] }
pathname: location.pathname, const nextNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
query: { if (selectedNoteKeys.includes(nextNoteKey)) {
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key selectedNoteKeys.pop()
} } else {
}) selectedNoteKeys.push(nextNoteKey)
}
this.focusNote(selectedNoteKeys, nextNoteKey)
ee.emit('list:moved') ee.emit('list:moved')
} }
@@ -186,17 +242,17 @@ class NoteList extends React.Component {
if (targetIndex < 0) targetIndex = 0 if (targetIndex < 0) targetIndex = 0
router.push({ const selectedNoteKeys = []
pathname: location.pathname, const nextNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
query: { selectedNoteKeys.push(nextNoteKey)
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
} this.focusNote(selectedNoteKeys, nextNoteKey)
})
ee.emit('list:moved') ee.emit('list:moved')
} }
handleNoteListKeyDown (e) { handleNoteListKeyDown (e) {
const { shiftKeyDown } = this.state
if (e.metaKey || e.ctrlKey) return true if (e.metaKey || e.ctrlKey) return true
if (e.keyCode === 65 && !e.shiftKey) { if (e.keyCode === 65 && !e.shiftKey) {
@@ -206,7 +262,7 @@ class NoteList extends React.Component {
if (e.keyCode === 68) { if (e.keyCode === 68) {
e.preventDefault() e.preventDefault()
ee.emit('detail:delete') this.deleteNote()
} }
if (e.keyCode === 69) { if (e.keyCode === 69) {
@@ -223,11 +279,20 @@ class NoteList extends React.Component {
e.preventDefault() e.preventDefault()
this.selectNextNote() this.selectNextNote()
} }
if (e.shiftKey) {
this.setState({ shiftKeyDown: true })
}
}
handleNoteListKeyUp (e) {
if (!e.shiftKey) {
this.setState({ shiftKeyDown: false })
}
} }
getNotes () { getNotes () {
let { data, params, location } = this.props const { data, params, location } = this.props
let { router } = this.context
if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) { if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) {
const allNotes = data.noteMap.map((note) => note) const allNotes = data.noteMap.map((note) => note)
@@ -302,6 +367,22 @@ class NoteList extends React.Component {
handleNoteClick (e, uniqueKey) { handleNoteClick (e, uniqueKey) {
let { router } = this.context let { router } = this.context
let { location } = this.props let { location } = this.props
let { shiftKeyDown, selectedNoteKeys } = this.state
if (shiftKeyDown && selectedNoteKeys.includes(uniqueKey)) {
const newSelectedNoteKeys = selectedNoteKeys.filter((noteKey) => noteKey !== uniqueKey)
this.setState({
selectedNoteKeys: newSelectedNoteKeys
})
return
}
if (!shiftKeyDown) {
selectedNoteKeys = []
}
selectedNoteKeys.push(uniqueKey)
this.setState({
selectedNoteKeys
})
router.push({ router.push({
pathname: location.pathname, pathname: location.pathname,
@@ -312,9 +393,9 @@ class NoteList extends React.Component {
} }
handleSortByChange (e) { handleSortByChange (e) {
let { dispatch } = this.props const { dispatch } = this.props
let config = { const config = {
sortBy: e.target.value sortBy: e.target.value
} }
@@ -326,9 +407,9 @@ class NoteList extends React.Component {
} }
handleListStyleButtonClick (e, style) { handleListStyleButtonClick (e, style) {
let { dispatch } = this.props const { dispatch } = this.props
let config = { const config = {
listStyle: style listStyle: style
} }
@@ -352,16 +433,23 @@ class NoteList extends React.Component {
} }
handleDragStart (e, note) { handleDragStart (e, note) {
const noteData = JSON.stringify(note) const { selectedNoteKeys } = this.state
const notes = this.notes.map((note) => Object.assign({}, note))
const selectedNotes = findNotesByKeys(notes, selectedNoteKeys)
const noteData = JSON.stringify(selectedNotes)
e.dataTransfer.setData('note', noteData) e.dataTransfer.setData('note', noteData)
this.setState({ selectedNoteKeys: [] })
} }
handleNoteContextMenu (e, uniqueKey) { handleNoteContextMenu (e, uniqueKey) {
const { location } = this.props const { location } = this.props
const note = this.notes.find((note) => { const { selectedNoteKeys } = this.state
const noteKey = `${note.storage}-${note.key}` const note = findNoteByKey(this.notes, uniqueKey)
return noteKey === uniqueKey const noteKey = getNoteKey(note)
})
if (selectedNoteKeys.length === 0 || !selectedNoteKeys.includes(noteKey)) {
this.handleNoteClick(e, uniqueKey)
}
const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top' const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top'
const deleteLabel = 'Delete Note' const deleteLabel = 'Delete Note'
@@ -370,47 +458,104 @@ class NoteList extends React.Component {
if (!location.pathname.match(/\/home|\/starred|\/trash/)) { if (!location.pathname.match(/\/home|\/starred|\/trash/)) {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: pinLabel, label: pinLabel,
click: (e) => this.pinToTop(e, uniqueKey) click: this.pinToTop
})) }))
} }
menu.append(new MenuItem({ menu.append(new MenuItem({
label: deleteLabel, label: deleteLabel,
click: (e) => this.deleteNote(e, uniqueKey) click: this.deleteNote
})) }))
menu.popup() menu.popup()
} }
pinToTop (e, uniqueKey) { pinToTop () {
const { data, params } = this.props const { selectedNoteKeys } = this.state
const storageKey = params.storageKey const { dispatch } = this.props
const folderKey = params.folderKey const notes = this.notes.map((note) => Object.assign({}, note))
const selectedNotes = findNotesByKeys(notes, selectedNoteKeys)
const currentStorage = data.storageMap.get(storageKey) Promise.all(
const currentFolder = _.find(currentStorage.folders, {key: folderKey}) selectedNotes.map((note) => {
note.isPinned = !note.isPinned
this.handleNoteClick(e, uniqueKey) return dataApi
const targetIndex = this.getTargetIndex() .updateNote(note.storage, note.key, note)
let note = this.notes[targetIndex] })
note.isPinned = !note.isPinned )
.then((updatedNotes) => {
dataApi updatedNotes.forEach((note) => {
.updateNote(note.storage, note.key, note) dispatch({
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE', type: 'UPDATE_NOTE',
note: note note
}) })
}) })
})
this.setState({ selectedNoteKeys: [] })
} }
deleteNote (e, uniqueKey) { deleteNote () {
this.handleNoteClick(e, uniqueKey) const { dispatch } = this.props
ee.emit('detail:delete') const { selectedNoteKeys } = this.state
const notes = this.notes.map((note) => Object.assign({}, note))
const selectedNotes = findNotesByKeys(notes, selectedNoteKeys)
const firstNote = selectedNotes[0]
if (firstNote.isTrashed) {
const noteExp = selectedNotes.length > 1 ? 'notes' : 'note'
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: `This will permanently remove ${selectedNotes.length} ${noteExp}.`,
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
Promise.all(
selectedNoteKeys.map((uniqueKey) => {
const storageKey = uniqueKey.split('-')[0]
const noteKey = uniqueKey.split('-')[1]
return dataApi
.deleteNote(storageKey, noteKey)
})
)
.then((data) => {
data.forEach((item) => {
dispatch({
type: 'DELETE_NOTE',
storageKey: item.storageKey,
noteKey: item.noteKey
})
})
})
.catch((err) => {
console.error('Cannot Delete note: ' + err)
})
console.log('Notes were all deleted')
} else {
Promise.all(
selectedNotes.map((note) => {
note.isTrashed = true
return dataApi
.updateNote(note.storage, note.key, note)
})
)
.then((newNotes) => {
newNotes.forEach((newNote) => {
dispatch({
type: 'UPDATE_NOTE',
note: newNote
})
})
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
console.log('Notes went to trash')
})
.catch((err) => {
console.error('Notes could not go to trash: ' + err)
})
}
this.setState({ selectedNoteKeys: [] })
} }
importFromFile () { importFromFile () {
const { dispatch, location } = this.props
const options = { const options = {
filters: [ filters: [
{ name: 'Documents', extensions: ['md', 'txt'] } { name: 'Documents', extensions: ['md', 'txt'] }
@@ -454,7 +599,7 @@ class NoteList extends React.Component {
}) })
hashHistory.push({ hashHistory.push({
pathname: location.pathname, pathname: location.pathname,
query: {key: `${note.storage}-${note.key}`} query: {key: getNoteKey(note)}
}) })
}) })
}) })
@@ -464,7 +609,7 @@ class NoteList extends React.Component {
getTargetIndex () { getTargetIndex () {
const { location } = this.props const { location } = this.props
const targetIndex = _.findIndex(this.notes, (note) => { const targetIndex = _.findIndex(this.notes, (note) => {
return `${note.storage}-${note.key}` === location.query.key return getNoteKey(note) === location.query.key
}) })
return targetIndex return targetIndex
} }
@@ -475,7 +620,7 @@ class NoteList extends React.Component {
// Find first storage // Find first storage
if (storage == null) { if (storage == null) {
for (let kv of data.storageMap) { for (const kv of data.storageMap) {
storage = kv[1] storage = kv[1]
break break
} }
@@ -501,6 +646,7 @@ class NoteList extends React.Component {
render () { render () {
let { location, notes, config, dispatch } = this.props let { location, notes, config, dispatch } = this.props
let { selectedNoteKeys } = this.state
let sortFunc = config.sortBy === 'CREATED_AT' let sortFunc = config.sortBy === 'CREATED_AT'
? sortByCreatedAt ? sortByCreatedAt
: config.sortBy === 'ALPHABETICAL' : config.sortBy === 'ALPHABETICAL'
@@ -533,14 +679,15 @@ class NoteList extends React.Component {
} }
}) })
let noteList = notes const noteList = notes
.map(note => { .map(note => {
if (note == null) { if (note == null) {
return null return null
} }
const isDefault = config.listStyle === 'DEFAULT' const isDefault = config.listStyle === 'DEFAULT'
const isActive = location.query.key === note.storage + '-' + note.key const uniqueKey = getNoteKey(note)
const isActive = selectedNoteKeys.includes(uniqueKey)
const dateDisplay = moment( const dateDisplay = moment(
config.sortBy === 'CREATED_AT' config.sortBy === 'CREATED_AT'
? note.createdAt : note.updatedAt ? note.createdAt : note.updatedAt
@@ -553,7 +700,7 @@ class NoteList extends React.Component {
isActive={isActive} isActive={isActive}
note={note} note={note}
dateDisplay={dateDisplay} dateDisplay={dateDisplay}
key={key} key={uniqueKey}
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)} handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleNoteClick={this.handleNoteClick.bind(this)} handleNoteClick={this.handleNoteClick.bind(this)}
handleDragStart={this.handleDragStart.bind(this)} handleDragStart={this.handleDragStart.bind(this)}
@@ -566,7 +713,7 @@ class NoteList extends React.Component {
<NoteItemSimple <NoteItemSimple
isActive={isActive} isActive={isActive}
note={note} note={note}
key={key} key={uniqueKey}
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)} handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleNoteClick={this.handleNoteClick.bind(this)} handleNoteClick={this.handleNoteClick.bind(this)}
handleDragStart={this.handleDragStart.bind(this)} handleDragStart={this.handleDragStart.bind(this)}
@@ -615,6 +762,7 @@ class NoteList extends React.Component {
ref='list' ref='list'
tabIndex='-1' tabIndex='-1'
onKeyDown={(e) => this.handleNoteListKeyDown(e)} onKeyDown={(e) => this.handleNoteListKeyDown(e)}
onKeyUp={this.handleNoteListKeyUp}
> >
{noteList} {noteList}
</div> </div>

View File

@@ -102,7 +102,7 @@
font-size 13px font-size 13px
.top-menu-preference .top-menu-preference
position absolute position absolute
left 11px left 7px
body[data-theme="white"] body[data-theme="white"]
.root, .root--folded .root, .root--folded

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageItem.styl' import styles from './StorageItem.styl'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
@@ -8,6 +9,7 @@ import RenameFolderModal from 'browser/main/modals/RenameFolderModal'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
import StorageItemChild from 'browser/components/StorageItem' import StorageItemChild from 'browser/components/StorageItem'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import _ from 'lodash'
const { remote } = require('electron') const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote const { Menu, MenuItem, dialog } = remote
@@ -22,7 +24,7 @@ class StorageItem extends React.Component {
} }
handleHeaderContextMenu (e) { handleHeaderContextMenu (e) {
let menu = new Menu() const menu = new Menu()
menu.append(new MenuItem({ menu.append(new MenuItem({
label: 'Add Folder', label: 'Add Folder',
click: (e) => this.handleAddFolderButtonClick(e) click: (e) => this.handleAddFolderButtonClick(e)
@@ -38,7 +40,7 @@ class StorageItem extends React.Component {
} }
handleUnlinkStorageClick (e) { handleUnlinkStorageClick (e) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Unlink Storage', message: 'Unlink Storage',
detail: 'This work will just detatches a storage from Boostnote. (Any data won\'t be deleted.)', detail: 'This work will just detatches a storage from Boostnote. (Any data won\'t be deleted.)',
@@ -46,7 +48,7 @@ class StorageItem extends React.Component {
}) })
if (index === 0) { if (index === 0) {
let { storage, dispatch } = this.props const { storage, dispatch } = this.props
dataApi.removeStorage(storage.key) dataApi.removeStorage(storage.key)
.then(() => { .then(() => {
dispatch({ dispatch({
@@ -67,7 +69,7 @@ class StorageItem extends React.Component {
} }
handleAddFolderButtonClick (e) { handleAddFolderButtonClick (e) {
let { storage } = this.props const { storage } = this.props
modal.open(CreateFolderModal, { modal.open(CreateFolderModal, {
storage storage
@@ -75,19 +77,19 @@ class StorageItem extends React.Component {
} }
handleHeaderInfoClick (e) { handleHeaderInfoClick (e) {
let { storage } = this.props const { storage } = this.props
hashHistory.push('/storages/' + storage.key) hashHistory.push('/storages/' + storage.key)
} }
handleFolderButtonClick (folderKey) { handleFolderButtonClick (folderKey) {
return (e) => { return (e) => {
let { storage } = this.props const { storage } = this.props
hashHistory.push('/storages/' + storage.key + '/folders/' + folderKey) hashHistory.push('/storages/' + storage.key + '/folders/' + folderKey)
} }
} }
handleFolderButtonContextMenu (e, folder) { handleFolderButtonContextMenu (e, folder) {
let menu = new Menu() const menu = new Menu()
menu.append(new MenuItem({ menu.append(new MenuItem({
label: 'Rename Folder', label: 'Rename Folder',
click: (e) => this.handleRenameFolderClick(e, folder) click: (e) => this.handleRenameFolderClick(e, folder)
@@ -103,7 +105,7 @@ class StorageItem extends React.Component {
} }
handleRenameFolderClick (e, folder) { handleRenameFolderClick (e, folder) {
let { storage } = this.props const { storage } = this.props
modal.open(RenameFolderModal, { modal.open(RenameFolderModal, {
storage, storage,
folder folder
@@ -111,7 +113,7 @@ class StorageItem extends React.Component {
} }
handleFolderDeleteClick (e, folder) { handleFolderDeleteClick (e, folder) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Delete Folder', message: 'Delete Folder',
detail: 'This will delete all notes in the folder and can not be undone.', detail: 'This will delete all notes in the folder and can not be undone.',
@@ -119,7 +121,7 @@ class StorageItem extends React.Component {
}) })
if (index === 0) { if (index === 0) {
let { storage, dispatch } = this.props const { storage, dispatch } = this.props
dataApi dataApi
.deleteFolder(storage.key, folder.key) .deleteFolder(storage.key, folder.key)
.then((data) => { .then((data) => {
@@ -142,48 +144,57 @@ class StorageItem extends React.Component {
e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor')
} }
dropNote (storage, folder, dispatch, location, noteData) {
noteData = noteData.filter((note) => folder.key !== note.folder)
if (noteData.length === 0) return
const newNoteData = noteData.map((note) => Object.assign({}, note, {storage: storage, folder: folder.key}))
Promise.all(
newNoteData.map((note) => dataApi.createNote(storage.key, note))
)
.then((createdNoteData) => {
createdNoteData.forEach((note) => {
dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
})
.catch((err) => {
console.error(`error on create notes: ${err}`)
})
.then(() => {
return Promise.all(
noteData.map((note) => dataApi.deleteNote(note.storage, note.key))
)
})
.then((deletedNoteData) => {
deletedNoteData.forEach((note) => {
dispatch({
type: 'DELETE_NOTE',
storageKey: note.storageKey,
noteKey: note.noteKey
})
})
})
.catch((err) => {
console.error(`error on delete notes: ${err}`)
})
}
handleDrop (e, storage, folder, dispatch, location) { handleDrop (e, storage, folder, dispatch, location) {
e.target.style.opacity = '1' e.target.style.opacity = '1'
e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor') e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor')
const noteData = JSON.parse(e.dataTransfer.getData('note')) const noteData = JSON.parse(e.dataTransfer.getData('note'))
const newNoteData = Object.assign({}, noteData, {storage: storage, folder: folder.key}) this.dropNote(storage, folder, dispatch, location, noteData)
if (folder.key === noteData.folder) return
dataApi
.createNote(storage.key, newNoteData)
.then((note) => {
dataApi
.deleteNote(noteData.storage, noteData.key)
.then((data) => {
let dispatchHandler = () => {
dispatch({
type: 'DELETE_NOTE',
storageKey: data.storageKey,
noteKey: data.noteKey
})
}
eventEmitter.once('list:moved', dispatchHandler)
eventEmitter.emit('list:next')
})
.catch((err) => {
console.error(err)
})
dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: `${note.storage}-${note.key}`}
})
})
} }
render () { render () {
let { storage, location, isFolded, data, dispatch } = this.props const { storage, location, isFolded, data, dispatch } = this.props
let { folderNoteMap, trashedSet } = data const { folderNoteMap, trashedSet } = data
let folderList = storage.folders.map((folder) => { const folderList = storage.folders.map((folder) => {
let isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key))) const isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
let noteSet = folderNoteMap.get(storage.key + '-' + folder.key) const noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
let noteCount = 0 let noteCount = 0
if (noteSet) { if (noteSet) {
@@ -211,7 +222,7 @@ class StorageItem extends React.Component {
) )
}) })
let isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$')) const isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$'))
return ( return (
<div styleName={isFolded ? 'root--folded' : 'root'} <div styleName={isFolded ? 'root--folded' : 'root'}
@@ -227,8 +238,8 @@ class StorageItem extends React.Component {
onMouseDown={(e) => this.handleToggleButtonClick(e)} onMouseDown={(e) => this.handleToggleButtonClick(e)}
> >
<img src={this.state.isOpen <img src={this.state.isOpen
? '../resources/icon/icon-down.svg' ? '../resources/icon/icon-down.svg'
: '../resources/icon/icon-right.svg' : '../resources/icon/icon-right.svg'
} }
/> />
</button> </button>
@@ -245,7 +256,7 @@ class StorageItem extends React.Component {
onClick={(e) => this.handleHeaderInfoClick(e)} onClick={(e) => this.handleHeaderInfoClick(e)}
> >
<span styleName='header-info-name'> <span styleName='header-info-name'>
{isFolded ? storage.name.substring(0, 1) : storage.name} {isFolded ? _.truncate(storage.name, {length: 1, omission: ''}) : storage.name}
</span> </span>
{isFolded && {isFolded &&
<span styleName='header-info--folded-tooltip'> <span styleName='header-info--folded-tooltip'>

View File

@@ -80,6 +80,7 @@
@extend .root @extend .root
.header .header
width 100% width 100%
padding-left 5px
.header-info .header-info
overflow ellipsis overflow ellipsis
padding 0 0 0 18px padding 0 0 0 18px
@@ -89,6 +90,7 @@
display none display none
.header-toggleButton .header-toggleButton
width 15px width 15px
padding-left 9px
.header-info--folded-tooltip .header-info--folded-tooltip
tooltip() tooltip()
position fixed position fixed

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './SideNav.styl' import styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal' import { openModal } from 'browser/main/lib/modal'
@@ -27,17 +28,17 @@ class SideNav extends React.Component {
} }
handleHomeButtonClick (e) { handleHomeButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/home') router.push('/home')
} }
handleStarredButtonClick (e) { handleStarredButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/starred') router.push('/starred')
} }
handleToggleButtonClick (e) { handleToggleButtonClick (e) {
let { dispatch, config } = this.props const { dispatch, config } = this.props
ConfigManager.set({isSideNavFolded: !config.isSideNavFolded}) ConfigManager.set({isSideNavFolded: !config.isSideNavFolded})
dispatch({ dispatch({
@@ -47,7 +48,7 @@ class SideNav extends React.Component {
} }
handleTrashedButtonClick (e) { handleTrashedButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/trashed') router.push('/trashed')
} }
@@ -62,7 +63,7 @@ class SideNav extends React.Component {
} }
SideNavComponent (isFolded, storageList) { SideNavComponent (isFolded, storageList) {
let { location, data } = this.props const { location, data } = this.props
const isHomeActive = !!location.pathname.match(/^\/home$/) const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/) const isStarredActive = !!location.pathname.match(/^\/starred$/)
@@ -109,7 +110,7 @@ class SideNav extends React.Component {
tagListComponent () { tagListComponent () {
const { data, location } = this.props const { data, location } = this.props
let tagList = data.tagNoteMap.map((tag, key) => { const tagList = data.tagNoteMap.map((tag, key) => {
return key return key
}) })
return ( return (
@@ -136,11 +137,11 @@ class SideNav extends React.Component {
} }
render () { render () {
let { data, location, config, dispatch } = this.props const { data, location, config, dispatch } = this.props
let isFolded = config.isSideNavFolded const isFolded = config.isSideNavFolded
let storageList = data.storageMap.map((storage, key) => { const storageList = data.storageMap.map((storage, key) => {
return <StorageItem return <StorageItem
key={storage.key} key={storage.key}
storage={storage} storage={storage}
@@ -150,7 +151,7 @@ class SideNav extends React.Component {
dispatch={dispatch} dispatch={dispatch}
/> />
}) })
let style = {} const style = {}
if (!isFolded) style.width = this.props.width if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/) const isTagActive = location.pathname.match(/tag/)
return ( return (

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './StatusBar.styl' import styles from './StatusBar.styl'
import ZoomManager from 'browser/main/lib/ZoomManager' import ZoomManager from 'browser/main/lib/ZoomManager'
@@ -11,7 +12,7 @@ const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2
class StatusBar extends React.Component { class StatusBar extends React.Component {
updateApp () { updateApp () {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Update Boostnote', message: 'Update Boostnote',
detail: 'New Boostnote is ready to be installed.', detail: 'New Boostnote is ready to be installed.',
@@ -24,7 +25,7 @@ class StatusBar extends React.Component {
} }
handleZoomButtonClick (e) { handleZoomButtonClick (e) {
let menu = new Menu() const menu = new Menu()
zoomOptions.forEach((zoom) => { zoomOptions.forEach((zoom) => {
menu.append(new MenuItem({ menu.append(new MenuItem({
@@ -37,7 +38,7 @@ class StatusBar extends React.Component {
} }
handleZoomMenuItemClick (zoomFactor) { handleZoomMenuItemClick (zoomFactor) {
let { dispatch } = this.props const { dispatch } = this.props
ZoomManager.setZoom(zoomFactor) ZoomManager.setZoom(zoomFactor)
dispatch({ dispatch({
type: 'SET_ZOOM', type: 'SET_ZOOM',
@@ -46,7 +47,7 @@ class StatusBar extends React.Component {
} }
render () { render () {
let { config, status } = this.context const { config, status } = this.context
return ( return (
<div className='StatusBar' <div className='StatusBar'

View File

@@ -1,16 +1,11 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TopBar.styl' import styles from './TopBar.styl'
import _ from 'lodash' import _ from 'lodash'
import NewNoteModal from 'browser/main/modals/NewNoteModal'
import ee from 'browser/main/lib/eventEmitter' import ee from 'browser/main/lib/eventEmitter'
import NewNoteButton from 'browser/main/NewNoteButton' import NewNoteButton from 'browser/main/NewNoteButton'
const { remote } = require('electron')
const { dialog } = remote
const OSX = window.process.platform === 'darwin'
class TopBar extends React.Component { class TopBar extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -121,7 +116,7 @@ class TopBar extends React.Component {
} }
render () { render () {
let { config, style, data, location } = this.props const { config, style, location } = this.props
return ( return (
<div className='TopBar' <div className='TopBar'
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'} styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}

View File

@@ -36,7 +36,7 @@ document.addEventListener('click', function (e) {
if (infoPanel) infoPanel.style.display = 'none' if (infoPanel) infoPanel.style.display = 'none'
}) })
let el = document.getElementById('content') const el = document.getElementById('content')
const history = syncHistoryWithStore(hashHistory, store) const history = syncHistoryWithStore(hashHistory, store)
function notify (...args) { function notify (...args) {
@@ -44,7 +44,7 @@ function notify (...args) {
} }
function updateApp () { function updateApp () {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Update Boostnote', message: 'Update Boostnote',
detail: 'New Boostnote is ready to be installed.', detail: 'New Boostnote is ready to be installed.',
@@ -81,7 +81,7 @@ ReactDOM.render((
</Router> </Router>
</Provider> </Provider>
), el, function () { ), el, function () {
let loadingCover = document.getElementById('loadingCover') const loadingCover = document.getElementById('loadingCover')
loadingCover.parentNode.removeChild(loadingCover) loadingCover.parentNode.removeChild(loadingCover)
ipcRenderer.on('update-ready', function () { ipcRenderer.on('update-ready', function () {

View File

@@ -4,6 +4,7 @@ const ConfigManager = require('browser/main/lib/ConfigManager')
const remote = require('electron').remote const remote = require('electron').remote
const os = require('os') const os = require('os')
let mobileAnalyticsClient
AWS.config.region = 'us-east-1' AWS.config.region = 'us-east-1'
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) { if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
@@ -13,7 +14,7 @@ if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnab
const validPlatformName = convertPlatformName(os.platform()) const validPlatformName = convertPlatformName(os.platform())
const mobileAnalyticsClient = new AMA.Manager({ mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx', appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appTitle: 'xxxxxxxxxx', appTitle: 'xxxxxxxxxx',
appVersionName: remote.app.getVersion().toString(), appVersionName: remote.app.getVersion().toString(),

View File

@@ -13,10 +13,10 @@ function release (el) {
function fire (command) { function fire (command) {
console.info('COMMAND >>', command) console.info('COMMAND >>', command)
let splitted = command.split(':') const splitted = command.split(':')
let target = splitted[0] const target = splitted[0]
let targetCommand = splitted[1] const targetCommand = splitted[1]
let targetCallees = callees const targetCallees = callees
.filter((callee) => callee.name === target) .filter((callee) => callee.name === target)
targetCallees.forEach((callee) => { targetCallees.forEach((callee) => {

View File

@@ -6,8 +6,6 @@ const win = global.process.platform === 'win32'
const electron = require('electron') const electron = require('electron')
const { ipcRenderer } = electron const { ipcRenderer } = electron
const consts = require('browser/lib/consts') const consts = require('browser/lib/consts')
const path = require('path')
const fs = require('fs')
let isInitialized = false let isInitialized = false
@@ -103,8 +101,8 @@ function get () {
} }
function set (updates) { function set (updates) {
let currentConfig = get() const currentConfig = get()
let newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates) const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
if (!validate(newConfig)) throw new Error('INVALID CONFIG') if (!validate(newConfig)) throw new Error('INVALID CONFIG')
_save(newConfig) _save(newConfig)
@@ -123,7 +121,7 @@ function set (updates) {
editorTheme.setAttribute('rel', 'stylesheet') editorTheme.setAttribute('rel', 'stylesheet')
document.head.appendChild(editorTheme) document.head.appendChild(editorTheme)
} }
let newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme) const newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme)
? newConfig.editor.theme ? newConfig.editor.theme
: 'default' : 'default'
@@ -141,7 +139,7 @@ function set (updates) {
} }
function assignConfigValues (originalConfig, rcConfig) { function assignConfigValues (originalConfig, rcConfig) {
let config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig) const config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig)
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey) config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey)
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui) config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui)
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor) config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor)

View File

@@ -19,7 +19,7 @@ function setZoom (zoomFactor, noSave = false) {
} }
function getZoom () { function getZoom () {
let config = ConfigManager.get() const config = ConfigManager.get()
return config.zoom return config.zoom
} }

View File

@@ -1,7 +1,5 @@
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const _ = require('lodash')
const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage') const { findStorage } = require('browser/lib/findStorage')
/** /**

View File

@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ``` * ```
*/ */
function createFolder (storageKey, input) { function createFolder (storageKey, input) {
let rawStorages
let targetStorage let targetStorage
try { try {
if (input == null) throw new Error('No input found.') if (input == null) throw new Error('No input found.')
@@ -41,7 +40,7 @@ function createFolder (storageKey, input) {
while (storage.folders.some((folder) => folder.key === key)) { while (storage.folders.some((folder) => folder.key === key)) {
key = keygen() key = keygen()
} }
let newFolder = { const newFolder = {
key, key,
color: input.color, color: input.color,
name: input.name name: input.name

View File

@@ -66,7 +66,7 @@ function createNote (storageKey, input) {
} }
} }
} }
let noteData = Object.assign({}, input, { const noteData = Object.assign({}, input, {
key, key,
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date(),

View File

@@ -19,7 +19,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ``` * ```
*/ */
function deleteFolder (storageKey, folderKey) { function deleteFolder (storageKey, folderKey) {
let rawStorages
let targetStorage let targetStorage
try { try {
targetStorage = findStorage(storageKey) targetStorage = findStorage(storageKey)
@@ -38,17 +37,17 @@ function deleteFolder (storageKey, folderKey) {
}) })
}) })
.then(function deleteFolderAndNotes (data) { .then(function deleteFolderAndNotes (data) {
let { storage, notes } = data const { storage, notes } = data
storage.folders = storage.folders storage.folders = storage.folders
.filter(function excludeTargetFolder (folder) { .filter(function excludeTargetFolder (folder) {
return folder.key !== folderKey return folder.key !== folderKey
}) })
let targetNotes = notes.filter(function filterTargetNotes (note) { const targetNotes = notes.filter(function filterTargetNotes (note) {
return note.folder === folderKey return note.folder === folderKey
}) })
let deleteAllNotes = targetNotes const deleteAllNotes = targetNotes
.map(function deleteNote (note) { .map(function deleteNote (note) {
const notePath = path.join(storage.path, 'notes', note.key + '.cson') const notePath = path.join(storage.path, 'notes', note.key + '.cson')
return sander.unlink(notePath) return sander.unlink(notePath)

View File

@@ -1,5 +1,4 @@
const resolveStorageData = require('./resolveStorageData') const resolveStorageData = require('./resolveStorageData')
const _ = require('lodash')
const path = require('path') const path = require('path')
const sander = require('sander') const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage') const { findStorage } = require('browser/lib/findStorage')
@@ -14,7 +13,7 @@ function deleteNote (storageKey, noteKey) {
return resolveStorageData(targetStorage) return resolveStorageData(targetStorage)
.then(function deleteNoteFile (storage) { .then(function deleteNoteFile (storage) {
let notePath = path.join(storage.path, 'notes', noteKey + '.cson') const notePath = path.join(storage.path, 'notes', noteKey + '.cson')
try { try {
sander.unlinkSync(notePath) sander.unlinkSync(notePath)

View File

@@ -20,7 +20,7 @@ const CSON = require('@rokt33r/season')
* 3. empty directory * 3. empty directory
*/ */
function init () { function init () {
let fetchStorages = function () { const fetchStorages = function () {
let rawStorages let rawStorages
try { try {
rawStorages = JSON.parse(window.localStorage.getItem('storages')) rawStorages = JSON.parse(window.localStorage.getItem('storages'))
@@ -34,8 +34,8 @@ function init () {
.map(resolveStorageData)) .map(resolveStorageData))
} }
let fetchNotes = function (storages) { const fetchNotes = function (storages) {
let findNotesFromEachStorage = storages const findNotesFromEachStorage = storages
.map((storage) => { .map((storage) => {
return resolveStorageNotes(storage) return resolveStorageNotes(storage)
.then((notes) => { .then((notes) => {

View File

@@ -9,7 +9,7 @@ const sander = require('sander')
function migrateFromV5Storage (storageKey, data) { function migrateFromV5Storage (storageKey, data) {
let targetStorage let targetStorage
try { try {
let cachedStorageList = JSON.parse(localStorage.getItem('storages')) const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.') if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(cachedStorageList, {key: storageKey}) targetStorage = _.find(cachedStorageList, {key: storageKey})
@@ -24,15 +24,15 @@ function migrateFromV5Storage (storageKey, data) {
} }
function importAll (storage, data) { function importAll (storage, data) {
let oldArticles = data.articles const oldArticles = data.articles
let notes = [] const notes = []
data.folders data.folders
.forEach(function (oldFolder) { .forEach(function (oldFolder) {
let folderKey = keygen() let folderKey = keygen()
while (storage.folders.some((folder) => folder.key === folderKey)) { while (storage.folders.some((folder) => folder.key === folderKey)) {
folderKey = keygen() folderKey = keygen()
} }
let newFolder = { const newFolder = {
key: folderKey, key: folderKey,
name: oldFolder.name, name: oldFolder.name,
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
@@ -40,7 +40,7 @@ function importAll (storage, data) {
storage.folders.push(newFolder) storage.folders.push(newFolder)
let articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key) const articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key)
articles.forEach((article) => { articles.forEach((article) => {
let noteKey = keygen() let noteKey = keygen()
let isUnique = false let isUnique = false
@@ -59,7 +59,7 @@ function importAll (storage, data) {
} }
if (article.mode === 'markdown') { if (article.mode === 'markdown') {
let newNote = { const newNote = {
tags: article.tags, tags: article.tags,
createdAt: article.createdAt, createdAt: article.createdAt,
updatedAt: article.updatedAt, updatedAt: article.updatedAt,
@@ -73,7 +73,7 @@ function importAll (storage, data) {
} }
notes.push(newNote) notes.push(newNote)
} else { } else {
let newNote = { const newNote = {
tags: article.tags, tags: article.tags,
createdAt: article.createdAt, createdAt: article.createdAt,
updatedAt: article.updatedAt, updatedAt: article.updatedAt,

View File

@@ -20,7 +20,7 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
.then(function saveNote (_oldStorage) { .then(function saveNote (_oldStorage) {
oldStorage = _oldStorage oldStorage = _oldStorage
let noteData let noteData
let notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson') const notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson')
try { try {
noteData = CSON.readFileSync(notePath) noteData = CSON.readFileSync(notePath)
} catch (err) { } catch (err) {

View File

@@ -1,6 +1,5 @@
const _ = require('lodash') const _ = require('lodash')
const resolveStorageData = require('./resolveStorageData') const resolveStorageData = require('./resolveStorageData')
const { findStorage } = require('browser/lib/findStorage')
/** /**
* @param {String} key * @param {String} key
@@ -19,7 +18,7 @@ function renameStorage (key, name) {
console.error(err) console.error(err)
return Promise.reject(err) return Promise.reject(err)
} }
let targetStorage = _.find(cachedStorageList, {key: key}) const targetStorage = _.find(cachedStorageList, {key: key})
if (targetStorage == null) return Promise.reject('Storage') if (targetStorage == null) return Promise.reject('Storage')
targetStorage.name = name targetStorage.name = name

View File

@@ -18,7 +18,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ``` * ```
*/ */
function reorderFolder (storageKey, oldIndex, newIndex) { function reorderFolder (storageKey, oldIndex, newIndex) {
let rawStorages
let targetStorage let targetStorage
try { try {
if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.') if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')

View File

@@ -4,7 +4,7 @@ const CSON = require('@rokt33r/season')
const migrateFromV6Storage = require('./migrateFromV6Storage') const migrateFromV6Storage = require('./migrateFromV6Storage')
function resolveStorageData (storageCache) { function resolveStorageData (storageCache) {
let storage = { const storage = {
key: storageCache.key, key: storageCache.key,
name: storageCache.name, name: storageCache.name,
type: storageCache.type, type: storageCache.type,
@@ -13,7 +13,7 @@ function resolveStorageData (storageCache) {
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json') const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')
try { try {
let jsonData = CSON.readFileSync(boostnoteJSONPath) const jsonData = CSON.readFileSync(boostnoteJSONPath)
if (!_.isArray(jsonData.folders)) throw new Error('folders should be an array.') if (!_.isArray(jsonData.folders)) throw new Error('folders should be an array.')
storage.folders = jsonData.folders storage.folders = jsonData.folders
storage.version = jsonData.version storage.version = jsonData.version
@@ -28,7 +28,7 @@ function resolveStorageData (storageCache) {
storage.version = '1.0' storage.version = '1.0'
} }
let version = parseInt(storage.version, 10) const version = parseInt(storage.version, 10)
if (version >= 1) { if (version >= 1) {
if (version > 1) { if (version > 1) {
console.log('The repository version is newer than one of current app.') console.log('The repository version is newer than one of current app.')

View File

@@ -16,13 +16,13 @@ function resolveStorageNotes (storage) {
} }
notePathList = [] notePathList = []
} }
let notes = notePathList const notes = notePathList
.filter(function filterOnlyCSONFile (notePath) { .filter(function filterOnlyCSONFile (notePath) {
return /\.cson$/.test(notePath) return /\.cson$/.test(notePath)
}) })
.map(function parseCSONFile (notePath) { .map(function parseCSONFile (notePath) {
try { try {
let data = CSON.readFileSync(path.join(notesDirPath, notePath)) const data = CSON.readFileSync(path.join(notesDirPath, notePath))
data.key = path.basename(notePath, '.cson') data.key = path.basename(notePath, '.cson')
data.storage = storage.key data.storage = storage.key
return data return data

View File

@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ``` * ```
*/ */
function updateFolder (storageKey, folderKey, input) { function updateFolder (storageKey, folderKey, input) {
let rawStorages
let targetStorage let targetStorage
try { try {
if (input == null) throw new Error('No input found.') if (input == null) throw new Error('No input found.')
@@ -37,7 +36,7 @@ function updateFolder (storageKey, folderKey, input) {
return resolveStorageData(targetStorage) return resolveStorageData(targetStorage)
.then(function updateFolder (storage) { .then(function updateFolder (storage) {
let targetFolder = _.find(storage.folders, {key: folderKey}) const targetFolder = _.find(storage.folders, {key: folderKey})
if (targetFolder == null) throw new Error('Target folder doesn\'t exist.') if (targetFolder == null) throw new Error('Target folder doesn\'t exist.')
targetFolder.name = input.name targetFolder.name = input.name
targetFolder.color = input.color targetFolder.color = input.color

View File

@@ -5,7 +5,7 @@ const CSON = require('@rokt33r/season')
const { findStorage } = require('browser/lib/findStorage') const { findStorage } = require('browser/lib/findStorage')
function validateInput (input) { function validateInput (input) {
let validatedInput = {} const validatedInput = {}
if (input.tags != null) { if (input.tags != null) {
if (!_.isArray(input.tags)) validatedInput.tags = [] if (!_.isArray(input.tags)) validatedInput.tags = []
@@ -81,7 +81,7 @@ function updateNote (storageKey, noteKey, input) {
return resolveStorageData(targetStorage) return resolveStorageData(targetStorage)
.then(function saveNote (storage) { .then(function saveNote (storage) {
let noteData let noteData
let notePath = path.join(storage.path, 'notes', noteKey + '.cson') const notePath = path.join(storage.path, 'notes', noteKey + '.cson')
try { try {
noteData = CSON.readFileSync(notePath) noteData = CSON.readFileSync(notePath)
} catch (err) { } catch (err) {

View File

@@ -16,7 +16,7 @@ class ModalBase extends React.Component {
close () { close () {
if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true}) if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true})
// Toggle overflow style on NoteList // Toggle overflow style on NoteList
let list = document.querySelector('.NoteList__list___browser-main-NoteList-') const list = document.querySelector('.NoteList__list___browser-main-NoteList-')
list.style.overflow = 'auto' list.style.overflow = 'auto'
} }
@@ -34,14 +34,14 @@ class ModalBase extends React.Component {
} }
} }
let el = document.createElement('div') const el = document.createElement('div')
document.body.appendChild(el) document.body.appendChild(el)
let modalBase = ReactDOM.render(<ModalBase />, el) const modalBase = ReactDOM.render(<ModalBase />, el)
export function openModal (component, props) { export function openModal (component, props) {
if (modalBase == null) { return } if (modalBase == null) { return }
// Hide scrollbar by removing overflow when modal opens // Hide scrollbar by removing overflow when modal opens
let list = document.querySelector('.NoteList__list___browser-main-NoteList-') const list = document.querySelector('.NoteList__list___browser-main-NoteList-')
list.style.overflow = 'hidden' list.style.overflow = 'hidden'
document.body.setAttribute('data-modal', 'open') document.body.setAttribute('data-modal', 'open')
modalBase.setState({component: component, componentProps: props, isHidden: false}) modalBase.setState({component: component, componentProps: props, isHidden: false})

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './CreateFolderModal.styl' import styles from './CreateFolderModal.styl'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
@@ -51,8 +52,8 @@ class CreateFolderModal extends React.Component {
confirm () { confirm () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
if (this.state.name.trim().length > 0) { if (this.state.name.trim().length > 0) {
let { storage } = this.props const { storage } = this.props
let input = { const input = {
name: this.state.name.trim(), name: this.state.name.trim(),
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
} }

View File

@@ -5,7 +5,6 @@ import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store' import store from 'browser/main/store'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
import _ from 'lodash' import _ from 'lodash'
import ModalEscButton from 'browser/components/ModalEscButton'
const CSON = require('@rokt33r/season') const CSON = require('@rokt33r/season')
const path = require('path') const path = require('path')
@@ -13,9 +12,9 @@ const electron = require('electron')
const { remote } = electron const { remote } = electron
function browseFolder () { function browseFolder () {
let dialog = remote.dialog const dialog = remote.dialog
let defaultPath = remote.app.getPath('home') const defaultPath = remote.app.getPath('home')
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dialog.showOpenDialog({ dialog.showOpenDialog({
title: 'Select Directory', title: 'Select Directory',
@@ -55,7 +54,7 @@ class InitModal extends React.Component {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
let newState = { const newState = {
isLoading: false isLoading: false
} }
if (data != null) { if (data != null) {
@@ -122,7 +121,7 @@ class InitModal extends React.Component {
notes: data.notes notes: data.notes
}) })
let defaultSnippetNote = dataApi const defaultSnippetNote = dataApi
.createNote(data.storage.key, { .createNote(data.storage.key, {
type: 'SNIPPET_NOTE', type: 'SNIPPET_NOTE',
folder: data.storage.folders[0].key, folder: data.storage.folders[0].key,
@@ -147,7 +146,7 @@ class InitModal extends React.Component {
note: note note: note
}) })
}) })
let defaultMarkdownNote = dataApi const defaultMarkdownNote = dataApi
.createNote(data.storage.key, { .createNote(data.storage.key, {
type: 'MARKDOWN_NOTE', type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key, folder: data.storage.folders[0].key,
@@ -184,6 +183,12 @@ class InitModal extends React.Component {
}) })
} }
handleKeyDown (e) {
if (e.keyCode === 27) {
this.props.close()
}
}
render () { render () {
if (this.state.isLoading) { if (this.state.isLoading) {
return <div styleName='root--loading'> return <div styleName='root--loading'>
@@ -194,19 +199,14 @@ class InitModal extends React.Component {
return ( return (
<div styleName='root' <div styleName='root'
tabIndex='-1' tabIndex='-1'
onKeyDown={this.props.close} onKeyDown={(e) => this.handleKeyDown(e)}
> >
<div styleName='header'>
<div styleName='header-title'>Initialize Storage</div>
</div>
<ModalEscButton handleEscButtonClick={this.props.close} />
<div styleName='body'> <div styleName='body'>
<div styleName='body-welcome'> <div styleName='body-welcome'>
Welcome! Welcome to Boostnote!
</div> </div>
<div styleName='body-description'> <div styleName='body-description'>
Please select a directory for Boostnote storage. Please select a directory for data storage.
</div> </div>
<div styleName='body-path'> <div styleName='body-path'>
<input styleName='body-path-input' <input styleName='body-path-input'
@@ -237,7 +237,7 @@ class InitModal extends React.Component {
? <span> ? <span>
<i className='fa fa-spin fa-spinner' /> Loading... <i className='fa fa-spin fa-spinner' /> Loading...
</span> </span>
: 'Let\'s Go!' : 'CREATE'
} }
</button> </button>
</div> </div>

View File

@@ -1,7 +1,11 @@
.root .root
modal() modal()
max-width 540px background-color #fff
max-width 100vw
max-height 100vh
overflow hidden overflow hidden
margin 0
padding 150px 0
position relative position relative
.root--loading .root--loading
@extend .root @extend .root
@@ -13,14 +17,6 @@
.loadingMessage .loadingMessage
color $ui-text-color color $ui-text-color
margin 15px auto 35px margin 15px auto 35px
.header
height 50px
font-size 18px
line-height 50px
padding 0 15px
background-color $ui-backgroundColor
border-bottom solid 1px $ui-borderColor
color $ui-text-color
.body .body
padding 30px padding 30px
@@ -32,20 +28,20 @@
color $ui-text-color color $ui-text-color
.body-description .body-description
font-size 14px font-size 16px
color $ui-text-color color $ui-text-color
text-align center text-align center
margin-bottom 25px margin-bottom 25px
.body-path .body-path
margin 0 auto 25px margin 0 auto 25px
width 280px width 330px
.body-path-input .body-path-input
height 30px height 40px
vertical-align middle vertical-align middle
width 250px width 300px
font-size 12px font-size 14px
border-style solid border-style solid
border-width 1px 0 1px 1px border-width 1px 0 1px 1px
border-color $border-color border-color $border-color
@@ -54,7 +50,10 @@
padding 0 5px padding 0 5px
.body-path-button .body-path-button
height 30px height 42px
width 30px
font-size 16px
font-weight 600
border none border none
border-top-right-radius 2px border-top-right-radius 2px
border-bottom-right-radius 2px border-bottom-right-radius 2px
@@ -69,6 +68,8 @@
.body-control-createButton .body-control-createButton
colorPrimaryButton() colorPrimaryButton()
font-size 14px
font-weight 600
border none border none
border-radius 2px border-radius 2px
height 40px height 40px

View File

@@ -26,7 +26,7 @@ class NewNoteModal extends React.Component {
handleMarkdownNoteButtonClick (e) { handleMarkdownNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props const { storage, folder, dispatch, location } = this.props
dataApi dataApi
.createNote(storage, { .createNote(storage, {
type: 'MARKDOWN_NOTE', type: 'MARKDOWN_NOTE',
@@ -58,7 +58,7 @@ class NewNoteModal extends React.Component {
handleSnippetNoteButtonClick (e) { handleSnippetNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props const { storage, folder, dispatch, location } = this.props
dataApi dataApi
.createNote(storage, { .createNote(storage, {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import styles from './FolderItem.styl' import styles from './FolderItem.styl'
@@ -23,7 +24,7 @@ class FolderItem extends React.Component {
} }
handleEditChange (e) { handleEditChange (e) {
let { folder } = this.state const { folder } = this.state
folder.name = this.refs.nameInput.value folder.name = this.refs.nameInput.value
this.setState({ this.setState({
@@ -36,7 +37,7 @@ class FolderItem extends React.Component {
} }
confirm () { confirm () {
let { storage, folder } = this.props const { storage, folder } = this.props
dataApi dataApi
.updateFolder(storage.key, folder.key, { .updateFolder(storage.key, folder.key, {
color: this.state.folder.color, color: this.state.folder.color,
@@ -162,7 +163,7 @@ class FolderItem extends React.Component {
} }
handleDeleteConfirmButtonClick (e) { handleDeleteConfirmButtonClick (e) {
let { storage, folder } = this.props const { storage, folder } = this.props
dataApi dataApi
.deleteFolder(storage.key, folder.key) .deleteFolder(storage.key, folder.key)
.then((data) => { .then((data) => {
@@ -197,8 +198,8 @@ class FolderItem extends React.Component {
} }
handleEditButtonClick (e) { handleEditButtonClick (e) {
let { folder: propsFolder } = this.props const { folder: propsFolder } = this.props
let { folder: stateFolder } = this.state const { folder: stateFolder } = this.state
const folder = Object.assign({}, stateFolder, propsFolder) const folder = Object.assign({}, stateFolder, propsFolder)
this.setState({ this.setState({
status: 'EDIT', status: 'EDIT',
@@ -215,7 +216,7 @@ class FolderItem extends React.Component {
} }
renderIdle () { renderIdle () {
let { folder } = this.props const { folder } = this.props
return ( return (
<div styleName='folderItem' <div styleName='folderItem'
onDoubleClick={(e) => this.handleEditButtonClick(e)} onDoubleClick={(e) => this.handleEditButtonClick(e)}

View File

@@ -1,16 +1,17 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
import styles from './FolderList.styl' import styles from './FolderList.styl'
import store from 'browser/main/store' import store from 'browser/main/store'
import FolderItem from './FolderItem' import FolderItem from './FolderItem'
import { SortableContainer, arrayMove } from 'react-sortable-hoc' import { SortableContainer } from 'react-sortable-hoc'
class FolderList extends React.Component { class FolderList extends React.Component {
render () { render () {
let { storage, hostBoundingBox } = this.props const { storage, hostBoundingBox } = this.props
let folderList = storage.folders.map((folder, index) => { const folderList = storage.folders.map((folder, index) => {
return <FolderItem key={folder.key} return <FolderItem key={folder.key}
folder={folder} folder={folder}
storage={storage} storage={storage}
@@ -53,7 +54,7 @@ class SortableFolderListComponent extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
this.onSortEnd = ({oldIndex, newIndex}) => { this.onSortEnd = ({oldIndex, newIndex}) => {
let { storage } = this.props const { storage } = this.props
dataApi dataApi
.reorderFolder(storage.key, oldIndex, newIndex) .reorderFolder(storage.key, oldIndex, newIndex)
.then((data) => { .then((data) => {

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './ConfigTab.styl' import styles from './ConfigTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager' import ConfigManager from 'browser/main/lib/ConfigManager'
@@ -41,7 +42,7 @@ class HotkeyTab extends React.Component {
} }
handleSaveButtonClick (e) { handleSaveButtonClick (e) {
let newConfig = { const newConfig = {
hotkey: this.state.config.hotkey hotkey: this.state.config.hotkey
} }
@@ -61,7 +62,7 @@ class HotkeyTab extends React.Component {
} }
handleHotkeyChange (e) { handleHotkeyChange (e) {
let { config } = this.state const { config } = this.state
config.hotkey = { config.hotkey = {
toggleFinder: this.refs.toggleFinder.value, toggleFinder: this.refs.toggleFinder.value,
toggleMain: this.refs.toggleMain.value toggleMain: this.refs.toggleMain.value
@@ -80,13 +81,13 @@ class HotkeyTab extends React.Component {
} }
render () { render () {
let keymapAlert = this.state.keymapAlert const keymapAlert = this.state.keymapAlert
let keymapAlertElement = keymapAlert != null const keymapAlertElement = keymapAlert != null
? <p className={`alert ${keymapAlert.type}`}> ? <p className={`alert ${keymapAlert.type}`}>
{keymapAlert.message} {keymapAlert.message}
</p> </p>
: null : null
let { config } = this.state const { config } = this.state
return ( return (
<div styleName='root'> <div styleName='root'>

View File

@@ -72,6 +72,11 @@ class InfoTab extends React.Component {
<div styleName='header--sub'>Community</div> <div styleName='header--sub'>Community</div>
<div styleName='top'> <div styleName='top'>
<ul styleName='list'> <ul styleName='list'>
<li>
<a href='https://boostnote.io/#subscribe'
onClick={(e) => this.handleLinkClick(e)}
>Subscribe to Newsletter</a>
</li>
<li> <li>
<a href='https://github.com/BoostIO/Boostnote/issues' <a href='https://github.com/BoostIO/Boostnote/issues'
onClick={(e) => this.handleLinkClick(e)} onClick={(e) => this.handleLinkClick(e)}
@@ -82,11 +87,6 @@ class InfoTab extends React.Component {
onClick={(e) => this.handleLinkClick(e)} onClick={(e) => this.handleLinkClick(e)}
>Blog</a> >Blog</a>
</li> </li>
<li>
<a href='https://www.reddit.com/r/Boostnote/'
onClick={(e) => this.handleLinkClick(e)}
>Reddit</a>
</li>
<li> <li>
<a href='https://www.facebook.com/groups/boostnote' <a href='https://www.facebook.com/groups/boostnote'
onClick={(e) => this.handleLinkClick(e)} onClick={(e) => this.handleLinkClick(e)}

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageItem.styl' import styles from './StorageItem.styl'
import consts from 'browser/lib/consts' import consts from 'browser/lib/consts'
@@ -19,8 +20,8 @@ class StorageItem extends React.Component {
} }
handleNewFolderButtonClick (e) { handleNewFolderButtonClick (e) {
let { storage } = this.props const { storage } = this.props
let input = { const input = {
name: 'Untitled', name: 'Untitled',
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7] color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
} }
@@ -38,12 +39,12 @@ class StorageItem extends React.Component {
} }
handleExternalButtonClick () { handleExternalButtonClick () {
let { storage } = this.props const { storage } = this.props
shell.showItemInFolder(storage.path) shell.showItemInFolder(storage.path)
} }
handleUnlinkButtonClick (e) { handleUnlinkButtonClick (e) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Unlink Storage', message: 'Unlink Storage',
detail: 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.', detail: 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.',
@@ -51,7 +52,7 @@ class StorageItem extends React.Component {
}) })
if (index === 0) { if (index === 0) {
let { storage } = this.props const { storage } = this.props
dataApi.removeStorage(storage.key) dataApi.removeStorage(storage.key)
.then(() => { .then(() => {
store.dispatch({ store.dispatch({
@@ -66,7 +67,7 @@ class StorageItem extends React.Component {
} }
handleLabelClick (e) { handleLabelClick (e) {
let { storage } = this.props const { storage } = this.props
this.setState({ this.setState({
isLabelEditing: true, isLabelEditing: true,
name: storage.name name: storage.name
@@ -81,7 +82,7 @@ class StorageItem extends React.Component {
} }
handleLabelBlur (e) { handleLabelBlur (e) {
let { storage } = this.props const { storage } = this.props
dataApi dataApi
.renameStorage(storage.key, this.state.name) .renameStorage(storage.key, this.state.name)
.then((_storage) => { .then((_storage) => {
@@ -96,7 +97,7 @@ class StorageItem extends React.Component {
} }
render () { render () {
let { storage, hostBoundingBox } = this.props const { storage, hostBoundingBox } = this.props
return ( return (
<div styleName='root' key={storage.key}> <div styleName='root' key={storage.key}>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './StoragesTab.styl' import styles from './StoragesTab.styl'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
@@ -8,9 +9,9 @@ const electron = require('electron')
const { shell, remote } = electron const { shell, remote } = electron
function browseFolder () { function browseFolder () {
let dialog = remote.dialog const dialog = remote.dialog
let defaultPath = remote.app.getPath('home') const defaultPath = remote.app.getPath('home')
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dialog.showOpenDialog({ dialog.showOpenDialog({
title: 'Select Directory', title: 'Select Directory',
@@ -56,10 +57,10 @@ class StoragesTab extends React.Component {
} }
renderList () { renderList () {
let { data, boundingBox } = this.props const { data, boundingBox } = this.props
if (!boundingBox) { return null } if (!boundingBox) { return null }
let storageList = data.storageMap.map((storage) => { const storageList = data.storageMap.map((storage) => {
return <StorageItem return <StorageItem
key={storage.key} key={storage.key}
storage={storage} storage={storage}
@@ -88,7 +89,7 @@ class StoragesTab extends React.Component {
browseFolder() browseFolder()
.then((targetPath) => { .then((targetPath) => {
if (targetPath.length > 0) { if (targetPath.length > 0) {
let { newStorage } = this.state const { newStorage } = this.state
newStorage.path = targetPath newStorage.path = targetPath
this.setState({ this.setState({
newStorage newStorage
@@ -102,7 +103,7 @@ class StoragesTab extends React.Component {
} }
handleAddStorageChange (e) { handleAddStorageChange (e) {
let { newStorage } = this.state const { newStorage } = this.state
newStorage.name = this.refs.addStorageName.value newStorage.name = this.refs.addStorageName.value
newStorage.path = this.refs.addStoragePath.value newStorage.path = this.refs.addStoragePath.value
this.setState({ this.setState({
@@ -117,7 +118,7 @@ class StoragesTab extends React.Component {
path: this.state.newStorage.path path: this.state.newStorage.path
}) })
.then((data) => { .then((data) => {
let { dispatch } = this.props const { dispatch } = this.props
dispatch({ dispatch({
type: 'ADD_STORAGE', type: 'ADD_STORAGE',
storage: data.storage, storage: data.storage,

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './ConfigTab.styl' import styles from './ConfigTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager' import ConfigManager from 'browser/main/lib/ConfigManager'
@@ -24,6 +25,7 @@ class UiTab extends React.Component {
} }
componentDidMount () { componentDidMount () {
CodeMirror.autoLoadMode(this.codeMirrorInstance.getCodeMirror(), 'javascript')
this.handleSettingDone = () => { this.handleSettingDone = () => {
this.setState({UiAlert: { this.setState({UiAlert: {
type: 'success', type: 'success',
@@ -40,10 +42,6 @@ class UiTab extends React.Component {
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
} }
componentWillMount () {
CodeMirror.autoLoadMode(ReactCodeMirror, 'javascript')
}
componentWillUnmount () { componentWillUnmount () {
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone) ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError) ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
@@ -119,8 +117,8 @@ class UiTab extends React.Component {
} }
render () { render () {
let UiAlert = this.state.UiAlert const UiAlert = this.state.UiAlert
let UiAlertElement = UiAlert != null const UiAlertElement = UiAlert != null
? <p className={`alert ${UiAlert.type}`}> ? <p className={`alert ${UiAlert.type}`}>
{UiAlert.message} {UiAlert.message}
</p> </p>
@@ -190,7 +188,7 @@ class UiTab extends React.Component {
} }
</select> </select>
<div styleName='code-mirror'> <div styleName='code-mirror'>
<ReactCodeMirror value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} /> <ReactCodeMirror ref={e => (this.codeMirrorInstance = e)} value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import HotkeyTab from './HotkeyTab' import HotkeyTab from './HotkeyTab'
@@ -42,7 +43,7 @@ class Preferences extends React.Component {
renderContent () { renderContent () {
const { boundingBox } = this.state const { boundingBox } = this.state
let { dispatch, config, data } = this.props const { dispatch, config, data } = this.props
switch (this.state.currentTab) { switch (this.state.currentTab) {
case 'INFO': case 'INFO':
@@ -94,9 +95,9 @@ class Preferences extends React.Component {
} }
render () { render () {
let content = this.renderContent() const content = this.renderContent()
let tabs = [ const tabs = [
{target: 'STORAGES', label: 'Storages'}, {target: 'STORAGES', label: 'Storages'},
{target: 'HOTKEY', label: 'Hotkey'}, {target: 'HOTKEY', label: 'Hotkey'},
{target: 'UI', label: 'UI'}, {target: 'UI', label: 'UI'},
@@ -104,8 +105,8 @@ class Preferences extends React.Component {
{target: 'CROWDFUNDING', label: 'Crowdfunding'} {target: 'CROWDFUNDING', label: 'Crowdfunding'}
] ]
let navButtons = tabs.map((tab) => { const navButtons = tabs.map((tab) => {
let isActive = this.state.currentTab === tab.target const isActive = this.state.currentTab === tab.target
return ( return (
<button styleName={isActive <button styleName={isActive
? 'nav-button--active' ? 'nav-button--active'

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './RenameFolderModal.styl' import styles from './RenameFolderModal.styl'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
@@ -48,7 +49,7 @@ class RenameFolderModal extends React.Component {
confirm () { confirm () {
if (this.state.name.trim().length > 0) { if (this.state.name.trim().length > 0) {
let { storage, folder } = this.props const { storage, folder } = this.props
dataApi dataApi
.updateFolder(storage.key, folder.key, { .updateFolder(storage.key, folder.key, {
name: this.state.name, name: this.state.name,

View File

@@ -27,8 +27,8 @@ function data (state = defaultDataMap(), action) {
action.notes.some((note) => { action.notes.some((note) => {
if (note === undefined) return true if (note === undefined) return true
let uniqueKey = note.storage + '-' + note.key const uniqueKey = note.storage + '-' + note.key
let folderKey = note.storage + '-' + note.folder const folderKey = note.storage + '-' + note.folder
state.noteMap.set(uniqueKey, note) state.noteMap.set(uniqueKey, note)
if (note.isStarred) { if (note.isStarred) {
@@ -65,10 +65,10 @@ function data (state = defaultDataMap(), action) {
return state return state
case 'UPDATE_NOTE': case 'UPDATE_NOTE':
{ {
let note = action.note const note = action.note
let uniqueKey = note.storage + '-' + note.key const uniqueKey = note.storage + '-' + note.key
let folderKey = note.storage + '-' + note.folder const folderKey = note.storage + '-' + note.folder
let oldNote = state.noteMap.get(uniqueKey) const oldNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state) state = Object.assign({}, state)
state.noteMap = new Map(state.noteMap) state.noteMap = new Map(state.noteMap)
@@ -110,7 +110,7 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap.set(folderKey, folderNoteSet) state.folderNoteMap.set(folderKey, folderNoteSet)
if (oldNote != null) { if (oldNote != null) {
let oldFolderKey = oldNote.storage + '-' + oldNote.folder const oldFolderKey = oldNote.storage + '-' + oldNote.folder
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey) let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
oldFolderNoteList = new Set(oldFolderNoteList) oldFolderNoteList = new Set(oldFolderNoteList)
oldFolderNoteList.delete(uniqueKey) oldFolderNoteList.delete(uniqueKey)
@@ -119,8 +119,8 @@ function data (state = defaultDataMap(), action) {
} }
if (oldNote != null) { if (oldNote != null) {
let discardedTags = _.difference(oldNote.tags, note.tags) const discardedTags = _.difference(oldNote.tags, note.tags)
let addedTags = _.difference(note.tags, oldNote.tags) const addedTags = _.difference(note.tags, oldNote.tags)
if (discardedTags.length + addedTags.length > 0) { if (discardedTags.length + addedTags.length > 0) {
state.tagNoteMap = new Map(state.tagNoteMap) state.tagNoteMap = new Map(state.tagNoteMap)
@@ -156,12 +156,12 @@ function data (state = defaultDataMap(), action) {
} }
case 'MOVE_NOTE': case 'MOVE_NOTE':
{ {
let originNote = action.originNote const originNote = action.originNote
let originKey = originNote.storage + '-' + originNote.key const originKey = originNote.storage + '-' + originNote.key
let note = action.note const note = action.note
let uniqueKey = note.storage + '-' + note.key const uniqueKey = note.storage + '-' + note.key
let folderKey = note.storage + '-' + note.folder const folderKey = note.storage + '-' + note.folder
let oldNote = state.noteMap.get(uniqueKey) const oldNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state) state = Object.assign({}, state)
state.noteMap = new Map(state.noteMap) state.noteMap = new Map(state.noteMap)
@@ -191,7 +191,7 @@ function data (state = defaultDataMap(), action) {
// From folderNoteMap // From folderNoteMap
state.folderNoteMap = new Map(state.folderNoteMap) state.folderNoteMap = new Map(state.folderNoteMap)
let originFolderKey = originNote.storage + '-' + originNote.folder const originFolderKey = originNote.storage + '-' + originNote.folder
let originFolderList = state.folderNoteMap.get(originFolderKey) let originFolderList = state.folderNoteMap.get(originFolderKey)
originFolderList = new Set(originFolderList) originFolderList = new Set(originFolderList)
originFolderList.delete(originKey) originFolderList.delete(originKey)
@@ -245,7 +245,7 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap.set(folderKey, folderNoteList) state.folderNoteMap.set(folderKey, folderNoteList)
if (oldNote != null) { if (oldNote != null) {
let oldFolderKey = oldNote.storage + '-' + oldNote.folder const oldFolderKey = oldNote.storage + '-' + oldNote.folder
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey) let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
oldFolderNoteList = new Set(oldFolderNoteList) oldFolderNoteList = new Set(oldFolderNoteList)
oldFolderNoteList.delete(uniqueKey) oldFolderNoteList.delete(uniqueKey)
@@ -255,8 +255,8 @@ function data (state = defaultDataMap(), action) {
// Remove from old folder map // Remove from old folder map
if (oldNote != null) { if (oldNote != null) {
let discardedTags = _.difference(oldNote.tags, note.tags) const discardedTags = _.difference(oldNote.tags, note.tags)
let addedTags = _.difference(note.tags, oldNote.tags) const addedTags = _.difference(note.tags, oldNote.tags)
if (discardedTags.length + addedTags.length > 0) { if (discardedTags.length + addedTags.length > 0) {
state.tagNoteMap = new Map(state.tagNoteMap) state.tagNoteMap = new Map(state.tagNoteMap)
@@ -292,8 +292,8 @@ function data (state = defaultDataMap(), action) {
} }
case 'DELETE_NOTE': case 'DELETE_NOTE':
{ {
let uniqueKey = action.storageKey + '-' + action.noteKey const uniqueKey = action.storageKey + '-' + action.noteKey
let targetNote = state.noteMap.get(uniqueKey) const targetNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state) state = Object.assign({}, state)
@@ -317,7 +317,7 @@ function data (state = defaultDataMap(), action) {
} }
// From folderNoteMap // From folderNoteMap
let folderKey = targetNote.storage + '-' + targetNote.folder const folderKey = targetNote.storage + '-' + targetNote.folder
state.folderNoteMap = new Map(state.folderNoteMap) state.folderNoteMap = new Map(state.folderNoteMap)
let folderSet = state.folderNoteMap.get(folderKey) let folderSet = state.folderNoteMap.get(folderKey)
folderSet = new Set(folderSet) folderSet = new Set(folderSet)
@@ -340,18 +340,14 @@ function data (state = defaultDataMap(), action) {
return state return state
} }
case 'UPDATE_FOLDER': case 'UPDATE_FOLDER':
{ state = Object.assign({}, state)
state = Object.assign({}, state) state.storageMap = new Map(state.storageMap)
state.storageMap = new Map(state.storageMap) state.storageMap.set(action.storage.key, action.storage)
state.storageMap.set(action.storage.key, action.storage)
}
return state return state
case 'REORDER_FOLDER': case 'REORDER_FOLDER':
{ state = Object.assign({}, state)
state = Object.assign({}, state) state.storageMap = new Map(state.storageMap)
state.storageMap = new Map(state.storageMap) state.storageMap.set(action.storage.key, action.storage)
state.storageMap.set(action.storage.key, action.storage)
}
return state return state
case 'DELETE_FOLDER': case 'DELETE_FOLDER':
{ {
@@ -361,8 +357,8 @@ function data (state = defaultDataMap(), action) {
// Get note list from folder-note map // Get note list from folder-note map
// and delete note set from folder-note map // and delete note set from folder-note map
let folderKey = action.storage.key + '-' + action.folderKey const folderKey = action.storage.key + '-' + action.folderKey
let noteSet = state.folderNoteMap.get(folderKey) const noteSet = state.folderNoteMap.get(folderKey)
state.folderNoteMap = new Map(state.folderNoteMap) state.folderNoteMap = new Map(state.folderNoteMap)
state.folderNoteMap.delete(folderKey) state.folderNoteMap.delete(folderKey)
@@ -375,7 +371,7 @@ function data (state = defaultDataMap(), action) {
if (noteSet != null) { if (noteSet != null) {
noteSet.forEach(function handleNoteKey (noteKey) { noteSet.forEach(function handleNoteKey (noteKey) {
// Get note from noteMap // Get note from noteMap
let note = state.noteMap.get(noteKey) const note = state.noteMap.get(noteKey)
if (note != null) { if (note != null) {
state.noteMap.delete(noteKey) state.noteMap.delete(noteKey)
@@ -417,8 +413,8 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap = new Map(state.folderNoteMap) state.folderNoteMap = new Map(state.folderNoteMap)
state.tagNoteMap = new Map(state.tagNoteMap) state.tagNoteMap = new Map(state.tagNoteMap)
action.notes.forEach((note) => { action.notes.forEach((note) => {
let uniqueKey = note.storage + '-' + note.key const uniqueKey = note.storage + '-' + note.key
let folderKey = note.storage + '-' + note.folder const folderKey = note.storage + '-' + note.folder
state.noteMap.set(uniqueKey, note) state.noteMap.set(uniqueKey, note)
if (note.isStarred) { if (note.isStarred) {
@@ -451,7 +447,7 @@ function data (state = defaultDataMap(), action) {
return state return state
case 'REMOVE_STORAGE': case 'REMOVE_STORAGE':
state = Object.assign({}, state) state = Object.assign({}, state)
let storage = state.storageMap.get(action.storageKey) const storage = state.storageMap.get(action.storageKey)
state.storageMap = new Map(state.storageMap) state.storageMap = new Map(state.storageMap)
state.storageMap.delete(action.storageKey) state.storageMap.delete(action.storageKey)
@@ -459,17 +455,17 @@ function data (state = defaultDataMap(), action) {
if (storage != null) { if (storage != null) {
state.folderMap = new Map(state.folderMap) state.folderMap = new Map(state.folderMap)
storage.folders.forEach((folder) => { storage.folders.forEach((folder) => {
let folderKey = storage.key + '-' + folder.key const folderKey = storage.key + '-' + folder.key
state.folderMap.delete(folderKey) state.folderMap.delete(folderKey)
}) })
} }
// Remove notes from noteMap and tagNoteMap // Remove notes from noteMap and tagNoteMap
let storageNoteSet = state.storageNoteMap.get(action.storageKey) const storageNoteSet = state.storageNoteMap.get(action.storageKey)
state.storageNoteMap = new Map(state.storageNoteMap) state.storageNoteMap = new Map(state.storageNoteMap)
state.storageNoteMap.delete(action.storageKey) state.storageNoteMap.delete(action.storageKey)
if (storageNoteSet != null) { if (storageNoteSet != null) {
let notes = storageNoteSet const notes = storageNoteSet
.map((noteKey) => state.noteMap.get(noteKey)) .map((noteKey) => state.noteMap.get(noteKey))
.filter((note) => note != null) .filter((note) => note != null)
@@ -477,7 +473,7 @@ function data (state = defaultDataMap(), action) {
state.tagNoteMap = new Map(state.tagNoteMap) state.tagNoteMap = new Map(state.tagNoteMap)
state.starredSet = new Set(state.starredSet) state.starredSet = new Set(state.starredSet)
notes.forEach((note) => { notes.forEach((note) => {
let noteKey = storage.key + '-' + note.key const noteKey = storage.key + '-' + note.key
state.noteMap.delete(noteKey) state.noteMap.delete(noteKey)
state.starredSet.delete(noteKey) state.starredSet.delete(noteKey)
note.tags.forEach((tag) => { note.tags.forEach((tag) => {
@@ -535,13 +531,13 @@ function status (state = defaultStatus, action) {
return state return state
} }
let reducer = combineReducers({ const reducer = combineReducers({
data, data,
config, config,
status, status,
routing: routerReducer routing: routerReducer
}) })
let store = createStore(reducer) const store = createStore(reducer)
export default store export default store

View File

@@ -86,6 +86,7 @@ colorPrimaryButton()
color $ui-text-color color $ui-text-color
background-color $default-button-background--hover background-color $default-button-background--hover
&:hover &:hover
transition 0.2s
background-color $default-button-background--active background-color $default-button-background--active
&:active &:active
&:active:hover &:active:hover

View File

@@ -61,8 +61,12 @@ if (process.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon')
mainWindow.removeAllListeners() mainWindow.removeAllListeners()
}) })
} else { } else {
mainWindow.on('close', function () {
storeWindowSize()
})
app.on('window-all-closed', function () { app.on('window-all-closed', function () {
quitApp() app.quit()
}) })
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "boost", "name": "boost",
"productName": "Boostnote", "productName": "Boostnote",
"version": "0.8.17", "version": "0.8.18",
"main": "index.js", "main": "index.js",
"description": "Boostnote", "description": "Boostnote",
"license": "GPL-3.0", "license": "GPL-3.0",
@@ -76,7 +76,7 @@
"moment": "^2.10.3", "moment": "^2.10.3",
"node-ipc": "^8.1.0", "node-ipc": "^8.1.0",
"raphael": "^2.2.7", "raphael": "^2.2.7",
"react": "^15.0.2", "react": "^15.5.4",
"react-codemirror": "^0.3.0", "react-codemirror": "^0.3.0",
"react-dom": "^15.0.2", "react-dom": "^15.0.2",
"react-redux": "^4.4.5", "react-redux": "^4.4.5",

View File

@@ -36,7 +36,7 @@ test.serial('Add Storage', (t) => {
return addStorage(input) return addStorage(input)
}) })
.then(function validateResult (data) { .then(function validateResult (data) {
let { storage, notes } = data const { storage, notes } = data
// Check data.storage // Check data.storage
t.true(_.isString(storage.key)) t.true(_.isString(storage.key))
@@ -53,13 +53,13 @@ test.serial('Add Storage', (t) => {
}) })
// Check localStorage // Check localStorage
let cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key}) const cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key})
t.is(cacheData.name, input.name) t.is(cacheData.name, input.name)
t.is(cacheData.type, input.type) t.is(cacheData.type, input.type)
t.is(cacheData.path, input.path) t.is(cacheData.path, input.path)
// Check boostnote.json // Check boostnote.json
let jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json')) const jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json'))
t.true(_.isArray(jsonData.folders)) t.true(_.isArray(jsonData.folders))
t.is(jsonData.version, '1.0') t.is(jsonData.version, '1.0')
t.is(jsonData.folders.length, t.context.v1StorageData.json.folders.length) t.is(jsonData.folders.length, t.context.v1StorageData.json.folders.length)

View File

@@ -33,7 +33,7 @@ test.serial('Create a folder', (t) => {
}) })
.then(function assert (data) { .then(function assert (data) {
t.true(_.find(data.storage.folders, input) != null) t.true(_.find(data.storage.folders, input) != null)
let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json')) console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, input) != null) t.true(_.find(jsonData.folders, input) != null)
}) })

View File

@@ -54,11 +54,11 @@ test.serial('Create a note', (t) => {
]) ])
}) })
.then(function assert (data) { .then(function assert (data) {
let data1 = data[0] const data1 = data[0]
let data2 = data[1] const data2 = data[1]
t.is(storageKey, data1.storage) t.is(storageKey, data1.storage)
let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(input1.title, data1.title) t.is(input1.title, data1.title)
t.is(input1.title, jsonData1.title) t.is(input1.title, jsonData1.title)
t.is(input1.description, data1.description) t.is(input1.description, data1.description)
@@ -73,7 +73,7 @@ test.serial('Create a note', (t) => {
t.is(input1.snippets[0].name, jsonData1.snippets[0].name) t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
t.is(storageKey, data2.storage) t.is(storageKey, data2.storage)
let jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson')) const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
t.is(input2.title, data2.title) t.is(input2.title, data2.title)
t.is(input2.title, jsonData2.title) t.is(input2.title, jsonData2.title)
t.is(input2.content, data2.content) t.is(input2.content, data2.content)

View File

@@ -31,10 +31,10 @@ test.serial('Delete a folder', (t) => {
}) })
.then(function assert (data) { .then(function assert (data) {
t.true(_.find(data.storage.folders, {key: folderKey}) == null) t.true(_.find(data.storage.folders, {key: folderKey}) == null)
let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, {key: folderKey}) == null) t.true(_.find(jsonData.folders, {key: folderKey}) == null)
let notePaths = sander.readdirSync(data.storage.path, 'notes') const notePaths = sander.readdirSync(data.storage.path, 'notes')
t.is(notePaths.length, t.context.storage.notes.filter((note) => note.folder !== folderKey).length) t.is(notePaths.length, t.context.storage.notes.filter((note) => note.folder !== folderKey).length)
}) })
}) })

View File

@@ -17,7 +17,7 @@ const os = require('os')
const dummyStoragePath = path.join(os.tmpdir(), 'test/migrate-test-storage') const dummyStoragePath = path.join(os.tmpdir(), 'test/migrate-test-storage')
test.beforeEach((t) => { test.beforeEach((t) => {
let dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath) const dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath)
console.log('init count', dummyData.notes.length) console.log('init count', dummyData.notes.length)
localStorage.setItem('storages', JSON.stringify([dummyData.cache])) localStorage.setItem('storages', JSON.stringify([dummyData.cache]))
}) })
@@ -32,11 +32,11 @@ test.serial('Migrate legacy storage into v1 storage', (t) => {
t.true(data) t.true(data)
// Check all notes migrated. // Check all notes migrated.
let dummyData = t.context.dummyData const dummyData = t.context.dummyData
let noteDirPath = path.join(dummyStoragePath, 'notes') const noteDirPath = path.join(dummyStoragePath, 'notes')
let fileList = sander.readdirSync(noteDirPath) const fileList = sander.readdirSync(noteDirPath)
t.is(dummyData.notes.length, fileList.length) t.is(dummyData.notes.length, fileList.length)
let noteMap = fileList const noteMap = fileList
.map((filePath) => { .map((filePath) => {
return CSON.readFileSync(path.join(noteDirPath, filePath)) return CSON.readFileSync(path.join(noteDirPath, filePath))
}) })

View File

@@ -38,15 +38,15 @@ test.serial('Move a note', (t) => {
]) ])
}) })
.then(function assert (data) { .then(function assert (data) {
let data1 = data[0] const data1 = data[0]
let data2 = data[1] const data2 = data[1]
let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(jsonData1.folder, folderKey1) t.is(jsonData1.folder, folderKey1)
t.is(jsonData1.title, note1.title) t.is(jsonData1.title, note1.title)
let jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson')) const jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson'))
t.is(jsonData2.folder, folderKey2) t.is(jsonData2.folder, folderKey2)
t.is(jsonData2.title, note2.title) t.is(jsonData2.title, note2.title)
try { try {

View File

@@ -27,7 +27,7 @@ test.serial('Rename a storage', (t) => {
return renameStorage(storageKey, 'changed') return renameStorage(storageKey, 'changed')
}) })
.then(function assert (data) { .then(function assert (data) {
let cachedStorageList = JSON.parse(localStorage.getItem('storages')) const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
t.true(_.find(cachedStorageList, {key: storageKey}).name === 'changed') t.true(_.find(cachedStorageList, {key: storageKey}).name === 'changed')
}) })
}) })

View File

@@ -34,8 +34,7 @@ test.serial('Reorder a folder', (t) => {
t.true(_.nth(data.storage.folders, 0).key === secondFolderKey) t.true(_.nth(data.storage.folders, 0).key === secondFolderKey)
t.true(_.nth(data.storage.folders, 1).key === firstFolderKey) t.true(_.nth(data.storage.folders, 1).key === firstFolderKey)
let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.nth(jsonData.folders, 0).key === secondFolderKey) t.true(_.nth(jsonData.folders, 0).key === secondFolderKey)
t.true(_.nth(jsonData.folders, 1).key === firstFolderKey) t.true(_.nth(jsonData.folders, 1).key === firstFolderKey)

View File

@@ -34,7 +34,7 @@ test.serial('Update a folder', (t) => {
}) })
.then(function assert (data) { .then(function assert (data) {
t.true(_.find(data.storage.folders, input) != null) t.true(_.find(data.storage.folders, input) != null)
let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json')) const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json')) console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, input) != null) t.true(_.find(jsonData.folders, input) != null)
}) })

Some files were not shown because too many files have changed in this diff Show More