-
this.handleStarButtonClick(e)}
- isActive={note.isStarred}
- />
-
this.handleTrashButtonClick(e)} />
-
this.handleInfoButtonClick(e)}
/>
+
+ this.handleStarButtonClick(e)}
+ isActive={note.isStarred}
+ />
+
+
+
+ this.handleTrashButtonClick(e)} />
this.handleMouseDown(e)}
onMouseUp={(e) => this.handleMouseUp(e)}
onMouseLeave={(e) => this.handleMouseLeave(e)}
- onClick={this.props.onClick}
- >
-
+
+ Star
)
}
diff --git a/browser/main/Detail/StarButton.styl b/browser/main/Detail/StarButton.styl
index 57627982..647f3f23 100644
--- a/browser/main/Detail/StarButton.styl
+++ b/browser/main/Detail/StarButton.styl
@@ -1,47 +1,40 @@
.root
- left 7px
- top 0
- padding 0
- color alpha($ui-favorite-star-button-color, 60%)
+ top 45px
+ topBarButtonRight()
&: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)
+ &:hover .tooltip
+ opacity 1
+
+.tooltip
+ tooltip()
+ position absolute
+ pointer-events none
+ top 26px
+ right 0
+ width 100%
+ z-index 200
+ padding 5px
+ line-height normal
+ border-radius 2px
+ opacity 0
+ transition 0.1s
.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%)
\ No newline at end of file
+ transition 0.2s
+ color alpha($ui-favorite-star-button-color, 0.6)
\ No newline at end of file
diff --git a/browser/main/Detail/TagSelect.js b/browser/main/Detail/TagSelect.js
index cb711f0e..3e1efb86 100644
--- a/browser/main/Detail/TagSelect.js
+++ b/browser/main/Detail/TagSelect.js
@@ -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'
@@ -37,6 +38,10 @@ class TagSelect extends React.Component {
}
}
+ handleNewTagBlur (e) {
+ this.submitTag()
+ }
+
removeLastTag () {
let { value } = this.props
@@ -59,7 +64,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 +106,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 (
this.handleTagRemoveButtonClick(tag)(e)}
>
-
+
)
@@ -134,6 +139,7 @@ class TagSelect extends React.Component {
placeholder='Add tag...'
onChange={(e) => this.handleNewTagInputChange(e)}
onKeyDown={(e) => this.handleNewTagInputKeyDown(e)}
+ onBlur={(e) => this.handleNewTagBlur(e)}
/>
)
diff --git a/browser/main/Detail/TagSelect.styl b/browser/main/Detail/TagSelect.styl
index 06958a82..ddd8b0cd 100644
--- a/browser/main/Detail/TagSelect.styl
+++ b/browser/main/Detail/TagSelect.styl
@@ -1,61 +1,53 @@
.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
+ margin-right 10px
.root::-webkit-scrollbar
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 borde-box
+ box-sizing border-box
border none
background-color transparent
outline none
padding 0 4px
+ font-size 13px
body[data-theme="dark"]
.tag
@@ -72,4 +64,20 @@ body[data-theme="dark"]
.newTag
border-color none
background-color transparent
- color $ui-dark-text-color
\ No newline at end of file
+ color $ui-dark-text-color
+
+body[data-theme="solarized-dark"]
+ .tag
+ background-color $ui-solarized-dark-tag-backgroundColor
+
+ .tag-removeButton
+ border-color $ui-button--focus-borderColor
+ background-color transparent
+
+ .tag-label
+ color $ui-solarized-dark-text-color
+
+ .newTag
+ border-color none
+ background-color transparent
+ color $ui-solarized-dark-text-color
\ No newline at end of file
diff --git a/browser/main/Detail/ToggleModeButton.js b/browser/main/Detail/ToggleModeButton.js
new file mode 100644
index 00000000..5a78cc51
--- /dev/null
+++ b/browser/main/Detail/ToggleModeButton.js
@@ -0,0 +1,25 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import styles from './ToggleModeButton.styl'
+
+const ToggleModeButton = ({
+ onClick, editorType
+}) => (
+
+
onClick('SPLIT')}>
+

+
+
onClick('EDITOR_PREVIEW')}>
+

