1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 02:06:29 +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-find-dom-node": "warn",
"react/no-render-return-value": "warn", "react/no-render-return-value": "warn",
"react/no-deprecated": "warn" "react/no-deprecated": "warn"
},
"globals": {
"FileReader": true,
"localStorage": true,
"fetch": true
} }
} }

View File

@@ -1,43 +1,72 @@
Dear all, <h1 align="center">Sponsors &amp; Backers</h1>
Thanks for your using! 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:
Boostnote is used in about 200 countries and regions, it is a awesome developer community.
To continue supporting this growth, and to satisfy community expectations, - [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
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)
--- ---
## Backers ## Backers via OpenCollective
[Kazz](https://twitter.com/kazup_bot) - $65
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 _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import path from 'path' import path from 'path'
@@ -67,7 +68,7 @@ export default class CodeEditor extends React.Component {
if (cm.somethingSelected()) cm.indentSelection('add') if (cm.somethingSelected()) cm.indentSelection('add')
else { else {
const tabs = cm.getOption('indentWithTabs') const tabs = cm.getOption('indentWithTabs')
if (line.trimLeft() === '- ' || line.trimLeft() === '* ' || line.trimLeft() === '+ ') { if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)\] )?$/)) {
cm.execCommand('goLineStart') cm.execCommand('goLineStart')
if (tabs) { if (tabs) {
cm.execCommand('insertTab') cm.execCommand('insertTab')
@@ -103,13 +104,14 @@ export default class CodeEditor extends React.Component {
this.editor.on('change', this.changeHandler) this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler) this.editor.on('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.addEventListener('load', this.loadStyleHandler) editorTheme.addEventListener('load', this.loadStyleHandler)
CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor) CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor)
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor) CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor) CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor) CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
CodeMirror.Vim.map('ZZ', ':q', 'normal')
} }
quitEditor () { quitEditor () {
@@ -120,7 +122,7 @@ export default class CodeEditor extends React.Component {
this.editor.off('blur', this.blurHandler) this.editor.off('blur', this.blurHandler)
this.editor.off('change', this.changeHandler) this.editor.off('change', this.changeHandler)
this.editor.off('paste', this.pasteHandler) this.editor.off('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler) editorTheme.removeEventListener('load', this.loadStyleHandler)
} }
@@ -196,7 +198,7 @@ export default class CodeEditor extends React.Component {
} }
setValue (value) { setValue (value) {
let cursor = this.editor.getCursor() const cursor = this.editor.getCursor()
this.editor.setValue(value) this.editor.setValue(value)
this.editor.setCursor(cursor) this.editor.setCursor(cursor)
} }
@@ -213,9 +215,7 @@ export default class CodeEditor extends React.Component {
} }
insertImageMd (imageMd) { insertImageMd (imageMd) {
const textarea = this.editor.getInputField() this.editor.replaceSelection(imageMd)
const cm = this.editor
cm.replaceSelection(`${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`)
} }
handlePaste (editor, e) { handlePaste (editor, e) {
@@ -223,7 +223,7 @@ export default class CodeEditor extends React.Component {
if (!dataTransferItem.type.match('image')) return if (!dataTransferItem.type.match('image')) return
const blob = dataTransferItem.getAsFile() const blob = dataTransferItem.getAsFile()
let reader = new FileReader() const reader = new FileReader()
let base64data let base64data
reader.readAsDataURL(blob) reader.readAsDataURL(blob)
@@ -243,7 +243,8 @@ export default class CodeEditor extends React.Component {
} }
render () { render () {
let { className, fontFamily, fontSize } = this.props const { className, fontSize } = this.props
let fontFamily = this.props.className
fontFamily = _.isString(fontFamily) && fontFamily.length > 0 fontFamily = _.isString(fontFamily) && fontFamily.length > 0
? [fontFamily].concat(defaultEditorFontFamily) ? [fontFamily].concat(defaultEditorFontFamily)
: defaultEditorFontFamily : defaultEditorFontFamily

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
/** /**
* @fileoverview Filter for all notes. * @fileoverview Filter for all notes.
*/ */
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './SideNavFilter.styl' import styles from './SideNavFilter.styl'
@@ -15,27 +16,53 @@ import styles from './SideNavFilter.styl'
*/ */
const SideNavFilter = ({ const SideNavFilter = ({
isFolded, isHomeActive, handleAllNotesButtonClick, isFolded, isHomeActive, handleAllNotesButtonClick,
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote,
counterTotalNote, counterStarredNote
}) => ( }) => (
<div styleName={isFolded ? 'menu--folded' : 'menu'}> <div styleName={isFolded ? 'menu--folded' : 'menu'}>
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'} <button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
onClick={handleAllNotesButtonClick} 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='menu-button-label'>All Notes</span>
<span styleName='counters'>{counterTotalNote}</span>
</button> </button>
<button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'} <button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'}
onClick={handleStarredButtonClick} 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='menu-button-label'>Starred</span>
<span styleName='counters'>{counterStarredNote}</span>
</button> </button>
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
onClick={handleTrashedButtonClick} 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='menu-button-label'>Trash</span>
<span styleName='counters'>{counterDelNote}</span>
</button> </button>
</div> </div>
) )

View File

@@ -3,49 +3,55 @@
.menu-button .menu-button
navButtonColor() navButtonColor()
height 32px height 36px
padding 0 15px padding 0 15px 0 20px
font-size 13px font-size 14px
width 100% width 100%
text-align left text-align left
overflow ellipsis 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 .menu-button--active
@extend .menu-button @extend .menu-button
color #e74c3c SideNavFilter()
background-color $ui-button--active-backgroundColor color #1EC38B
.menu-button-label background-color alpha($ui-button-default--active-backgroundColor, 20%)
color $ui-text-color .menu-button-label, .counters
color #1EC38B
&:hover &:hover
background-color alpha($ui-button--active-backgroundColor, 50%) color #1EC38B
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 .menu-button-star--active
@extend .menu-button @extend .menu-button
color #F9BF3B SideNavFilter()
background-color $ui-button--active-backgroundColor color #1EC38B
.menu-button-label background-color alpha($ui-button-default--active-backgroundColor, 20%)
color $ui-text-color .menu-button-label, .counters
&:hover color #1EC38B
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B .menu-button-trash--active
.menu-button-label @extend .menu-button
color $ui-text-color SideNavFilter()
&:active, &:active:hover color #1EC38B
background-color alpha($ui-button--active-backgroundColor, 50%) background-color alpha($ui-button-default--active-backgroundColor, 20%)
color #F9BF3B .menu-button-label, .counters
.menu-button-label color #1EC38B
color $ui-text-color
.menu-button-label .menu-button-label
margin-left 5px margin-left 10px
flex 1
.menu--folded .menu--folded
@extend .menu @extend .menu
@@ -54,6 +60,10 @@
&:hover .menu-button-label &:hover .menu-button-label
transition opacity 0.15s transition opacity 0.15s
opacity 1 opacity 1
color $ui-tooltip-text-color
background-color $ui-tooltip-backgroundColor
.menu-button-label .menu-button-label
position fixed position fixed
display inline-block display inline-block
@@ -63,15 +73,73 @@
margin-top -8px margin-top -8px
margin-left 0 margin-left 0
overflow ellipsis overflow ellipsis
background-color $ui-tooltip-backgroundColor
z-index 10 z-index 10
color white
line-height 32px line-height 32px
border-top-right-radius 2px border-top-right-radius 2px
border-bottom-right-radius 2px border-bottom-right-radius 2px
pointer-events none pointer-events none
opacity 0 opacity 0
font-size 13px 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"] body[data-theme="dark"]
.menu-button .menu-button
@@ -103,3 +171,14 @@ body[data-theme="dark"]
color $ui-favorite-star-button-color color $ui-favorite-star-button-color
.menu-button-label .menu-button-label
color $ui-dark-text-color 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 () { render () {
let { isActive, snippet, isDeletable } = this.props const { isActive, snippet, isDeletable } = this.props
return ( return (
<div styleName={isActive <div styleName={isActive
? 'root--active' ? 'root--active'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,11 +3,12 @@ import emoji from 'markdown-it-emoji'
import math from '@rokt33r/markdown-it-math' import math from '@rokt33r/markdown-it-math'
import _ from 'lodash' import _ from 'lodash'
// FIXME We should not depend on global variable.
const katex = window.katex const katex = window.katex
function createGutter (str) { function createGutter (str) {
let lc = (str.match(/\n/g) || []).length const lc = (str.match(/\n/g) || []).length
let lines = [] const lines = []
for (let i = 1; i <= lc; i++) { for (let i = 1; i <= lc; i++) {
lines.push('<span class="CodeMirror-linenumber">' + i + '</span>') lines.push('<span class="CodeMirror-linenumber">' + i + '</span>')
} }
@@ -75,8 +76,8 @@ md.use(require('markdown-it-plantuml'))
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) { md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token let content, terminate, i, l, token
let nextLine = startLine + 1 let nextLine = startLine + 1
let terminatorRules = state.md.block.ruler.getRules('paragraph') const terminatorRules = state.md.block.ruler.getRules('paragraph')
let endLine = state.lineMax const endLine = state.lineMax
// jump line-by-line until empty one or EOF // jump line-by-line until empty one or EOF
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
@@ -106,7 +107,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
token.map = [ startLine, state.line ] token.map = [ startLine, state.line ]
if (state.parentType === 'list') { if (state.parentType === 'list') {
let match = content.match(/^\[( |x)\] ?(.+)/i) const match = content.match(/^\[( |x)\] ?(.+)/i)
if (match) { if (match) {
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>` content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>`
} }
@@ -123,7 +124,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
}) })
// Add line number attribute for scrolling // Add line number attribute for scrolling
let originalRender = md.renderer.render const originalRender = md.renderer.render
md.renderer.render = function render (tokens, options, env) { md.renderer.render = function render (tokens, options, env) {
tokens.forEach((token) => { tokens.forEach((token) => {
switch (token.type) { switch (token.type) {
@@ -134,40 +135,12 @@ md.renderer.render = function render (tokens, options, env) {
token.attrPush(['data-line', token.map[0]]) token.attrPush(['data-line', token.map[0]])
} }
}) })
let result = originalRender.call(md.renderer, tokens, options, env) const result = originalRender.call(md.renderer, tokens, options, env)
return result return result
} }
// FIXME We should not depend on global variable.
window.md = md 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) { function normalizeLinkText (linkText) {
return md.normalizeLinkText(linkText) return md.normalizeLinkText(linkText)
} }
@@ -178,7 +151,7 @@ const markdown = {
const renderedContent = md.render(content) const renderedContent = md.render(content)
return renderedContent return renderedContent
}, },
strip,
normalizeLinkText normalizeLinkText
} }
export default markdown 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) { function findByTag (notes, block) {
const tag = block.match(/#(.+)/)[1] const tag = block.match(/#(.+)/)[1]
let regExp = new RegExp(_.escapeRegExp(tag), 'i') const regExp = new RegExp(_.escapeRegExp(tag), 'i')
return notes.filter((note) => { return notes.filter((note) => {
if (!_.isArray(note.tags)) return false if (!_.isArray(note.tags)) return false
return note.tags.some((_tag) => { return note.tags.some((_tag) => {
@@ -26,7 +26,7 @@ function findByTag (notes, block) {
} }
function findByWord (notes, block) { function findByWord (notes, block) {
let regExp = new RegExp(_.escapeRegExp(block), 'i') const regExp = new RegExp(_.escapeRegExp(block), 'i')
return notes.filter((note) => { return notes.filter((note) => {
if (_.isArray(note.tags) && note.tags.some((_tag) => { if (_.isArray(note.tags) && note.tags.some((_tag) => {
return _tag.match(regExp) return _tag.match(regExp)

View File

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

View File

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

View File

@@ -1,21 +1,22 @@
.root .root
position relative position relative
border solid 1px transparent border solid 1px transparent
line-height 26px
vertical-align middle vertical-align middle
border-radius 2px border-radius 2px
transition 0.15s transition 0.15s
user-select none user-select none
margin-right 10px
&:hover &:hover
background-color $ui-button--hover-backgroundColor background-color $ui-button--hover-backgroundColor
.root--search, .root--focus .root--search, .root--focus
@extend .root @extend .root
background-color $ui-noteDetail-backgroundColor = #F4F4F4 background-color $ui-noteDetail-backgroundColor = #fff
border-color $ui-input--focus-borderColor border-color $ui-input--focus-borderColor
width 100px width 154px
height 30px
&:hover &:hover
border-color $ui-input--focus-borderColor border-color $ui-input--focus-borderColor = #fff
.idle .idle
position relative position relative
@@ -24,13 +25,16 @@
.idle-label .idle-label
right 20px right 20px
overflow ellipsis overflow ellipsis
display flex
align-items center
.idle-label-name .idle-label-name
font-size 14px font-size 13px
padding 2px font-weight 600
margin-left 4px
.idle-label-name-surfix .idle-label-name-surfix
font-size 10px font-size 15px
color $ui-inactive-text-color color $ui-inactive-text-color
margin-left 5px margin-left 5px
.idle-caret .idle-caret
@@ -39,35 +43,37 @@
width 20px width 20px
line-height 34px line-height 34px
.search
absolute top left right bottom
line-height 34px
.search-input .search-input
vertical-align middle vertical-align middle
position relative position relative
top -2px top 0
font-size 14px
outline none outline none
border none border none
height 20px width 100%
line-height 20px
background-color transparent background-color transparent
padding 0 10px padding 0 10px
.search-optionList .search-optionList
position fixed position absolute
top 30px
max-height 450px max-height 450px
min-width 150px
overflow auto overflow auto
z-index 200 z-index 200
border $ui-border border $ui-border
background-color white background-color white
border-radius 2px border-radius 2px
padding 10px 6px
.search-optionList-item .search-optionList-item
width 140px
height 34px height 34px
width 250px display flex
align-items center
box-sizing border-box box-sizing border-box
padding 0 5px padding 0
margin-bottom 10px
overflow ellipsis overflow ellipsis
cursor pointer cursor pointer
&:hover &:hover
@@ -81,13 +87,17 @@
background-color $ui-button--active-backgroundColor background-color $ui-button--active-backgroundColor
color $ui-button--active-color color $ui-button--active-color
.search-optionList-item-name .search-optionList-item-name
border-left solid 2px transparent border-left solid 3px transparent
padding 2px 5px padding 6px
.search-optionList-item-name-surfix .search-optionList-item-name-surfix
font-size 10px font-size 10px
color $ui-inactive-text-color color $ui-inactive-text-color
margin-left 5px margin-left 5px
body[data-theme="dark"] body[data-theme="dark"]
.root .root
color $ui-dark-text-color 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 CSSModules from 'browser/lib/CSSModules'
import styles from './InfoButton.styl' import styles from './InfoButton.styl'
@@ -6,9 +7,9 @@ const InfoButton = ({
onClick onClick
}) => ( }) => (
<button styleName='control-infoButton' <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> </button>
) )

View File

@@ -1,20 +1,10 @@
.control-infoButton .control-infoButton
float right top 10px
margin-bottom 10px
topBarButtonLight() 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 .infoButton
padding 0px padding 0px
margin 15px 0
body[data-theme="dark"] body[data-theme="dark"]
.control-infoButton .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 CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'

View File

@@ -10,12 +10,12 @@
.control-infoButton-panel .control-infoButton-panel
z-index 200 z-index 200
margin-top 38px margin-top 0px
margin-left -140px right 0
position absolute position absolute
padding 20px 25px 0 25px padding 20px 25px 0 25px
width 300px width 300px
height 500px height 350px
overflow auto overflow auto
background-color $ui-noteList-backgroundColor 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) 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 .control-infoButton-panel-trash
z-index 200 z-index 200
margin-top 45px margin-top 0px
margin-left -190px right 0px
position absolute position absolute
padding 20px 25px 0 25px padding 20px 25px 0 25px
width 300px 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 CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'

View File

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

View File

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

View File

@@ -1,33 +1,31 @@
@import('DetailVars') @import('DetailVars')
$info-height = 60px $info-height = 50px
$info-margin-under-border = 27px $info-margin-under-border = 30px
.info .info
absolute top left right absolute top left right
left $note-detail-left-margin left 0
right $note-detail-right-margin right 0
height $info-height height $info-height
border-bottom $ui-border border-bottom 1px solid #eee
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
width 100%
display flex
align-items center
.info-left .info-left
float left padding 0 10px
padding 0 5px width 100%
margin 0px 2px display flex
.info-left-top align-items center
display inline-block
height $info-height
line-height $info-height
.info-left-top-folderSelect .info-left-top-folderSelect
padding 0 3px
height 34px
line-height 26px
display flex display flex
align-items center align-items center
justify-content center justify-content center
border-radius 3px
.info-left-button .info-left-button
width 34px width 34px
height 34px height 34px
@@ -48,18 +46,18 @@ $info-margin-under-border = 27px
.info-right .info-right
position absolute position absolute
right 0 right 40px
top 0 top 60px
background $ui-noteDetail-backgroundColor
bottom 1px bottom 1px
padding-left 30px padding-left 30px
z-index 101
.undo-button .undo-button
width 34px width 34px
height 34px height 34px
border-radius 17px border-radius 17px
font-size 14px font-size 14px
margin 15px 7px margin 5px 0px
border none border none
color $ui-button-color color $ui-button-color
display flex display flex
@@ -72,6 +70,7 @@ $info-margin-under-border = 27px
border-color $ui-button--active-backgroundColor border-color $ui-button--active-backgroundColor
&:hover &:hover
background-color alpha($ui-button--hover-backgroundColor, 60%) background-color alpha($ui-button--hover-backgroundColor, 60%)
transition 0.2s
.control-lockButton-tooltip .control-lockButton-tooltip
opacity 1 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 CSSModules from 'browser/lib/CSSModules'
import styles from './SnippetNoteDetail.styl' import styles from './SnippetNoteDetail.styl'
import CodeEditor from 'browser/components/CodeEditor' import CodeEditor from 'browser/components/CodeEditor'
@@ -18,6 +19,7 @@ import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton' import TrashButton from './TrashButton'
import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton' import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel' import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed' import InfoPanelTrashed from './InfoPanelTrashed'
@@ -60,7 +62,7 @@ class SnippetNoteDetail extends React.Component {
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) { if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
if (this.saveQueue != null) this.saveNow() if (this.saveQueue != null) this.saveNow()
let nextNote = Object.assign({ const nextNote = Object.assign({
description: '' description: ''
}, nextProps.note, { }, nextProps.note, {
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet)) snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
@@ -69,7 +71,7 @@ class SnippetNoteDetail extends React.Component {
snippetIndex: 0, snippetIndex: 0,
note: nextNote note: nextNote
}, () => { }, () => {
let { snippets } = this.state.note const { snippets } = this.state.note
snippets.forEach((snippet, index) => { snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload() this.refs['code-' + index].reload()
}) })
@@ -83,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleChange (e) { handleChange (e) {
let { note } = this.state const { note } = this.state
if (this.refs.tags) note.tags = this.refs.tags.value if (this.refs.tags) note.tags = this.refs.tags.value
note.description = this.refs.description.value note.description = this.refs.description.value
@@ -105,7 +107,7 @@ class SnippetNoteDetail extends React.Component {
} }
saveNow () { saveNow () {
let { note, dispatch } = this.props const { note, dispatch } = this.props
clearTimeout(this.saveQueue) clearTimeout(this.saveQueue)
this.saveQueue = null this.saveQueue = null
@@ -121,11 +123,11 @@ class SnippetNoteDetail extends React.Component {
} }
handleFolderChange (e) { handleFolderChange (e) {
let { note } = this.state const { note } = this.state
let value = this.refs.folder.value const value = this.refs.folder.value
let splitted = value.split('-') const splitted = value.split('-')
let newStorageKey = splitted.shift() const newStorageKey = splitted.shift()
let newFolderKey = splitted.shift() const newFolderKey = splitted.shift()
dataApi dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey) .moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -134,7 +136,7 @@ class SnippetNoteDetail extends React.Component {
isMovingNote: true, isMovingNote: true,
note: Object.assign({}, newNote) note: Object.assign({}, newNote)
}, () => { }, () => {
let { dispatch, location } = this.props const { dispatch, location } = this.props
dispatch({ dispatch({
type: 'MOVE_NOTE', type: 'MOVE_NOTE',
originNote: note, originNote: note,
@@ -154,7 +156,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleStarButtonClick (e) { handleStarButtonClick (e) {
let { note } = this.state const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR') if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred note.isStarred = !note.isStarred
@@ -171,22 +173,22 @@ class SnippetNoteDetail extends React.Component {
} }
handleTrashButtonClick (e) { handleTrashButtonClick (e) {
let { note } = this.state const { note } = this.state
const { isTrashed } = note const { isTrashed } = note
if (isTrashed) { if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Confirm note deletion', message: 'Confirm note deletion',
detail: 'This will permanently remove this note.', detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel'] buttons: ['Confirm', 'Cancel']
}) })
if (dialogueButtonIndex === 1) return if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props const { note, dispatch } = this.props
dataApi dataApi
.deleteNote(note.storage, note.key) .deleteNote(note.storage, note.key)
.then((data) => { .then((data) => {
let dispatchHandler = () => { const dispatchHandler = () => {
dispatch({ dispatch({
type: 'DELETE_NOTE', type: 'DELETE_NOTE',
storageKey: data.storageKey, storageKey: data.storageKey,
@@ -208,7 +210,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleUndoButtonClick (e) { handleUndoButtonClick (e) {
let { note } = this.state const { note } = this.state
note.isTrashed = false note.isTrashed = false
@@ -237,7 +239,7 @@ class SnippetNoteDetail extends React.Component {
handleTabDeleteButtonClick (e, index) { handleTabDeleteButtonClick (e, index) {
if (this.state.note.snippets.length > 1) { if (this.state.note.snippets.length > 1) {
if (this.state.note.snippets[index].content.trim().length > 0) { if (this.state.note.snippets[index].content.trim().length > 0) {
let dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), { const dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Delete a snippet', message: 'Delete a snippet',
detail: 'This work cannot be undone.', detail: 'This work cannot be undone.',
@@ -287,7 +289,7 @@ class SnippetNoteDetail extends React.Component {
handleModeOptionClick (index, name) { handleModeOptionClick (index, name) {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() const snippets = this.state.note.snippets.slice()
snippets[index].mode = name snippets[index].mode = name
this.setState({note: Object.assign(this.state.note, {snippets: snippets})}) this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
@@ -305,7 +307,7 @@ class SnippetNoteDetail extends React.Component {
handleCodeChange (index) { handleCodeChange (index) {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() const snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value snippets[index].content = this.refs['code-' + index].value
this.setState({note: Object.assign(this.state.note, {snippets: snippets})}) this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({ this.setState({
@@ -332,7 +334,7 @@ class SnippetNoteDetail extends React.Component {
break break
case 76: case 76:
{ {
let isSuper = global.process.platform === 'darwin' const isSuper = global.process.platform === 'darwin'
? e.metaKey ? e.metaKey
: e.ctrlKey : e.ctrlKey
if (isSuper) { if (isSuper) {
@@ -343,7 +345,7 @@ class SnippetNoteDetail extends React.Component {
break break
case 84: case 84:
{ {
let isSuper = global.process.platform === 'darwin' const isSuper = global.process.platform === 'darwin'
? e.metaKey ? e.metaKey
: e.ctrlKey : e.ctrlKey
if (isSuper) { if (isSuper) {
@@ -356,7 +358,7 @@ class SnippetNoteDetail extends React.Component {
} }
handleModeButtonClick (e, index) { handleModeButtonClick (e, index) {
let menu = new Menu() const menu = new Menu()
CodeMirror.modeInfo.forEach((mode) => { CodeMirror.modeInfo.forEach((mode) => {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: mode.name, label: mode.name,
@@ -397,8 +399,8 @@ class SnippetNoteDetail extends React.Component {
} }
handleIndentSizeItemClick (e, indentSize) { handleIndentSizeItemClick (e, indentSize) {
let { config, dispatch } = this.props const { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, { const editor = Object.assign({}, config.editor, {
indentSize indentSize
}) })
ConfigManager.set({ ConfigManager.set({
@@ -413,8 +415,8 @@ class SnippetNoteDetail extends React.Component {
} }
handleIndentTypeItemClick (e, indentType) { handleIndentTypeItemClick (e, indentType) {
let { config, dispatch } = this.props const { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, { const editor = Object.assign({}, config.editor, {
indentType indentType
}) })
ConfigManager.set({ ConfigManager.set({
@@ -433,14 +435,14 @@ class SnippetNoteDetail extends React.Component {
} }
addSnippet () { addSnippet () {
let { note } = this.state const { note } = this.state
note.snippets = note.snippets.concat([{ note.snippets = note.snippets.concat([{
name: '', name: '',
mode: 'Plain Text', mode: 'Plain Text',
content: '' content: ''
}]) }])
let snippetIndex = note.snippets.length - 1 const snippetIndex = note.snippets.length - 1
this.setState({ this.setState({
note, note,
@@ -486,19 +488,19 @@ class SnippetNoteDetail extends React.Component {
} }
render () { render () {
let { data, config, location } = this.props const { data, config, location } = this.props
let { note } = this.state const { note } = this.state
let storageKey = note.storage const storageKey = note.storage
let folderKey = note.folder const folderKey = note.folder
let editorFontSize = parseInt(config.editor.fontSize, 10) let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14 if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10) let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4 if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let tabList = note.snippets.map((snippet, index) => { const tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
return <SnippetTab return <SnippetTab
key={index} key={index}
@@ -512,8 +514,8 @@ class SnippetNoteDetail extends React.Component {
/> />
}) })
let viewList = note.snippets.map((snippet, index) => { const viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode)) let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
@@ -547,7 +549,7 @@ class SnippetNoteDetail extends React.Component {
</div> </div>
}) })
let options = [] const options = []
data.storageMap.forEach((storage, index) => { data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => { storage.folders.forEach((folder) => {
options.push({ options.push({
@@ -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'> const trashTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>
@@ -566,7 +568,7 @@ class SnippetNoteDetail extends React.Component {
/> />
</div> </div>
<div styleName='info-right'> <div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} /> <PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton <InfoButton
onClick={(e) => this.handleInfoButtonClick(e)} onClick={(e) => this.handleInfoButtonClick(e)}
/> />
@@ -583,10 +585,6 @@ class SnippetNoteDetail extends React.Component {
const detailTopBar = <div styleName='info'> const detailTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'> <div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect' <FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder} value={this.state.note.storage + '-' + this.state.note.folder}
@@ -603,15 +601,21 @@ class SnippetNoteDetail extends React.Component {
/> />
</div> </div>
<div styleName='info-right'> <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 <InfoButton
onClick={(e) => this.handleInfoButtonClick(e)} 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 <InfoPanel
storageName={currentOption.storage.name} storageName={currentOption.storage.name}
folderName={currentOption.folder.name} folderName={currentOption.folder.name}

View File

@@ -3,14 +3,14 @@
.root .root
absolute top bottom right absolute top bottom right
border-width 0 border-left 1px solid alpha(#DEDEDE, 60%)
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
box-shadow $note-detail-box-shadow box-shadow none
.body .body
absolute left right absolute left right
left $note-detail-left-margin left $snippet-note-detail-left-margin
right $note-detail-right-margin right $snippet-note-detail-right-margin
top $info-height + $info-margin-under-border top $info-height + $info-margin-under-border
bottom $statusBar-height bottom $statusBar-height
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
@@ -43,7 +43,7 @@
overflow hidden overflow hidden
.tabList .plusButton .tabList .plusButton
navButtonColor() navWhiteButtonColor()
width 30px width 30px
.tabView .tabView
@@ -55,24 +55,30 @@
.override .override
absolute bottom left absolute bottom left
bottom 2px bottom 1px
left 60px left 60px
height 23px
z-index 101 z-index 101
button button
navButtonColor() navButtonColor()
height 24px padding 0 6px
&:hover
color $ui-active-color
&:active .update-icon &:active .update-icon
color white color $ui-active-color
.control-fullScreenButton .control-fullScreenButton
float right top 80px
padding 0 0 2px 0 margin-bottom 10px
topBarButtonLight() topBarButtonLight()
body[data-theme="white"]
.root
box-shadow $note-detail-box-shadow
border none
body[data-theme="dark"] body[data-theme="dark"]
.root .root
border-color $ui-dark-borderColor border none
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
box-shadow none 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 CSSModules from 'browser/lib/CSSModules'
import styles from './StarButton.styl' import styles from './StarButton.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -31,7 +32,7 @@ class StarButton extends React.Component {
} }
render () { render () {
let { className } = this.props const { className } = this.props
return ( return (
<button className={_.isString(className) <button className={_.isString(className)
@@ -47,10 +48,10 @@ class StarButton extends React.Component {
onMouseLeave={(e) => this.handleMouseLeave(e)} onMouseLeave={(e) => this.handleMouseLeave(e)}
onClick={this.props.onClick} onClick={this.props.onClick}
> >
<i styleName='icon' <img styleName='icon'
className={this.state.isActive || this.props.isActive src={this.state.isActive || this.props.isActive
? 'fa fa-star' ? '../resources/icon/icon-starred.svg'
: 'fa fa-star-o' : '../resources/icon/icon-star.svg'
} }
/> />
</button> </button>

View File

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

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react' import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TagSelect.styl' import styles from './TagSelect.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -59,7 +60,7 @@ class TagSelect extends React.Component {
submitTag () { submitTag () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
let { value } = this.props let { value } = this.props
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_') const newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
if (newTag.length <= 0) { if (newTag.length <= 0) {
this.setState({ this.setState({
@@ -101,9 +102,9 @@ class TagSelect extends React.Component {
} }
render () { render () {
let { value, className } = this.props const { value, className } = this.props
let tagList = _.isArray(value) const tagList = _.isArray(value)
? value.map((tag) => { ? value.map((tag) => {
return ( return (
<span styleName='tag' <span styleName='tag'
@@ -113,7 +114,7 @@ class TagSelect extends React.Component {
<button styleName='tag-removeButton' <button styleName='tag-removeButton'
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)} 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> </button>
</span> </span>
) )

View File

@@ -1,9 +1,9 @@
.root .root
display inline-block display flex
align-items center
user-select none user-select none
height 23px
vertical-align middle vertical-align middle
width 300px width 100%
overflow-x scroll overflow-x scroll
white-space nowrap white-space nowrap
@@ -11,51 +11,42 @@
display none display none
.tag .tag
display inline-block display flex
margin 1px 3px align-items center
padding 0 margin 0px 2px
height 20px padding 2px 4px
background-color alpha($ui-tag-backgroundColor, 10%) background-color alpha($ui-tag-backgroundColor, 3%)
border-radius 3px border-radius 4px
overflow hidden position relative
clearfix() clearfix()
.tag-removeButton .tag-removeButton
float right
height 20px
width 18px
margin 0 margin 0
padding 0 padding 0
border-style solid border-style solid
border-width 0 border-width 0
border-radius 20px border-radius 20px
line-height 18px
background-color transparent background-color transparent
color $ui-button-color color $ui-button-color
position absolute
right 6px
.tag-removeButton-icon .tag-removeButton-icon
width 5px width 5px
padding-right 4px padding-right 4px
.tag-label .tag-label
font-size 11px font-size 13px
font-weight 600 color: $ui-text-color
color: alpha($ui-text-color, 80%) padding 4px 16px 4px 8px
float left
height 20px
line-height 20px
padding 0 6px
.newTag .newTag
display inline-block
margin 2px 0 15px 2px
vertical-align middle
height 18px
box-sizing border-box box-sizing border-box
border none border none
background-color transparent background-color transparent
outline none outline none
padding 0 4px padding 0 4px
font-size 13px
body[data-theme="dark"] body[data-theme="dark"]
.tag .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 CSSModules from 'browser/lib/CSSModules'
import styles from './TrashButton.styl' import styles from './TrashButton.styl'
@@ -8,7 +9,7 @@ const TrashButton = ({
<button styleName='control-trashButton' <button styleName='control-trashButton'
onClick={(e) => onClick(e)} onClick={(e) => onClick(e)}
> >
<i className='fa fa-trash trashButton' styleName='info-button' /> <img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
</button> </button>
) )

View File

@@ -1,10 +1,14 @@
.control-trashButton .control-trashButton
float right top 120px
margin-bottom 10px
topBarButtonLight()
.control-trashButton--in-trash
top 60px
topBarButtonLight() topBarButtonLight()
.trashButton .trashButton
padding 0px padding 0px
margin 15px 0
body[data-theme="dark"] body[data-theme="dark"]
.control-trashButton .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 CSSModules from 'browser/lib/CSSModules'
import styles from './Detail.styl' import styles from './Detail.styl'
import _ from 'lodash' import _ from 'lodash'
@@ -32,12 +33,12 @@ class Detail extends React.Component {
} }
render () { render () {
let { location, data, config } = this.props const { location, data, config } = this.props
let note = null let note = null
if (location.query.key != null) { if (location.query.key != null) {
let splitted = location.query.key.split('-') const splitted = location.query.key.split('-')
let storageKey = splitted.shift() const storageKey = splitted.shift()
let noteKey = splitted.shift() const noteKey = splitted.shift()
note = data.noteMap.get(storageKey + '-' + noteKey) note = data.noteMap.get(storageKey + '-' + noteKey)
} }

View File

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

View File

@@ -44,6 +44,13 @@ $control-height = 34px
opacity 0 opacity 0
transition 0.1s 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"] body[data-theme="dark"]
.root, .root--expanded .root, .root--expanded
background-color $ui-dark-noteList-backgroundColor 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 CSSModules from 'browser/lib/CSSModules'
import styles from './NewNoteButton.styl' import styles from './NewNoteButton.styl'
import _ from 'lodash' import _ from 'lodash'
import modal from 'browser/main/lib/modal' import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal' import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron') const { remote } = require('electron')
const { dialog } = remote const { dialog } = remote
@@ -34,7 +33,7 @@ class NewNoteButton extends React.Component {
} }
handleNewNoteButtonClick (e) { handleNewNoteButtonClick (e) {
const { config, location, dispatch } = this.props const { location, dispatch } = this.props
const { storage, folder } = this.resolveTargetFolder() const { storage, folder } = this.resolveTargetFolder()
modal.open(NewNoteModal, { modal.open(NewNoteModal, {
@@ -51,7 +50,7 @@ class NewNoteButton extends React.Component {
// Find first storage // Find first storage
if (storage == null) { if (storage == null) {
for (let kv of data.storageMap) { for (const kv of data.storageMap) {
storage = kv[1] storage = kv[1]
break break
} }
@@ -85,7 +84,7 @@ class NewNoteButton extends React.Component {
<div styleName='control'> <div styleName='control'>
<button styleName='control-newNoteButton' <button styleName='control-newNoteButton'
onClick={(e) => this.handleNewNoteButtonClick(e)}> 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'> <span styleName='control-newNoteButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n Make a Note {OSX ? '⌘' : '^'} + n
</span> </span>

View File

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

View File

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

View File

@@ -5,27 +5,23 @@
.header .header
position relative position relative
height 25px height 36px
width 100% width 100%
margin-bottom 5px margin-bottom 5px
transition 0.15s transition 0.15s
display flex
align-items center
.header--active .header--active
margin-bottom 5px margin-bottom 5px
background-color $ui-button--active-backgroundColor background-color alpha($ui-button-default--active-backgroundColor, 20%)
transition color background-color 0.15s transition color background-color 0.15s
display flex
.header--active align-items center
.header-toggleButton .header-toggleButton
color $ui-text-color
.header--active
.header-info .header-info
color $ui-text-color
.header--active
.header-addFolderButton .header-addFolderButton
color $ui-text-color color #1EC38B
.header-toggleButton .header-toggleButton
navButtonColor() navButtonColor()
@@ -38,23 +34,31 @@
border-radius 50% border-radius 50%
&:hover &:hover
transition 0.2s transition 0.2s
background-color alpha($ui-button--active-backgroundColor, 40%) background-color alpha($ui-button-default--hover-backgroundColor, 40%)
color $ui-text-color color $ui-text-color
.header-info .header-info
navButtonColor() navButtonColor()
display block display block
width 100% width 100%
height 25px height 36px
padding-left 23px padding-left 25px
padding-right 10px padding-right 15px
line-height 22px line-height 22px
cursor pointer cursor pointer
font-size 13px font-size 14px
border none border none
overflow ellipsis overflow ellipsis
text-align left 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 .header-info-path
font-size 10px font-size 10px
@@ -63,17 +67,14 @@
.header-addFolderButton .header-addFolderButton
navButtonColor() navButtonColor()
position absolute position absolute
right 0 right 7px
width 25px width 25px
height 25px height 25px
padding 0 padding 0
border none border none
margin-right 5px
border-radius 50% border-radius 50%
&:hover &:hover
transition 0.2s transition 0.2s
background-color alpha($ui-button--active-backgroundColor, 40%)
color $ui-text-color
.root--folded .root--folded
@extend .root @extend .root
@@ -102,6 +103,33 @@
font-size 10px font-size 10px
margin 0 5px 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"] body[data-theme="dark"]
.header--active .header--active
background-color $ui-dark-button--active-backgroundColor 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 CSSModules from 'browser/lib/CSSModules'
import styles from './SideNav.styl' import styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal' import { openModal } from 'browser/main/lib/modal'
@@ -9,25 +10,35 @@ import TagListItem from 'browser/components/TagListItem'
import SideNavFilter from 'browser/components/SideNavFilter' import SideNavFilter from 'browser/components/SideNavFilter'
import StorageList from 'browser/components/StorageList' import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton' import NavToggleButton from 'browser/components/NavToggleButton'
import EventEmitter from 'browser/main/lib/eventEmitter'
class SideNav extends React.Component { class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7 // TODO: should not use electron stuff v0.7
componentDidMount () {
EventEmitter.on('side:preferences', this.handleMenuButtonClick)
}
componentWillUnmount () {
EventEmitter.off('side:preferences', this.handleMenuButtonClick)
}
handleMenuButtonClick (e) { handleMenuButtonClick (e) {
openModal(PreferencesModal) openModal(PreferencesModal)
} }
handleHomeButtonClick (e) { handleHomeButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/home') router.push('/home')
} }
handleStarredButtonClick (e) { handleStarredButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/starred') router.push('/starred')
} }
handleToggleButtonClick (e) { handleToggleButtonClick (e) {
let { dispatch, config } = this.props const { dispatch, config } = this.props
ConfigManager.set({isSideNavFolded: !config.isSideNavFolded}) ConfigManager.set({isSideNavFolded: !config.isSideNavFolded})
dispatch({ dispatch({
@@ -37,7 +48,7 @@ class SideNav extends React.Component {
} }
handleTrashedButtonClick (e) { handleTrashedButtonClick (e) {
let { router } = this.context const { router } = this.context
router.push('/trashed') router.push('/trashed')
} }
@@ -52,7 +63,7 @@ class SideNav extends React.Component {
} }
SideNavComponent (isFolded, storageList) { SideNavComponent (isFolded, storageList) {
let { location, data } = this.props const { location, data } = this.props
const isHomeActive = !!location.pathname.match(/^\/home$/) const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/) const isStarredActive = !!location.pathname.match(/^\/starred$/)
@@ -72,6 +83,9 @@ class SideNav extends React.Component {
isTrashedActive={isTrashedActive} isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)} handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)} handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
counterTotalNote={data.noteMap._map.size}
counterStarredNote={data.starredSet._set.size}
counterDelNote={data.trashedSet._set.size}
/> />
<StorageList storageList={storageList} /> <StorageList storageList={storageList} />
@@ -96,7 +110,7 @@ class SideNav extends React.Component {
tagListComponent () { tagListComponent () {
const { data, location } = this.props const { data, location } = this.props
let tagList = data.tagNoteMap.map((tag, key) => { const tagList = data.tagNoteMap.map((tag, key) => {
return key return key
}) })
return ( return (
@@ -123,11 +137,11 @@ class SideNav extends React.Component {
} }
render () { render () {
let { data, location, config, dispatch } = this.props const { data, location, config, dispatch } = this.props
let isFolded = config.isSideNavFolded const isFolded = config.isSideNavFolded
let storageList = data.storageMap.map((storage, key) => { const storageList = data.storageMap.map((storage, key) => {
return <StorageItem return <StorageItem
key={storage.key} key={storage.key}
storage={storage} storage={storage}
@@ -137,7 +151,7 @@ class SideNav extends React.Component {
dispatch={dispatch} dispatch={dispatch}
/> />
}) })
let style = {} const style = {}
if (!isFolded) style.width = this.props.width if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/) const isTagActive = location.pathname.match(/tag/)
return ( return (
@@ -148,15 +162,26 @@ class SideNav extends React.Component {
> >
<div styleName='top'> <div styleName='top'>
<div styleName='switch-buttons'> <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 ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}><i className='fa fa-tags fa-fw' /></button> <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>
<div> <div>
<button styleName='top-menu' <button styleName='top-menu-preference'
onClick={(e) => this.handleMenuButtonClick(e)} onClick={(e) => this.handleMenuButtonClick(e)}
> >
<i className='fa fa-wrench fa-fw' /> <img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
<span styleName='top-menu-label'>Preferences</span>
</button> </button>
</div> </div>
</div> </div>

View File

@@ -1,9 +1,10 @@
@import('../Detail/DetailVars') @import('../Detail/DetailVars')
.root .root
absolute bottom left right position absolute
bottom 10px
right 10px
z-index 100 z-index 100
background-color $ui-noteDetail-backgroundColor
display flex display flex
.blank .blank
@@ -21,7 +22,18 @@
.zoom .zoom
navButtonColor() 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 .update
navButtonColor() navButtonColor()
@@ -37,14 +49,14 @@
body[data-theme="dark"] body[data-theme="dark"]
.root .root
background-color $ui-dark-noteDetail-backgroundColor
border-color $ui-dark-borderColor border-color $ui-dark-borderColor
box-shadow none box-shadow none
.zoom .zoom
border-color $ui-dark-borderColor border-color $ui-dark-borderColor
background-color transparent
color #f9f9f9
&:hover &:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s transition 0.15s
color $ui-dark-text-color 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 CSSModules from 'browser/lib/CSSModules'
import styles from './StatusBar.styl' import styles from './StatusBar.styl'
import ZoomManager from 'browser/main/lib/ZoomManager' import ZoomManager from 'browser/main/lib/ZoomManager'
@@ -11,7 +12,7 @@ const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2
class StatusBar extends React.Component { class StatusBar extends React.Component {
updateApp () { updateApp () {
let index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',
message: 'Update Boostnote', message: 'Update Boostnote',
detail: 'New Boostnote is ready to be installed.', detail: 'New Boostnote is ready to be installed.',
@@ -24,7 +25,7 @@ class StatusBar extends React.Component {
} }
handleZoomButtonClick (e) { handleZoomButtonClick (e) {
let menu = new Menu() const menu = new Menu()
zoomOptions.forEach((zoom) => { zoomOptions.forEach((zoom) => {
menu.append(new MenuItem({ menu.append(new MenuItem({
@@ -37,7 +38,7 @@ class StatusBar extends React.Component {
} }
handleZoomMenuItemClick (zoomFactor) { handleZoomMenuItemClick (zoomFactor) {
let { dispatch } = this.props const { dispatch } = this.props
ZoomManager.setZoom(zoomFactor) ZoomManager.setZoom(zoomFactor)
dispatch({ dispatch({
type: 'SET_ZOOM', type: 'SET_ZOOM',
@@ -46,7 +47,7 @@ class StatusBar extends React.Component {
} }
render () { render () {
let { config, status } = this.context const { config, status } = this.context
return ( return (
<div className='StatusBar' <div className='StatusBar'
@@ -55,8 +56,8 @@ class StatusBar extends React.Component {
<button styleName='zoom' <button styleName='zoom'
onClick={(e) => this.handleZoomButtonClick(e)} onClick={(e) => this.handleZoomButtonClick(e)}
> >
<i className='fa fa-search-plus' />&nbsp; <img src='../resources/icon/icon-zoom.svg' />
{Math.floor(config.zoom * 100)}% <span>{Math.floor(config.zoom * 100)}%</span>
</button> </button>
{status.updateReady {status.updateReady

View File

@@ -36,7 +36,7 @@ $control-height = 34px
outline none outline none
border none border none
color $ui-text-color color $ui-text-color
font-size 16px font-size 18px
padding-bottom 2px padding-bottom 2px
background-color $ui-noteList-backgroundColor background-color $ui-noteList-backgroundColor
@@ -112,6 +112,21 @@ $control-height = 34px
opacity 0 opacity 0
transition 0.1s 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"] body[data-theme="dark"]
.root, .root--expanded .root, .root--expanded
background-color $ui-dark-noteList-backgroundColor 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 CSSModules from 'browser/lib/CSSModules'
import styles from './TopBar.styl' import styles from './TopBar.styl'
import _ from 'lodash' import _ from 'lodash'
import NewNoteModal from 'browser/main/modals/NewNoteModal'
import ee from 'browser/main/lib/eventEmitter' import ee from 'browser/main/lib/eventEmitter'
import NewNoteButton from 'browser/main/NewNoteButton' import NewNoteButton from 'browser/main/NewNoteButton'
const { remote } = require('electron')
const { dialog } = remote
const OSX = window.process.platform === 'darwin'
class TopBar extends React.Component { class TopBar extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -121,7 +116,7 @@ class TopBar extends React.Component {
} }
render () { render () {
let { config, style, data, location } = this.props const { config, style, location } = this.props
return ( return (
<div className='TopBar' <div className='TopBar'
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'} styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,9 +13,9 @@ const electron = require('electron')
const { remote } = electron const { remote } = electron
function browseFolder () { function browseFolder () {
let dialog = remote.dialog const dialog = remote.dialog
let defaultPath = remote.app.getPath('home') const defaultPath = remote.app.getPath('home')
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dialog.showOpenDialog({ dialog.showOpenDialog({
title: 'Select Directory', title: 'Select Directory',
@@ -55,7 +55,7 @@ class InitModal extends React.Component {
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
let newState = { const newState = {
isLoading: false isLoading: false
} }
if (data != null) { if (data != null) {
@@ -122,7 +122,7 @@ class InitModal extends React.Component {
notes: data.notes notes: data.notes
}) })
let defaultSnippetNote = dataApi const defaultSnippetNote = dataApi
.createNote(data.storage.key, { .createNote(data.storage.key, {
type: 'SNIPPET_NOTE', type: 'SNIPPET_NOTE',
folder: data.storage.folders[0].key, folder: data.storage.folders[0].key,
@@ -147,12 +147,12 @@ class InitModal extends React.Component {
note: note note: note
}) })
}) })
let defaultMarkdownNote = dataApi const defaultMarkdownNote = dataApi
.createNote(data.storage.key, { .createNote(data.storage.key, {
type: 'MARKDOWN_NOTE', type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key, folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote!', 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) => { .then((note) => {
store.dispatch({ store.dispatch({
@@ -184,6 +184,12 @@ class InitModal extends React.Component {
}) })
} }
handleKeyDown (e) {
if (e.keyCode === 27) {
this.props.close()
}
}
render () { render () {
if (this.state.isLoading) { if (this.state.isLoading) {
return <div styleName='root--loading'> return <div styleName='root--loading'>
@@ -194,7 +200,7 @@ class InitModal extends React.Component {
return ( return (
<div styleName='root' <div styleName='root'
tabIndex='-1' tabIndex='-1'
onKeyDown={this.props.close} onKeyDown={(e) => this.handleKeyDown(e)}
> >
<div styleName='header'> <div styleName='header'>

View File

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

View File

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

View File

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

View File

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

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