mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-15 02:36:36 +00:00
Merge branch 'master' into export-yfm
This commit is contained in:
@@ -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'
|
||||
@@ -11,7 +11,7 @@ const electron = require('electron')
|
||||
const { shell } = electron
|
||||
const ipc = electron.ipcRenderer
|
||||
class Blog extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,12 +20,12 @@ class Blog extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
clearMessage () {
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
BlogAlert: null
|
||||
@@ -33,30 +33,41 @@ class Blog extends React.Component {
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({BlogAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
this.setState({
|
||||
BlogAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
this.setState({BlogAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}})
|
||||
this.handleSettingError = err => {
|
||||
this.setState({
|
||||
BlogAlert: {
|
||||
type: 'error',
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.oldBlog = this.state.config.blog
|
||||
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleBlogChange (e) {
|
||||
handleBlogChange(e) {
|
||||
const { config } = this.state
|
||||
config.blog = {
|
||||
password: !_.isNil(this.refs.passwordInput) ? this.refs.passwordInput.value : config.blog.password,
|
||||
username: !_.isNil(this.refs.usernameInput) ? this.refs.usernameInput.value : config.blog.username,
|
||||
token: !_.isNil(this.refs.tokenInput) ? this.refs.tokenInput.value : config.blog.token,
|
||||
password: !_.isNil(this.refs.passwordInput)
|
||||
? this.refs.passwordInput.value
|
||||
: config.blog.password,
|
||||
username: !_.isNil(this.refs.usernameInput)
|
||||
? this.refs.usernameInput.value
|
||||
: config.blog.username,
|
||||
token: !_.isNil(this.refs.tokenInput)
|
||||
? this.refs.tokenInput.value
|
||||
: config.blog.token,
|
||||
authMethod: this.refs.authMethodDropdown.value,
|
||||
address: this.refs.addressInput.value,
|
||||
type: this.refs.typeDropdown.value
|
||||
@@ -75,7 +86,7 @@ class Blog extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
blog: this.state.config.blog
|
||||
}
|
||||
@@ -90,36 +101,36 @@ class Blog extends React.Component {
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
render () {
|
||||
const {config, BlogAlert} = this.state
|
||||
const blogAlertElement = BlogAlert != null
|
||||
? <p className={`alert ${BlogAlert.type}`}>
|
||||
{BlogAlert.message}
|
||||
</p>
|
||||
: null
|
||||
render() {
|
||||
const { config, BlogAlert } = this.state
|
||||
const blogAlertElement =
|
||||
BlogAlert != null ? (
|
||||
<p className={`alert ${BlogAlert.type}`}>{BlogAlert.message}</p>
|
||||
) : null
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Blog')}</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Blog Type')}
|
||||
</div>
|
||||
<div styleName='group-section-label'>{i18n.__('Blog Type')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select
|
||||
value={config.blog.type}
|
||||
ref='typeDropdown'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
>
|
||||
<option value='wordpress' key='wordpress'>{i18n.__('wordpress')}</option>
|
||||
<option value='wordpress' key='wordpress'>
|
||||
{i18n.__('wordpress')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Blog Address')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='addressInput'
|
||||
value={config.blog.address}
|
||||
type='text'
|
||||
@@ -127,8 +138,11 @@ class Blog extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{blogAlertElement}
|
||||
</div>
|
||||
@@ -143,49 +157,59 @@ class Blog extends React.Component {
|
||||
<select
|
||||
value={config.blog.authMethod}
|
||||
ref='authMethodDropdown'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
>
|
||||
<option value='JWT' key='JWT'>{i18n.__('JWT')}</option>
|
||||
<option value='USER' key='USER'>{i18n.__('USER')}</option>
|
||||
<option value='JWT' key='JWT'>
|
||||
{i18n.__('JWT')}
|
||||
</option>
|
||||
<option value='USER' key='USER'>
|
||||
{i18n.__('USER')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{ config.blog.authMethod === 'JWT' &&
|
||||
{config.blog.authMethod === 'JWT' && (
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Token')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='tokenInput'
|
||||
value={config.blog.token}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ config.blog.authMethod === 'USER' &&
|
||||
)}
|
||||
{config.blog.authMethod === 'USER' && (
|
||||
<div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('UserName')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='usernameInput'
|
||||
value={config.blog.username}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Password')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleBlogChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleBlogChange(e)}
|
||||
ref='passwordInput'
|
||||
value={config.blog.password}
|
||||
type='password' />
|
||||
type='password'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,111 @@
|
||||
@import('./Tab')
|
||||
|
||||
.container
|
||||
display flex
|
||||
flex-direction column
|
||||
align-items center
|
||||
justify-content center
|
||||
position relative
|
||||
margin-bottom 2em
|
||||
margin-left 2em
|
||||
|
||||
.box-minmax
|
||||
width 608px
|
||||
height 45px
|
||||
display flex
|
||||
justify-content space-between
|
||||
font-size $tab--button-font-size
|
||||
color $ui-text-color
|
||||
span first-child
|
||||
margin-top 18px
|
||||
padding-right 10px
|
||||
padding-left 10px
|
||||
padding-top 8px
|
||||
position relative
|
||||
border $ui-borderColor
|
||||
border-radius 5px
|
||||
background $ui-backgroundColor
|
||||
|
||||
div[id^="secondRow"]
|
||||
position absolute
|
||||
z-index 2
|
||||
left 0
|
||||
top 0
|
||||
margin-bottom -42px
|
||||
.rs-label
|
||||
margin-left -20px
|
||||
|
||||
div[id^="firstRow"]
|
||||
position absolute
|
||||
z-index 2
|
||||
left 0
|
||||
top 0
|
||||
margin-bottom -25px
|
||||
.rs-range
|
||||
&::-webkit-slider-thumb
|
||||
margin-top 0px
|
||||
transform rotate(180deg)
|
||||
.rs-label
|
||||
margin-bottom -85px
|
||||
margin-top 85px
|
||||
|
||||
|
||||
.rs-range
|
||||
margin-top 29px
|
||||
width 600px
|
||||
-webkit-appearance none
|
||||
&:focus
|
||||
outline black
|
||||
&::-webkit-slider-runnable-track
|
||||
width 100%
|
||||
height 0.1px
|
||||
cursor pointer
|
||||
box-shadow none
|
||||
background $ui-backgroundColor
|
||||
border-radius 0px
|
||||
border 0px solid #010101
|
||||
cursor none
|
||||
|
||||
&::-webkit-slider-thumb
|
||||
box-shadow none
|
||||
border 1px solid $ui-borderColor
|
||||
box-shadow 0px 10px 10px rgba(0, 0, 0, 0.25)
|
||||
height 32px
|
||||
width 32px
|
||||
border-radius 22px
|
||||
background white
|
||||
cursor pointer
|
||||
-webkit-appearance none
|
||||
margin-top -20px
|
||||
border-color $ui-default-button-backgroundColor
|
||||
height 32px
|
||||
border-top-left-radius 10%
|
||||
border-top-right-radius 10%
|
||||
|
||||
.rs-label
|
||||
position relative
|
||||
transform-origin center center
|
||||
display block
|
||||
background transparent
|
||||
border-radius none
|
||||
line-height 30px
|
||||
font-weight normal
|
||||
box-sizing border-box
|
||||
border none
|
||||
margin-bottom -5px
|
||||
margin-top -10px
|
||||
clear both
|
||||
float left
|
||||
height 17px
|
||||
margin-left -25px
|
||||
left attr(value)
|
||||
color $ui-text-color
|
||||
font-style normal
|
||||
font-weight normal
|
||||
line-height normal
|
||||
font-size $tab--button-font-size
|
||||
.root
|
||||
padding 15px
|
||||
color $ui-text-color
|
||||
margin-bottom 30px
|
||||
|
||||
.group
|
||||
@@ -14,10 +117,17 @@
|
||||
|
||||
.group-header2
|
||||
font-size 20px
|
||||
color $ui-text-color
|
||||
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
|
||||
@@ -128,30 +238,30 @@ colorDarkControl()
|
||||
background-color $ui-dark-backgroundColor
|
||||
color $ui-dark-text-color
|
||||
|
||||
colorSolarizedDarkControl()
|
||||
colorThemedControl(theme)
|
||||
border none
|
||||
background-color $ui-solarized-dark-button-backgroundColor
|
||||
color $ui-solarized-dark-text-color
|
||||
background-color get-theme-var(theme, 'button-backgroundColor')
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
colorMonokaiControl()
|
||||
border none
|
||||
background-color $ui-monokai-button-backgroundColor
|
||||
color $ui-monokai-text-color
|
||||
body[data-theme="default"],
|
||||
body[data-theme="white"]
|
||||
.root
|
||||
color $ui-text-color
|
||||
|
||||
colorDraculaControl()
|
||||
border none
|
||||
background-color $ui-dracula-button-backgroundColor
|
||||
color $ui-dracula-text-color
|
||||
.group-header2
|
||||
color $ui-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
|
||||
@@ -169,85 +279,44 @@ body[data-theme="dark"]
|
||||
.group-section-control
|
||||
select, .group-section-control-input
|
||||
colorDarkControl()
|
||||
.rs-label
|
||||
color $ui-dark-text-color
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
color $ui-solarized-dark-text-color
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.root
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.group-header
|
||||
color $ui-solarized-dark-text-color
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
.group-header
|
||||
.group-header--sub
|
||||
color get-theme-var(theme, 'text-color')
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
|
||||
.group-header2
|
||||
color $ui-solarized-dark-text-color
|
||||
.group-header2
|
||||
.group-header2--sub
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.group-section-control-input
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
.group-section-control-input
|
||||
border-color get-theme-var(theme, '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()
|
||||
.group-control
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
.group-control-leftButton
|
||||
colorDarkDefaultButton()
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
.group-control-rightButton
|
||||
colorThemedPrimaryButton(theme)
|
||||
.group-hint
|
||||
colorThemedControl(theme)
|
||||
.group-section-control
|
||||
select, .group-section-control-input
|
||||
colorThemedControl(theme)
|
||||
.rs-label
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
color $ui-monokai-text-color
|
||||
for theme in 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
.group-header
|
||||
color $ui-monokai-text-color
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
.group-header2
|
||||
color $ui-monokai-text-color
|
||||
|
||||
.group-section-control-input
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
.group-control
|
||||
border-color $ui-monokai-borderColor
|
||||
.group-control-leftButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-monokai-borderColor
|
||||
.group-control-rightButton
|
||||
colorMonokaiPrimaryButton()
|
||||
.group-hint
|
||||
colorMonokaiControl()
|
||||
.group-section-control
|
||||
select, .group-section-control-input
|
||||
colorMonokaiControl()
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
|
||||
.group-header
|
||||
color $ui-dracula-text-color
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.group-header2
|
||||
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()
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
|
||||
@@ -7,52 +7,93 @@ const electron = require('electron')
|
||||
const { shell } = electron
|
||||
|
||||
class Crowdfunding extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
}
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='header'>{i18n.__('Crowdfunding')}</div>
|
||||
<div styleName='group-header'>{i18n.__('Crowdfunding')}</div>
|
||||
<p>{i18n.__('Thank you for using Boostnote!')}</p>
|
||||
<br />
|
||||
<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>
|
||||
<br />
|
||||
<p>{i18n.__('### Sustainable Open Source Ecosystem')}</p>
|
||||
<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>
|
||||
<br />
|
||||
<p>{i18n.__('### We believe Meritocracy')}</p>
|
||||
<p>{i18n.__('We think developers who has skill and did 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.__(
|
||||
'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>
|
||||
<p>
|
||||
{i18n.__(
|
||||
'We’ve realized IssueHunt could enhance sustainability of open-source ecosystem.'
|
||||
)}
|
||||
</p>
|
||||
<br />
|
||||
<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>
|
||||
<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.__('Thank you,')}</p>
|
||||
<p>{i18n.__('The Boostnote Team')}</p>
|
||||
<br />
|
||||
<button styleName='cf-link'>
|
||||
<a href='http://bit.ly/issuehunt-from-boostnote-app' onClick={(e) => this.handleLinkClick(e)}>{i18n.__('See IssueHunt')}</a>
|
||||
<a
|
||||
href='http://bit.ly/issuehunt-from-boostnote-app'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('See IssueHunt')}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Crowdfunding.propTypes = {
|
||||
}
|
||||
Crowdfunding.propTypes = {}
|
||||
|
||||
export default CSSModules(Crowdfunding, styles)
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
@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
|
||||
height 35px
|
||||
@@ -30,20 +24,15 @@ 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
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.root
|
||||
color get-theme-var(theme, 'text-color')
|
||||
p
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
color $ui-monokai-text-color
|
||||
p
|
||||
color $ui-monokai-text-color
|
||||
for theme in 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
p
|
||||
color $ui-dracula-text-color
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
@@ -11,7 +11,7 @@ const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
class ExportTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -19,7 +19,7 @@ class ExportTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
clearMessage () {
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
ExportAlert: null
|
||||
@@ -27,7 +27,7 @@ class ExportTab extends React.Component {
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({
|
||||
ExportAlert: {
|
||||
@@ -36,11 +36,12 @@ class ExportTab extends React.Component {
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
this.handleSettingError = err => {
|
||||
this.setState({
|
||||
ExportAlert: {
|
||||
type: 'error',
|
||||
message: err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -51,12 +52,12 @@ class ExportTab extends React.Component {
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
export: this.state.config.export
|
||||
}
|
||||
@@ -72,12 +73,14 @@ class ExportTab extends React.Component {
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
handleExportChange (e) {
|
||||
handleExportChange(e) {
|
||||
const { config } = this.state
|
||||
|
||||
config.export = {
|
||||
metadata: this.refs.metadata.value,
|
||||
variable: !_.isNil(this.refs.variable) ? this.refs.variable.value : config.export.variable,
|
||||
variable: !_.isNil(this.refs.variable)
|
||||
? this.refs.variable.value
|
||||
: config.export.variable,
|
||||
prefixAttachmentFolder: this.refs.prefixAttachmentFolder.checked
|
||||
}
|
||||
|
||||
@@ -96,14 +99,13 @@ class ExportTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { config, ExportAlert } = this.state
|
||||
|
||||
const ExportAlertElement = ExportAlert != null
|
||||
? <p className={`alert ${ExportAlert.type}`}>
|
||||
{ExportAlert.message}
|
||||
</p>
|
||||
: null
|
||||
const ExportAlertElement =
|
||||
ExportAlert != null ? (
|
||||
<p className={`alert ${ExportAlert.type}`}>{ExportAlert.message}</p>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<div styleName='root'>
|
||||
@@ -111,48 +113,60 @@ class ExportTab extends React.Component {
|
||||
<div styleName='group-header'>{i18n.__('Export')}</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Metadata')}
|
||||
</div>
|
||||
<div styleName='group-section-label'>{i18n.__('Metadata')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select value={config.export.metadata}
|
||||
onChange={(e) => this.handleExportChange(e)}
|
||||
<select
|
||||
value={config.export.metadata}
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
ref='metadata'
|
||||
>
|
||||
<option value='DONT_EXPORT'>{i18n.__(`Don't export`)}</option>
|
||||
<option value='MERGE_HEADER'>{i18n.__('Merge with the header')}</option>
|
||||
<option value='MERGE_VARIABLE'>{i18n.__('Merge with a variable')}</option>
|
||||
<option value='MERGE_HEADER'>
|
||||
{i18n.__('Merge with the header')}
|
||||
</option>
|
||||
<option value='MERGE_VARIABLE'>
|
||||
{i18n.__('Merge with a variable')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ config.export.metadata === 'MERGE_VARIABLE' &&
|
||||
{config.export.metadata === 'MERGE_VARIABLE' && (
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Variable Name')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Variable Name')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleExportChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
ref='variable'
|
||||
value={config.export.variable}
|
||||
type='text' />
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleExportChange(e)}
|
||||
<input
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
checked={config.export.prefixAttachmentFolder}
|
||||
ref='prefixAttachmentFolder'
|
||||
type='checkbox'
|
||||
/>
|
||||
/>
|
||||
|
||||
{i18n.__('Prefix attachment folder')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{ExportAlertElement}
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,13 @@ 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'
|
||||
|
||||
class FolderItem extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -24,7 +24,7 @@ class FolderItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleEditChange (e) {
|
||||
handleEditChange(e) {
|
||||
const { folder } = this.state
|
||||
|
||||
folder.name = this.refs.nameInput.value
|
||||
@@ -33,18 +33,18 @@ class FolderItem extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleConfirmButtonClick (e) {
|
||||
handleConfirmButtonClick(e) {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
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) => {
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
@@ -55,9 +55,12 @@ class FolderItem extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleColorButtonClick (e) {
|
||||
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
|
||||
this.setState({ folder }, function () {
|
||||
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
|
||||
@@ -67,30 +70,32 @@ class FolderItem extends React.Component {
|
||||
const folder = Object.assign({}, this.state.folder, {
|
||||
colorPickerPos: {
|
||||
left: 25,
|
||||
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
||||
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
|
||||
}
|
||||
})
|
||||
this.setState({ folder })
|
||||
})
|
||||
}
|
||||
|
||||
handleColorChange (color) {
|
||||
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 })
|
||||
handleColorPickerClose(event) {
|
||||
const folder = Object.assign({}, this.state.folder, {
|
||||
showColumnPicker: false
|
||||
})
|
||||
this.setState({ folder })
|
||||
}
|
||||
|
||||
handleCancelButtonClick (e) {
|
||||
handleCancelButtonClick(e) {
|
||||
this.setState({
|
||||
status: 'IDLE'
|
||||
})
|
||||
}
|
||||
|
||||
handleFolderItemBlur (e) {
|
||||
handleFolderItemBlur(e) {
|
||||
let el = e.relatedTarget
|
||||
while (el != null) {
|
||||
if (el === this.refs.root) {
|
||||
@@ -101,7 +106,7 @@ class FolderItem extends React.Component {
|
||||
this.confirm()
|
||||
}
|
||||
|
||||
renderEdit (e) {
|
||||
renderEdit(e) {
|
||||
const popover = { position: 'absolute', zIndex: 2 }
|
||||
const cover = {
|
||||
position: 'fixed',
|
||||
@@ -110,51 +115,64 @@ class FolderItem extends React.Component {
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}
|
||||
const pickerStyle = Object.assign({}, {
|
||||
position: 'absolute'
|
||||
}, this.state.folder.colorPickerPos)
|
||||
const pickerStyle = Object.assign(
|
||||
{},
|
||||
{
|
||||
position: 'absolute'
|
||||
},
|
||||
this.state.folder.colorPickerPos
|
||||
)
|
||||
return (
|
||||
<div styleName='folderItem'
|
||||
onBlur={(e) => this.handleFolderItemBlur(e)}
|
||||
<div
|
||||
styleName='folderItem'
|
||||
onBlur={e => this.handleFolderItemBlur(e)}
|
||||
tabIndex='-1'
|
||||
ref='root'
|
||||
>
|
||||
<div styleName='folderItem-left'>
|
||||
<button styleName='folderItem-left-colorButton' style={{color: this.state.folder.color}}
|
||||
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-left-colorButton'
|
||||
style={{ color: this.state.folder.color }}
|
||||
onClick={e =>
|
||||
!this.state.folder.showColumnPicker &&
|
||||
this.handleColorButtonClick(e)
|
||||
}
|
||||
>
|
||||
{this.state.folder.showColumnPicker
|
||||
? <div style={popover}>
|
||||
<div style={cover}
|
||||
{this.state.folder.showColumnPicker ? (
|
||||
<div style={popover}>
|
||||
<div
|
||||
style={cover}
|
||||
onClick={() => this.handleColorPickerClose()}
|
||||
/>
|
||||
<div style={pickerStyle}>
|
||||
<SketchPicker
|
||||
ref='colorPicker'
|
||||
color={this.state.folder.color}
|
||||
onChange={(color) => this.handleColorChange(color)}
|
||||
onChangeComplete={(color) => this.handleColorChange(color)}
|
||||
onChange={color => this.handleColorChange(color)}
|
||||
onChangeComplete={color => this.handleColorChange(color)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
) : null}
|
||||
<i className='fa fa-square' />
|
||||
</button>
|
||||
<input styleName='folderItem-left-nameInput'
|
||||
<input
|
||||
styleName='folderItem-left-nameInput'
|
||||
value={this.state.folder.name}
|
||||
ref='nameInput'
|
||||
onChange={(e) => this.handleEditChange(e)}
|
||||
onChange={e => this.handleEditChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-confirmButton'
|
||||
onClick={(e) => this.handleConfirmButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-confirmButton'
|
||||
onClick={e => this.handleConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
@@ -163,79 +181,85 @@ class FolderItem extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
handleDeleteConfirmButtonClick (e) {
|
||||
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
|
||||
})
|
||||
dataApi.deleteFolder(storage.key, folder.key).then(data => {
|
||||
store.dispatch({
|
||||
type: 'DELETE_FOLDER',
|
||||
storage: data.storage,
|
||||
folderKey: data.folderKey
|
||||
})
|
||||
}
|
||||
|
||||
renderDelete () {
|
||||
return (
|
||||
<div styleName='folderItem'>
|
||||
<div styleName='folderItem-left'>
|
||||
{i18n.__('Are you sure to ')} <span styleName='folderItem-left-danger'>{i18n.__(' delete')}</span> {i18n.__('this folder?')}
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-dangerButton'
|
||||
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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) {
|
||||
renderDelete() {
|
||||
return (
|
||||
<div styleName='folderItem'>
|
||||
<div styleName='folderItem-left'>
|
||||
{i18n.__('Are you sure to ')}{' '}
|
||||
<span styleName='folderItem-left-danger'>{i18n.__(' delete')}</span>{' '}
|
||||
{i18n.__('this folder?')}
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button
|
||||
styleName='folderItem-right-dangerButton'
|
||||
onClick={e => this.handleDeleteConfirmButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Confirm')}
|
||||
</button>
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleCancelButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
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 () {
|
||||
renderIdle() {
|
||||
const { folder } = this.props
|
||||
return (
|
||||
<div styleName='folderItem'
|
||||
onDoubleClick={(e) => this.handleEditButtonClick(e)}
|
||||
<div
|
||||
styleName='folderItem'
|
||||
onDoubleClick={e => this.handleEditButtonClick(e)}
|
||||
>
|
||||
<div styleName='folderItem-left'
|
||||
style={{borderColor: folder.color}}
|
||||
>
|
||||
<span styleName='folderItem-left-name'>{folder.name}</span>
|
||||
<div styleName='folderItem-left' style={{ borderColor: folder.color }}>
|
||||
<span>{folder.name}</span>
|
||||
<span styleName='folderItem-left-key'>({folder.key})</span>
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleEditButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleEditButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Edit')}
|
||||
</button>
|
||||
<button styleName='folderItem-right-button'
|
||||
onClick={(e) => this.handleDeleteButtonClick(e)}
|
||||
<button
|
||||
styleName='folderItem-right-button'
|
||||
onClick={e => this.handleDeleteButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Delete')}
|
||||
</button>
|
||||
@@ -244,7 +268,7 @@ class FolderItem extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
switch (this.state.status) {
|
||||
case 'DELETE':
|
||||
return this.renderDelete()
|
||||
@@ -277,7 +301,7 @@ FolderItem.propTypes = {
|
||||
}
|
||||
|
||||
class Handle extends React.Component {
|
||||
render () {
|
||||
render() {
|
||||
return (
|
||||
<div styleName='folderItem-drag-handle'>
|
||||
<i className='fa fa-reorder' />
|
||||
@@ -287,11 +311,11 @@ class Handle extends React.Component {
|
||||
}
|
||||
|
||||
class SortableFolderItemComponent extends React.Component {
|
||||
render () {
|
||||
const StyledHandle = CSSModules(Handle, this.props.styles)
|
||||
render() {
|
||||
const StyledHandle = CSSModules(Handle, styles)
|
||||
const DragHandle = SortableHandle(StyledHandle)
|
||||
|
||||
const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
|
||||
const StyledFolderItem = CSSModules(FolderItem, styles)
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
.folderItem-right-button
|
||||
vertical-align middle
|
||||
height 25px
|
||||
margin-top 2.5px
|
||||
margin-top 2px
|
||||
colorDefaultButton()
|
||||
border-radius 2px
|
||||
border $ui-border
|
||||
@@ -107,73 +107,32 @@ body[data-theme="dark"]
|
||||
.folderItem-right-dangerButton
|
||||
colorDarkDangerButton()
|
||||
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.folderItem
|
||||
&:hover
|
||||
background-color get-theme-var(theme, 'button-backgroundColor')
|
||||
|
||||
.folderItem-left-danger
|
||||
color $danger-color
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.folderItem
|
||||
&:hover
|
||||
background-color $ui-solarized-dark-button-backgroundColor
|
||||
.folderItem-left-key
|
||||
color $ui-dark-inactive-text-color
|
||||
|
||||
.folderItem-left-danger
|
||||
color $danger-color
|
||||
.folderItem-left-colorButton
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
.folderItem-left-key
|
||||
color $ui-dark-inactive-text-color
|
||||
.folderItem-right-button
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
.folderItem-left-colorButton
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
.folderItem-right-confirmButton
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
.folderItem-right-button
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
.folderItem-right-dangerButton
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
.folderItem-right-confirmButton
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
for theme in 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
.folderItem-right-dangerButton
|
||||
colorSolarizedDarkPrimaryButton()
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.folderItem
|
||||
&:hover
|
||||
background-color $ui-monokai-button-backgroundColor
|
||||
|
||||
.folderItem-left-danger
|
||||
color $danger-color
|
||||
|
||||
.folderItem-left-key
|
||||
color $ui-dark-inactive-text-color
|
||||
|
||||
.folderItem-left-colorButton
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
.folderItem-right-button
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
.folderItem-right-confirmButton
|
||||
colorMonokaiPrimaryButton()
|
||||
|
||||
.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()
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
@@ -3,30 +3,34 @@ 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'
|
||||
|
||||
class FolderList extends React.Component {
|
||||
render () {
|
||||
render() {
|
||||
const { storage, hostBoundingBox } = this.props
|
||||
|
||||
const folderList = storage.folders.map((folder, index) => {
|
||||
return <FolderItem key={folder.key}
|
||||
folder={folder}
|
||||
storage={storage}
|
||||
index={index}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
return (
|
||||
<FolderItem
|
||||
key={folder.key}
|
||||
folder={folder}
|
||||
storage={storage}
|
||||
index={index}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div styleName='folderList'>
|
||||
{folderList.length > 0
|
||||
? folderList
|
||||
: <div styleName='folderList-empty'>{i18n.__('No Folders')}</div>
|
||||
}
|
||||
<div>
|
||||
{folderList.length > 0 ? (
|
||||
folderList
|
||||
) : (
|
||||
<div styleName='folderList-empty'>{i18n.__('No Folders')}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -52,23 +56,21 @@ FolderList.propTypes = {
|
||||
}
|
||||
|
||||
class SortableFolderListComponent extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.onSortEnd = ({oldIndex, newIndex}) => {
|
||||
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()
|
||||
dataApi.reorderFolder(storage.key, oldIndex, newIndex).then(data => {
|
||||
store.dispatch({
|
||||
type: 'REORDER_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
this.setState()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const StyledFolderList = CSSModules(FolderList, this.props.styles)
|
||||
const SortableFolderList = SortableContainer(StyledFolderList)
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -11,7 +11,7 @@ const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
class HotkeyTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,27 +20,35 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
}
|
||||
this.handleSettingError = (err) => {
|
||||
if (
|
||||
this.state.config.hotkey.toggleMain === '' ||
|
||||
this.state.config.hotkey.toggleMode === ''
|
||||
) {
|
||||
this.setState({keymapAlert: {
|
||||
this.setState({
|
||||
keymapAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}})
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = err => {
|
||||
if (
|
||||
this.state.config.hotkey.toggleMain === '' ||
|
||||
this.state.config.hotkey.toggleMode === '' ||
|
||||
this.state.config.hotkey.toggleDirection === ''
|
||||
) {
|
||||
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.setState({
|
||||
keymapAlert: {
|
||||
type: 'error',
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
this.oldHotkey = this.state.config.hotkey
|
||||
@@ -48,12 +56,12 @@ class HotkeyTab extends React.Component {
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
hotkey: this.state.config.hotkey
|
||||
}
|
||||
@@ -68,20 +76,25 @@ class HotkeyTab extends React.Component {
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
handleHintToggleButtonClick (e) {
|
||||
handleHintToggleButtonClick(e) {
|
||||
this.setState({
|
||||
isHotkeyHintOpen: !this.state.isHotkeyHintOpen
|
||||
})
|
||||
}
|
||||
|
||||
handleHotkeyChange (e) {
|
||||
handleHotkeyChange(e) {
|
||||
const { config } = this.state
|
||||
config.hotkey = {
|
||||
config.hotkey = Object.assign({}, config.hotkey, {
|
||||
toggleMain: this.refs.toggleMain.value,
|
||||
toggleMode: this.refs.toggleMode.value,
|
||||
toggleDirection: this.refs.toggleDirection.value,
|
||||
deleteNote: this.refs.deleteNote.value,
|
||||
pasteSmartly: this.refs.pasteSmartly.value
|
||||
}
|
||||
pasteSmartly: this.refs.pasteSmartly.value,
|
||||
prettifyMarkdown: this.refs.prettifyMarkdown.value,
|
||||
toggleMenuBar: this.refs.toggleMenuBar.value,
|
||||
insertDate: this.refs.insertDate.value,
|
||||
insertDateTime: this.refs.insertDateTime.value
|
||||
})
|
||||
this.setState({
|
||||
config
|
||||
})
|
||||
@@ -96,7 +109,7 @@ class HotkeyTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
clearMessage () {
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
keymapAlert: null
|
||||
@@ -104,13 +117,12 @@ class HotkeyTab extends React.Component {
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const keymapAlert = this.state.keymapAlert
|
||||
const keymapAlertElement = keymapAlert != null
|
||||
? <p className={`alert ${keymapAlert.type}`}>
|
||||
{keymapAlert.message}
|
||||
</p>
|
||||
: null
|
||||
const keymapAlertElement =
|
||||
keymapAlert != null ? (
|
||||
<p className={`alert ${keymapAlert.type}`}>{keymapAlert.message}</p>
|
||||
) : null
|
||||
const { config } = this.state
|
||||
|
||||
return (
|
||||
@@ -118,10 +130,13 @@ class HotkeyTab extends React.Component {
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Hotkeys')}</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Show/Hide Boostnote')}</div>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Show/Hide Boostnote')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleMain'
|
||||
value={config.hotkey.toggleMain}
|
||||
type='text'
|
||||
@@ -129,21 +144,53 @@ 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)}
|
||||
<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)}
|
||||
ref='toggleMode'
|
||||
value={config.hotkey.toggleMode}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Toggle Direction')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='toggleDirection'
|
||||
value={config.hotkey.toggleDirection}
|
||||
type='text'
|
||||
/>
|
||||
</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)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='deleteNote'
|
||||
value={config.hotkey.deleteNote}
|
||||
type='text'
|
||||
@@ -153,53 +200,139 @@ class HotkeyTab extends React.Component {
|
||||
<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)}
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='pasteSmartly'
|
||||
value={config.hotkey.pasteSmartly}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Prettify Markdown')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleHotkeyChange(e)}
|
||||
ref='prettifyMarkdown'
|
||||
value={config.hotkey.prettifyMarkdown}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Insert Current Date')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
ref='insertDate'
|
||||
value={config.hotkey.insertDate}
|
||||
type='text'
|
||||
disabled='true'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Insert Current Date and Time')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
ref='insertDateTime'
|
||||
value={config.hotkey.insertDateTime}
|
||||
type='text'
|
||||
disabled='true'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-leftButton'
|
||||
onClick={(e) => this.handleHintToggleButtonClick(e)}
|
||||
<button
|
||||
styleName='group-control-leftButton'
|
||||
onClick={e => this.handleHintToggleButtonClick(e)}
|
||||
>
|
||||
{this.state.isHotkeyHintOpen
|
||||
? i18n.__('Hide Help')
|
||||
: i18n.__('Help')
|
||||
}
|
||||
: i18n.__('Help')}
|
||||
</button>
|
||||
<button styleName='group-control-rightButton'
|
||||
onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{keymapAlertElement}
|
||||
</div>
|
||||
{this.state.isHotkeyHintOpen &&
|
||||
{this.state.isHotkeyHintOpen && (
|
||||
<div styleName='group-hint'>
|
||||
<p>{i18n.__('Available Keys')}</p>
|
||||
<ul>
|
||||
<li><code>0</code> to <code>9</code></li>
|
||||
<li><code>A</code> to <code>Z</code></li>
|
||||
<li><code>F1</code> to <code>F24</code></li>
|
||||
<li>Punctuations like <code>~</code>, <code>!</code>, <code>@</code>, <code>#</code>, <code>$</code>, etc.</li>
|
||||
<li><code>Plus</code></li>
|
||||
<li><code>Space</code></li>
|
||||
<li><code>Backspace</code></li>
|
||||
<li><code>Delete</code></li>
|
||||
<li><code>Insert</code></li>
|
||||
<li><code>Return</code> (or <code>Enter</code> as alias)</li>
|
||||
<li><code>Up</code>, <code>Down</code>, <code>Left</code> and <code>Right</code></li>
|
||||
<li><code>Home</code> and <code>End</code></li>
|
||||
<li><code>PageUp</code> and <code>PageDown</code></li>
|
||||
<li><code>Escape</code> (or <code>Esc</code> for short)</li>
|
||||
<li><code>VolumeUp</code>, <code>VolumeDown</code> and <code>VolumeMute</code></li>
|
||||
<li><code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>, <code>MediaStop</code> and <code>MediaPlayPause</code></li>
|
||||
<li><code>Control</code> (or <code>Ctrl</code> for short)</li>
|
||||
<li><code>Shift</code></li>
|
||||
<li>
|
||||
<code>0</code> to <code>9</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>A</code> to <code>Z</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>F1</code> to <code>F24</code>
|
||||
</li>
|
||||
<li>
|
||||
Punctuations like <code>~</code>, <code>!</code>,{' '}
|
||||
<code>@</code>, <code>#</code>, <code>$</code>, etc.
|
||||
</li>
|
||||
<li>
|
||||
<code>Plus</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Space</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Backspace</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Delete</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Insert</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Return</code> (or <code>Enter</code> as alias)
|
||||
</li>
|
||||
<li>
|
||||
<code>Up</code>, <code>Down</code>, <code>Left</code> and{' '}
|
||||
<code>Right</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Home</code> and <code>End</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>PageUp</code> and <code>PageDown</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Escape</code> (or <code>Esc</code> for short)
|
||||
</li>
|
||||
<li>
|
||||
<code>VolumeUp</code>, <code>VolumeDown</code> and{' '}
|
||||
<code>VolumeMute</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>,{' '}
|
||||
<code>MediaStop</code> and <code>MediaPlayPause</code>
|
||||
</li>
|
||||
<li>
|
||||
<code>Control</code> (or <code>Ctrl</code> for short)
|
||||
</li>
|
||||
<li>
|
||||
<code>Shift</code>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
@@ -12,7 +12,7 @@ const { shell, remote } = electron
|
||||
const appVersion = remote.app.getVersion()
|
||||
|
||||
class InfoTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,18 +20,18 @@ class InfoTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
handleConfigChange (e) {
|
||||
handleConfigChange(e) {
|
||||
const newConfig = { amaEnabled: this.refs.amaEnabled.checked }
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
}
|
||||
|
||||
handleSaveButtonClick (e) {
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
amaEnabled: this.state.config.amaEnabled
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class InfoTab extends React.Component {
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
amaMessage: i18n.__('Thank\'s for trusting us')
|
||||
amaMessage: i18n.__("Thank's for trusting us")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -61,62 +61,95 @@ class InfoTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
infoMessage () {
|
||||
toggleAutoUpdate() {
|
||||
const newConfig = {
|
||||
autoUpdateEnabled: !this.state.config.autoUpdateEnabled
|
||||
}
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
ConfigManager.set(newConfig)
|
||||
}
|
||||
|
||||
infoMessage() {
|
||||
const { amaMessage } = this.state
|
||||
return amaMessage ? <p styleName='policy-confirm'>{amaMessage}</p> : null
|
||||
}
|
||||
|
||||
render () {
|
||||
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>
|
||||
<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)}
|
||||
>{i18n.__('Subscribe to Newsletter')}</a>
|
||||
<a
|
||||
href='https://boostnote.io/#subscribe'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Subscribe to Newsletter')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://github.com/BoostIO/Boostnote/issues'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('GitHub')}</a>
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/issues'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('GitHub')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://medium.com/boostnote'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Blog')}</a>
|
||||
<a
|
||||
href='https://medium.com/boostnote'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Blog')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://www.facebook.com/groups/boostnote'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Facebook Group')}</a>
|
||||
<a
|
||||
href='https://www.facebook.com/groups/boostnote'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Facebook Group')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://twitter.com/boostnoteapp'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Twitter')}</a>
|
||||
<a
|
||||
href='https://twitter.com/boostnoteapp'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Twitter')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div styleName='header--sub'>{i18n.__('About')}</div>
|
||||
<div styleName='group-header--sub'>{i18n.__('About')}</div>
|
||||
|
||||
<div styleName='top'>
|
||||
<div styleName='icon-space'>
|
||||
<img styleName='icon' src='../resources/app.png' width='92' height='92' />
|
||||
<img
|
||||
styleName='icon'
|
||||
src='../resources/app.png'
|
||||
width='92'
|
||||
height='92'
|
||||
/>
|
||||
<div styleName='icon-right'>
|
||||
<div styleName='appId'>{i18n.__('Boostnote')} {appVersion}</div>
|
||||
<div styleName='appId'>Boostnote Legacy {appVersion}</div>
|
||||
<div styleName='description'>
|
||||
{i18n.__('An open source note-taking app made for programmers just like you.')}
|
||||
{i18n.__(
|
||||
'An open source note-taking app made for programmers just like you.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,37 +157,71 @@ class InfoTab extends React.Component {
|
||||
|
||||
<ul styleName='list'>
|
||||
<li>
|
||||
<a href='https://boostnote.io'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Website')}</a>
|
||||
<a
|
||||
href='https://boostnote.io'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Website')}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Development')}</a>{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('Copyright (C) 2017 - 2018 BoostIO')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('License: GPL v3')}
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Development')}
|
||||
</a>
|
||||
{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>{i18n.__('Copyright (C) 2017 - 2020 BoostIO')}</li>
|
||||
<li styleName='cc'>{i18n.__('License: GPL v3')}</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={this.toggleAutoUpdate.bind(this)}
|
||||
checked={this.state.config.autoUpdateEnabled}
|
||||
/>
|
||||
{i18n.__('Enable Auto Update')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr styleName='separate-line' />
|
||||
|
||||
<div styleName='policy'>{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>
|
||||
<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 />
|
||||
<div>{i18n.__('You can choose to enable or disable this option.')}</div>
|
||||
<input onChange={(e) => this.handleConfigChange(e)}
|
||||
<input
|
||||
onChange={e => this.handleConfigChange(e)}
|
||||
checked={this.state.config.amaEnabled}
|
||||
ref='amaEnabled'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable analytics to help improve Boostnote')}<br />
|
||||
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>{i18n.__('Save')}</button>
|
||||
{i18n.__('Enable analytics to help improve Boostnote')}
|
||||
<br />
|
||||
<button
|
||||
styleName='policy-submit'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
<br />
|
||||
{this.infoMessage()}
|
||||
</div>
|
||||
@@ -162,7 +229,6 @@ class InfoTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
InfoTab.propTypes = {
|
||||
}
|
||||
InfoTab.propTypes = {}
|
||||
|
||||
export default CSSModules(InfoTab, styles)
|
||||
|
||||
@@ -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,25 +56,22 @@
|
||||
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
|
||||
.list
|
||||
a
|
||||
color $ui-solarized-dark-active-color
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.root
|
||||
color get-theme-var(theme, 'text-color')
|
||||
.appId
|
||||
color get-theme-var(theme, 'text-color')
|
||||
.list
|
||||
a
|
||||
color get-theme-var(theme, 'active-color')
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
color $ui-monokai-text-color
|
||||
.list
|
||||
a
|
||||
color $ui-monokai-active-color
|
||||
for theme in 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
.list
|
||||
a
|
||||
color $ui-dracula-active-color
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
|
||||
@@ -64,102 +64,31 @@ top-bar--height = 50px
|
||||
margin-top 10px
|
||||
overflow-y auto
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
modalDark()
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.root
|
||||
background-color transparent
|
||||
.top-bar
|
||||
background-color transparent
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
p
|
||||
color get-theme-var(theme, 'text-color')
|
||||
.nav
|
||||
background-color transparent
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
.nav-button
|
||||
background-color transparent
|
||||
color get-theme-var(theme, 'text-color')
|
||||
&:hover
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.top-bar
|
||||
background-color transparent
|
||||
border-color #4A4D52
|
||||
p
|
||||
color $tab--dark-text-color
|
||||
.nav-button--active
|
||||
@extend .nav-button
|
||||
color get-theme-var(theme, 'button--active-color')
|
||||
background-color get-theme-var(theme, 'button--active-backgroundColor')
|
||||
|
||||
.nav
|
||||
background-color transparent
|
||||
border-color $ui-dark-borderColor
|
||||
for theme in 'dark' 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
.nav-button
|
||||
background-color transparent
|
||||
color $tab--dark-text-color
|
||||
&:hover
|
||||
color $ui-dark-text-color
|
||||
|
||||
.nav-button--active
|
||||
@extend .nav-button
|
||||
color white
|
||||
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
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
background-color transparent
|
||||
.top-bar
|
||||
background-color transparent
|
||||
border-color $ui-monokai-borderColor
|
||||
p
|
||||
color $ui-monokai-text-color
|
||||
.nav
|
||||
background-color transparent
|
||||
border-color $ui-monokai-borderColor
|
||||
.nav-button
|
||||
background-color transparent
|
||||
color $ui-monokai-text-color
|
||||
&:hover
|
||||
color $ui-monokai-text-color
|
||||
|
||||
.nav-button--active
|
||||
@extend .nav-button
|
||||
color $ui-monokai-button--active-color
|
||||
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
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
@@ -4,14 +4,21 @@ 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 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 () {
|
||||
componentDidMount() {
|
||||
this.props.onRef(this)
|
||||
const { rulers, enableRulers } = this.props
|
||||
this.cm = CodeMirror(this.refs.root, {
|
||||
@@ -48,36 +55,50 @@ class SnippetEditor extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
this.props.onRef(undefined)
|
||||
}
|
||||
|
||||
onSnippetChanged (newSnippet) {
|
||||
onSnippetChanged(newSnippet) {
|
||||
this.snippet = newSnippet
|
||||
this.cm.setValue(this.snippet.content)
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (newSnippet) {
|
||||
onSnippetNameOrPrefixChanged(newSnippet) {
|
||||
this.snippet.name = newSnippet.name
|
||||
this.snippet.prefix = newSnippet.prefix.toString().replace(/\s/g, '').split(',')
|
||||
this.snippet.prefix = newSnippet.prefix
|
||||
.toString()
|
||||
.replace(/\s/g, '')
|
||||
.split(',')
|
||||
this.saveSnippet()
|
||||
}
|
||||
|
||||
saveSnippet () {
|
||||
dataApi.updateSnippet(this.snippet).catch((err) => { throw err })
|
||||
saveSnippet() {
|
||||
dataApi
|
||||
.updateSnippet(this.snippet)
|
||||
.then(snippets => snippetManager.assignSnippets(snippets))
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { fontSize } = this.props
|
||||
let fontFamily = this.props.fontFamily
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
fontFamily =
|
||||
_.isString(fontFamily) && fontFamily.length > 0
|
||||
? [fontFamily].concat(defaultEditorFontFamily)
|
||||
: defaultEditorFontFamily
|
||||
return (
|
||||
<div styleName='SnippetEditor' ref='root' tabIndex='-1' style={{
|
||||
fontFamily: fontFamily.join(', '),
|
||||
fontSize: fontSize
|
||||
}} />
|
||||
<div
|
||||
styleName='SnippetEditor'
|
||||
ref='root'
|
||||
tabIndex='-1'
|
||||
style={{
|
||||
fontFamily: fontFamily.join(', '),
|
||||
fontSize: fontSize
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,53 +7,65 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||
import context from 'browser/lib/context'
|
||||
|
||||
class SnippetList extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
snippets: []
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.reloadSnippetList()
|
||||
eventEmitter.on('snippetList:reload', this.reloadSnippetList.bind(this))
|
||||
}
|
||||
|
||||
reloadSnippetList () {
|
||||
reloadSnippetList() {
|
||||
dataApi.fetchSnippet().then(snippets => {
|
||||
this.setState({snippets})
|
||||
this.setState({ snippets })
|
||||
this.props.onSnippetSelect(this.props.currentSnippet)
|
||||
})
|
||||
}
|
||||
|
||||
handleSnippetContextMenu (snippet) {
|
||||
context.popup([{
|
||||
label: i18n.__('Delete snippet'),
|
||||
click: () => this.deleteSnippet(snippet)
|
||||
}])
|
||||
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 })
|
||||
deleteSnippet(snippet) {
|
||||
dataApi
|
||||
.deleteSnippet(snippet)
|
||||
.then(() => {
|
||||
this.reloadSnippetList()
|
||||
this.props.onSnippetDeleted(snippet)
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
handleSnippetClick (snippet) {
|
||||
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 })
|
||||
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) {
|
||||
defineSnippetStyleName(snippet) {
|
||||
const { currentSnippet } = this.props
|
||||
|
||||
if (currentSnippet == null) {
|
||||
@@ -67,29 +79,31 @@ class SnippetList extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
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()}>
|
||||
<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>
|
||||
))
|
||||
}
|
||||
{snippets.map(snippet => (
|
||||
<li
|
||||
styleName={this.defineSnippetStyleName(snippet)}
|
||||
key={snippet.id}
|
||||
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
||||
onClick={() => this.handleSnippetClick(snippet)}
|
||||
>
|
||||
{snippet.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import copy from 'copy-to-clipboard'
|
||||
const path = require('path')
|
||||
|
||||
class SnippetTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentSnippet: null
|
||||
@@ -19,7 +19,7 @@ class SnippetTab extends React.Component {
|
||||
this.changeDelay = null
|
||||
}
|
||||
|
||||
notify (title, options) {
|
||||
notify(title, options) {
|
||||
if (global.process.platform === 'win32') {
|
||||
options.icon = path.join(
|
||||
'file://',
|
||||
@@ -30,7 +30,7 @@ class SnippetTab extends React.Component {
|
||||
return new window.Notification(title, options)
|
||||
}
|
||||
|
||||
handleSnippetNameOrPrefixChange () {
|
||||
handleSnippetNameOrPrefixChange() {
|
||||
clearTimeout(this.changeDelay)
|
||||
this.changeDelay = setTimeout(() => {
|
||||
// notify the snippet editor that the name or prefix of snippet has been changed
|
||||
@@ -39,20 +39,20 @@ class SnippetTab extends React.Component {
|
||||
}, 500)
|
||||
}
|
||||
|
||||
handleSnippetSelect (snippet) {
|
||||
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})
|
||||
this.setState({ currentSnippet: changedSnippet })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSnippetNameOrPrefixChanged (e, type) {
|
||||
onSnippetNameOrPrefixChanged(e, type) {
|
||||
const newSnippet = Object.assign({}, this.state.currentSnippet)
|
||||
if (type === 'name') {
|
||||
newSnippet.name = e.target.value
|
||||
@@ -63,14 +63,14 @@ class SnippetTab extends React.Component {
|
||||
this.handleSnippetNameOrPrefixChange()
|
||||
}
|
||||
|
||||
handleDeleteSnippet (snippet) {
|
||||
handleDeleteSnippet(snippet) {
|
||||
// prevent old snippet still display when deleted
|
||||
if (snippet.id === this.state.currentSnippet.id) {
|
||||
this.setState({currentSnippet: null})
|
||||
this.setState({ currentSnippet: null })
|
||||
}
|
||||
}
|
||||
|
||||
handleCopySnippet (e) {
|
||||
handleCopySnippet(e) {
|
||||
const showCopyNotification = this.props.config.ui.showCopyNotification
|
||||
copy(this.state.currentSnippet.content)
|
||||
if (showCopyNotification) {
|
||||
@@ -81,7 +81,7 @@ class SnippetTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { config, storageKey } = this.props
|
||||
const { currentSnippet } = this.state
|
||||
|
||||
@@ -91,16 +91,23 @@ class SnippetTab extends React.Component {
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='header'>{i18n.__('Snippets')}</div>
|
||||
<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'}}>
|
||||
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
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleCopySnippet(e)}
|
||||
>
|
||||
{i18n.__('Copy')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,18 +117,26 @@ class SnippetTab extends React.Component {
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
value={currentSnippet ? currentSnippet.name : ''}
|
||||
onChange={e => { this.onSnippetNameOrPrefixChanged(e, 'name') }}
|
||||
type='text' />
|
||||
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-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' />
|
||||
onChange={e => {
|
||||
this.onSnippetNameOrPrefixChanged(e, 'prefix')
|
||||
}}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='snippet-editor-section'>
|
||||
@@ -140,7 +155,10 @@ class SnippetTab extends React.Component {
|
||||
matchingTriples={config.editor.matchingTriples}
|
||||
explodingPairs={config.editor.explodingPairs}
|
||||
scrollPastEnd={config.editor.scrollPastEnd}
|
||||
onRef={ref => { this.snippetEditor = ref }} />
|
||||
onRef={ref => {
|
||||
this.snippetEditor = ref
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,7 +166,6 @@ class SnippetTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
SnippetTab.PropTypes = {
|
||||
}
|
||||
SnippetTab.PropTypes = {}
|
||||
|
||||
export default CSSModules(SnippetTab, styles)
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
@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
|
||||
|
||||
.group
|
||||
margin-bottom 45px
|
||||
|
||||
@@ -127,7 +118,7 @@
|
||||
background darken(#f5f5f5, 5)
|
||||
|
||||
.snippet-detail
|
||||
width 70%
|
||||
width 67%
|
||||
height calc(100% - 200px)
|
||||
position absolute
|
||||
left 33%
|
||||
@@ -149,66 +140,25 @@ body[data-theme="default"], body[data-theme="white"]
|
||||
.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()
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.snippets
|
||||
background get-theme-var(theme, 'backgroundColor')
|
||||
.snippet-item
|
||||
color get-theme-var(theme, 'text-color')
|
||||
&::after
|
||||
background get-theme-var(theme, 'borderColor')
|
||||
&:hover
|
||||
background darken(get-theme-var(theme, 'backgroundColor'), 5)
|
||||
.snippet-item-selected
|
||||
background darken(get-theme-var(theme, 'backgroundColor'), 5)
|
||||
.snippet-detail
|
||||
color get-theme-var(theme, 'text-color')
|
||||
.group-control-button
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
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()
|
||||
for theme in 'dark' 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
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()
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
@@ -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'
|
||||
|
||||
@@ -12,7 +12,7 @@ const { shell, remote } = require('electron')
|
||||
const { dialog } = remote
|
||||
|
||||
class StorageItem extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -20,137 +20,156 @@ class StorageItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleNewFolderButtonClick (e) {
|
||||
handleNewFolderButtonClick(e) {
|
||||
const { storage } = this.props
|
||||
const input = {
|
||||
name: i18n.__('New Folder'),
|
||||
color: consts.FOLDER_COLORS[Math.floor(Math.random() * 7) % 7]
|
||||
}
|
||||
|
||||
dataApi.createFolder(storage.key, input)
|
||||
.then((data) => {
|
||||
dataApi
|
||||
.createFolder(storage.key, input)
|
||||
.then(data => {
|
||||
store.dispatch({
|
||||
type: 'UPDATE_FOLDER',
|
||||
storage: data.storage
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
handleExternalButtonClick () {
|
||||
handleExternalButtonClick() {
|
||||
const { storage } = this.props
|
||||
shell.showItemInFolder(storage.path)
|
||||
}
|
||||
|
||||
handleUnlinkButtonClick (e) {
|
||||
handleUnlinkButtonClick(e) {
|
||||
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: i18n.__('Unlink Storage'),
|
||||
detail: i18n.__('Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.'),
|
||||
detail: i18n.__(
|
||||
'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.'
|
||||
),
|
||||
buttons: [i18n.__('Unlink'), i18n.__('Cancel')]
|
||||
})
|
||||
|
||||
if (index === 0) {
|
||||
const { storage } = this.props
|
||||
dataApi.removeStorage(storage.key)
|
||||
dataApi
|
||||
.removeStorage(storage.key)
|
||||
.then(() => {
|
||||
store.dispatch({
|
||||
type: 'REMOVE_STORAGE',
|
||||
storageKey: storage.key
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleLabelClick (e) {
|
||||
handleLabelClick(e) {
|
||||
const { storage } = this.props
|
||||
this.setState({
|
||||
isLabelEditing: true,
|
||||
name: storage.name
|
||||
}, () => {
|
||||
this.refs.label.focus()
|
||||
})
|
||||
this.setState(
|
||||
{
|
||||
isLabelEditing: true,
|
||||
name: storage.name
|
||||
},
|
||||
() => {
|
||||
this.refs.label.focus()
|
||||
}
|
||||
)
|
||||
}
|
||||
handleLabelChange (e) {
|
||||
handleLabelChange(e) {
|
||||
this.setState({
|
||||
name: this.refs.label.value
|
||||
})
|
||||
}
|
||||
|
||||
handleLabelBlur (e) {
|
||||
handleLabelBlur(e) {
|
||||
const { storage } = this.props
|
||||
dataApi
|
||||
.renameStorage(storage.key, this.state.name)
|
||||
.then((_storage) => {
|
||||
store.dispatch({
|
||||
type: 'RENAME_STORAGE',
|
||||
storage: _storage
|
||||
})
|
||||
this.setState({
|
||||
isLabelEditing: false
|
||||
})
|
||||
dataApi.renameStorage(storage.key, this.state.name).then(_storage => {
|
||||
store.dispatch({
|
||||
type: 'RENAME_STORAGE',
|
||||
storage: _storage
|
||||
})
|
||||
this.setState({
|
||||
isLabelEditing: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const { storage, hostBoundingBox } = this.props
|
||||
|
||||
return (
|
||||
<div styleName='root' key={storage.key}>
|
||||
<div styleName='header'>
|
||||
{this.state.isLabelEditing
|
||||
? <div styleName='header-label--edit'>
|
||||
<input styleName='header-label-input'
|
||||
{this.state.isLabelEditing ? (
|
||||
<div styleName='header-label--edit'>
|
||||
<input
|
||||
styleName='header-label-input'
|
||||
value={this.state.name}
|
||||
ref='label'
|
||||
onChange={(e) => this.handleLabelChange(e)}
|
||||
onBlur={(e) => this.handleLabelBlur(e)}
|
||||
onChange={e => this.handleLabelChange(e)}
|
||||
onBlur={e => this.handleLabelBlur(e)}
|
||||
/>
|
||||
</div>
|
||||
: <div styleName='header-label'
|
||||
onClick={(e) => this.handleLabelClick(e)}
|
||||
) : (
|
||||
<div
|
||||
styleName='header-label'
|
||||
onClick={e => this.handleLabelClick(e)}
|
||||
>
|
||||
<i className='fa fa-folder-open' />
|
||||
<i className='fa fa-folder-open' />
|
||||
|
||||
{storage.name}
|
||||
<span styleName='header-label-path'>({storage.path})</span>
|
||||
<i styleName='header-label-editButton' className='fa fa-pencil' />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
<div styleName='header-control'>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleNewFolderButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleNewFolderButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-plus' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -20}}
|
||||
>{i18n.__('Add Folder')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -20 }}
|
||||
>
|
||||
{i18n.__('Add Folder')}
|
||||
</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleExternalButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleExternalButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-external-link' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -50}}
|
||||
>{i18n.__('Open Storage folder')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -50 }}
|
||||
>
|
||||
{i18n.__('Open Storage folder')}
|
||||
</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleUnlinkButtonClick(e)}
|
||||
<button
|
||||
styleName='header-control-button'
|
||||
onClick={e => this.handleUnlinkButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-unlink' />
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -10}}
|
||||
>{i18n.__('Unlink')}</span>
|
||||
<span
|
||||
styleName='header-control-button-tooltip'
|
||||
style={{ left: -10 }}
|
||||
>
|
||||
{i18n.__('Unlink')}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<FolderList storage={storage}
|
||||
hostBoundingBox={hostBoundingBox}
|
||||
/>
|
||||
<FolderList storage={storage} hostBoundingBox={hostBoundingBox} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,4 +101,19 @@ body[data-theme="solarized-dark"]
|
||||
.header-control-button
|
||||
border-color $ui-solarized-dark-button-backgroundColor
|
||||
background-color $ui-solarized-dark-button-backgroundColor
|
||||
color $ui-solarized-dark-text-color
|
||||
color $ui-solarized-dark-text-color
|
||||
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.header
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
|
||||
.header-control-button
|
||||
colorThemedPrimaryButton(theme)
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
|
||||
for theme in 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
@@ -3,30 +3,36 @@ import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './StoragesTab.styl'
|
||||
import dataApi from 'browser/main/lib/dataApi'
|
||||
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
||||
import StorageItem from './StorageItem'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import { humanFileSize } from 'browser/lib/utils'
|
||||
import fs from 'fs'
|
||||
|
||||
const electron = require('electron')
|
||||
const { shell, remote } = electron
|
||||
|
||||
function browseFolder () {
|
||||
function browseFolder() {
|
||||
const dialog = remote.dialog
|
||||
|
||||
const defaultPath = remote.app.getPath('home')
|
||||
return new Promise((resolve, reject) => {
|
||||
dialog.showOpenDialog({
|
||||
title: i18n.__('Select Directory'),
|
||||
defaultPath,
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
}, function (targetPaths) {
|
||||
if (targetPaths == null) return resolve('')
|
||||
resolve(targetPaths[0])
|
||||
})
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
title: i18n.__('Select Directory'),
|
||||
defaultPath,
|
||||
properties: ['openDirectory', 'createDirectory']
|
||||
},
|
||||
function(targetPaths) {
|
||||
if (targetPaths == null) return resolve('')
|
||||
resolve(targetPaths[0])
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
class StoragesTab extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -35,60 +41,148 @@ class StoragesTab extends React.Component {
|
||||
name: 'Unnamed',
|
||||
type: 'FILESYSTEM',
|
||||
path: ''
|
||||
}
|
||||
},
|
||||
attachments: []
|
||||
}
|
||||
this.loadAttachmentStorage()
|
||||
}
|
||||
|
||||
handleAddStorageButton (e) {
|
||||
this.setState({
|
||||
page: 'ADD_STORAGE',
|
||||
newStorage: {
|
||||
name: 'Unnamed',
|
||||
type: 'FILESYSTEM',
|
||||
path: ''
|
||||
}
|
||||
}, () => {
|
||||
this.refs.addStorageName.select()
|
||||
loadAttachmentStorage() {
|
||||
const promises = []
|
||||
this.props.data.noteMap.map(note => {
|
||||
const promise = attachmentManagement.getAttachmentsPathAndStatus(
|
||||
note.content,
|
||||
note.storage,
|
||||
note.key
|
||||
)
|
||||
if (promise) promises.push(promise)
|
||||
})
|
||||
|
||||
Promise.all(promises)
|
||||
.then(data => {
|
||||
const result = data.reduce((acc, curr) => acc.concat(curr), [])
|
||||
this.setState({ attachments: result })
|
||||
})
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
handleLinkClick (e) {
|
||||
handleAddStorageButton(e) {
|
||||
this.setState(
|
||||
{
|
||||
page: 'ADD_STORAGE',
|
||||
newStorage: {
|
||||
name: 'Unnamed',
|
||||
type: 'FILESYSTEM',
|
||||
path: ''
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.refs.addStorageName.select()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
renderList () {
|
||||
const { data, boundingBox } = this.props
|
||||
handleRemoveUnusedAttachments(attachments) {
|
||||
attachmentManagement
|
||||
.removeAttachmentsByPaths(attachments)
|
||||
.then(() => this.loadAttachmentStorage())
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
if (!boundingBox) { return null }
|
||||
const storageList = data.storageMap.map((storage) => {
|
||||
return <StorageItem
|
||||
key={storage.key}
|
||||
storage={storage}
|
||||
hostBoundingBox={boundingBox}
|
||||
/>
|
||||
renderList() {
|
||||
const { data, boundingBox } = this.props
|
||||
const { attachments } = this.state
|
||||
|
||||
const unusedAttachments = attachments.filter(
|
||||
attachment => !attachment.isInUse
|
||||
)
|
||||
const inUseAttachments = attachments.filter(
|
||||
attachment => attachment.isInUse
|
||||
)
|
||||
|
||||
const totalUnusedAttachments = unusedAttachments.length
|
||||
const totalInuseAttachments = inUseAttachments.length
|
||||
const totalAttachments = totalUnusedAttachments + totalInuseAttachments
|
||||
|
||||
const totalUnusedAttachmentsSize = unusedAttachments.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalInuseAttachmentsSize = inUseAttachments.reduce((acc, curr) => {
|
||||
const stats = fs.statSync(curr.path)
|
||||
const fileSizeInBytes = stats.size
|
||||
return acc + fileSizeInBytes
|
||||
}, 0)
|
||||
const totalAttachmentsSize =
|
||||
totalUnusedAttachmentsSize + totalInuseAttachmentsSize
|
||||
|
||||
const unusedAttachmentPaths = unusedAttachments.reduce(
|
||||
(acc, curr) => acc.concat(curr.path),
|
||||
[]
|
||||
)
|
||||
|
||||
if (!boundingBox) {
|
||||
return null
|
||||
}
|
||||
const storageList = data.storageMap.map(storage => {
|
||||
return (
|
||||
<StorageItem
|
||||
key={storage.key}
|
||||
storage={storage}
|
||||
hostBoundingBox={boundingBox}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div styleName='list'>
|
||||
<div styleName='header'>{i18n.__('Storage Locations')}</div>
|
||||
{storageList.length > 0
|
||||
? storageList
|
||||
: <div styleName='list-empty'>{i18n.__('No storage found.')}</div>
|
||||
}
|
||||
{storageList.length > 0 ? (
|
||||
storageList
|
||||
) : (
|
||||
<div styleName='list-empty'>{i18n.__('No storage found.')}</div>
|
||||
)}
|
||||
<div styleName='list-control'>
|
||||
<button styleName='list-control-addStorageButton'
|
||||
onClick={(e) => this.handleAddStorageButton(e)}
|
||||
<button
|
||||
styleName='list-control-addStorageButton'
|
||||
onClick={e => this.handleAddStorageButton(e)}
|
||||
>
|
||||
<i className='fa fa-plus' /> {i18n.__('Add Storage Location')}
|
||||
</button>
|
||||
</div>
|
||||
<div styleName='header'>{i18n.__('Attachment storage')}</div>
|
||||
<p styleName='list-attachment-label'>
|
||||
Unused attachments size: {humanFileSize(totalUnusedAttachmentsSize)} (
|
||||
{totalUnusedAttachments} items)
|
||||
</p>
|
||||
<p styleName='list-attachment-label'>
|
||||
In use attachments size: {humanFileSize(totalInuseAttachmentsSize)} (
|
||||
{totalInuseAttachments} items)
|
||||
</p>
|
||||
<p styleName='list-attachment-label'>
|
||||
Total attachments size: {humanFileSize(totalAttachmentsSize)} (
|
||||
{totalAttachments} items)
|
||||
</p>
|
||||
<button
|
||||
styleName='list-attachement-clear-button'
|
||||
onClick={() =>
|
||||
this.handleRemoveUnusedAttachments(unusedAttachmentPaths)
|
||||
}
|
||||
>
|
||||
{i18n.__('Clear unused attachments')}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
handleAddStorageBrowseButtonClick (e) {
|
||||
handleAddStorageBrowseButtonClick(e) {
|
||||
browseFolder()
|
||||
.then((targetPath) => {
|
||||
.then(targetPath => {
|
||||
if (targetPath.length > 0) {
|
||||
const { newStorage } = this.state
|
||||
newStorage.path = targetPath
|
||||
@@ -97,13 +191,13 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.error('BrowseFAILED')
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageChange (e) {
|
||||
handleAddStorageChange(e) {
|
||||
const { newStorage } = this.state
|
||||
newStorage.name = this.refs.addStorageName.value
|
||||
newStorage.path = this.refs.addStoragePath.value
|
||||
@@ -112,13 +206,13 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageCreateButton (e) {
|
||||
handleAddStorageCreateButton(e) {
|
||||
dataApi
|
||||
.addStorage({
|
||||
name: this.state.newStorage.name,
|
||||
path: this.state.newStorage.path
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
const { dispatch } = this.props
|
||||
dispatch({
|
||||
type: 'ADD_STORAGE',
|
||||
@@ -131,37 +225,39 @@ class StoragesTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleAddStorageCancelButton (e) {
|
||||
handleAddStorageCancelButton(e) {
|
||||
this.setState({
|
||||
page: 'LIST'
|
||||
})
|
||||
}
|
||||
|
||||
renderAddStorage () {
|
||||
renderAddStorage() {
|
||||
return (
|
||||
<div styleName='addStorage'>
|
||||
|
||||
<div styleName='addStorage-header'>{i18n.__('Add Storage')}</div>
|
||||
|
||||
<div styleName='addStorage-body'>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Name')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-name'>
|
||||
<input styleName='addStorage-body-section-name-input'
|
||||
<input
|
||||
styleName='addStorage-body-section-name-input'
|
||||
ref='addStorageName'
|
||||
value={this.state.newStorage.name}
|
||||
onChange={(e) => this.handleAddStorageChange(e)}
|
||||
onChange={e => this.handleAddStorageChange(e)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>{i18n.__('Type')}</div>
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Type')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-type'>
|
||||
<select styleName='addStorage-body-section-type-select'
|
||||
<select
|
||||
styleName='addStorage-body-section-type-select'
|
||||
value={this.state.newStorage.type}
|
||||
readOnly
|
||||
>
|
||||
@@ -169,25 +265,31 @@ class StoragesTab extends React.Component {
|
||||
</select>
|
||||
<div styleName='addStorage-body-section-type-description'>
|
||||
{i18n.__('Setting up 3rd-party cloud storage integration:')}{' '}
|
||||
<a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
|
||||
onClick={(e) => this.handleLinkClick(e)}
|
||||
>{i18n.__('Cloud-Syncing-and-Backup')}</a>
|
||||
<a
|
||||
href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
|
||||
onClick={e => this.handleLinkClick(e)}
|
||||
>
|
||||
{i18n.__('Cloud-Syncing-and-Backup')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-section'>
|
||||
<div styleName='addStorage-body-section-label'>{i18n.__('Location')}
|
||||
<div styleName='addStorage-body-section-label'>
|
||||
{i18n.__('Location')}
|
||||
</div>
|
||||
<div styleName='addStorage-body-section-path'>
|
||||
<input styleName='addStorage-body-section-path-input'
|
||||
<input
|
||||
styleName='addStorage-body-section-path-input'
|
||||
ref='addStoragePath'
|
||||
placeholder={i18n.__('Select Folder')}
|
||||
value={this.state.newStorage.path}
|
||||
onChange={(e) => this.handleAddStorageChange(e)}
|
||||
onChange={e => this.handleAddStorageChange(e)}
|
||||
/>
|
||||
<button styleName='addStorage-body-section-path-button'
|
||||
onClick={(e) => this.handleAddStorageBrowseButtonClick(e)}
|
||||
<button
|
||||
styleName='addStorage-body-section-path-button'
|
||||
onClick={e => this.handleAddStorageBrowseButtonClick(e)}
|
||||
>
|
||||
...
|
||||
</button>
|
||||
@@ -195,21 +297,25 @@ class StoragesTab extends React.Component {
|
||||
</div>
|
||||
|
||||
<div styleName='addStorage-body-control'>
|
||||
<button styleName='addStorage-body-control-createButton'
|
||||
onClick={(e) => this.handleAddStorageCreateButton(e)}
|
||||
>{i18n.__('Add')}</button>
|
||||
<button styleName='addStorage-body-control-cancelButton'
|
||||
onClick={(e) => this.handleAddStorageCancelButton(e)}
|
||||
>{i18n.__('Cancel')}</button>
|
||||
<button
|
||||
styleName='addStorage-body-control-createButton'
|
||||
onClick={e => this.handleAddStorageCreateButton(e)}
|
||||
>
|
||||
{i18n.__('Add')}
|
||||
</button>
|
||||
<button
|
||||
styleName='addStorage-body-control-cancelButton'
|
||||
onClick={e => this.handleAddStorageCancelButton(e)}
|
||||
>
|
||||
{i18n.__('Cancel')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
renderContent() {
|
||||
switch (this.state.page) {
|
||||
case 'ADD_STORAGE':
|
||||
case 'ADD_FOLDER':
|
||||
@@ -220,12 +326,8 @@ class StoragesTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
{this.renderContent()}
|
||||
</div>
|
||||
)
|
||||
render() {
|
||||
return <div styleName='root'>{this.renderContent()}</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
@import('./Tab')
|
||||
|
||||
.root
|
||||
padding 15px
|
||||
color $ui-text-color
|
||||
@import('./ConfigTab')
|
||||
|
||||
.list
|
||||
margin-bottom 15px
|
||||
@@ -37,6 +33,17 @@
|
||||
colorDefaultButton()
|
||||
font-size $tab--button-font-size
|
||||
border-radius 2px
|
||||
.list-attachment-label
|
||||
margin-bottom 10px
|
||||
color $ui-text-color
|
||||
.list-attachement-clear-button
|
||||
height 30px
|
||||
border none
|
||||
border-top-right-radius 2px
|
||||
border-bottom-right-radius 2px
|
||||
colorPrimaryButton()
|
||||
vertical-align middle
|
||||
padding 0 20px
|
||||
|
||||
.addStorage
|
||||
margin-bottom 15px
|
||||
@@ -158,119 +165,52 @@ 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
|
||||
.list-attachement-clear-button
|
||||
colorDarkPrimaryButton()
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.root
|
||||
color $ui-monokai-text-color
|
||||
apply-theme(theme)
|
||||
body[data-theme={theme}]
|
||||
.root
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.folderList-item
|
||||
border-bottom $ui-monokai-borderColor
|
||||
.folderList-item
|
||||
border-bottom get-theme-var(theme, 'borderColor')
|
||||
|
||||
.folderList-empty
|
||||
color $ui-monokai-text-color
|
||||
.folderList-empty
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.list-empty
|
||||
color $ui-monokai-text-color
|
||||
.list-control-addStorageButton
|
||||
border-color $ui-monokai-button-backgroundColor
|
||||
background-color $ui-monokai-button-backgroundColor
|
||||
color $ui-monokai-text-color
|
||||
.list-empty
|
||||
color get-theme-var(theme, 'text-color')
|
||||
.list-control-addStorageButton
|
||||
border-color get-theme-var(theme, 'button-backgroundColor')
|
||||
background-color get-theme-var(theme, 'button-backgroundColor')
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.addStorage-header
|
||||
color $ui-monokai-text-color
|
||||
border-color $ui-monokai-borderColor
|
||||
.addStorage-header
|
||||
color get-theme-var(theme, 'text-color')
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
|
||||
.addStorage-body-section-name-input
|
||||
border-color $$ui-monokai-borderColor
|
||||
.addStorage-body-section-name-input
|
||||
border-color $get-theme-var(theme, 'borderColor')
|
||||
|
||||
.addStorage-body-section-type-description
|
||||
color $ui-monokai-text-color
|
||||
.addStorage-body-section-type-description
|
||||
color get-theme-var(theme, 'text-color')
|
||||
|
||||
.addStorage-body-section-path-button
|
||||
colorPrimaryButton()
|
||||
.addStorage-body-control
|
||||
border-color $ui-monokai-borderColor
|
||||
.addStorage-body-section-path-button
|
||||
colorPrimaryButton()
|
||||
.addStorage-body-control
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
|
||||
.addStorage-body-control-createButton
|
||||
colorDarkPrimaryButton()
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color $ui-monokai-borderColor
|
||||
.addStorage-body-control-createButton
|
||||
colorDarkPrimaryButton()
|
||||
.addStorage-body-control-cancelButton
|
||||
colorDarkDefaultButton()
|
||||
border-color get-theme-var(theme, 'borderColor')
|
||||
.list-attachement-clear-button
|
||||
colorThemedPrimaryButton(theme)
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.root
|
||||
color $ui-dracula-text-color
|
||||
for theme in 'solarized-dark' 'dracula'
|
||||
apply-theme(theme)
|
||||
|
||||
.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
|
||||
for theme in $themes
|
||||
apply-theme(theme)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
class Preferences extends React.Component {
|
||||
constructor (props) {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
@@ -29,44 +29,39 @@ class Preferences extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
this.refs.root.focus()
|
||||
const boundingBox = this.getContentBoundingBox()
|
||||
this.setState({ boundingBox })
|
||||
}
|
||||
|
||||
switchTeam (teamId) {
|
||||
this.setState({currentTeamId: teamId})
|
||||
switchTeam(teamId) {
|
||||
this.setState({ currentTeamId: teamId })
|
||||
}
|
||||
|
||||
handleNavButtonClick (tab) {
|
||||
return (e) => {
|
||||
this.setState({currentTab: tab})
|
||||
handleNavButtonClick(tab) {
|
||||
return e => {
|
||||
this.setState({ currentTab: tab })
|
||||
}
|
||||
}
|
||||
|
||||
handleEscButtonClick () {
|
||||
handleEscButtonClick() {
|
||||
this.props.close()
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
renderContent() {
|
||||
const { boundingBox } = this.state
|
||||
const { dispatch, config, data } = this.props
|
||||
|
||||
switch (this.state.currentTab) {
|
||||
case 'INFO':
|
||||
return (
|
||||
<InfoTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
/>
|
||||
)
|
||||
return <InfoTab dispatch={dispatch} config={config} />
|
||||
case 'HOTKEY':
|
||||
return (
|
||||
<HotkeyTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({HotkeyAlert: alert})}
|
||||
haveToSave={alert => this.setState({ HotkeyAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'UI':
|
||||
@@ -74,19 +69,17 @@ class Preferences extends React.Component {
|
||||
<UiTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({UIAlert: alert})}
|
||||
haveToSave={alert => this.setState({ UIAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'CROWDFUNDING':
|
||||
return (
|
||||
<Crowdfunding />
|
||||
)
|
||||
return <Crowdfunding />
|
||||
case 'BLOG':
|
||||
return (
|
||||
<Blog
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
haveToSave={alert => this.setState({BlogAlert: alert})}
|
||||
haveToSave={alert => this.setState({ BlogAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'EXPORT':
|
||||
@@ -95,17 +88,11 @@ class Preferences extends React.Component {
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
data={data}
|
||||
haveToSave={alert => this.setState({ExportAlert: alert})}
|
||||
haveToSave={alert => this.setState({ ExportAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'SNIPPET':
|
||||
return (
|
||||
<SnippetTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
data={data}
|
||||
/>
|
||||
)
|
||||
return <SnippetTab dispatch={dispatch} config={config} data={data} />
|
||||
case 'STORAGES':
|
||||
default:
|
||||
return (
|
||||
@@ -118,68 +105,74 @@ class Preferences extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
|
||||
getContentBoundingBox () {
|
||||
getContentBoundingBox() {
|
||||
return this.refs.content.getBoundingClientRect()
|
||||
}
|
||||
|
||||
haveToSaveNotif (type, message) {
|
||||
return (
|
||||
<p styleName={`saving--${type}`}>{message}</p>
|
||||
)
|
||||
haveToSaveNotif(type, message) {
|
||||
return <p styleName={`saving--${type}`}>{message}</p>
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const content = this.renderContent()
|
||||
|
||||
const tabs = [
|
||||
{target: 'STORAGES', label: i18n.__('Storage')},
|
||||
{target: 'HOTKEY', label: i18n.__('Hotkeys'), Hotkey: this.state.HotkeyAlert},
|
||||
{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: 'EXPORT', label: i18n.__('Export'), Export: this.state.ExportAlert},
|
||||
{target: 'SNIPPET', label: i18n.__('Snippets')}
|
||||
{ target: 'STORAGES', label: i18n.__('Storage') },
|
||||
{
|
||||
target: 'HOTKEY',
|
||||
label: i18n.__('Hotkeys'),
|
||||
Hotkey: this.state.HotkeyAlert
|
||||
},
|
||||
{ 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: 'EXPORT',
|
||||
label: i18n.__('Export'),
|
||||
Export: this.state.ExportAlert
|
||||
},
|
||||
{ target: 'SNIPPET', label: i18n.__('Snippets') }
|
||||
]
|
||||
|
||||
const navButtons = tabs.map((tab) => {
|
||||
const navButtons = tabs.map(tab => {
|
||||
const isActive = this.state.currentTab === tab.target
|
||||
const isUiHotkeyTab = _.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab
|
||||
const isUiHotkeyTab =
|
||||
_.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab
|
||||
return (
|
||||
<button styleName={isActive
|
||||
? 'nav-button--active'
|
||||
: 'nav-button'
|
||||
}
|
||||
<button
|
||||
styleName={isActive ? 'nav-button--active' : 'nav-button'}
|
||||
key={tab.target}
|
||||
onClick={(e) => this.handleNavButtonClick(tab.target)(e)}
|
||||
onClick={e => this.handleNavButtonClick(tab.target)(e)}
|
||||
>
|
||||
<span styleName='nav-button-label'>
|
||||
{tab.label}
|
||||
</span>
|
||||
{isUiHotkeyTab ? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message) : null}
|
||||
<span>{tab.label}</span>
|
||||
{isUiHotkeyTab
|
||||
? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message)
|
||||
: null}
|
||||
</button>
|
||||
)
|
||||
})
|
||||
|
||||
return (
|
||||
<div styleName='root'
|
||||
<div
|
||||
styleName='root'
|
||||
ref='root'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyDown={e => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='top-bar'>
|
||||
<p>{i18n.__('Your preferences for Boostnote')}</p>
|
||||
</div>
|
||||
<ModalEscButton handleEscButtonClick={(e) => this.handleEscButtonClick(e)} />
|
||||
<div styleName='nav'>
|
||||
{navButtons}
|
||||
</div>
|
||||
<ModalEscButton
|
||||
handleEscButtonClick={e => this.handleEscButtonClick(e)}
|
||||
/>
|
||||
<div styleName='nav'>{navButtons}</div>
|
||||
<div ref='content' styleName='content'>
|
||||
{content}
|
||||
</div>
|
||||
@@ -193,4 +186,4 @@ Preferences.propTypes = {
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
export default connect((x) => x)(CSSModules(Preferences, styles))
|
||||
export default connect(x => x)(CSSModules(Preferences, styles))
|
||||
|
||||
Reference in New Issue
Block a user