+
+
Toggle Mode
+
+)
+
+ToggleModeButton.propTypes = {
+ onClick: PropTypes.func.isRequired,
+ editorType: PropTypes.string.Required
+}
+
+export default CSSModules(ToggleModeButton, styles)
diff --git a/browser/main/Detail/ToggleModeButton.styl b/browser/main/Detail/ToggleModeButton.styl
new file mode 100644
index 00000000..b9d3cc6c
--- /dev/null
+++ b/browser/main/Detail/ToggleModeButton.styl
@@ -0,0 +1,61 @@
+.control-toggleModeButton
+ border 1px solid #eee
+ height 34px
+ display flex
+ align-items center
+
+ div
+ width 40px
+ height 100%
+ background-color #f9f9f9
+ display flex
+ align-items center
+ justify-content center
+ cursor pointer
+
+ &:first-child
+ border-right 1px solid #eee
+ .active
+ background-color #fff
+ box-shadow 2px 0px 7px #eee
+ z-index 1
+ &:hover .tooltip
+ opacity 1
+
+.tooltip
+ tooltip()
+ position absolute
+ pointer-events none
+ top 47px
+ right 11px
+ z-index 200
+ padding 5px
+ line-height normal
+ border-radius 2px
+ opacity 0
+ transition 0.1s
+
+body[data-theme="dark"]
+ .control-fullScreenButton
+ topBarButtonDark()
+
+ .control-toggleModeButton
+ border 1px solid #444444
+ div
+ background-color $ui-dark-noteDetail-backgroundColor
+ &:first-child
+ border-right 1px solid #444444
+ .active
+ background-color #3A404C
+ box-shadow 2px 0px 7px #444444
+
+body[data-theme="solarized-dark"]
+ .control-toggleModeButton
+ border 1px solid #586E75
+ div
+ background-color $ui-solarized-dark-noteDetail-backgroundColor
+ &:first-child
+ border-right 1px solid #586E75
+ .active
+ background-color #002B36
+ box-shadow 2px 0px 7px #222222
\ No newline at end of file
diff --git a/browser/main/Detail/TrashButton.js b/browser/main/Detail/TrashButton.js
index 04dcaacd..474eb9e5 100644
--- a/browser/main/Detail/TrashButton.js
+++ b/browser/main/Detail/TrashButton.js
@@ -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,8 @@ const TrashButton = ({
)
diff --git a/browser/main/Detail/TrashButton.styl b/browser/main/Detail/TrashButton.styl
index 1d7d3add..455d36a6 100644
--- a/browser/main/Detail/TrashButton.styl
+++ b/browser/main/Detail/TrashButton.styl
@@ -1,10 +1,28 @@
.control-trashButton
- float right
- topBarButtonLight()
+ top 115px
+ topBarButtonRight()
+ &:hover .tooltip
+ opacity 1
+
+.tooltip
+ tooltip()
+ position absolute
+ pointer-events none
+ top 26px
+ right 0
+ z-index 200
+ padding 5px
+ line-height normal
+ border-radius 2px
+ opacity 0
+ transition 0.1s
+
+.control-trashButton--in-trash
+ top 60px
+ topBarButtonRight()
.trashButton
padding 0px
- margin 15px 0
body[data-theme="dark"]
.control-trashButton
diff --git a/browser/main/Detail/index.js b/browser/main/Detail/index.js
index 884c6452..70f37a41 100644
--- a/browser/main/Detail/index.js
+++ b/browser/main/Detail/index.js
@@ -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)
}
diff --git a/browser/main/Main.js b/browser/main/Main.js
index c5a86135..3fefdb45 100644
--- a/browser/main/Main.js
+++ b/browser/main/Main.js
@@ -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,15 +12,11 @@ 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) {
super(props)
@@ -27,7 +24,7 @@ class Main extends React.Component {
mobileAnalytics.initAwsMobileAnalytics()
}
- let { config } = props
+ const { config } = props
this.state = {
isRightSliderFocused: false,
@@ -43,7 +40,7 @@ class Main extends React.Component {
}
getChildContext () {
- let { status, config } = this.props
+ const { status, config } = this.props
return {
status,
@@ -52,10 +49,14 @@ 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 if (config.ui.theme === 'solarized-dark') {
+ document.body.setAttribute('data-theme', 'solarized-dark')
} else {
document.body.setAttribute('data-theme', 'default')
}
@@ -75,11 +76,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)
}
@@ -103,8 +102,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({
@@ -119,8 +118,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({
@@ -133,7 +132,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
@@ -186,7 +185,10 @@ 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
return (
diff --git a/browser/main/SideNav/ListButton.js b/browser/main/SideNav/ListButton.js
new file mode 100644
index 00000000..1365c4cb
--- /dev/null
+++ b/browser/main/SideNav/ListButton.js
@@ -0,0 +1,24 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import styles from './SwitchButton.styl'
+
+const ListButton = ({
+ onClick, isTagActive
+}) => (
+
+
+ Notes
+
+)
+
+ListButton.propTypes = {
+ onClick: PropTypes.func.isRequired,
+ isTagActive: PropTypes.bool.isRequired
+}
+
+export default CSSModules(ListButton, styles)
diff --git a/browser/main/SideNav/PreferenceButton.js b/browser/main/SideNav/PreferenceButton.js
new file mode 100644
index 00000000..9f483a28
--- /dev/null
+++ b/browser/main/SideNav/PreferenceButton.js
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import styles from './PreferenceButton.styl'
+
+const PreferenceButton = ({
+ onClick
+}) => (
+ onClick(e)}>
+
+ Preferences
+
+)
+
+PreferenceButton.propTypes = {
+ onClick: PropTypes.func.isRequired
+}
+
+export default CSSModules(PreferenceButton, styles)
diff --git a/browser/main/SideNav/PreferenceButton.styl b/browser/main/SideNav/PreferenceButton.styl
new file mode 100644
index 00000000..97a48982
--- /dev/null
+++ b/browser/main/SideNav/PreferenceButton.styl
@@ -0,0 +1,51 @@
+.top-menu-preference
+ navButtonColor()
+ position absolute
+ top 22px
+ right 10px
+ width 2em
+ background-color transparent
+ &:hover
+ color $ui-button-default--active-backgroundColor
+ background-color transparent
+ .tooltip
+ opacity 1
+ &:active, &:active:hover
+ color $ui-button-default--active-backgroundColor
+
+body[data-theme="white"]
+ .top-menu-preference
+ navWhiteButtonColor()
+ background-color transparent
+ &:hover
+ color #0B99F1
+ background-color transparent
+ &:active, &:active:hover
+ color #0B99F1
+ background-color transparent
+
+body[data-theme="dark"]
+ .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
+
+
+
+.tooltip
+ tooltip()
+ position absolute
+ pointer-events none
+ top 26px
+ left -20px
+ z-index 200
+ padding 5px
+ line-height normal
+ border-radius 2px
+ opacity 0
+ transition 0.1s
\ No newline at end of file
diff --git a/browser/main/SideNav/SideNav.styl b/browser/main/SideNav/SideNav.styl
index 752b85cc..a0ffb2e7 100644
--- a/browser/main/SideNav/SideNav.styl
+++ b/browser/main/SideNav/SideNav.styl
@@ -1,62 +1,57 @@
.root
absolute top left bottom
width $sideNav-width
- background-color #f9f9f9
+ background-color #2E3235
user-select none
color $ui-text-color
+ height: 100vh
+ display: flex
+ flex-direction column
.top
- height $topBar-height
+ padding-bottom 15px
-.top-menu
- navButtonColor()
- height $topBar-height
- padding 0 15px
- font-size 12px
- width 100%
- text-align left
- &:hover
- color $ui-text-color
- &:active, &:active:hover
- color $ui-text-color
- background-color alpha($ui-button--active-backgroundColor, 20%)
+.switch-buttons
+ background-color transparent
+ border 0
+ margin 24px auto 4px 14px
+ display flex
+ text-align center
+
+
.top-menu-label
margin-left 5px
overflow ellipsis
+ opacity 0
-.storageList
- absolute left right
- bottom 37px
- top 160px
+.tabBody
+ flex 1
+ display flex
+ flex-direction column
+
+.tag-title
+ padding-left 15px
+ padding-bottom 13px
+ p
+ color $ui-button-default-color
+
+.tagList
overflow-y auto
-
-.storageList-empty
- padding 0 10px
- margin-top 15px
- line-height 24px
- color $ui-inactive-text-color
-
-.navToggle
- navButtonColor()
- display block
- position absolute
- right 5px
- bottom 5px
- border-radius 16.5px
- height 34px
- width 34px
- line-height 32px
- padding 0
+ flex: 1
.root--folded
- @extend .root
- width 44px
- .storageList-empty
- white-space nowrap
- transform rotate(90deg)
+ height 100vh
+ width $sideNav--folded-width
+ background-color #2E3235
+ .switch-buttons
+ display none
+ .top
+ height 60px
.top-menu
- width 44px - 1
+ position static
+ width $sideNav--folded-width
+ height 60px
text-align center
&:hover .top-menu-label
transition opacity 0.15s
@@ -65,66 +60,38 @@
position fixed
display inline-block
height 30px
- left 32px
+ left $sideNav--folded-width
padding 0 10px
margin-top -8px
opacity 0
margin-left 0
overflow hidden
- background-color $ui-tooltip-backgroundColor
z-index 10
color white
line-height 30px
border-top-right-radius 2px
border-bottom-right-radius 2px
pointer-events none
- font-size 12px
- .menu-button, .menu-button--active
- text-align center
- &:hover .menu-button-label
- transition opacity 0.15s
- opacity 1
+ font-size 13px
+ .top-menu-preference
+ position absolute
+ left 7px
- .menu-button-label
- position fixed
- display inline-block
- height 32px
- left 44px
- padding 0 10px
- 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 12px
+body[data-theme="white"]
+ .root, .root--folded
+ background-color #f9f9f9
+ color $ui-text-color
body[data-theme="dark"]
.root, .root--folded
- border-color $ui-dark-borderColor
+ border-right 1px solid $ui-dark-borderColor
background-color $ui-dark-backgroundColor
color $ui-dark-text-color
.top
border-color $ui-dark-borderColor
- .top-menu
- navDarkButtonColor()
- &:active
- background-color alpha($ui-dark-button--active-backgroundColor, 20%)
- &:hover
- background-color alpha($ui-dark-button--active-backgroundColor, 20%)
-
- .storageList-empty
- color $ui-dark-inactive-text-color
-
- .navToggle
- &:hover
- background-color alpha($ui-dark-button--active-backgroundColor, 20%)
- transition 0.15s
- color $ui-dark-text-color
\ No newline at end of file
+body[data-theme="solarized-dark"]
+ .root, .root--folded
+ background-color $ui-solarized-dark-backgroundColor
+ border-right 1px solid $ui-solarized-dark-borderColor
diff --git a/browser/main/SideNav/StorageItem.js b/browser/main/SideNav/StorageItem.js
index c7985f75..4379a76c 100644
--- a/browser/main/SideNav/StorageItem.js
+++ b/browser/main/SideNav/StorageItem.js
@@ -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 './StorageItem.styl'
import { hashHistory } from 'react-router'
@@ -8,6 +9,7 @@ import RenameFolderModal from 'browser/main/modals/RenameFolderModal'
import dataApi from 'browser/main/lib/dataApi'
import StorageItemChild from 'browser/components/StorageItem'
import eventEmitter from 'browser/main/lib/eventEmitter'
+import _ from 'lodash'
const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote
@@ -22,7 +24,7 @@ class StorageItem extends React.Component {
}
handleHeaderContextMenu (e) {
- let menu = new Menu()
+ const menu = new Menu()
menu.append(new MenuItem({
label: 'Add Folder',
click: (e) => this.handleAddFolderButtonClick(e)
@@ -38,7 +40,7 @@ class StorageItem extends React.Component {
}
handleUnlinkStorageClick (e) {
- let index = dialog.showMessageBox(remote.getCurrentWindow(), {
+ const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Unlink Storage',
detail: 'This work will just detatches a storage from Boostnote. (Any data won\'t be deleted.)',
@@ -46,7 +48,7 @@ class StorageItem extends React.Component {
})
if (index === 0) {
- let { storage, dispatch } = this.props
+ const { storage, dispatch } = this.props
dataApi.removeStorage(storage.key)
.then(() => {
dispatch({
@@ -67,7 +69,7 @@ class StorageItem extends React.Component {
}
handleAddFolderButtonClick (e) {
- let { storage } = this.props
+ const { storage } = this.props
modal.open(CreateFolderModal, {
storage
@@ -75,19 +77,19 @@ class StorageItem extends React.Component {
}
handleHeaderInfoClick (e) {
- let { storage } = this.props
+ const { storage } = this.props
hashHistory.push('/storages/' + storage.key)
}
handleFolderButtonClick (folderKey) {
return (e) => {
- let { storage } = this.props
+ const { storage } = this.props
hashHistory.push('/storages/' + storage.key + '/folders/' + folderKey)
}
}
handleFolderButtonContextMenu (e, folder) {
- let menu = new Menu()
+ const menu = new Menu()
menu.append(new MenuItem({
label: 'Rename Folder',
click: (e) => this.handleRenameFolderClick(e, folder)
@@ -103,7 +105,7 @@ class StorageItem extends React.Component {
}
handleRenameFolderClick (e, folder) {
- let { storage } = this.props
+ const { storage } = this.props
modal.open(RenameFolderModal, {
storage,
folder
@@ -111,7 +113,7 @@ class StorageItem extends React.Component {
}
handleFolderDeleteClick (e, folder) {
- let index = dialog.showMessageBox(remote.getCurrentWindow(), {
+ const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete Folder',
detail: 'This will delete all notes in the folder and can not be undone.',
@@ -119,7 +121,7 @@ class StorageItem extends React.Component {
})
if (index === 0) {
- let { storage, dispatch } = this.props
+ const { storage, dispatch } = this.props
dataApi
.deleteFolder(storage.key, folder.key)
.then((data) => {
@@ -142,48 +144,57 @@ class StorageItem extends React.Component {
e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor')
}
+ dropNote (storage, folder, dispatch, location, noteData) {
+ noteData = noteData.filter((note) => folder.key !== note.folder)
+ if (noteData.length === 0) return
+ const newNoteData = noteData.map((note) => Object.assign({}, note, {storage: storage, folder: folder.key}))
+
+ Promise.all(
+ newNoteData.map((note) => dataApi.createNote(storage.key, note))
+ )
+ .then((createdNoteData) => {
+ createdNoteData.forEach((note) => {
+ dispatch({
+ type: 'UPDATE_NOTE',
+ note: note
+ })
+ })
+ })
+ .catch((err) => {
+ console.error(`error on create notes: ${err}`)
+ })
+ .then(() => {
+ return Promise.all(
+ noteData.map((note) => dataApi.deleteNote(note.storage, note.key))
+ )
+ })
+ .then((deletedNoteData) => {
+ deletedNoteData.forEach((note) => {
+ dispatch({
+ type: 'DELETE_NOTE',
+ storageKey: note.storageKey,
+ noteKey: note.noteKey
+ })
+ })
+ })
+ .catch((err) => {
+ console.error(`error on delete notes: ${err}`)
+ })
+ }
+
handleDrop (e, storage, folder, dispatch, location) {
e.target.style.opacity = '1'
e.target.style.backgroundColor = e.dataTransfer.getData('defaultColor')
const noteData = JSON.parse(e.dataTransfer.getData('note'))
- const newNoteData = Object.assign({}, noteData, {storage: storage, folder: folder.key})
- if (folder.key === noteData.folder) return
- dataApi
- .createNote(storage.key, newNoteData)
- .then((note) => {
- dataApi
- .deleteNote(noteData.storage, noteData.key)
- .then((data) => {
- let dispatchHandler = () => {
- dispatch({
- type: 'DELETE_NOTE',
- storageKey: data.storageKey,
- noteKey: data.noteKey
- })
- }
- eventEmitter.once('list:moved', dispatchHandler)
- eventEmitter.emit('list:next')
- })
- .catch((err) => {
- console.error(err)
- })
- dispatch({
- type: 'UPDATE_NOTE',
- note: note
- })
- hashHistory.push({
- pathname: location.pathname,
- query: {key: `${note.storage}-${note.key}`}
- })
- })
+ this.dropNote(storage, folder, dispatch, location, noteData)
}
render () {
- let { storage, location, isFolded, data, dispatch } = this.props
- let { folderNoteMap, trashedSet } = data
- let folderList = storage.folders.map((folder) => {
- let isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
- let noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
+ const { storage, location, isFolded, data, dispatch } = this.props
+ const { folderNoteMap, trashedSet } = data
+ const folderList = storage.folders.map((folder) => {
+ const isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
+ const noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
let noteCount = 0
if (noteSet) {
@@ -211,7 +222,7 @@ class StorageItem extends React.Component {
)
})
- let isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$'))
+ const isActive = location.pathname.match(new RegExp('\/storages\/' + storage.key + '$'))
return (
this.handleToggleButtonClick(e)}
>
-
@@ -237,7 +248,7 @@ class StorageItem extends React.Component {
this.handleAddFolderButtonClick(e)}
>
-
+
}
@@ -245,7 +256,7 @@ class StorageItem extends React.Component {
onClick={(e) => this.handleHeaderInfoClick(e)}
>
- {isFolded ? storage.name.substring(0, 1) : storage.name}
+ {isFolded ? _.truncate(storage.name, {length: 1, omission: ''}) : storage.name}
{isFolded &&
diff --git a/browser/main/SideNav/StorageItem.styl b/browser/main/SideNav/StorageItem.styl
index af3ff0ef..619498ec 100644
--- a/browser/main/SideNav/StorageItem.styl
+++ b/browser/main/SideNav/StorageItem.styl
@@ -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,22 +67,20 @@
.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
.header
width 100%
+ padding-left 5px
.header-info
overflow ellipsis
padding 0 0 0 18px
@@ -88,6 +90,7 @@
display none
.header-toggleButton
width 15px
+ padding-left 9px
.header-info--folded-tooltip
tooltip()
position fixed
@@ -102,6 +105,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
@@ -149,4 +179,8 @@ body[data-theme="dark"]
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
&:active, &:active:hover
color $ui-dark-text-color
- background-color $ui-dark-button--active-backgroundColor
\ No newline at end of file
+ background-color $ui-dark-button--active-backgroundColor
+
+
+
+
diff --git a/browser/main/SideNav/SwitchButton.styl b/browser/main/SideNav/SwitchButton.styl
new file mode 100644
index 00000000..54e21b03
--- /dev/null
+++ b/browser/main/SideNav/SwitchButton.styl
@@ -0,0 +1,59 @@
+.non-active-button
+ color $ui-inactive-text-color
+ font-size 16px
+ border 0
+ background-color transparent
+ transition 0.2s
+ display flex
+ text-align center
+ margin-right 4px
+ position relative
+ &:hover
+ color alpha(#239F86, 60%)
+ .tooltip
+ opacity 1
+
+.active-button
+ @extend .non-active-button
+ color $ui-button-default--active-backgroundColor
+
+.tooltip
+ tooltip()
+ position absolute
+ pointer-events none
+ top 22px
+ left -2px
+ z-index 200
+ padding 5px
+ line-height normal
+ border-radius 2px
+ opacity 0
+ transition 0.1s
+
+body[data-theme="white"]
+ .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"]
+ .non-active-button
+ color alpha($ui-dark-text-color, 60%)
+ &:hover
+ color alpha(#0B99F1, 60%)
+
+ .tag-title
+ p
+ color alpha($ui-dark-text-color, 60%)
\ No newline at end of file
diff --git a/browser/main/SideNav/TagButton.js b/browser/main/SideNav/TagButton.js
new file mode 100644
index 00000000..87d92c49
--- /dev/null
+++ b/browser/main/SideNav/TagButton.js
@@ -0,0 +1,24 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import styles from './SwitchButton.styl'
+
+const TagButton = ({
+ onClick, isTagActive
+}) => (
+
+
+ Tags
+
+)
+
+TagButton.propTypes = {
+ onClick: PropTypes.func.isRequired,
+ isTagActive: PropTypes.bool.isRequired
+}
+
+export default CSSModules(TagButton, styles)
diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js
index 909c6777..4c162f1e 100644
--- a/browser/main/SideNav/index.js
+++ b/browser/main/SideNav/index.js
@@ -1,30 +1,47 @@
-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'
import PreferencesModal from '../modals/PreferencesModal'
import ConfigManager from 'browser/main/lib/ConfigManager'
import StorageItem from './StorageItem'
+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'
+import PreferenceButton from './PreferenceButton'
+import ListButton from './ListButton'
+import TagButton from './TagButton'
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({
@@ -34,19 +51,100 @@ class SideNav extends React.Component {
}
handleTrashedButtonClick (e) {
- let { router } = this.context
+ const { router } = this.context
router.push('/trashed')
}
+ handleSwitchFoldersButtonClick () {
+ const { router } = this.context
+ router.push('/home')
+ }
+
+ handleSwitchTagsButtonClick () {
+ const { router } = this.context
+ router.push('/alltags')
+ }
+
+ SideNavComponent (isFolded, storageList) {
+ const { location, data } = this.props
+
+ const isHomeActive = !!location.pathname.match(/^\/home$/)
+ const isStarredActive = !!location.pathname.match(/^\/starred$/)
+ const isTrashedActive = !!location.pathname.match(/^\/trashed$/)
+
+ let component
+
+ // TagsMode is not selected
+ if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) {
+ component = (
+
+ this.handleHomeButtonClick(e)}
+ isStarredActive={isStarredActive}
+ 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}
+ />
+
+
+
+
+ )
+ } else {
+ component = (
+
+
+
+ {this.tagListComponent(data)}
+
+
+ )
+ }
+
+ return component
+ }
+
+ tagListComponent () {
+ const { data, location } = this.props
+ const tagList = data.tagNoteMap.map((tag, key) => {
+ return key
+ })
+ return (
+ tagList.map(tag => (
+
+ ))
+ )
+ }
+
+ getTagActive (path, tag) {
+ const pathSegments = path.split('/')
+ const pathTag = pathSegments[pathSegments.length - 1]
+ return pathTag === tag
+ }
+
+ handleClickTagListItem (name) {
+ const { router } = this.context
+ router.push(`/tags/${name}`)
+ }
+
render () {
- let { data, location, config, dispatch } = this.props
+ const { data, location, config, dispatch } = this.props
- let isFolded = config.isSideNavFolded
- let isHomeActive = !!location.pathname.match(/^\/home$/)
- let isStarredActive = !!location.pathname.match(/^\/starred$/)
- let isTrashedActive = !!location.pathname.match(/^\/trashed$/)
+ const isFolded = config.isSideNavFolded
- let storageList = data.storageMap.map((storage, key) => {
+ const storageList = data.storageMap.map((storage, key) => {
return
})
- let style = {}
+ const style = {}
if (!isFolded) style.width = this.props.width
+ const isTagActive = location.pathname.match(/tag/)
return (
-
this.handleMenuButtonClick(e)}
- >
-
- Preferences
-
+
+
+
+
+
-
-
this.handleHomeButtonClick(e)}
- isStarredActive={isStarredActive}
- isTrashedActive={isTrashedActive}
- handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
- handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
- />
-
-
- {storageList.length > 0 ? storageList : (
-
No storage mount.
- )}
-
- this.handleToggleButtonClick(e)}
- >
- {isFolded
- ?
- :
- }
-
+ {this.SideNavComponent(isFolded, storageList)}
)
}
diff --git a/browser/main/StatusBar/StatusBar.styl b/browser/main/StatusBar/StatusBar.styl
index 8dd8dc99..9f189fec 100644
--- a/browser/main/StatusBar/StatusBar.styl
+++ b/browser/main/StatusBar/StatusBar.styl
@@ -1,9 +1,10 @@
@import('../Detail/DetailVars')
.root
- absolute bottom left right
- height $statusBar-height
- background-color $ui-noteDetail-backgroundColor
+ position absolute
+ bottom 10px
+ right 10px
+ z-index 100
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
diff --git a/browser/main/StatusBar/index.js b/browser/main/StatusBar/index.js
index f3748548..2106a230 100644
--- a/browser/main/StatusBar/index.js
+++ b/browser/main/StatusBar/index.js
@@ -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 (
this.handleZoomButtonClick(e)}
>
-
- {Math.floor(config.zoom * 100)}%
+

+
{Math.floor(config.zoom * 100)}%
-
-
{status.updateReady
?
Ready to Update!
diff --git a/browser/main/TopBar/TopBar.styl b/browser/main/TopBar/TopBar.styl
index 0a88d32e..eb0fc12f 100644
--- a/browser/main/TopBar/TopBar.styl
+++ b/browser/main/TopBar/TopBar.styl
@@ -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
@@ -170,3 +185,26 @@ body[data-theme="dark"]
.control-newPostButton-tooltip
darkTooltip()
+
+
+body[data-theme="solarized-dark"]
+ .root, .root--expanded
+ background-color $ui-solarized-dark-noteList-backgroundColor
+
+ .control
+ border-color $ui-solarized-dark-borderColor
+ .control-search
+ background-color $ui-solarized-dark-noteList-backgroundColor
+
+ .control-search-icon
+ absolute top bottom left
+ line-height 32px
+ width 35px
+ color $ui-solarized-dark-inactive-text-color
+ background-color $ui-solarized-dark-noteList-backgroundColor
+
+ .control-search-input
+ background-color $ui-solarized-dark-noteList-backgroundColor
+ input
+ background-color $ui-solarized-dark-noteList-backgroundColor
+ color $ui-solarized-dark-text-color
\ No newline at end of file
diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js
index c469adb4..11d31abd 100644
--- a/browser/main/TopBar/index.js
+++ b/browser/main/TopBar/index.js
@@ -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)
@@ -18,7 +13,10 @@ class TopBar extends React.Component {
this.state = {
search: '',
searchOptions: [],
- isSearching: false
+ isSearching: false,
+ isAlphabet: false,
+ isIME: false,
+ isConfirmTranslation: false
}
this.focusSearchHandler = () => {
@@ -34,9 +32,52 @@ class TopBar extends React.Component {
ee.off('top:focus-search', this.focusSearchHandler)
}
+ handleKeyDown (e) {
+ // reset states
+ this.setState({
+ isAlphabet: false,
+ isIME: false
+ })
+
+ // When the key is an alphabet, del, enter or ctr
+ if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) {
+ this.setState({
+ isAlphabet: true
+ })
+ // When the key is an IME input (Japanese, Chinese)
+ } else if (e.keyCode === 229) {
+ this.setState({
+ isIME: true
+ })
+ }
+ }
+
+ handleKeyUp (e) {
+ const { router } = this.context
+ // reset states
+ this.setState({
+ isConfirmTranslation: false
+ })
+
+ // When the key is translation confirmation (Enter, Space)
+ if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) {
+ this.setState({
+ isConfirmTranslation: true
+ })
+ router.push('/searched')
+ this.setState({
+ search: this.refs.searchInput.value
+ })
+ }
+ }
+
handleSearchChange (e) {
- let { router } = this.context
- router.push('/searched')
+ const { router } = this.context
+ if (this.state.isAlphabet || this.state.isConfirmTranslation) {
+ router.push('/searched')
+ } else {
+ e.preventDefault()
+ }
this.setState({
search: this.refs.searchInput.value
})
@@ -75,7 +116,7 @@ class TopBar extends React.Component {
}
render () {
- let { config, style, data, location } = this.props
+ const { config, style, location } = this.props
return (
this.handleSearchChange(e)}
+ onKeyDown={(e) => this.handleKeyDown(e)}
+ onKeyUp={(e) => this.handleKeyUp(e)}
placeholder='Search'
type='text'
className='searchInput'
diff --git a/browser/main/global.styl b/browser/main/global.styl
index 552e0d6c..27d1ae73 100644
--- a/browser/main/global.styl
+++ b/browser/main/global.styl
@@ -1,4 +1,5 @@
global-reset()
+@import '../styles/vars.styl'
DEFAULT_FONTS = 'OpenSans', helvetica, arial, sans-serif
@@ -12,6 +13,7 @@ body
color textColor
font-size fontSize
font-weight 200
+ -webkit-font-smoothing antialiased
button, input, select, textarea
font-family DEFAULT_FONTS
@@ -64,7 +66,7 @@ textarea.block-input
fullsize()
modalZIndex= 1000
-modalBackColor = transparentify(white, 65%)
+modalBackColor = white
.ace_focus
outline-color rgb(59, 153, 252)
outline-offset 0px
@@ -83,15 +85,19 @@ modalBackColor = transparentify(white, 65%)
absolute top left bottom right
background-color modalBackColor
z-index modalZIndex + 1
+
+
body[data-theme="dark"]
.ModalBase
.modalBack
- background-color alpha(black, 60%)
+ background-color $ui-dark-backgroundColor
+ .sortableItemHelper
+ color: $ui-dark-text-color
.CodeMirror
font-family inherit !important
line-height 1.4em
- height 100%
+ height 96%
.CodeMirror > div > textarea
margin-bottom -1em
.CodeMirror-focused .CodeMirror-selected
@@ -102,3 +108,15 @@ body[data-theme="dark"]
background #B1D7FE
::selection
background #B1D7FE
+
+.sortableItemHelper
+ z-index modalZIndex + 5
+
+body[data-theme="solarized-dark"]
+ .ModalBase
+ .modalBack
+ background-color $ui-solarized-dark-backgroundColor
+ .sortableItemHelper
+ color: $ui-solarized-dark-text-color
+
+
diff --git a/browser/main/index.js b/browser/main/index.js
index 15553150..d7ed7bfd 100644
--- a/browser/main/index.js
+++ b/browser/main/index.js
@@ -27,13 +27,16 @@ document.addEventListener('click', function (e) {
const className = e.target.className
if (!className && typeof (className) !== 'string') return
const isInfoButton = className.includes('infoButton')
- const isInfoPanel = e.target.offsetParent.className.includes('infoPanel')
+ const offsetParent = e.target.offsetParent
+ const isInfoPanel = offsetParent !== null
+ ? offsetParent.className.includes('infoPanel')
+ : false
if (isInfoButton || isInfoPanel) return
const infoPanel = document.querySelector('.infoPanel')
if (infoPanel) infoPanel.style.display = 'none'
})
-let el = document.getElementById('content')
+const el = document.getElementById('content')
const history = syncHistoryWithStore(hashHistory, store)
function notify (...args) {
@@ -41,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.',
@@ -62,6 +65,11 @@ ReactDOM.render((
+
+
+
+
+
@@ -73,7 +81,7 @@ ReactDOM.render((
), el, function () {
- let loadingCover = document.getElementById('loadingCover')
+ const loadingCover = document.getElementById('loadingCover')
loadingCover.parentNode.removeChild(loadingCover)
ipcRenderer.on('update-ready', function () {
diff --git a/browser/main/lib/AwsMobileAnalyticsConfig.js b/browser/main/lib/AwsMobileAnalyticsConfig.js
index 70df7b7d..1ef4f8da 100644
--- a/browser/main/lib/AwsMobileAnalyticsConfig.js
+++ b/browser/main/lib/AwsMobileAnalyticsConfig.js
@@ -2,19 +2,47 @@ const AWS = require('aws-sdk')
const AMA = require('aws-sdk-mobile-analytics')
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) {
+if (!getSendEventCond()) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
})
- const mobileAnalyticsClient = new AMA.Manager({
+
+ const validPlatformName = convertPlatformName(os.platform())
+
+ mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
- appTitle: 'xxxxxxxxxx'
+ appTitle: 'xxxxxxxxxx',
+ appVersionName: remote.app.getVersion().toString(),
+ platform: validPlatformName
})
}
+function convertPlatformName (platformName) {
+ if (platformName === 'darwin') {
+ return 'MacOS'
+ } else if (platformName === 'win32') {
+ return 'Windows'
+ } else if (platformName === 'linux') {
+ return 'Linux'
+ } else {
+ return ''
+ }
+}
+
+function getSendEventCond () {
+ const isDev = process.env.NODE_ENV !== 'production'
+ const isDisable = !ConfigManager.default.get().amaEnabled
+ const isOffline = !window.navigator.onLine
+ return isDev || isDisable || isOffline
+}
+
function initAwsMobileAnalytics () {
- if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
+ if (getSendEventCond()) return
AWS.config.credentials.get((err) => {
if (!err) {
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
@@ -24,16 +52,28 @@ function initAwsMobileAnalytics () {
})
}
-function recordDynamicCustomEvent (type) {
- if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
- mobileAnalyticsClient.recordEvent(type)
+function recordDynamicCustomEvent (type, options = {}) {
+ if (getSendEventCond()) return
+ try {
+ mobileAnalyticsClient.recordEvent(type, options)
+ } catch (analyticsError) {
+ if (analyticsError instanceof ReferenceError) {
+ console.log(analyticsError.name + ': ' + analyticsError.message)
+ }
+ }
}
function recordStaticCustomEvent () {
- if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
- mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
- uiColorTheme: ConfigManager.default.get().ui.theme
- })
+ if (getSendEventCond()) return
+ try {
+ mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
+ uiColorTheme: ConfigManager.default.get().ui.theme
+ })
+ } catch (analyticsError) {
+ if (analyticsError instanceof ReferenceError) {
+ console.log(analyticsError.name + ': ' + analyticsError.message)
+ }
+ }
}
module.exports = {
diff --git a/browser/main/lib/Commander.js b/browser/main/lib/Commander.js
index 959de5f0..6eef62ee 100644
--- a/browser/main/lib/Commander.js
+++ b/browser/main/lib/Commander.js
@@ -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) => {
diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js
index cdd7eb80..cde284d0 100644
--- a/browser/main/lib/ConfigManager.js
+++ b/browser/main/lib/ConfigManager.js
@@ -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
@@ -25,6 +23,7 @@ export const DEFAULT_CONFIG = {
},
ui: {
theme: 'default',
+ showCopyNotification: true,
disableDirectWrite: false,
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
},
@@ -36,13 +35,19 @@ export const DEFAULT_CONFIG = {
indentType: 'space',
indentSize: '2',
displayLineNumbers: true,
- switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR
+ switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR
+ scrollPastEnd: false,
+ type: 'SPLIT'
},
preview: {
fontSize: '14',
fontFamily: win ? 'Segoe UI' : 'Lato',
codeBlockTheme: 'dracula',
- lineNumber: true
+ lineNumber: true,
+ latexInlineOpen: '$',
+ latexInlineClose: '$',
+ latexBlockOpen: '$$',
+ latexBlockClose: '$$'
}
}
@@ -91,7 +96,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 +108,17 @@ 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 if (newConfig.ui.theme === 'solarized-dark') {
+ document.body.setAttribute('data-theme', 'solarized-dark')
} else {
document.body.setAttribute('data-theme', 'default')
}
@@ -117,12 +130,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 +148,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)
diff --git a/browser/main/lib/ZoomManager.js b/browser/main/lib/ZoomManager.js
index 463df222..a8903ca3 100644
--- a/browser/main/lib/ZoomManager.js
+++ b/browser/main/lib/ZoomManager.js
@@ -19,7 +19,7 @@ function setZoom (zoomFactor, noSave = false) {
}
function getZoom () {
- let config = ConfigManager.get()
+ const config = ConfigManager.get()
return config.zoom
}
diff --git a/browser/main/lib/dataApi/copyImage.js b/browser/main/lib/dataApi/copyImage.js
index 8f7fa656..ae79f8fb 100644
--- a/browser/main/lib/dataApi/copyImage.js
+++ b/browser/main/lib/dataApi/copyImage.js
@@ -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')
/**
diff --git a/browser/main/lib/dataApi/createFolder.js b/browser/main/lib/dataApi/createFolder.js
index 9357e17c..05fcea37 100644
--- a/browser/main/lib/dataApi/createFolder.js
+++ b/browser/main/lib/dataApi/createFolder.js
@@ -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
diff --git a/browser/main/lib/dataApi/createNote.js b/browser/main/lib/dataApi/createNote.js
index 29544ea6..4b667385 100644
--- a/browser/main/lib/dataApi/createNote.js
+++ b/browser/main/lib/dataApi/createNote.js
@@ -66,12 +66,16 @@ function createNote (storageKey, input) {
}
}
}
- let noteData = Object.assign({}, input, {
- key,
- createdAt: new Date(),
- updatedAt: new Date(),
- storage: storageKey
- })
+ const noteData = Object.assign({},
+ {
+ createdAt: new Date(),
+ updatedAt: new Date()
+ },
+ input, // input may contain more accurate dates
+ {
+ key,
+ storage: storageKey
+ })
CSON.writeFileSync(path.join(storage.path, 'notes', key + '.cson'), _.omit(noteData, ['key', 'storage']))
diff --git a/browser/main/lib/dataApi/deleteFolder.js b/browser/main/lib/dataApi/deleteFolder.js
index c687382d..908677e1 100644
--- a/browser/main/lib/dataApi/deleteFolder.js
+++ b/browser/main/lib/dataApi/deleteFolder.js
@@ -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)
diff --git a/browser/main/lib/dataApi/deleteNote.js b/browser/main/lib/dataApi/deleteNote.js
index 52af55ab..49498a30 100644
--- a/browser/main/lib/dataApi/deleteNote.js
+++ b/browser/main/lib/dataApi/deleteNote.js
@@ -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)
diff --git a/browser/main/lib/dataApi/index.js b/browser/main/lib/dataApi/index.js
index bad6f527..768dfe32 100644
--- a/browser/main/lib/dataApi/index.js
+++ b/browser/main/lib/dataApi/index.js
@@ -6,6 +6,7 @@ const dataApi = {
createFolder: require('./createFolder'),
updateFolder: require('./updateFolder'),
deleteFolder: require('./deleteFolder'),
+ reorderFolder: require('./reorderFolder'),
createNote: require('./createNote'),
updateNote: require('./updateNote'),
deleteNote: require('./deleteNote'),
diff --git a/browser/main/lib/dataApi/init.js b/browser/main/lib/dataApi/init.js
index 67d853e0..7f81e90b 100644
--- a/browser/main/lib/dataApi/init.js
+++ b/browser/main/lib/dataApi/init.js
@@ -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) => {
diff --git a/browser/main/lib/dataApi/migrateFromV5Storage.js b/browser/main/lib/dataApi/migrateFromV5Storage.js
index be922731..b11e66e9 100644
--- a/browser/main/lib/dataApi/migrateFromV5Storage.js
+++ b/browser/main/lib/dataApi/migrateFromV5Storage.js
@@ -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,
diff --git a/browser/main/lib/dataApi/moveNote.js b/browser/main/lib/dataApi/moveNote.js
index da44211d..4580062e 100644
--- a/browser/main/lib/dataApi/moveNote.js
+++ b/browser/main/lib/dataApi/moveNote.js
@@ -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) {
diff --git a/browser/main/lib/dataApi/renameStorage.js b/browser/main/lib/dataApi/renameStorage.js
index 3c82130d..78242bed 100644
--- a/browser/main/lib/dataApi/renameStorage.js
+++ b/browser/main/lib/dataApi/renameStorage.js
@@ -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
diff --git a/browser/main/lib/dataApi/reorderFolder.js b/browser/main/lib/dataApi/reorderFolder.js
new file mode 100644
index 00000000..9102438e
--- /dev/null
+++ b/browser/main/lib/dataApi/reorderFolder.js
@@ -0,0 +1,42 @@
+const _ = require('lodash')
+_.move = require('lodash-move').default
+const path = require('path')
+const resolveStorageData = require('./resolveStorageData')
+const CSON = require('@rokt33r/season')
+const { findStorage } = require('browser/lib/findStorage')
+
+/**
+ * @param {String} storageKey
+ * @param {number} oldIndex
+ * @param {number} newIndex
+ *
+ * @return {Object}
+ * ```
+ * {
+ * storage: Object
+ * }
+ * ```
+ */
+function reorderFolder (storageKey, oldIndex, newIndex) {
+ let targetStorage
+ try {
+ if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')
+ if (!_.isNumber(newIndex)) throw new Error('newIndex must be a number.')
+
+ targetStorage = findStorage(storageKey)
+ } catch (e) {
+ return Promise.reject(e)
+ }
+
+ return resolveStorageData(targetStorage)
+ .then(function reorderFolder (storage) {
+ storage.folders = _.move(storage.folders, oldIndex, newIndex)
+ CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version']))
+
+ return {
+ storage
+ }
+ })
+}
+
+module.exports = reorderFolder
diff --git a/browser/main/lib/dataApi/resolveStorageData.js b/browser/main/lib/dataApi/resolveStorageData.js
index e25ab16d..af040c5d 100644
--- a/browser/main/lib/dataApi/resolveStorageData.js
+++ b/browser/main/lib/dataApi/resolveStorageData.js
@@ -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.')
diff --git a/browser/main/lib/dataApi/resolveStorageNotes.js b/browser/main/lib/dataApi/resolveStorageNotes.js
index 104b0c00..5684f06e 100644
--- a/browser/main/lib/dataApi/resolveStorageNotes.js
+++ b/browser/main/lib/dataApi/resolveStorageNotes.js
@@ -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
diff --git a/browser/main/lib/dataApi/updateFolder.js b/browser/main/lib/dataApi/updateFolder.js
index e128a2d3..2a325c60 100644
--- a/browser/main/lib/dataApi/updateFolder.js
+++ b/browser/main/lib/dataApi/updateFolder.js
@@ -2,6 +2,7 @@ const _ = require('lodash')
const path = require('path')
const resolveStorageData = require('./resolveStorageData')
const CSON = require('@rokt33r/season')
+const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} storageKey
@@ -22,25 +23,20 @@ const CSON = require('@rokt33r/season')
* ```
*/
function updateFolder (storageKey, folderKey, input) {
- let rawStorages
let targetStorage
try {
if (input == null) throw new Error('No input found.')
if (!_.isString(input.name)) throw new Error('Name must be a string.')
if (!_.isString(input.color)) throw new Error('Color must be a string.')
- rawStorages = JSON.parse(localStorage.getItem('storages'))
- if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
-
- targetStorage = _.find(rawStorages, {key: storageKey})
- if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
+ targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
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
diff --git a/browser/main/lib/dataApi/updateNote.js b/browser/main/lib/dataApi/updateNote.js
index 4bf5ca29..2fbd52c2 100644
--- a/browser/main/lib/dataApi/updateNote.js
+++ b/browser/main/lib/dataApi/updateNote.js
@@ -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 = []
@@ -26,6 +26,10 @@ function validateInput (input) {
validatedInput.isTrashed = !!input.isTrashed
}
+ if (input.isPinned !== undefined) {
+ validatedInput.isPinned = !!input.isPinned
+ }
+
validatedInput.type = input.type
switch (input.type) {
case 'MARKDOWN_NOTE':
@@ -77,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) {
@@ -104,6 +108,7 @@ function updateNote (storageKey, noteKey, input) {
noteData.isStarred = false
noteData.isTrashed = false
noteData.tags = []
+ noteData.isPinned = false
}
if (noteData.type === 'SNIPPET_NOTE') {
diff --git a/browser/main/lib/mixpanel.js b/browser/main/lib/mixpanel.js
deleted file mode 100644
index 5fd54b90..00000000
--- a/browser/main/lib/mixpanel.js
+++ /dev/null
@@ -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
-}
diff --git a/browser/main/lib/modal.js b/browser/main/lib/modal.js
index 1964d52e..7a7a9c8c 100644
--- a/browser/main/lib/modal.js
+++ b/browser/main/lib/modal.js
@@ -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(, el)
+const modalBase = ReactDOM.render(, 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})
diff --git a/browser/main/modals/CreateFolderModal.js b/browser/main/modals/CreateFolderModal.js
index 1ac0ee97..e623ad8d 100644
--- a/browser/main/modals/CreateFolderModal.js
+++ b/browser/main/modals/CreateFolderModal.js
@@ -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]
}
diff --git a/browser/main/modals/CreateFolderModal.styl b/browser/main/modals/CreateFolderModal.styl
index 16ca7fba..97fddec7 100644
--- a/browser/main/modals/CreateFolderModal.styl
+++ b/browser/main/modals/CreateFolderModal.styl
@@ -4,10 +4,9 @@
height 270px
overflow hidden
position relative
- padding 0 40px
.header
- height 70px
+ height 80px
margin-bottom 10px
margin-top 20px
font-size 18px
@@ -15,23 +14,27 @@
background-color $ui-backgroundColor
color $ui-text-color
+.title
+ font-size 36px
+ font-weight 600
+
.control-folder-label
text-align left
- font-size 12px
+ font-size 14px
color $ui-text-color
.control-folder-input
display block
- height 30px
- width 420px
+ height 40px
+ width 490px
padding 0 5px
- margin 10px auto 15px
+ margin 10px 0
border 1px solid #C9C9C9 // TODO: use variable.
border-radius 2px
background-color transparent
outline none
vertical-align middle
- font-size 14px
+ font-size 16px
&:disabled
background-color $ui-input--disabled-backgroundColor
&:focus, &:active
@@ -39,14 +42,13 @@
.control-confirmButton
display block
- float right
- height 30px
- width 100px
+ height 35px
+ width 140px
border none
border-radius 2px
padding 0 25px
margin 20px auto
- font-size 12px
+ font-size 14px
colorPrimaryButton()
body[data-theme="dark"]
@@ -56,7 +58,6 @@ body[data-theme="dark"]
height 270px
overflow hidden
position relative
- padding 0 40px
.header
background-color transparent
diff --git a/browser/main/modals/InitModal.js b/browser/main/modals/InitModal.js
index c7c2778e..024c6f42 100644
--- a/browser/main/modals/InitModal.js
+++ b/browser/main/modals/InitModal.js
@@ -5,7 +5,6 @@ import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
import { hashHistory } from 'react-router'
import _ from 'lodash'
-import ModalEscButton from 'browser/components/ModalEscButton'
const CSON = require('@rokt33r/season')
const path = require('path')
@@ -13,9 +12,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 +54,7 @@ class InitModal extends React.Component {
} catch (err) {
console.error(err)
}
- let newState = {
+ const newState = {
isLoading: false
}
if (data != null) {
@@ -122,7 +121,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 +146,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 and Registration Required. \n- [ ] Quick search and copy the content of note. `macOS: Cmd + Alt + S / windows: Ctrl + Alt + S` \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
+ content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n\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 +183,12 @@ class InitModal extends React.Component {
})
}
+ handleKeyDown (e) {
+ if (e.keyCode === 27) {
+ this.props.close()
+ }
+ }
+
render () {
if (this.state.isLoading) {
return
@@ -196,17 +201,12 @@ class InitModal extends React.Component {
tabIndex='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
>
-
-
-
this.handleCloseButtonClick(e)} />
- Welcome!
+ Welcome to Boostnote!
- Please select a directory for Boostnote storage.
+ Please select a directory for data storage.
Loading...
- : 'Let\'s Go!'
+ : 'CREATE'
}
diff --git a/browser/main/modals/InitModal.styl b/browser/main/modals/InitModal.styl
index 73b7308a..62e02b68 100644
--- a/browser/main/modals/InitModal.styl
+++ b/browser/main/modals/InitModal.styl
@@ -1,7 +1,11 @@
.root
modal()
- max-width 540px
+ background-color #fff
+ max-width 100vw
+ max-height 100vh
overflow hidden
+ margin 0
+ padding 150px 0
position relative
.root--loading
@extend .root
@@ -13,14 +17,6 @@
.loadingMessage
color $ui-text-color
margin 15px auto 35px
-.header
- height 50px
- font-size 18px
- line-height 50px
- padding 0 15px
- background-color $ui-backgroundColor
- border-bottom solid 1px $ui-borderColor
- color $ui-text-color
.body
padding 30px
@@ -32,20 +28,20 @@
color $ui-text-color
.body-description
- font-size 14px
+ font-size 16px
color $ui-text-color
text-align center
margin-bottom 25px
.body-path
margin 0 auto 25px
- width 280px
+ width 330px
.body-path-input
- height 30px
+ height 40px
vertical-align middle
- width 250px
- font-size 12px
+ width 300px
+ font-size 14px
border-style solid
border-width 1px 0 1px 1px
border-color $border-color
@@ -54,7 +50,10 @@
padding 0 5px
.body-path-button
- height 30px
+ height 42px
+ width 30px
+ font-size 16px
+ font-weight 600
border none
border-top-right-radius 2px
border-bottom-right-radius 2px
@@ -69,6 +68,8 @@
.body-control-createButton
colorPrimaryButton()
+ font-size 14px
+ font-weight 600
border none
border-radius 2px
height 40px
diff --git a/browser/main/modals/NewNoteModal.js b/browser/main/modals/NewNoteModal.js
index 4e794832..346fe920 100644
--- a/browser/main/modals/NewNoteModal.js
+++ b/browser/main/modals/NewNoteModal.js
@@ -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, {
diff --git a/browser/main/modals/NewNoteModal.styl b/browser/main/modals/NewNoteModal.styl
index b12a20cf..748ab88c 100644
--- a/browser/main/modals/NewNoteModal.styl
+++ b/browser/main/modals/NewNoteModal.styl
@@ -9,16 +9,19 @@
font-size 18px
line-height 50px
padding 0 15px
- background-color $ui-backgroundColor
- border-bottom solid 1px $ui-borderColor
color $ui-text-color
+ margin-bottom 20px
+
+.title
+ font-size 36px
+ font-weight 600
.control
- padding 25px 15px 15px
+ padding 25px 0px
text-align center
.control-button
- width 220px
+ width 240px
height 220px
margin 0 15px
border $ui-border
@@ -30,8 +33,8 @@
colorPrimaryButton()
.control-button-icon
- font-size 50px
- margin-bottom 15px
+ font-size 48px
+ margin-bottom 25px
.control-button-label
font-size 18px
@@ -49,8 +52,6 @@ body[data-theme="dark"]
modalDark()
.header
- background-color $ui-dark-button--hover-backgroundColor
- border-color $ui-dark-borderColor
color $ui-dark-text-color
.control-button
@@ -63,3 +64,20 @@ body[data-theme="dark"]
.description
color $ui-inactive-text-color
+body[data-theme="solarized-dark"]
+ .root
+ background-color transparent
+
+ .header
+ color $ui-solarized-dark-text-color
+
+ .control-button
+ border-color $ui-solarized-dark-borderColor
+ color $ui-solarized-dark-text-color
+ background-color transparent
+ &:focus
+ colorDarkPrimaryButton()
+
+ .description
+ color $ui-solarized-dark-text-color
+
diff --git a/browser/main/modals/PreferencesModal/ConfigTab.styl b/browser/main/modals/PreferencesModal/ConfigTab.styl
index 11114272..ae54218c 100644
--- a/browser/main/modals/PreferencesModal/ConfigTab.styl
+++ b/browser/main/modals/PreferencesModal/ConfigTab.styl
@@ -31,10 +31,15 @@
.group-section-control
flex 1
+ margin-left 5px
.group-section-control select
outline none
border 1px solid $ui-borderColor
+ font-size 16px
+ height 30px
+ width 250px
+ margin-bottom 5px
background-color transparent
.group-section-control-input
@@ -62,10 +67,17 @@
text-align right
:global
.alert
- font-size 12px
- line-height 30px
- padding 0 5px
- float right
+ display inline-block
+ position absolute
+ top 60px
+ right 15px
+ font-size 14px
+ .success
+ color #1EC38B
+ .error
+ color red
+
+
.group-control-leftButton
colorDefaultButton()
@@ -77,14 +89,16 @@
margin-right 10px
.group-control-rightButton
- float right
+ position absolute
+ top 10px
+ right 20px
colorPrimaryButton()
border none
border-radius 2px
font-size $tab--button-font-size
- height 35px
- width 100px
- margin-right 10px
+ height 40px
+ width 120px
+ padding 0 15px
.group-hint
border $ui-border
@@ -101,7 +115,6 @@
line-height 1.2
.note-for-keymap
- margin-left: 10px
font-size: 12px
.code-mirror
@@ -114,6 +127,12 @@ colorDarkControl()
border-color $ui-dark-borderColor
background-color $ui-dark-backgroundColor
color $ui-dark-text-color
+
+colorSolarizedDarkControl()
+ border none
+ background-color $ui-solarized-dark-button-backgroundColor
+ color $ui-solarized-dark-text-color
+
body[data-theme="dark"]
.root
@@ -141,3 +160,33 @@ body[data-theme="dark"]
.group-section-control
select, .group-section-control-input
colorDarkControl()
+
+
+body[data-theme="solarized-dark"]
+ .root
+ color $ui-solarized-dark-text-color
+
+ .group-header
+ color $ui-solarized-dark-text-color
+ border-color $ui-solarized-dark-borderColor
+
+ .group-header2
+ color $ui-solarized-dark-text-color
+
+ .group-section-control-input
+ border-color $ui-solarized-dark-borderColor
+
+ .group-control
+ border-color $ui-solarized-dark-borderColor
+ .group-control-leftButton
+ colorDarkDefaultButton()
+ border-color $ui-solarized-dark-borderColor
+ .group-control-rightButton
+ colorSolarizedDarkPrimaryButton()
+ .group-hint
+ colorSolarizedDarkControl()
+ .group-section-control
+ select, .group-section-control-input
+ colorSolarizedDarkControl()
+
+
diff --git a/browser/main/modals/PreferencesModal/Crowdfunding.js b/browser/main/modals/PreferencesModal/Crowdfunding.js
new file mode 100644
index 00000000..3dccd27b
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/Crowdfunding.js
@@ -0,0 +1,49 @@
+import React from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import styles from './Crowdfunding.styl'
+
+const electron = require('electron')
+const { shell } = electron
+
+class Crowdfunding extends React.Component {
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ }
+ }
+
+ handleLinkClick (e) {
+ shell.openExternal(e.currentTarget.href)
+ e.preventDefault()
+ }
+
+ render () {
+ return (
+
+
Crowdfunding
+
Dear all,
+
+
Thanks for your using!
+
Boostnote is used in about 200 countries and regions, it is a awesome developer community.
+
+
To continue supporting this growth, and to satisfy community expectations,
+
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.
+
+
+ this.handleLinkClick(e)}>Support via OpenCollective
+
+
+ )
+ }
+}
+
+Crowdfunding.propTypes = {
+}
+
+export default CSSModules(Crowdfunding, styles)
diff --git a/browser/main/modals/PreferencesModal/Crowdfunding.styl b/browser/main/modals/PreferencesModal/Crowdfunding.styl
new file mode 100644
index 00000000..930c33f0
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/Crowdfunding.styl
@@ -0,0 +1,36 @@
+@import('./Tab')
+
+.root
+ padding 15px
+ white-space pre
+ line-height 1.4
+ color alpha($ui-text-color, 90%)
+ width 100%
+ font-size 14px
+p
+ font-size 16px
+
+.cf-link
+ width 250px
+ height 35px
+ border-radius 2px
+ border none
+ background-color alpha(#1EC38B, 90%)
+ &:hover
+ background-color #1EC38B
+ transition 0.2s
+ a
+ text-decoration none
+ color white
+ font-weight 600
+ font-size 16px
+
+body[data-theme="dark"]
+ p
+ color $ui-dark-text-color
+
+body[data-theme="solarized-dark"]
+ .root
+ color $ui-solarized-dark-text-color
+ p
+ color $ui-solarized-dark-text-color
\ No newline at end of file
diff --git a/browser/main/modals/PreferencesModal/FolderItem.js b/browser/main/modals/PreferencesModal/FolderItem.js
new file mode 100644
index 00000000..9d1cd08f
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderItem.js
@@ -0,0 +1,304 @@
+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'
+import dataApi from 'browser/main/lib/dataApi'
+import store from 'browser/main/store'
+import { SketchPicker } from 'react-color'
+import { SortableElement, SortableHandle } from 'react-sortable-hoc'
+
+class FolderItem extends React.Component {
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ status: 'IDLE',
+ folder: {
+ showColumnPicker: false,
+ colorPickerPos: { left: 0, top: 0 },
+ color: props.color,
+ name: props.name
+ }
+ }
+ }
+
+ handleEditChange (e) {
+ const { folder } = this.state
+
+ folder.name = this.refs.nameInput.value
+ this.setState({
+ folder
+ })
+ }
+
+ handleConfirmButtonClick (e) {
+ this.confirm()
+ }
+
+ confirm () {
+ const { storage, folder } = this.props
+ dataApi
+ .updateFolder(storage.key, folder.key, {
+ color: this.state.folder.color,
+ name: this.state.folder.name
+ })
+ .then((data) => {
+ store.dispatch({
+ type: 'UPDATE_FOLDER',
+ storage: data.storage
+ })
+ this.setState({
+ status: 'IDLE'
+ })
+ })
+ }
+
+ handleColorButtonClick (e) {
+ const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
+ this.setState({ folder }, function () {
+ // After the color picker has been painted, re-calculate its position
+ // by comparing its dimensions to the host dimensions.
+ const { hostBoundingBox } = this.props
+ const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
+ const colorPickerBox = colorPickerNode.getBoundingClientRect()
+ const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
+ const folder = Object.assign({}, this.state.folder, {
+ colorPickerPos: {
+ left: 25,
+ top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
+ }
+ })
+ this.setState({ folder })
+ })
+ }
+
+ handleColorChange (color) {
+ const folder = Object.assign({}, this.state.folder, { color: color.hex })
+ this.setState({ folder })
+ }
+
+ handleColorPickerClose (event) {
+ const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
+ this.setState({ folder })
+ }
+
+ handleCancelButtonClick (e) {
+ this.setState({
+ status: 'IDLE'
+ })
+ }
+
+ handleFolderItemBlur (e) {
+ let el = e.relatedTarget
+ while (el != null) {
+ if (el === this.refs.root) {
+ return false
+ }
+ el = el.parentNode
+ }
+ this.confirm()
+ }
+
+ renderEdit (e) {
+ const popover = { position: 'absolute', zIndex: 2 }
+ const cover = {
+ position: 'fixed',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ }
+ const pickerStyle = Object.assign({}, {
+ position: 'absolute'
+ }, this.state.folder.colorPickerPos)
+ return (
+
this.handleFolderItemBlur(e)}
+ tabIndex='-1'
+ ref='root'
+ >
+
+
!this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
+ >
+ {this.state.folder.showColumnPicker
+ ?
+
this.handleColorPickerClose()}
+ />
+
+ this.handleColorChange(color)}
+ onChangeComplete={(color) => this.handleColorChange(color)}
+ />
+
+
+ : null
+ }
+
+
+
this.handleEditChange(e)}
+ />
+
+
+ this.handleConfirmButtonClick(e)}
+ >
+ Confirm
+
+ this.handleCancelButtonClick(e)}
+ >
+ Cancel
+
+
+
+ )
+ }
+
+ handleDeleteConfirmButtonClick (e) {
+ const { storage, folder } = this.props
+ dataApi
+ .deleteFolder(storage.key, folder.key)
+ .then((data) => {
+ store.dispatch({
+ type: 'DELETE_FOLDER',
+ storage: data.storage,
+ folderKey: data.folderKey
+ })
+ })
+ }
+
+ renderDelete () {
+ return (
+
+
+ Are you sure to delete this folder?
+
+
+ this.handleDeleteConfirmButtonClick(e)}
+ >
+ Confirm
+
+ this.handleCancelButtonClick(e)}
+ >
+ Cancel
+
+
+
+ )
+ }
+
+ handleEditButtonClick (e) {
+ const { folder: propsFolder } = this.props
+ const { folder: stateFolder } = this.state
+ const folder = Object.assign({}, stateFolder, propsFolder)
+ this.setState({
+ status: 'EDIT',
+ folder
+ }, () => {
+ this.refs.nameInput.select()
+ })
+ }
+
+ handleDeleteButtonClick (e) {
+ this.setState({
+ status: 'DELETE'
+ })
+ }
+
+ renderIdle () {
+ const { folder } = this.props
+ return (
+
this.handleEditButtonClick(e)}
+ >
+
+ {folder.name}
+ ({folder.key})
+
+
+ this.handleEditButtonClick(e)}
+ >
+ Edit
+
+ this.handleDeleteButtonClick(e)}
+ >
+ Delete
+
+
+
+ )
+ }
+
+ render () {
+ switch (this.state.status) {
+ case 'DELETE':
+ return this.renderDelete()
+ case 'EDIT':
+ return this.renderEdit()
+ case 'IDLE':
+ default:
+ return this.renderIdle()
+ }
+ }
+}
+
+FolderItem.propTypes = {
+ hostBoundingBox: PropTypes.shape({
+ bottom: PropTypes.number,
+ height: PropTypes.number,
+ left: PropTypes.number,
+ right: PropTypes.number,
+ top: PropTypes.number,
+ width: PropTypes.number
+ }),
+ storage: PropTypes.shape({
+ key: PropTypes.string
+ }),
+ folder: PropTypes.shape({
+ key: PropTypes.string,
+ color: PropTypes.string,
+ name: PropTypes.string
+ })
+}
+
+class Handle extends React.Component {
+ render () {
+ return (
+
+
+
+ )
+ }
+}
+
+class SortableFolderItemComponent extends React.Component {
+ render () {
+ const StyledHandle = CSSModules(Handle, this.props.styles)
+ const DragHandle = SortableHandle(StyledHandle)
+
+ const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
+
+ return (
+
+
+
+
+ )
+ }
+}
+
+export default CSSModules(SortableElement(SortableFolderItemComponent), styles)
diff --git a/browser/main/modals/PreferencesModal/FolderItem.styl b/browser/main/modals/PreferencesModal/FolderItem.styl
new file mode 100644
index 00000000..acc4cbfb
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderItem.styl
@@ -0,0 +1,128 @@
+.folderItem
+ height 35px
+ box-sizing border-box
+ padding 2.5px 15px
+ &:hover
+ background-color darken(white, 3%)
+
+.folderItem-drag-handle
+ height 35px
+ border none
+ padding 0 10px
+ line-height 35px
+ float left
+ cursor row-resize
+
+.folderItem-left
+ height 30px
+ border-left solid 2px transparent
+ padding 0 10px
+ line-height 30px
+ float left
+.folderItem-left-danger
+ color $danger-color
+ font-weight bold
+
+.folderItem-left-key
+ color $ui-inactive-text-color
+ font-size 13px
+ margin 0 5px
+ border none
+
+.folderItem-left-colorButton
+ colorDefaultButton()
+ height 25px
+ width 25px
+ line-height 23px
+ padding 0
+ box-sizing border-box
+ vertical-align middle
+ border $ui-border
+ border-radius 2px
+ margin-right 5px
+ margin-left -15px
+
+.folderItem-left-nameInput
+ height 25px
+ box-sizing border-box
+ vertical-align middle
+ border $ui-border
+ border-radius 2px
+ padding 0 5px
+ outline none
+
+.folderItem-right
+ float right
+
+.folderItem-right-button
+ vertical-align middle
+ height 25px
+ margin-top 2.5px
+ colorDefaultButton()
+ border-radius 2px
+ border $ui-border
+ margin-right 5px
+ padding 0 5px
+ &:last-child
+ margin-right 0
+
+.folderItem-right-confirmButton
+ @extend .folderItem-right-button
+ border none
+ colorPrimaryButton()
+
+.folderItem-right-dangerButton
+ @extend .folderItem-right-button
+ border none
+ colorDangerButton()
+
+body[data-theme="dark"]
+ .folderItem
+ &:hover
+ background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
+
+ .folderItem-left-danger
+ color $danger-color
+ font-weight bold
+
+ .folderItem-left-key
+ color $ui-dark-inactive-text-color
+
+ .folderItem-left-colorButton
+ colorDarkDefaultButton()
+ border-color $ui-dark-borderColor
+
+ .folderItem-right-button
+ colorDarkDefaultButton()
+ border-color $ui-dark-borderColor
+
+ .folderItem-right-confirmButton
+ colorDarkPrimaryButton()
+
+ .folderItem-right-dangerButton
+ colorDarkDangerButton()
+
+
+
+body[data-theme="solarized-dark"]
+ .folderItem
+ &:hover
+ background-color $ui-solarized-dark-button-backgroundColor
+
+ .folderItem-left-danger
+ color $danger-color
+
+ .folderItem-left-key
+ color $ui-dark-inactive-text-color
+
+ .folderItem-left-colorButton
+ colorSolarizedDarkPrimaryButton()
+
+ .folderItem-right-button
+ colorSolarizedDarkPrimaryButton()
+
+ .folderItem-right-confirmButton
+ colorSolarizedDarkPrimaryButton()
+
+ .folderItem-right-dangerButton
+ colorSolarizedDarkPrimaryButton()
diff --git a/browser/main/modals/PreferencesModal/FolderList.js b/browser/main/modals/PreferencesModal/FolderList.js
new file mode 100644
index 00000000..8585f641
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderList.js
@@ -0,0 +1,85 @@
+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 } from 'react-sortable-hoc'
+
+class FolderList extends React.Component {
+ render () {
+ const { storage, hostBoundingBox } = this.props
+
+ const folderList = storage.folders.map((folder, index) => {
+ return
+ })
+
+ return (
+
+ {folderList.length > 0
+ ? folderList
+ :
No Folders
+ }
+
+ )
+ }
+}
+
+FolderList.propTypes = {
+ hostBoundingBox: PropTypes.shape({
+ bottom: PropTypes.number,
+ height: PropTypes.number,
+ left: PropTypes.number,
+ right: PropTypes.number,
+ top: PropTypes.number,
+ width: PropTypes.number
+ }),
+ storage: PropTypes.shape({
+ key: PropTypes.string
+ }),
+ folder: PropTypes.shape({
+ key: PropTypes.number,
+ color: PropTypes.string,
+ name: PropTypes.string
+ })
+}
+
+class SortableFolderListComponent extends React.Component {
+ constructor (props) {
+ super(props)
+ this.onSortEnd = ({oldIndex, newIndex}) => {
+ const { storage } = this.props
+ dataApi
+ .reorderFolder(storage.key, oldIndex, newIndex)
+ .then((data) => {
+ store.dispatch({
+ type: 'REORDER_FOLDER',
+ storage: data.storage
+ })
+ this.setState()
+ })
+ }
+ }
+
+ render () {
+ const StyledFolderList = CSSModules(FolderList, this.props.styles)
+ const SortableFolderList = SortableContainer(StyledFolderList)
+
+ return (
+
+ )
+ }
+}
+
+export default CSSModules(SortableFolderListComponent, styles)
diff --git a/browser/main/modals/PreferencesModal/FolderList.styl b/browser/main/modals/PreferencesModal/FolderList.styl
new file mode 100644
index 00000000..e69de29b
diff --git a/browser/main/modals/PreferencesModal/HotkeyTab.js b/browser/main/modals/PreferencesModal/HotkeyTab.js
index f75e41b8..9a15e79f 100644
--- a/browser/main/modals/PreferencesModal/HotkeyTab.js
+++ b/browser/main/modals/PreferencesModal/HotkeyTab.js
@@ -1,8 +1,10 @@
-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'
import store from 'browser/main/store'
+import _ from 'lodash'
const electron = require('electron')
const ipc = electron.ipcRenderer
@@ -40,7 +42,7 @@ class HotkeyTab extends React.Component {
}
handleSaveButtonClick (e) {
- let newConfig = {
+ const newConfig = {
hotkey: this.state.config.hotkey
}
@@ -50,6 +52,7 @@ class HotkeyTab extends React.Component {
type: 'SET_UI',
config: newConfig
})
+ this.clearMessage()
}
handleHintToggleButtonClick (e) {
@@ -59,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
@@ -69,14 +72,22 @@ class HotkeyTab extends React.Component {
})
}
+ clearMessage () {
+ _.debounce(() => {
+ this.setState({
+ keymapAlert: null
+ })
+ }, 2000)()
+ }
+
render () {
- let keymapAlert = this.state.keymapAlert
- let keymapAlertElement = keymapAlert != null
+ const keymapAlert = this.state.keymapAlert
+ const keymapAlertElement = keymapAlert != null
?
{keymapAlert.message}
: null
- let { config } = this.state
+ const { config } = this.state
return (
@@ -94,7 +105,7 @@ class HotkeyTab extends React.Component {
-
Toggle Finder(popup)
+
Toggle Finder (Quick search)
this.handleHotkeyChange(e)}
diff --git a/browser/main/modals/PreferencesModal/InfoTab.js b/browser/main/modals/PreferencesModal/InfoTab.js
index 35cd53a2..2a1db828 100644
--- a/browser/main/modals/PreferencesModal/InfoTab.js
+++ b/browser/main/modals/PreferencesModal/InfoTab.js
@@ -4,6 +4,7 @@ import styles from './InfoTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager'
import store from 'browser/main/store'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
+import _ from 'lodash'
const electron = require('electron')
const { shell, remote } = electron
@@ -36,8 +37,21 @@ class InfoTab extends React.Component {
if (!newConfig.amaEnabled) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
+ this.setState({
+ amaMessage: 'We hope we will gain your trust'
+ })
+ } else {
+ this.setState({
+ amaMessage: 'Thank\'s for trust us'
+ })
}
+ _.debounce(() => {
+ this.setState({
+ amaMessage: ''
+ })
+ }, 3000)()
+
ConfigManager.set(newConfig)
store.dispatch({
@@ -46,10 +60,49 @@ class InfoTab extends React.Component {
})
}
+ infoMessage () {
+ const { amaMessage } = this.state
+ return amaMessage ?
{amaMessage}
: null
+ }
+
render () {
return (
-
Info
+
+
Community
+
+
+
+
+
Info
@@ -62,31 +115,17 @@ class InfoTab extends React.Component {
+
-
+
+
+
Data collection policy
-
We collect only the number of DAU for Boostnote and DO NOT collect any detail information
-
such as your note content. You can see how it works on this.handleLinkClick(e)}>GitHub.
-
These data are only used for Boostnote improvements.
+
We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.
+
+
This data is only used for Boostnote improvements.
this.handleConfigChange(e)}
checked={this.state.config.amaEnabled}
ref='amaEnabled'
@@ -107,6 +148,7 @@ class InfoTab extends React.Component {
/>
Enable to send analytics to our servers
this.handleSaveButtonClick(e)}>Save
+ {this.infoMessage()}
)
}
diff --git a/browser/main/modals/PreferencesModal/InfoTab.styl b/browser/main/modals/PreferencesModal/InfoTab.styl
index 6158c634..cc04a10f 100644
--- a/browser/main/modals/PreferencesModal/InfoTab.styl
+++ b/browser/main/modals/PreferencesModal/InfoTab.styl
@@ -42,13 +42,29 @@
color #4E8EC6
text-decoration none
+.separate-line
+ margin 40px 0
+
.policy
+ width 100%
font-size 20px
margin-bottom 10px
.policy-submit
margin-top 10px
+.policy-confirm
+ margin-top 10px
+ font-size 12px
+
body[data-theme="dark"]
.root
color alpha($tab--dark-text-color, 80%)
+
+
+body[data-theme="solarized-dark"]
+ .root
+ color $ui-solarized-dark-text-color
+.list
+ a
+ color $ui-solarized-dark-active-color
diff --git a/browser/main/modals/PreferencesModal/PreferencesModal.styl b/browser/main/modals/PreferencesModal/PreferencesModal.styl
index a0a670b5..4a280a38 100644
--- a/browser/main/modals/PreferencesModal/PreferencesModal.styl
+++ b/browser/main/modals/PreferencesModal/PreferencesModal.styl
@@ -4,9 +4,10 @@ top-bar--height = 50px
.root
modal()
- max-width 800px
- min-height 500px
- height 80%
+ max-width 100vw
+ min-height 100vh
+ height 100vh
+ width 100vw
overflow hidden
position relative
@@ -24,23 +25,23 @@ top-bar--height = 50px
absolute top left right
top top-bar--height
left 0
- width 140px
- margin-left 30px
+ width 170px
+ margin-left 10px
margin-top 20px
background-color $ui-backgroundColor
.nav-button
font-size 14px
text-align left
- width 100px
- margin 4px 0
- padding 5px 0
+ width 150px
+ margin 5px 0
+ padding 7px 0
padding-left 10px
border none
border-radius 2px
background-color transparent
color $ui-text-color
- font-size 14px
+ font-size 16px
.nav-button--active
@extend .nav-button
@@ -55,7 +56,7 @@ top-bar--height = 50px
.content
absolute left right bottom
top top-bar--height
- left 140px
+ left 170px
margin-top 10px
overflow-y auto
@@ -85,3 +86,29 @@ body[data-theme="dark"]
background-color $dark-primary-button-background--active
&:hover
color white
+
+
+body[data-theme="solarized-dark"]
+ .root
+ background-color transparent
+ .top-bar
+ background-color transparent
+ border-color $ui-solarized-dark-borderColor
+ p
+ color $ui-solarized-dark-text-color
+ .nav
+ background-color transparent
+ border-color $ui-solarized-dark-borderColor
+ .nav-button
+ background-color transparent
+ color $ui-solarized-dark-text-color
+ &:hover
+ color $ui-solarized-dark-text-color
+
+ .nav-button--active
+ @extend .nav-button
+ color $ui-solarized-dark-button--active-color
+ background-color $ui-solarized-dark-button--active-backgroundColor
+ &:hover
+ color white
+
diff --git a/browser/main/modals/PreferencesModal/StorageItem.js b/browser/main/modals/PreferencesModal/StorageItem.js
index d3586f35..f2092835 100644
--- a/browser/main/modals/PreferencesModal/StorageItem.js
+++ b/browser/main/modals/PreferencesModal/StorageItem.js
@@ -1,265 +1,14 @@
-import React, { PropTypes } from 'react'
-import ReactDOM from 'react-dom'
+import PropTypes from 'prop-types'
+import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageItem.styl'
import consts from 'browser/lib/consts'
import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
+import FolderList from './FolderList'
const { shell, remote } = require('electron')
const { dialog } = remote
-import { SketchPicker } from 'react-color'
-
-class UnstyledFolderItem extends React.Component {
- constructor (props) {
- super(props)
-
- this.state = {
- status: 'IDLE',
- folder: {
- showColumnPicker: false,
- colorPickerPos: { left: 0, top: 0 },
- color: props.color,
- name: props.name
- }
- }
- }
-
- handleEditChange (e) {
- let { folder } = this.state
-
- folder.name = this.refs.nameInput.value
- this.setState({
- folder
- })
- }
-
- handleConfirmButtonClick (e) {
- this.confirm()
- }
-
- confirm () {
- let { storage, folder } = this.props
- dataApi
- .updateFolder(storage.key, folder.key, {
- color: this.state.folder.color,
- name: this.state.folder.name
- })
- .then((data) => {
- store.dispatch({
- type: 'UPDATE_FOLDER',
- storage: data.storage
- })
- this.setState({
- status: 'IDLE'
- })
- })
- }
-
- handleColorButtonClick (e) {
- const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
- this.setState({ folder }, function () {
- // After the color picker has been painted, re-calculate its position
- // by comparing its dimensions to the host dimensions.
- const { hostBoundingBox } = this.props
- const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
- const colorPickerBox = colorPickerNode.getBoundingClientRect()
- const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
- const folder = Object.assign({}, this.state.folder, {
- colorPickerPos: {
- left: 25,
- top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
- }
- })
- this.setState({ folder })
- })
- }
-
- handleColorChange (color) {
- const folder = Object.assign({}, this.state.folder, { color: color.hex })
- this.setState({ folder })
- }
-
- handleColorPickerClose (event) {
- const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
- this.setState({ folder })
- }
-
- handleCancelButtonClick (e) {
- this.setState({
- status: 'IDLE'
- })
- }
-
- handleFolderItemBlur (e) {
- let el = e.relatedTarget
- while (el != null) {
- if (el === this.refs.root) {
- return false
- }
- el = el.parentNode
- }
- this.confirm()
- }
-
- renderEdit (e) {
- const popover = { position: 'absolute', zIndex: 2 }
- const cover = {
- position: 'fixed',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0
- }
- const pickerStyle = Object.assign({}, {
- position: 'absolute'
- }, this.state.folder.colorPickerPos)
- return (
-
this.handleFolderItemBlur(e)}
- tabIndex='-1'
- ref='root'
- >
-
-
!this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
- >
- {this.state.folder.showColumnPicker
- ?
-
this.handleColorPickerClose()}
- />
-
- this.handleColorChange(color)}
- onChangeComplete={(color) => this.handleColorChange(color)}
- />
-
-
- : null
- }
-
-
-
this.handleEditChange(e)}
- />
-
-
- this.handleConfirmButtonClick(e)}
- >
- Confirm
-
- this.handleCancelButtonClick(e)}
- >
- Cancel
-
-
-
- )
- }
-
- handleDeleteConfirmButtonClick (e) {
- let { storage, folder } = this.props
- dataApi
- .deleteFolder(storage.key, folder.key)
- .then((data) => {
- store.dispatch({
- type: 'DELETE_FOLDER',
- storage: data.storage,
- folderKey: data.folderKey
- })
- })
- }
-
- renderDelete () {
- return (
-
-
- Are you sure to delete this folder?
-
-
- this.handleDeleteConfirmButtonClick(e)}
- >
- Confirm
-
- this.handleCancelButtonClick(e)}
- >
- Cancel
-
-
-
- )
- }
-
- handleEditButtonClick (e) {
- let { folder: propsFolder } = this.props
- let { folder: stateFolder } = this.state
- const folder = Object.assign({}, stateFolder, propsFolder)
- this.setState({
- status: 'EDIT',
- folder
- }, () => {
- this.refs.nameInput.select()
- })
- }
-
- handleDeleteButtonClick (e) {
- this.setState({
- status: 'DELETE'
- })
- }
-
- renderIdle () {
- let { folder } = this.props
- return (
-
this.handleEditButtonClick(e)}
- >
-
- {folder.name}
- ({folder.key})
-
-
- this.handleEditButtonClick(e)}
- >
- Edit
-
- this.handleDeleteButtonClick(e)}
- >
- Delete
-
-
-
-
- )
- }
-
- render () {
- switch (this.state.status) {
- case 'DELETE':
- return this.renderDelete()
- case 'EDIT':
- return this.renderEdit()
- case 'IDLE':
- default:
- return this.renderIdle()
- }
- }
-}
-
-const FolderItem = CSSModules(UnstyledFolderItem, styles)
class StorageItem extends React.Component {
constructor (props) {
@@ -271,8 +20,8 @@ class StorageItem extends React.Component {
}
handleNewFolderButtonClick (e) {
- let { storage } = this.props
- let input = {
+ const { storage } = this.props
+ const input = {
name: 'Untitled',
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
}
@@ -290,12 +39,12 @@ class StorageItem extends React.Component {
}
handleExternalButtonClick () {
- let { storage } = this.props
+ const { storage } = this.props
shell.showItemInFolder(storage.path)
}
handleUnlinkButtonClick (e) {
- let index = dialog.showMessageBox(remote.getCurrentWindow(), {
+ const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Unlink Storage',
detail: 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.',
@@ -303,7 +52,7 @@ class StorageItem extends React.Component {
})
if (index === 0) {
- let { storage } = this.props
+ const { storage } = this.props
dataApi.removeStorage(storage.key)
.then(() => {
store.dispatch({
@@ -318,7 +67,7 @@ class StorageItem extends React.Component {
}
handleLabelClick (e) {
- let { storage } = this.props
+ const { storage } = this.props
this.setState({
isLabelEditing: true,
name: storage.name
@@ -333,7 +82,7 @@ class StorageItem extends React.Component {
}
handleLabelBlur (e) {
- let { storage } = this.props
+ const { storage } = this.props
dataApi
.renameStorage(storage.key, this.state.name)
.then((_storage) => {
@@ -348,14 +97,8 @@ class StorageItem extends React.Component {
}
render () {
- let { storage, hostBoundingBox } = this.props
- let folderList = storage.folders.map((folder) => {
- return
- })
+ const { storage, hostBoundingBox } = this.props
+
return (
@@ -404,12 +147,9 @@ class StorageItem extends React.Component {
-
- {folderList.length > 0
- ? folderList
- :
No Folders
- }
-
+
)
}
@@ -426,11 +166,6 @@ StorageItem.propTypes = {
}),
storage: PropTypes.shape({
key: PropTypes.string
- }),
- folder: PropTypes.shape({
- key: PropTypes.string,
- color: PropTypes.string,
- name: PropTypes.string
})
}
diff --git a/browser/main/modals/PreferencesModal/StorageItem.styl b/browser/main/modals/PreferencesModal/StorageItem.styl
index 538edfb8..13759007 100644
--- a/browser/main/modals/PreferencesModal/StorageItem.styl
+++ b/browser/main/modals/PreferencesModal/StorageItem.styl
@@ -63,75 +63,6 @@
z-index 10
white-space nowrap
-.folderList-item
- height 35px
- box-sizing border-box
- padding 2.5px 15px
- &:hover
- background-color darken(white, 3%)
-.folderList-item-left
- height 30px
- border-left solid 2px transparent
- padding 0 10px
- line-height 30px
- float left
-.folderList-item-left-danger
- color $danger-color
- font-weight bold
-
-.folderList-item-left-key
- color $ui-inactive-text-color
- font-size 10px
- margin 0 5px
- border none
-
-.folderList-item-left-colorButton
- colorDefaultButton()
- height 25px
- width 25px
- line-height 23px
- padding 0
- box-sizing border-box
- vertical-align middle
- border $ui-border
- border-radius 2px
- margin-right 5px
- margin-left -15px
-
-.folderList-item-left-nameInput
- height 25px
- box-sizing border-box
- vertical-align middle
- border $ui-border
- border-radius 2px
- padding 0 5px
- outline none
-
-.folderList-item-right
- float right
-
-.folderList-item-right-button
- vertical-align middle
- height 25px
- margin-top 2.5px
- colorDefaultButton()
- border-radius 2px
- border $ui-border
- margin-right 5px
- padding 0 5px
- &:last-child
- margin-right 0
-
-.folderList-item-right-confirmButton
- @extend .folderList-item-right-button
- border none
- colorPrimaryButton()
-
-.folderList-item-right-dangerButton
- @extend .folderList-item-right-button
- border none
- colorDangerButton()
-
body[data-theme="dark"]
.header
border-color $ui-dark-borderColor
@@ -153,28 +84,3 @@ body[data-theme="dark"]
top 25px
z-index 10
white-space nowrap
-
- .folderList-item
- &:hover
- background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
-
- .folderList-item-left-danger
- color $danger-color
- font-weight bold
-
- .folderList-item-left-key
- color $ui-dark-inactive-text-color
-
- .folderList-item-left-colorButton
- colorDarkDefaultButton()
- border-color $ui-dark-borderColor
-
- .folderList-item-right-button
- colorDarkDefaultButton()
- border-color $ui-dark-borderColor
-
- .folderList-item-right-confirmButton
- colorDarkPrimaryButton()
-
- .folderList-item-right-dangerButton
- colorDarkDangerButton()
diff --git a/browser/main/modals/PreferencesModal/StoragesTab.js b/browser/main/modals/PreferencesModal/StoragesTab.js
index dc1f96f0..5c328f8a 100644
--- a/browser/main/modals/PreferencesModal/StoragesTab.js
+++ b/browser/main/modals/PreferencesModal/StoragesTab.js
@@ -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 styles from './StoragesTab.styl'
import dataApi from 'browser/main/lib/dataApi'
import StorageItem from './StorageItem'
const electron = require('electron')
-const remote = electron.remote
+const { shell, 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',
@@ -50,11 +51,16 @@ class StoragesTab extends React.Component {
})
}
+ handleLinkClick (e) {
+ shell.openExternal(e.currentTarget.href)
+ e.preventDefault()
+ }
+
renderList () {
- let { data, boundingBox } = this.props
+ const { data, boundingBox } = this.props
if (!boundingBox) { return null }
- let storageList = data.storageMap.map((storage) => {
+ const storageList = data.storageMap.map((storage) => {
return
{
if (targetPath.length > 0) {
- let { newStorage } = this.state
+ const { newStorage } = this.state
newStorage.path = targetPath
this.setState({
newStorage
@@ -97,7 +103,7 @@ class StoragesTab extends React.Component {
}
handleAddStorageChange (e) {
- let { newStorage } = this.state
+ const { newStorage } = this.state
newStorage.name = this.refs.addStorageName.value
newStorage.path = this.refs.addStoragePath.value
this.setState({
@@ -112,7 +118,7 @@ class StoragesTab extends React.Component {
path: this.state.newStorage.path
})
.then((data) => {
- let { dispatch } = this.props
+ const { dispatch } = this.props
dispatch({
type: 'ADD_STORAGE',
storage: data.storage,
@@ -161,7 +167,10 @@ class StoragesTab extends React.Component {
diff --git a/browser/main/modals/PreferencesModal/StoragesTab.styl b/browser/main/modals/PreferencesModal/StoragesTab.styl
index 966a8eab..230f0aed 100644
--- a/browser/main/modals/PreferencesModal/StoragesTab.styl
+++ b/browser/main/modals/PreferencesModal/StoragesTab.styl
@@ -158,3 +158,44 @@ body[data-theme="dark"]
.addStorage-body-control-cancelButton
colorDarkDefaultButton()
border-color $ui-dark-borderColor
+
+
+
+body[data-theme="solarized-dark"]
+ .root
+ color $ui-solarized-dark-text-color
+
+ .folderList-item
+ border-bottom $ui-solarized-dark-borderColor
+
+ .folderList-empty
+ color $ui-solarized-dark-text-color
+
+ .list-empty
+ color $ui-solarized-dark-text-color
+ .list-control-addStorageButton
+ border-color $ui-solarized-dark-button-backgroundColor
+ background-color $ui-solarized-dark-button-backgroundColor
+ color $ui-solarized-dark-text-color
+
+ .addStorage-header
+ color $ui-solarized-dark-text-color
+ border-color $ui-solarized-dark-borderColor
+
+ .addStorage-body-section-name-input
+ border-color $$ui-solarized-dark-borderColor
+
+ .addStorage-body-section-type-description
+ color $ui-solarized-dark-text-color
+
+ .addStorage-body-section-path-button
+ colorPrimaryButton()
+ .addStorage-body-control
+ border-color $ui-solarized-dark-borderColor
+
+ .addStorage-body-control-createButton
+ colorDarkPrimaryButton()
+ .addStorage-body-control-cancelButton
+ colorDarkDefaultButton()
+ border-color $ui-solarized-dark-borderColor
+
diff --git a/browser/main/modals/PreferencesModal/Tab.styl b/browser/main/modals/PreferencesModal/Tab.styl
index 7280407b..e5fc48da 100644
--- a/browser/main/modals/PreferencesModal/Tab.styl
+++ b/browser/main/modals/PreferencesModal/Tab.styl
@@ -10,8 +10,12 @@ $tab--button-font-size = 14px
$tab--dark-text-color = #E5E5E5
.header
- font-size 24px
- margin-bottom 30px
+ font-size 36px
+ margin-bottom 60px
+
+.header--sub
+ font-size 36px
+ margin-bottom 20px
body[data-theme="dark"]
.header
diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js
index 61aca0dc..0baedf4c 100644
--- a/browser/main/modals/PreferencesModal/UiTab.js
+++ b/browser/main/modals/PreferencesModal/UiTab.js
@@ -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'
@@ -9,6 +10,11 @@ import CodeMirror from 'codemirror'
const OSX = global.process.platform === 'darwin'
+import _ from 'lodash'
+
+const electron = require('electron')
+const ipc = electron.ipcRenderer
+
class UiTab extends React.Component {
constructor (props) {
super(props)
@@ -18,8 +24,27 @@ class UiTab extends React.Component {
}
}
- componentWillMount () {
- CodeMirror.autoLoadMode(ReactCodeMirror, 'javascript')
+ componentDidMount () {
+ CodeMirror.autoLoadMode(this.codeMirrorInstance.getCodeMirror(), 'javascript')
+ this.handleSettingDone = () => {
+ this.setState({UiAlert: {
+ type: 'success',
+ message: 'Successfully applied!'
+ }})
+ }
+ this.handleSettingError = (err) => {
+ this.setState({UiAlert: {
+ type: 'error',
+ message: err.message != null ? err.message : 'Error occurs!'
+ }})
+ }
+ ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
+ ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
+ }
+
+ componentWillUnmount () {
+ ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
+ ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
}
handleUIChange (e) {
@@ -36,6 +61,7 @@ class UiTab extends React.Component {
const newConfig = {
ui: {
theme: this.refs.uiTheme.value,
+ showCopyNotification: this.refs.showCopyNotification.checked,
disableDirectWrite: this.refs.uiD2w != null
? this.refs.uiD2w.checked
: false
@@ -48,20 +74,25 @@ class UiTab extends React.Component {
indentSize: this.refs.editorIndentSize.value,
displayLineNumbers: this.refs.editorDisplayLineNumbers.checked,
switchPreview: this.refs.editorSwitchPreview.value,
- keyMap: this.refs.editorKeyMap.value
+ keyMap: this.refs.editorKeyMap.value,
+ scrollPastEnd: this.refs.scrollPastEnd.checked
},
preview: {
fontSize: this.refs.previewFontSize.value,
fontFamily: this.refs.previewFontFamily.value,
codeBlockTheme: this.refs.previewCodeBlockTheme.value,
- lineNumber: this.refs.previewLineNumber.checked
+ lineNumber: this.refs.previewLineNumber.checked,
+ latexInlineOpen: this.refs.previewLatexInlineOpen.value,
+ latexInlineClose: this.refs.previewLatexInlineClose.value,
+ latexBlockOpen: this.refs.previewLatexBlockOpen.value,
+ latexBlockClose: this.refs.previewLatexBlockClose.value
}
}
const newCodemirrorTheme = this.refs.editorTheme.value
if (newCodemirrorTheme !== codemirrorTheme) {
- checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme}.css`)
+ checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`)
}
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme })
@@ -80,9 +111,25 @@ class UiTab extends React.Component {
type: 'SET_UI',
config: newConfig
})
+ this.clearMessage()
+ }
+
+ clearMessage () {
+ _.debounce(() => {
+ this.setState({
+ UiAlert: null
+ })
+ }, 2000)()
}
render () {
+ const UiAlert = this.state.UiAlert
+ const UiAlertElement = UiAlert != null
+ ?
+ {UiAlert.message}
+
+ : null
+
const themes = consts.THEMES
const { config, codemirrorTheme } = this.state
const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};'
@@ -91,19 +138,30 @@ class UiTab extends React.Component {
UI
-
Theme
-
+ Color Theme
+
+
+
{
global.process.platform === 'win32'
?
@@ -137,7 +195,7 @@ class UiTab extends React.Component {
}
-
+ (this.codeMirrorInstance = e)} value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} />
@@ -219,7 +277,7 @@ class UiTab extends React.Component {
- Please restart boostnote after you change the keymap
+ ⚠️ Please restart boostnote after you change the keymap
@@ -234,6 +292,18 @@ class UiTab extends React.Component {
+
+
+
+
+
Preview
@@ -286,13 +356,64 @@ class UiTab extends React.Component {
Show line numbers for preview code blocks
+
+
+ LaTeX Inline Open Delimiter
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
+
+ LaTeX Inline Close Delimiter
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
+
+ LaTeX Block Open Delimiter
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
+
+ LaTeX Block Close Delimiter
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
-
+
this.handleSaveUIClick(e)}
- >
- Save
+ onClick={(e) => this.handleSaveUIClick(e)}>Save
+ {UiAlertElement}
diff --git a/browser/main/modals/PreferencesModal/index.js b/browser/main/modals/PreferencesModal/index.js
index c7b9a68d..2fff0364 100644
--- a/browser/main/modals/PreferencesModal/index.js
+++ b/browser/main/modals/PreferencesModal/index.js
@@ -1,13 +1,16 @@
-import React, { PropTypes } from 'react'
+import PropTypes from 'prop-types'
+import React from 'react'
import ReactDOM from 'react-dom'
import { connect } from 'react-redux'
import HotkeyTab from './HotkeyTab'
import UiTab from './UiTab'
import InfoTab from './InfoTab'
+import Crowdfunding from './Crowdfunding'
import StoragesTab from './StoragesTab'
import ModalEscButton from 'browser/components/ModalEscButton'
import CSSModules from 'browser/lib/CSSModules'
import styles from './PreferencesModal.styl'
+import RealtimeNotification from 'browser/components/RealtimeNotification'
class Preferences extends React.Component {
constructor (props) {
@@ -40,7 +43,7 @@ class Preferences extends React.Component {
renderContent () {
const { boundingBox } = this.state
- let { dispatch, config, data } = this.props
+ const { dispatch, config, data } = this.props
switch (this.state.currentTab) {
case 'INFO':
@@ -64,6 +67,10 @@ class Preferences extends React.Component {
config={config}
/>
)
+ case 'CROWDFUNDING':
+ return (
+
+ )
case 'STORAGES':
default:
return (
@@ -88,17 +95,18 @@ class Preferences extends React.Component {
}
render () {
- let content = this.renderContent()
+ const content = this.renderContent()
- let tabs = [
+ const tabs = [
{target: 'STORAGES', label: 'Storages'},
{target: 'HOTKEY', label: 'Hotkey'},
{target: 'UI', label: 'UI'},
- {target: 'INFO', label: 'Info'}
+ {target: 'INFO', label: 'Community / Info'},
+ {target: 'CROWDFUNDING', label: 'Crowdfunding'}
]
- let navButtons = tabs.map((tab) => {
- let isActive = this.state.currentTab === tab.target
+ const navButtons = tabs.map((tab) => {
+ const isActive = this.state.currentTab === tab.target
return (
{content}
+
)
}
diff --git a/browser/main/modals/RenameFolderModal.js b/browser/main/modals/RenameFolderModal.js
index 09e86632..bb08f36d 100644
--- a/browser/main/modals/RenameFolderModal.js
+++ b/browser/main/modals/RenameFolderModal.js
@@ -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 './RenameFolderModal.styl'
import dataApi from 'browser/main/lib/dataApi'
@@ -48,7 +49,7 @@ class RenameFolderModal extends React.Component {
confirm () {
if (this.state.name.trim().length > 0) {
- let { storage, folder } = this.props
+ const { storage, folder } = this.props
dataApi
.updateFolder(storage.key, folder.key, {
name: this.state.name,
diff --git a/browser/main/store.js b/browser/main/store.js
index 68c46876..647d0ac9 100644
--- a/browser/main/store.js
+++ b/browser/main/store.js
@@ -27,8 +27,8 @@ function data (state = defaultDataMap(), action) {
action.notes.some((note) => {
if (note === undefined) return true
- let uniqueKey = note.storage + '-' + note.key
- let folderKey = note.storage + '-' + note.folder
+ const uniqueKey = note.storage + '-' + note.key
+ const folderKey = note.storage + '-' + note.folder
state.noteMap.set(uniqueKey, note)
if (note.isStarred) {
@@ -65,10 +65,10 @@ function data (state = defaultDataMap(), action) {
return state
case 'UPDATE_NOTE':
{
- let note = action.note
- let uniqueKey = note.storage + '-' + note.key
- let folderKey = note.storage + '-' + note.folder
- let oldNote = state.noteMap.get(uniqueKey)
+ const note = action.note
+ const uniqueKey = note.storage + '-' + note.key
+ const folderKey = note.storage + '-' + note.folder
+ const oldNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state)
state.noteMap = new Map(state.noteMap)
@@ -110,7 +110,7 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap.set(folderKey, folderNoteSet)
if (oldNote != null) {
- let oldFolderKey = oldNote.storage + '-' + oldNote.folder
+ const oldFolderKey = oldNote.storage + '-' + oldNote.folder
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
oldFolderNoteList = new Set(oldFolderNoteList)
oldFolderNoteList.delete(uniqueKey)
@@ -119,8 +119,8 @@ function data (state = defaultDataMap(), action) {
}
if (oldNote != null) {
- let discardedTags = _.difference(oldNote.tags, note.tags)
- let addedTags = _.difference(note.tags, oldNote.tags)
+ const discardedTags = _.difference(oldNote.tags, note.tags)
+ const addedTags = _.difference(note.tags, oldNote.tags)
if (discardedTags.length + addedTags.length > 0) {
state.tagNoteMap = new Map(state.tagNoteMap)
@@ -156,12 +156,12 @@ function data (state = defaultDataMap(), action) {
}
case 'MOVE_NOTE':
{
- let originNote = action.originNote
- let originKey = originNote.storage + '-' + originNote.key
- let note = action.note
- let uniqueKey = note.storage + '-' + note.key
- let folderKey = note.storage + '-' + note.folder
- let oldNote = state.noteMap.get(uniqueKey)
+ const originNote = action.originNote
+ const originKey = originNote.storage + '-' + originNote.key
+ const note = action.note
+ const uniqueKey = note.storage + '-' + note.key
+ const folderKey = note.storage + '-' + note.folder
+ const oldNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state)
state.noteMap = new Map(state.noteMap)
@@ -191,7 +191,7 @@ function data (state = defaultDataMap(), action) {
// From folderNoteMap
state.folderNoteMap = new Map(state.folderNoteMap)
- let originFolderKey = originNote.storage + '-' + originNote.folder
+ const originFolderKey = originNote.storage + '-' + originNote.folder
let originFolderList = state.folderNoteMap.get(originFolderKey)
originFolderList = new Set(originFolderList)
originFolderList.delete(originKey)
@@ -245,7 +245,7 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap.set(folderKey, folderNoteList)
if (oldNote != null) {
- let oldFolderKey = oldNote.storage + '-' + oldNote.folder
+ const oldFolderKey = oldNote.storage + '-' + oldNote.folder
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
oldFolderNoteList = new Set(oldFolderNoteList)
oldFolderNoteList.delete(uniqueKey)
@@ -255,8 +255,8 @@ function data (state = defaultDataMap(), action) {
// Remove from old folder map
if (oldNote != null) {
- let discardedTags = _.difference(oldNote.tags, note.tags)
- let addedTags = _.difference(note.tags, oldNote.tags)
+ const discardedTags = _.difference(oldNote.tags, note.tags)
+ const addedTags = _.difference(note.tags, oldNote.tags)
if (discardedTags.length + addedTags.length > 0) {
state.tagNoteMap = new Map(state.tagNoteMap)
@@ -292,8 +292,8 @@ function data (state = defaultDataMap(), action) {
}
case 'DELETE_NOTE':
{
- let uniqueKey = action.storageKey + '-' + action.noteKey
- let targetNote = state.noteMap.get(uniqueKey)
+ const uniqueKey = action.storageKey + '-' + action.noteKey
+ const targetNote = state.noteMap.get(uniqueKey)
state = Object.assign({}, state)
@@ -317,7 +317,7 @@ function data (state = defaultDataMap(), action) {
}
// From folderNoteMap
- let folderKey = targetNote.storage + '-' + targetNote.folder
+ const folderKey = targetNote.storage + '-' + targetNote.folder
state.folderNoteMap = new Map(state.folderNoteMap)
let folderSet = state.folderNoteMap.get(folderKey)
folderSet = new Set(folderSet)
@@ -340,11 +340,14 @@ function data (state = defaultDataMap(), action) {
return state
}
case 'UPDATE_FOLDER':
- {
- state = Object.assign({}, state)
- state.storageMap = new Map(state.storageMap)
- state.storageMap.set(action.storage.key, action.storage)
- }
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+ return state
+ case 'REORDER_FOLDER':
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
return state
case 'DELETE_FOLDER':
{
@@ -354,8 +357,8 @@ function data (state = defaultDataMap(), action) {
// Get note list from folder-note map
// and delete note set from folder-note map
- let folderKey = action.storage.key + '-' + action.folderKey
- let noteSet = state.folderNoteMap.get(folderKey)
+ const folderKey = action.storage.key + '-' + action.folderKey
+ const noteSet = state.folderNoteMap.get(folderKey)
state.folderNoteMap = new Map(state.folderNoteMap)
state.folderNoteMap.delete(folderKey)
@@ -368,7 +371,7 @@ function data (state = defaultDataMap(), action) {
if (noteSet != null) {
noteSet.forEach(function handleNoteKey (noteKey) {
// Get note from noteMap
- let note = state.noteMap.get(noteKey)
+ const note = state.noteMap.get(noteKey)
if (note != null) {
state.noteMap.delete(noteKey)
@@ -410,8 +413,8 @@ function data (state = defaultDataMap(), action) {
state.folderNoteMap = new Map(state.folderNoteMap)
state.tagNoteMap = new Map(state.tagNoteMap)
action.notes.forEach((note) => {
- let uniqueKey = note.storage + '-' + note.key
- let folderKey = note.storage + '-' + note.folder
+ const uniqueKey = note.storage + '-' + note.key
+ const folderKey = note.storage + '-' + note.folder
state.noteMap.set(uniqueKey, note)
if (note.isStarred) {
@@ -444,7 +447,7 @@ function data (state = defaultDataMap(), action) {
return state
case 'REMOVE_STORAGE':
state = Object.assign({}, state)
- let storage = state.storageMap.get(action.storageKey)
+ const storage = state.storageMap.get(action.storageKey)
state.storageMap = new Map(state.storageMap)
state.storageMap.delete(action.storageKey)
@@ -452,17 +455,17 @@ function data (state = defaultDataMap(), action) {
if (storage != null) {
state.folderMap = new Map(state.folderMap)
storage.folders.forEach((folder) => {
- let folderKey = storage.key + '-' + folder.key
+ const folderKey = storage.key + '-' + folder.key
state.folderMap.delete(folderKey)
})
}
// Remove notes from noteMap and tagNoteMap
- let storageNoteSet = state.storageNoteMap.get(action.storageKey)
+ const storageNoteSet = state.storageNoteMap.get(action.storageKey)
state.storageNoteMap = new Map(state.storageNoteMap)
state.storageNoteMap.delete(action.storageKey)
if (storageNoteSet != null) {
- let notes = storageNoteSet
+ const notes = storageNoteSet
.map((noteKey) => state.noteMap.get(noteKey))
.filter((note) => note != null)
@@ -470,7 +473,7 @@ function data (state = defaultDataMap(), action) {
state.tagNoteMap = new Map(state.tagNoteMap)
state.starredSet = new Set(state.starredSet)
notes.forEach((note) => {
- let noteKey = storage.key + '-' + note.key
+ const noteKey = storage.key + '-' + note.key
state.noteMap.delete(noteKey)
state.starredSet.delete(noteKey)
note.tags.forEach((tag) => {
@@ -528,13 +531,13 @@ function status (state = defaultStatus, action) {
return state
}
-let reducer = combineReducers({
+const reducer = combineReducers({
data,
config,
status,
routing: routerReducer
})
-let store = createStore(reducer)
+const store = createStore(reducer)
export default store
diff --git a/browser/styles/index.styl b/browser/styles/index.styl
index 8df338c0..a7d31f8c 100644
--- a/browser/styles/index.styl
+++ b/browser/styles/index.styl
@@ -5,7 +5,7 @@ $danger-color = #c9302c
$danger-lighten-color = lighten(#c9302c, 5%)
// Layouts
-$statusBar-height = 24px
+$statusBar-height = 0px
$sideNav-width = 200px
$sideNav--folded-width = 44px
$topBar-height = 60px
@@ -15,18 +15,18 @@ $ui-text-color = #333333
$ui-inactive-text-color = #939395
$ui-borderColor = #D1D1D1
$ui-backgroundColor = #FFFFFF
-$ui-noteList-backgroundColor = #F3F3F3
-$ui-noteDetail-backgroundColor = #F4F4F4
+$ui-noteList-backgroundColor = #FBFBFB
+$ui-noteDetail-backgroundColor = #FFFFFF
$ui-border = solid 1px $ui-borderColor
$ui-active-color = #6AA5E9
$ui-tag-backgroundColor = rgba(0, 0, 0, 0.3)
-// UI Button
-$ui-button-color = #939395
-$ui-button--hover-backgroundColor = #D9D9D9
-$ui-button--active-color = white
-$ui-button--active-backgroundColor = #D9D9D9
-$ui-button--focus-borderColor = lighten(#369DCD, 25%)
+// UI Default Button
+$ui-button-default-color = #FBFBFB
+$ui-button-default--hover-backgroundColor = #2B8976
+$ui-button-default--active-color = white
+$ui-button-default--active-backgroundColor = #2B8976
+$ui-button-default--focus-borderColor = lighten(#369DCD, 25%)
// UI Tooltip
$ui-tooltip-text-color = white
@@ -86,6 +86,7 @@ colorPrimaryButton()
color $ui-text-color
background-color $default-button-background--hover
&:hover
+ transition 0.2s
background-color $default-button-background--active
&:active
&:active:hover
@@ -105,6 +106,18 @@ colorDarkPrimaryButton()
&:active:hover
background-color $dark-primary-button-background--active
+
+colorSolarizedDarkPrimaryButton()
+ color $ui-solarized-dark-text-color
+ background-color $ui-solarized-dark-button-backgroundColor
+ border none
+ &:hover
+ background-color $dark-primary-button-background--hover
+ &:active
+ &:active:hover
+ background-color $dark-primary-button-background--active
+
+
// Danger button(Brand color)
$danger-button-background = #c9302c
$danger-button-background--hover = darken(#c9302c, 5%)
@@ -119,6 +132,22 @@ colorDangerButton()
&:active:hover
background-color $danger-button-background--active
+/**
+* SideNav
+*/
+SideNavFilter()
+ background-color $ui-button-default--active-backgroundColor
+ .counters
+ color $ui-button-default-color
+ .menu-button-label
+ color $ui-button-default-color
+ &:hover
+ background-color alpha($ui-button-default--hover-backgroundColor, 20%)
+ &:active, &:active:hover
+ background-color alpha($ui-button-default--hover-backgroundColor, 20%)
+ .menu-button-label
+ color #1EC38B
+
/**
* Nav
*/
@@ -129,13 +158,12 @@ navButtonColor()
background-color transparent
transition 0.15s
&:hover
- background-color alpha($ui-button--active-backgroundColor, 20%)
transition 0.15s
- color $ui-text-color
+ color $ui-button-default-color
&:active, &:active:hover
- background-color $ui-button--active-backgroundColor
- color $ui-text-color
+ color $ui-button-default-color
transition 0.15s
+
/**
* # Modal Stuff
* These will be moved lib/modal
@@ -150,34 +178,68 @@ modal()
position relative
z-index $modal-z-index
width 100%
+ margin-left 80px
+ margin-right 80px
+ margin-bottom 80px
+ margin-top 100px
background-color $modal-background
overflow hidden
border-radius $modal-border-radius
- box-shadow 0 0 1px rgba(76,86,103,.15), 0 2px 18px rgba(31,37,50,.22)
-topBarButtonLight()
+topBarButtonRight()
+ position absolute
width 34px
height 34px
border-radius 17px
font-size 14px
- margin 15px 7px
border none
- color $ui-button-color
+ color alpha($ui-button-color, 0.2)
fill $ui-button-color
background-color transparent
&:active
border-color $ui-button--active-backgroundColor
&:hover
- background-color alpha($ui-button--hover-backgroundColor, 60%)
+ // transform scale(1.1)
+ transition 0.4s
+ color $ui-button-color
.control-lockButton-tooltip
opacity 1
-// Dark theme
+// White theme
+$ui-white-noteList-backgroundColor = #F3F3F3
+$ui-white-noteDetail-backgroundColor = #F4F4F4
+
+/**
+* Nav
+*/
+navWhiteButtonColor()
+ border none
+ color $ui-button-color
+ background-color transparent
+ transition 0.15s
+ &:hover
+ background-color alpha($ui-button--active-backgroundColor, 20%)
+ transition 0.15s
+ color $ui-text-color
+ &:active, &:active:hover
+ background-color $ui-button--active-backgroundColor
+ color $ui-text-color
+ transition 0.15s
+
+// UI Button
+$ui-button-color = #939395
+$ui-button--hover-backgroundColor = #F6F6F6
+$ui-button--active-color = white
+$ui-button--active-backgroundColor = #D9D9D9
+$ui-button--focus-borderColor = lighten(#369DCD, 25%)
+
+/******* Dark theme ********/
$ui-dark-active-color = #3A404C
-$ui-dark-borderColor = lighten(#21252B, 20%)
-$ui-dark-backgroundColor = #1E2124
-$ui-dark-noteList-backgroundColor = #282C30
-$ui-dark-noteDetail-backgroundColor = #2D3033
+$ui-dark-borderColor = #444444
+$ui-dark-backgroundColor = #2C3033
+$ui-dark-noteList-backgroundColor = #2C3033
+$ui-dark-noteDetail-backgroundColor = #2C3033
+
$ui-dark-tag-backgroundColor = #3A404C
$dark-background-color = lighten($ui-dark-backgroundColor, 10%)
$ui-dark-text-color = #DDDDDD
@@ -200,6 +262,7 @@ colorDarkDefaultButton()
&:active:hover
background-color $ui-dark-button--active-backgroundColor
+
$dark-danger-button-background = #c9302c
$dark-danger-button-background--hover = darken(#c9302c, 5%)
$dark-danger-button-background--active = darken(#c9302c, 10%)
@@ -230,12 +293,10 @@ topBarButtonDark()
border-color $ui-dark-borderColor
color $ui-dark-topbar-button-color
&:hover
- background-color $dark-default-button-background--hover
color $ui-dark-tooltip-text-color
&:active
border-color $ui-dark-button--focus-borderColor
&:active:hover
- background-color $ui-dark-button--active-backgroundColor
color $ui-dark-tooltip-text-color
&:focus
border-color $ui-button--focus-borderColor
@@ -260,4 +321,22 @@ modalDark()
background-color $ui-dark-backgroundColor
overflow hidden
border-radius $modal-border-radius
- box-shadow 2px 2px 10px black
+
+
+/******* Solarized Dark theme ********/
+$ui-solarized-dark-backgroundColor = #073642
+$ui-solarized-dark-noteList-backgroundColor = #073642
+$ui-solarized-dark-noteDetail-backgroundColor = #073642
+
+$ui-solarized-dark-text-color = #93a1a1
+$ui-solarized-dark-active-color = #2aa198
+
+$ui-solarized-dark-borderColor = #586e75
+
+$ui-solarized-dark-tag-backgroundColor = #002b36
+
+$ui-solarized-dark-button-backgroundColor = #002b36
+$ui-solarized-dark-button--active-color = #93a1a1
+$ui-solarized-dark-button--active-backgroundColor = #073642
+$ui-solarized-dark-button--hover-backgroundColor = lighten($ui-dark-backgroundColor, 10%)
+$ui-solarized-dark-button--focus-borderColor = lighten(#369DCD, 25%)
\ No newline at end of file
diff --git a/browser/styles/main/index.styl b/browser/styles/main/index.styl
deleted file mode 100644
index a27b98ac..00000000
--- a/browser/styles/main/index.styl
+++ /dev/null
@@ -1,113 +0,0 @@
-@import '../vars'
-@import '../mixins/*'
-global-reset()
-@import '../theme/*'
-
-DEFAULT_FONTS = 'Lato', helvetica, arial, sans-serif
-
-html, body
- width 100%
- height 100%
- overflow hidden
-
-body
- font-family DEFAULT_FONTS
- color textColor
- font-size fontSize
- font-weight 400
-
-body[data-modal="open"]
- #content *
- overflow hidden !important
-
-button, input, select, textarea
- font-family DEFAULT_FONTS
-
-div, span, a, button, input, textarea
- box-sizing border-box
-
-a
- color brandColor
- &:hover
- color lighten(brandColor, 5%)
- &:visited
- color brandColor
-
-hr
- border-top none
- border-bottom solid 1px borderColor
- margin 15px 0
-
-button
- font-weight 400
- cursor pointer
- &:focus, &.focus
- outline none
-
-.noSelect
- noSelect()
-
-.text-center
- text-align center
-
-.form-group
- margin-bottom 15px
- &>label
- display block
- margin-bottom 5px
-
-.block-input, .inline-input
- border solid 1px borderColor
- padding 0 10px
- font-size 1em
- height 33px
- border-radius 5px
- box-sizing border-box
- &:focus, &.focus
- border solid 1px brandBorderColor
- outline none
- &.circleInput
- border-radius 16.5px
-
-.block-input
- display block
- width 100%
-
-.inline-input
- display inline-block
- margin-right 5px
-
-.relative
- position relative
-
-textarea.block-input
- resize vertical
- height 125px
- border-radius 5px
- padding 5px 10px
-
-#content
- fullsize()
-
-modalZIndex= 1000
-modalBackColor = transparentify(black, 65%)
-
-.ModalBase
- fixed top left bottom right
- z-index modalZIndex
- &.hide
- display none
- .modalBack
- absolute top left bottom right
- background-color modalBackColor
- z-index modalZIndex + 1
- .modal
- position relative
- width 650px
- margin 50px auto 0
- z-index modalZIndex + 2
- background-color white
- padding 15px
- color #666666
- border-radius 5px
-
diff --git a/docs/build.md b/docs/build.md
index 10b681c6..08fd9ac5 100644
--- a/docs/build.md
+++ b/docs/build.md
@@ -1,11 +1,11 @@
# Build
-This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md).
+This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## Environments
* npm: 4.x
* node: 7.x
-You should use `npm v4.x` because `$ grand pre-build` fails on `v5.x`.
+You should use `npm v4.x` because `$ grunt pre-build` fails on `v5.x`.
## Development
@@ -53,3 +53,32 @@ grunt pre-build
You will find the executable in the `dist` directory. Note, the auto updater won't work because the app isn't signed.
If you find it necessary, you can use codesign or authenticode with this executable.
+
+## Make own distribution packages (deb, rpm)
+
+Distribution packages are created by exec `grunt build` on Linux platform (e.g. Ubuntu, Fedora).
+
+> Note: You can create both `.deb` and `.rpm` in a single environment.
+
+After installing the supported version of `node` and `npm`, install build dependency packages.
+
+
+Ubuntu/Debian:
+
+```
+$ sudo apt-get install -y rpm fakeroot
+```
+
+Fedora:
+
+```
+$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
+```
+
+Then execute `grunt build`.
+
+```
+$ grunt build
+```
+
+You will find `.deb` and `.rpm` in the `dist` directory.
diff --git a/docs/de/build.md b/docs/de/build.md
new file mode 100644
index 00000000..44b744ca
--- /dev/null
+++ b/docs/de/build.md
@@ -0,0 +1,87 @@
+# Build
+Diese Seite ist auch verfügbar in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
+
+## Umgebungen
+* npm: 4.x
+* node: 7.x
+
+Du solltest `npm v4.x` benutzen weil `$ grunt pre-build` scheitert mit Version `v5.x`.
+
+## Entwicklung
+
+Wir verwenden Webpack HMR für die Entwicklung von Boostnote.
+Durch Ausführen der folgenden Befehle, im root Verzeichnis des Projektes, wird Boostnote mit der Default Konfiguration gestartet.
+
+Installiere die nötigen Pakete unter Verwendung von yarn.
+
+```
+$ yarn
+```
+
+Bauen und Ausführen.
+
+```
+$ yarn run dev-start
+```
+
+Dieser Befehl startet `yarn run webpack` und `yarn run hot` parallel. Es hat den selben Effekt wie beide Befehle separat in zwei Terminals zu starten.
+
+Das `webpack` überprüft den Code auf Änderungen und wendet diese dann automatisch an.
+
+Wenn folgender Fehler passiert: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, bitte Boostnote neu starten.
+
+
+
+> ### Notiz
+> Es gibt einige Fälle bei denen die App manuell zu refreshen ist.
+> 1. Wenn eine "constructor method" einer Komponente manuell editiert wird.
+> 2. Wenn eine neue CSS Klasse ergänzt wird (ähnlich wie 1: die CSS Klasse wird von jeder Komponenete neu geschrieben. Dieser Prozess passiert in der "Constructor method".)
+
+## Deploy
+
+Wir verwenden Grunt um das Deployment zu automatisieren.
+Du kannst das Programm unter Verwendung von `grunt` bauen. Jedoch empfehlen wir das nicht denn der default task beinhaltet codesign und authenticode.
+
+Deshalb haben wir ein separates Script vorbereitet welches eine ausführbare Datei erstellt.
+
+Dieser build funktioniert nicht mit npm v5.3.0. Deshalb musst du für den Build die Version v5.2.0 verwenden.
+
+```
+grunt pre-build
+```
+Du findest die ausführbare Datein in dem Verzeichnis `dist`. Beachte, der auto updater funktioniert nicht da die app nicht signiert ist.
+
+Wenn du es für notwendig erachtest, kannst du codesign or authenticode mit dieser ausführbaren Datei verwenden.
+
+## Erstelle eigene Distributions Pakete (deb, rpm)
+
+Distributions Pakete können mittels `grunt build` auf Linux Plattformen (e.g. Ubuntu, Fedora) erstellt werden.
+
+> Beachte: Du kannst bei `.deb` and `.rpm` in der selben Umgebung erstellen.
+
+Nach der Installation der supporteten Version von `node` and `npm`, installiere auch build dependency packages.
+
+
+Ubuntu/Debian:
+
+```
+$ sudo apt-get install -y rpm fakeroot
+```
+
+Fedora:
+
+```
+$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
+```
+
+Dann führe `grunt build` aus.
+
+```
+$ grunt build
+```
+
+Du findest nun die `.deb` undd `.rpm` Pakete in dem `dist` Ordner.
+
+---
+
+Special thanks: Translated by [gino909](https://github.com/gino909)
diff --git a/docs/de/debug.md b/docs/de/debug.md
new file mode 100644
index 00000000..ee1a734c
--- /dev/null
+++ b/docs/de/debug.md
@@ -0,0 +1,25 @@
+# How to debug Boostnote (Electron app)
+Diese Seite ist auch verfügbar in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md).
+
+Boostnote is eine Electron app, somit basiert sie auf Chromium; Entwickler können die `Developer Tools` verwenden, wie Google Chrome.
+
+Du kannst die `Developer Tools` so einschalten:
+
+
+Die `Developer Tools` schauen dann ungefähr so aus:
+
+
+Wenn Fehler vorkommen, werden die Fehlermeldungen in der `console` ausgegeben.
+
+## Debugging
+Zum Beispiel kannst du mit dem `debugger` Haltepunkte im Code setzen wie hier veranschaulicht:
+
+
+Das ist ledigtlich ein Beispiel, du kannst die Art von Debugging verwenden die für dich am besten ist.
+
+## Referenz
+* [Official document of Google Chrome about debugging](https://developer.chrome.com/devtools)
+
+---
+
+Special thanks: Translated by [gino909](https://github.com/gino909)
diff --git a/docs/debug.md b/docs/debug.md
index 297782dc..30c217a4 100644
--- a/docs/debug.md
+++ b/docs/debug.md
@@ -1,5 +1,5 @@
# How to debug Boostnote (Electron app)
-This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
+This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md).
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.
diff --git a/docs/fr/build.md b/docs/fr/build.md
new file mode 100644
index 00000000..0d718742
--- /dev/null
+++ b/docs/fr/build.md
@@ -0,0 +1,83 @@
+# Build
+Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md).
+
+## Environnements
+* npm: 4.x
+* node: 7.x
+
+Il est conseillé d'utiliser `npm v4.x` car `$ grunt pre-build` ne marche pas sur la `v5.x`.
+
+## Développement
+
+Webpack HMR est utilisé pour développer Boostnote.
+En utilisant les commandes suivantes à la racine du projet, cela va démarrer Boostnote avec les configurations par défaut.
+
+Installez les paquets requis à l'aide de `yarn`.
+
+```
+$ yarn
+```
+Build et start
+
+```
+$ yarn run dev-start
+```
+
+Cette commande lance `yarn run webpack` et `yarn run hot` en parallèle. Cela revient au même que si on utilisait ces deux commandes dans 2 terminaux.
+
+La commande `webpack` va surveiller les changements de code et les appliquer automatiquement.
+
+Si l'erreur suivante apparait : `Failed to load resource: net::ERR_CONNECTION_REFUSED`, relancez Boostnote.
+
+
+
+> ### Notice
+> Il y a certains cas où vous voudrez relancer l'application manuellement.
+> 1. Quand vous éditez la méthode constructeur dans un composant
+> 2. Quand vous ajoutez une nouvelle classe css. (Comme pour 1: la classe est réécrite pour chaque composant. Le process intervient dans la méthode constructeur)
+
+## Déploiement
+
+On utilise Grunt pour le déploiement automatique.
+Vous pouvez build le programme en utilisant `grunt`. Cependant, nous ne recommandons pas cette méthode car la task par défaut inclut codesign et authenticode.
+
+Nous avons donc préparé un script séparé qui va rendre un fichier exécutable.
+
+Le build ne fonctionne pas sur `npm v5.3.0`. Il faut donc utiliser `npm v5.2.0` quand vous faites le build.
+
+```
+grunt pre-build
+```
+Vous trouverez l'exécutable dans le dossier `dist`.
+Note : l'auto updater ne marchera pas car l'application n'est pas signée.
+
+Si vous trouvez ça nécessaire, vous pouvez utiliser codesign ou authenticode avec cet exécutable.
+
+## Faire un paquet (deb, rpm)
+
+Les paquets sont créés en exécutant `grunt build` sur une plateforme Linux (e.g. Ubuntu, Fedora).
+
+> Note: Vous pouvez créer à la fois un `.deb` et un `.rpm` dans un seul et même environnement.
+
+Après avoir installé la version supportée de `node` et de `npm`, installer les paquets de builds.
+
+
+Ubuntu/Debian:
+
+```
+$ sudo apt-get install -y rpm fakeroot
+```
+
+Fedora:
+
+```
+$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
+```
+
+Puis exécutez `grunt build`.
+
+```
+$ grunt build
+```
+
+Vous trouverez le `.deb` et le `.rpm` dans le dossier `dist`.
diff --git a/docs/fr/debug.md b/docs/fr/debug.md
new file mode 100644
index 00000000..9395e4f9
--- /dev/null
+++ b/docs/fr/debug.md
@@ -0,0 +1,22 @@
+# Comment débugger Boostnote (Application Electron)
+Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
+
+Boostnote est une application Electron donc basée sur Chromium. Il est possible d'utiliser les `Developer Tools` comme dans Google Chrome.
+
+Vous pouvez utiliser les `Developer Tools` de la façon suivante :
+
+
+Les `Developer Tools` ressemblent à ça :
+
+
+Quand une erreur arrive, les messages d'erreurs sont affichés dans la `console`.
+
+## Debugging
+Par exemple, vous pouvez utiliser le `debugger` pour placer un point d'arrêt dans le code de la façon suivante:
+
+
+
+C'est une façon comme une autre de faire, vous pouvez trouver une façon de débugger que vous trouverez plus adaptée.
+
+## Références
+* [Documentation officiel de Google Chrome sur le debugging](https://developer.chrome.com/devtools)
\ No newline at end of file
diff --git a/docs/jp/build.md b/docs/jp/build.md
index 0e7270f1..4d0fab33 100644
--- a/docs/jp/build.md
+++ b/docs/jp/build.md
@@ -46,3 +46,32 @@ grunt pre-build
実行ファイルは`dist`から見つかります。この場合、認証されていないため、自動アップデーターは使えません。
必要であれば、この実行ファイルからCodesignやAuthenticodeなどの署名ができます。
+
+## ディストリビューション用パッケージ (deb, rpm)
+
+ディストリビューション用パッケージはLinuxプラットフォーム(Ubuntu や Fedora)上で `grunt build` を実行する事で作成されます。
+
+> 一つの環境で `.deb` と `.rpm` の両方を作成する事が出来ます。
+
+
+対応するバージョンの `node` と `npm` をインストールした後、必要なパッケージをインストールします。
+
+Ubuntu/Debian:
+
+```
+$ sudo apt-get install -y rpm fakeroot
+```
+
+Fedora:
+
+```
+$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
+```
+
+`grunt build` を実行します。
+
+```
+$ grunt build
+```
+
+`.deb` と `.rpm` は `dist` 配下に作成されます。
diff --git a/docs/ko/build.md b/docs/ko/build.md
index 6bed0f0a..7bbe302f 100644
--- a/docs/ko/build.md
+++ b/docs/ko/build.md
@@ -1,43 +1,49 @@
# Build
+## 환경
+* npm: 4.x
+* node: 7.x
+
+`$ grunt pre-build`를 `npm v5.x`에서 실행할 수 없기 때문에, 반드시 `npm v4.x`를 사용하셔야 합니다.
+
## 개발
-Webpack HRM을 개발을 위해 사용합니다.
-다음 명령을 통해 저희가 해둔 설정을 사용 할 수 있습니다.
+개발에 있어서 Webpack HRM을 사용합니다.
+다음과 같은 명령을 프로젝트 디렉토리에서 실행하면, 기본 설정을 사용 할 수 있습니다.
+
+먼저, yarn을 이용해서 필요한 패키지들을 설치합니다.
```
-yarn run webpack
+$ yarn
```
-몇 초 후, 다음 메세지를 보게 될겁니다.
+그 다음, 아래의 명령으로 빌드를 끝내고 자동적으로 어플리케이션을 실행합니다.
```
-webpack: bundle is now VALID.
+$ yarn run dev-start
```
-그럼 앱을 실행합시다.
+이 명령은 `yarn run webpack` 과 `yarn run hot`을 동시에 실행합니다. 이는 두개의 터미널에서 각각의 명령을 동시에 실행하는 것과 같습니다.
-```
-yarn run hot
-```
+`Webpack`은 코드의 변화를 자동으로 탐지하여 적용시키는 역할을 합니다.
-> 원래 앱은 `yarn start`로 실행가능합니다. 하지만 이 경우, 컴파일된 스크립트를 사용할 것입니다.
+만약, `Failed to load resource: net::ERR_CONNECTION_REFUSED`과 같은 에러가 나타난다면 Boostnote를 리로드해주세요.
-이로써 웹팩이 자동적으로 코드변경을 확인하고 적용해줄 것입니다.
+
> ### 주의
> 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다.
-> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우샐
+> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우
> 2. 새로운 CSS코드를 추가할 경우(1.과 같은 이유: CSS클래스는 콤포넌트마다 다시 만들어 지는데, 이 작업은 컨스트럭터에서 일어납니다.)
## 배포
-그런트를 사용합니다.
-실제 디플로이는 `grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
+Boostnote에서는 배포 자동화를 위하여 그런트를 사용합니다.
+실제 배포는 `grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
-This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
+이 빌드는 npm v5.3.0에서는 작동하지 않습니다. 그러므로, 성공적으로 빌드하기 위해서는 v5.2.0을 사용해야 합니다.
```
grunt pre-build
diff --git a/docs/ko/debug.md b/docs/ko/debug.md
new file mode 100644
index 00000000..290eee9c
--- /dev/null
+++ b/docs/ko/debug.md
@@ -0,0 +1,21 @@
+# Boostnote의 디버그 방법(Electron app)
+
+Boostnote는 Electron 애플리케이션이므로 Chromium위에서 작동합니다. 그렇기 때문에 개발자분들은 Google Chrome 브라우저에서 처럼 `Developer Tools`를 사용하실 수 있습니다.
+
+다음과 같이 `Developer Tools`를 실행할 수 있습니다:
+
+
+`Developer Tools`는 다음과 같이 나타납니다:
+
+
+에러가 발생할 때에는, 에러메시지가 `console`위에 표시 됩니다.
+
+## 디버깅
+예를들면 `debugger`를 사용하여 코드 안에서 다음과 같이 일시 정지지점을 설정할 수 있습니다:
+
+
+
+이는 단순한 하나의 예시에 불과합니다. 자기자신에게 가장 잘 맞는 디버그 방법을 찾는 것도 좋을 것 입니다.
+
+## 참고
+* [디버그에 관한 Google Chrome의 공식 문서](https://developer.chrome.com/devtools)
diff --git a/docs/ru/build.md b/docs/ru/build.md
index fde7ec99..d106e482 100644
--- a/docs/ru/build.md
+++ b/docs/ru/build.md
@@ -4,7 +4,7 @@
* npm: 4.x
* node: 7.x
-Вы должны использовать `npm v4.x`, так как `$ grand pre-build` не работает в `v5.x`.
+Вы должны использовать `npm v4.x`, так как `$ grunt pre-build` не работает в `v5.x`.
## Разработка
diff --git a/docs/zh_CN/build.md b/docs/zh_CN/build.md
index 5e3bcc5e..9183ebb3 100644
--- a/docs/zh_CN/build.md
+++ b/docs/zh_CN/build.md
@@ -4,7 +4,7 @@
* npm: 4.x
* node: 7.x
-因为`$ grand pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x`。
+因为`$ grunt pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x`。
## 开发
diff --git a/gruntfile.js b/gruntfile.js
index 1d6bc3ce..5683adda 100644
--- a/gruntfile.js
+++ b/gruntfile.js
@@ -50,6 +50,25 @@ module.exports = function (grunt) {
src: path.join(__dirname, 'dist', 'Boostnote-linux-x64'),
dest: path.join(__dirname, 'dist')
}
+ },
+ 'electron-installer-redhat': {
+ app: {
+ options: {
+ name: 'boostnote',
+ productName: 'Boostnote',
+ genericName: 'Boostnote',
+ productDescription: 'The opensource note app for developer.',
+ arch: 'x86_64',
+ categories: [
+ 'Development',
+ 'Utility'
+ ],
+ icon: path.join(__dirname, 'resources/app.png'),
+ bin: 'Boostnote'
+ },
+ src: path.join(__dirname, 'dist', 'Boostnote-linux-x64'),
+ dest: path.join(__dirname, 'dist')
+ }
}
}
@@ -57,6 +76,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-electron-installer')
if (!WIN) {
grunt.loadNpmTasks('grunt-electron-installer-debian')
+ grunt.loadNpmTasks('grunt-electron-installer-redhat')
}
grunt.registerTask('compile', function () {
@@ -244,7 +264,7 @@ module.exports = function (grunt) {
grunt.task.run(['compile', 'pack:osx', 'codesign', 'create-osx-installer', 'zip:osx'])
break
case 'linux':
- grunt.task.run(['compile', 'pack:linux', 'electron-installer-debian'])
+ grunt.task.run(['compile', 'pack:linux', 'electron-installer-debian', 'electron-installer-redhat'])
break
}
})
diff --git a/lib/main-menu.js b/lib/main-menu.js
index 6ec9a6af..3555c381 100644
--- a/lib/main-menu.js
+++ b/lib/main-menu.js
@@ -18,6 +18,16 @@ const boost = macOS
{
type: 'separator'
},
+ {
+ label: 'Preferences',
+ accelerator: 'Command+,',
+ click () {
+ mainWindow.webContents.send('side:preferences')
+ }
+ },
+ {
+ type: 'separator'
+ },
{
label: 'Hide Boostnote',
accelerator: 'Command+H',
@@ -37,7 +47,8 @@ const boost = macOS
},
{
label: 'Quit Boostnote',
- role: 'quit'
+ role: 'quit',
+ accelerator: 'CommandOrControl+Q'
}
]
}
@@ -45,7 +56,18 @@ const boost = macOS
label: 'Boostnote',
submenu: [
{
- role: 'quit'
+ label: 'Preferences',
+ accelerator: 'Control+,',
+ click () {
+ mainWindow.webContents.send('side:preferences')
+ }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ role: 'quit',
+ accelerator: 'Control+Q'
}
]
}
@@ -131,7 +153,16 @@ if (LINUX) {
file.submenu.push({
type: 'separator'
}, {
- role: 'quit'
+ label: 'Preferences',
+ accelerator: 'Control+,',
+ click () {
+ mainWindow.webContents.send('side:preferences')
+ }
+ }, {
+ type: 'separator'
+ }, {
+ role: 'quit',
+ accelerator: 'Control+Q'
})
}
diff --git a/lib/main-window.js b/lib/main-window.js
index 5b53448d..5c0090fc 100644
--- a/lib/main-window.js
+++ b/lib/main-window.js
@@ -43,7 +43,7 @@ if (process.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon')
mainWindow.on('close', function (e) {
e.preventDefault()
if (process.platform === 'win32') {
- mainWindow.minimize()
+ quitApp()
} else {
if (mainWindow.isFullScreen()) {
mainWindow.once('leave-full-screen', function () {
@@ -57,20 +57,33 @@ if (process.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon')
})
app.on('before-quit', function (e) {
- try {
- config.set('windowsize', mainWindow.getBounds())
- } catch (e) {
- // ignore any errors because an error occurs only on update
- // refs: https://github.com/BoostIO/Boostnote/issues/243
- }
+ storeWindowSize()
mainWindow.removeAllListeners()
})
} else {
+ mainWindow.on('close', function () {
+ storeWindowSize()
+ })
+
app.on('window-all-closed', function () {
app.quit()
})
}
+function quitApp () {
+ storeWindowSize()
+ app.quit()
+}
+
+function storeWindowSize () {
+ try {
+ config.set('windowsize', mainWindow.getBounds())
+ } catch (e) {
+ // ignore any errors because an error occurs only on update
+ // refs: https://github.com/BoostIO/Boostnote/issues/243
+ }
+}
+
app.on('activate', function () {
if (mainWindow == null) return null
mainWindow.show()
diff --git a/lib/main.html b/lib/main.html
index 4c10fcac..69a47900 100644
--- a/lib/main.html
+++ b/lib/main.html
@@ -53,6 +53,10 @@
font-weight: 100;
color: #888;
}
+ .CodeEditor {
+ opacity: 1 !important;
+ pointer-events: auto !important;
+ }
@@ -67,6 +71,7 @@
+
@@ -77,6 +82,7 @@
+
diff --git a/package.json b/package.json
index e5e1afc7..0b16a7ab 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "boost",
"productName": "Boostnote",
- "version": "0.8.14",
+ "version": "0.8.19",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -16,7 +16,7 @@
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
},
"config": {
- "electron-version": "1.2.8"
+ "electron-version": "1.6.15"
},
"repository": {
"type": "git",
@@ -61,24 +61,29 @@
"js-sequence-diagrams": "^1000000.0.6",
"katex": "^0.7.1",
"lodash": "^4.11.1",
+ "lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0",
"markdown-it-imsize": "^2.0.1",
+ "markdown-it-kbd": "^1.1.1",
"markdown-it-multimd-table": "^2.0.1",
"markdown-it-named-headers": "^0.0.4",
+ "markdown-it-plantuml": "^0.3.0",
"md5": "^2.0.0",
- "mixpanel": "^0.4.1",
+ "mdurl": "^1.0.1",
"moment": "^2.10.3",
"node-ipc": "^8.1.0",
"raphael": "^2.2.7",
- "react": "^15.0.2",
+ "react": "^15.5.4",
"react-codemirror": "^0.3.0",
"react-dom": "^15.0.2",
"react-redux": "^4.4.5",
+ "react-sortable-hoc": "^0.6.7",
"redux": "^3.5.2",
"sander": "^0.5.1",
+ "striptags": "^2.2.1",
"superagent": "^1.2.0",
"superagent-promise": "^1.0.3"
},
@@ -97,12 +102,13 @@
"css-loader": "^0.19.0",
"devtron": "^1.1.0",
"dom-storage": "^2.0.2",
+ "electron": "^1.6.15",
"electron-packager": "^6.0.0",
- "electron-prebuilt": "^1.2.8",
"eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1",
"eslint-config-standard-jsx": "^3.2.0",
"eslint-plugin-react": "^7.2.0",
+ "eslint-plugin-standard": "^3.0.1",
"faker": "^3.1.0",
"grunt": "^0.4.5",
"grunt-electron-installer": "^1.2.0",
@@ -124,7 +130,8 @@
"webpack-dev-server": "^1.12.0"
},
"optionalDependencies": {
- "grunt-electron-installer-debian": "^0.2.0"
+ "grunt-electron-installer-debian": "^0.2.0",
+ "grunt-electron-installer-redhat": "^0.3.1"
},
"optional": false,
"ava": {
diff --git a/readme.md b/readme.md
index 97fd4ec4..9d64bf5d 100644
--- a/readme.md
+++ b/readme.md
@@ -1,12 +1,12 @@
New:zap:
-[Android and iOS apps](https://github.com/BoostIO/Boostnote-mobile) are released!
+Open sourcing our [Android and iOS apps](https://github.com/BoostIO/Boostnote-mobile)!

Note-taking app for programmers.
-
Apps available for Mac, Windows, Linux, Android and iOS!
-
Built with Electron, React + Redux, Webpack and CSSModules
+
Apps available for Mac, Windows, Linux, Android and iOS.
+
Built with Electron, React + Redux, Webpack and CSSModules.
[](https://travis-ci.org/BoostIO/Boostnote)
@@ -14,23 +14,32 @@ New:zap:
- [Rokt33r](https://github.com/rokt33r)
- [sota1235](https://github.com/sota1235)
- [Kohei TAKATA](https://github.com/kohei-takata)
-- [asmsuechan](https://github.com/asmsuechan)
-- [Kazu Yokomizo](https://github.com/kazup01)
+- [Sosuke](https://github.com/sosukesuzuki)
+- [Kazz](https://github.com/kazup01)
## Contributors
-[Great contributors](https://github.com/BoostIO/Boostnote/graphs/contributors) :tada:
+Thank you to all the people who already contributed to Boostnote!
-## Slack Group
-Let's talk about Boostnote's great features, new feature requests and things like Japanese gourmet. 🍣
-[Join us](https://join.slack.com/t/boostnote-group/shared_invite/MjMxMDA0MjYxNzkzLTE1MDM2MjIyMjctZmNlNTMyZGJhZA)
+

-## More Information
+## Supporting Boostnote
+Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider:
+- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
+
+## Community
+- [Facebook Group](https://www.facebook.com/groups/boostnote/)
+- [Twitter](https://twitter.com/boostnoteapp)
+- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjc2MDM0MDEyODk2LThlZDlhYmYwMjdkMmJjMGM5MGFiMGJmNzk5ZTdhNzFhMmNmMDFlY2M2YTE1MTZkOThiOGZmNTI3YzJiOTBhMTQ)
+- [Blog](https://medium.com/boostnote)
+- [Reddit](https://www.reddit.com/r/Boostnote/)
+
+
+#### More Information
* [Website](https://boostnote.io)
-* [Boostnote Team](https://boostnote.io/team/) : Boostnote for the creative hacker teams. Share your markdown notes and snippets instantly with your team. **We will release it at August!** 🏃💨
-* [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
-* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md) : Development configurations for Boostnote 🚀
+* [Subscribe to the Newsletter](https://boostnote.io/#community): Get updates on Boostnote progress. No spam, ever :)
+* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md): Development configurations for Boostnote.
* Copyright (C) 2017 Maisin&Co.
-## License
+#### License
[GPL v3](./LICENSE).
diff --git a/resources/fonts/Lato-Black.ttf b/resources/fonts/Lato-Black.ttf
new file mode 100644
index 00000000..3f7819f6
Binary files /dev/null and b/resources/fonts/Lato-Black.ttf differ
diff --git a/resources/fonts/Lato-Black.woff b/resources/fonts/Lato-Black.woff
new file mode 100644
index 00000000..a0ab25e9
Binary files /dev/null and b/resources/fonts/Lato-Black.woff differ
diff --git a/resources/fonts/Lato-Black.woff2 b/resources/fonts/Lato-Black.woff2
new file mode 100644
index 00000000..3ee7cd44
Binary files /dev/null and b/resources/fonts/Lato-Black.woff2 differ
diff --git a/resources/icon/icon-all-active.svg b/resources/icon/icon-all-active.svg
new file mode 100644
index 00000000..3e3ade1c
--- /dev/null
+++ b/resources/icon/icon-all-active.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-all.svg b/resources/icon/icon-all.svg
new file mode 100644
index 00000000..1db75a98
--- /dev/null
+++ b/resources/icon/icon-all.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-code-off.svg b/resources/icon/icon-code-off.svg
new file mode 100644
index 00000000..62a10b3a
--- /dev/null
+++ b/resources/icon/icon-code-off.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-code-on.svg b/resources/icon/icon-code-on.svg
new file mode 100644
index 00000000..729b41bf
--- /dev/null
+++ b/resources/icon/icon-code-on.svg
@@ -0,0 +1,28 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-column-list.svg b/resources/icon/icon-column-list.svg
new file mode 100644
index 00000000..e8f04dad
--- /dev/null
+++ b/resources/icon/icon-column-list.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-column.svg b/resources/icon/icon-column.svg
new file mode 100644
index 00000000..fa5f46a7
--- /dev/null
+++ b/resources/icon/icon-column.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-down.svg b/resources/icon/icon-down.svg
new file mode 100644
index 00000000..2914499c
--- /dev/null
+++ b/resources/icon/icon-down.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-edit-lock.svg b/resources/icon/icon-edit-lock.svg
new file mode 100644
index 00000000..12ede4cc
--- /dev/null
+++ b/resources/icon/icon-edit-lock.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-edit.svg b/resources/icon/icon-edit.svg
new file mode 100644
index 00000000..cb7d92cc
--- /dev/null
+++ b/resources/icon/icon-edit.svg
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-full.svg b/resources/icon/icon-full.svg
new file mode 100644
index 00000000..621ebacc
--- /dev/null
+++ b/resources/icon/icon-full.svg
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-info.svg b/resources/icon/icon-info.svg
new file mode 100644
index 00000000..253b8cab
--- /dev/null
+++ b/resources/icon/icon-info.svg
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-list-active.svg b/resources/icon/icon-list-active.svg
new file mode 100644
index 00000000..5da16c7c
--- /dev/null
+++ b/resources/icon/icon-list-active.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-list.svg b/resources/icon/icon-list.svg
new file mode 100644
index 00000000..41ca8a4d
--- /dev/null
+++ b/resources/icon/icon-list.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-lock.svg b/resources/icon/icon-lock.svg
new file mode 100644
index 00000000..e4ff775f
--- /dev/null
+++ b/resources/icon/icon-lock.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-mode-markdown-off-active.svg b/resources/icon/icon-mode-markdown-off-active.svg
new file mode 100644
index 00000000..0159836b
--- /dev/null
+++ b/resources/icon/icon-mode-markdown-off-active.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-mode-markdown-off.svg b/resources/icon/icon-mode-markdown-off.svg
new file mode 100644
index 00000000..7f6a0235
--- /dev/null
+++ b/resources/icon/icon-mode-markdown-off.svg
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-mode-split-on-active.svg b/resources/icon/icon-mode-split-on-active.svg
new file mode 100644
index 00000000..338d2bd7
--- /dev/null
+++ b/resources/icon/icon-mode-split-on-active.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-mode-split-on.svg b/resources/icon/icon-mode-split-on.svg
new file mode 100644
index 00000000..c212d7f2
--- /dev/null
+++ b/resources/icon/icon-mode-split-on.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-newnote.svg b/resources/icon/icon-newnote.svg
new file mode 100644
index 00000000..2daac352
--- /dev/null
+++ b/resources/icon/icon-newnote.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-note-code.svg b/resources/icon/icon-note-code.svg
new file mode 100644
index 00000000..4dd832e7
--- /dev/null
+++ b/resources/icon/icon-note-code.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-note-text.svg b/resources/icon/icon-note-text.svg
new file mode 100644
index 00000000..3fb972b1
--- /dev/null
+++ b/resources/icon/icon-note-text.svg
@@ -0,0 +1,21 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-plus.svg b/resources/icon/icon-plus.svg
new file mode 100644
index 00000000..062fac29
--- /dev/null
+++ b/resources/icon/icon-plus.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-previewoff-off.svg b/resources/icon/icon-previewoff-off.svg
new file mode 100644
index 00000000..b0e720e7
--- /dev/null
+++ b/resources/icon/icon-previewoff-off.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-previewoff-on.svg b/resources/icon/icon-previewoff-on.svg
new file mode 100644
index 00000000..8a6c5d7e
--- /dev/null
+++ b/resources/icon/icon-previewoff-on.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-right.svg b/resources/icon/icon-right.svg
new file mode 100644
index 00000000..448ff6b4
--- /dev/null
+++ b/resources/icon/icon-right.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-setting.svg b/resources/icon/icon-setting.svg
new file mode 100644
index 00000000..75a842e5
--- /dev/null
+++ b/resources/icon/icon-setting.svg
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-sidebar.svg b/resources/icon/icon-sidebar.svg
new file mode 100644
index 00000000..da4a0926
--- /dev/null
+++ b/resources/icon/icon-sidebar.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-star-active.svg b/resources/icon/icon-star-active.svg
new file mode 100644
index 00000000..c87b883d
--- /dev/null
+++ b/resources/icon/icon-star-active.svg
@@ -0,0 +1,22 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-star-sidenav.svg b/resources/icon/icon-star-sidenav.svg
new file mode 100644
index 00000000..932f4d66
--- /dev/null
+++ b/resources/icon/icon-star-sidenav.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-star.svg b/resources/icon/icon-star.svg
new file mode 100644
index 00000000..da4abb3d
--- /dev/null
+++ b/resources/icon/icon-star.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-starred.svg b/resources/icon/icon-starred.svg
new file mode 100644
index 00000000..68eb6f07
--- /dev/null
+++ b/resources/icon/icon-starred.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-tag-active.svg b/resources/icon/icon-tag-active.svg
new file mode 100644
index 00000000..887e7344
--- /dev/null
+++ b/resources/icon/icon-tag-active.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-tag.svg b/resources/icon/icon-tag.svg
new file mode 100644
index 00000000..ee23dcfc
--- /dev/null
+++ b/resources/icon/icon-tag.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-trash-active.svg b/resources/icon/icon-trash-active.svg
new file mode 100644
index 00000000..593098fc
--- /dev/null
+++ b/resources/icon/icon-trash-active.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-trash-sidenav.svg b/resources/icon/icon-trash-sidenav.svg
new file mode 100644
index 00000000..ba87033b
--- /dev/null
+++ b/resources/icon/icon-trash-sidenav.svg
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-trash.svg b/resources/icon/icon-trash.svg
new file mode 100644
index 00000000..64dedb87
--- /dev/null
+++ b/resources/icon/icon-trash.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-unlock.svg b/resources/icon/icon-unlock.svg
new file mode 100644
index 00000000..0e20453f
--- /dev/null
+++ b/resources/icon/icon-unlock.svg
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-x.svg b/resources/icon/icon-x.svg
new file mode 100644
index 00000000..6cfecc48
--- /dev/null
+++ b/resources/icon/icon-x.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/icon/icon-zoom.svg b/resources/icon/icon-zoom.svg
new file mode 100644
index 00000000..f45e7da0
--- /dev/null
+++ b/resources/icon/icon-zoom.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/resources/repository/top.png b/resources/repository/top.png
index 584aa1d6..ac8dc699 100644
Binary files a/resources/repository/top.png and b/resources/repository/top.png differ
diff --git a/snap/gui/boostnote.desktop b/snap/gui/boostnote.desktop
new file mode 100755
index 00000000..0d97116a
--- /dev/null
+++ b/snap/gui/boostnote.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Boostnote
+Comment=A note-taking app for programmers
+Exec=$SNAP/etc/boostnote/Boostnote
+Icon=resources/app.png
+MimeType=image/x-foo;
+NotShowIn=KDE;
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
new file mode 100644
index 00000000..b7c3157d
--- /dev/null
+++ b/snap/snapcraft.yaml
@@ -0,0 +1,48 @@
+name: boostnote
+version: '0.1'
+summary: A note-taking app for programmers
+description: |
+ Boostnote is an open source note-taking app made for programmers just like you. https://boostnote.io
+ https://github.com/BoostIO/Boostnote
+
+grade: stable
+confinement: strict
+
+apps:
+ asmstnote:
+ command: desktop-launch $SNAP/etc/boostnote/Boostnote
+ plugs:
+ - browser-support
+ - network
+ - unity7
+ - gsettings
+
+parts:
+ src:
+ plugin: nodejs
+ source: .
+
+ deps:
+ plugin: nil
+ stage-packages:
+ - libgconf-2-4
+ - libnss3
+ - libxss1
+ - fontconfig-config
+
+ desktop-integration:
+ plugin: nil
+ stage-packages:
+ - libappindicator1
+ - libdbusmenu-glib4
+ - libnotify4
+ - libunity9
+
+ launcher:
+ plugin: dump
+ source: .
+ stage:
+ - etc/boostnote
+ organize:
+ dist/Boostnote-linux-x64: etc/boostnote
+ after: [desktop-glib-only]
diff --git a/tests/dataApi/addStorage.js b/tests/dataApi/addStorage.js
index d5bc2994..da39a993 100644
--- a/tests/dataApi/addStorage.js
+++ b/tests/dataApi/addStorage.js
@@ -36,7 +36,7 @@ test.serial('Add Storage', (t) => {
return addStorage(input)
})
.then(function validateResult (data) {
- let { storage, notes } = data
+ const { storage, notes } = data
// Check data.storage
t.true(_.isString(storage.key))
@@ -53,13 +53,13 @@ test.serial('Add Storage', (t) => {
})
// Check localStorage
- let cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key})
+ const cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key})
t.is(cacheData.name, input.name)
t.is(cacheData.type, input.type)
t.is(cacheData.path, input.path)
// Check boostnote.json
- let jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json'))
+ const jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json'))
t.true(_.isArray(jsonData.folders))
t.is(jsonData.version, '1.0')
t.is(jsonData.folders.length, t.context.v1StorageData.json.folders.length)
diff --git a/tests/dataApi/createFolder-test.js b/tests/dataApi/createFolder-test.js
index 7d9a65a7..1b9a1c83 100644
--- a/tests/dataApi/createFolder-test.js
+++ b/tests/dataApi/createFolder-test.js
@@ -33,7 +33,7 @@ test.serial('Create a folder', (t) => {
})
.then(function assert (data) {
t.true(_.find(data.storage.folders, input) != null)
- let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, input) != null)
})
diff --git a/tests/dataApi/createNote-test.js b/tests/dataApi/createNote-test.js
index 5c31574e..47446aab 100644
--- a/tests/dataApi/createNote-test.js
+++ b/tests/dataApi/createNote-test.js
@@ -54,11 +54,11 @@ test.serial('Create a note', (t) => {
])
})
.then(function assert (data) {
- let data1 = data[0]
- let data2 = data[1]
+ const data1 = data[0]
+ const data2 = data[1]
t.is(storageKey, data1.storage)
- let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+ const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(input1.title, data1.title)
t.is(input1.title, jsonData1.title)
t.is(input1.description, data1.description)
@@ -73,7 +73,7 @@ test.serial('Create a note', (t) => {
t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
t.is(storageKey, data2.storage)
- let jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
+ const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
t.is(input2.title, data2.title)
t.is(input2.title, jsonData2.title)
t.is(input2.content, data2.content)
diff --git a/tests/dataApi/deleteFolder-test.js b/tests/dataApi/deleteFolder-test.js
index 4adf38e1..1d9c7646 100644
--- a/tests/dataApi/deleteFolder-test.js
+++ b/tests/dataApi/deleteFolder-test.js
@@ -31,10 +31,10 @@ test.serial('Delete a folder', (t) => {
})
.then(function assert (data) {
t.true(_.find(data.storage.folders, {key: folderKey}) == null)
- let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, {key: folderKey}) == null)
- let notePaths = sander.readdirSync(data.storage.path, 'notes')
+ const notePaths = sander.readdirSync(data.storage.path, 'notes')
t.is(notePaths.length, t.context.storage.notes.filter((note) => note.folder !== folderKey).length)
})
})
diff --git a/tests/dataApi/migrateFromV6Storage-test.js b/tests/dataApi/migrateFromV6Storage-test.js
index 220289c6..7cdcdb71 100644
--- a/tests/dataApi/migrateFromV6Storage-test.js
+++ b/tests/dataApi/migrateFromV6Storage-test.js
@@ -17,7 +17,7 @@ const os = require('os')
const dummyStoragePath = path.join(os.tmpdir(), 'test/migrate-test-storage')
test.beforeEach((t) => {
- let dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath)
+ const dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath)
console.log('init count', dummyData.notes.length)
localStorage.setItem('storages', JSON.stringify([dummyData.cache]))
})
@@ -32,11 +32,11 @@ test.serial('Migrate legacy storage into v1 storage', (t) => {
t.true(data)
// Check all notes migrated.
- let dummyData = t.context.dummyData
- let noteDirPath = path.join(dummyStoragePath, 'notes')
- let fileList = sander.readdirSync(noteDirPath)
+ const dummyData = t.context.dummyData
+ const noteDirPath = path.join(dummyStoragePath, 'notes')
+ const fileList = sander.readdirSync(noteDirPath)
t.is(dummyData.notes.length, fileList.length)
- let noteMap = fileList
+ const noteMap = fileList
.map((filePath) => {
return CSON.readFileSync(path.join(noteDirPath, filePath))
})
diff --git a/tests/dataApi/moveNote-test.js b/tests/dataApi/moveNote-test.js
index 4c31ddca..3fe31c58 100644
--- a/tests/dataApi/moveNote-test.js
+++ b/tests/dataApi/moveNote-test.js
@@ -38,15 +38,15 @@ test.serial('Move a note', (t) => {
])
})
.then(function assert (data) {
- let data1 = data[0]
- let data2 = data[1]
+ const data1 = data[0]
+ const data2 = data[1]
- let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+ const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(jsonData1.folder, folderKey1)
t.is(jsonData1.title, note1.title)
- let jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson'))
+ const jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson'))
t.is(jsonData2.folder, folderKey2)
t.is(jsonData2.title, note2.title)
try {
diff --git a/tests/dataApi/renameStorage-test.js b/tests/dataApi/renameStorage-test.js
index b898d6f1..f5c64cb6 100644
--- a/tests/dataApi/renameStorage-test.js
+++ b/tests/dataApi/renameStorage-test.js
@@ -27,7 +27,7 @@ test.serial('Rename a storage', (t) => {
return renameStorage(storageKey, 'changed')
})
.then(function assert (data) {
- let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
+ const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
t.true(_.find(cachedStorageList, {key: storageKey}).name === 'changed')
})
})
diff --git a/tests/dataApi/reorderFolder-test.js b/tests/dataApi/reorderFolder-test.js
new file mode 100644
index 00000000..55bff0eb
--- /dev/null
+++ b/tests/dataApi/reorderFolder-test.js
@@ -0,0 +1,47 @@
+const test = require('ava')
+const reorderFolder = require('browser/main/lib/dataApi/reorderFolder')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('@rokt33r/season')
+
+const storagePath = path.join(os.tmpdir(), 'test/reorder-folder')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Reorder a folder', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const firstFolderKey = t.context.storage.json.folders[0].key
+ const secondFolderKey = t.context.storage.json.folders[1].key
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return reorderFolder(storageKey, 0, 1)
+ })
+ .then(function assert (data) {
+ t.true(_.nth(data.storage.folders, 0).key === secondFolderKey)
+ t.true(_.nth(data.storage.folders, 1).key === firstFolderKey)
+
+ const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+
+ t.true(_.nth(jsonData.folders, 0).key === secondFolderKey)
+ t.true(_.nth(jsonData.folders, 1).key === firstFolderKey)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/updateFolder-test.js b/tests/dataApi/updateFolder-test.js
index ad486344..ca9fcf99 100644
--- a/tests/dataApi/updateFolder-test.js
+++ b/tests/dataApi/updateFolder-test.js
@@ -34,7 +34,7 @@ test.serial('Update a folder', (t) => {
})
.then(function assert (data) {
t.true(_.find(data.storage.folders, input) != null)
- let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ const jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.find(jsonData.folders, input) != null)
})
diff --git a/tests/dataApi/updateNote-test.js b/tests/dataApi/updateNote-test.js
index 2c6aad9c..6043ee1e 100644
--- a/tests/dataApi/updateNote-test.js
+++ b/tests/dataApi/updateNote-test.js
@@ -74,8 +74,8 @@ test.serial('Update a note', (t) => {
createNote(storageKey, input2)
])
.then(function updateNotes (data) {
- let data1 = data[0]
- let data2 = data[1]
+ const data1 = data[0]
+ const data2 = data[1]
return Promise.all([
updateNote(data1.storage, data1.key, input3),
updateNote(data1.storage, data2.key, input4)
@@ -83,10 +83,10 @@ test.serial('Update a note', (t) => {
})
})
.then(function assert (data) {
- let data1 = data[0]
- let data2 = data[1]
+ const data1 = data[0]
+ const data2 = data[1]
- let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+ const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
t.is(input3.title, data1.title)
t.is(input3.title, jsonData1.title)
t.is(input3.description, data1.description)
@@ -100,7 +100,7 @@ test.serial('Update a note', (t) => {
t.is(input3.snippets[0].name, data1.snippets[0].name)
t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
- let jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
+ const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
t.is(input4.title, data2.title)
t.is(input4.title, jsonData2.title)
t.is(input4.content, data2.content)
diff --git a/tests/lib/get-todo-status-test.js b/tests/lib/get-todo-status-test.js
index 55f951f5..c97ae2b9 100644
--- a/tests/lib/get-todo-status-test.js
+++ b/tests/lib/get-todo-status-test.js
@@ -11,7 +11,12 @@ test('getTodoStatus should return a correct hash object', t => {
['- [ ] a\n', { total: 1, completed: 0 }],
['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n', { total: 1, completed: 0 }],
- ['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }]
+ ['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }],
+ ['+ [ ] a\n+ [testx] a\n', { total: 1, completed: 0 }],
+ ['+ [ ] a\n+ [xtest] a\n', { total: 1, completed: 0 }],
+ ['+ [ ] a\n+ foo[x]bar a\n', { total: 1, completed: 0 }],
+ ['+ [ ] a\n+ foo[x] bar a\n', { total: 1, completed: 0 }],
+ ['+ [ ] a\n+ foo [x]bar a\n', { total: 1, completed: 0 }]
]
testCases.forEach(testCase => {
diff --git a/tests/lib/markdown-text-helper-test.js b/tests/lib/markdown-text-helper-test.js
new file mode 100644
index 00000000..e4ad86bc
--- /dev/null
+++ b/tests/lib/markdown-text-helper-test.js
@@ -0,0 +1,46 @@
+/**
+ * @fileoverview Unit test for browser/lib/markdown
+ */
+const test = require('ava')
+const markdown = require('browser/lib/markdownTextHelper')
+
+test(t => {
+ // [input, expected]
+ const testCases = [
+ // List
+ [' - ', ' '],
+ [' + ', ' '],
+ [' * ', ' '],
+ [' * ', ' '],
+ [' 1. ', ' '],
+ [' 2. ', ' '],
+ [' 10. ', ' '],
+ ['\t- ', '\t'],
+ ['- ', ''],
+ // Header with using line
+ ['\n==', '\n'],
+ ['\n===', '\n'],
+ ['test\n===', 'test\n'],
+ // Code block
+ ['```test\n', ''],
+ ['```test\nhoge', 'hoge'],
+ // HTML tag
+ ['<>', ''],
+ ['
', 'test'],
+ ['hoge', 'hogetest'],
+ ['moge', 'testmoge'],
+ // Emphasis
+ ['~~', ''],
+ ['~~text~~', 'text'],
+ // Don't remove underscore
+ ['`MY_TITLE`', 'MY_TITLE'],
+ ['MY_TITLE', 'MY_TITLE'],
+ // I have no idea for it...
+ ['```test', '`test']
+ ]
+
+ testCases.forEach(testCase => {
+ const [input, expected] = testCase
+ t.is(markdown.strip(input), expected, `Test for strip() input: ${input} expected: ${expected}`)
+ })
+})
diff --git a/tests/lib/search-test.js b/tests/lib/search-test.js
index e99a3612..1550a08f 100644
--- a/tests/lib/search-test.js
+++ b/tests/lib/search-test.js
@@ -6,26 +6,30 @@ import _ from 'lodash'
const pickContents = (notes) => notes.map((note) => { return note.content })
let notes = []
-let note1, note2
+let note1, note2, note3
test.before(t => {
const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] }
const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] }
+ const data3 = { type: 'MARKDOWN_NOTE', content: '#content4', tags: ['tag1'] }
+
note1 = dummyNote(data1)
note2 = dummyNote(data2)
+ note3 = dummyNote(data3)
- notes = [note1, note2]
+ notes = [note1, note2, note3]
})
test('it can find notes by tags or words', t => {
// [input, expected content (Array)]
const testCases = [
- ['#tag1', [note1.content, note2.content]],
+ ['#tag1', [note1.content, note2.content, note3.content]],
['#tag1 #tag2', [note2.content]],
['#tag1 #tag2 #tag3', []],
['content1', [note1.content, note2.content]],
['content1 content2', [note2.content]],
- ['content1 content2 content3', []]
+ ['content1 content2 content3', []],
+ ['#content4', [note3.content]]
]
testCases.forEach((testCase) => {
diff --git a/webpack-skeleton.js b/webpack-skeleton.js
index 4767d1f9..87bbe744 100644
--- a/webpack-skeleton.js
+++ b/webpack-skeleton.js
@@ -39,8 +39,9 @@ var config = {
'fs-jetpack',
'@rokt33r/markdown-it-math',
'markdown-it-checkbox',
+ 'markdown-it-kbd',
+ 'markdown-it-plantuml',
'devtron',
- 'mixpanel',
'@rokt33r/season',
{
react: 'var React',
diff --git a/yarn.lock b/yarn.lock
index d4510193..4d105edc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14,6 +14,10 @@
fs-plus "2.x"
optimist "~0.4.0"
+"@types/node@^7.0.18":
+ version "7.0.46"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.46.tgz#c3dedd25558c676b3d6303e51799abb9c3f8f314"
+
abab@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
@@ -216,6 +220,19 @@ asar@^0.11.0:
mkdirp "^0.5.0"
mksnapshot "^0.3.0"
+asar@^0.12.0:
+ version "0.12.4"
+ resolved "https://registry.yarnpkg.com/asar/-/asar-0.12.4.tgz#2dd3f116882eab8c0f23b754792a82a7d9fce171"
+ dependencies:
+ chromium-pickle-js "^0.2.0"
+ commander "^2.9.0"
+ cuint "^0.2.1"
+ glob "^6.0.4"
+ minimatch "^3.0.3"
+ mkdirp "^0.5.0"
+ mksnapshot "^0.3.0"
+ tmp "0.0.28"
+
asar@^0.9.0:
version "0.9.1"
resolved "https://registry.yarnpkg.com/asar/-/asar-0.9.1.tgz#b2f2fe1b49c163013bdb229d6eba2d2078ff5cc4"
@@ -278,6 +295,12 @@ async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.1, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+async@^2.0.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
+ dependencies:
+ lodash "^4.14.0"
+
async@~0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/async/-/async-0.1.22.tgz#0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061"
@@ -1059,12 +1082,12 @@ babel-register@^6.11.6, babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
-babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
- regenerator-runtime "^0.10.0"
+ regenerator-runtime "^0.11.0"
babel-template@^6.24.1, babel-template@^6.7.0:
version "6.24.1"
@@ -1296,6 +1319,10 @@ camelcase@^2.0.0, camelcase@^2.0.1, camelcase@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+camelcase@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
caniuse-api@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
@@ -1385,6 +1412,10 @@ chromium-pickle-js@0.1.0, chromium-pickle-js@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.1.0.tgz#1d48b107d82126a2f3e211c2ea25f803ba551b21"
+chromium-pickle-js@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205"
+
ci-info@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
@@ -1440,7 +1471,7 @@ cliui@^2.1.0:
right-align "^0.1.1"
wordwrap "0.0.2"
-cliui@^3.0.3:
+cliui@^3.0.3, cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
dependencies:
@@ -1704,9 +1735,9 @@ create-error-class@^3.0.1:
dependencies:
capture-stack-trace "^1.0.0"
-create-react-class@^15.5.1, create-react-class@^15.5.2:
- version "15.5.3"
- resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.3.tgz#fb0f7cae79339e9a179e194ef466efa3923820fe"
+create-react-class@^15.5.1, create-react-class@^15.5.2, create-react-class@^15.6.0:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
@@ -2121,6 +2152,20 @@ electron-installer-debian@^0.1.0:
word-wrap "^1.1.0"
yargs "^3.32.0"
+electron-installer-redhat@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/electron-installer-redhat/-/electron-installer-redhat-0.3.1.tgz#f39bfafff512cb38027d66d756cc489254eef8f3"
+ dependencies:
+ asar "^0.12.0"
+ async "^2.0.0"
+ debug "^2.2.0"
+ fs-extra "^1.0.0"
+ glob "^7.0.0"
+ lodash "^4.0.1"
+ temp "^0.8.3"
+ word-wrap "^1.1.0"
+ yargs "^6.0.0"
+
electron-osx-sign@^0.3.0:
version "0.3.2"
resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.3.2.tgz#88fa7d6ebadb5d9c79368b96491a0d8c4630146e"
@@ -2150,17 +2195,18 @@ electron-packager@^6.0.0:
rimraf "^2.3.2"
run-series "^1.1.1"
-electron-prebuilt@^1.2.8:
- version "1.4.13"
- resolved "https://registry.yarnpkg.com/electron-prebuilt/-/electron-prebuilt-1.4.13.tgz#0a0e4d7bf895a242061ccfab29394dcda1da33d2"
- dependencies:
- electron-download "^3.0.1"
- extract-zip "^1.0.3"
-
electron-to-chromium@^1.2.7:
version "1.3.11"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.11.tgz#744761df1d67b492b322ce9aa0aba5393260eb61"
+electron@^1.6.15:
+ version "1.7.9"
+ resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.9.tgz#add54e9f8f83ed02f6519ec10135f698b19336cf"
+ dependencies:
+ "@types/node" "^7.0.18"
+ electron-download "^3.0.1"
+ extract-zip "^1.0.3"
+
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@@ -2353,6 +2399,10 @@ eslint-plugin-react@~6.7.1:
doctrine "^1.2.2"
jsx-ast-utils "^1.3.3"
+eslint-plugin-standard@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2"
+
eslint-plugin-standard@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3"
@@ -2640,6 +2690,18 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
+fbjs@^0.8.16:
+ version "0.8.16"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
+ dependencies:
+ core-js "^1.0.0"
+ isomorphic-fetch "^2.1.1"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.9"
+
fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
@@ -2843,6 +2905,14 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
+fs-extra@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950"
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^2.1.0"
+ klaw "^1.0.0"
+
fs-plus@2.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/fs-plus/-/fs-plus-2.10.1.tgz#3204781d7840611e6364e7b6fb058c96327c5aa5"
@@ -2907,6 +2977,10 @@ generate-object-property@^1.1.0:
dependencies:
is-property "^1.0.0"
+get-caller-file@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
get-folder-size@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/get-folder-size/-/get-folder-size-1.0.0.tgz#134d663a0e745611b72f71c83b13f1b12f31ba29"
@@ -3076,6 +3150,12 @@ grunt-electron-installer-debian@^0.2.0:
dependencies:
electron-installer-debian "^0.1.0"
+grunt-electron-installer-redhat@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/grunt-electron-installer-redhat/-/grunt-electron-installer-redhat-0.3.1.tgz#ce3093d1113a53e2c34bd72fed4a919971adce96"
+ dependencies:
+ electron-installer-redhat "^0.3.0"
+
grunt-electron-installer@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/grunt-electron-installer/-/grunt-electron-installer-1.2.3.tgz#50652ec4d0248233da76b4ac2ca69f3894c7240e"
@@ -3902,6 +3982,12 @@ lodash-es@^4.2.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
+lodash-move@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/lodash-move/-/lodash-move-1.1.1.tgz#59f76e0f1ac57e6d8683f531bec07c5b6ea4e348"
+ dependencies:
+ lodash "^4.6.1"
+
lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@@ -3951,7 +4037,7 @@ lodash@^3.5.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -4021,6 +4107,10 @@ markdown-it-imsize:
version "2.0.1"
resolved "https://registry.yarnpkg.com/markdown-it-imsize/-/markdown-it-imsize-2.0.1.tgz#cca0427905d05338a247cb9ca9d968c5cddd5170"
+markdown-it-kbd@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/markdown-it-kbd/-/markdown-it-kbd-1.1.1.tgz#55142d93a76bb8903de09d98d8a547b63d935977"
+
markdown-it-multimd-table@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/markdown-it-multimd-table/-/markdown-it-multimd-table-2.0.1.tgz#2e246dc2ec4ca093cbf05d43c9c1cc64e31f255d"
@@ -4033,6 +4123,10 @@ markdown-it-named-headers@^0.0.4:
dependencies:
string "^3.0.1"
+markdown-it-plantuml@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-plantuml/-/markdown-it-plantuml-0.3.0.tgz#6eb039c45f618e89bb992968f7922765f2735665"
+
markdown-it@^5.0.3:
version "5.1.0"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-5.1.0.tgz#25286b8465bac496f3f1b77eed544643e9bd718d"
@@ -4093,7 +4187,7 @@ md5@^2.0.0:
crypt "~0.0.1"
is-buffer "~1.1.1"
-mdurl@~1.0.1:
+mdurl@^1.0.1, mdurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
@@ -4203,7 +4297,7 @@ minimatch@0.3:
lru-cache "2"
sigmund "~1.0.0"
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
@@ -4230,10 +4324,6 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-mixpanel@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.4.1.tgz#0e92ee336fb89a164f54830f093c9cae8517fb8f"
-
mkdirp@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
@@ -4605,7 +4695,7 @@ os-locale@^1.4.0:
dependencies:
lcid "^1.0.0"
-os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -5150,7 +5240,15 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
-prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7:
+prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8:
+ version "15.6.0"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
+ dependencies:
+ fbjs "^0.8.16"
+ loose-envify "^1.3.1"
+ object-assign "^4.1.1"
+
+prop-types@~15.5.7:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
@@ -5339,6 +5437,15 @@ react-router@^2.4.0:
loose-envify "^1.2.0"
warning "^3.0.0"
+react-sortable-hoc@^0.6.7:
+ version "0.6.7"
+ resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-0.6.7.tgz#e30d247bc36dd5a605430c331ac9cb50a5fa72a6"
+ dependencies:
+ babel-runtime "^6.11.6"
+ invariant "^2.2.1"
+ lodash "^4.12.0"
+ prop-types "^15.5.7"
+
react-transform-catch-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-transform-catch-errors/-/react-transform-catch-errors-1.0.2.tgz#1b4d4a76e97271896fc16fe3086c793ec88a9eeb"
@@ -5350,14 +5457,15 @@ react-transform-hmr@^1.0.3:
global "^4.3.0"
react-proxy "^1.1.7"
-react@^15.0.2:
- version "15.5.4"
- resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047"
+react@^15.5.4:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
dependencies:
+ create-react-class "^15.6.0"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
- prop-types "^15.5.7"
+ prop-types "^15.5.10"
reactcss@^1.2.0:
version "1.2.2"
@@ -5495,9 +5603,9 @@ regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
-regenerator-runtime@^0.10.0:
- version "0.10.5"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
+regenerator-runtime@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
regenerator-transform@0.9.11:
version "0.9.11"
@@ -5613,6 +5721,14 @@ request@^2.45.0, request@^2.79.0, request@^2.81.0:
tunnel-agent "^0.6.0"
uuid "^3.0.0"
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
require-precompiled@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/require-precompiled/-/require-precompiled-0.1.0.tgz#5a1b52eb70ebed43eb982e974c85ab59571e56fa"
@@ -5773,7 +5889,7 @@ serve-static@1.12.3:
parseurl "~1.3.1"
send "0.15.3"
-set-blocking@~2.0.0:
+set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -6075,6 +6191,10 @@ strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+striptags@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/striptags/-/striptags-2.2.1.tgz#4c450b708d41b8bf39cf24c49ff234fc6aabfd32"
+
style-loader@^0.12.4:
version "0.12.4"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.12.4.tgz#ae7d0665dc4dc653daa2fe97bb90914bc1d22d9b"
@@ -6276,6 +6396,12 @@ tinycolor2@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
+tmp@0.0.28:
+ version "0.0.28"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120"
+ dependencies:
+ os-tmpdir "~1.0.1"
+
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -6679,6 +6805,10 @@ whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
+which-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
which@^1.2.9:
version "1.2.14"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
@@ -6811,7 +6941,7 @@ xtend@~2.1.1:
dependencies:
object-keys "~0.4.0"
-y18n@^3.2.0:
+y18n@^3.2.0, y18n@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
@@ -6819,6 +6949,12 @@ yallist@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+yargs-parser@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+ dependencies:
+ camelcase "^3.0.0"
+
yargs@^3.32.0:
version "3.32.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
@@ -6831,6 +6967,24 @@ yargs@^3.32.0:
window-size "^0.1.4"
y18n "^3.2.0"
+yargs@^6.0.0:
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+ dependencies:
+ camelcase "^3.0.0"
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ os-locale "^1.4.0"
+ read-pkg-up "^1.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^1.0.2"
+ which-module "^1.0.0"
+ y18n "^3.2.1"
+ yargs-parser "^4.2.0"
+
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"