mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-23 22:51:42 +00:00
Merge branch 'master' into html-to-md
# Conflicts: # browser/main/modals/NewNoteModal.js # package-lock.json # package.json # yarn.lock
This commit is contained in:
@@ -3,7 +3,7 @@ import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './CreateFolderModal.styl'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import store from 'browser/main/store'
|
||||
import { store } from 'browser/main/store'
|
||||
import consts from 'browser/lib/consts'
|
||||
import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
|
||||
@@ -128,3 +128,29 @@ body[data-theme="monokai"]
|
||||
|
||||
.control-confirmButton
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
modalDracula()
|
||||
width 500px
|
||||
height 270px
|
||||
overflow hidden
|
||||
position relative
|
||||
|
||||
.header
|
||||
background-color transparent
|
||||
border-color $ui-dark-borderColor
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.control-folder-label
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.control-folder-input
|
||||
border 1px solid $ui-input--create-folder-modal
|
||||
color white
|
||||
|
||||
.description
|
||||
color $ui-inactive-text-color
|
||||
|
||||
.control-confirmButton
|
||||
colorDraculaPrimaryButton()
|
||||
@@ -1,21 +1,18 @@
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NewNoteModal.styl'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import { hashHistory } from 'react-router'
|
||||
import ee from 'browser/main/lib/eventEmitter'
|
||||
import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import { openModal } from 'browser/main/lib/modal'
|
||||
import CreateMarkdownFromURLModal from '../modals/CreateMarkdownFromURLModal'
|
||||
import { createMarkdownNote, createSnippetNote } from 'browser/lib/newNote'
|
||||
import queryString from 'query-string'
|
||||
|
||||
class NewNoteModal extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
}
|
||||
this.lock = false
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@@ -26,7 +23,7 @@ class NewNoteModal extends React.Component {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
handleCreateMarkdownFromUrlClick(e) {
|
||||
handleCreateMarkdownFromUrlClick (e) {
|
||||
this.props.close()
|
||||
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
@@ -35,34 +32,18 @@ class NewNoteModal extends React.Component {
|
||||
folder: folder,
|
||||
dispatch,
|
||||
location
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
handleMarkdownNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
dataApi
|
||||
.createNote(storage, {
|
||||
type: 'MARKDOWN_NOTE',
|
||||
folder: folder,
|
||||
title: '',
|
||||
content: ''
|
||||
})
|
||||
.then((note) => {
|
||||
const noteHash = note.key
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
hashHistory.push({
|
||||
pathname: location.pathname,
|
||||
query: {key: noteHash}
|
||||
})
|
||||
ee.emit('list:jump', noteHash)
|
||||
ee.emit('detail:focus')
|
||||
this.props.close()
|
||||
const { storage, folder, dispatch, location, config } = this.props
|
||||
const params = location.search !== '' && queryString.parse(location.search)
|
||||
if (!this.lock) {
|
||||
this.lock = true
|
||||
createMarkdownNote(storage, folder, dispatch, location, params, config).then(() => {
|
||||
setTimeout(this.props.close, 200)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleMarkdownNoteButtonKeyDown (e) {
|
||||
@@ -73,36 +54,14 @@ class NewNoteModal extends React.Component {
|
||||
}
|
||||
|
||||
handleSnippetNoteButtonClick (e) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
|
||||
const { storage, folder, dispatch, location } = this.props
|
||||
|
||||
dataApi
|
||||
.createNote(storage, {
|
||||
type: 'SNIPPET_NOTE',
|
||||
folder: folder,
|
||||
title: '',
|
||||
description: '',
|
||||
snippets: [{
|
||||
name: '',
|
||||
mode: 'text',
|
||||
content: ''
|
||||
}]
|
||||
})
|
||||
.then((note) => {
|
||||
const noteHash = note.key
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: note
|
||||
})
|
||||
hashHistory.push({
|
||||
pathname: location.pathname,
|
||||
query: {key: noteHash}
|
||||
})
|
||||
ee.emit('list:jump', noteHash)
|
||||
ee.emit('detail:focus')
|
||||
this.props.close()
|
||||
const { storage, folder, dispatch, location, config } = this.props
|
||||
const params = location.search !== '' && queryString.parse(location.search)
|
||||
if (!this.lock) {
|
||||
this.lock = true
|
||||
createSnippetNote(storage, folder, dispatch, location, params, config).then(() => {
|
||||
setTimeout(this.props.close, 200)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSnippetNoteButtonKeyDown (e) {
|
||||
@@ -120,50 +79,63 @@ class NewNoteModal extends React.Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='header'>
|
||||
<div styleName='title'>{i18n.__('Make a note')}</div>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
|
||||
/>
|
||||
<div styleName='control'>
|
||||
<button styleName='control-button'
|
||||
onClick={(e) => this.handleMarkdownNoteButtonClick(e)}
|
||||
onKeyDown={(e) => this.handleMarkdownNoteButtonKeyDown(e)}
|
||||
<button
|
||||
styleName='control-button'
|
||||
onClick={e => this.handleMarkdownNoteButtonClick(e)}
|
||||
onKeyDown={e => this.handleMarkdownNoteButtonKeyDown(e)}
|
||||
ref='markdownButton'
|
||||
>
|
||||
<i styleName='control-button-icon'
|
||||
className='fa fa-file-text-o'
|
||||
/><br />
|
||||
<span styleName='control-button-label'>{i18n.__('Markdown Note')}</span><br />
|
||||
<span styleName='control-button-description'>{i18n.__('This format is for creating text documents. Checklists, code blocks and Latex blocks are available.')}</span>
|
||||
<i styleName='control-button-icon' className='fa fa-file-text-o' />
|
||||
<br />
|
||||
<span styleName='control-button-label'>
|
||||
{i18n.__('Markdown Note')}
|
||||
</span>
|
||||
<br />
|
||||
<span styleName='control-button-description'>
|
||||
{i18n.__(
|
||||
'This format is for creating text documents. Checklists, code blocks and Latex blocks are available.'
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button styleName='control-button'
|
||||
onClick={(e) => this.handleSnippetNoteButtonClick(e)}
|
||||
onKeyDown={(e) => this.handleSnippetNoteButtonKeyDown(e)}
|
||||
<button
|
||||
styleName='control-button'
|
||||
onClick={e => this.handleSnippetNoteButtonClick(e)}
|
||||
onKeyDown={e => this.handleSnippetNoteButtonKeyDown(e)}
|
||||
ref='snippetButton'
|
||||
>
|
||||
<i styleName='control-button-icon'
|
||||
className='fa fa-code'
|
||||
/><br />
|
||||
<span styleName='control-button-label'>{i18n.__('Snippet Note')}</span><br />
|
||||
<span styleName='control-button-description'>{i18n.__('This format is for creating code snippets. Multiple snippets can be grouped into a single note.')}
|
||||
<i styleName='control-button-icon' className='fa fa-code' /><br />
|
||||
<span styleName='control-button-label'>
|
||||
{i18n.__('Snippet Note')}
|
||||
</span>
|
||||
<br />
|
||||
<span styleName='control-button-description'>
|
||||
{i18n.__(
|
||||
'This format is for creating code snippets. Multiple snippets can be grouped into a single note.'
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div styleName='description'><i className='fa fa-arrows-h' />{i18n.__('Tab to switch format')}</div>
|
||||
<div styleName='from-url' onClick={(e) => this.handleCreateMarkdownFromUrlClick(e)}>Or, create a new markdown note from a URL</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NewNoteModal.propTypes = {
|
||||
}
|
||||
NewNoteModal.propTypes = {}
|
||||
|
||||
export default CSSModules(NewNoteModal, styles)
|
||||
|
||||
@@ -103,3 +103,20 @@ body[data-theme="monokai"]
|
||||
|
||||
.description, .from-url
|
||||
color $ui-monokai-text-color
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
background-color transparent
|
||||
|
||||
.header
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.control-button
|
||||
border-color $ui-dracula-borderColor
|
||||
color $ui-dracula-text-color
|
||||
background-color transparent
|
||||
&:focus
|
||||
colorDraculaPrimaryButton()
|
||||
|
||||
.description
|
||||
color $ui-dracula-text-color
|
||||
@@ -2,7 +2,7 @@ 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 { store } from 'browser/main/store'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
@@ -43,7 +43,7 @@ class Blog extends React.Component {
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({BlogAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('Error occurs!')
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
}
|
||||
this.oldBlog = this.state.config.blog
|
||||
@@ -70,7 +70,7 @@ class Blog extends React.Component {
|
||||
this.props.haveToSave({
|
||||
tab: 'Blog',
|
||||
type: 'warning',
|
||||
message: i18n.__('You have to save!')
|
||||
message: i18n.__('Unsaved Changes!')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,21 @@
|
||||
margin-bottom 15px
|
||||
margin-top 30px
|
||||
|
||||
.group-header--sub
|
||||
@extend .group-header
|
||||
margin-bottom 10px
|
||||
|
||||
.group-header2--sub
|
||||
@extend .group-header2
|
||||
margin-bottom 10px
|
||||
|
||||
.group-section
|
||||
margin-bottom 20px
|
||||
display flex
|
||||
line-height 30px
|
||||
|
||||
.group-section-label
|
||||
width 150px
|
||||
width 200px
|
||||
text-align left
|
||||
margin-right 10px
|
||||
font-size 14px
|
||||
@@ -68,9 +76,9 @@
|
||||
:global
|
||||
.alert
|
||||
display inline-block
|
||||
position absolute
|
||||
top 60px
|
||||
right 15px
|
||||
position fixed
|
||||
top 130px
|
||||
right 100px
|
||||
font-size 14px
|
||||
.success
|
||||
color #1EC38B
|
||||
@@ -127,7 +135,7 @@ 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
|
||||
@@ -138,16 +146,22 @@ colorMonokaiControl()
|
||||
background-color $ui-monokai-button-backgroundColor
|
||||
color $ui-monokai-text-color
|
||||
|
||||
colorDraculaControl()
|
||||
border none
|
||||
background-color $ui-dracula-button-backgroundColor
|
||||
color $ui-dracula-text-color
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
color $ui-dark-text-color
|
||||
|
||||
.group-header
|
||||
.group-header--sub
|
||||
color $ui-dark-text-color
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
.group-header2
|
||||
.group-header2--sub
|
||||
color $ui-dark-text-color
|
||||
|
||||
.group-section-control-input
|
||||
@@ -165,27 +179,29 @@ 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
|
||||
.group-header--sub
|
||||
color $ui-solarized-dark-text-color
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
|
||||
.group-header2
|
||||
.group-header2--sub
|
||||
color $ui-solarized-dark-text-color
|
||||
|
||||
.group-section-control-input
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
|
||||
.group-control
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
.group-control-leftButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
.group-control-rightButton
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
.group-hint
|
||||
@@ -199,20 +215,22 @@ body[data-theme="monokai"]
|
||||
color $ui-monokai-text-color
|
||||
|
||||
.group-header
|
||||
.group-header--sub
|
||||
color $ui-monokai-text-color
|
||||
border-color $ui-monokai-borderColor
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
.group-header2
|
||||
.group-header2--sub
|
||||
color $ui-monokai-text-color
|
||||
|
||||
.group-section-control-input
|
||||
border-color $ui-monokai-borderColor
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
.group-control
|
||||
border-color $ui-monokai-borderColor
|
||||
border-color $ui-monokai-borderColor
|
||||
.group-control-leftButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-monokai-borderColor
|
||||
border-color $ui-monokai-borderColor
|
||||
.group-control-rightButton
|
||||
colorMonokaiPrimaryButton()
|
||||
.group-hint
|
||||
@@ -220,3 +238,32 @@ body[data-theme="monokai"]
|
||||
.group-section-control
|
||||
select, .group-section-control-input
|
||||
colorMonokaiControl()
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.group-header
|
||||
.group-header--sub
|
||||
color $ui-dracula-text-color
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.group-header2
|
||||
.group-header2--sub
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.group-section-control-input
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.group-control
|
||||
border-color $ui-dracula-borderColor
|
||||
.group-control-leftButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-dracula-borderColor
|
||||
.group-control-rightButton
|
||||
colorDraculaPrimaryButton()
|
||||
.group-hint
|
||||
colorDraculaControl()
|
||||
.group-section-control
|
||||
select, .group-section-control-input
|
||||
colorDraculaControl()
|
||||
@@ -22,22 +22,28 @@ class Crowdfunding extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='header'>{i18n.__('Crowdfunding')}</div>
|
||||
<p>{i18n.__('Dear everyone,')}</p>
|
||||
<br />
|
||||
<div styleName='group-header'>{i18n.__('Crowdfunding')}</div>
|
||||
<p>{i18n.__('Thank you for using Boostnote!')}</p>
|
||||
<p>{i18n.__('Boostnote is used in about 200 different countries and regions by an awesome community of developers.')}</p>
|
||||
<br />
|
||||
<p>{i18n.__('To continue supporting this growth, and to satisfy community expectations,')}</p>
|
||||
<p>{i18n.__('we would like to invest more time and resources in this project.')}</p>
|
||||
<p>{i18n.__('We launched IssueHunt which is an issue-based crowdfunding / sourcing platform for open source projects.')}</p>
|
||||
<p>{i18n.__('Anyone can put a bounty on not only a bug but also on OSS feature requests listed on IssueHunt. Collected funds will be distributed to project owners and contributors.')}</p>
|
||||
<div styleName='group-header2--sub'>{i18n.__('Sustainable Open Source Ecosystem')}</div>
|
||||
<p>{i18n.__('We discussed about open-source ecosystem and IssueHunt concept with the Boostnote team repeatedly. We actually also discussed with Matz who father of Ruby.')}</p>
|
||||
<p>{i18n.__('The original reason why we made IssueHunt was to reward our contributors of Boostnote project. We’ve got tons of Github stars and hundred of contributors in two years.')}</p>
|
||||
<p>{i18n.__('We thought that it will be nice if we can pay reward for our contributors.')}</p>
|
||||
<div styleName='group-header2--sub'>{i18n.__('We believe Meritocracy')}</div>
|
||||
<p>{i18n.__('We think developers who have skills and do great things must be rewarded properly.')}</p>
|
||||
<p>{i18n.__('OSS projects are used in everywhere on the internet, but no matter how they great, most of owners of those projects need to have another job to sustain their living.')}</p>
|
||||
<p>{i18n.__('It sometimes looks like exploitation.')}</p>
|
||||
<p>{i18n.__('We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.')}</p>
|
||||
<br />
|
||||
<p>{i18n.__('If you like this project and see its potential, you can help by supporting us on OpenCollective!')}</p>
|
||||
<p>{i18n.__('As same as issues of Boostnote are already funded on IssueHunt, your open-source projects can be also started funding from now.')}</p>
|
||||
<br />
|
||||
<p>{i18n.__('Thanks,')}</p>
|
||||
<p>{i18n.__('Boostnote maintainers')}</p>
|
||||
<p>{i18n.__('Thank you,')}</p>
|
||||
<p>{i18n.__('The Boostnote Team')}</p>
|
||||
<br />
|
||||
<button styleName='cf-link'>
|
||||
<a href='https://opencollective.com/boostnoteio' onClick={(e) => this.handleLinkClick(e)}>{i18n.__('Support via OpenCollective')}</a>
|
||||
<a href='http://bit.ly/issuehunt-from-boostnote-app' onClick={(e) => this.handleLinkClick(e)}>{i18n.__('See IssueHunt')}</a>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
@import('./Tab')
|
||||
@import('./ConfigTab')
|
||||
|
||||
.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
|
||||
line-height 1.4
|
||||
|
||||
.cf-link
|
||||
width 250px
|
||||
height 35px
|
||||
border-radius 2px
|
||||
border none
|
||||
background-color alpha(#1EC38B, 90%)
|
||||
padding-left 20px
|
||||
padding-right 20px
|
||||
&:hover
|
||||
background-color #1EC38B
|
||||
transition 0.2s
|
||||
@@ -28,7 +23,7 @@ p
|
||||
body[data-theme="dark"]
|
||||
p
|
||||
color $ui-dark-text-color
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
color $ui-solarized-dark-text-color
|
||||
@@ -40,3 +35,9 @@ body[data-theme="monokai"]
|
||||
color $ui-monokai-text-color
|
||||
p
|
||||
color $ui-monokai-text-color
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
p
|
||||
color $ui-dracula-text-color
|
||||
@@ -4,7 +4,7 @@ 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 { store } from 'browser/main/store'
|
||||
import { SketchPicker } from 'react-color'
|
||||
import { SortableElement, SortableHandle } from 'react-sortable-hoc'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
height 35px
|
||||
box-sizing border-box
|
||||
padding 2.5px 15px
|
||||
display flex
|
||||
&:hover
|
||||
background-color darken(white, 3%)
|
||||
|
||||
@@ -18,7 +19,10 @@
|
||||
border-left solid 2px transparent
|
||||
padding 0 10px
|
||||
line-height 30px
|
||||
float left
|
||||
flex 1
|
||||
white-space nowrap
|
||||
text-overflow ellipsis
|
||||
overflow hidden
|
||||
.folderItem-left-danger
|
||||
color $danger-color
|
||||
font-weight bold
|
||||
@@ -52,12 +56,13 @@
|
||||
outline none
|
||||
|
||||
.folderItem-right
|
||||
float right
|
||||
-webkit-box-flex: 1
|
||||
white-space nowrap
|
||||
|
||||
.folderItem-right-button
|
||||
vertical-align middle
|
||||
height 25px
|
||||
margin-top 2.5px
|
||||
margin-top 2px
|
||||
colorDefaultButton()
|
||||
border-radius 2px
|
||||
border $ui-border
|
||||
@@ -149,3 +154,26 @@ body[data-theme="monokai"]
|
||||
|
||||
.folderItem-right-dangerButton
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.folderItem
|
||||
&:hover
|
||||
background-color $ui-dracula-button-backgroundColor
|
||||
|
||||
.folderItem-left-danger
|
||||
color $danger-color
|
||||
|
||||
.folderItem-left-key
|
||||
color $ui-dark-inactive-text-color
|
||||
|
||||
.folderItem-left-colorButton
|
||||
colorDraculaPrimaryButton()
|
||||
|
||||
.folderItem-right-button
|
||||
colorDraculaPrimaryButton()
|
||||
|
||||
.folderItem-right-confirmButton
|
||||
colorDraculaPrimaryButton()
|
||||
|
||||
.folderItem-right-dangerButton
|
||||
colorDraculaPrimaryButton()
|
||||
@@ -3,7 +3,7 @@ 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 { store } from 'browser/main/store'
|
||||
import FolderItem from './FolderItem'
|
||||
import { SortableContainer } from 'react-sortable-hoc'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
@@ -3,7 +3,7 @@ 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 { store } from 'browser/main/store'
|
||||
import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
@@ -28,10 +28,20 @@ class HotkeyTab extends React.Component {
|
||||
}})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('Error occurs!')
|
||||
}})
|
||||
if (
|
||||
this.state.config.hotkey.toggleMain === '' ||
|
||||
this.state.config.hotkey.toggleMode === ''
|
||||
) {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
} else {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
}
|
||||
}
|
||||
this.oldHotkey = this.state.config.hotkey
|
||||
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
@@ -68,7 +78,10 @@ class HotkeyTab extends React.Component {
|
||||
const { config } = this.state
|
||||
config.hotkey = {
|
||||
toggleMain: this.refs.toggleMain.value,
|
||||
toggleMode: this.refs.toggleMode.value
|
||||
toggleMode: this.refs.toggleMode.value,
|
||||
deleteNote: this.refs.deleteNote.value,
|
||||
pasteSmartly: this.refs.pasteSmartly.value,
|
||||
toggleMenuBar: this.refs.toggleMenuBar.value
|
||||
}
|
||||
this.setState({
|
||||
config
|
||||
@@ -79,7 +92,7 @@ class HotkeyTab extends React.Component {
|
||||
this.props.haveToSave({
|
||||
tab: 'Hotkey',
|
||||
type: 'warning',
|
||||
message: i18n.__('You have to save!')
|
||||
message: i18n.__('Unsaved Changes!')
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -117,7 +130,18 @@ class HotkeyTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Toggle editor mode')}</div>
|
||||
<div styleName='group-section-label'>{i18n.__('Show/Hide Menu Bar')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
ref='toggleMenuBar'
|
||||
value={config.hotkey.toggleMenuBar}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Toggle Editor Mode')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
@@ -127,6 +151,28 @@ class HotkeyTab extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Delete Note')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
ref='deleteNote'
|
||||
value={config.hotkey.deleteNote}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Paste HTML')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
ref='pasteSmartly'
|
||||
value={config.hotkey.pasteSmartly}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-leftButton'
|
||||
onClick={(e) => this.handleHintToggleButtonClick(e)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './InfoTab.styl'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import store from 'browser/main/store'
|
||||
import { store } from 'browser/main/store'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
@@ -69,10 +69,14 @@ class InfoTab extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
|
||||
<div styleName='header--sub'>{i18n.__('Community')}</div>
|
||||
<div styleName='group-header'>{i18n.__('Community')}</div>
|
||||
<div styleName='top'>
|
||||
<ul styleName='list'>
|
||||
<li>
|
||||
<a href='https://issuehunt.io/repos/53266139'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Bounty on IssueHunt')}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://boostnote.io/#subscribe'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
@@ -84,7 +88,7 @@ class InfoTab extends React.Component {
|
||||
>{i18n.__('GitHub')}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://boostlog.io/@junp1234'
|
||||
<a href='https://medium.com/boostnote'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Blog')}</a>
|
||||
</li>
|
||||
@@ -103,7 +107,7 @@ class InfoTab extends React.Component {
|
||||
|
||||
<hr />
|
||||
|
||||
<div styleName='header--sub'>{i18n.__('About')}</div>
|
||||
<div styleName='group-header--sub'>{i18n.__('About')}</div>
|
||||
|
||||
<div styleName='top'>
|
||||
<div styleName='icon-space'>
|
||||
@@ -129,7 +133,7 @@ class InfoTab extends React.Component {
|
||||
>{i18n.__('Development')}</a>{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('Copyright (C) 2017 - 2018 BoostIO')}
|
||||
{i18n.__('Copyright (C) 2017 - 2019 BoostIO')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('License: GPL v3')}
|
||||
@@ -138,7 +142,7 @@ class InfoTab extends React.Component {
|
||||
|
||||
<hr styleName='separate-line' />
|
||||
|
||||
<div styleName='policy'>{i18n.__('Analytics')}</div>
|
||||
<div styleName='group-header2--sub'>{i18n.__('Analytics')}</div>
|
||||
<div>{i18n.__('Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.')}</div>
|
||||
<div>{i18n.__('You can see how it works on ')}<a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
|
||||
<br />
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
@import('./Tab')
|
||||
|
||||
.root
|
||||
padding 15px
|
||||
white-space pre
|
||||
line-height 1.4
|
||||
color alpha($ui-text-color, 90%)
|
||||
width 100%
|
||||
font-size 14px
|
||||
|
||||
.top
|
||||
text-align left
|
||||
margin-bottom 20px
|
||||
@import('./ConfigTab.styl')
|
||||
|
||||
.icon-space
|
||||
margin 20px 0
|
||||
@@ -45,13 +33,21 @@
|
||||
.separate-line
|
||||
margin 40px 0
|
||||
|
||||
.policy
|
||||
width 100%
|
||||
font-size 20px
|
||||
margin-bottom 10px
|
||||
|
||||
.policy-submit
|
||||
margin-top 10px
|
||||
height 35px
|
||||
border-radius 2px
|
||||
border none
|
||||
background-color alpha(#1EC38B, 90%)
|
||||
padding-left 20px
|
||||
padding-right 20px
|
||||
text-decoration none
|
||||
color white
|
||||
font-weight 600
|
||||
font-size 16px
|
||||
&:hover
|
||||
background-color #1EC38B
|
||||
transition 0.2s
|
||||
|
||||
.policy-confirm
|
||||
margin-top 10px
|
||||
@@ -60,11 +56,14 @@
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
color alpha($tab--dark-text-color, 80%)
|
||||
|
||||
.appId
|
||||
color $ui-dark-text-color
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
color $ui-solarized-dark-text-color
|
||||
.appId
|
||||
color $ui-solarized-dark-text-color
|
||||
.list
|
||||
a
|
||||
color $ui-solarized-dark-active-color
|
||||
@@ -72,6 +71,17 @@ body[data-theme="solarized-dark"]
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
color $ui-monokai-text-color
|
||||
.appId
|
||||
color $ui-monokai-text-color
|
||||
.list
|
||||
a
|
||||
color $ui-monokai-active-color
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
.appId
|
||||
color $ui-dracula-text-color
|
||||
.list
|
||||
a
|
||||
color $ui-dracula-active-color
|
||||
@@ -90,7 +90,7 @@ body[data-theme="dark"]
|
||||
background-color $dark-primary-button-background--active
|
||||
&:hover
|
||||
color white
|
||||
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
@@ -139,3 +139,27 @@ body[data-theme="monokai"]
|
||||
background-color $ui-monokai-button--active-backgroundColor
|
||||
&:hover
|
||||
color white
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
background-color transparent
|
||||
.top-bar
|
||||
background-color transparent
|
||||
border-color $ui-dracula-borderColor
|
||||
p
|
||||
color $ui-dracula-text-color
|
||||
.nav
|
||||
background-color transparent
|
||||
border-color $ui-dracula-borderColor
|
||||
.nav-button
|
||||
background-color transparent
|
||||
color $ui-dracula-text-color
|
||||
&:hover
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.nav-button--active
|
||||
@extend .nav-button
|
||||
color $ui-dracula-button--active-color
|
||||
background-color $ui-dracula-button--active-backgroundColor
|
||||
&:hover
|
||||
color #f8f8f2
|
||||
98
browser/main/modals/PreferencesModal/SnippetEditor.js
Normal file
98
browser/main/modals/PreferencesModal/SnippetEditor.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import CodeMirror from 'codemirror'
|
||||
import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import styles from './SnippetTab.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import snippetManager from '../../../lib/SnippetManager'
|
||||
|
||||
const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
|
||||
const buildCMRulers = (rulers, enableRulers) =>
|
||||
enableRulers ? rulers.map(ruler => ({ column: ruler })) : []
|
||||
|
||||
class SnippetEditor extends React.Component {
|
||||
|
||||
componentDidMount () {
|
||||
this.props.onRef(this)
|
||||
const { rulers, enableRulers } = this.props
|
||||
this.cm = CodeMirror(this.refs.root, {
|
||||
rulers: buildCMRulers(rulers, enableRulers),
|
||||
lineNumbers: this.props.displayLineNumbers,
|
||||
lineWrapping: true,
|
||||
theme: this.props.theme,
|
||||
indentUnit: this.props.indentSize,
|
||||
tabSize: this.props.indentSize,
|
||||
indentWithTabs: this.props.indentType !== 'space',
|
||||
keyMap: this.props.keyMap,
|
||||
scrollPastEnd: this.props.scrollPastEnd,
|
||||
dragDrop: false,
|
||||
foldGutter: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||
autoCloseBrackets: {
|
||||
pairs: this.props.matchingPairs,
|
||||
triples: this.props.matchingTriples,
|
||||
explode: this.props.explodingPairs,
|
||||
override: true
|
||||
},
|
||||
mode: 'null'
|
||||
})
|
||||
this.cm.setSize('100%', '100%')
|
||||
let changeDelay = null
|
||||
|
||||
this.cm.on('change', () => {
|
||||
this.snippet.content = this.cm.getValue()
|
||||
|
||||
clearTimeout(changeDelay)
|
||||
changeDelay = setTimeout(() => {
|
||||
this.saveSnippet()
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.onRef(undefined)
|
||||
}
|
||||
|
||||
onSnippetChanged (newSnippet) {
|
||||
this.snippet = newSnippet
|
||||
this.cm.setValue(this.snippet.content)
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (newSnippet) {
|
||||
this.snippet.name = newSnippet.name
|
||||
this.snippet.prefix = newSnippet.prefix.toString().replace(/\s/g, '').split(',')
|
||||
this.saveSnippet()
|
||||
}
|
||||
|
||||
saveSnippet () {
|
||||
dataApi.updateSnippet(this.snippet)
|
||||
.then(snippets => snippetManager.assignSnippets(snippets))
|
||||
.catch((err) => { throw err })
|
||||
}
|
||||
|
||||
render () {
|
||||
const { fontSize } = this.props
|
||||
let fontFamily = this.props.fontFamily
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
return (
|
||||
<div styleName='SnippetEditor' ref='root' tabIndex='-1' style={{
|
||||
fontFamily: fontFamily.join(', '),
|
||||
fontSize: fontSize
|
||||
}} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SnippetEditor.defaultProps = {
|
||||
readOnly: false,
|
||||
theme: 'xcode',
|
||||
keyMap: 'sublime',
|
||||
fontSize: 14,
|
||||
fontFamily: 'Monaco, Consolas',
|
||||
indentSize: 4,
|
||||
indentType: 'space'
|
||||
}
|
||||
|
||||
export default CSSModules(SnippetEditor, styles)
|
||||
99
browser/main/modals/PreferencesModal/SnippetList.js
Normal file
99
browser/main/modals/PreferencesModal/SnippetList.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import React from 'react'
|
||||
import styles from './SnippetTab.styl'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import context from 'browser/lib/context'
|
||||
|
||||
class SnippetList extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
snippets: []
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.reloadSnippetList()
|
||||
eventEmitter.on('snippetList:reload', this.reloadSnippetList.bind(this))
|
||||
}
|
||||
|
||||
reloadSnippetList () {
|
||||
dataApi.fetchSnippet().then(snippets => {
|
||||
this.setState({snippets})
|
||||
this.props.onSnippetSelect(this.props.currentSnippet)
|
||||
})
|
||||
}
|
||||
|
||||
handleSnippetContextMenu (snippet) {
|
||||
context.popup([{
|
||||
label: i18n.__('Delete snippet'),
|
||||
click: () => this.deleteSnippet(snippet)
|
||||
}])
|
||||
}
|
||||
|
||||
deleteSnippet (snippet) {
|
||||
dataApi.deleteSnippet(snippet).then(() => {
|
||||
this.reloadSnippetList()
|
||||
this.props.onSnippetDeleted(snippet)
|
||||
}).catch(err => { throw err })
|
||||
}
|
||||
|
||||
handleSnippetClick (snippet) {
|
||||
this.props.onSnippetSelect(snippet)
|
||||
}
|
||||
|
||||
createSnippet () {
|
||||
dataApi.createSnippet().then(() => {
|
||||
this.reloadSnippetList()
|
||||
// scroll to end of list when added new snippet
|
||||
const snippetList = document.getElementById('snippets')
|
||||
snippetList.scrollTop = snippetList.scrollHeight
|
||||
}).catch(err => { throw err })
|
||||
}
|
||||
|
||||
defineSnippetStyleName (snippet) {
|
||||
const { currentSnippet } = this.props
|
||||
|
||||
if (currentSnippet == null) {
|
||||
return 'snippet-item'
|
||||
}
|
||||
|
||||
if (currentSnippet.id === snippet.id) {
|
||||
return 'snippet-item-selected'
|
||||
} else {
|
||||
return 'snippet-item'
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { snippets } = this.state
|
||||
return (
|
||||
<div styleName='snippet-list'>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-control'>
|
||||
<button styleName='group-control-button' onClick={() => this.createSnippet()}>
|
||||
<i className='fa fa-plus' /> {i18n.__('New Snippet')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul id='snippets' styleName='snippets'>
|
||||
{
|
||||
snippets.map((snippet) => (
|
||||
<li
|
||||
styleName={this.defineSnippetStyleName(snippet)}
|
||||
key={snippet.id}
|
||||
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
||||
onClick={() => this.handleSnippetClick(snippet)}>
|
||||
{snippet.name}
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CSSModules(SnippetList, styles)
|
||||
154
browser/main/modals/PreferencesModal/SnippetTab.js
Normal file
154
browser/main/modals/PreferencesModal/SnippetTab.js
Normal file
@@ -0,0 +1,154 @@
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './SnippetTab.styl'
|
||||
import SnippetEditor from './SnippetEditor'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import SnippetList from './SnippetList'
|
||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import copy from 'copy-to-clipboard'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
class SnippetTab extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentSnippet: null
|
||||
}
|
||||
this.changeDelay = null
|
||||
}
|
||||
|
||||
notify (title, options) {
|
||||
if (global.process.platform === 'win32') {
|
||||
options.icon = path.join(
|
||||
'file://',
|
||||
global.__dirname,
|
||||
'../../resources/app.png'
|
||||
)
|
||||
}
|
||||
return new window.Notification(title, options)
|
||||
}
|
||||
|
||||
handleSnippetNameOrPrefixChange () {
|
||||
clearTimeout(this.changeDelay)
|
||||
this.changeDelay = setTimeout(() => {
|
||||
// notify the snippet editor that the name or prefix of snippet has been changed
|
||||
this.snippetEditor.onSnippetNameOrPrefixChanged(this.state.currentSnippet)
|
||||
eventEmitter.emit('snippetList:reload')
|
||||
}, 500)
|
||||
}
|
||||
|
||||
handleSnippetSelect (snippet) {
|
||||
const { currentSnippet } = this.state
|
||||
if (snippet !== null) {
|
||||
if (currentSnippet === null || currentSnippet.id !== snippet.id) {
|
||||
dataApi.fetchSnippet(snippet.id).then(changedSnippet => {
|
||||
// notify the snippet editor to load the content of the new snippet
|
||||
this.snippetEditor.onSnippetChanged(changedSnippet)
|
||||
this.setState({currentSnippet: changedSnippet})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (e, type) {
|
||||
const newSnippet = Object.assign({}, this.state.currentSnippet)
|
||||
if (type === 'name') {
|
||||
newSnippet.name = e.target.value
|
||||
} else {
|
||||
newSnippet.prefix = e.target.value
|
||||
}
|
||||
this.setState({ currentSnippet: newSnippet })
|
||||
this.handleSnippetNameOrPrefixChange()
|
||||
}
|
||||
|
||||
handleDeleteSnippet (snippet) {
|
||||
// prevent old snippet still display when deleted
|
||||
if (snippet.id === this.state.currentSnippet.id) {
|
||||
this.setState({currentSnippet: null})
|
||||
}
|
||||
}
|
||||
|
||||
handleCopySnippet (e) {
|
||||
const showCopyNotification = this.props.config.ui.showCopyNotification
|
||||
copy(this.state.currentSnippet.content)
|
||||
if (showCopyNotification) {
|
||||
this.notify('Saved to Clipboard!', {
|
||||
body: 'Paste it wherever you want!',
|
||||
silent: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { config, storageKey } = this.props
|
||||
const { currentSnippet } = this.state
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group-header'>{i18n.__('Snippets')}</div>
|
||||
<SnippetList
|
||||
onSnippetSelect={this.handleSnippetSelect.bind(this)}
|
||||
onSnippetDeleted={this.handleDeleteSnippet.bind(this)}
|
||||
currentSnippet={currentSnippet} />
|
||||
<div styleName='snippet-detail' style={{visibility: currentSnippet ? 'visible' : 'hidden'}}>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={e => this.handleCopySnippet(e)}>{i18n.__('Copy')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Snippet name')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
value={currentSnippet ? currentSnippet.name : ''}
|
||||
onChange={e => { this.onSnippetNameOrPrefixChanged(e, 'name') }}
|
||||
type='text' />
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Snippet prefix')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
value={currentSnippet ? currentSnippet.prefix : ''}
|
||||
onChange={e => { this.onSnippetNameOrPrefixChanged(e, 'prefix') }}
|
||||
type='text' />
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='snippet-editor-section'>
|
||||
<SnippetEditor
|
||||
storageKey={storageKey}
|
||||
theme={config.editor.theme}
|
||||
keyMap={config.editor.keyMap}
|
||||
fontFamily={config.editor.fontFamily}
|
||||
fontSize={editorFontSize}
|
||||
indentType={config.editor.indentType}
|
||||
indentSize={editorIndentSize}
|
||||
enableRulers={config.editor.enableRulers}
|
||||
rulers={config.editor.rulers}
|
||||
displayLineNumbers={config.editor.displayLineNumbers}
|
||||
matchingPairs={config.editor.matchingPairs}
|
||||
matchingTriples={config.editor.matchingTriples}
|
||||
explodingPairs={config.editor.explodingPairs}
|
||||
scrollPastEnd={config.editor.scrollPastEnd}
|
||||
onRef={ref => { this.snippetEditor = ref }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SnippetTab.PropTypes = {
|
||||
}
|
||||
|
||||
export default CSSModules(SnippetTab, styles)
|
||||
205
browser/main/modals/PreferencesModal/SnippetTab.styl
Normal file
205
browser/main/modals/PreferencesModal/SnippetTab.styl
Normal file
@@ -0,0 +1,205 @@
|
||||
@import('./ConfigTab')
|
||||
|
||||
.group
|
||||
margin-bottom 45px
|
||||
|
||||
.group-header
|
||||
@extend .header
|
||||
color $ui-text-color
|
||||
|
||||
.group-header2
|
||||
font-size 20px
|
||||
color $ui-text-color
|
||||
margin-bottom 15px
|
||||
margin-top 30px
|
||||
|
||||
.group-section
|
||||
margin-bottom 20px
|
||||
display flex
|
||||
line-height 30px
|
||||
|
||||
.group-section-label
|
||||
width 150px
|
||||
text-align left
|
||||
margin-right 10px
|
||||
font-size 14px
|
||||
|
||||
.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
|
||||
height 30px
|
||||
vertical-align middle
|
||||
width 400px
|
||||
font-size $tab--button-font-size
|
||||
border solid 1px $border-color
|
||||
border-radius 2px
|
||||
padding 0 5px
|
||||
outline none
|
||||
&:disabled
|
||||
background-color $ui-input--disabled-backgroundColor
|
||||
|
||||
.group-control-button
|
||||
height 30px
|
||||
border none
|
||||
border-top-right-radius 2px
|
||||
border-bottom-right-radius 2px
|
||||
colorPrimaryButton()
|
||||
vertical-align middle
|
||||
padding 0 20px
|
||||
|
||||
.group-checkBoxSection
|
||||
margin-bottom 15px
|
||||
display flex
|
||||
line-height 30px
|
||||
padding-left 15px
|
||||
|
||||
.group-control
|
||||
padding-top 10px
|
||||
box-sizing border-box
|
||||
height 40px
|
||||
text-align right
|
||||
:global
|
||||
.alert
|
||||
display inline-block
|
||||
position absolute
|
||||
top 60px
|
||||
right 15px
|
||||
font-size 14px
|
||||
.success
|
||||
color #1EC38B
|
||||
.error
|
||||
color red
|
||||
.warning
|
||||
color #FFA500
|
||||
|
||||
.snippet-list
|
||||
width 30%
|
||||
height calc(100% - 200px)
|
||||
position absolute
|
||||
|
||||
.snippets
|
||||
height calc(100% - 8px)
|
||||
overflow scroll
|
||||
background: #f5f5f5
|
||||
|
||||
.snippet-item
|
||||
height 50px
|
||||
font-size 15px
|
||||
line-height 50px
|
||||
padding 0 5%
|
||||
cursor pointer
|
||||
position relative
|
||||
|
||||
&::after
|
||||
width 90%
|
||||
height 1px
|
||||
background rgba(0, 0, 0, 0.1)
|
||||
position absolute
|
||||
top 100%
|
||||
left 5%
|
||||
content ''
|
||||
|
||||
&:hover
|
||||
background darken(#f5f5f5, 5)
|
||||
|
||||
.snippet-item-selected
|
||||
@extend .snippet-list .snippet-item
|
||||
background darken(#f5f5f5, 5)
|
||||
|
||||
.snippet-detail
|
||||
width 67%
|
||||
height calc(100% - 200px)
|
||||
position absolute
|
||||
left 33%
|
||||
|
||||
.SnippetEditor
|
||||
position absolute
|
||||
width 100%
|
||||
height 90%
|
||||
|
||||
body[data-theme="default"], body[data-theme="white"]
|
||||
.snippets
|
||||
background $ui-backgroundColor
|
||||
.snippet-item
|
||||
color black
|
||||
&::after
|
||||
background $ui-borderColor
|
||||
&:hover
|
||||
background darken($ui-backgroundColor, 5)
|
||||
.snippet-item-selected
|
||||
background darken($ui-backgroundColor, 5)
|
||||
|
||||
body[data-theme="dark"]
|
||||
.snippets
|
||||
background $ui-dark-backgroundColor
|
||||
.snippet-item
|
||||
color white
|
||||
&::after
|
||||
background $ui-dark-borderColor
|
||||
&:hover
|
||||
background darken($ui-dark-backgroundColor, 5)
|
||||
.snippet-item-selected
|
||||
background darken($ui-dark-backgroundColor, 5)
|
||||
.snippet-detail
|
||||
color white
|
||||
.group-control-button
|
||||
colorDarkPrimaryButton()
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.snippets
|
||||
background $ui-solarized-dark-backgroundColor
|
||||
.snippet-item
|
||||
color white
|
||||
&::after
|
||||
background $ui-solarized-dark-borderColor
|
||||
&:hover
|
||||
background darken($ui-solarized-dark-backgroundColor, 5)
|
||||
.snippet-item-selected
|
||||
background darken($ui-solarized-dark-backgroundColor, 5)
|
||||
.snippet-detail
|
||||
color white
|
||||
.group-control-button
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.snippets
|
||||
background $ui-monokai-backgroundColor
|
||||
.snippet-item
|
||||
color White
|
||||
&::after
|
||||
background $ui-monokai-borderColor
|
||||
&:hover
|
||||
background darken($ui-monokai-backgroundColor, 5)
|
||||
.snippet-item-selected
|
||||
background darken($ui-monokai-backgroundColor, 5)
|
||||
.snippet-detail
|
||||
color white
|
||||
.group-control-button
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.snippets
|
||||
background $ui-dracula-backgroundColor
|
||||
.snippet-item
|
||||
color #f8f8f2
|
||||
&::after
|
||||
background $ui-dracula-borderColor
|
||||
&:hover
|
||||
background darken($ui-dracula-backgroundColor, 5)
|
||||
.snippet-item-selected
|
||||
background darken($ui-dracula-backgroundColor, 5)
|
||||
.snippet-detail
|
||||
color #f8f8f2
|
||||
.group-control-button
|
||||
colorDraculaPrimaryButton()
|
||||
@@ -4,7 +4,7 @@ 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 { store } from 'browser/main/store'
|
||||
import FolderList from './FolderList'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
|
||||
@@ -9,13 +9,17 @@
|
||||
box-sizing border-box
|
||||
border-bottom $default-border
|
||||
margin-bottom 5px
|
||||
display flex
|
||||
|
||||
.header-label
|
||||
float left
|
||||
cursor pointer
|
||||
&:hover
|
||||
.header-label-editButton
|
||||
opacity 1
|
||||
flex 1
|
||||
white-space nowrap
|
||||
text-overflow ellipsis
|
||||
overflow hidden
|
||||
|
||||
.header-label-path
|
||||
color $ui-inactive-text-color
|
||||
@@ -38,8 +42,8 @@
|
||||
outline none
|
||||
|
||||
.header-control
|
||||
float right
|
||||
|
||||
-webkit-box-flex: 1
|
||||
white-space nowrap
|
||||
.header-control-button
|
||||
width 30px
|
||||
height 25px
|
||||
|
||||
@@ -70,7 +70,7 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
return (
|
||||
<div styleName='list'>
|
||||
<div styleName='header'>{i18n.__('Storages')}</div>
|
||||
<div styleName='header'>{i18n.__('Storage Locations')}</div>
|
||||
{storageList.length > 0
|
||||
? storageList
|
||||
: <div styleName='list-empty'>{i18n.__('No storage found.')}</div>
|
||||
@@ -182,7 +182,7 @@ class StoragesTab extends React.Component {
|
||||
<div styleName='addStorage-body-section-path'>
|
||||
<input styleName='addStorage-body-section-path-input'
|
||||
ref='addStoragePath'
|
||||
placeholder='Select Folder'
|
||||
placeholder={i18n.__('Select Folder')}
|
||||
value={this.state.newStorage.path}
|
||||
onChange={(e) => this.handleAddStorageChange(e)}
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
@import('./Tab')
|
||||
|
||||
.root
|
||||
padding 15px
|
||||
color $ui-text-color
|
||||
@import('./ConfigTab')
|
||||
|
||||
.list
|
||||
margin-bottom 15px
|
||||
@@ -158,7 +154,7 @@ body[data-theme="dark"]
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-dark-borderColor
|
||||
|
||||
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
@@ -236,3 +232,41 @@ body[data-theme="monokai"]
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.folderList-item
|
||||
border-bottom $ui-dracula-borderColor
|
||||
|
||||
.folderList-empty
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.list-empty
|
||||
color $ui-dracula-text-color
|
||||
.list-control-addStorageButton
|
||||
border-color $ui-dracula-button-backgroundColor
|
||||
background-color $ui-dracula-button-backgroundColor
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.addStorage-header
|
||||
color $ui-dracula-text-color
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.addStorage-body-section-name-input
|
||||
border-color $$ui-dracula-borderColor
|
||||
|
||||
.addStorage-body-section-type-description
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.addStorage-body-section-path-button
|
||||
colorPrimaryButton()
|
||||
.addStorage-body-control
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.addStorage-body-control-createButton
|
||||
colorDarkPrimaryButton()
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-dracula-borderColor
|
||||
@@ -3,7 +3,7 @@ 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 { store } from 'browser/main/store'
|
||||
import consts from 'browser/lib/consts'
|
||||
import ReactCodeMirror from 'react-codemirror'
|
||||
import CodeMirror from 'codemirror'
|
||||
@@ -11,6 +11,7 @@ import 'codemirror-mode-elixir'
|
||||
import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import { getLanguages } from 'browser/lib/Languages'
|
||||
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
|
||||
@@ -28,6 +29,10 @@ class UiTab extends React.Component {
|
||||
|
||||
componentDidMount () {
|
||||
CodeMirror.autoLoadMode(this.codeMirrorInstance.getCodeMirror(), 'javascript')
|
||||
CodeMirror.autoLoadMode(this.customCSSCM.getCodeMirror(), 'css')
|
||||
CodeMirror.autoLoadMode(this.customMarkdownLintConfigCM.getCodeMirror(), 'javascript')
|
||||
this.customCSSCM.getCodeMirror().setSize('400px', '400px')
|
||||
this.customMarkdownLintConfigCM.getCodeMirror().setSize('400px', '200px')
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({UiAlert: {
|
||||
type: 'success',
|
||||
@@ -37,7 +42,7 @@ class UiTab extends React.Component {
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({UiAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('Error occurs!')
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
}
|
||||
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
@@ -64,9 +69,15 @@ class UiTab extends React.Component {
|
||||
ui: {
|
||||
theme: this.refs.uiTheme.value,
|
||||
language: this.refs.uiLanguage.value,
|
||||
defaultNote: this.refs.defaultNote.value,
|
||||
tagNewNoteWithFilteringTags: this.refs.tagNewNoteWithFilteringTags.checked,
|
||||
showCopyNotification: this.refs.showCopyNotification.checked,
|
||||
confirmDeletion: this.refs.confirmDeletion.checked,
|
||||
showOnlyRelatedTags: this.refs.showOnlyRelatedTags.checked,
|
||||
showTagsAlphabetically: this.refs.showTagsAlphabetically.checked,
|
||||
saveTagsAlphabetically: this.refs.saveTagsAlphabetically.checked,
|
||||
enableLiveNoteCounts: this.refs.enableLiveNoteCounts.checked,
|
||||
showMenuBar: this.refs.showMenuBar.checked,
|
||||
disableDirectWrite: this.refs.uiD2w != null
|
||||
? this.refs.uiD2w.checked
|
||||
: false
|
||||
@@ -82,8 +93,19 @@ class UiTab extends React.Component {
|
||||
displayLineNumbers: this.refs.editorDisplayLineNumbers.checked,
|
||||
switchPreview: this.refs.editorSwitchPreview.value,
|
||||
keyMap: this.refs.editorKeyMap.value,
|
||||
snippetDefaultLanguage: this.refs.editorSnippetDefaultLanguage.value,
|
||||
scrollPastEnd: this.refs.scrollPastEnd.checked,
|
||||
fetchUrlTitle: this.refs.editorFetchUrlTitle.checked
|
||||
fetchUrlTitle: this.refs.editorFetchUrlTitle.checked,
|
||||
enableTableEditor: this.refs.enableTableEditor.checked,
|
||||
enableFrontMatterTitle: this.refs.enableFrontMatterTitle.checked,
|
||||
frontMatterTitleField: this.refs.frontMatterTitleField.value,
|
||||
matchingPairs: this.refs.matchingPairs.value,
|
||||
matchingTriples: this.refs.matchingTriples.value,
|
||||
explodingPairs: this.refs.explodingPairs.value,
|
||||
spellcheck: this.refs.spellcheck.checked,
|
||||
enableSmartPaste: this.refs.enableSmartPaste.checked,
|
||||
enableMarkdownLint: this.refs.enableMarkdownLint.checked,
|
||||
customMarkdownLintConfig: this.customMarkdownLintConfigCM.getCodeMirror().getValue()
|
||||
},
|
||||
preview: {
|
||||
fontSize: this.refs.previewFontSize.value,
|
||||
@@ -96,17 +118,27 @@ class UiTab extends React.Component {
|
||||
latexBlockClose: this.refs.previewLatexBlockClose.value,
|
||||
plantUMLServerAddress: this.refs.previewPlantUMLServerAddress.value,
|
||||
scrollPastEnd: this.refs.previewScrollPastEnd.checked,
|
||||
scrollSync: this.refs.previewScrollSync.checked,
|
||||
smartQuotes: this.refs.previewSmartQuotes.checked,
|
||||
breaks: this.refs.previewBreaks.checked,
|
||||
sanitize: this.refs.previewSanitize.value
|
||||
smartArrows: this.refs.previewSmartArrows.checked,
|
||||
sanitize: this.refs.previewSanitize.value,
|
||||
allowCustomCSS: this.refs.previewAllowCustomCSS.checked,
|
||||
lineThroughCheckbox: this.refs.lineThroughCheckbox.checked,
|
||||
customCSS: this.customCSSCM.getCodeMirror().getValue()
|
||||
}
|
||||
}
|
||||
|
||||
const newCodemirrorTheme = this.refs.editorTheme.value
|
||||
|
||||
if (newCodemirrorTheme !== codemirrorTheme) {
|
||||
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`)
|
||||
const theme = consts.THEMES.find(theme => theme.name === newCodemirrorTheme)
|
||||
|
||||
if (theme) {
|
||||
checkHighLight.setAttribute('href', `../${theme.path}`)
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme }, () => {
|
||||
const {ui, editor, preview} = this.props.config
|
||||
this.currentConfig = {ui, editor, preview}
|
||||
@@ -116,7 +148,7 @@ class UiTab extends React.Component {
|
||||
this.props.haveToSave({
|
||||
tab: 'UI',
|
||||
type: 'warning',
|
||||
message: i18n.__('You have to save!')
|
||||
message: i18n.__('Unsaved Changes!')
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -159,13 +191,16 @@ class UiTab extends React.Component {
|
||||
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};'
|
||||
const enableEditRulersStyle = config.editor.enableRulers ? 'block' : 'none'
|
||||
const fontFamily = normalizeEditorFontFamily(config.editor.fontFamily)
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Interface')}</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
{i18n.__('Interface Theme')}
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Interface Theme')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.ui.theme}
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -175,13 +210,16 @@ class UiTab extends React.Component {
|
||||
<option value='white'>{i18n.__('White')}</option>
|
||||
<option value='solarized-dark'>{i18n.__('Solarized Dark')}</option>
|
||||
<option value='monokai'>{i18n.__('Monokai')}</option>
|
||||
<option value='dracula'>{i18n.__('Dracula')}</option>
|
||||
<option value='dark'>{i18n.__('Dark')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
{i18n.__('Language')}
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Language')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.ui.language}
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -194,6 +232,32 @@ class UiTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Default New Note')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.ui.defaultNote}
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
ref='defaultNote'
|
||||
>
|
||||
<option value='ALWAYS_ASK'>{i18n.__('Always Ask')}</option>
|
||||
<option value='MARKDOWN_NOTE'>{i18n.__('Markdown Note')}</option>
|
||||
<option value='SNIPPET_NOTE'>{i18n.__('Snippet Note')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.showMenuBar}
|
||||
ref='showMenuBar'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Show menu bar')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -214,16 +278,6 @@ class UiTab extends React.Component {
|
||||
{i18n.__('Show a confirmation dialog when deleting notes')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.showOnlyRelatedTags}
|
||||
ref='showOnlyRelatedTags'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Show only related tags')}
|
||||
</label>
|
||||
</div>
|
||||
{
|
||||
global.process.platform === 'win32'
|
||||
? <div styleName='group-checkBoxSection'>
|
||||
@@ -234,11 +288,69 @@ class UiTab extends React.Component {
|
||||
disabled={OSX}
|
||||
type='checkbox'
|
||||
/>
|
||||
Disable Direct Write(It will be applied after restarting)
|
||||
{i18n.__('Disable Direct Write (It will be applied after restarting)')}
|
||||
</label>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
|
||||
<div styleName='group-header2'>Tags</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.saveTagsAlphabetically}
|
||||
ref='saveTagsAlphabetically'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Save tags of a note in alphabetical order')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.showTagsAlphabetically}
|
||||
ref='showTagsAlphabetically'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Show tags of a note in alphabetical order')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.showOnlyRelatedTags}
|
||||
ref='showOnlyRelatedTags'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Show only related tags')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.enableLiveNoteCounts}
|
||||
ref='enableLiveNoteCounts'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable live count of notes')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.ui.tagNewNoteWithFilteringTags}
|
||||
ref='tagNewNoteWithFilteringTags'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('New notes are tagged with the filtering tags')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-header2'>Editor</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
@@ -252,12 +364,20 @@ class UiTab extends React.Component {
|
||||
>
|
||||
{
|
||||
themes.map((theme) => {
|
||||
return (<option value={theme} key={theme}>{theme}</option>)
|
||||
return (<option value={theme.name} key={theme.name}>{theme.name}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
<div styleName='code-mirror'>
|
||||
<ReactCodeMirror ref={e => (this.codeMirrorInstance = e)} value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} />
|
||||
<div styleName='code-mirror' style={{fontFamily}}>
|
||||
<ReactCodeMirror
|
||||
ref={e => (this.codeMirrorInstance = e)}
|
||||
value={codemirrorSampleCode}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
readOnly: true,
|
||||
mode: 'javascript',
|
||||
theme: codemirrorTheme
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -372,6 +492,48 @@ class UiTab extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Snippet Default Language')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.editor.snippetDefaultLanguage}
|
||||
ref='editorSnippetDefaultLanguage'
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
>
|
||||
<option key='Auto Detect' value='Auto Detect'>{i18n.__('Auto Detect')}</option>
|
||||
{
|
||||
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => (<option key={name} value={name}>{name}</option>))
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Front matter title field')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
ref='frontMatterTitleField'
|
||||
value={config.editor.frontMatterTitleField}
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.enableFrontMatterTitle}
|
||||
ref='enableFrontMatterTitle'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Extract title from front matter')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -405,6 +567,109 @@ class UiTab extends React.Component {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.enableTableEditor}
|
||||
ref='enableTableEditor'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable smart table editor')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.enableSmartPaste}
|
||||
ref='enableSmartPaste'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable HTML paste')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.spellcheck}
|
||||
ref='spellcheck'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable spellcheck - Experimental feature!! :)')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Matching character pairs')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
value={this.state.config.editor.matchingPairs}
|
||||
ref='matchingPairs'
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Matching character triples')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
value={this.state.config.editor.matchingTriples}
|
||||
ref='matchingTriples'
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Exploding character pairs')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
value={this.state.config.editor.explodingPairs}
|
||||
ref='explodingPairs'
|
||||
onChange={(e) => this.handleUIChange(e)}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Custom MarkdownLint Rules')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.enableMarkdownLint}
|
||||
ref='enableMarkdownLint'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable MarkdownLint')}
|
||||
<div style={{fontFamily, display: this.state.config.editor.enableMarkdownLint ? 'block' : 'none'}}>
|
||||
<ReactCodeMirror
|
||||
width='400px'
|
||||
height='200px'
|
||||
onChange={e => this.handleUIChange(e)}
|
||||
ref={e => (this.customMarkdownLintConfigCM = e)}
|
||||
value={config.editor.customMarkdownLintConfig}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
mode: 'application/json',
|
||||
theme: codemirrorTheme,
|
||||
lint: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers']
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-header2'>{i18n.__('Preview')}</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
@@ -432,8 +697,9 @@ class UiTab extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Code block Theme')}</div>
|
||||
<div styleName='group-section-label'>{i18n.__('Code Block Theme')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.preview.codeBlockTheme}
|
||||
ref='previewCodeBlockTheme'
|
||||
@@ -441,12 +707,22 @@ class UiTab extends React.Component {
|
||||
>
|
||||
{
|
||||
themes.map((theme) => {
|
||||
return (<option value={theme} key={theme}>{theme}</option>)
|
||||
return (<option value={theme.name} key={theme.name}>{theme.name}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.preview.lineThroughCheckbox}
|
||||
ref='lineThroughCheckbox'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Allow line through checkbox')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -457,6 +733,16 @@ class UiTab extends React.Component {
|
||||
{i18n.__('Allow preview to scroll past the last line')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.preview.scrollSync}
|
||||
ref='previewScrollSync'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('When scrolling, synchronize preview with editor')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -474,7 +760,7 @@ class UiTab extends React.Component {
|
||||
ref='previewSmartQuotes'
|
||||
type='checkbox'
|
||||
/>
|
||||
Enable smart quotes
|
||||
{i18n.__('Enable smart quotes')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
@@ -484,7 +770,17 @@ class UiTab extends React.Component {
|
||||
ref='previewBreaks'
|
||||
type='checkbox'
|
||||
/>
|
||||
Render newlines in Markdown paragraphs as <br>
|
||||
{i18n.__('Render newlines in Markdown paragraphs as <br>')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.preview.smartArrows}
|
||||
ref='previewSmartArrows'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -569,6 +865,33 @@ class UiTab extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Custom CSS')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={config.preview.allowCustomCSS}
|
||||
ref='previewAllowCustomCSS'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Allow custom CSS for preview')}
|
||||
<div style={{fontFamily}}>
|
||||
<ReactCodeMirror
|
||||
width='400px'
|
||||
height='400px'
|
||||
onChange={e => this.handleUIChange(e)}
|
||||
ref={e => (this.customCSSCM = e)}
|
||||
value={config.preview.customCSS}
|
||||
defaultValue={'/* Drop Your Custom CSS Code Here */\n'}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
mode: 'css',
|
||||
theme: codemirrorTheme
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
|
||||
@@ -6,6 +6,7 @@ import UiTab from './UiTab'
|
||||
import InfoTab from './InfoTab'
|
||||
import Crowdfunding from './Crowdfunding'
|
||||
import StoragesTab from './StoragesTab'
|
||||
import SnippetTab from './SnippetTab'
|
||||
import Blog from './Blog'
|
||||
import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
@@ -86,6 +87,14 @@ class Preferences extends React.Component {
|
||||
haveToSave={alert => this.setState({BlogAlert: alert})}
|
||||
/>
|
||||
)
|
||||
case 'SNIPPET':
|
||||
return (
|
||||
<SnippetTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
data={data}
|
||||
/>
|
||||
)
|
||||
case 'STORAGES':
|
||||
default:
|
||||
return (
|
||||
@@ -123,7 +132,8 @@ class Preferences extends React.Component {
|
||||
{target: 'UI', label: i18n.__('Interface'), UI: this.state.UIAlert},
|
||||
{target: 'INFO', label: i18n.__('About')},
|
||||
{target: 'CROWDFUNDING', label: i18n.__('Crowdfunding')},
|
||||
{target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert}
|
||||
{target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert},
|
||||
{target: 'SNIPPET', label: i18n.__('Snippets')}
|
||||
]
|
||||
|
||||
const navButtons = tabs.map((tab) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './RenameFolderModal.styl'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import store from 'browser/main/store'
|
||||
import { store } from 'browser/main/store'
|
||||
import ModalEscButton from 'browser/components/ModalEscButton'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user