1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

Merge with master resolve conflict

This commit is contained in:
voidSatisfaction
2017-11-27 14:05:26 +09:00
170 changed files with 2287 additions and 1036 deletions

View File

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

View File

@@ -1,43 +1,72 @@
Dear all,
<h1 align="center">Sponsors &amp; Backers</h1>
Thanks for your using!
Boostnote is used in about 200 countries and regions, it is a awesome developer community.
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:
To continue supporting this growth, and to satisfy community expectations,
we would like to invest more time in this project.
If you like this project and see its potential, you can help!
Thanks,
Boostnote maintainers.
### >> [Support via OpenCollective](https://opencollective.com/boostnoteio)
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
---
## Backers
[Kazz](https://twitter.com/kazup_bot) - $65
## Backers via OpenCollective
Intense Raiden - $45
### [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/.
ravy22 - $25
### [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/.
trentpolack - $20
### [Bronze Sponsors / $50 per month](https://opencollective.com/boostnoteio/order/2258)
- Get your name and Url (or E-mail) on Readme.md on GitHub.
hikariru - $10
### [Backers3 / $10 per month](https://opencollective.com/boostnoteio/order/2176)
- [Ralph03](https://opencollective.com/ralph03)
kolchan11 - $10
- [Nikolas Dan](https://opencollective.com/nikolas-dan)
RonWalker22 - $10
### [Backers2 / $5 per month](https://opencollective.com/boostnoteio/order/2175)
- [Yeojong Kim](https://twitter.com/yeojoy)
hocchuc - $5
- [Scotia Draven](https://opencollective.com/scotia-draven)
Adam - $5
- [A. J. Vargas](https://opencollective.com/aj-vargas)
Steve - $5
### [Backers1](https://opencollective.com/boostnoteio/order/2563) and One-time sponsors
- Ryosuke Tamura - $30
evmin - $5
- tatoosh11 - $10
[@yeojoy](https://twitter.com/yeojoy) - $5
- Alexander Borovkov - $10
Scotia Draven - $5
- spoonhoop - $5
- Drew Williams - $2
- Andy Shaw - $2
- mysafesky -$2
---
## Backers via Bountysource
https://salt.bountysource.com/teams/boostnote
- Kuzz - $65
- Intense Raiden - $45
- ravy22 - $25
- trentpolack - $20
- hikariru - $10
- kolchan11 - $10
- RonWalker22 - $10
- hocchuc - $5
- Adam - $5
- Steve - $5
- evmin - $5

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react'
import PropTypes from 'prop-types'
import React from 'react'
import _ from 'lodash'
import CodeMirror from 'codemirror'
import path from 'path'
@@ -67,7 +68,7 @@ export default class CodeEditor extends React.Component {
if (cm.somethingSelected()) cm.indentSelection('add')
else {
const tabs = cm.getOption('indentWithTabs')
if (line.trimLeft() === '- ' || line.trimLeft() === '* ' || line.trimLeft() === '+ ') {
if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)\] )?$/)) {
cm.execCommand('goLineStart')
if (tabs) {
cm.execCommand('insertTab')
@@ -103,13 +104,14 @@ export default class CodeEditor extends React.Component {
this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme')
const editorTheme = document.getElementById('editorTheme')
editorTheme.addEventListener('load', this.loadStyleHandler)
CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor)
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
CodeMirror.Vim.map('ZZ', ':q', 'normal')
}
quitEditor () {
@@ -120,7 +122,7 @@ export default class CodeEditor extends React.Component {
this.editor.off('blur', this.blurHandler)
this.editor.off('change', this.changeHandler)
this.editor.off('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme')
const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler)
}
@@ -196,7 +198,7 @@ export default class CodeEditor extends React.Component {
}
setValue (value) {
let cursor = this.editor.getCursor()
const cursor = this.editor.getCursor()
this.editor.setValue(value)
this.editor.setCursor(cursor)
}
@@ -213,9 +215,7 @@ export default class CodeEditor extends React.Component {
}
insertImageMd (imageMd) {
const textarea = this.editor.getInputField()
const cm = this.editor
cm.replaceSelection(`${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`)
this.editor.replaceSelection(imageMd)
}
handlePaste (editor, e) {
@@ -223,7 +223,7 @@ export default class CodeEditor extends React.Component {
if (!dataTransferItem.type.match('image')) return
const blob = dataTransferItem.getAsFile()
let reader = new FileReader()
const reader = new FileReader()
let base64data
reader.readAsDataURL(blob)
@@ -243,7 +243,8 @@ export default class CodeEditor extends React.Component {
}
render () {
let { className, fontFamily, fontSize } = this.props
const { className, fontSize } = this.props
let fontFamily = this.props.className
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
? [fontFamily].concat(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 styles from './MarkdownEditor.styl'
import CodeEditor from 'browser/components/CodeEditor'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import eventEmitter from 'browser/main/lib/eventEmitter'
import { findStorage } from 'browser/lib/findStorage'
const _ = require('lodash')
class MarkdownEditor extends React.Component {
constructor (props) {
@@ -70,9 +70,9 @@ class MarkdownEditor extends React.Component {
}
handleContextMenu (e) {
let { config } = this.props
const { config } = this.props
if (config.editor.switchPreview === 'RIGHTCLICK') {
let newStatus = this.state.status === 'PREVIEW'
const newStatus = this.state.status === 'PREVIEW'
? 'CODE'
: 'PREVIEW'
this.setState({
@@ -91,9 +91,9 @@ class MarkdownEditor extends React.Component {
handleBlur (e) {
if (this.state.isLocked) return
this.setState({ keyPressed: new Set() })
let { config } = this.props
const { config } = this.props
if (config.editor.switchPreview === 'BLUR') {
let cursorPosition = this.refs.code.editor.getCursor()
const cursorPosition = this.refs.code.editor.getCursor()
this.setState({
status: 'PREVIEW'
}, () => {
@@ -109,7 +109,7 @@ class MarkdownEditor extends React.Component {
}
handlePreviewMouseUp (e) {
let { config } = this.props
const { config } = this.props
if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) {
this.setState({
status: 'CODE'
@@ -123,15 +123,15 @@ class MarkdownEditor extends React.Component {
handleCheckboxClick (e) {
e.preventDefault()
e.stopPropagation()
let idMatch = /checkbox-([0-9]+)/
let checkedMatch = /\[x\]/i
let uncheckedMatch = /\[ \]/
const idMatch = /checkbox-([0-9]+)/
const checkedMatch = /\[x\]/i
const uncheckedMatch = /\[ \]/
if (idMatch.test(e.target.getAttribute('id'))) {
let lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
let lines = this.refs.code.value
const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
const lines = this.refs.code.value
.split('\n')
let targetLine = lines[lineIndex]
const targetLine = lines[lineIndex]
if (targetLine.match(checkedMatch)) {
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
@@ -163,12 +163,12 @@ class MarkdownEditor extends React.Component {
}
handleKeyDown (e) {
let { config } = this.props
const { config } = this.props
if (this.state.status !== 'CODE') return false
const keyPressed = this.state.keyPressed
keyPressed.add(e.keyCode)
this.setState({ keyPressed })
let isNoteHandlerKey = (el) => { return keyPressed.has(el) }
const isNoteHandlerKey = (el) => { return keyPressed.has(el) }
// These conditions are for ctrl-e and ctrl-w
if (keyPressed.size === this.escapeFromEditor.length &&
!this.state.isLocked && this.state.status === 'CODE' &&
@@ -207,14 +207,14 @@ class MarkdownEditor extends React.Component {
}
render () {
let { className, value, config, storageKey } = this.props
const { className, value, config, storageKey } = this.props
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let previewStyle = {}
const previewStyle = {}
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
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 _ from 'lodash'
import CodeMirror from 'codemirror'
@@ -33,6 +34,15 @@ function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber) {
font-weight: normal;
text-rendering: optimizeLegibility;
}
@font-face {
font-family: 'Lato';
src: url('${appPath}/resources/fonts/Lato-Black.woff2') format('woff2'), /* Modern Browsers */
url('${appPath}/resources/fonts/Lato-Black.woff') format('woff'), /* Modern Browsers */
url('${appPath}/resources/fonts/Lato-Black.ttf') format('truetype');
font-style: normal;
font-weight: 700;
text-rendering: optimizeLegibility;
}
${markdownStyle}
body {
font-family: '${fontFamily.join("','")}';
@@ -117,10 +127,10 @@ export default class MarkdownPreview extends React.Component {
e.preventDefault()
e.stopPropagation()
let anchor = e.target.closest('a')
let href = anchor.getAttribute('href')
const anchor = e.target.closest('a')
const href = anchor.getAttribute('href')
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) {
this.getWindow().scrollTo(0, targetElement.offsetTop)
}
@@ -242,7 +252,8 @@ export default class MarkdownPreview extends React.Component {
}
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].concat(defaultFontFamily)
: defaultFontFamily
@@ -258,7 +269,9 @@ export default class MarkdownPreview extends React.Component {
theme = consts.THEMES.some((_theme) => _theme === theme) && theme !== 'default'
? theme
: 'elegant'
this.getWindow().document.getElementById('codeTheme').href = `${appPath}/node_modules/codemirror/theme/${theme.split(' ')[0]}.css`
this.getWindow().document.getElementById('codeTheme').href = theme.startsWith('solarized')
? `${appPath}/node_modules/codemirror/theme/solarized.css`
: `${appPath}/node_modules/codemirror/theme/${theme}.css`
}
rewriteIframe () {
@@ -273,7 +286,8 @@ export default class MarkdownPreview extends React.Component {
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)
@@ -316,7 +330,7 @@ export default class MarkdownPreview extends React.Component {
let syntax = CodeMirror.findModeByName(el.className)
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
CodeMirror.requireMode(syntax.mode, () => {
let content = htmlTextHelper.decodeEntities(el.innerHTML)
const content = htmlTextHelper.decodeEntities(el.innerHTML)
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.onclick = (e) => {
@@ -341,7 +355,7 @@ export default class MarkdownPreview extends React.Component {
})
})
})
let opts = {}
const opts = {}
// if (this.props.theme === 'dark') {
// opts['font-color'] = '#DDD'
// opts['line-color'] = '#DDD'
@@ -351,7 +365,7 @@ export default class MarkdownPreview extends React.Component {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.flowchart'), (el) => {
Raphael.setWindow(this.getWindow())
try {
let diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML))
const diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML))
el.innerHTML = ''
diagram.drawSVG(el, opts)
_.forEach(el.querySelectorAll('a'), (el) => {
@@ -367,7 +381,7 @@ export default class MarkdownPreview extends React.Component {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.sequence'), (el) => {
Raphael.setWindow(this.getWindow())
try {
let diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML))
const diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML))
el.innerHTML = ''
diagram.drawSVG(el, {theme: 'simple'})
_.forEach(el.querySelectorAll('a'), (el) => {
@@ -390,11 +404,11 @@ export default class MarkdownPreview extends React.Component {
}
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++) {
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) {
block = blocks[index - 1]
block != null && this.getWindow().scrollTo(0, block.offsetTop)
@@ -424,7 +438,7 @@ export default class MarkdownPreview extends React.Component {
}
render () {
let { className, style, tabIndex } = this.props
const { className, style, tabIndex } = this.props
return (
<iframe className={className != null
? '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 styles from './ModalEscButton.styl'

View File

@@ -1,7 +1,8 @@
/**
* @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 CSSModules from 'browser/lib/CSSModules'

View File

@@ -10,6 +10,9 @@
line-height 32px
padding 0
body[data-theme="white"]
navWhiteButtonColor()
body[data-theme="dark"]
.navToggle
&:hover

View File

@@ -1,7 +1,8 @@
/**
* @fileoverview Note item component.
*/
import React, { PropTypes } from 'react'
import PropTypes from 'prop-types'
import React from 'react'
import { isArray } from 'lodash'
import CSSModules from 'browser/lib/CSSModules'
import { getTodoStatus } from 'browser/lib/getTodoStatus'
@@ -70,7 +71,7 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont
<div styleName='item-bottom-time'>{dateDisplay}</div>
{note.isStarred
? <i styleName='item-star' className='fa fa-star' /> : ''
? <img styleName='item-star' src='../resources/icon/icon-starred.svg' /> : ''
}
{note.isPinned && !pathname.match(/\/home|\/starred|\/trash/)
? <i styleName='item-pin' className='fa fa-thumb-tack' /> : ''

View File

@@ -11,9 +11,9 @@ $control-height = 30px
user-select none
cursor pointer
background-color $ui-noteList-backgroundColor
transition background-color 0.2s
transition 0.2s
&:hover
background-color alpha($ui-button--active-backgroundColor, 40%)
background-color alpha($ui-button--active-backgroundColor, 20%)
.item-title
.item-title-icon
.item-bottom-time
@@ -25,7 +25,7 @@ $control-height = 30px
.item-star
color $ui-favorite-star-button-color
&:active
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
.item-title
.item-title-icon
@@ -43,7 +43,7 @@ $control-height = 30px
.item--active
@extend .item
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 60%)
color $ui-text-color
.item-title
.item-title-empty
@@ -59,12 +59,12 @@ $control-height = 30px
.item-star
color $ui-favorite-star-button-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
background-color alpha($ui-button--active-backgroundColor, 40%)
color #e74c3c
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
background-color alpha($ui-button--active-backgroundColor, 40%)
color #e74c3c
.menu-button-label
color $ui-text-color
@@ -73,14 +73,16 @@ $control-height = 30px
position relative
font-size 12px
color $ui-inactive-text-color
top 2px
.item-title
font-size 14px
font-size 15px
font-weight 700
position relative
top -12px
left 20px
padding-right 15px
padding-bottom 4px
padding 0px 15px 0px 0px
margin-bottom 4px
overflow ellipsis
color $ui-inactive-text-color
@@ -91,7 +93,7 @@ $control-height = 30px
.item-bottom
position relative
bottom 0px
margin-top 2px
margin-top 10px
font-size 12px
line-height 20px
overflow ellipsis
@@ -100,19 +102,17 @@ $control-height = 30px
.item-bottom-tagList
flex 1
overflow ellipsis
line-height 20px
padding-top 7px
line-height 25px
padding-left 2px
margin-right 27px
margin-right 40px
.item-bottom-tagList-item
font-size 11px
margin-right 8px
padding 0
height 20px
box-sizing border-box
border-radius 2px
padding 1px 2px
padding 4px
vertical-align middle
background-color white
color $ui-inactive-text-color
@@ -125,10 +125,10 @@ $control-height = 30px
.item-star
position absolute
right -20px
bottom 2px
width 34px
height 34px
right -6px
bottom 23px
width 16px
height 16px
color alpha($ui-favorite-star-button-color, 60%)
font-size 12px
padding 0
@@ -136,8 +136,8 @@ $control-height = 30px
.item-pin
position absolute
right -21px
bottom 28px
right 0px
bottom 2px
width 34px
height 34px
color #E54D42
@@ -145,6 +145,20 @@ $control-height = 30px
padding 0
border-radius 17px
body[data-theme="white"]
.item
background-color $ui-white-noteList-backgroundColor
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
&:active
background-color $ui-button--active-backgroundColor
.item--active
@extend .item
background-color $ui-button--active-backgroundColor
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor
@@ -196,7 +210,7 @@ body[data-theme="dark"]
background-color alpha(white, 10%)
color $ui-dark-text-color
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
color #c0392b
.item-bottom-tagList-item
background-color alpha(#fff, 20%)

View File

@@ -1,7 +1,8 @@
/**
* @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 styles from './NoteItemSimple.styl'

View File

@@ -11,15 +11,15 @@ $control-height = 30px
user-select none
cursor pointer
background-color $ui-noteList-backgroundColor
transition background-color 0.15s
transition 0.2s
&:hover
background-color alpha($ui-button--active-backgroundColor, 40%)
background-color alpha($ui-button--active-backgroundColor, 20%)
.item-simple-title
.item-simple-title-empty
.item-simple-title-icon
color $ui-text-color
&:active
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
.item-simple-title
.item-simple-title-empty
@@ -28,7 +28,7 @@ $control-height = 30px
.item-simple--active
@extend .item-simple
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 60%)
color $ui-text-color
.item-simple-title
.item-simple-title-empty
@@ -37,12 +37,12 @@ $control-height = 30px
.item-simple-title-icon
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
background-color alpha($ui-button--active-backgroundColor, 40%)
color #e74c3c
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
background-color alpha($ui-button--active-backgroundColor, 40%)
color #e74c3c
.menu-button-label
color $ui-text-color
@@ -67,6 +67,20 @@ $control-height = 30px
font-weight normal
color $ui-inactive-text-color
body[data-theme="white"]
.item-simple
background-color $ui-white-noteList-backgroundColor
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
&:active
background-color $ui-button--active-backgroundColor
.item-simple--active
@extend .item-simple
background-color $ui-button--active-backgroundColor
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor
@@ -115,7 +129,7 @@ body[data-theme="dark"]
background-color alpha(white, 10%)
color $ui-dark-text-color
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
color #c0392b
.item-simple-bottom-tagList-item
background-color alpha(#fff, 20%)

View File

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

View File

@@ -1,7 +1,8 @@
/**
* @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 styles from './SideNavFilter.styl'
@@ -15,27 +16,53 @@ import styles from './SideNavFilter.styl'
*/
const SideNavFilter = ({
isFolded, isHomeActive, handleAllNotesButtonClick,
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote,
counterTotalNote, counterStarredNote
}) => (
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
onClick={handleAllNotesButtonClick}
>
<i className='fa fa-archive fa-fw' />
<div styleName='iconWrap'>
<img src={isHomeActive
? '../resources/icon/icon-all-active.svg'
: '../resources/icon/icon-all.svg'
}
/>
</div>
<span styleName='menu-button-label'>All Notes</span>
<span styleName='counters'>{counterTotalNote}</span>
</button>
<button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'}
onClick={handleStarredButtonClick}
>
<i className='fa fa-star fa-fw' />
<div styleName='iconWrap'>
<img src={isStarredActive
? '../resources/icon/icon-star-active.svg'
: '../resources/icon/icon-star.svg'
}
/>
</div>
<span styleName='menu-button-label'>Starred</span>
<span styleName='counters'>{counterStarredNote}</span>
</button>
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
onClick={handleTrashedButtonClick}
>
<i className='fa fa-trash fa-fw' />
<div styleName='iconWrap'>
<img src={isTrashedActive
? '../resources/icon/icon-trash-active.svg'
: '../resources/icon/icon-trash.svg'
}
/>
</div>
<span styleName='menu-button-label'>Trash</span>
<span styleName='counters'>{counterDelNote}</span>
</button>
</div>
)

View File

@@ -3,49 +3,55 @@
.menu-button
navButtonColor()
height 32px
padding 0 15px
font-size 13px
height 36px
padding 0 15px 0 20px
font-size 14px
width 100%
text-align left
overflow ellipsis
display flex
align-items center
&:hover, &:active, &:active:hover
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.iconWrap
width 20px
text-align center
.counters
float right
color $ui-inactive-text-color
.menu-button--active
@extend .menu-button
color #e74c3c
background-color $ui-button--active-backgroundColor
.menu-button-label
color $ui-text-color
SideNavFilter()
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.menu-button-label, .counters
color #1EC38B
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
color #1EC38B
.menu-button-star--active
@extend .menu-button
color #F9BF3B
background-color $ui-button--active-backgroundColor
.menu-button-label
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
SideNavFilter()
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.menu-button-label, .counters
color #1EC38B
.menu-button-trash--active
@extend .menu-button
SideNavFilter()
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.menu-button-label, .counters
color #1EC38B
.menu-button-label
margin-left 5px
margin-left 10px
flex 1
.menu--folded
@extend .menu
@@ -54,6 +60,10 @@
&:hover .menu-button-label
transition opacity 0.15s
opacity 1
color $ui-tooltip-text-color
background-color $ui-tooltip-backgroundColor
.menu-button-label
position fixed
display inline-block
@@ -63,15 +73,73 @@
margin-top -8px
margin-left 0
overflow ellipsis
background-color $ui-tooltip-backgroundColor
z-index 10
color white
line-height 32px
border-top-right-radius 2px
border-bottom-right-radius 2px
pointer-events none
opacity 0
font-size 13px
.counters
display none
body[data-theme="white"]
.menu-button
navWhiteButtonColor()
.counters
color $ui-inactive-text-color
.menu-button--active
@extend .menu-button
color #e74c3c
background-color $ui-button--active-backgroundColor
.menu-button-label
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
.menu-button-star--active
@extend .menu-button
color #F9BF3B
background-color $ui-button--active-backgroundColor
.menu-button-label
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
.menu-button-trash--active
@extend .menu-button
color #5D9E36
background-color $ui-button--active-backgroundColor
.menu-button-label
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #5D9E36
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color alpha($ui-button--active-backgroundColor, 50%)
color #5D9E36
.menu-button-label
color $ui-text-color
body[data-theme="dark"]
.menu-button
@@ -103,3 +171,14 @@ body[data-theme="dark"]
color $ui-favorite-star-button-color
.menu-button-label
color $ui-dark-text-color
.menu-button-trash--active
color #5D9E36
background-color $ui-dark-button--active-backgroundColor
.menu-button-label
color $ui-dark-text-color
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
color #5D9E36
.menu-button-label
color $ui-dark-text-color

View File

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

View File

@@ -1,7 +1,8 @@
/**
* @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 CSSModules from 'browser/lib/CSSModules'
import { isNumber } from 'lodash'

View File

@@ -5,32 +5,31 @@
.folderList-item
display flex
width 100%
height 26px
height 34px
background-color transparent
color $ui-inactive-text-color
padding 0
margin-bottom 5px
text-align left
border none
overflow ellipsis
font-size 13px
font-size 14px
&:first-child
margin-top 0
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
color #1EC38B;
background-color alpha($ui-button-default--active-backgroundColor, 20%)
transition background-color 0.15s
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
color $$ui-button-default-color
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.folderList-item--active
@extend .folderList-item
color $ui-text-color
background-color $ui-button--active-backgroundColor
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 50%)
color #1EC38B;
background-color alpha($ui-button-default--active-backgroundColor, 50%)
.folderList-item-name
display block
@@ -69,8 +68,28 @@
.folderList-item-name--folded
@extend .folderList-item-name
padding-left 12px
padding-left 17px
text
display none
body[data-theme="white"]
.folderList-item
color $ui-inactive-text-color
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
transition background-color 0.15s
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
.folderList-item--active
@extend .folderList-item
color $ui-text-color
background-color $ui-button--active-backgroundColor
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 50%)
body[data-theme="dark"]
.folderList-item

View File

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

View File

@@ -1,7 +1,7 @@
.storageList
absolute left right
bottom 37px
top 160px
top 180px
overflow-y auto
.storageList-empty

View File

@@ -1,7 +1,8 @@
/**
* @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 CSSModules from 'browser/lib/CSSModules'

View File

@@ -13,15 +13,15 @@
&:first-child
margin-top 0
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
color $ui-button-default-color
background-color alpha($ui-button-default--active-backgroundColor, 20%)
transition background-color 0.15s
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
&:active, &:active:hover
color $ui-button-default-color
background-color $ui-button-default--active-backgroundColor
.tagList-item-active
background-color $ui-button--active-backgroundColor
background-color $ui-button-default--active-backgroundColor
display flex
width 100%
height 26px
@@ -31,8 +31,9 @@
border none
overflow ellipsis
font-size 13px
color $ui-button-default-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
background-color alpha($ui-button-default--active-backgroundColor, 60%)
transition 0.2s
.tagList-item-name
@@ -47,6 +48,22 @@
overflow hidden
text-overflow ellipsis
body[data-theme="white"]
.tagList-item
color $ui-inactive-text-color
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
.tagList-item-active
background-color $ui-button--active-backgroundColor
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
body[data-theme="dark"]
.tagList-item
color $ui-dark-inactive-text-color

View File

@@ -2,7 +2,8 @@
* @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 styles from './TodoListPercentage.styl'

View File

@@ -1,24 +1,25 @@
.percentageBar
position absolute
top 58px
right: 0px
top 50px
right 0px
left 0px
background-color #DADFE1
width 100%
height: 15px
height: 17px
font-size: 12px
z-index 100
border-radius 2px
.progressBar
background-color: #6C7A89
height 15px
background-color: #1EC38B
height 17px
border-radius 2px
transition 0.3s
transition 0.4s cubic-bezier(0.4, 0.4, 0, 1)
.percentageText
color #f4f4f4
padding: 2px 43%
font-weight 600
body[data-theme="dark"]
.percentageBar

View File

@@ -2,7 +2,8 @@
* @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 styles from './TodoProcess.styl'

View File

@@ -118,7 +118,7 @@ hr
h1, h2, h3, h4, h5, h6
font-weight bold
h1
font-size 2.25em
font-size 2.55em
padding-bottom 0.3em
line-height 1.2em
border-bottom solid 1px borderColor

View File

@@ -64,7 +64,7 @@ $list-width = 250px
.result-nav-storageList
absolute bottom left right
top 110px + 32px + 10px + 10px
top 110px + 32px + 10px + 10px + 20px
overflow-y auto
.result-list

View File

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

View File

@@ -18,18 +18,18 @@ class NoteList extends React.Component {
}
componentDidUpdate () {
let { index } = this.props
const { index } = this.props
if (index > -1) {
let list = this.refs.root
let item = list.childNodes[index]
const list = this.refs.root
const item = list.childNodes[index]
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) {
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
}
let overflowAbove = list.scrollTop > item.offsetTop
const overflowAbove = list.scrollTop > item.offsetTop
if (overflowAbove) {
list.scrollTop = item.offsetTop
}
@@ -44,7 +44,7 @@ class NoteList extends React.Component {
}
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) {
this.setState({
@@ -54,9 +54,9 @@ class NoteList extends React.Component {
}
render () {
let { notes, index } = this.props
const { notes, index } = this.props
let notesList = notes
const notesList = notes
.slice(0, 10 + 10 * this.state.range)
.map((note, _index) => {
const isActive = (index === _index)

View File

@@ -19,18 +19,18 @@ class StorageSection extends React.Component {
}
handleHeaderClick (e) {
let { storage } = this.props
const { storage } = this.props
this.props.handleStorageButtonClick(e, storage.key)
}
handleFolderClick (e, folder) {
let { storage } = this.props
const { storage } = this.props
this.props.handleFolderButtonClick(e, storage.key, folder.key)
}
render () {
let { storage, filter } = this.props
let folderList = storage.folders
const { storage, filter } = this.props
const folderList = storage.folders
.map(folder => (
<StorageItem
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 { connect, Provider } from 'react-redux'
import _ from 'lodash'
import ipc from './ipcClient'
import store from './store'
import CSSModules from 'browser/lib/CSSModules'
import styles from './FinderMain.styl'
@@ -19,7 +19,7 @@ const { remote } = electron
const { Menu } = remote
function hideFinder () {
let finderWindow = remote.getCurrentWindow()
const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'win32') {
finderWindow.blur()
finderWindow.hide()
@@ -136,7 +136,7 @@ class FinderMain extends React.Component {
}
handleOnlySnippetCheckboxChange (e) {
let { filter } = this.state
const { filter } = this.state
filter.includeSnippet = e.target.checked
this.setState({
filter: filter,
@@ -147,7 +147,7 @@ class FinderMain extends React.Component {
}
handleOnlyMarkdownCheckboxChange (e) {
let { filter } = this.state
const { filter } = this.state
filter.includeMarkdown = e.target.checked
this.refs.list.resetScroll()
this.setState({
@@ -159,7 +159,7 @@ class FinderMain extends React.Component {
}
handleAllNotesButtonClick (e) {
let { filter } = this.state
const { filter } = this.state
filter.type = 'ALL'
this.refs.list.resetScroll()
this.setState({
@@ -171,7 +171,7 @@ class FinderMain extends React.Component {
}
handleStarredButtonClick (e) {
let { filter } = this.state
const { filter } = this.state
filter.type = 'STARRED'
this.refs.list.resetScroll()
this.setState({
@@ -183,7 +183,7 @@ class FinderMain extends React.Component {
}
handleStorageButtonClick (e, storage) {
let { filter } = this.state
const { filter } = this.state
filter.type = 'STORAGE'
filter.storage = storage
this.refs.list.resetScroll()
@@ -196,7 +196,7 @@ class FinderMain extends React.Component {
}
handleFolderButtonClick (e, storage, folder) {
let { filter } = this.state
const { filter } = this.state
filter.type = 'FOLDER'
filter.storage = storage
filter.folder = folder
@@ -218,12 +218,12 @@ class FinderMain extends React.Component {
}
render () {
let { data, config } = this.props
let { filter, search } = this.state
let storageList = []
for (let key in data.storageMap) {
let storage = data.storageMap[key]
let item = (
const { data, config } = this.props
const { filter, search } = this.state
const storageList = []
for (const key in data.storageMap) {
const storage = data.storageMap[key]
const item = (
<StorageSection
filter={filter}
storage={storage}
@@ -252,7 +252,7 @@ class FinderMain extends React.Component {
notes.push(data.noteMap[id])
})
} else {
for (let key in data.noteMap) {
for (const key in data.noteMap) {
notes.push(data.noteMap[key])
}
}
@@ -264,13 +264,13 @@ class FinderMain extends React.Component {
}
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
.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
return (

View File

@@ -10,7 +10,7 @@ nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
function killFinder () {
let finderWindow = remote.getCurrentWindow()
const finderWindow = remote.getCurrentWindow()
finderWindow.removeAllListeners()
if (global.process.platform === 'darwin') {
// Only OSX has another app process.
@@ -21,7 +21,7 @@ function killFinder () {
}
function toggleFinder () {
let finderWindow = remote.getCurrentWindow()
const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'darwin') {
if (finderWindow.isVisible()) {
finderWindow.hide()
@@ -84,6 +84,8 @@ nodeIpc.connectTo(
const { config } = payload
if (config.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark')
} else if (config.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white')
} else {
document.body.setAttribute('data-theme', 'default')
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,11 +3,12 @@ import emoji from 'markdown-it-emoji'
import math from '@rokt33r/markdown-it-math'
import _ from 'lodash'
// FIXME We should not depend on global variable.
const katex = window.katex
function createGutter (str) {
let lc = (str.match(/\n/g) || []).length
let lines = []
const lc = (str.match(/\n/g) || []).length
const lines = []
for (let i = 1; i <= lc; i++) {
lines.push('<span class="CodeMirror-linenumber">' + i + '</span>')
}
@@ -75,8 +76,8 @@ md.use(require('markdown-it-plantuml'))
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token
let nextLine = startLine + 1
let terminatorRules = state.md.block.ruler.getRules('paragraph')
let endLine = state.lineMax
const terminatorRules = state.md.block.ruler.getRules('paragraph')
const endLine = state.lineMax
// jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
@@ -106,7 +107,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
token.map = [ startLine, state.line ]
if (state.parentType === 'list') {
let match = content.match(/^\[( |x)\] ?(.+)/i)
const match = content.match(/^\[( |x)\] ?(.+)/i)
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>`
}
@@ -123,7 +124,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
})
// Add line number attribute for scrolling
let originalRender = md.renderer.render
const originalRender = md.renderer.render
md.renderer.render = function render (tokens, options, env) {
tokens.forEach((token) => {
switch (token.type) {
@@ -134,40 +135,12 @@ md.renderer.render = function render (tokens, options, env) {
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
}
// FIXME We should not depend on global variable.
window.md = md
function strip (input) {
var output = input
try {
output = output
.replace(/^([\s\t]*)([\*\-\+]|\d\.)\s+/gm, '$1')
.replace(/\n={2,}/g, '\n')
.replace(/~~/g, '')
.replace(/`{3}.*\n/g, '')
.replace(/<(.*?)>/g, '$1')
.replace(/^[=\-]{2,}\s*$/g, '')
.replace(/\[\^.+?\](: .*?$)?/g, '')
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
.replace(/>/g, '')
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
.replace(/([\*_]{1,3})(\S.*?\S)\1/g, '$2')
.replace(/(`{3,})(.*?)\1/gm, '$2')
.replace(/^-{3,}\s*$/g, '')
.replace(/`(.+?)`/g, '$1')
.replace(/\n{2,}/g, '\n\n')
} catch (e) {
console.error(e)
return input
}
return output
}
function normalizeLinkText (linkText) {
return md.normalizeLinkText(linkText)
}
@@ -178,7 +151,7 @@ const markdown = {
const renderedContent = md.render(content)
return renderedContent
},
strip,
normalizeLinkText
}
export default markdown

View File

@@ -0,0 +1,39 @@
/**
* @fileoverview Text trimmer for markdown note.
*/
/**
* @param {string} input
* @return {string}
*/
export function strip (input) {
let output = input
try {
output = output
.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, '$1')
.replace(/\n={2,}/g, '\n')
.replace(/~~/g, '')
.replace(/`{3}.*\n/g, '')
.replace(/<(.*?)>/g, '$1')
.replace(/^[=\-]{2,}\s*$/g, '')
.replace(/\[\^.+?\](: .*?$)?/g, '')
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
.replace(/>/g, '')
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
.replace(/(`{3,})(.*?)\1/gm, '$2')
.replace(/^-{3,}\s*$/g, '')
.replace(/`(.+?)`/g, '$1')
.replace(/\n{2,}/g, '\n\n')
} catch (e) {
console.error(e)
return input
}
return output
}
export default {
strip
}

View File

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

View File

@@ -1,5 +1,8 @@
.root
absolute top bottom right
display flex
align-items center
justify-content center
.empty
height 320px
@@ -8,8 +11,9 @@
.empty-message
width 100%
font-size 42px
line-height 72px
font-size 36px
font-weight 600
line-height 56px
text-align center
color $ui-inactive-text-color

View File

@@ -3,7 +3,9 @@
*/
// Margin on the left side and the right side for NoteDetail component.
$note-detail-left-margin = 25px
$note-detail-right-margin = 25px
$note-detail-left-margin = 100px
$note-detail-right-margin = 120px
$snippet-note-detail-left-margin = 60px
$snippet-note-detail-right-margin = 80px
$note-detail-box-shadow = 2px 0 15px -8px #b1b1b1 inset

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 styles from './FolderSelect.styl'
import _ from 'lodash'
@@ -73,8 +74,8 @@ class FolderSelect extends React.Component {
case 9:
if (e.shiftKey) {
e.preventDefault()
let 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 tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])')
const previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1]
if (previousEl != null) previousEl.focus()
}
}
@@ -89,9 +90,9 @@ class FolderSelect extends React.Component {
}
handleSearchInputChange (e) {
let { folders } = this.props
let search = this.refs.search.value
let optionIndex = search.length > 0
const { folders } = this.props
const search = this.refs.search.value
const optionIndex = search.length > 0
? _.findIndex(folders, (folder) => {
return folder.name.match(new RegExp('^' + _.escapeRegExp(search), 'i'))
})
@@ -129,7 +130,7 @@ class FolderSelect extends React.Component {
nextOption () {
let { optionIndex } = this.state
let { folders } = this.props
const { folders } = this.props
optionIndex++
if (optionIndex >= folders.length) optionIndex = 0
@@ -140,7 +141,7 @@ class FolderSelect extends React.Component {
}
previousOption () {
let { folders } = this.props
const { folders } = this.props
let { optionIndex } = this.state
optionIndex--
@@ -152,10 +153,10 @@ class FolderSelect extends React.Component {
}
selectOption () {
let { folders } = this.props
let optionIndex = this.state.optionIndex
const { folders } = this.props
const optionIndex = this.state.optionIndex
let folder = folders[optionIndex]
const folder = folders[optionIndex]
if (folder != null) {
this.setState({
status: 'FOCUS'
@@ -184,10 +185,10 @@ class FolderSelect extends React.Component {
}
render () {
let { className, data, value } = this.props
let splitted = value.split('-')
let storageKey = splitted.shift()
let folderKey = splitted.shift()
const { className, data, value } = this.props
const splitted = value.split('-')
const storageKey = splitted.shift()
const folderKey = splitted.shift()
let options = []
data.storageMap.forEach((storage, index) => {
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) {
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))
}
let optionList = options
const optionList = options
.map((option, index) => {
return (
<div styleName={index === this.state.optionIndex
@@ -259,12 +260,11 @@ class FolderSelect extends React.Component {
{optionList}
</div>
</div>
: <div styleName='idle'>
: <div styleName='idle' style={{color: currentOption.folder.color}}>
<div styleName='idle-label'>
<span styleName='idle-label-name'
style={{color: currentOption.folder.color}}
>
{currentOption.folder.name} /
<i className='fa fa-folder' />
<span styleName='idle-label-name'>
{currentOption.folder.name}
</span>
</div>
</div>

View File

@@ -1,21 +1,22 @@
.root
position relative
border solid 1px transparent
line-height 26px
vertical-align middle
border-radius 2px
transition 0.15s
user-select none
margin-right 10px
&:hover
background-color $ui-button--hover-backgroundColor
.root--search, .root--focus
@extend .root
background-color $ui-noteDetail-backgroundColor = #F4F4F4
background-color $ui-noteDetail-backgroundColor = #fff
border-color $ui-input--focus-borderColor
width 100px
width 154px
height 30px
&:hover
border-color $ui-input--focus-borderColor
border-color $ui-input--focus-borderColor = #fff
.idle
position relative
@@ -24,13 +25,16 @@
.idle-label
right 20px
overflow ellipsis
display flex
align-items center
.idle-label-name
font-size 14px
padding 2px
font-size 13px
font-weight 600
margin-left 4px
.idle-label-name-surfix
font-size 10px
font-size 15px
color $ui-inactive-text-color
margin-left 5px
.idle-caret
@@ -38,40 +42,42 @@
height 34px
width 20px
line-height 34px
.search
absolute top left right bottom
line-height 34px
.search-input
vertical-align middle
position relative
top -2px
top 0
font-size 14px
outline none
border none
height 20px
line-height 20px
width 100%
background-color transparent
padding 0 10px
.search-optionList
position fixed
position absolute
top 30px
max-height 450px
min-width 150px
overflow auto
z-index 200
border $ui-border
background-color white
border-radius 2px
padding 10px 6px
.search-optionList-item
width 140px
height 34px
width 250px
display flex
align-items center
box-sizing border-box
padding 0 5px
padding 0
margin-bottom 10px
overflow ellipsis
cursor pointer
&:hover
background-color $ui-button--hover-backgroundColor
background-color $ui-button--hover-backgroundColor
.search-optionList-item--active
@extend .search-optionList-item
@@ -81,13 +87,17 @@
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
.search-optionList-item-name
border-left solid 2px transparent
padding 2px 5px
border-left solid 3px transparent
padding 6px
.search-optionList-item-name-surfix
font-size 10px
color $ui-inactive-text-color
margin-left 5px
body[data-theme="dark"]
.root
color $ui-dark-text-color

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 styles from './InfoButton.styl'
@@ -6,9 +7,9 @@ const InfoButton = ({
onClick
}) => (
<button styleName='control-infoButton'
onClick={onClick}
onClick={(e) => onClick(e)}
>
<i className='fa fa-info infoButton' styleName='info-button' />
<img className='infoButton' src='../resources/icon/icon-info.svg' />
</button>
)

View File

@@ -1,20 +1,10 @@
.control-infoButton
float right
top 10px
margin-bottom 10px
topBarButtonLight()
.control-infoPanel
position fixed
pointer-events none
top 50px
z-index 200
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.infoButton
padding 0px
margin 15px 0
body[data-theme="dark"]
.control-infoButton

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 styles from './InfoPanel.styl'

View File

@@ -10,12 +10,12 @@
.control-infoButton-panel
z-index 200
margin-top 38px
margin-left -140px
margin-top 0px
right 0
position absolute
padding 20px 25px 0 25px
width 300px
height 500px
height 350px
overflow auto
background-color $ui-noteList-backgroundColor
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
@@ -32,8 +32,8 @@
.control-infoButton-panel-trash
z-index 200
margin-top 45px
margin-left -190px
margin-top 0px
right 0px
position absolute
padding 20px 25px 0 25px
width 300px

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 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 styles from './MarkdownNoteDetail.styl'
import MarkdownEditor from 'browser/components/MarkdownEditor'
@@ -9,12 +10,13 @@ import FolderSelect from './FolderSelect'
import dataApi from 'browser/main/lib/dataApi'
import { hashHistory } from 'react-router'
import ee from 'browser/main/lib/eventEmitter'
import markdown from 'browser/lib/markdown'
import markdown from 'browser/lib/markdownTextHelper'
import StatusBar from '../StatusBar'
import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton'
import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed'
@@ -24,7 +26,7 @@ import striptags from 'striptags'
const electron = require('electron')
const { remote } = electron
const { Menu, MenuItem, dialog } = remote
const { dialog } = remote
class MarkdownNoteDetail extends React.Component {
constructor (props) {
@@ -73,7 +75,7 @@ class MarkdownNoteDetail extends React.Component {
}
handleChange (e) {
let { note } = this.state
const { note } = this.state
note.content = this.refs.content.value
if (this.refs.tags) note.tags = this.refs.tags.value
@@ -95,7 +97,7 @@ class MarkdownNoteDetail extends React.Component {
}
saveNow () {
let { note, dispatch } = this.props
const { note, dispatch } = this.props
clearTimeout(this.saveQueue)
this.saveQueue = null
@@ -111,11 +113,11 @@ class MarkdownNoteDetail extends React.Component {
}
handleFolderChange (e) {
let { note } = this.state
let value = this.refs.folder.value
let splitted = value.split('-')
let newStorageKey = splitted.shift()
let newFolderKey = splitted.shift()
const { note } = this.state
const value = this.refs.folder.value
const splitted = value.split('-')
const newStorageKey = splitted.shift()
const newFolderKey = splitted.shift()
dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -124,7 +126,7 @@ class MarkdownNoteDetail extends React.Component {
isMovingNote: true,
note: Object.assign({}, newNote)
}, () => {
let { dispatch, location } = this.props
const { dispatch, location } = this.props
dispatch({
type: 'MOVE_NOTE',
originNote: note,
@@ -144,7 +146,7 @@ class MarkdownNoteDetail extends React.Component {
}
handleStarButtonClick (e) {
let { note } = this.state
const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred
@@ -169,22 +171,22 @@ class MarkdownNoteDetail extends React.Component {
}
handleTrashButtonClick (e) {
let { note } = this.state
const { note } = this.state
const { isTrashed } = note
if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props
const { note, dispatch } = this.props
dataApi
.deleteNote(note.storage, note.key)
.then((data) => {
let dispatchHandler = () => {
const dispatchHandler = () => {
dispatch({
type: 'DELETE_NOTE',
storageKey: data.storageKey,
@@ -206,7 +208,7 @@ class MarkdownNoteDetail extends React.Component {
}
handleUndoButtonClick (e) {
let { note } = this.state
const { note } = this.state
note.isTrashed = false
@@ -231,7 +233,7 @@ class MarkdownNoteDetail extends React.Component {
}
getToggleLockButton () {
return this.state.isLocked ? 'fa-lock' : 'fa-unlock'
return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg'
}
handleDeleteKeyDown (e) {
@@ -261,12 +263,12 @@ class MarkdownNoteDetail extends React.Component {
}
render () {
let { data, config, location } = this.props
let { note } = this.state
let storageKey = note.storage
let folderKey = note.folder
const { data, config, location } = this.props
const { note } = this.state
const storageKey = note.storage
const folderKey = note.folder
let options = []
const options = []
data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => {
options.push({
@@ -275,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'>
<div styleName='info-left'>
@@ -285,7 +287,7 @@ class MarkdownNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
@@ -302,10 +304,6 @@ class MarkdownNoteDetail extends React.Component {
const detailTopBar = <div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
@@ -325,31 +323,38 @@ class MarkdownNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<StarButton
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
{(() => {
const faClassName = `fa ${this.getToggleLockButton()}`
const imgSrc = `${this.getToggleLockButton()}`
const lockButtonComponent =
<button styleName='control-lockButton'
onFocus={(e) => this.handleFocus(e)}
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
>
<i className={faClassName} styleName='lock-button' />
<span styleName='control-lockButton-tooltip'>
{this.state.isLocked ? 'Unlock Editor' : 'Keep Editor Locked'}
</span>
<img styleName='iconInfo' src={imgSrc} />
</button>
return (
this.state.isLockButtonShown ? lockButtonComponent : ''
)
})()}
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
</button>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}

View File

@@ -3,47 +3,47 @@
.root
absolute top right bottom
border-width 0
border-left 1px solid alpha(#DEDEDE, 60%)
background-color $ui-noteDetail-backgroundColor
box-shadow $note-detail-box-shadow
box-shadow none
padding 20px 40px
.lock-button
padding-bottom 3px
.control-lockButton
top 160px
margin-bottom 10px
topBarButtonLight()
.control-lockButton-tooltip
tooltip()
position fixed
pointer-events none
top 50px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.trashed-infopanel
top 40px
position relative
.control-fullScreenButton
float right
padding 0 0 2px 0
top 80px
topBarButtonLight()
.body
absolute left right
left $note-detail-left-margin
right $note-detail-right-margin
left 0
right 0
top $info-height + $info-margin-under-border
bottom $statusBar-height
margin 0 45px
.body-noteEditor
absolute top bottom left right
body[data-theme="white"]
.root
box-shadow $note-detail-box-shadow
border none
body[data-theme="dark"]
.root
background-color $ui-dark-noteDetail-backgroundColor
box-shadow none
border none
.control-lockButton
topBarButtonDark()

View File

@@ -1,33 +1,31 @@
@import('DetailVars')
$info-height = 60px
$info-margin-under-border = 27px
$info-height = 50px
$info-margin-under-border = 30px
.info
absolute top left right
left $note-detail-left-margin
right $note-detail-right-margin
left 0
right 0
height $info-height
border-bottom $ui-border
border-bottom 1px solid #eee
background-color $ui-noteDetail-backgroundColor
width 100%
display flex
align-items center
.info-left
float left
padding 0 5px
margin 0px 2px
.info-left-top
display inline-block
height $info-height
line-height $info-height
padding 0 10px
width 100%
display flex
align-items center
.info-left-top-folderSelect
padding 0 3px
height 34px
line-height 26px
display flex
align-items center
justify-content center
border-radius 3px
.info-left-button
width 34px
height 34px
@@ -48,18 +46,18 @@ $info-margin-under-border = 27px
.info-right
position absolute
right 0
top 0
background $ui-noteDetail-backgroundColor
right 40px
top 60px
bottom 1px
padding-left 30px
z-index 101
.undo-button
width 34px
height 34px
border-radius 17px
font-size 14px
margin 15px 7px
margin 5px 0px
border none
color $ui-button-color
display flex
@@ -72,6 +70,7 @@ $info-margin-under-border = 27px
border-color $ui-button--active-backgroundColor
&:hover
background-color alpha($ui-button--hover-backgroundColor, 60%)
transition 0.2s
.control-lockButton-tooltip
opacity 1

View File

@@ -0,0 +1,20 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './TrashButton.styl'
const PermanentDeleteButton = ({
onClick
}) => (
<button styleName='control-trashButton--in-trash'
onClick={(e) => onClick(e)}
>
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
</button>
)
PermanentDeleteButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(PermanentDeleteButton, styles)

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 styles from './SnippetNoteDetail.styl'
import CodeEditor from 'browser/components/CodeEditor'
@@ -18,6 +19,7 @@ import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton'
import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed'
@@ -60,7 +62,7 @@ class SnippetNoteDetail extends React.Component {
componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
if (this.saveQueue != null) this.saveNow()
let nextNote = Object.assign({
const nextNote = Object.assign({
description: ''
}, nextProps.note, {
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
@@ -69,7 +71,7 @@ class SnippetNoteDetail extends React.Component {
snippetIndex: 0,
note: nextNote
}, () => {
let { snippets } = this.state.note
const { snippets } = this.state.note
snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload()
})
@@ -83,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
}
handleChange (e) {
let { note } = this.state
const { note } = this.state
if (this.refs.tags) note.tags = this.refs.tags.value
note.description = this.refs.description.value
@@ -105,7 +107,7 @@ class SnippetNoteDetail extends React.Component {
}
saveNow () {
let { note, dispatch } = this.props
const { note, dispatch } = this.props
clearTimeout(this.saveQueue)
this.saveQueue = null
@@ -121,11 +123,11 @@ class SnippetNoteDetail extends React.Component {
}
handleFolderChange (e) {
let { note } = this.state
let value = this.refs.folder.value
let splitted = value.split('-')
let newStorageKey = splitted.shift()
let newFolderKey = splitted.shift()
const { note } = this.state
const value = this.refs.folder.value
const splitted = value.split('-')
const newStorageKey = splitted.shift()
const newFolderKey = splitted.shift()
dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -134,7 +136,7 @@ class SnippetNoteDetail extends React.Component {
isMovingNote: true,
note: Object.assign({}, newNote)
}, () => {
let { dispatch, location } = this.props
const { dispatch, location } = this.props
dispatch({
type: 'MOVE_NOTE',
originNote: note,
@@ -154,7 +156,7 @@ class SnippetNoteDetail extends React.Component {
}
handleStarButtonClick (e) {
let { note } = this.state
const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred
@@ -171,22 +173,22 @@ class SnippetNoteDetail extends React.Component {
}
handleTrashButtonClick (e) {
let { note } = this.state
const { note } = this.state
const { isTrashed } = note
if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props
const { note, dispatch } = this.props
dataApi
.deleteNote(note.storage, note.key)
.then((data) => {
let dispatchHandler = () => {
const dispatchHandler = () => {
dispatch({
type: 'DELETE_NOTE',
storageKey: data.storageKey,
@@ -208,7 +210,7 @@ class SnippetNoteDetail extends React.Component {
}
handleUndoButtonClick (e) {
let { note } = this.state
const { note } = this.state
note.isTrashed = false
@@ -237,7 +239,7 @@ class SnippetNoteDetail extends React.Component {
handleTabDeleteButtonClick (e, index) {
if (this.state.note.snippets.length > 1) {
if (this.state.note.snippets[index].content.trim().length > 0) {
let dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
const dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete a snippet',
detail: 'This work cannot be undone.',
@@ -287,7 +289,7 @@ class SnippetNoteDetail extends React.Component {
handleModeOptionClick (index, name) {
return (e) => {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].mode = name
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
@@ -305,7 +307,7 @@ class SnippetNoteDetail extends React.Component {
handleCodeChange (index) {
return (e) => {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({
@@ -332,7 +334,7 @@ class SnippetNoteDetail extends React.Component {
break
case 76:
{
let isSuper = global.process.platform === 'darwin'
const isSuper = global.process.platform === 'darwin'
? e.metaKey
: e.ctrlKey
if (isSuper) {
@@ -343,7 +345,7 @@ class SnippetNoteDetail extends React.Component {
break
case 84:
{
let isSuper = global.process.platform === 'darwin'
const isSuper = global.process.platform === 'darwin'
? e.metaKey
: e.ctrlKey
if (isSuper) {
@@ -356,7 +358,7 @@ class SnippetNoteDetail extends React.Component {
}
handleModeButtonClick (e, index) {
let menu = new Menu()
const menu = new Menu()
CodeMirror.modeInfo.forEach((mode) => {
menu.append(new MenuItem({
label: mode.name,
@@ -397,8 +399,8 @@ class SnippetNoteDetail extends React.Component {
}
handleIndentSizeItemClick (e, indentSize) {
let { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, {
const { config, dispatch } = this.props
const editor = Object.assign({}, config.editor, {
indentSize
})
ConfigManager.set({
@@ -413,8 +415,8 @@ class SnippetNoteDetail extends React.Component {
}
handleIndentTypeItemClick (e, indentType) {
let { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, {
const { config, dispatch } = this.props
const editor = Object.assign({}, config.editor, {
indentType
})
ConfigManager.set({
@@ -433,14 +435,14 @@ class SnippetNoteDetail extends React.Component {
}
addSnippet () {
let { note } = this.state
const { note } = this.state
note.snippets = note.snippets.concat([{
name: '',
mode: 'Plain Text',
content: ''
}])
let snippetIndex = note.snippets.length - 1
const snippetIndex = note.snippets.length - 1
this.setState({
note,
@@ -486,19 +488,19 @@ class SnippetNoteDetail extends React.Component {
}
render () {
let { data, config, location } = this.props
let { note } = this.state
const { data, config, location } = this.props
const { note } = this.state
let storageKey = note.storage
let folderKey = note.folder
const storageKey = note.storage
const folderKey = note.folder
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
const tabList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
return <SnippetTab
key={index}
@@ -512,8 +514,8 @@ class SnippetNoteDetail extends React.Component {
/>
})
let viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
const viewList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
@@ -547,7 +549,7 @@ class SnippetNoteDetail extends React.Component {
</div>
})
let options = []
const options = []
data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => {
options.push({
@@ -556,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'>
<div styleName='info-left'>
@@ -566,7 +568,7 @@ class SnippetNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
@@ -583,10 +585,6 @@ class SnippetNoteDetail extends React.Component {
const detailTopBar = <div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
@@ -603,15 +601,21 @@ class SnippetNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
</button>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<StarButton
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
</button>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}

View File

@@ -3,14 +3,14 @@
.root
absolute top bottom right
border-width 0
border-left 1px solid alpha(#DEDEDE, 60%)
background-color $ui-noteDetail-backgroundColor
box-shadow $note-detail-box-shadow
box-shadow none
.body
absolute left right
left $note-detail-left-margin
right $note-detail-right-margin
left $snippet-note-detail-left-margin
right $snippet-note-detail-right-margin
top $info-height + $info-margin-under-border
bottom $statusBar-height
background-color $ui-noteDetail-backgroundColor
@@ -43,7 +43,7 @@
overflow hidden
.tabList .plusButton
navButtonColor()
navWhiteButtonColor()
width 30px
.tabView
@@ -55,24 +55,30 @@
.override
absolute bottom left
bottom 2px
bottom 1px
left 60px
height 23px
z-index 101
button
navButtonColor()
height 24px
padding 0 6px
&:hover
color $ui-active-color
&:active .update-icon
color white
color $ui-active-color
.control-fullScreenButton
float right
padding 0 0 2px 0
top 80px
margin-bottom 10px
topBarButtonLight()
body[data-theme="white"]
.root
box-shadow $note-detail-box-shadow
border none
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor
border none
background-color $ui-dark-noteDetail-backgroundColor
box-shadow none

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 styles from './StarButton.styl'
import _ from 'lodash'
@@ -31,7 +32,7 @@ class StarButton extends React.Component {
}
render () {
let { className } = this.props
const { className } = this.props
return (
<button className={_.isString(className)
@@ -47,10 +48,10 @@ class StarButton extends React.Component {
onMouseLeave={(e) => this.handleMouseLeave(e)}
onClick={this.props.onClick}
>
<i styleName='icon'
className={this.state.isActive || this.props.isActive
? 'fa fa-star'
: 'fa fa-star-o'
<img styleName='icon'
src={this.state.isActive || this.props.isActive
? '../resources/icon/icon-starred.svg'
: '../resources/icon/icon-star.svg'
}
/>
</button>

View File

@@ -1,47 +1,24 @@
.root
left 7px
top 0
padding 0
color alpha($ui-favorite-star-button-color, 60%)
top 45px
topBarButtonLight()
&:hover
transition 0.15s
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-favorite-star-button-color
&:active
transition 0.15s
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-favorite-star-button-color
transition 0.2s
color alpha($ui-favorite-star-button-color, 0.6)
.root--active
@extend .root
transition 0.15s
color $ui-favorite-star-button-color
&:hover
transition 0.15s
color $ui-favorite-star-button-color
background-color alpha($ui-button--active-backgroundColor, 40%)
&:active
transition 0.15s
color $ui-favorite-star-button-color
background-color alpha($ui-button--active-backgroundColor, 40%)
transition 0.2s
color alpha($ui-favorite-star-button-color, 0.6)
.icon
transition transform 0.15s
body[data-theme="dark"]
.root
topBarButtonDark()
&:hover
transition 0.15s
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
color $ui-favorite-star-button-color
&:active
transition 0.15s
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
color $ui-favorite-star-button-color
.root--active
@extend .root
color $ui-favorite-star-button-color
&:hover
transition 0.15s
color $ui-favorite-star-button-color
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.2s
color alpha($ui-favorite-star-button-color, 0.6)

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 styles from './TagSelect.styl'
import _ from 'lodash'
@@ -59,7 +60,7 @@ class TagSelect extends React.Component {
submitTag () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
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) {
this.setState({
@@ -101,9 +102,9 @@ class TagSelect extends React.Component {
}
render () {
let { value, className } = this.props
const { value, className } = this.props
let tagList = _.isArray(value)
const tagList = _.isArray(value)
? value.map((tag) => {
return (
<span styleName='tag'
@@ -113,7 +114,7 @@ class TagSelect extends React.Component {
<button styleName='tag-removeButton'
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
>
<i className='fa fa-times fa-fw tag-removeButton-icon' />
<img className='tag-removeButton-icon' src='../resources/icon/icon-x.svg' width='8px' />
</button>
</span>
)

View File

@@ -1,9 +1,9 @@
.root
display inline-block
display flex
align-items center
user-select none
height 23px
vertical-align middle
width 300px
width 100%
overflow-x scroll
white-space nowrap
@@ -11,51 +11,42 @@
display none
.tag
display inline-block
margin 1px 3px
padding 0
height 20px
background-color alpha($ui-tag-backgroundColor, 10%)
border-radius 3px
overflow hidden
display flex
align-items center
margin 0px 2px
padding 2px 4px
background-color alpha($ui-tag-backgroundColor, 3%)
border-radius 4px
position relative
clearfix()
.tag-removeButton
float right
height 20px
width 18px
margin 0
padding 0
border-style solid
border-width 0
border-radius 20px
line-height 18px
background-color transparent
color $ui-button-color
position absolute
right 6px
.tag-removeButton-icon
width 5px
padding-right 4px
.tag-label
font-size 11px
font-weight 600
color: alpha($ui-text-color, 80%)
float left
height 20px
line-height 20px
padding 0 6px
font-size 13px
color: $ui-text-color
padding 4px 16px 4px 8px
.newTag
display inline-block
margin 2px 0 15px 2px
vertical-align middle
height 18px
box-sizing border-box
border none
background-color transparent
outline none
padding 0 4px
font-size 13px
body[data-theme="dark"]
.tag

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 styles from './TrashButton.styl'
@@ -8,7 +9,7 @@ const TrashButton = ({
<button styleName='control-trashButton'
onClick={(e) => onClick(e)}
>
<i className='fa fa-trash trashButton' styleName='info-button' />
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
</button>
)

View File

@@ -1,10 +1,14 @@
.control-trashButton
float right
top 120px
margin-bottom 10px
topBarButtonLight()
.control-trashButton--in-trash
top 60px
topBarButtonLight()
.trashButton
padding 0px
margin 15px 0
body[data-theme="dark"]
.control-trashButton

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 styles from './Detail.styl'
import _ from 'lodash'
@@ -32,12 +33,12 @@ class Detail extends React.Component {
}
render () {
let { location, data, config } = this.props
const { location, data, config } = this.props
let note = null
if (location.query.key != null) {
let splitted = location.query.key.split('-')
let storageKey = splitted.shift()
let noteKey = splitted.shift()
const splitted = location.query.key.split('-')
const storageKey = splitted.shift()
const noteKey = splitted.shift()
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 styles from './Main.styl'
import { connect } from 'react-redux'
@@ -11,14 +12,9 @@ import _ from 'lodash'
import ConfigManager from 'browser/main/lib/ConfigManager'
import modal from 'browser/main/lib/modal'
import InitModal from 'browser/main/modals/InitModal'
import mixpanel from 'browser/main/lib/mixpanel'
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
import eventEmitter from 'browser/main/lib/eventEmitter'
function focused () {
mixpanel.track('MAIN_FOCUSED')
}
class Main extends React.Component {
constructor (props) {
@@ -28,7 +24,7 @@ class Main extends React.Component {
mobileAnalytics.initAwsMobileAnalytics()
}
let { config } = props
const { config } = props
this.state = {
isRightSliderFocused: false,
@@ -44,7 +40,7 @@ class Main extends React.Component {
}
getChildContext () {
let { status, config } = this.props
const { status, config } = this.props
return {
status,
@@ -53,10 +49,12 @@ class Main extends React.Component {
}
componentDidMount () {
let { dispatch, config } = this.props
const { dispatch, config } = this.props
if (config.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark')
} else if (config.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white')
} else {
document.body.setAttribute('data-theme', 'default')
}
@@ -76,11 +74,9 @@ class Main extends React.Component {
})
eventEmitter.on('editor:fullscreen', this.toggleFullScreen)
window.addEventListener('focus', focused)
}
componentWillUnmount () {
window.removeEventListener('focus', focused)
eventEmitter.off('editor:fullscreen', this.toggleFullScreen)
}
@@ -104,8 +100,8 @@ class Main extends React.Component {
this.setState({
isRightSliderFocused: false
}, () => {
let { dispatch } = this.props
let newListWidth = this.state.listWidth
const { dispatch } = this.props
const newListWidth = this.state.listWidth
// TODO: ConfigManager should dispatch itself.
ConfigManager.set({listWidth: newListWidth})
dispatch({
@@ -120,8 +116,8 @@ class Main extends React.Component {
this.setState({
isLeftSliderFocused: false
}, () => {
let { dispatch } = this.props
let navWidth = this.state.navWidth
const { dispatch } = this.props
const navWidth = this.state.navWidth
// TODO: ConfigManager should dispatch itself.
ConfigManager.set({ navWidth })
dispatch({
@@ -134,7 +130,7 @@ class Main extends React.Component {
handleMouseMove (e) {
if (this.state.isRightSliderFocused) {
let offset = this.refs.body.getBoundingClientRect().left
const offset = this.refs.body.getBoundingClientRect().left
let newListWidth = e.pageX - offset
if (newListWidth < 10) {
newListWidth = 10
@@ -187,7 +183,7 @@ class Main extends React.Component {
}
render () {
let { config } = this.props
const { config } = this.props
// the width of the navigation bar when it is folded/collapsed
const foldedNavigationWidth = 44

View File

@@ -44,6 +44,13 @@ $control-height = 34px
opacity 0
transition 0.1s
body[data-theme="white"]
.root, .root--expanded
background-color $ui-white-noteList-backgroundColor
.control-newNoteButton
background-color $ui-white-noteList-backgroundColor
body[data-theme="dark"]
.root, .root--expanded
background-color $ui-dark-noteList-backgroundColor

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 styles from './NewNoteButton.styl'
import _ from 'lodash'
import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import eventEmitter from 'browser/main/lib/eventEmitter'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron')
const { dialog } = remote
@@ -34,7 +33,7 @@ class NewNoteButton extends React.Component {
}
handleNewNoteButtonClick (e) {
const { config, location, dispatch } = this.props
const { location, dispatch } = this.props
const { storage, folder } = this.resolveTargetFolder()
modal.open(NewNoteModal, {
@@ -51,7 +50,7 @@ class NewNoteButton extends React.Component {
// Find first storage
if (storage == null) {
for (let kv of data.storageMap) {
for (const kv of data.storageMap) {
storage = kv[1]
break
}
@@ -85,7 +84,7 @@ class NewNoteButton extends React.Component {
<div styleName='control'>
<button styleName='control-newNoteButton'
onClick={(e) => this.handleNewNoteButtonClick(e)}>
<i className='fa fa-pencil-square-o' />
<img styleName='iconTag' src='../resources/icon/icon-newnote.svg' />
<span styleName='control-newNoteButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n
</span>

View File

@@ -21,14 +21,14 @@ $control-height = 30px
.control-sortBy-select
appearance: none;
margin-left 3px
margin-left 5px
color $ui-inactive-text-color
padding 0
border none
background-color transparent
outline none
cursor pointer
font-size 11px
font-size 12px
&:hover
transition 0.2s
color $ui-text-color
@@ -59,6 +59,13 @@ $control-height = 30px
top $control-height
overflow auto
body[data-theme="white"]
.root
background-color $ui-white-noteList-backgroundColor
.control
background-color $ui-white-noteList-backgroundColor
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor

View File

@@ -1,7 +1,7 @@
.root
absolute top left bottom
width $sideNav-width
background-color #f9f9f9
background-color #2E3235
user-select none
color $ui-text-color
height: 100vh
@@ -11,24 +11,25 @@
.top
padding-bottom 15px
.top-menu
.top-menu-preference
navButtonColor()
position absolute
top 22px
right 5px
height 23px
right 10px
width 2em
background-color transparent
&:hover
color $ui-text-color
color $ui-button-default--active-backgroundColor
background-color transparent
&:active, &:active:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
color $ui-button-default--active-backgroundColor
.switch-buttons
background-color transparent
border 0
height 25px
margin 20px auto 0px 8px
margin 24px auto 4px 14px
display flex
text-align center
.non-active-button
color $ui-inactive-text-color
@@ -36,13 +37,16 @@
border 0
background-color transparent
transition 0.2s
display flex
text-align center
margin-right 4px;
&:hover
color alpha(#0B99F1, 60%)
color alpha(#239F86, 60%)
.active-button
@extend .non-active-button
color #0B99F1
color $ui-button-default--active-backgroundColor
.top-menu-label
margin-left 5px
overflow ellipsis
@@ -57,7 +61,7 @@
padding-left 15px
padding-bottom 13px
p
color $ui-text-color
color $ui-button-default-color
.tagList
overflow-y auto
@@ -66,6 +70,7 @@
.root--folded
height 100vh
width $sideNav--folded-width
background-color #2E3235
.switch-buttons
display none
.top
@@ -88,7 +93,6 @@
opacity 0
margin-left 0
overflow hidden
background-color $ui-tooltip-backgroundColor
z-index 10
color white
line-height 30px
@@ -96,6 +100,41 @@
border-bottom-right-radius 2px
pointer-events none
font-size 13px
.top-menu-preference
position absolute
left 11px
body[data-theme="white"]
.root, .root--folded
background-color #f9f9f9
color $ui-text-color
.top-menu-preference
navWhiteButtonColor()
background-color transparent
&:hover
color #0B99F1
background-color transparent
&:active, &:active:hover
color #0B99F1
background-color transparent
.non-active-button
color $ui-inactive-text-color
&:hover
color alpha(#0B99F1, 60%)
.tag-title
p
color $ui-text-color
.non-active-button
&:hover
color alpha(#0B99F1, 60%)
.active-button
@extend .non-active-button
color #0B99F1
body[data-theme="dark"]
.root, .root--folded
@@ -106,12 +145,15 @@ body[data-theme="dark"]
.top
border-color $ui-dark-borderColor
.top-menu
.top-menu-preference
navDarkButtonColor()
background-color transparent
&:active
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
.non-active-button
color alpha($ui-dark-text-color, 60%)

View File

@@ -5,27 +5,23 @@
.header
position relative
height 25px
height 36px
width 100%
margin-bottom 5px
transition 0.15s
display flex
align-items center
.header--active
margin-bottom 5px
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button-default--active-backgroundColor, 20%)
transition color background-color 0.15s
.header--active
display flex
align-items center
.header-toggleButton
color $ui-text-color
.header--active
.header-info
color $ui-text-color
.header--active
.header-addFolderButton
color $ui-text-color
color #1EC38B
.header-toggleButton
navButtonColor()
@@ -38,23 +34,31 @@
border-radius 50%
&:hover
transition 0.2s
background-color alpha($ui-button--active-backgroundColor, 40%)
background-color alpha($ui-button-default--hover-backgroundColor, 40%)
color $ui-text-color
.header-info
navButtonColor()
display block
width 100%
height 25px
padding-left 23px
padding-right 10px
height 36px
padding-left 25px
padding-right 15px
line-height 22px
cursor pointer
font-size 13px
font-size 14px
border none
overflow ellipsis
text-align left
background-color alpha($ui-button--active-backgroundColor, 20%)
font-weight 600;
background-color transparent
&:hover
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
transition background-color 0.15s
&:active, &:active:hover
color #1EC38B
background-color alpha($ui-button-default--active-backgroundColor, 20%)
.header-info-path
font-size 10px
@@ -63,17 +67,14 @@
.header-addFolderButton
navButtonColor()
position absolute
right 0
right 7px
width 25px
height 25px
padding 0
border none
margin-right 5px
border-radius 50%
&:hover
transition 0.2s
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
.root--folded
@extend .root
@@ -102,6 +103,33 @@
font-size 10px
margin 0 5px
body[data-theme="white"]
.header--active
background-color $ui-button--active-backgroundColor
transition color background-color 0.15s
.header-toggleButton
color $ui-text-color
.header-info
color $ui-text-color
.header-addFolderButton
color $ui-text-color
.header-toggleButton
navWhiteButtonColor()
&:hover
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
.header-info
navWhiteButtonColor()
background-color alpha($ui-button--active-backgroundColor, 20%)
.header-addFolderButton
navWhiteButtonColor()
&:hover
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
body[data-theme="dark"]
.header--active
background-color $ui-dark-button--active-backgroundColor

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 styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal'
@@ -9,25 +10,35 @@ import TagListItem from 'browser/components/TagListItem'
import SideNavFilter from 'browser/components/SideNavFilter'
import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton'
import EventEmitter from 'browser/main/lib/eventEmitter'
class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7
componentDidMount () {
EventEmitter.on('side:preferences', this.handleMenuButtonClick)
}
componentWillUnmount () {
EventEmitter.off('side:preferences', this.handleMenuButtonClick)
}
handleMenuButtonClick (e) {
openModal(PreferencesModal)
}
handleHomeButtonClick (e) {
let { router } = this.context
const { router } = this.context
router.push('/home')
}
handleStarredButtonClick (e) {
let { router } = this.context
const { router } = this.context
router.push('/starred')
}
handleToggleButtonClick (e) {
let { dispatch, config } = this.props
const { dispatch, config } = this.props
ConfigManager.set({isSideNavFolded: !config.isSideNavFolded})
dispatch({
@@ -37,7 +48,7 @@ class SideNav extends React.Component {
}
handleTrashedButtonClick (e) {
let { router } = this.context
const { router } = this.context
router.push('/trashed')
}
@@ -52,7 +63,7 @@ class SideNav extends React.Component {
}
SideNavComponent (isFolded, storageList) {
let { location, data } = this.props
const { location, data } = this.props
const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/)
@@ -72,6 +83,9 @@ class SideNav extends React.Component {
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
counterTotalNote={data.noteMap._map.size}
counterStarredNote={data.starredSet._set.size}
counterDelNote={data.trashedSet._set.size}
/>
<StorageList storageList={storageList} />
@@ -96,7 +110,7 @@ class SideNav extends React.Component {
tagListComponent () {
const { data, location } = this.props
let tagList = data.tagNoteMap.map((tag, key) => {
const tagList = data.tagNoteMap.map((tag, key) => {
return key
})
return (
@@ -123,11 +137,11 @@ class SideNav extends React.Component {
}
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
key={storage.key}
storage={storage}
@@ -137,7 +151,7 @@ class SideNav extends React.Component {
dispatch={dispatch}
/>
})
let style = {}
const style = {}
if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/)
return (
@@ -148,15 +162,26 @@ class SideNav extends React.Component {
>
<div styleName='top'>
<div styleName='switch-buttons'>
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}><i className='fa fa-folder fa-fw' /></button>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}><i className='fa fa-tags fa-fw' /></button>
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>
<img src={isTagActive
? '../resources/icon/icon-list.svg'
: '../resources/icon/icon-list-active.svg'
}
/>
</button>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>
<img src={isTagActive
? '../resources/icon/icon-tag-active.svg'
: '../resources/icon/icon-tag.svg'
}
/>
</button>
</div>
<div>
<button styleName='top-menu'
<button styleName='top-menu-preference'
onClick={(e) => this.handleMenuButtonClick(e)}
>
<i className='fa fa-wrench fa-fw' />
<span styleName='top-menu-label'>Preferences</span>
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
</button>
</div>
</div>

View File

@@ -1,9 +1,10 @@
@import('../Detail/DetailVars')
.root
absolute bottom left right
position absolute
bottom 10px
right 10px
z-index 100
background-color $ui-noteDetail-backgroundColor
display flex
.blank
@@ -21,8 +22,19 @@
.zoom
navButtonColor()
height 24px
color rgba(0,0,0,.54)
height 20px
display flex
padding 0
align-items center
background-color transparent
&:hover
color $ui-active-color
&:active
color $ui-active-color
span
margin-left 5px
.update
navButtonColor()
height 24px
@@ -37,14 +49,14 @@
body[data-theme="dark"]
.root
background-color $ui-dark-noteDetail-backgroundColor
border-color $ui-dark-borderColor
box-shadow none
.zoom
border-color $ui-dark-borderColor
background-color transparent
color #f9f9f9
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s
color $ui-dark-text-color

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 styles from './StatusBar.styl'
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 {
updateApp () {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Update Boostnote',
detail: 'New Boostnote is ready to be installed.',
@@ -24,7 +25,7 @@ class StatusBar extends React.Component {
}
handleZoomButtonClick (e) {
let menu = new Menu()
const menu = new Menu()
zoomOptions.forEach((zoom) => {
menu.append(new MenuItem({
@@ -37,7 +38,7 @@ class StatusBar extends React.Component {
}
handleZoomMenuItemClick (zoomFactor) {
let { dispatch } = this.props
const { dispatch } = this.props
ZoomManager.setZoom(zoomFactor)
dispatch({
type: 'SET_ZOOM',
@@ -46,7 +47,7 @@ class StatusBar extends React.Component {
}
render () {
let { config, status } = this.context
const { config, status } = this.context
return (
<div className='StatusBar'
@@ -55,8 +56,8 @@ class StatusBar extends React.Component {
<button styleName='zoom'
onClick={(e) => this.handleZoomButtonClick(e)}
>
<i className='fa fa-search-plus' />&nbsp;
{Math.floor(config.zoom * 100)}%
<img src='../resources/icon/icon-zoom.svg' />
<span>{Math.floor(config.zoom * 100)}%</span>
</button>
{status.updateReady

View File

@@ -36,7 +36,7 @@ $control-height = 34px
outline none
border none
color $ui-text-color
font-size 16px
font-size 18px
padding-bottom 2px
background-color $ui-noteList-backgroundColor
@@ -112,6 +112,21 @@ $control-height = 34px
opacity 0
transition 0.1s
body[data-theme="white"]
.root, .root--expanded
background-color $ui-white-noteList-backgroundColor
.control
border-color $ui-dark-borderColor
.control-search
background-color $ui-white-noteList-backgroundColor
.control-search-input
background-color $ui-white-noteList-backgroundColor
input
background-color $ui-white-noteList-backgroundColor
body[data-theme="dark"]
.root, .root--expanded
background-color $ui-dark-noteList-backgroundColor

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

View File

@@ -12,6 +12,7 @@ body
color textColor
font-size fontSize
font-weight 200
-webkit-font-smoothing antialiased
button, input, select, textarea
font-family DEFAULT_FONTS

View File

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

View File

@@ -4,6 +4,7 @@ const ConfigManager = require('browser/main/lib/ConfigManager')
const remote = require('electron').remote
const os = require('os')
let mobileAnalyticsClient
AWS.config.region = 'us-east-1'
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 mobileAnalyticsClient = new AMA.Manager({
mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appTitle: 'xxxxxxxxxx',
appVersionName: remote.app.getVersion().toString(),

View File

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

View File

@@ -6,8 +6,6 @@ const win = global.process.platform === 'win32'
const electron = require('electron')
const { ipcRenderer } = electron
const consts = require('browser/lib/consts')
const path = require('path')
const fs = require('fs')
let isInitialized = false
@@ -91,7 +89,11 @@ function get () {
: 'default'
if (config.editor.theme !== 'default') {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
if (config.editor.theme.startsWith('solarized')) {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
} else {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
}
}
}
@@ -99,13 +101,15 @@ function get () {
}
function set (updates) {
let currentConfig = get()
let newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
const currentConfig = get()
const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
if (!validate(newConfig)) throw new Error('INVALID CONFIG')
_save(newConfig)
if (newConfig.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark')
} else if (newConfig.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white')
} else {
document.body.setAttribute('data-theme', 'default')
}
@@ -117,12 +121,16 @@ function set (updates) {
editorTheme.setAttribute('rel', 'stylesheet')
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
: 'default'
if (newTheme !== 'default') {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
if (newTheme.startsWith('solarized')) {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
} else {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
}
}
ipcRenderer.send('config-renew', {
@@ -131,7 +139,7 @@ function set (updates) {
}
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.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui)
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor)

View File

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

View File

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

View File

@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ```
*/
function createFolder (storageKey, input) {
let rawStorages
let targetStorage
try {
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)) {
key = keygen()
}
let newFolder = {
const newFolder = {
key,
color: input.color,
name: input.name

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ const sander = require('sander')
function migrateFromV5Storage (storageKey, data) {
let targetStorage
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.')
targetStorage = _.find(cachedStorageList, {key: storageKey})
@@ -24,15 +24,15 @@ function migrateFromV5Storage (storageKey, data) {
}
function importAll (storage, data) {
let oldArticles = data.articles
let notes = []
const oldArticles = data.articles
const notes = []
data.folders
.forEach(function (oldFolder) {
let folderKey = keygen()
while (storage.folders.some((folder) => folder.key === folderKey)) {
folderKey = keygen()
}
let newFolder = {
const newFolder = {
key: folderKey,
name: oldFolder.name,
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
@@ -40,7 +40,7 @@ function importAll (storage, data) {
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) => {
let noteKey = keygen()
let isUnique = false
@@ -59,7 +59,7 @@ function importAll (storage, data) {
}
if (article.mode === 'markdown') {
let newNote = {
const newNote = {
tags: article.tags,
createdAt: article.createdAt,
updatedAt: article.updatedAt,
@@ -73,7 +73,7 @@ function importAll (storage, data) {
}
notes.push(newNote)
} else {
let newNote = {
const newNote = {
tags: article.tags,
createdAt: article.createdAt,
updatedAt: article.updatedAt,

View File

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

View File

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

View File

@@ -18,7 +18,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ```
*/
function reorderFolder (storageKey, oldIndex, newIndex) {
let rawStorages
let targetStorage
try {
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')
function resolveStorageData (storageCache) {
let storage = {
const storage = {
key: storageCache.key,
name: storageCache.name,
type: storageCache.type,
@@ -13,7 +13,7 @@ function resolveStorageData (storageCache) {
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')
try {
let jsonData = CSON.readFileSync(boostnoteJSONPath)
const jsonData = CSON.readFileSync(boostnoteJSONPath)
if (!_.isArray(jsonData.folders)) throw new Error('folders should be an array.')
storage.folders = jsonData.folders
storage.version = jsonData.version
@@ -28,7 +28,7 @@ function resolveStorageData (storageCache) {
storage.version = '1.0'
}
let version = parseInt(storage.version, 10)
const version = parseInt(storage.version, 10)
if (version >= 1) {
if (version > 1) {
console.log('The repository version is newer than one of current app.')

View File

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

View File

@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
* ```
*/
function updateFolder (storageKey, folderKey, input) {
let rawStorages
let targetStorage
try {
if (input == null) throw new Error('No input found.')
@@ -37,7 +36,7 @@ function updateFolder (storageKey, folderKey, input) {
return resolveStorageData(targetStorage)
.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.')
targetFolder.name = input.name
targetFolder.color = input.color

View File

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

View File

@@ -1,121 +0,0 @@
import store from 'browser/main/store'
const _ = require('lodash')
const keygen = require('browser/lib/keygen')
const Mixpanel = require('mixpanel')
const mixpanel = Mixpanel.init('7a0aca437d72dfd07cbcbf58d3b61f27', {key: 'fde4fd23f4d550f1b646bcd7d4374b1f'})
const moment = require('moment')
const electron = require('electron')
function _getClientKey () {
let clientKey = localStorage.getItem('clientKey')
if (!_.isString(clientKey) || clientKey.length !== 40) {
clientKey = keygen(20)
_setClientKey(clientKey)
}
return clientKey
}
function _setClientKey (newKey) {
localStorage.setItem('clientKey', newKey)
}
function _fetch () {
let events
try {
events = JSON.parse(localStorage.getItem('events'))
if (!_.isArray(events)) throw new Error('events is not an array.')
} catch (err) {
console.warn(err)
events = []
localStorage.setItem('events', JSON.stringify(events))
console.info('Events cache initialzed')
}
return events
}
function _keep (name, properties) {
let events = _fetch()
properties.time = new Date()
events.push({
name,
properties
})
localStorage.setItem('events', JSON.stringify(events))
}
function _keepUnique (name, properties) {
let events = _fetch()
properties.time = new Date()
events = events.filter((event) => event.name !== name)
events.push({
name,
properties
})
localStorage.setItem('events', JSON.stringify(events))
}
function _flush () {
let events = _fetch()
let spliced = events.splice(0, 50)
localStorage.setItem('events', JSON.stringify(events))
if (spliced.length > 0) {
let parsedEvents = spliced
.filter((event) => {
if (!_.isObject(event)) return false
if (!_.isString(event.name)) return false
if (!_.isObject(event.properties)) return false
if (!moment(event.properties.time).isValid()) return false
if (new Date() - moment(event.properties.time).toDate() > 1000 * 3600 * 24 * 3) return false
return true
})
.map((event) => {
return {
event: event.name,
properties: event.properties
}
})
mixpanel.import_batch(parsedEvents, {}, (errs) => {
if (errs.length > 0) {
let events = _fetch()
events = events.concat(spliced)
localStorage.setItem('events', JSON.stringify(events))
} else {
_flush()
}
})
let state = store.getState()
mixpanel.people.set(_getClientKey(), {
storage_count: state.data.storageMap.size,
note_count: state.data.noteMap.size,
version: electron.remote.app.getVersion()
})
}
}
setInterval(_flush, 1000 * 60 * 60)
function track (name, properties) {
switch (name) {
case 'MAIN_FOCUSED':
properties = Object.assign({}, properties, {
distinct_id: _getClientKey()
})
_keepUnique(name, properties)
break
default:
properties = Object.assign({}, properties, {
distinct_id: _getClientKey()
})
_keep(name, properties)
}
}
module.exports = {
_mp: mixpanel,
track
}

View File

@@ -16,7 +16,7 @@ class ModalBase extends React.Component {
close () {
if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true})
// 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'
}
@@ -34,14 +34,14 @@ class ModalBase extends React.Component {
}
}
let el = document.createElement('div')
const el = document.createElement('div')
document.body.appendChild(el)
let modalBase = ReactDOM.render(<ModalBase />, el)
const modalBase = ReactDOM.render(<ModalBase />, el)
export function openModal (component, props) {
if (modalBase == null) { return }
// 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'
document.body.setAttribute('data-modal', 'open')
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 styles from './CreateFolderModal.styl'
import dataApi from 'browser/main/lib/dataApi'
@@ -51,8 +52,8 @@ class CreateFolderModal extends React.Component {
confirm () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
if (this.state.name.trim().length > 0) {
let { storage } = this.props
let input = {
const { storage } = this.props
const input = {
name: this.state.name.trim(),
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
}

View File

@@ -13,9 +13,9 @@ const electron = require('electron')
const { remote } = electron
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) => {
dialog.showOpenDialog({
title: 'Select Directory',
@@ -55,7 +55,7 @@ class InitModal extends React.Component {
} catch (err) {
console.error(err)
}
let newState = {
const newState = {
isLoading: false
}
if (data != null) {
@@ -122,7 +122,7 @@ class InitModal extends React.Component {
notes: data.notes
})
let defaultSnippetNote = dataApi
const defaultSnippetNote = dataApi
.createNote(data.storage.key, {
type: 'SNIPPET_NOTE',
folder: data.storage.folders[0].key,
@@ -147,12 +147,12 @@ class InitModal extends React.Component {
note: note
})
})
let defaultMarkdownNote = dataApi
const defaultMarkdownNote = dataApi
.createNote(data.storage.key, {
type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote!',
content: '# Welcome to Boostnote! \n### _Click to edit this note._\n\n---\n\nBoostnote is an *open source* note-taking app. \nRepository is published on [GitHub](https://github.com/BoostIO/Boostnote), and tweeting everyday on [@Boostnoteapp](https://twitter.com/boostnoteapp)!\n\n## Features \n- [x] No internet or registration required. \n- [ ] Quick search and copy the content of note. macOS: <kbd>Cmd</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> / windows: <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
})
.then((note) => {
store.dispatch({
@@ -184,6 +184,12 @@ class InitModal extends React.Component {
})
}
handleKeyDown (e) {
if (e.keyCode === 27) {
this.props.close()
}
}
render () {
if (this.state.isLoading) {
return <div styleName='root--loading'>
@@ -194,7 +200,7 @@ class InitModal extends React.Component {
return (
<div styleName='root'
tabIndex='-1'
onKeyDown={this.props.close}
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='header'>

View File

@@ -26,7 +26,7 @@ class NewNoteModal extends React.Component {
handleMarkdownNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props
const { storage, folder, dispatch, location } = this.props
dataApi
.createNote(storage, {
type: 'MARKDOWN_NOTE',
@@ -58,7 +58,7 @@ class NewNoteModal extends React.Component {
handleSnippetNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props
const { storage, folder, dispatch, location } = this.props
dataApi
.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 ReactDOM from 'react-dom'
import styles from './FolderItem.styl'
@@ -23,7 +24,7 @@ class FolderItem extends React.Component {
}
handleEditChange (e) {
let { folder } = this.state
const { folder } = this.state
folder.name = this.refs.nameInput.value
this.setState({
@@ -36,7 +37,7 @@ class FolderItem extends React.Component {
}
confirm () {
let { storage, folder } = this.props
const { storage, folder } = this.props
dataApi
.updateFolder(storage.key, folder.key, {
color: this.state.folder.color,
@@ -162,7 +163,7 @@ class FolderItem extends React.Component {
}
handleDeleteConfirmButtonClick (e) {
let { storage, folder } = this.props
const { storage, folder } = this.props
dataApi
.deleteFolder(storage.key, folder.key)
.then((data) => {
@@ -197,8 +198,8 @@ class FolderItem extends React.Component {
}
handleEditButtonClick (e) {
let { folder: propsFolder } = this.props
let { folder: stateFolder } = this.state
const { folder: propsFolder } = this.props
const { folder: stateFolder } = this.state
const folder = Object.assign({}, stateFolder, propsFolder)
this.setState({
status: 'EDIT',
@@ -215,7 +216,7 @@ class FolderItem extends React.Component {
}
renderIdle () {
let { folder } = this.props
const { folder } = this.props
return (
<div styleName='folderItem'
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 dataApi from 'browser/main/lib/dataApi'
import styles from './FolderList.styl'
import store from 'browser/main/store'
import FolderItem from './FolderItem'
import { SortableContainer, arrayMove } from 'react-sortable-hoc'
import { SortableContainer } from 'react-sortable-hoc'
class FolderList extends React.Component {
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}
folder={folder}
storage={storage}
@@ -53,7 +54,7 @@ class SortableFolderListComponent extends React.Component {
constructor (props) {
super(props)
this.onSortEnd = ({oldIndex, newIndex}) => {
let { storage } = this.props
const { storage } = this.props
dataApi
.reorderFolder(storage.key, oldIndex, newIndex)
.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 styles from './ConfigTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager'
@@ -41,7 +42,7 @@ class HotkeyTab extends React.Component {
}
handleSaveButtonClick (e) {
let newConfig = {
const newConfig = {
hotkey: this.state.config.hotkey
}
@@ -61,7 +62,7 @@ class HotkeyTab extends React.Component {
}
handleHotkeyChange (e) {
let { config } = this.state
const { config } = this.state
config.hotkey = {
toggleFinder: this.refs.toggleFinder.value,
toggleMain: this.refs.toggleMain.value
@@ -80,13 +81,13 @@ class HotkeyTab extends React.Component {
}
render () {
let keymapAlert = this.state.keymapAlert
let keymapAlertElement = keymapAlert != null
const keymapAlert = this.state.keymapAlert
const keymapAlertElement = keymapAlert != null
? <p className={`alert ${keymapAlert.type}`}>
{keymapAlert.message}
</p>
: null
let { config } = this.state
const { config } = this.state
return (
<div styleName='root'>

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