mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
Merge with master resolve conflict
This commit is contained in:
@@ -12,5 +12,10 @@
|
||||
"react/no-find-dom-node": "warn",
|
||||
"react/no-render-return-value": "warn",
|
||||
"react/no-deprecated": "warn"
|
||||
},
|
||||
"globals": {
|
||||
"FileReader": true,
|
||||
"localStorage": true,
|
||||
"fetch": true
|
||||
}
|
||||
}
|
||||
|
||||
81
Backers.md
81
Backers.md
@@ -1,43 +1,72 @@
|
||||
Dear all,
|
||||
<h1 align="center">Sponsors & Backers</h1>
|
||||
|
||||
Thanks for your using!
|
||||
Boostnote is used in about 200 countries and regions, it is a awesome developer community.
|
||||
Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome backers. If you'd like to join them, please consider:
|
||||
|
||||
To continue supporting this growth, and to satisfy community expectations,
|
||||
we would like to invest more time in this project.
|
||||
|
||||
If you like this project and see its potential, you can help!
|
||||
|
||||
Thanks,
|
||||
Boostnote maintainers.
|
||||
|
||||
### >> [Support via OpenCollective](https://opencollective.com/boostnoteio)
|
||||
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
|
||||
|
||||
---
|
||||
|
||||
## Backers
|
||||
[Kazz](https://twitter.com/kazup_bot) - $65
|
||||
## Backers via OpenCollective
|
||||
|
||||
Intense Raiden - $45
|
||||
### [Gold Sponsors / $1,000 per month](https://opencollective.com/boostnoteio/order/2259)
|
||||
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
|
||||
|
||||
ravy22 - $25
|
||||
### [Silver Sponsors / $250 per month](https://opencollective.com/boostnoteio/order/2257)
|
||||
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
|
||||
|
||||
trentpolack - $20
|
||||
### [Bronze Sponsors / $50 per month](https://opencollective.com/boostnoteio/order/2258)
|
||||
- Get your name and Url (or E-mail) on Readme.md on GitHub.
|
||||
|
||||
hikariru - $10
|
||||
### [Backers3 / $10 per month](https://opencollective.com/boostnoteio/order/2176)
|
||||
- [Ralph03](https://opencollective.com/ralph03)
|
||||
|
||||
kolchan11 - $10
|
||||
- [Nikolas Dan](https://opencollective.com/nikolas-dan)
|
||||
|
||||
RonWalker22 - $10
|
||||
### [Backers2 / $5 per month](https://opencollective.com/boostnoteio/order/2175)
|
||||
- [Yeojong Kim](https://twitter.com/yeojoy)
|
||||
|
||||
hocchuc - $5
|
||||
- [Scotia Draven](https://opencollective.com/scotia-draven)
|
||||
|
||||
Adam - $5
|
||||
- [A. J. Vargas](https://opencollective.com/aj-vargas)
|
||||
|
||||
Steve - $5
|
||||
### [Backers1](https://opencollective.com/boostnoteio/order/2563) and One-time sponsors
|
||||
- Ryosuke Tamura - $30
|
||||
|
||||
evmin - $5
|
||||
- tatoosh11 - $10
|
||||
|
||||
[@yeojoy](https://twitter.com/yeojoy) - $5
|
||||
- Alexander Borovkov - $10
|
||||
|
||||
Scotia Draven - $5
|
||||
- spoonhoop - $5
|
||||
|
||||
- Drew Williams - $2
|
||||
|
||||
- Andy Shaw - $2
|
||||
|
||||
- mysafesky -$2
|
||||
|
||||
---
|
||||
|
||||
## Backers via Bountysource
|
||||
https://salt.bountysource.com/teams/boostnote
|
||||
|
||||
- Kuzz - $65
|
||||
|
||||
- Intense Raiden - $45
|
||||
|
||||
- ravy22 - $25
|
||||
|
||||
- trentpolack - $20
|
||||
|
||||
- hikariru - $10
|
||||
|
||||
- kolchan11 - $10
|
||||
|
||||
- RonWalker22 - $10
|
||||
|
||||
- hocchuc - $5
|
||||
|
||||
- Adam - $5
|
||||
|
||||
- Steve - $5
|
||||
|
||||
- evmin - $5
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import CodeMirror from 'codemirror'
|
||||
import path from 'path'
|
||||
@@ -67,7 +68,7 @@ export default class CodeEditor extends React.Component {
|
||||
if (cm.somethingSelected()) cm.indentSelection('add')
|
||||
else {
|
||||
const tabs = cm.getOption('indentWithTabs')
|
||||
if (line.trimLeft() === '- ' || line.trimLeft() === '* ' || line.trimLeft() === '+ ') {
|
||||
if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)\] )?$/)) {
|
||||
cm.execCommand('goLineStart')
|
||||
if (tabs) {
|
||||
cm.execCommand('insertTab')
|
||||
@@ -103,13 +104,14 @@ export default class CodeEditor extends React.Component {
|
||||
this.editor.on('change', this.changeHandler)
|
||||
this.editor.on('paste', this.pasteHandler)
|
||||
|
||||
let editorTheme = document.getElementById('editorTheme')
|
||||
const editorTheme = document.getElementById('editorTheme')
|
||||
editorTheme.addEventListener('load', this.loadStyleHandler)
|
||||
|
||||
CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor)
|
||||
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
|
||||
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
|
||||
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
|
||||
CodeMirror.Vim.map('ZZ', ':q', 'normal')
|
||||
}
|
||||
|
||||
quitEditor () {
|
||||
@@ -120,7 +122,7 @@ export default class CodeEditor extends React.Component {
|
||||
this.editor.off('blur', this.blurHandler)
|
||||
this.editor.off('change', this.changeHandler)
|
||||
this.editor.off('paste', this.pasteHandler)
|
||||
let editorTheme = document.getElementById('editorTheme')
|
||||
const editorTheme = document.getElementById('editorTheme')
|
||||
editorTheme.removeEventListener('load', this.loadStyleHandler)
|
||||
}
|
||||
|
||||
@@ -196,7 +198,7 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
setValue (value) {
|
||||
let cursor = this.editor.getCursor()
|
||||
const cursor = this.editor.getCursor()
|
||||
this.editor.setValue(value)
|
||||
this.editor.setCursor(cursor)
|
||||
}
|
||||
@@ -213,9 +215,7 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
insertImageMd (imageMd) {
|
||||
const textarea = this.editor.getInputField()
|
||||
const cm = this.editor
|
||||
cm.replaceSelection(`${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`)
|
||||
this.editor.replaceSelection(imageMd)
|
||||
}
|
||||
|
||||
handlePaste (editor, e) {
|
||||
@@ -223,7 +223,7 @@ export default class CodeEditor extends React.Component {
|
||||
if (!dataTransferItem.type.match('image')) return
|
||||
|
||||
const blob = dataTransferItem.getAsFile()
|
||||
let reader = new FileReader()
|
||||
const reader = new FileReader()
|
||||
let base64data
|
||||
|
||||
reader.readAsDataURL(blob)
|
||||
@@ -243,7 +243,8 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, fontFamily, fontSize } = this.props
|
||||
const { className, fontSize } = this.props
|
||||
let fontFamily = this.props.className
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './MarkdownEditor.styl'
|
||||
import CodeEditor from 'browser/components/CodeEditor'
|
||||
import MarkdownPreview from 'browser/components/MarkdownPreview'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
const _ = require('lodash')
|
||||
|
||||
class MarkdownEditor extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -70,9 +70,9 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
handleContextMenu (e) {
|
||||
let { config } = this.props
|
||||
const { config } = this.props
|
||||
if (config.editor.switchPreview === 'RIGHTCLICK') {
|
||||
let newStatus = this.state.status === 'PREVIEW'
|
||||
const newStatus = this.state.status === 'PREVIEW'
|
||||
? 'CODE'
|
||||
: 'PREVIEW'
|
||||
this.setState({
|
||||
@@ -91,9 +91,9 @@ class MarkdownEditor extends React.Component {
|
||||
handleBlur (e) {
|
||||
if (this.state.isLocked) return
|
||||
this.setState({ keyPressed: new Set() })
|
||||
let { config } = this.props
|
||||
const { config } = this.props
|
||||
if (config.editor.switchPreview === 'BLUR') {
|
||||
let cursorPosition = this.refs.code.editor.getCursor()
|
||||
const cursorPosition = this.refs.code.editor.getCursor()
|
||||
this.setState({
|
||||
status: 'PREVIEW'
|
||||
}, () => {
|
||||
@@ -109,7 +109,7 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
handlePreviewMouseUp (e) {
|
||||
let { config } = this.props
|
||||
const { config } = this.props
|
||||
if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) {
|
||||
this.setState({
|
||||
status: 'CODE'
|
||||
@@ -123,15 +123,15 @@ class MarkdownEditor extends React.Component {
|
||||
handleCheckboxClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let idMatch = /checkbox-([0-9]+)/
|
||||
let checkedMatch = /\[x\]/i
|
||||
let uncheckedMatch = /\[ \]/
|
||||
const idMatch = /checkbox-([0-9]+)/
|
||||
const checkedMatch = /\[x\]/i
|
||||
const uncheckedMatch = /\[ \]/
|
||||
if (idMatch.test(e.target.getAttribute('id'))) {
|
||||
let lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
|
||||
let lines = this.refs.code.value
|
||||
const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
|
||||
const lines = this.refs.code.value
|
||||
.split('\n')
|
||||
|
||||
let targetLine = lines[lineIndex]
|
||||
const targetLine = lines[lineIndex]
|
||||
|
||||
if (targetLine.match(checkedMatch)) {
|
||||
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
|
||||
@@ -163,12 +163,12 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
let { config } = this.props
|
||||
const { config } = this.props
|
||||
if (this.state.status !== 'CODE') return false
|
||||
const keyPressed = this.state.keyPressed
|
||||
keyPressed.add(e.keyCode)
|
||||
this.setState({ keyPressed })
|
||||
let isNoteHandlerKey = (el) => { return keyPressed.has(el) }
|
||||
const isNoteHandlerKey = (el) => { return keyPressed.has(el) }
|
||||
// These conditions are for ctrl-e and ctrl-w
|
||||
if (keyPressed.size === this.escapeFromEditor.length &&
|
||||
!this.state.isLocked && this.state.status === 'CODE' &&
|
||||
@@ -207,14 +207,14 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, value, config, storageKey } = this.props
|
||||
const { className, value, config, storageKey } = this.props
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
|
||||
let previewStyle = {}
|
||||
const previewStyle = {}
|
||||
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
|
||||
|
||||
const storage = findStorage(storageKey)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import markdown from 'browser/lib/markdown'
|
||||
import _ from 'lodash'
|
||||
import CodeMirror from 'codemirror'
|
||||
@@ -33,6 +34,15 @@ function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber) {
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('${appPath}/resources/fonts/Lato-Black.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.woff') format('woff'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
${markdownStyle}
|
||||
body {
|
||||
font-family: '${fontFamily.join("','")}';
|
||||
@@ -117,10 +127,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
let anchor = e.target.closest('a')
|
||||
let href = anchor.getAttribute('href')
|
||||
const anchor = e.target.closest('a')
|
||||
const href = anchor.getAttribute('href')
|
||||
if (_.isString(href) && href.match(/^#/)) {
|
||||
let targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length))
|
||||
const targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length))
|
||||
if (targetElement != null) {
|
||||
this.getWindow().scrollTo(0, targetElement.offsetTop)
|
||||
}
|
||||
@@ -242,7 +252,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
applyStyle () {
|
||||
let { fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props
|
||||
const { fontSize, lineNumber, codeBlockTheme } = this.props
|
||||
let { fontFamily, codeBlockFontFamily } = this.props
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
|
||||
? [fontFamily].concat(defaultFontFamily)
|
||||
: defaultFontFamily
|
||||
@@ -258,7 +269,9 @@ export default class MarkdownPreview extends React.Component {
|
||||
theme = consts.THEMES.some((_theme) => _theme === theme) && theme !== 'default'
|
||||
? theme
|
||||
: 'elegant'
|
||||
this.getWindow().document.getElementById('codeTheme').href = `${appPath}/node_modules/codemirror/theme/${theme.split(' ')[0]}.css`
|
||||
this.getWindow().document.getElementById('codeTheme').href = theme.startsWith('solarized')
|
||||
? `${appPath}/node_modules/codemirror/theme/solarized.css`
|
||||
: `${appPath}/node_modules/codemirror/theme/${theme}.css`
|
||||
}
|
||||
|
||||
rewriteIframe () {
|
||||
@@ -273,7 +286,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
el.removeEventListener('click', this.linkClickHandler)
|
||||
})
|
||||
|
||||
let { value, theme, indentSize, codeBlockTheme, showCopyNotification, storagePath } = this.props
|
||||
const { theme, indentSize, showCopyNotification, storagePath } = this.props
|
||||
let { value, codeBlockTheme } = this.props
|
||||
|
||||
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
|
||||
|
||||
@@ -316,7 +330,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
let syntax = CodeMirror.findModeByName(el.className)
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
CodeMirror.requireMode(syntax.mode, () => {
|
||||
let content = htmlTextHelper.decodeEntities(el.innerHTML)
|
||||
const content = htmlTextHelper.decodeEntities(el.innerHTML)
|
||||
const copyIcon = document.createElement('i')
|
||||
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
|
||||
copyIcon.onclick = (e) => {
|
||||
@@ -341,7 +355,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
})
|
||||
})
|
||||
})
|
||||
let opts = {}
|
||||
const opts = {}
|
||||
// if (this.props.theme === 'dark') {
|
||||
// opts['font-color'] = '#DDD'
|
||||
// opts['line-color'] = '#DDD'
|
||||
@@ -351,7 +365,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.flowchart'), (el) => {
|
||||
Raphael.setWindow(this.getWindow())
|
||||
try {
|
||||
let diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML))
|
||||
const diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML))
|
||||
el.innerHTML = ''
|
||||
diagram.drawSVG(el, opts)
|
||||
_.forEach(el.querySelectorAll('a'), (el) => {
|
||||
@@ -367,7 +381,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.sequence'), (el) => {
|
||||
Raphael.setWindow(this.getWindow())
|
||||
try {
|
||||
let diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML))
|
||||
const diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML))
|
||||
el.innerHTML = ''
|
||||
diagram.drawSVG(el, {theme: 'simple'})
|
||||
_.forEach(el.querySelectorAll('a'), (el) => {
|
||||
@@ -390,11 +404,11 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
scrollTo (targetRow) {
|
||||
let blocks = this.getWindow().document.querySelectorAll('body>[data-line]')
|
||||
const blocks = this.getWindow().document.querySelectorAll('body>[data-line]')
|
||||
|
||||
for (let index = 0; index < blocks.length; index++) {
|
||||
let block = blocks[index]
|
||||
let row = parseInt(block.getAttribute('data-line'))
|
||||
const row = parseInt(block.getAttribute('data-line'))
|
||||
if (row > targetRow || index === blocks.length - 1) {
|
||||
block = blocks[index - 1]
|
||||
block != null && this.getWindow().scrollTo(0, block.offsetTop)
|
||||
@@ -424,7 +438,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, style, tabIndex } = this.props
|
||||
const { className, style, tabIndex } = this.props
|
||||
return (
|
||||
<iframe className={className != null
|
||||
? 'MarkdownPreview ' + className
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, {PropTypes} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './ModalEscButton.styl'
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Micro component for toggle SideNav
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import styles from './NavToggleButton.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
line-height 32px
|
||||
padding 0
|
||||
|
||||
body[data-theme="white"]
|
||||
navWhiteButtonColor()
|
||||
|
||||
body[data-theme="dark"]
|
||||
.navToggle
|
||||
&:hover
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Note item component.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { isArray } from 'lodash'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import { getTodoStatus } from 'browser/lib/getTodoStatus'
|
||||
@@ -70,7 +71,7 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont
|
||||
|
||||
<div styleName='item-bottom-time'>{dateDisplay}</div>
|
||||
{note.isStarred
|
||||
? <i styleName='item-star' className='fa fa-star' /> : ''
|
||||
? <img styleName='item-star' src='../resources/icon/icon-starred.svg' /> : ''
|
||||
}
|
||||
{note.isPinned && !pathname.match(/\/home|\/starred|\/trash/)
|
||||
? <i styleName='item-pin' className='fa fa-thumb-tack' /> : ''
|
||||
|
||||
@@ -11,9 +11,9 @@ $control-height = 30px
|
||||
user-select none
|
||||
cursor pointer
|
||||
background-color $ui-noteList-backgroundColor
|
||||
transition background-color 0.2s
|
||||
transition 0.2s
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
.item-title
|
||||
.item-title-icon
|
||||
.item-bottom-time
|
||||
@@ -25,7 +25,7 @@ $control-height = 30px
|
||||
.item-star
|
||||
color $ui-favorite-star-button-color
|
||||
&:active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
.item-title
|
||||
.item-title-icon
|
||||
@@ -43,7 +43,7 @@ $control-height = 30px
|
||||
|
||||
.item--active
|
||||
@extend .item
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
color $ui-text-color
|
||||
.item-title
|
||||
.item-title-empty
|
||||
@@ -59,12 +59,12 @@ $control-height = 30px
|
||||
.item-star
|
||||
color $ui-favorite-star-button-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
@@ -73,14 +73,16 @@ $control-height = 30px
|
||||
position relative
|
||||
font-size 12px
|
||||
color $ui-inactive-text-color
|
||||
top 2px
|
||||
|
||||
.item-title
|
||||
font-size 14px
|
||||
font-size 15px
|
||||
font-weight 700
|
||||
position relative
|
||||
top -12px
|
||||
left 20px
|
||||
padding-right 15px
|
||||
padding-bottom 4px
|
||||
padding 0px 15px 0px 0px
|
||||
margin-bottom 4px
|
||||
overflow ellipsis
|
||||
color $ui-inactive-text-color
|
||||
|
||||
@@ -91,7 +93,7 @@ $control-height = 30px
|
||||
.item-bottom
|
||||
position relative
|
||||
bottom 0px
|
||||
margin-top 2px
|
||||
margin-top 10px
|
||||
font-size 12px
|
||||
line-height 20px
|
||||
overflow ellipsis
|
||||
@@ -100,19 +102,17 @@ $control-height = 30px
|
||||
.item-bottom-tagList
|
||||
flex 1
|
||||
overflow ellipsis
|
||||
line-height 20px
|
||||
padding-top 7px
|
||||
line-height 25px
|
||||
padding-left 2px
|
||||
margin-right 27px
|
||||
margin-right 40px
|
||||
|
||||
.item-bottom-tagList-item
|
||||
font-size 11px
|
||||
margin-right 8px
|
||||
padding 0
|
||||
height 20px
|
||||
box-sizing border-box
|
||||
border-radius 2px
|
||||
padding 1px 2px
|
||||
padding 4px
|
||||
vertical-align middle
|
||||
background-color white
|
||||
color $ui-inactive-text-color
|
||||
@@ -125,10 +125,10 @@ $control-height = 30px
|
||||
|
||||
.item-star
|
||||
position absolute
|
||||
right -20px
|
||||
bottom 2px
|
||||
width 34px
|
||||
height 34px
|
||||
right -6px
|
||||
bottom 23px
|
||||
width 16px
|
||||
height 16px
|
||||
color alpha($ui-favorite-star-button-color, 60%)
|
||||
font-size 12px
|
||||
padding 0
|
||||
@@ -136,8 +136,8 @@ $control-height = 30px
|
||||
|
||||
.item-pin
|
||||
position absolute
|
||||
right -21px
|
||||
bottom 28px
|
||||
right 0px
|
||||
bottom 2px
|
||||
width 34px
|
||||
height 34px
|
||||
color #E54D42
|
||||
@@ -145,6 +145,20 @@ $control-height = 30px
|
||||
padding 0
|
||||
border-radius 17px
|
||||
|
||||
body[data-theme="white"]
|
||||
.item
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
&:active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.item--active
|
||||
@extend .item
|
||||
background-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
border-color $ui-dark-borderColor
|
||||
@@ -196,7 +210,7 @@ body[data-theme="dark"]
|
||||
background-color alpha(white, 10%)
|
||||
color $ui-dark-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
|
||||
color #c0392b
|
||||
.item-bottom-tagList-item
|
||||
background-color alpha(#fff, 20%)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Note item component with simple display mode.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NoteItemSimple.styl'
|
||||
|
||||
|
||||
@@ -11,15 +11,15 @@ $control-height = 30px
|
||||
user-select none
|
||||
cursor pointer
|
||||
background-color $ui-noteList-backgroundColor
|
||||
transition background-color 0.15s
|
||||
transition 0.2s
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
.item-simple-title
|
||||
.item-simple-title-empty
|
||||
.item-simple-title-icon
|
||||
color $ui-text-color
|
||||
&:active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
.item-simple-title
|
||||
.item-simple-title-empty
|
||||
@@ -28,7 +28,7 @@ $control-height = 30px
|
||||
|
||||
.item-simple--active
|
||||
@extend .item-simple
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
color $ui-text-color
|
||||
.item-simple-title
|
||||
.item-simple-title-empty
|
||||
@@ -37,12 +37,12 @@ $control-height = 30px
|
||||
.item-simple-title-icon
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
@@ -67,6 +67,20 @@ $control-height = 30px
|
||||
font-weight normal
|
||||
color $ui-inactive-text-color
|
||||
|
||||
body[data-theme="white"]
|
||||
.item-simple
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
&:active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.item-simple--active
|
||||
@extend .item-simple
|
||||
background-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
border-color $ui-dark-borderColor
|
||||
@@ -115,7 +129,7 @@ body[data-theme="dark"]
|
||||
background-color alpha(white, 10%)
|
||||
color $ui-dark-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
|
||||
color #c0392b
|
||||
.item-simple-bottom-tagList-item
|
||||
background-color alpha(#fff, 20%)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './RealtimeNotification.styl'
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Filter for all notes.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './SideNavFilter.styl'
|
||||
|
||||
@@ -15,27 +16,53 @@ import styles from './SideNavFilter.styl'
|
||||
*/
|
||||
const SideNavFilter = ({
|
||||
isFolded, isHomeActive, handleAllNotesButtonClick,
|
||||
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick
|
||||
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote,
|
||||
counterTotalNote, counterStarredNote
|
||||
}) => (
|
||||
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
|
||||
|
||||
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
|
||||
onClick={handleAllNotesButtonClick}
|
||||
>
|
||||
<i className='fa fa-archive fa-fw' />
|
||||
<div styleName='iconWrap'>
|
||||
<img src={isHomeActive
|
||||
? '../resources/icon/icon-all-active.svg'
|
||||
: '../resources/icon/icon-all.svg'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<span styleName='menu-button-label'>All Notes</span>
|
||||
<span styleName='counters'>{counterTotalNote}</span>
|
||||
</button>
|
||||
|
||||
<button styleName={isStarredActive ? 'menu-button-star--active' : 'menu-button'}
|
||||
onClick={handleStarredButtonClick}
|
||||
>
|
||||
<i className='fa fa-star fa-fw' />
|
||||
<div styleName='iconWrap'>
|
||||
<img src={isStarredActive
|
||||
? '../resources/icon/icon-star-active.svg'
|
||||
: '../resources/icon/icon-star.svg'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<span styleName='menu-button-label'>Starred</span>
|
||||
<span styleName='counters'>{counterStarredNote}</span>
|
||||
</button>
|
||||
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
|
||||
|
||||
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
|
||||
onClick={handleTrashedButtonClick}
|
||||
>
|
||||
<i className='fa fa-trash fa-fw' />
|
||||
<div styleName='iconWrap'>
|
||||
<img src={isTrashedActive
|
||||
? '../resources/icon/icon-trash-active.svg'
|
||||
: '../resources/icon/icon-trash.svg'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<span styleName='menu-button-label'>Trash</span>
|
||||
<span styleName='counters'>{counterDelNote}</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -3,49 +3,55 @@
|
||||
|
||||
.menu-button
|
||||
navButtonColor()
|
||||
height 32px
|
||||
padding 0 15px
|
||||
font-size 13px
|
||||
height 36px
|
||||
padding 0 15px 0 20px
|
||||
font-size 14px
|
||||
width 100%
|
||||
text-align left
|
||||
overflow ellipsis
|
||||
display flex
|
||||
align-items center
|
||||
&:hover, &:active, &:active:hover
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
|
||||
.iconWrap
|
||||
width 20px
|
||||
text-align center
|
||||
|
||||
.counters
|
||||
float right
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.menu-button--active
|
||||
@extend .menu-button
|
||||
color #e74c3c
|
||||
background-color $ui-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
SideNavFilter()
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
.menu-button-label, .counters
|
||||
color #1EC38B
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
color #1EC38B
|
||||
|
||||
.menu-button-star--active
|
||||
@extend .menu-button
|
||||
color #F9BF3B
|
||||
background-color $ui-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #F9BF3B
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #F9BF3B
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
SideNavFilter()
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
.menu-button-label, .counters
|
||||
color #1EC38B
|
||||
|
||||
.menu-button-trash--active
|
||||
@extend .menu-button
|
||||
SideNavFilter()
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
.menu-button-label, .counters
|
||||
color #1EC38B
|
||||
|
||||
.menu-button-label
|
||||
margin-left 5px
|
||||
margin-left 10px
|
||||
flex 1
|
||||
|
||||
.menu--folded
|
||||
@extend .menu
|
||||
@@ -54,6 +60,10 @@
|
||||
&:hover .menu-button-label
|
||||
transition opacity 0.15s
|
||||
opacity 1
|
||||
color $ui-tooltip-text-color
|
||||
background-color $ui-tooltip-backgroundColor
|
||||
|
||||
|
||||
.menu-button-label
|
||||
position fixed
|
||||
display inline-block
|
||||
@@ -63,15 +73,73 @@
|
||||
margin-top -8px
|
||||
margin-left 0
|
||||
overflow ellipsis
|
||||
background-color $ui-tooltip-backgroundColor
|
||||
z-index 10
|
||||
color white
|
||||
line-height 32px
|
||||
border-top-right-radius 2px
|
||||
border-bottom-right-radius 2px
|
||||
pointer-events none
|
||||
opacity 0
|
||||
font-size 13px
|
||||
.counters
|
||||
display none
|
||||
|
||||
body[data-theme="white"]
|
||||
.menu-button
|
||||
navWhiteButtonColor()
|
||||
|
||||
.counters
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.menu-button--active
|
||||
@extend .menu-button
|
||||
color #e74c3c
|
||||
background-color $ui-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #e74c3c
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
|
||||
.menu-button-star--active
|
||||
@extend .menu-button
|
||||
color #F9BF3B
|
||||
background-color $ui-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #F9BF3B
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #F9BF3B
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
|
||||
.menu-button-trash--active
|
||||
@extend .menu-button
|
||||
color #5D9E36
|
||||
background-color $ui-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #5D9E36
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
&:active, &:active:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #5D9E36
|
||||
.menu-button-label
|
||||
color $ui-text-color
|
||||
|
||||
body[data-theme="dark"]
|
||||
.menu-button
|
||||
@@ -103,3 +171,14 @@ body[data-theme="dark"]
|
||||
color $ui-favorite-star-button-color
|
||||
.menu-button-label
|
||||
color $ui-dark-text-color
|
||||
|
||||
.menu-button-trash--active
|
||||
color #5D9E36
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
.menu-button-label
|
||||
color $ui-dark-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
|
||||
color #5D9E36
|
||||
.menu-button-label
|
||||
color $ui-dark-text-color
|
||||
@@ -86,7 +86,7 @@ class SnippetTab extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { isActive, snippet, isDeletable } = this.props
|
||||
const { isActive, snippet, isDeletable } = this.props
|
||||
return (
|
||||
<div styleName={isActive
|
||||
? 'root--active'
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Micro component for showing storage.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import styles from './StorageItem.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import { isNumber } from 'lodash'
|
||||
|
||||
@@ -5,32 +5,31 @@
|
||||
.folderList-item
|
||||
display flex
|
||||
width 100%
|
||||
height 26px
|
||||
height 34px
|
||||
background-color transparent
|
||||
color $ui-inactive-text-color
|
||||
padding 0
|
||||
margin-bottom 5px
|
||||
text-align left
|
||||
border none
|
||||
overflow ellipsis
|
||||
font-size 13px
|
||||
font-size 14px
|
||||
&:first-child
|
||||
margin-top 0
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
color #1EC38B;
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
transition background-color 0.15s
|
||||
&:active
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
color $$ui-button-default-color
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
|
||||
.folderList-item--active
|
||||
@extend .folderList-item
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
color #1EC38B;
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 50%)
|
||||
|
||||
.folderList-item-name
|
||||
display block
|
||||
@@ -69,8 +68,28 @@
|
||||
|
||||
.folderList-item-name--folded
|
||||
@extend .folderList-item-name
|
||||
padding-left 12px
|
||||
padding-left 17px
|
||||
text
|
||||
display none
|
||||
|
||||
body[data-theme="white"]
|
||||
.folderList-item
|
||||
color $ui-inactive-text-color
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
transition background-color 0.15s
|
||||
&:active
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.folderList-item--active
|
||||
@extend .folderList-item
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 50%)
|
||||
|
||||
body[data-theme="dark"]
|
||||
.folderList-item
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* @fileoverview Micro component for showing StorageList
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import styles from './StorgaeList.styl'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import styles from './StorageList.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.storageList
|
||||
absolute left right
|
||||
bottom 37px
|
||||
top 160px
|
||||
top 180px
|
||||
overflow-y auto
|
||||
|
||||
.storageList-empty
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* @fileoverview Micro component for showing TagList.
|
||||
*/
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import styles from './TagListItem.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
&:first-child
|
||||
margin-top 0
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
color $ui-button-default-color
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
transition background-color 0.15s
|
||||
&:active
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
&:active, &:active:hover
|
||||
color $ui-button-default-color
|
||||
background-color $ui-button-default--active-backgroundColor
|
||||
|
||||
.tagList-item-active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color $ui-button-default--active-backgroundColor
|
||||
display flex
|
||||
width 100%
|
||||
height 26px
|
||||
@@ -31,8 +31,9 @@
|
||||
border none
|
||||
overflow ellipsis
|
||||
font-size 13px
|
||||
color $ui-button-default-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 60%)
|
||||
transition 0.2s
|
||||
|
||||
.tagList-item-name
|
||||
@@ -47,6 +48,22 @@
|
||||
overflow hidden
|
||||
text-overflow ellipsis
|
||||
|
||||
body[data-theme="white"]
|
||||
.tagList-item
|
||||
color $ui-inactive-text-color
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
&:active
|
||||
color $ui-text-color
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.tagList-item-active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-text-color
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||
|
||||
body[data-theme="dark"]
|
||||
.tagList-item
|
||||
color $ui-dark-inactive-text-color
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
* @fileoverview Percentage of todo achievement.
|
||||
*/
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TodoListPercentage.styl'
|
||||
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
.percentageBar
|
||||
position absolute
|
||||
top 58px
|
||||
right: 0px
|
||||
top 50px
|
||||
right 0px
|
||||
left 0px
|
||||
background-color #DADFE1
|
||||
width 100%
|
||||
height: 15px
|
||||
height: 17px
|
||||
font-size: 12px
|
||||
z-index 100
|
||||
border-radius 2px
|
||||
|
||||
.progressBar
|
||||
background-color: #6C7A89
|
||||
height 15px
|
||||
background-color: #1EC38B
|
||||
height 17px
|
||||
border-radius 2px
|
||||
transition 0.3s
|
||||
transition 0.4s cubic-bezier(0.4, 0.4, 0, 1)
|
||||
|
||||
.percentageText
|
||||
color #f4f4f4
|
||||
padding: 2px 43%
|
||||
font-weight 600
|
||||
|
||||
body[data-theme="dark"]
|
||||
.percentageBar
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
* @fileoverview Percentage of todo achievement.
|
||||
*/
|
||||
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TodoProcess.styl'
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ hr
|
||||
h1, h2, h3, h4, h5, h6
|
||||
font-weight bold
|
||||
h1
|
||||
font-size 2.25em
|
||||
font-size 2.55em
|
||||
padding-bottom 0.3em
|
||||
line-height 1.2em
|
||||
border-bottom solid 1px borderColor
|
||||
|
||||
@@ -64,7 +64,7 @@ $list-width = 250px
|
||||
|
||||
.result-nav-storageList
|
||||
absolute bottom left right
|
||||
top 110px + 32px + 10px + 10px
|
||||
top 110px + 32px + 10px + 10px + 20px
|
||||
overflow-y auto
|
||||
|
||||
.result-list
|
||||
|
||||
@@ -56,7 +56,7 @@ class NoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
selectPriorSnippet () {
|
||||
let { note } = this.props
|
||||
const { note } = this.props
|
||||
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
|
||||
this.setState({
|
||||
snippetIndex: (this.state.snippetIndex + note.snippets.length - 1) % note.snippets.length
|
||||
@@ -65,7 +65,7 @@ class NoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
selectNextSnippet () {
|
||||
let { note } = this.props
|
||||
const { note } = this.props
|
||||
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
|
||||
this.setState({
|
||||
snippetIndex: (this.state.snippetIndex + 1) % note.snippets.length
|
||||
@@ -74,7 +74,7 @@ class NoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
saveToClipboard () {
|
||||
let { note } = this.props
|
||||
const { note } = this.props
|
||||
|
||||
if (note.type === 'MARKDOWN_NOTE') {
|
||||
clipboard.writeText(note.content)
|
||||
@@ -95,7 +95,7 @@ class NoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { note, config } = this.props
|
||||
const { note, config } = this.props
|
||||
if (note == null) {
|
||||
return (
|
||||
<div styleName='root' />
|
||||
@@ -110,8 +110,8 @@ class NoteDetail extends React.Component {
|
||||
const storage = findStorage(note.storage)
|
||||
|
||||
if (note.type === 'SNIPPET_NOTE') {
|
||||
let tabList = note.snippets.map((snippet, index) => {
|
||||
let isActive = this.state.snippetIndex === index
|
||||
const tabList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
return <div styleName={isActive
|
||||
? 'tabList-item--active'
|
||||
: 'tabList-item'
|
||||
@@ -131,8 +131,8 @@ class NoteDetail extends React.Component {
|
||||
</div>
|
||||
})
|
||||
|
||||
let viewList = note.snippets.map((snippet, index) => {
|
||||
let isActive = this.state.snippetIndex === index
|
||||
const viewList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
|
||||
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
|
||||
@@ -18,18 +18,18 @@ class NoteList extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
let { index } = this.props
|
||||
const { index } = this.props
|
||||
|
||||
if (index > -1) {
|
||||
let list = this.refs.root
|
||||
let item = list.childNodes[index]
|
||||
const list = this.refs.root
|
||||
const item = list.childNodes[index]
|
||||
if (item == null) return null
|
||||
|
||||
let overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
|
||||
const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
|
||||
if (overflowBelow) {
|
||||
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
|
||||
}
|
||||
let overflowAbove = list.scrollTop > item.offsetTop
|
||||
const overflowAbove = list.scrollTop > item.offsetTop
|
||||
if (overflowAbove) {
|
||||
list.scrollTop = item.offsetTop
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class NoteList extends React.Component {
|
||||
}
|
||||
|
||||
handleScroll (e) {
|
||||
let { notes } = this.props
|
||||
const { notes } = this.props
|
||||
|
||||
if (e.target.offsetHeight + e.target.scrollTop > e.target.scrollHeight - 100 && notes.length > this.state.range * 10 + 10) {
|
||||
this.setState({
|
||||
@@ -54,9 +54,9 @@ class NoteList extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { notes, index } = this.props
|
||||
const { notes, index } = this.props
|
||||
|
||||
let notesList = notes
|
||||
const notesList = notes
|
||||
.slice(0, 10 + 10 * this.state.range)
|
||||
.map((note, _index) => {
|
||||
const isActive = (index === _index)
|
||||
|
||||
@@ -19,18 +19,18 @@ class StorageSection extends React.Component {
|
||||
}
|
||||
|
||||
handleHeaderClick (e) {
|
||||
let { storage } = this.props
|
||||
const { storage } = this.props
|
||||
this.props.handleStorageButtonClick(e, storage.key)
|
||||
}
|
||||
|
||||
handleFolderClick (e, folder) {
|
||||
let { storage } = this.props
|
||||
const { storage } = this.props
|
||||
this.props.handleFolderButtonClick(e, storage.key, folder.key)
|
||||
}
|
||||
|
||||
render () {
|
||||
let { storage, filter } = this.props
|
||||
let folderList = storage.folders
|
||||
const { storage, filter } = this.props
|
||||
const folderList = storage.folders
|
||||
.map(folder => (
|
||||
<StorageItem
|
||||
key={folder.key}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { connect, Provider } from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
import ipc from './ipcClient'
|
||||
import store from './store'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './FinderMain.styl'
|
||||
@@ -19,7 +19,7 @@ const { remote } = electron
|
||||
const { Menu } = remote
|
||||
|
||||
function hideFinder () {
|
||||
let finderWindow = remote.getCurrentWindow()
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
if (global.process.platform === 'win32') {
|
||||
finderWindow.blur()
|
||||
finderWindow.hide()
|
||||
@@ -136,7 +136,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleOnlySnippetCheckboxChange (e) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.includeSnippet = e.target.checked
|
||||
this.setState({
|
||||
filter: filter,
|
||||
@@ -147,7 +147,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleOnlyMarkdownCheckboxChange (e) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.includeMarkdown = e.target.checked
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
@@ -159,7 +159,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleAllNotesButtonClick (e) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.type = 'ALL'
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
@@ -171,7 +171,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleStarredButtonClick (e) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.type = 'STARRED'
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
@@ -183,7 +183,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleStorageButtonClick (e, storage) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.type = 'STORAGE'
|
||||
filter.storage = storage
|
||||
this.refs.list.resetScroll()
|
||||
@@ -196,7 +196,7 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
handleFolderButtonClick (e, storage, folder) {
|
||||
let { filter } = this.state
|
||||
const { filter } = this.state
|
||||
filter.type = 'FOLDER'
|
||||
filter.storage = storage
|
||||
filter.folder = folder
|
||||
@@ -218,12 +218,12 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, config } = this.props
|
||||
let { filter, search } = this.state
|
||||
let storageList = []
|
||||
for (let key in data.storageMap) {
|
||||
let storage = data.storageMap[key]
|
||||
let item = (
|
||||
const { data, config } = this.props
|
||||
const { filter, search } = this.state
|
||||
const storageList = []
|
||||
for (const key in data.storageMap) {
|
||||
const storage = data.storageMap[key]
|
||||
const item = (
|
||||
<StorageSection
|
||||
filter={filter}
|
||||
storage={storage}
|
||||
@@ -252,7 +252,7 @@ class FinderMain extends React.Component {
|
||||
notes.push(data.noteMap[id])
|
||||
})
|
||||
} else {
|
||||
for (let key in data.noteMap) {
|
||||
for (const key in data.noteMap) {
|
||||
notes.push(data.noteMap[key])
|
||||
}
|
||||
}
|
||||
@@ -264,13 +264,13 @@ class FinderMain extends React.Component {
|
||||
}
|
||||
|
||||
if (search.trim().length > 0) {
|
||||
let needle = new RegExp(_.escapeRegExp(search.trim()), 'i')
|
||||
const needle = new RegExp(_.escapeRegExp(search.trim()), 'i')
|
||||
notes = notes.filter((note) => note.title.match(needle))
|
||||
}
|
||||
notes = notes
|
||||
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
|
||||
|
||||
let activeNote = notes[this.state.index]
|
||||
const activeNote = notes[this.state.index]
|
||||
this.noteCount = notes.length
|
||||
|
||||
return (
|
||||
|
||||
@@ -10,7 +10,7 @@ nodeIpc.config.retry = 1500
|
||||
nodeIpc.config.silent = true
|
||||
|
||||
function killFinder () {
|
||||
let finderWindow = remote.getCurrentWindow()
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
finderWindow.removeAllListeners()
|
||||
if (global.process.platform === 'darwin') {
|
||||
// Only OSX has another app process.
|
||||
@@ -21,7 +21,7 @@ function killFinder () {
|
||||
}
|
||||
|
||||
function toggleFinder () {
|
||||
let finderWindow = remote.getCurrentWindow()
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
if (global.process.platform === 'darwin') {
|
||||
if (finderWindow.isVisible()) {
|
||||
finderWindow.hide()
|
||||
@@ -84,6 +84,8 @@ nodeIpc.connectTo(
|
||||
const { config } = payload
|
||||
if (config.ui.theme === 'dark') {
|
||||
document.body.setAttribute('data-theme', 'dark')
|
||||
} else if (config.ui.theme === 'white') {
|
||||
document.body.setAttribute('data-theme', 'white')
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { combineReducers, createStore } from 'redux'
|
||||
import { routerReducer } from 'react-router-redux'
|
||||
import { DEFAULT_CONFIG } from 'browser/main/lib/ConfigManager'
|
||||
|
||||
let defaultData = {
|
||||
const defaultData = {
|
||||
storageMap: {},
|
||||
noteMap: {},
|
||||
starredSet: [],
|
||||
@@ -40,12 +40,12 @@ function config (state = DEFAULT_CONFIG, action) {
|
||||
return state
|
||||
}
|
||||
|
||||
let reducer = combineReducers({
|
||||
const reducer = combineReducers({
|
||||
data,
|
||||
config,
|
||||
routing: routerReducer
|
||||
})
|
||||
|
||||
let store = createStore(reducer)
|
||||
const store = createStore(reducer)
|
||||
|
||||
export default store
|
||||
|
||||
@@ -38,15 +38,15 @@ class MutableMap {
|
||||
}
|
||||
|
||||
map (cb) {
|
||||
let result = []
|
||||
for (let [key, value] of this._map) {
|
||||
const result = []
|
||||
for (const [key, value] of this._map) {
|
||||
result.push(cb(value, key))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
toJS () {
|
||||
let result = {}
|
||||
const result = {}
|
||||
for (let [key, value] of this._map) {
|
||||
if (value instanceof MutableSet || value instanceof MutableMap) {
|
||||
value = value.toJS()
|
||||
@@ -85,7 +85,7 @@ class MutableSet {
|
||||
}
|
||||
|
||||
map (cb) {
|
||||
let result = []
|
||||
const result = []
|
||||
this._set.forEach(function (value, key) {
|
||||
result.push(cb(value, key))
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export function findNoteTitle (value) {
|
||||
let splitted = value.split('\n')
|
||||
const splitted = value.split('\n')
|
||||
let title = null
|
||||
let isInsideCodeBlock = false
|
||||
|
||||
splitted.some((line, index) => {
|
||||
let trimmedLine = line.trim()
|
||||
let trimmedNextLine = splitted[index + 1] === undefined ? '' : splitted[index + 1].trim()
|
||||
const trimmedLine = line.trim()
|
||||
const trimmedNextLine = splitted[index + 1] === undefined ? '' : splitted[index + 1].trim()
|
||||
if (trimmedLine.match('```')) {
|
||||
isInsideCodeBlock = !isInsideCodeBlock
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export function getTodoStatus (content) {
|
||||
let splitted = content.split('\n')
|
||||
const splitted = content.split('\n')
|
||||
let numberOfTodo = 0
|
||||
let numberOfCompletedTodo = 0
|
||||
|
||||
splitted.forEach((line) => {
|
||||
let trimmedLine = line.trim()
|
||||
const trimmedLine = line.trim()
|
||||
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
|
||||
numberOfTodo++
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ import emoji from 'markdown-it-emoji'
|
||||
import math from '@rokt33r/markdown-it-math'
|
||||
import _ from 'lodash'
|
||||
|
||||
// FIXME We should not depend on global variable.
|
||||
const katex = window.katex
|
||||
|
||||
function createGutter (str) {
|
||||
let lc = (str.match(/\n/g) || []).length
|
||||
let lines = []
|
||||
const lc = (str.match(/\n/g) || []).length
|
||||
const lines = []
|
||||
for (let i = 1; i <= lc; i++) {
|
||||
lines.push('<span class="CodeMirror-linenumber">' + i + '</span>')
|
||||
}
|
||||
@@ -75,8 +76,8 @@ md.use(require('markdown-it-plantuml'))
|
||||
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
|
||||
let content, terminate, i, l, token
|
||||
let nextLine = startLine + 1
|
||||
let terminatorRules = state.md.block.ruler.getRules('paragraph')
|
||||
let endLine = state.lineMax
|
||||
const terminatorRules = state.md.block.ruler.getRules('paragraph')
|
||||
const endLine = state.lineMax
|
||||
|
||||
// jump line-by-line until empty one or EOF
|
||||
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
|
||||
@@ -106,7 +107,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
|
||||
token.map = [ startLine, state.line ]
|
||||
|
||||
if (state.parentType === 'list') {
|
||||
let match = content.match(/^\[( |x)\] ?(.+)/i)
|
||||
const match = content.match(/^\[( |x)\] ?(.+)/i)
|
||||
if (match) {
|
||||
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>`
|
||||
}
|
||||
@@ -123,7 +124,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
|
||||
})
|
||||
|
||||
// Add line number attribute for scrolling
|
||||
let originalRender = md.renderer.render
|
||||
const originalRender = md.renderer.render
|
||||
md.renderer.render = function render (tokens, options, env) {
|
||||
tokens.forEach((token) => {
|
||||
switch (token.type) {
|
||||
@@ -134,40 +135,12 @@ md.renderer.render = function render (tokens, options, env) {
|
||||
token.attrPush(['data-line', token.map[0]])
|
||||
}
|
||||
})
|
||||
let result = originalRender.call(md.renderer, tokens, options, env)
|
||||
const result = originalRender.call(md.renderer, tokens, options, env)
|
||||
return result
|
||||
}
|
||||
// FIXME We should not depend on global variable.
|
||||
window.md = md
|
||||
|
||||
function strip (input) {
|
||||
var output = input
|
||||
try {
|
||||
output = output
|
||||
.replace(/^([\s\t]*)([\*\-\+]|\d\.)\s+/gm, '$1')
|
||||
.replace(/\n={2,}/g, '\n')
|
||||
.replace(/~~/g, '')
|
||||
.replace(/`{3}.*\n/g, '')
|
||||
.replace(/<(.*?)>/g, '$1')
|
||||
.replace(/^[=\-]{2,}\s*$/g, '')
|
||||
.replace(/\[\^.+?\](: .*?$)?/g, '')
|
||||
.replace(/\s{0,2}\[.*?\]: .*?$/g, '')
|
||||
.replace(/!\[.*?\][\[\(].*?[\]\)]/g, '')
|
||||
.replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1')
|
||||
.replace(/>/g, '')
|
||||
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '')
|
||||
.replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
|
||||
.replace(/([\*_]{1,3})(\S.*?\S)\1/g, '$2')
|
||||
.replace(/(`{3,})(.*?)\1/gm, '$2')
|
||||
.replace(/^-{3,}\s*$/g, '')
|
||||
.replace(/`(.+?)`/g, '$1')
|
||||
.replace(/\n{2,}/g, '\n\n')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return input
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
function normalizeLinkText (linkText) {
|
||||
return md.normalizeLinkText(linkText)
|
||||
}
|
||||
@@ -178,7 +151,7 @@ const markdown = {
|
||||
const renderedContent = md.render(content)
|
||||
return renderedContent
|
||||
},
|
||||
strip,
|
||||
normalizeLinkText
|
||||
}
|
||||
|
||||
export default markdown
|
||||
|
||||
39
browser/lib/markdownTextHelper.js
Normal file
39
browser/lib/markdownTextHelper.js
Normal 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
|
||||
}
|
||||
@@ -16,7 +16,7 @@ export default function searchFromNotes (notes, search) {
|
||||
|
||||
function findByTag (notes, block) {
|
||||
const tag = block.match(/#(.+)/)[1]
|
||||
let regExp = new RegExp(_.escapeRegExp(tag), 'i')
|
||||
const regExp = new RegExp(_.escapeRegExp(tag), 'i')
|
||||
return notes.filter((note) => {
|
||||
if (!_.isArray(note.tags)) return false
|
||||
return note.tags.some((_tag) => {
|
||||
@@ -26,7 +26,7 @@ function findByTag (notes, block) {
|
||||
}
|
||||
|
||||
function findByWord (notes, block) {
|
||||
let regExp = new RegExp(_.escapeRegExp(block), 'i')
|
||||
const regExp = new RegExp(_.escapeRegExp(block), 'i')
|
||||
return notes.filter((note) => {
|
||||
if (_.isArray(note.tags) && note.tags.some((_tag) => {
|
||||
return _tag.match(regExp)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
.root
|
||||
absolute top bottom right
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
|
||||
.empty
|
||||
height 320px
|
||||
@@ -8,8 +11,9 @@
|
||||
|
||||
.empty-message
|
||||
width 100%
|
||||
font-size 42px
|
||||
line-height 72px
|
||||
font-size 36px
|
||||
font-weight 600
|
||||
line-height 56px
|
||||
text-align center
|
||||
color $ui-inactive-text-color
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
*/
|
||||
|
||||
// Margin on the left side and the right side for NoteDetail component.
|
||||
$note-detail-left-margin = 25px
|
||||
$note-detail-right-margin = 25px
|
||||
$note-detail-left-margin = 100px
|
||||
$note-detail-right-margin = 120px
|
||||
$snippet-note-detail-left-margin = 60px
|
||||
$snippet-note-detail-right-margin = 80px
|
||||
|
||||
$note-detail-box-shadow = 2px 0 15px -8px #b1b1b1 inset
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './FolderSelect.styl'
|
||||
import _ from 'lodash'
|
||||
@@ -73,8 +74,8 @@ class FolderSelect extends React.Component {
|
||||
case 9:
|
||||
if (e.shiftKey) {
|
||||
e.preventDefault()
|
||||
let tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])')
|
||||
let previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1]
|
||||
const tabbable = document.querySelectorAll('a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])')
|
||||
const previousEl = tabbable[Array.prototype.indexOf.call(tabbable, this.refs.root) - 1]
|
||||
if (previousEl != null) previousEl.focus()
|
||||
}
|
||||
}
|
||||
@@ -89,9 +90,9 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
handleSearchInputChange (e) {
|
||||
let { folders } = this.props
|
||||
let search = this.refs.search.value
|
||||
let optionIndex = search.length > 0
|
||||
const { folders } = this.props
|
||||
const search = this.refs.search.value
|
||||
const optionIndex = search.length > 0
|
||||
? _.findIndex(folders, (folder) => {
|
||||
return folder.name.match(new RegExp('^' + _.escapeRegExp(search), 'i'))
|
||||
})
|
||||
@@ -129,7 +130,7 @@ class FolderSelect extends React.Component {
|
||||
|
||||
nextOption () {
|
||||
let { optionIndex } = this.state
|
||||
let { folders } = this.props
|
||||
const { folders } = this.props
|
||||
|
||||
optionIndex++
|
||||
if (optionIndex >= folders.length) optionIndex = 0
|
||||
@@ -140,7 +141,7 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
previousOption () {
|
||||
let { folders } = this.props
|
||||
const { folders } = this.props
|
||||
let { optionIndex } = this.state
|
||||
|
||||
optionIndex--
|
||||
@@ -152,10 +153,10 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
selectOption () {
|
||||
let { folders } = this.props
|
||||
let optionIndex = this.state.optionIndex
|
||||
const { folders } = this.props
|
||||
const optionIndex = this.state.optionIndex
|
||||
|
||||
let folder = folders[optionIndex]
|
||||
const folder = folders[optionIndex]
|
||||
if (folder != null) {
|
||||
this.setState({
|
||||
status: 'FOCUS'
|
||||
@@ -184,10 +185,10 @@ class FolderSelect extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, data, value } = this.props
|
||||
let splitted = value.split('-')
|
||||
let storageKey = splitted.shift()
|
||||
let folderKey = splitted.shift()
|
||||
const { className, data, value } = this.props
|
||||
const splitted = value.split('-')
|
||||
const storageKey = splitted.shift()
|
||||
const folderKey = splitted.shift()
|
||||
let options = []
|
||||
data.storageMap.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
@@ -198,14 +199,14 @@ class FolderSelect extends React.Component {
|
||||
})
|
||||
})
|
||||
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
if (this.state.search.trim().length > 0) {
|
||||
let filter = new RegExp('^' + _.escapeRegExp(this.state.search), 'i')
|
||||
const filter = new RegExp('^' + _.escapeRegExp(this.state.search), 'i')
|
||||
options = options.filter((option) => filter.test(option.folder.name))
|
||||
}
|
||||
|
||||
let optionList = options
|
||||
const optionList = options
|
||||
.map((option, index) => {
|
||||
return (
|
||||
<div styleName={index === this.state.optionIndex
|
||||
@@ -259,12 +260,11 @@ class FolderSelect extends React.Component {
|
||||
{optionList}
|
||||
</div>
|
||||
</div>
|
||||
: <div styleName='idle'>
|
||||
: <div styleName='idle' style={{color: currentOption.folder.color}}>
|
||||
<div styleName='idle-label'>
|
||||
<span styleName='idle-label-name'
|
||||
style={{color: currentOption.folder.color}}
|
||||
>
|
||||
{currentOption.folder.name} /
|
||||
<i className='fa fa-folder' />
|
||||
<span styleName='idle-label-name'>
|
||||
{currentOption.folder.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
.root
|
||||
position relative
|
||||
border solid 1px transparent
|
||||
line-height 26px
|
||||
vertical-align middle
|
||||
border-radius 2px
|
||||
transition 0.15s
|
||||
user-select none
|
||||
margin-right 10px
|
||||
&:hover
|
||||
background-color $ui-button--hover-backgroundColor
|
||||
|
||||
.root--search, .root--focus
|
||||
@extend .root
|
||||
background-color $ui-noteDetail-backgroundColor = #F4F4F4
|
||||
background-color $ui-noteDetail-backgroundColor = #fff
|
||||
border-color $ui-input--focus-borderColor
|
||||
width 100px
|
||||
width 154px
|
||||
height 30px
|
||||
&:hover
|
||||
border-color $ui-input--focus-borderColor
|
||||
border-color $ui-input--focus-borderColor = #fff
|
||||
|
||||
.idle
|
||||
position relative
|
||||
@@ -24,13 +25,16 @@
|
||||
.idle-label
|
||||
right 20px
|
||||
overflow ellipsis
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
.idle-label-name
|
||||
font-size 14px
|
||||
padding 2px
|
||||
font-size 13px
|
||||
font-weight 600
|
||||
margin-left 4px
|
||||
|
||||
.idle-label-name-surfix
|
||||
font-size 10px
|
||||
font-size 15px
|
||||
color $ui-inactive-text-color
|
||||
margin-left 5px
|
||||
.idle-caret
|
||||
@@ -38,40 +42,42 @@
|
||||
height 34px
|
||||
width 20px
|
||||
line-height 34px
|
||||
|
||||
.search
|
||||
absolute top left right bottom
|
||||
line-height 34px
|
||||
|
||||
|
||||
.search-input
|
||||
vertical-align middle
|
||||
position relative
|
||||
top -2px
|
||||
top 0
|
||||
font-size 14px
|
||||
outline none
|
||||
border none
|
||||
height 20px
|
||||
line-height 20px
|
||||
width 100%
|
||||
background-color transparent
|
||||
padding 0 10px
|
||||
|
||||
.search-optionList
|
||||
position fixed
|
||||
position absolute
|
||||
top 30px
|
||||
max-height 450px
|
||||
min-width 150px
|
||||
overflow auto
|
||||
z-index 200
|
||||
border $ui-border
|
||||
background-color white
|
||||
border-radius 2px
|
||||
padding 10px 6px
|
||||
|
||||
.search-optionList-item
|
||||
width 140px
|
||||
height 34px
|
||||
width 250px
|
||||
display flex
|
||||
align-items center
|
||||
box-sizing border-box
|
||||
padding 0 5px
|
||||
padding 0
|
||||
margin-bottom 10px
|
||||
overflow ellipsis
|
||||
cursor pointer
|
||||
&:hover
|
||||
background-color $ui-button--hover-backgroundColor
|
||||
background-color $ui-button--hover-backgroundColor
|
||||
|
||||
.search-optionList-item--active
|
||||
@extend .search-optionList-item
|
||||
@@ -81,13 +87,17 @@
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
.search-optionList-item-name
|
||||
border-left solid 2px transparent
|
||||
padding 2px 5px
|
||||
border-left solid 3px transparent
|
||||
padding 6px
|
||||
.search-optionList-item-name-surfix
|
||||
font-size 10px
|
||||
color $ui-inactive-text-color
|
||||
margin-left 5px
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
color $ui-dark-text-color
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoButton.styl'
|
||||
|
||||
@@ -6,9 +7,9 @@ const InfoButton = ({
|
||||
onClick
|
||||
}) => (
|
||||
<button styleName='control-infoButton'
|
||||
onClick={onClick}
|
||||
onClick={(e) => onClick(e)}
|
||||
>
|
||||
<i className='fa fa-info infoButton' styleName='info-button' />
|
||||
<img className='infoButton' src='../resources/icon/icon-info.svg' />
|
||||
</button>
|
||||
)
|
||||
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
.control-infoButton
|
||||
float right
|
||||
top 10px
|
||||
margin-bottom 10px
|
||||
topBarButtonLight()
|
||||
|
||||
.control-infoPanel
|
||||
position fixed
|
||||
pointer-events none
|
||||
top 50px
|
||||
z-index 200
|
||||
line-height normal
|
||||
border-radius 2px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
.infoButton
|
||||
padding 0px
|
||||
margin 15px 0
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-infoButton
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoPanel.styl'
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
.control-infoButton-panel
|
||||
z-index 200
|
||||
margin-top 38px
|
||||
margin-left -140px
|
||||
margin-top 0px
|
||||
right 0
|
||||
position absolute
|
||||
padding 20px 25px 0 25px
|
||||
width 300px
|
||||
height 500px
|
||||
height 350px
|
||||
overflow auto
|
||||
background-color $ui-noteList-backgroundColor
|
||||
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
|
||||
@@ -32,8 +32,8 @@
|
||||
|
||||
.control-infoButton-panel-trash
|
||||
z-index 200
|
||||
margin-top 45px
|
||||
margin-left -190px
|
||||
margin-top 0px
|
||||
right 0px
|
||||
position absolute
|
||||
padding 20px 25px 0 25px
|
||||
width 300px
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoPanel.styl'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './MarkdownNoteDetail.styl'
|
||||
import MarkdownEditor from 'browser/components/MarkdownEditor'
|
||||
@@ -9,12 +10,13 @@ import FolderSelect from './FolderSelect'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import { hashHistory } from 'react-router'
|
||||
import ee from 'browser/main/lib/eventEmitter'
|
||||
import markdown from 'browser/lib/markdown'
|
||||
import markdown from 'browser/lib/markdownTextHelper'
|
||||
import StatusBar from '../StatusBar'
|
||||
import _ from 'lodash'
|
||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import TrashButton from './TrashButton'
|
||||
import PermanentDeleteButton from './PermanentDeleteButton'
|
||||
import InfoButton from './InfoButton'
|
||||
import InfoPanel from './InfoPanel'
|
||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||
@@ -24,7 +26,7 @@ import striptags from 'striptags'
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote } = electron
|
||||
const { Menu, MenuItem, dialog } = remote
|
||||
const { dialog } = remote
|
||||
|
||||
class MarkdownNoteDetail extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -73,7 +75,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
|
||||
note.content = this.refs.content.value
|
||||
if (this.refs.tags) note.tags = this.refs.tags.value
|
||||
@@ -95,7 +97,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
saveNow () {
|
||||
let { note, dispatch } = this.props
|
||||
const { note, dispatch } = this.props
|
||||
clearTimeout(this.saveQueue)
|
||||
this.saveQueue = null
|
||||
|
||||
@@ -111,11 +113,11 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleFolderChange (e) {
|
||||
let { note } = this.state
|
||||
let value = this.refs.folder.value
|
||||
let splitted = value.split('-')
|
||||
let newStorageKey = splitted.shift()
|
||||
let newFolderKey = splitted.shift()
|
||||
const { note } = this.state
|
||||
const value = this.refs.folder.value
|
||||
const splitted = value.split('-')
|
||||
const newStorageKey = splitted.shift()
|
||||
const newFolderKey = splitted.shift()
|
||||
|
||||
dataApi
|
||||
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
|
||||
@@ -124,7 +126,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
isMovingNote: true,
|
||||
note: Object.assign({}, newNote)
|
||||
}, () => {
|
||||
let { dispatch, location } = this.props
|
||||
const { dispatch, location } = this.props
|
||||
dispatch({
|
||||
type: 'MOVE_NOTE',
|
||||
originNote: note,
|
||||
@@ -144,7 +146,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleStarButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
|
||||
|
||||
note.isStarred = !note.isStarred
|
||||
@@ -169,22 +171,22 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleTrashButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
const { isTrashed } = note
|
||||
|
||||
if (isTrashed) {
|
||||
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Confirm note deletion',
|
||||
detail: 'This will permanently remove this note.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (dialogueButtonIndex === 1) return
|
||||
let { note, dispatch } = this.props
|
||||
const { note, dispatch } = this.props
|
||||
dataApi
|
||||
.deleteNote(note.storage, note.key)
|
||||
.then((data) => {
|
||||
let dispatchHandler = () => {
|
||||
const dispatchHandler = () => {
|
||||
dispatch({
|
||||
type: 'DELETE_NOTE',
|
||||
storageKey: data.storageKey,
|
||||
@@ -206,7 +208,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleUndoButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
|
||||
note.isTrashed = false
|
||||
|
||||
@@ -231,7 +233,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
getToggleLockButton () {
|
||||
return this.state.isLocked ? 'fa-lock' : 'fa-unlock'
|
||||
return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg'
|
||||
}
|
||||
|
||||
handleDeleteKeyDown (e) {
|
||||
@@ -261,12 +263,12 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, config, location } = this.props
|
||||
let { note } = this.state
|
||||
let storageKey = note.storage
|
||||
let folderKey = note.folder
|
||||
const { data, config, location } = this.props
|
||||
const { note } = this.state
|
||||
const storageKey = note.storage
|
||||
const folderKey = note.folder
|
||||
|
||||
let options = []
|
||||
const options = []
|
||||
data.storageMap.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
options.push({
|
||||
@@ -275,7 +277,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
})
|
||||
})
|
||||
})
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
const trashTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
@@ -285,7 +287,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
@@ -302,10 +304,6 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
@@ -325,31 +323,38 @@ class MarkdownNoteDetail extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
|
||||
<StarButton
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
|
||||
{(() => {
|
||||
const faClassName = `fa ${this.getToggleLockButton()}`
|
||||
const imgSrc = `${this.getToggleLockButton()}`
|
||||
const lockButtonComponent =
|
||||
<button styleName='control-lockButton'
|
||||
onFocus={(e) => this.handleFocus(e)}
|
||||
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
||||
>
|
||||
<i className={faClassName} styleName='lock-button' />
|
||||
<span styleName='control-lockButton-tooltip'>
|
||||
{this.state.isLocked ? 'Unlock Editor' : 'Keep Editor Locked'}
|
||||
</span>
|
||||
<img styleName='iconInfo' src={imgSrc} />
|
||||
</button>
|
||||
|
||||
return (
|
||||
this.state.isLockButtonShown ? lockButtonComponent : ''
|
||||
)
|
||||
})()}
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
|
||||
</button>
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
|
||||
<InfoPanel
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
|
||||
@@ -3,47 +3,47 @@
|
||||
|
||||
.root
|
||||
absolute top right bottom
|
||||
border-width 0
|
||||
border-left 1px solid alpha(#DEDEDE, 60%)
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
box-shadow $note-detail-box-shadow
|
||||
box-shadow none
|
||||
padding 20px 40px
|
||||
|
||||
.lock-button
|
||||
padding-bottom 3px
|
||||
|
||||
.control-lockButton
|
||||
top 160px
|
||||
margin-bottom 10px
|
||||
topBarButtonLight()
|
||||
|
||||
.control-lockButton-tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
pointer-events none
|
||||
top 50px
|
||||
z-index 200
|
||||
padding 5px
|
||||
line-height normal
|
||||
border-radius 2px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
.trashed-infopanel
|
||||
top 40px
|
||||
position relative
|
||||
|
||||
.control-fullScreenButton
|
||||
float right
|
||||
padding 0 0 2px 0
|
||||
top 80px
|
||||
topBarButtonLight()
|
||||
|
||||
.body
|
||||
absolute left right
|
||||
left $note-detail-left-margin
|
||||
right $note-detail-right-margin
|
||||
left 0
|
||||
right 0
|
||||
top $info-height + $info-margin-under-border
|
||||
bottom $statusBar-height
|
||||
|
||||
margin 0 45px
|
||||
.body-noteEditor
|
||||
absolute top bottom left right
|
||||
|
||||
body[data-theme="white"]
|
||||
.root
|
||||
box-shadow $note-detail-box-shadow
|
||||
border none
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
box-shadow none
|
||||
border none
|
||||
|
||||
.control-lockButton
|
||||
topBarButtonDark()
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
@import('DetailVars')
|
||||
|
||||
$info-height = 60px
|
||||
$info-margin-under-border = 27px
|
||||
$info-height = 50px
|
||||
$info-margin-under-border = 30px
|
||||
|
||||
.info
|
||||
absolute top left right
|
||||
left $note-detail-left-margin
|
||||
right $note-detail-right-margin
|
||||
left 0
|
||||
right 0
|
||||
height $info-height
|
||||
border-bottom $ui-border
|
||||
border-bottom 1px solid #eee
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
width 100%
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
.info-left
|
||||
float left
|
||||
padding 0 5px
|
||||
margin 0px 2px
|
||||
.info-left-top
|
||||
display inline-block
|
||||
height $info-height
|
||||
line-height $info-height
|
||||
padding 0 10px
|
||||
width 100%
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
|
||||
.info-left-top-folderSelect
|
||||
padding 0 3px
|
||||
height 34px
|
||||
line-height 26px
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
border-radius 3px
|
||||
|
||||
.info-left-button
|
||||
width 34px
|
||||
height 34px
|
||||
@@ -48,18 +46,18 @@ $info-margin-under-border = 27px
|
||||
|
||||
.info-right
|
||||
position absolute
|
||||
right 0
|
||||
top 0
|
||||
background $ui-noteDetail-backgroundColor
|
||||
right 40px
|
||||
top 60px
|
||||
bottom 1px
|
||||
padding-left 30px
|
||||
z-index 101
|
||||
|
||||
.undo-button
|
||||
width 34px
|
||||
height 34px
|
||||
border-radius 17px
|
||||
font-size 14px
|
||||
margin 15px 7px
|
||||
margin 5px 0px
|
||||
border none
|
||||
color $ui-button-color
|
||||
display flex
|
||||
@@ -72,6 +70,7 @@ $info-margin-under-border = 27px
|
||||
border-color $ui-button--active-backgroundColor
|
||||
&:hover
|
||||
background-color alpha($ui-button--hover-backgroundColor, 60%)
|
||||
transition 0.2s
|
||||
.control-lockButton-tooltip
|
||||
opacity 1
|
||||
|
||||
|
||||
20
browser/main/Detail/PermanentDeleteButton.js
Normal file
20
browser/main/Detail/PermanentDeleteButton.js
Normal 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)
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './SnippetNoteDetail.styl'
|
||||
import CodeEditor from 'browser/components/CodeEditor'
|
||||
@@ -18,6 +19,7 @@ import _ from 'lodash'
|
||||
import { findNoteTitle } from 'browser/lib/findNoteTitle'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import TrashButton from './TrashButton'
|
||||
import PermanentDeleteButton from './PermanentDeleteButton'
|
||||
import InfoButton from './InfoButton'
|
||||
import InfoPanel from './InfoPanel'
|
||||
import InfoPanelTrashed from './InfoPanelTrashed'
|
||||
@@ -60,7 +62,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
|
||||
if (this.saveQueue != null) this.saveNow()
|
||||
let nextNote = Object.assign({
|
||||
const nextNote = Object.assign({
|
||||
description: ''
|
||||
}, nextProps.note, {
|
||||
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
|
||||
@@ -69,7 +71,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
snippetIndex: 0,
|
||||
note: nextNote
|
||||
}, () => {
|
||||
let { snippets } = this.state.note
|
||||
const { snippets } = this.state.note
|
||||
snippets.forEach((snippet, index) => {
|
||||
this.refs['code-' + index].reload()
|
||||
})
|
||||
@@ -83,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleChange (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
|
||||
if (this.refs.tags) note.tags = this.refs.tags.value
|
||||
note.description = this.refs.description.value
|
||||
@@ -105,7 +107,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
saveNow () {
|
||||
let { note, dispatch } = this.props
|
||||
const { note, dispatch } = this.props
|
||||
clearTimeout(this.saveQueue)
|
||||
this.saveQueue = null
|
||||
|
||||
@@ -121,11 +123,11 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleFolderChange (e) {
|
||||
let { note } = this.state
|
||||
let value = this.refs.folder.value
|
||||
let splitted = value.split('-')
|
||||
let newStorageKey = splitted.shift()
|
||||
let newFolderKey = splitted.shift()
|
||||
const { note } = this.state
|
||||
const value = this.refs.folder.value
|
||||
const splitted = value.split('-')
|
||||
const newStorageKey = splitted.shift()
|
||||
const newFolderKey = splitted.shift()
|
||||
|
||||
dataApi
|
||||
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
|
||||
@@ -134,7 +136,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
isMovingNote: true,
|
||||
note: Object.assign({}, newNote)
|
||||
}, () => {
|
||||
let { dispatch, location } = this.props
|
||||
const { dispatch, location } = this.props
|
||||
dispatch({
|
||||
type: 'MOVE_NOTE',
|
||||
originNote: note,
|
||||
@@ -154,7 +156,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleStarButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
|
||||
|
||||
note.isStarred = !note.isStarred
|
||||
@@ -171,22 +173,22 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleTrashButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
const { isTrashed } = note
|
||||
|
||||
if (isTrashed) {
|
||||
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Confirm note deletion',
|
||||
detail: 'This will permanently remove this note.',
|
||||
buttons: ['Confirm', 'Cancel']
|
||||
})
|
||||
if (dialogueButtonIndex === 1) return
|
||||
let { note, dispatch } = this.props
|
||||
const { note, dispatch } = this.props
|
||||
dataApi
|
||||
.deleteNote(note.storage, note.key)
|
||||
.then((data) => {
|
||||
let dispatchHandler = () => {
|
||||
const dispatchHandler = () => {
|
||||
dispatch({
|
||||
type: 'DELETE_NOTE',
|
||||
storageKey: data.storageKey,
|
||||
@@ -208,7 +210,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleUndoButtonClick (e) {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
|
||||
note.isTrashed = false
|
||||
|
||||
@@ -237,7 +239,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
handleTabDeleteButtonClick (e, index) {
|
||||
if (this.state.note.snippets.length > 1) {
|
||||
if (this.state.note.snippets[index].content.trim().length > 0) {
|
||||
let dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
const dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Delete a snippet',
|
||||
detail: 'This work cannot be undone.',
|
||||
@@ -287,7 +289,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
handleModeOptionClick (index, name) {
|
||||
return (e) => {
|
||||
let snippets = this.state.note.snippets.slice()
|
||||
const snippets = this.state.note.snippets.slice()
|
||||
snippets[index].mode = name
|
||||
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
|
||||
|
||||
@@ -305,7 +307,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
handleCodeChange (index) {
|
||||
return (e) => {
|
||||
let snippets = this.state.note.snippets.slice()
|
||||
const snippets = this.state.note.snippets.slice()
|
||||
snippets[index].content = this.refs['code-' + index].value
|
||||
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
|
||||
this.setState({
|
||||
@@ -332,7 +334,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
break
|
||||
case 76:
|
||||
{
|
||||
let isSuper = global.process.platform === 'darwin'
|
||||
const isSuper = global.process.platform === 'darwin'
|
||||
? e.metaKey
|
||||
: e.ctrlKey
|
||||
if (isSuper) {
|
||||
@@ -343,7 +345,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
break
|
||||
case 84:
|
||||
{
|
||||
let isSuper = global.process.platform === 'darwin'
|
||||
const isSuper = global.process.platform === 'darwin'
|
||||
? e.metaKey
|
||||
: e.ctrlKey
|
||||
if (isSuper) {
|
||||
@@ -356,7 +358,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleModeButtonClick (e, index) {
|
||||
let menu = new Menu()
|
||||
const menu = new Menu()
|
||||
CodeMirror.modeInfo.forEach((mode) => {
|
||||
menu.append(new MenuItem({
|
||||
label: mode.name,
|
||||
@@ -397,8 +399,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleIndentSizeItemClick (e, indentSize) {
|
||||
let { config, dispatch } = this.props
|
||||
let editor = Object.assign({}, config.editor, {
|
||||
const { config, dispatch } = this.props
|
||||
const editor = Object.assign({}, config.editor, {
|
||||
indentSize
|
||||
})
|
||||
ConfigManager.set({
|
||||
@@ -413,8 +415,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
handleIndentTypeItemClick (e, indentType) {
|
||||
let { config, dispatch } = this.props
|
||||
let editor = Object.assign({}, config.editor, {
|
||||
const { config, dispatch } = this.props
|
||||
const editor = Object.assign({}, config.editor, {
|
||||
indentType
|
||||
})
|
||||
ConfigManager.set({
|
||||
@@ -433,14 +435,14 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
addSnippet () {
|
||||
let { note } = this.state
|
||||
const { note } = this.state
|
||||
|
||||
note.snippets = note.snippets.concat([{
|
||||
name: '',
|
||||
mode: 'Plain Text',
|
||||
content: ''
|
||||
}])
|
||||
let snippetIndex = note.snippets.length - 1
|
||||
const snippetIndex = note.snippets.length - 1
|
||||
|
||||
this.setState({
|
||||
note,
|
||||
@@ -486,19 +488,19 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, config, location } = this.props
|
||||
let { note } = this.state
|
||||
const { data, config, location } = this.props
|
||||
const { note } = this.state
|
||||
|
||||
let storageKey = note.storage
|
||||
let folderKey = note.folder
|
||||
const storageKey = note.storage
|
||||
const folderKey = note.folder
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
|
||||
let tabList = note.snippets.map((snippet, index) => {
|
||||
let isActive = this.state.snippetIndex === index
|
||||
const tabList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
|
||||
return <SnippetTab
|
||||
key={index}
|
||||
@@ -512,8 +514,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
/>
|
||||
})
|
||||
|
||||
let viewList = note.snippets.map((snippet, index) => {
|
||||
let isActive = this.state.snippetIndex === index
|
||||
const viewList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
|
||||
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
@@ -547,7 +549,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
</div>
|
||||
})
|
||||
|
||||
let options = []
|
||||
const options = []
|
||||
data.storageMap.forEach((storage, index) => {
|
||||
storage.folders.forEach((folder) => {
|
||||
options.push({
|
||||
@@ -556,7 +558,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
})
|
||||
})
|
||||
})
|
||||
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
|
||||
|
||||
const trashTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
@@ -566,7 +568,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
@@ -583,10 +585,6 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<StarButton styleName='info-left-button'
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
<div styleName='info-left-top'>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
@@ -603,15 +601,21 @@ class SnippetNoteDetail extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}
|
||||
>
|
||||
<i className='fa fa-window-maximize' styleName='fullScreen-button' />
|
||||
</button>
|
||||
<InfoButton
|
||||
onClick={(e) => this.handleInfoButtonClick(e)}
|
||||
/>
|
||||
|
||||
<StarButton
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
/>
|
||||
|
||||
<button styleName='control-fullScreenButton'
|
||||
onMouseDown={(e) => this.handleFullScreenButton(e)}>
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
|
||||
</button>
|
||||
|
||||
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
|
||||
<InfoPanel
|
||||
storageName={currentOption.storage.name}
|
||||
folderName={currentOption.folder.name}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
.root
|
||||
absolute top bottom right
|
||||
border-width 0
|
||||
border-left 1px solid alpha(#DEDEDE, 60%)
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
box-shadow $note-detail-box-shadow
|
||||
box-shadow none
|
||||
|
||||
.body
|
||||
absolute left right
|
||||
left $note-detail-left-margin
|
||||
right $note-detail-right-margin
|
||||
left $snippet-note-detail-left-margin
|
||||
right $snippet-note-detail-right-margin
|
||||
top $info-height + $info-margin-under-border
|
||||
bottom $statusBar-height
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
@@ -43,7 +43,7 @@
|
||||
overflow hidden
|
||||
|
||||
.tabList .plusButton
|
||||
navButtonColor()
|
||||
navWhiteButtonColor()
|
||||
width 30px
|
||||
|
||||
.tabView
|
||||
@@ -55,24 +55,30 @@
|
||||
|
||||
.override
|
||||
absolute bottom left
|
||||
bottom 2px
|
||||
bottom 1px
|
||||
left 60px
|
||||
height 23px
|
||||
z-index 101
|
||||
button
|
||||
navButtonColor()
|
||||
height 24px
|
||||
padding 0 6px
|
||||
&:hover
|
||||
color $ui-active-color
|
||||
&:active .update-icon
|
||||
color white
|
||||
color $ui-active-color
|
||||
|
||||
.control-fullScreenButton
|
||||
float right
|
||||
padding 0 0 2px 0
|
||||
top 80px
|
||||
margin-bottom 10px
|
||||
topBarButtonLight()
|
||||
|
||||
body[data-theme="white"]
|
||||
.root
|
||||
box-shadow $note-detail-box-shadow
|
||||
border none
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
border-color $ui-dark-borderColor
|
||||
border none
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
box-shadow none
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './StarButton.styl'
|
||||
import _ from 'lodash'
|
||||
@@ -31,7 +32,7 @@ class StarButton extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className } = this.props
|
||||
const { className } = this.props
|
||||
|
||||
return (
|
||||
<button className={_.isString(className)
|
||||
@@ -47,10 +48,10 @@ class StarButton extends React.Component {
|
||||
onMouseLeave={(e) => this.handleMouseLeave(e)}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
<i styleName='icon'
|
||||
className={this.state.isActive || this.props.isActive
|
||||
? 'fa fa-star'
|
||||
: 'fa fa-star-o'
|
||||
<img styleName='icon'
|
||||
src={this.state.isActive || this.props.isActive
|
||||
? '../resources/icon/icon-starred.svg'
|
||||
: '../resources/icon/icon-star.svg'
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -1,47 +1,24 @@
|
||||
.root
|
||||
left 7px
|
||||
top 0
|
||||
padding 0
|
||||
color alpha($ui-favorite-star-button-color, 60%)
|
||||
top 45px
|
||||
topBarButtonLight()
|
||||
&:hover
|
||||
transition 0.15s
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-favorite-star-button-color
|
||||
&:active
|
||||
transition 0.15s
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-favorite-star-button-color
|
||||
transition 0.2s
|
||||
color alpha($ui-favorite-star-button-color, 0.6)
|
||||
|
||||
.root--active
|
||||
@extend .root
|
||||
transition 0.15s
|
||||
color $ui-favorite-star-button-color
|
||||
&:hover
|
||||
transition 0.15s
|
||||
color $ui-favorite-star-button-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
&:active
|
||||
transition 0.15s
|
||||
color $ui-favorite-star-button-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
transition 0.2s
|
||||
color alpha($ui-favorite-star-button-color, 0.6)
|
||||
|
||||
.icon
|
||||
transition transform 0.15s
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
topBarButtonDark()
|
||||
&:hover
|
||||
transition 0.15s
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
color $ui-favorite-star-button-color
|
||||
&:active
|
||||
transition 0.15s
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
color $ui-favorite-star-button-color
|
||||
|
||||
.root--active
|
||||
@extend .root
|
||||
color $ui-favorite-star-button-color
|
||||
&:hover
|
||||
transition 0.15s
|
||||
color $ui-favorite-star-button-color
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
transition 0.2s
|
||||
color alpha($ui-favorite-star-button-color, 0.6)
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TagSelect.styl'
|
||||
import _ from 'lodash'
|
||||
@@ -59,7 +60,7 @@ class TagSelect extends React.Component {
|
||||
submitTag () {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
|
||||
let { value } = this.props
|
||||
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
|
||||
const newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
|
||||
|
||||
if (newTag.length <= 0) {
|
||||
this.setState({
|
||||
@@ -101,9 +102,9 @@ class TagSelect extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { value, className } = this.props
|
||||
const { value, className } = this.props
|
||||
|
||||
let tagList = _.isArray(value)
|
||||
const tagList = _.isArray(value)
|
||||
? value.map((tag) => {
|
||||
return (
|
||||
<span styleName='tag'
|
||||
@@ -113,7 +114,7 @@ class TagSelect extends React.Component {
|
||||
<button styleName='tag-removeButton'
|
||||
onClick={(e) => this.handleTagRemoveButtonClick(tag)(e)}
|
||||
>
|
||||
<i className='fa fa-times fa-fw tag-removeButton-icon' />
|
||||
<img className='tag-removeButton-icon' src='../resources/icon/icon-x.svg' width='8px' />
|
||||
</button>
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
.root
|
||||
display inline-block
|
||||
display flex
|
||||
align-items center
|
||||
user-select none
|
||||
height 23px
|
||||
vertical-align middle
|
||||
width 300px
|
||||
width 100%
|
||||
overflow-x scroll
|
||||
white-space nowrap
|
||||
|
||||
@@ -11,51 +11,42 @@
|
||||
display none
|
||||
|
||||
.tag
|
||||
display inline-block
|
||||
margin 1px 3px
|
||||
padding 0
|
||||
height 20px
|
||||
background-color alpha($ui-tag-backgroundColor, 10%)
|
||||
border-radius 3px
|
||||
overflow hidden
|
||||
display flex
|
||||
align-items center
|
||||
margin 0px 2px
|
||||
padding 2px 4px
|
||||
background-color alpha($ui-tag-backgroundColor, 3%)
|
||||
border-radius 4px
|
||||
position relative
|
||||
clearfix()
|
||||
|
||||
.tag-removeButton
|
||||
float right
|
||||
height 20px
|
||||
width 18px
|
||||
margin 0
|
||||
padding 0
|
||||
border-style solid
|
||||
border-width 0
|
||||
border-radius 20px
|
||||
line-height 18px
|
||||
background-color transparent
|
||||
color $ui-button-color
|
||||
position absolute
|
||||
right 6px
|
||||
|
||||
.tag-removeButton-icon
|
||||
width 5px
|
||||
padding-right 4px
|
||||
|
||||
.tag-label
|
||||
font-size 11px
|
||||
font-weight 600
|
||||
color: alpha($ui-text-color, 80%)
|
||||
float left
|
||||
height 20px
|
||||
line-height 20px
|
||||
padding 0 6px
|
||||
font-size 13px
|
||||
color: $ui-text-color
|
||||
padding 4px 16px 4px 8px
|
||||
|
||||
.newTag
|
||||
display inline-block
|
||||
margin 2px 0 15px 2px
|
||||
vertical-align middle
|
||||
height 18px
|
||||
box-sizing border-box
|
||||
border none
|
||||
background-color transparent
|
||||
outline none
|
||||
padding 0 4px
|
||||
font-size 13px
|
||||
|
||||
body[data-theme="dark"]
|
||||
.tag
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TrashButton.styl'
|
||||
|
||||
@@ -8,7 +9,7 @@ const TrashButton = ({
|
||||
<button styleName='control-trashButton'
|
||||
onClick={(e) => onClick(e)}
|
||||
>
|
||||
<i className='fa fa-trash trashButton' styleName='info-button' />
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
|
||||
</button>
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
.control-trashButton
|
||||
float right
|
||||
top 120px
|
||||
margin-bottom 10px
|
||||
topBarButtonLight()
|
||||
|
||||
.control-trashButton--in-trash
|
||||
top 60px
|
||||
topBarButtonLight()
|
||||
|
||||
.trashButton
|
||||
padding 0px
|
||||
margin 15px 0
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-trashButton
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './Detail.styl'
|
||||
import _ from 'lodash'
|
||||
@@ -32,12 +33,12 @@ class Detail extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { location, data, config } = this.props
|
||||
const { location, data, config } = this.props
|
||||
let note = null
|
||||
if (location.query.key != null) {
|
||||
let splitted = location.query.key.split('-')
|
||||
let storageKey = splitted.shift()
|
||||
let noteKey = splitted.shift()
|
||||
const splitted = location.query.key.split('-')
|
||||
const storageKey = splitted.shift()
|
||||
const noteKey = splitted.shift()
|
||||
|
||||
note = data.noteMap.get(storageKey + '-' + noteKey)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './Main.styl'
|
||||
import { connect } from 'react-redux'
|
||||
@@ -11,14 +12,9 @@ import _ from 'lodash'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import modal from 'browser/main/lib/modal'
|
||||
import InitModal from 'browser/main/modals/InitModal'
|
||||
import mixpanel from 'browser/main/lib/mixpanel'
|
||||
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
|
||||
function focused () {
|
||||
mixpanel.track('MAIN_FOCUSED')
|
||||
}
|
||||
|
||||
class Main extends React.Component {
|
||||
|
||||
constructor (props) {
|
||||
@@ -28,7 +24,7 @@ class Main extends React.Component {
|
||||
mobileAnalytics.initAwsMobileAnalytics()
|
||||
}
|
||||
|
||||
let { config } = props
|
||||
const { config } = props
|
||||
|
||||
this.state = {
|
||||
isRightSliderFocused: false,
|
||||
@@ -44,7 +40,7 @@ class Main extends React.Component {
|
||||
}
|
||||
|
||||
getChildContext () {
|
||||
let { status, config } = this.props
|
||||
const { status, config } = this.props
|
||||
|
||||
return {
|
||||
status,
|
||||
@@ -53,10 +49,12 @@ class Main extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
let { dispatch, config } = this.props
|
||||
const { dispatch, config } = this.props
|
||||
|
||||
if (config.ui.theme === 'dark') {
|
||||
document.body.setAttribute('data-theme', 'dark')
|
||||
} else if (config.ui.theme === 'white') {
|
||||
document.body.setAttribute('data-theme', 'white')
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
@@ -76,11 +74,9 @@ class Main extends React.Component {
|
||||
})
|
||||
|
||||
eventEmitter.on('editor:fullscreen', this.toggleFullScreen)
|
||||
window.addEventListener('focus', focused)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('focus', focused)
|
||||
eventEmitter.off('editor:fullscreen', this.toggleFullScreen)
|
||||
}
|
||||
|
||||
@@ -104,8 +100,8 @@ class Main extends React.Component {
|
||||
this.setState({
|
||||
isRightSliderFocused: false
|
||||
}, () => {
|
||||
let { dispatch } = this.props
|
||||
let newListWidth = this.state.listWidth
|
||||
const { dispatch } = this.props
|
||||
const newListWidth = this.state.listWidth
|
||||
// TODO: ConfigManager should dispatch itself.
|
||||
ConfigManager.set({listWidth: newListWidth})
|
||||
dispatch({
|
||||
@@ -120,8 +116,8 @@ class Main extends React.Component {
|
||||
this.setState({
|
||||
isLeftSliderFocused: false
|
||||
}, () => {
|
||||
let { dispatch } = this.props
|
||||
let navWidth = this.state.navWidth
|
||||
const { dispatch } = this.props
|
||||
const navWidth = this.state.navWidth
|
||||
// TODO: ConfigManager should dispatch itself.
|
||||
ConfigManager.set({ navWidth })
|
||||
dispatch({
|
||||
@@ -134,7 +130,7 @@ class Main extends React.Component {
|
||||
|
||||
handleMouseMove (e) {
|
||||
if (this.state.isRightSliderFocused) {
|
||||
let offset = this.refs.body.getBoundingClientRect().left
|
||||
const offset = this.refs.body.getBoundingClientRect().left
|
||||
let newListWidth = e.pageX - offset
|
||||
if (newListWidth < 10) {
|
||||
newListWidth = 10
|
||||
@@ -187,7 +183,7 @@ class Main extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { config } = this.props
|
||||
const { config } = this.props
|
||||
|
||||
// the width of the navigation bar when it is folded/collapsed
|
||||
const foldedNavigationWidth = 44
|
||||
|
||||
@@ -44,6 +44,13 @@ $control-height = 34px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
body[data-theme="white"]
|
||||
.root, .root--expanded
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
.control-newNoteButton
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root, .root--expanded
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NewNoteButton.styl'
|
||||
import _ from 'lodash'
|
||||
import modal from 'browser/main/lib/modal'
|
||||
import NewNoteModal from 'browser/main/modals/NewNoteModal'
|
||||
import { hashHistory } from 'react-router'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
@@ -34,7 +33,7 @@ class NewNoteButton extends React.Component {
|
||||
}
|
||||
|
||||
handleNewNoteButtonClick (e) {
|
||||
const { config, location, dispatch } = this.props
|
||||
const { location, dispatch } = this.props
|
||||
const { storage, folder } = this.resolveTargetFolder()
|
||||
|
||||
modal.open(NewNoteModal, {
|
||||
@@ -51,7 +50,7 @@ class NewNoteButton extends React.Component {
|
||||
|
||||
// Find first storage
|
||||
if (storage == null) {
|
||||
for (let kv of data.storageMap) {
|
||||
for (const kv of data.storageMap) {
|
||||
storage = kv[1]
|
||||
break
|
||||
}
|
||||
@@ -85,7 +84,7 @@ class NewNoteButton extends React.Component {
|
||||
<div styleName='control'>
|
||||
<button styleName='control-newNoteButton'
|
||||
onClick={(e) => this.handleNewNoteButtonClick(e)}>
|
||||
<i className='fa fa-pencil-square-o' />
|
||||
<img styleName='iconTag' src='../resources/icon/icon-newnote.svg' />
|
||||
<span styleName='control-newNoteButton-tooltip'>
|
||||
Make a Note {OSX ? '⌘' : '^'} + n
|
||||
</span>
|
||||
|
||||
@@ -21,14 +21,14 @@ $control-height = 30px
|
||||
|
||||
.control-sortBy-select
|
||||
appearance: none;
|
||||
margin-left 3px
|
||||
margin-left 5px
|
||||
color $ui-inactive-text-color
|
||||
padding 0
|
||||
border none
|
||||
background-color transparent
|
||||
outline none
|
||||
cursor pointer
|
||||
font-size 11px
|
||||
font-size 12px
|
||||
&:hover
|
||||
transition 0.2s
|
||||
color $ui-text-color
|
||||
@@ -59,6 +59,13 @@ $control-height = 30px
|
||||
top $control-height
|
||||
overflow auto
|
||||
|
||||
body[data-theme="white"]
|
||||
.root
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
.control
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.root
|
||||
absolute top left bottom
|
||||
width $sideNav-width
|
||||
background-color #f9f9f9
|
||||
background-color #2E3235
|
||||
user-select none
|
||||
color $ui-text-color
|
||||
height: 100vh
|
||||
@@ -11,24 +11,25 @@
|
||||
.top
|
||||
padding-bottom 15px
|
||||
|
||||
.top-menu
|
||||
.top-menu-preference
|
||||
navButtonColor()
|
||||
position absolute
|
||||
top 22px
|
||||
right 5px
|
||||
height 23px
|
||||
right 10px
|
||||
width 2em
|
||||
background-color transparent
|
||||
&:hover
|
||||
color $ui-text-color
|
||||
color $ui-button-default--active-backgroundColor
|
||||
background-color transparent
|
||||
&:active, &:active:hover
|
||||
color $ui-text-color
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
color $ui-button-default--active-backgroundColor
|
||||
|
||||
.switch-buttons
|
||||
background-color transparent
|
||||
border 0
|
||||
height 25px
|
||||
margin 20px auto 0px 8px
|
||||
margin 24px auto 4px 14px
|
||||
display flex
|
||||
text-align center
|
||||
|
||||
.non-active-button
|
||||
color $ui-inactive-text-color
|
||||
@@ -36,13 +37,16 @@
|
||||
border 0
|
||||
background-color transparent
|
||||
transition 0.2s
|
||||
display flex
|
||||
text-align center
|
||||
margin-right 4px;
|
||||
&:hover
|
||||
color alpha(#0B99F1, 60%)
|
||||
color alpha(#239F86, 60%)
|
||||
|
||||
.active-button
|
||||
@extend .non-active-button
|
||||
color #0B99F1
|
||||
|
||||
color $ui-button-default--active-backgroundColor
|
||||
|
||||
.top-menu-label
|
||||
margin-left 5px
|
||||
overflow ellipsis
|
||||
@@ -57,7 +61,7 @@
|
||||
padding-left 15px
|
||||
padding-bottom 13px
|
||||
p
|
||||
color $ui-text-color
|
||||
color $ui-button-default-color
|
||||
|
||||
.tagList
|
||||
overflow-y auto
|
||||
@@ -66,6 +70,7 @@
|
||||
.root--folded
|
||||
height 100vh
|
||||
width $sideNav--folded-width
|
||||
background-color #2E3235
|
||||
.switch-buttons
|
||||
display none
|
||||
.top
|
||||
@@ -88,7 +93,6 @@
|
||||
opacity 0
|
||||
margin-left 0
|
||||
overflow hidden
|
||||
background-color $ui-tooltip-backgroundColor
|
||||
z-index 10
|
||||
color white
|
||||
line-height 30px
|
||||
@@ -96,6 +100,41 @@
|
||||
border-bottom-right-radius 2px
|
||||
pointer-events none
|
||||
font-size 13px
|
||||
.top-menu-preference
|
||||
position absolute
|
||||
left 11px
|
||||
|
||||
body[data-theme="white"]
|
||||
.root, .root--folded
|
||||
background-color #f9f9f9
|
||||
color $ui-text-color
|
||||
|
||||
.top-menu-preference
|
||||
navWhiteButtonColor()
|
||||
background-color transparent
|
||||
&:hover
|
||||
color #0B99F1
|
||||
background-color transparent
|
||||
&:active, &:active:hover
|
||||
color #0B99F1
|
||||
background-color transparent
|
||||
|
||||
.non-active-button
|
||||
color $ui-inactive-text-color
|
||||
&:hover
|
||||
color alpha(#0B99F1, 60%)
|
||||
|
||||
.tag-title
|
||||
p
|
||||
color $ui-text-color
|
||||
|
||||
.non-active-button
|
||||
&:hover
|
||||
color alpha(#0B99F1, 60%)
|
||||
|
||||
.active-button
|
||||
@extend .non-active-button
|
||||
color #0B99F1
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root, .root--folded
|
||||
@@ -106,12 +145,15 @@ body[data-theme="dark"]
|
||||
.top
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
.top-menu
|
||||
.top-menu-preference
|
||||
navDarkButtonColor()
|
||||
background-color transparent
|
||||
&:active
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
background-color transparent
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
background-color transparent
|
||||
|
||||
.non-active-button
|
||||
color alpha($ui-dark-text-color, 60%)
|
||||
|
||||
@@ -5,27 +5,23 @@
|
||||
|
||||
.header
|
||||
position relative
|
||||
height 25px
|
||||
height 36px
|
||||
width 100%
|
||||
margin-bottom 5px
|
||||
transition 0.15s
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
.header--active
|
||||
margin-bottom 5px
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
transition color background-color 0.15s
|
||||
|
||||
.header--active
|
||||
display flex
|
||||
align-items center
|
||||
.header-toggleButton
|
||||
color $ui-text-color
|
||||
|
||||
.header--active
|
||||
.header-info
|
||||
color $ui-text-color
|
||||
|
||||
.header--active
|
||||
.header-addFolderButton
|
||||
color $ui-text-color
|
||||
color #1EC38B
|
||||
|
||||
.header-toggleButton
|
||||
navButtonColor()
|
||||
@@ -38,23 +34,31 @@
|
||||
border-radius 50%
|
||||
&:hover
|
||||
transition 0.2s
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
background-color alpha($ui-button-default--hover-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
|
||||
.header-info
|
||||
navButtonColor()
|
||||
display block
|
||||
width 100%
|
||||
height 25px
|
||||
padding-left 23px
|
||||
padding-right 10px
|
||||
height 36px
|
||||
padding-left 25px
|
||||
padding-right 15px
|
||||
line-height 22px
|
||||
cursor pointer
|
||||
font-size 13px
|
||||
font-size 14px
|
||||
border none
|
||||
overflow ellipsis
|
||||
text-align left
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
font-weight 600;
|
||||
background-color transparent
|
||||
&:hover
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
transition background-color 0.15s
|
||||
&:active, &:active:hover
|
||||
color #1EC38B
|
||||
background-color alpha($ui-button-default--active-backgroundColor, 20%)
|
||||
|
||||
.header-info-path
|
||||
font-size 10px
|
||||
@@ -63,17 +67,14 @@
|
||||
.header-addFolderButton
|
||||
navButtonColor()
|
||||
position absolute
|
||||
right 0
|
||||
right 7px
|
||||
width 25px
|
||||
height 25px
|
||||
padding 0
|
||||
border none
|
||||
margin-right 5px
|
||||
border-radius 50%
|
||||
&:hover
|
||||
transition 0.2s
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
|
||||
.root--folded
|
||||
@extend .root
|
||||
@@ -102,6 +103,33 @@
|
||||
font-size 10px
|
||||
margin 0 5px
|
||||
|
||||
body[data-theme="white"]
|
||||
.header--active
|
||||
background-color $ui-button--active-backgroundColor
|
||||
transition color background-color 0.15s
|
||||
.header-toggleButton
|
||||
color $ui-text-color
|
||||
.header-info
|
||||
color $ui-text-color
|
||||
.header-addFolderButton
|
||||
color $ui-text-color
|
||||
|
||||
.header-toggleButton
|
||||
navWhiteButtonColor()
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
|
||||
.header-info
|
||||
navWhiteButtonColor()
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
|
||||
.header-addFolderButton
|
||||
navWhiteButtonColor()
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 40%)
|
||||
color $ui-text-color
|
||||
|
||||
body[data-theme="dark"]
|
||||
.header--active
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './SideNav.styl'
|
||||
import { openModal } from 'browser/main/lib/modal'
|
||||
@@ -9,25 +10,35 @@ import TagListItem from 'browser/components/TagListItem'
|
||||
import SideNavFilter from 'browser/components/SideNavFilter'
|
||||
import StorageList from 'browser/components/StorageList'
|
||||
import NavToggleButton from 'browser/components/NavToggleButton'
|
||||
import EventEmitter from 'browser/main/lib/eventEmitter'
|
||||
|
||||
class SideNav extends React.Component {
|
||||
// TODO: should not use electron stuff v0.7
|
||||
|
||||
componentDidMount () {
|
||||
EventEmitter.on('side:preferences', this.handleMenuButtonClick)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
EventEmitter.off('side:preferences', this.handleMenuButtonClick)
|
||||
}
|
||||
|
||||
handleMenuButtonClick (e) {
|
||||
openModal(PreferencesModal)
|
||||
}
|
||||
|
||||
handleHomeButtonClick (e) {
|
||||
let { router } = this.context
|
||||
const { router } = this.context
|
||||
router.push('/home')
|
||||
}
|
||||
|
||||
handleStarredButtonClick (e) {
|
||||
let { router } = this.context
|
||||
const { router } = this.context
|
||||
router.push('/starred')
|
||||
}
|
||||
|
||||
handleToggleButtonClick (e) {
|
||||
let { dispatch, config } = this.props
|
||||
const { dispatch, config } = this.props
|
||||
|
||||
ConfigManager.set({isSideNavFolded: !config.isSideNavFolded})
|
||||
dispatch({
|
||||
@@ -37,7 +48,7 @@ class SideNav extends React.Component {
|
||||
}
|
||||
|
||||
handleTrashedButtonClick (e) {
|
||||
let { router } = this.context
|
||||
const { router } = this.context
|
||||
router.push('/trashed')
|
||||
}
|
||||
|
||||
@@ -52,7 +63,7 @@ class SideNav extends React.Component {
|
||||
}
|
||||
|
||||
SideNavComponent (isFolded, storageList) {
|
||||
let { location, data } = this.props
|
||||
const { location, data } = this.props
|
||||
|
||||
const isHomeActive = !!location.pathname.match(/^\/home$/)
|
||||
const isStarredActive = !!location.pathname.match(/^\/starred$/)
|
||||
@@ -72,6 +83,9 @@ class SideNav extends React.Component {
|
||||
isTrashedActive={isTrashedActive}
|
||||
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
|
||||
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
|
||||
counterTotalNote={data.noteMap._map.size}
|
||||
counterStarredNote={data.starredSet._set.size}
|
||||
counterDelNote={data.trashedSet._set.size}
|
||||
/>
|
||||
|
||||
<StorageList storageList={storageList} />
|
||||
@@ -96,7 +110,7 @@ class SideNav extends React.Component {
|
||||
|
||||
tagListComponent () {
|
||||
const { data, location } = this.props
|
||||
let tagList = data.tagNoteMap.map((tag, key) => {
|
||||
const tagList = data.tagNoteMap.map((tag, key) => {
|
||||
return key
|
||||
})
|
||||
return (
|
||||
@@ -123,11 +137,11 @@ class SideNav extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { data, location, config, dispatch } = this.props
|
||||
const { data, location, config, dispatch } = this.props
|
||||
|
||||
let isFolded = config.isSideNavFolded
|
||||
const isFolded = config.isSideNavFolded
|
||||
|
||||
let storageList = data.storageMap.map((storage, key) => {
|
||||
const storageList = data.storageMap.map((storage, key) => {
|
||||
return <StorageItem
|
||||
key={storage.key}
|
||||
storage={storage}
|
||||
@@ -137,7 +151,7 @@ class SideNav extends React.Component {
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
})
|
||||
let style = {}
|
||||
const style = {}
|
||||
if (!isFolded) style.width = this.props.width
|
||||
const isTagActive = location.pathname.match(/tag/)
|
||||
return (
|
||||
@@ -148,15 +162,26 @@ class SideNav extends React.Component {
|
||||
>
|
||||
<div styleName='top'>
|
||||
<div styleName='switch-buttons'>
|
||||
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}><i className='fa fa-folder fa-fw' /></button>
|
||||
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}><i className='fa fa-tags fa-fw' /></button>
|
||||
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>
|
||||
<img src={isTagActive
|
||||
? '../resources/icon/icon-list.svg'
|
||||
: '../resources/icon/icon-list-active.svg'
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>
|
||||
<img src={isTagActive
|
||||
? '../resources/icon/icon-tag-active.svg'
|
||||
: '../resources/icon/icon-tag.svg'
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button styleName='top-menu'
|
||||
<button styleName='top-menu-preference'
|
||||
onClick={(e) => this.handleMenuButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-wrench fa-fw' />
|
||||
<span styleName='top-menu-label'>Preferences</span>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
@import('../Detail/DetailVars')
|
||||
|
||||
.root
|
||||
absolute bottom left right
|
||||
position absolute
|
||||
bottom 10px
|
||||
right 10px
|
||||
z-index 100
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
display flex
|
||||
|
||||
.blank
|
||||
@@ -21,8 +22,19 @@
|
||||
|
||||
.zoom
|
||||
navButtonColor()
|
||||
height 24px
|
||||
|
||||
color rgba(0,0,0,.54)
|
||||
height 20px
|
||||
display flex
|
||||
padding 0
|
||||
align-items center
|
||||
background-color transparent
|
||||
&:hover
|
||||
color $ui-active-color
|
||||
&:active
|
||||
color $ui-active-color
|
||||
span
|
||||
margin-left 5px
|
||||
|
||||
.update
|
||||
navButtonColor()
|
||||
height 24px
|
||||
@@ -37,14 +49,14 @@
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
border-color $ui-dark-borderColor
|
||||
box-shadow none
|
||||
|
||||
.zoom
|
||||
border-color $ui-dark-borderColor
|
||||
background-color transparent
|
||||
color #f9f9f9
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
transition 0.15s
|
||||
color $ui-dark-text-color
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './StatusBar.styl'
|
||||
import ZoomManager from 'browser/main/lib/ZoomManager'
|
||||
@@ -11,7 +12,7 @@ const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2
|
||||
|
||||
class StatusBar extends React.Component {
|
||||
updateApp () {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Update Boostnote',
|
||||
detail: 'New Boostnote is ready to be installed.',
|
||||
@@ -24,7 +25,7 @@ class StatusBar extends React.Component {
|
||||
}
|
||||
|
||||
handleZoomButtonClick (e) {
|
||||
let menu = new Menu()
|
||||
const menu = new Menu()
|
||||
|
||||
zoomOptions.forEach((zoom) => {
|
||||
menu.append(new MenuItem({
|
||||
@@ -37,7 +38,7 @@ class StatusBar extends React.Component {
|
||||
}
|
||||
|
||||
handleZoomMenuItemClick (zoomFactor) {
|
||||
let { dispatch } = this.props
|
||||
const { dispatch } = this.props
|
||||
ZoomManager.setZoom(zoomFactor)
|
||||
dispatch({
|
||||
type: 'SET_ZOOM',
|
||||
@@ -46,7 +47,7 @@ class StatusBar extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { config, status } = this.context
|
||||
const { config, status } = this.context
|
||||
|
||||
return (
|
||||
<div className='StatusBar'
|
||||
@@ -55,8 +56,8 @@ class StatusBar extends React.Component {
|
||||
<button styleName='zoom'
|
||||
onClick={(e) => this.handleZoomButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-search-plus' />
|
||||
{Math.floor(config.zoom * 100)}%
|
||||
<img src='../resources/icon/icon-zoom.svg' />
|
||||
<span>{Math.floor(config.zoom * 100)}%</span>
|
||||
</button>
|
||||
|
||||
{status.updateReady
|
||||
|
||||
@@ -36,7 +36,7 @@ $control-height = 34px
|
||||
outline none
|
||||
border none
|
||||
color $ui-text-color
|
||||
font-size 16px
|
||||
font-size 18px
|
||||
padding-bottom 2px
|
||||
background-color $ui-noteList-backgroundColor
|
||||
|
||||
@@ -112,6 +112,21 @@ $control-height = 34px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
body[data-theme="white"]
|
||||
.root, .root--expanded
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
.control
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
.control-search
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
.control-search-input
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
input
|
||||
background-color $ui-white-noteList-backgroundColor
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root, .root--expanded
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './TopBar.styl'
|
||||
import _ from 'lodash'
|
||||
import NewNoteModal from 'browser/main/modals/NewNoteModal'
|
||||
import ee from 'browser/main/lib/eventEmitter'
|
||||
import NewNoteButton from 'browser/main/NewNoteButton'
|
||||
|
||||
const { remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
|
||||
const OSX = window.process.platform === 'darwin'
|
||||
|
||||
class TopBar extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
@@ -121,7 +116,7 @@ class TopBar extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let { config, style, data, location } = this.props
|
||||
const { config, style, location } = this.props
|
||||
return (
|
||||
<div className='TopBar'
|
||||
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
|
||||
|
||||
@@ -12,6 +12,7 @@ body
|
||||
color textColor
|
||||
font-size fontSize
|
||||
font-weight 200
|
||||
-webkit-font-smoothing antialiased
|
||||
|
||||
button, input, select, textarea
|
||||
font-family DEFAULT_FONTS
|
||||
|
||||
@@ -36,7 +36,7 @@ document.addEventListener('click', function (e) {
|
||||
if (infoPanel) infoPanel.style.display = 'none'
|
||||
})
|
||||
|
||||
let el = document.getElementById('content')
|
||||
const el = document.getElementById('content')
|
||||
const history = syncHistoryWithStore(hashHistory, store)
|
||||
|
||||
function notify (...args) {
|
||||
@@ -44,7 +44,7 @@ function notify (...args) {
|
||||
}
|
||||
|
||||
function updateApp () {
|
||||
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: 'Update Boostnote',
|
||||
detail: 'New Boostnote is ready to be installed.',
|
||||
@@ -81,7 +81,7 @@ ReactDOM.render((
|
||||
</Router>
|
||||
</Provider>
|
||||
), el, function () {
|
||||
let loadingCover = document.getElementById('loadingCover')
|
||||
const loadingCover = document.getElementById('loadingCover')
|
||||
loadingCover.parentNode.removeChild(loadingCover)
|
||||
|
||||
ipcRenderer.on('update-ready', function () {
|
||||
|
||||
@@ -4,6 +4,7 @@ const ConfigManager = require('browser/main/lib/ConfigManager')
|
||||
|
||||
const remote = require('electron').remote
|
||||
const os = require('os')
|
||||
let mobileAnalyticsClient
|
||||
|
||||
AWS.config.region = 'us-east-1'
|
||||
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
|
||||
@@ -13,7 +14,7 @@ if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnab
|
||||
|
||||
const validPlatformName = convertPlatformName(os.platform())
|
||||
|
||||
const mobileAnalyticsClient = new AMA.Manager({
|
||||
mobileAnalyticsClient = new AMA.Manager({
|
||||
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
appTitle: 'xxxxxxxxxx',
|
||||
appVersionName: remote.app.getVersion().toString(),
|
||||
|
||||
@@ -13,10 +13,10 @@ function release (el) {
|
||||
|
||||
function fire (command) {
|
||||
console.info('COMMAND >>', command)
|
||||
let splitted = command.split(':')
|
||||
let target = splitted[0]
|
||||
let targetCommand = splitted[1]
|
||||
let targetCallees = callees
|
||||
const splitted = command.split(':')
|
||||
const target = splitted[0]
|
||||
const targetCommand = splitted[1]
|
||||
const targetCallees = callees
|
||||
.filter((callee) => callee.name === target)
|
||||
|
||||
targetCallees.forEach((callee) => {
|
||||
|
||||
@@ -6,8 +6,6 @@ const win = global.process.platform === 'win32'
|
||||
const electron = require('electron')
|
||||
const { ipcRenderer } = electron
|
||||
const consts = require('browser/lib/consts')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
let isInitialized = false
|
||||
|
||||
@@ -91,7 +89,11 @@ function get () {
|
||||
: 'default'
|
||||
|
||||
if (config.editor.theme !== 'default') {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
|
||||
if (config.editor.theme.startsWith('solarized')) {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
|
||||
} else {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,13 +101,15 @@ function get () {
|
||||
}
|
||||
|
||||
function set (updates) {
|
||||
let currentConfig = get()
|
||||
let newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
|
||||
const currentConfig = get()
|
||||
const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
|
||||
if (!validate(newConfig)) throw new Error('INVALID CONFIG')
|
||||
_save(newConfig)
|
||||
|
||||
if (newConfig.ui.theme === 'dark') {
|
||||
document.body.setAttribute('data-theme', 'dark')
|
||||
} else if (newConfig.ui.theme === 'white') {
|
||||
document.body.setAttribute('data-theme', 'white')
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
@@ -117,12 +121,16 @@ function set (updates) {
|
||||
editorTheme.setAttribute('rel', 'stylesheet')
|
||||
document.head.appendChild(editorTheme)
|
||||
}
|
||||
let newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme)
|
||||
const newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme)
|
||||
? newConfig.editor.theme
|
||||
: 'default'
|
||||
|
||||
if (newTheme !== 'default') {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
|
||||
if (newTheme.startsWith('solarized')) {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
|
||||
} else {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
|
||||
}
|
||||
}
|
||||
|
||||
ipcRenderer.send('config-renew', {
|
||||
@@ -131,7 +139,7 @@ function set (updates) {
|
||||
}
|
||||
|
||||
function assignConfigValues (originalConfig, rcConfig) {
|
||||
let config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig)
|
||||
const config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig)
|
||||
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey)
|
||||
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui)
|
||||
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor)
|
||||
|
||||
@@ -19,7 +19,7 @@ function setZoom (zoomFactor, noSave = false) {
|
||||
}
|
||||
|
||||
function getZoom () {
|
||||
let config = ConfigManager.get()
|
||||
const config = ConfigManager.get()
|
||||
|
||||
return config.zoom
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
|
||||
* ```
|
||||
*/
|
||||
function createFolder (storageKey, input) {
|
||||
let rawStorages
|
||||
let targetStorage
|
||||
try {
|
||||
if (input == null) throw new Error('No input found.')
|
||||
@@ -41,7 +40,7 @@ function createFolder (storageKey, input) {
|
||||
while (storage.folders.some((folder) => folder.key === key)) {
|
||||
key = keygen()
|
||||
}
|
||||
let newFolder = {
|
||||
const newFolder = {
|
||||
key,
|
||||
color: input.color,
|
||||
name: input.name
|
||||
|
||||
@@ -66,7 +66,7 @@ function createNote (storageKey, input) {
|
||||
}
|
||||
}
|
||||
}
|
||||
let noteData = Object.assign({}, input, {
|
||||
const noteData = Object.assign({}, input, {
|
||||
key,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
|
||||
@@ -19,7 +19,6 @@ const { findStorage } = require('browser/lib/findStorage')
|
||||
* ```
|
||||
*/
|
||||
function deleteFolder (storageKey, folderKey) {
|
||||
let rawStorages
|
||||
let targetStorage
|
||||
try {
|
||||
targetStorage = findStorage(storageKey)
|
||||
@@ -38,17 +37,17 @@ function deleteFolder (storageKey, folderKey) {
|
||||
})
|
||||
})
|
||||
.then(function deleteFolderAndNotes (data) {
|
||||
let { storage, notes } = data
|
||||
const { storage, notes } = data
|
||||
storage.folders = storage.folders
|
||||
.filter(function excludeTargetFolder (folder) {
|
||||
return folder.key !== folderKey
|
||||
})
|
||||
|
||||
let targetNotes = notes.filter(function filterTargetNotes (note) {
|
||||
const targetNotes = notes.filter(function filterTargetNotes (note) {
|
||||
return note.folder === folderKey
|
||||
})
|
||||
|
||||
let deleteAllNotes = targetNotes
|
||||
const deleteAllNotes = targetNotes
|
||||
.map(function deleteNote (note) {
|
||||
const notePath = path.join(storage.path, 'notes', note.key + '.cson')
|
||||
return sander.unlink(notePath)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const resolveStorageData = require('./resolveStorageData')
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const sander = require('sander')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
@@ -14,7 +13,7 @@ function deleteNote (storageKey, noteKey) {
|
||||
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(function deleteNoteFile (storage) {
|
||||
let notePath = path.join(storage.path, 'notes', noteKey + '.cson')
|
||||
const notePath = path.join(storage.path, 'notes', noteKey + '.cson')
|
||||
|
||||
try {
|
||||
sander.unlinkSync(notePath)
|
||||
|
||||
@@ -20,7 +20,7 @@ const CSON = require('@rokt33r/season')
|
||||
* 3. empty directory
|
||||
*/
|
||||
function init () {
|
||||
let fetchStorages = function () {
|
||||
const fetchStorages = function () {
|
||||
let rawStorages
|
||||
try {
|
||||
rawStorages = JSON.parse(window.localStorage.getItem('storages'))
|
||||
@@ -34,8 +34,8 @@ function init () {
|
||||
.map(resolveStorageData))
|
||||
}
|
||||
|
||||
let fetchNotes = function (storages) {
|
||||
let findNotesFromEachStorage = storages
|
||||
const fetchNotes = function (storages) {
|
||||
const findNotesFromEachStorage = storages
|
||||
.map((storage) => {
|
||||
return resolveStorageNotes(storage)
|
||||
.then((notes) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ const sander = require('sander')
|
||||
function migrateFromV5Storage (storageKey, data) {
|
||||
let targetStorage
|
||||
try {
|
||||
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
|
||||
|
||||
targetStorage = _.find(cachedStorageList, {key: storageKey})
|
||||
@@ -24,15 +24,15 @@ function migrateFromV5Storage (storageKey, data) {
|
||||
}
|
||||
|
||||
function importAll (storage, data) {
|
||||
let oldArticles = data.articles
|
||||
let notes = []
|
||||
const oldArticles = data.articles
|
||||
const notes = []
|
||||
data.folders
|
||||
.forEach(function (oldFolder) {
|
||||
let folderKey = keygen()
|
||||
while (storage.folders.some((folder) => folder.key === folderKey)) {
|
||||
folderKey = keygen()
|
||||
}
|
||||
let newFolder = {
|
||||
const newFolder = {
|
||||
key: folderKey,
|
||||
name: oldFolder.name,
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
@@ -40,7 +40,7 @@ function importAll (storage, data) {
|
||||
|
||||
storage.folders.push(newFolder)
|
||||
|
||||
let articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key)
|
||||
const articles = oldArticles.filter((article) => article.FolderKey === oldFolder.key)
|
||||
articles.forEach((article) => {
|
||||
let noteKey = keygen()
|
||||
let isUnique = false
|
||||
@@ -59,7 +59,7 @@ function importAll (storage, data) {
|
||||
}
|
||||
|
||||
if (article.mode === 'markdown') {
|
||||
let newNote = {
|
||||
const newNote = {
|
||||
tags: article.tags,
|
||||
createdAt: article.createdAt,
|
||||
updatedAt: article.updatedAt,
|
||||
@@ -73,7 +73,7 @@ function importAll (storage, data) {
|
||||
}
|
||||
notes.push(newNote)
|
||||
} else {
|
||||
let newNote = {
|
||||
const newNote = {
|
||||
tags: article.tags,
|
||||
createdAt: article.createdAt,
|
||||
updatedAt: article.updatedAt,
|
||||
|
||||
@@ -20,7 +20,7 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
|
||||
.then(function saveNote (_oldStorage) {
|
||||
oldStorage = _oldStorage
|
||||
let noteData
|
||||
let notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson')
|
||||
const notePath = path.join(oldStorage.path, 'notes', noteKey + '.cson')
|
||||
try {
|
||||
noteData = CSON.readFileSync(notePath)
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const _ = require('lodash')
|
||||
const resolveStorageData = require('./resolveStorageData')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
@@ -19,7 +18,7 @@ function renameStorage (key, name) {
|
||||
console.error(err)
|
||||
return Promise.reject(err)
|
||||
}
|
||||
let targetStorage = _.find(cachedStorageList, {key: key})
|
||||
const targetStorage = _.find(cachedStorageList, {key: key})
|
||||
if (targetStorage == null) return Promise.reject('Storage')
|
||||
|
||||
targetStorage.name = name
|
||||
|
||||
@@ -18,7 +18,6 @@ const { findStorage } = require('browser/lib/findStorage')
|
||||
* ```
|
||||
*/
|
||||
function reorderFolder (storageKey, oldIndex, newIndex) {
|
||||
let rawStorages
|
||||
let targetStorage
|
||||
try {
|
||||
if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')
|
||||
|
||||
@@ -4,7 +4,7 @@ const CSON = require('@rokt33r/season')
|
||||
const migrateFromV6Storage = require('./migrateFromV6Storage')
|
||||
|
||||
function resolveStorageData (storageCache) {
|
||||
let storage = {
|
||||
const storage = {
|
||||
key: storageCache.key,
|
||||
name: storageCache.name,
|
||||
type: storageCache.type,
|
||||
@@ -13,7 +13,7 @@ function resolveStorageData (storageCache) {
|
||||
|
||||
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')
|
||||
try {
|
||||
let jsonData = CSON.readFileSync(boostnoteJSONPath)
|
||||
const jsonData = CSON.readFileSync(boostnoteJSONPath)
|
||||
if (!_.isArray(jsonData.folders)) throw new Error('folders should be an array.')
|
||||
storage.folders = jsonData.folders
|
||||
storage.version = jsonData.version
|
||||
@@ -28,7 +28,7 @@ function resolveStorageData (storageCache) {
|
||||
storage.version = '1.0'
|
||||
}
|
||||
|
||||
let version = parseInt(storage.version, 10)
|
||||
const version = parseInt(storage.version, 10)
|
||||
if (version >= 1) {
|
||||
if (version > 1) {
|
||||
console.log('The repository version is newer than one of current app.')
|
||||
|
||||
@@ -16,13 +16,13 @@ function resolveStorageNotes (storage) {
|
||||
}
|
||||
notePathList = []
|
||||
}
|
||||
let notes = notePathList
|
||||
const notes = notePathList
|
||||
.filter(function filterOnlyCSONFile (notePath) {
|
||||
return /\.cson$/.test(notePath)
|
||||
})
|
||||
.map(function parseCSONFile (notePath) {
|
||||
try {
|
||||
let data = CSON.readFileSync(path.join(notesDirPath, notePath))
|
||||
const data = CSON.readFileSync(path.join(notesDirPath, notePath))
|
||||
data.key = path.basename(notePath, '.cson')
|
||||
data.storage = storage.key
|
||||
return data
|
||||
|
||||
@@ -23,7 +23,6 @@ const { findStorage } = require('browser/lib/findStorage')
|
||||
* ```
|
||||
*/
|
||||
function updateFolder (storageKey, folderKey, input) {
|
||||
let rawStorages
|
||||
let targetStorage
|
||||
try {
|
||||
if (input == null) throw new Error('No input found.')
|
||||
@@ -37,7 +36,7 @@ function updateFolder (storageKey, folderKey, input) {
|
||||
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(function updateFolder (storage) {
|
||||
let targetFolder = _.find(storage.folders, {key: folderKey})
|
||||
const targetFolder = _.find(storage.folders, {key: folderKey})
|
||||
if (targetFolder == null) throw new Error('Target folder doesn\'t exist.')
|
||||
targetFolder.name = input.name
|
||||
targetFolder.color = input.color
|
||||
|
||||
@@ -5,7 +5,7 @@ const CSON = require('@rokt33r/season')
|
||||
const { findStorage } = require('browser/lib/findStorage')
|
||||
|
||||
function validateInput (input) {
|
||||
let validatedInput = {}
|
||||
const validatedInput = {}
|
||||
|
||||
if (input.tags != null) {
|
||||
if (!_.isArray(input.tags)) validatedInput.tags = []
|
||||
@@ -81,7 +81,7 @@ function updateNote (storageKey, noteKey, input) {
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(function saveNote (storage) {
|
||||
let noteData
|
||||
let notePath = path.join(storage.path, 'notes', noteKey + '.cson')
|
||||
const notePath = path.join(storage.path, 'notes', noteKey + '.cson')
|
||||
try {
|
||||
noteData = CSON.readFileSync(notePath)
|
||||
} catch (err) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class ModalBase extends React.Component {
|
||||
close () {
|
||||
if (modalBase != null) modalBase.setState({component: null, componentProps: null, isHidden: true})
|
||||
// Toggle overflow style on NoteList
|
||||
let list = document.querySelector('.NoteList__list___browser-main-NoteList-')
|
||||
const list = document.querySelector('.NoteList__list___browser-main-NoteList-')
|
||||
list.style.overflow = 'auto'
|
||||
}
|
||||
|
||||
@@ -34,14 +34,14 @@ class ModalBase extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
let el = document.createElement('div')
|
||||
const el = document.createElement('div')
|
||||
document.body.appendChild(el)
|
||||
let modalBase = ReactDOM.render(<ModalBase />, el)
|
||||
const modalBase = ReactDOM.render(<ModalBase />, el)
|
||||
|
||||
export function openModal (component, props) {
|
||||
if (modalBase == null) { return }
|
||||
// Hide scrollbar by removing overflow when modal opens
|
||||
let list = document.querySelector('.NoteList__list___browser-main-NoteList-')
|
||||
const list = document.querySelector('.NoteList__list___browser-main-NoteList-')
|
||||
list.style.overflow = 'hidden'
|
||||
document.body.setAttribute('data-modal', 'open')
|
||||
modalBase.setState({component: component, componentProps: props, isHidden: false})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './CreateFolderModal.styl'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
@@ -51,8 +52,8 @@ class CreateFolderModal extends React.Component {
|
||||
confirm () {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
|
||||
if (this.state.name.trim().length > 0) {
|
||||
let { storage } = this.props
|
||||
let input = {
|
||||
const { storage } = this.props
|
||||
const input = {
|
||||
name: this.state.name.trim(),
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ const electron = require('electron')
|
||||
const { remote } = electron
|
||||
|
||||
function browseFolder () {
|
||||
let dialog = remote.dialog
|
||||
const dialog = remote.dialog
|
||||
|
||||
let defaultPath = remote.app.getPath('home')
|
||||
const defaultPath = remote.app.getPath('home')
|
||||
return new Promise((resolve, reject) => {
|
||||
dialog.showOpenDialog({
|
||||
title: 'Select Directory',
|
||||
@@ -55,7 +55,7 @@ class InitModal extends React.Component {
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
let newState = {
|
||||
const newState = {
|
||||
isLoading: false
|
||||
}
|
||||
if (data != null) {
|
||||
@@ -122,7 +122,7 @@ class InitModal extends React.Component {
|
||||
notes: data.notes
|
||||
})
|
||||
|
||||
let defaultSnippetNote = dataApi
|
||||
const defaultSnippetNote = dataApi
|
||||
.createNote(data.storage.key, {
|
||||
type: 'SNIPPET_NOTE',
|
||||
folder: data.storage.folders[0].key,
|
||||
@@ -147,12 +147,12 @@ class InitModal extends React.Component {
|
||||
note: note
|
||||
})
|
||||
})
|
||||
let defaultMarkdownNote = dataApi
|
||||
const defaultMarkdownNote = dataApi
|
||||
.createNote(data.storage.key, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
folder: data.storage.folders[0].key,
|
||||
title: 'Welcome to Boostnote!',
|
||||
content: '# Welcome to Boostnote! \n### _Click to edit this note._\n\n---\n\nBoostnote is an *open source* note-taking app. \nRepository is published on [GitHub](https://github.com/BoostIO/Boostnote), and tweeting everyday on [@Boostnoteapp](https://twitter.com/boostnoteapp)!\n\n## Features \n- [x] No internet or registration required. \n- [ ] Quick search and copy the content of note. macOS: <kbd>Cmd</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> / windows: <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
|
||||
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
|
||||
})
|
||||
.then((note) => {
|
||||
store.dispatch({
|
||||
@@ -184,6 +184,12 @@ class InitModal extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
if (this.state.isLoading) {
|
||||
return <div styleName='root--loading'>
|
||||
@@ -194,7 +200,7 @@ class InitModal extends React.Component {
|
||||
return (
|
||||
<div styleName='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={this.props.close}
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
>
|
||||
|
||||
<div styleName='header'>
|
||||
|
||||
@@ -26,7 +26,7 @@ class NewNoteModal extends React.Component {
|
||||
handleMarkdownNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
let { storage, folder, dispatch, location } = this.props
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
dataApi
|
||||
.createNote(storage, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
@@ -58,7 +58,7 @@ class NewNoteModal extends React.Component {
|
||||
handleSnippetNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
let { storage, folder, dispatch, location } = this.props
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
|
||||
dataApi
|
||||
.createNote(storage, {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import ReactDOM from 'react-dom'
|
||||
import styles from './FolderItem.styl'
|
||||
@@ -23,7 +24,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
|
||||
handleEditChange (e) {
|
||||
let { folder } = this.state
|
||||
const { folder } = this.state
|
||||
|
||||
folder.name = this.refs.nameInput.value
|
||||
this.setState({
|
||||
@@ -36,7 +37,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
|
||||
confirm () {
|
||||
let { storage, folder } = this.props
|
||||
const { storage, folder } = this.props
|
||||
dataApi
|
||||
.updateFolder(storage.key, folder.key, {
|
||||
color: this.state.folder.color,
|
||||
@@ -162,7 +163,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
|
||||
handleDeleteConfirmButtonClick (e) {
|
||||
let { storage, folder } = this.props
|
||||
const { storage, folder } = this.props
|
||||
dataApi
|
||||
.deleteFolder(storage.key, folder.key)
|
||||
.then((data) => {
|
||||
@@ -197,8 +198,8 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
|
||||
handleEditButtonClick (e) {
|
||||
let { folder: propsFolder } = this.props
|
||||
let { folder: stateFolder } = this.state
|
||||
const { folder: propsFolder } = this.props
|
||||
const { folder: stateFolder } = this.state
|
||||
const folder = Object.assign({}, stateFolder, propsFolder)
|
||||
this.setState({
|
||||
status: 'EDIT',
|
||||
@@ -215,7 +216,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
|
||||
renderIdle () {
|
||||
let { folder } = this.props
|
||||
const { folder } = this.props
|
||||
return (
|
||||
<div styleName='folderItem'
|
||||
onDoubleClick={(e) => this.handleEditButtonClick(e)}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import styles from './FolderList.styl'
|
||||
import store from 'browser/main/store'
|
||||
import FolderItem from './FolderItem'
|
||||
import { SortableContainer, arrayMove } from 'react-sortable-hoc'
|
||||
import { SortableContainer } from 'react-sortable-hoc'
|
||||
|
||||
class FolderList extends React.Component {
|
||||
render () {
|
||||
let { storage, hostBoundingBox } = this.props
|
||||
const { storage, hostBoundingBox } = this.props
|
||||
|
||||
let folderList = storage.folders.map((folder, index) => {
|
||||
const folderList = storage.folders.map((folder, index) => {
|
||||
return <FolderItem key={folder.key}
|
||||
folder={folder}
|
||||
storage={storage}
|
||||
@@ -53,7 +54,7 @@ class SortableFolderListComponent extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.onSortEnd = ({oldIndex, newIndex}) => {
|
||||
let { storage } = this.props
|
||||
const { storage } = this.props
|
||||
dataApi
|
||||
.reorderFolder(storage.key, oldIndex, newIndex)
|
||||
.then((data) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './ConfigTab.styl'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
@@ -41,7 +42,7 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
let newConfig = {
|
||||
const newConfig = {
|
||||
hotkey: this.state.config.hotkey
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
|
||||
handleHotkeyChange (e) {
|
||||
let { config } = this.state
|
||||
const { config } = this.state
|
||||
config.hotkey = {
|
||||
toggleFinder: this.refs.toggleFinder.value,
|
||||
toggleMain: this.refs.toggleMain.value
|
||||
@@ -80,13 +81,13 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
let keymapAlert = this.state.keymapAlert
|
||||
let keymapAlertElement = keymapAlert != null
|
||||
const keymapAlert = this.state.keymapAlert
|
||||
const keymapAlertElement = keymapAlert != null
|
||||
? <p className={`alert ${keymapAlert.type}`}>
|
||||
{keymapAlert.message}
|
||||
</p>
|
||||
: null
|
||||
let { config } = this.state
|
||||
const { config } = this.state
|
||||
|
||||
return (
|
||||
<div styleName='root'>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user