mirror of
https://github.com/BoostIo/Boostnote
synced 2026-05-06 07:42:27 +00:00
Merge branch 'master' into fix-autocomplete-codeblock
This commit is contained in:
@@ -70,22 +70,22 @@ class InfoPanel extends React.Component {
|
||||
<hr />
|
||||
|
||||
<div id='export-wrap'>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e, 'export-md')}>
|
||||
<i className='fa fa-file-code-o' />
|
||||
<p>{i18n.__('.md')}</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e, 'export-txt')}>
|
||||
<i className='fa fa-file-text-o' />
|
||||
<p>{i18n.__('.txt')}</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsHtml(e, 'export-html')}>
|
||||
<i className='fa fa-html5' />
|
||||
<p>{i18n.__('.html')}</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => print(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => print(e, 'print')}>
|
||||
<i className='fa fa-print' />
|
||||
<p>{i18n.__('Print')}</p>
|
||||
</button>
|
||||
|
||||
@@ -31,17 +31,17 @@ const InfoPanelTrashed = ({
|
||||
</div>
|
||||
|
||||
<div id='export-wrap'>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsMd(e, 'export-md')}>
|
||||
<i className='fa fa-file-code-o' />
|
||||
<p>.md</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsTxt(e, 'export-txt')}>
|
||||
<i className='fa fa-file-text-o' />
|
||||
<p>.txt</p>
|
||||
</button>
|
||||
|
||||
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
|
||||
<button styleName='export--enable' onClick={(e) => exportAsHtml(e, 'export-html')}>
|
||||
<i className='fa fa-html5' />
|
||||
<p>.html</p>
|
||||
</button>
|
||||
|
||||
@@ -39,12 +39,14 @@ class MarkdownNoteDetail extends React.Component {
|
||||
isMovingNote: false,
|
||||
note: Object.assign({
|
||||
title: '',
|
||||
content: ''
|
||||
content: '',
|
||||
linesHighlighted: []
|
||||
}, props.note),
|
||||
isLockButtonShown: false,
|
||||
isLocked: false,
|
||||
editorType: props.config.editor.type
|
||||
}
|
||||
|
||||
this.dispatchTimer = null
|
||||
|
||||
this.toggleLockButton = this.handleToggleLockButton.bind(this)
|
||||
@@ -71,7 +73,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
if (!this.state.isMovingNote && (isNewNote || hasDeletedTags)) {
|
||||
if (this.saveQueue != null) this.saveNow()
|
||||
this.setState({
|
||||
note: Object.assign({}, nextProps.note)
|
||||
note: Object.assign({linesHighlighted: []}, nextProps.note)
|
||||
}, () => {
|
||||
this.refs.content.reload()
|
||||
if (this.refs.tags) this.refs.tags.reset()
|
||||
@@ -190,6 +192,36 @@ class MarkdownNoteDetail extends React.Component {
|
||||
ee.emit('export:save-html')
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
switch (e.keyCode) {
|
||||
// tab key
|
||||
case 9:
|
||||
if (e.ctrlKey && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
this.jumpNextTab()
|
||||
} else if (e.ctrlKey && e.shiftKey) {
|
||||
e.preventDefault()
|
||||
this.jumpPrevTab()
|
||||
} else if (!e.ctrlKey && !e.shiftKey && e.target === this.refs.description) {
|
||||
e.preventDefault()
|
||||
this.focusEditor()
|
||||
}
|
||||
break
|
||||
// I key
|
||||
case 73:
|
||||
{
|
||||
const isSuper = global.process.platform === 'darwin'
|
||||
? e.metaKey
|
||||
: e.ctrlKey
|
||||
if (isSuper) {
|
||||
e.preventDefault()
|
||||
this.handleInfoButtonClick(e)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
handleTrashButtonClick (e) {
|
||||
const { note } = this.state
|
||||
const { isTrashed } = note
|
||||
@@ -331,6 +363,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
value={note.content}
|
||||
storageKey={note.storage}
|
||||
noteKey={note.key}
|
||||
linesHighlighted={note.linesHighlighted}
|
||||
onChange={this.handleUpdateContent.bind(this)}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
/>
|
||||
@@ -341,6 +374,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
value={note.content}
|
||||
storageKey={note.storage}
|
||||
noteKey={note.key}
|
||||
linesHighlighted={note.linesHighlighted}
|
||||
onChange={this.handleUpdateContent.bind(this)}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
/>
|
||||
@@ -458,6 +492,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
<div className='NoteDetail'
|
||||
style={this.props.style}
|
||||
styleName='root'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
>
|
||||
|
||||
{location.pathname === '/trashed' ? trashTopBar : detailTopBar}
|
||||
|
||||
@@ -48,7 +48,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
note: Object.assign({
|
||||
description: ''
|
||||
}, props.note, {
|
||||
snippets: props.note.snippets.map((snippet) => Object.assign({}, snippet))
|
||||
snippets: props.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,8 +76,9 @@ class SnippetNoteDetail extends React.Component {
|
||||
const nextNote = Object.assign({
|
||||
description: ''
|
||||
}, nextProps.note, {
|
||||
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
|
||||
snippets: nextProps.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
|
||||
})
|
||||
|
||||
this.setState({
|
||||
snippetIndex: 0,
|
||||
note: nextNote
|
||||
@@ -410,6 +411,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
return (e) => {
|
||||
const snippets = this.state.note.snippets.slice()
|
||||
snippets[index].content = this.refs['code-' + index].value
|
||||
snippets[index].linesHighlighted = e.options.linesHighlighted
|
||||
|
||||
this.setState(state => ({note: Object.assign(state.note, {snippets: snippets})}))
|
||||
this.setState(state => ({
|
||||
note: state.note
|
||||
@@ -434,6 +437,18 @@ class SnippetNoteDetail extends React.Component {
|
||||
this.focusEditor()
|
||||
}
|
||||
break
|
||||
// I key
|
||||
case 73:
|
||||
{
|
||||
const isSuper = global.process.platform === 'darwin'
|
||||
? e.metaKey
|
||||
: e.ctrlKey
|
||||
if (isSuper) {
|
||||
e.preventDefault()
|
||||
this.handleInfoButtonClick(e)
|
||||
}
|
||||
}
|
||||
break
|
||||
// L key
|
||||
case 76:
|
||||
{
|
||||
@@ -590,7 +605,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
note.snippets = note.snippets.concat([{
|
||||
name: '',
|
||||
mode: config.editor.snippetDefaultLanguage || 'text',
|
||||
content: ''
|
||||
content: '',
|
||||
linesHighlighted: []
|
||||
}])
|
||||
const snippetIndex = note.snippets.length - 1
|
||||
|
||||
@@ -633,11 +649,18 @@ class SnippetNoteDetail extends React.Component {
|
||||
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
|
||||
}
|
||||
|
||||
showWarning () {
|
||||
showWarning (e, msg) {
|
||||
const warningMessage = (msg) => ({
|
||||
'export-txt': 'Text export',
|
||||
'export-md': 'Markdown export',
|
||||
'export-html': 'HTML export',
|
||||
'print': 'Print'
|
||||
})[msg]
|
||||
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: i18n.__('Sorry!'),
|
||||
detail: i18n.__('md/text import is available only a markdown note.'),
|
||||
detail: i18n.__(warningMessage(msg) + ' is available only in markdown notes.'),
|
||||
buttons: [i18n.__('OK')]
|
||||
})
|
||||
}
|
||||
@@ -673,10 +696,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
const viewList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
|
||||
let syntax = CodeMirror.findModeByName(convertModeName(snippet.mode))
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
|
||||
return <div styleName='tabView'
|
||||
key={index}
|
||||
style={{zIndex: isActive ? 5 : 4}}
|
||||
@@ -685,6 +706,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
? <MarkdownEditor styleName='tabView-content'
|
||||
value={snippet.content}
|
||||
config={config}
|
||||
linesHighlighted={snippet.linesHighlighted}
|
||||
onChange={(e) => this.handleCodeChange(index)(e)}
|
||||
ref={'code-' + index}
|
||||
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
|
||||
@@ -693,18 +715,27 @@ class SnippetNoteDetail extends React.Component {
|
||||
: <CodeEditor styleName='tabView-content'
|
||||
mode={snippet.mode}
|
||||
value={snippet.content}
|
||||
linesHighlighted={snippet.linesHighlighted}
|
||||
theme={config.editor.theme}
|
||||
fontFamily={config.editor.fontFamily}
|
||||
fontSize={editorFontSize}
|
||||
indentType={config.editor.indentType}
|
||||
indentSize={editorIndentSize}
|
||||
displayLineNumbers={config.editor.displayLineNumbers}
|
||||
matchingPairs={config.editor.matchingPairs}
|
||||
matchingTriples={config.editor.matchingTriples}
|
||||
explodingPairs={config.editor.explodingPairs}
|
||||
codeBlockMatchingPairs={config.editor.codeBlockMatchingPairs}
|
||||
codeBlockMatchingTriples={config.editor.codeBlockMatchingTriples}
|
||||
codeBlockExplodingPairs={config.editor.codeBlockExplodingPairs}
|
||||
keyMap={config.editor.keyMap}
|
||||
scrollPastEnd={config.editor.scrollPastEnd}
|
||||
fetchUrlTitle={config.editor.fetchUrlTitle}
|
||||
enableTableEditor={config.editor.enableTableEditor}
|
||||
onChange={(e) => this.handleCodeChange(index)(e)}
|
||||
ref={'code-' + index}
|
||||
enableSmartPaste={config.editor.enableSmartPaste}
|
||||
hotkey={config.hotkey}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
@@ -788,7 +819,9 @@ class SnippetNoteDetail extends React.Component {
|
||||
createdAt={formatDate(note.createdAt)}
|
||||
exportAsMd={this.showWarning}
|
||||
exportAsTxt={this.showWarning}
|
||||
exportAsHtml={this.showWarning}
|
||||
type={note.type}
|
||||
print={this.showWarning}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
.tabList
|
||||
absolute left right
|
||||
top 55px
|
||||
top 70px
|
||||
height 30px
|
||||
display flex
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
@@ -57,6 +57,9 @@
|
||||
.tabList .tabButton
|
||||
navWhiteButtonColor()
|
||||
width 30px
|
||||
border-left 1px solid $ui-borderColor
|
||||
border-top 1px solid $ui-borderColor
|
||||
border-right 1px solid $ui-borderColor
|
||||
|
||||
.tabView
|
||||
absolute left right bottom
|
||||
@@ -98,17 +101,34 @@
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
body[data-theme="white"]
|
||||
body[data-theme="white"], body[data-theme="default"]
|
||||
.root
|
||||
box-shadow $note-detail-box-shadow
|
||||
border none
|
||||
|
||||
.tabButton
|
||||
&:hover
|
||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||
color $ui-text-color
|
||||
transition 0.15s
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
border-left 1px solid $ui-dark-borderColor
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
box-shadow none
|
||||
|
||||
.tabList .tabButton
|
||||
border-color $ui-dark-borderColor
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
|
||||
.tabButton
|
||||
&:hover
|
||||
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||
color $ui-dark-text-color
|
||||
transition 0.15s
|
||||
|
||||
.body
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
@@ -118,7 +138,6 @@ body[data-theme="dark"]
|
||||
border 1px solid $ui-dark-borderColor
|
||||
|
||||
.tabList
|
||||
background-color $ui-button--active-backgroundColor
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
.tabList .list
|
||||
@@ -150,6 +169,15 @@ body[data-theme="solarized-dark"]
|
||||
color $ui-solarized-dark-text-color
|
||||
border 1px solid $ui-solarized-dark-borderColor
|
||||
|
||||
.tabList .tabButton
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
|
||||
.tabButton
|
||||
&:hover
|
||||
color $ui-solarized-dark-button--active-color
|
||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||
transition 0.15s
|
||||
|
||||
.tabList
|
||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||
color $ui-solarized-dark-text-color
|
||||
@@ -167,6 +195,14 @@ body[data-theme="monokai"]
|
||||
color $ui-monokai-text-color
|
||||
border 1px solid $ui-monokai-borderColor
|
||||
|
||||
.tabList .tabButton
|
||||
border-color $ui-monokai-borderColor
|
||||
|
||||
.tabButton
|
||||
&:hover
|
||||
color $ui-monokai-text-color
|
||||
background-color $ui-monokai-noteDetail-backgroundColor
|
||||
|
||||
.tabList
|
||||
background-color $ui-monokai-noteDetail-backgroundColor
|
||||
color $ui-monokai-text-color
|
||||
@@ -184,6 +220,14 @@ body[data-theme="dracula"]
|
||||
color $ui-dracula-text-color
|
||||
border 1px solid $ui-dracula-borderColor
|
||||
|
||||
.tabList .tabButton
|
||||
border-color $ui-dracula-borderColor
|
||||
|
||||
.tabButton
|
||||
&:hover
|
||||
color $ui-dracula-text-color
|
||||
background-color $ui-dracula-noteDetail-backgroundColor
|
||||
|
||||
.tabList
|
||||
background-color $ui-dracula-noteDetail-backgroundColor
|
||||
color $ui-dracula-text-color
|
||||
@@ -45,8 +45,14 @@ class TagSelect extends React.Component {
|
||||
value = _.isArray(value)
|
||||
? value.slice()
|
||||
: []
|
||||
value.push(newTag)
|
||||
value = _.uniq(value)
|
||||
|
||||
if (!_.includes(value, newTag)) {
|
||||
value.push(newTag)
|
||||
}
|
||||
|
||||
if (this.props.saveTagsAlphabetically) {
|
||||
value = _.sortBy(value)
|
||||
}
|
||||
|
||||
this.setState({
|
||||
newTag: ''
|
||||
|
||||
Reference in New Issue
Block a user