mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 09:46:22 +00:00
Merge branch 'master' into filter-tags-and-folders
# Conflicts: # locales/zh-CN.json
This commit is contained in:
@@ -273,7 +273,7 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { rulers, enableRulers, enableMarkdownLint } = this.props
|
||||
const { rulers, enableRulers, enableMarkdownLint, RTL } = this.props
|
||||
eventEmitter.on('line:jump', this.scrollToLineHandeler)
|
||||
|
||||
snippetManager.init()
|
||||
@@ -294,6 +294,8 @@ export default class CodeEditor extends React.Component {
|
||||
scrollPastEnd: this.props.scrollPastEnd,
|
||||
inputStyle: 'textarea',
|
||||
dragDrop: false,
|
||||
direction: RTL ? 'rtl' : 'ltr',
|
||||
rtlMoveVisually: RTL,
|
||||
foldGutter: true,
|
||||
lint: enableMarkdownLint ? this.getCodeEditorLintConfig() : false,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||
@@ -555,6 +557,10 @@ export default class CodeEditor extends React.Component {
|
||||
if (prevProps.keyMap !== this.props.keyMap) {
|
||||
needRefresh = true
|
||||
}
|
||||
if (prevProps.RTL !== this.props.RTL) {
|
||||
this.editor.setOption('direction', this.props.RTL ? 'rtl' : 'ltr')
|
||||
this.editor.setOption('rtlMoveVisually', this.props.RTL)
|
||||
}
|
||||
if (prevProps.enableMarkdownLint !== enableMarkdownLint || prevProps.customMarkdownLintConfig !== customMarkdownLintConfig) {
|
||||
if (!enableMarkdownLint) {
|
||||
this.editor.setOption('lint', {default: false})
|
||||
@@ -1219,7 +1225,8 @@ CodeEditor.propTypes = {
|
||||
spellCheck: PropTypes.bool,
|
||||
enableMarkdownLint: PropTypes.bool,
|
||||
customMarkdownLintConfig: PropTypes.string,
|
||||
deleteUnusedAttachments: PropTypes.bool
|
||||
deleteUnusedAttachments: PropTypes.bool,
|
||||
RTL: PropTypes.bool
|
||||
}
|
||||
|
||||
CodeEditor.defaultProps = {
|
||||
@@ -1235,5 +1242,6 @@ CodeEditor.defaultProps = {
|
||||
enableMarkdownLint: DEFAULT_CONFIG.editor.enableMarkdownLint,
|
||||
customMarkdownLintConfig: DEFAULT_CONFIG.editor.customMarkdownLintConfig,
|
||||
prettierConfig: DEFAULT_CONFIG.editor.prettierConfig,
|
||||
deleteUnusedAttachments: DEFAULT_CONFIG.editor.deleteUnusedAttachments
|
||||
deleteUnusedAttachments: DEFAULT_CONFIG.editor.deleteUnusedAttachments,
|
||||
RTL: false
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const {className, value, config, storageKey, noteKey, linesHighlighted} = this.props
|
||||
const {className, value, config, storageKey, noteKey, linesHighlighted, RTL} = this.props
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
@@ -325,6 +325,7 @@ class MarkdownEditor extends React.Component {
|
||||
customMarkdownLintConfig={config.editor.customMarkdownLintConfig}
|
||||
prettierConfig={config.editor.prettierConfig}
|
||||
deleteUnusedAttachments={config.editor.deleteUnusedAttachments}
|
||||
RTL={RTL}
|
||||
/>
|
||||
<MarkdownPreview styleName={this.state.status === 'PREVIEW'
|
||||
? 'preview'
|
||||
@@ -360,6 +361,7 @@ class MarkdownEditor extends React.Component {
|
||||
allowCustomCSS={config.preview.allowCustomCSS}
|
||||
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
||||
onDrop={(e) => this.handleDropImage(e)}
|
||||
RTL={RTL}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@ import yaml from 'js-yaml'
|
||||
import { render } from 'react-dom'
|
||||
import Carousel from 'react-image-carousel'
|
||||
import ConfigManager from '../main/lib/ConfigManager'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
const { remote, shell } = require('electron')
|
||||
const attachmentManagement = require('../main/lib/dataApi/attachmentManagement')
|
||||
@@ -63,7 +64,8 @@ function buildStyle (opts) {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
} = opts
|
||||
return `
|
||||
@font-face {
|
||||
@@ -100,11 +102,14 @@ ${markdownStyle}
|
||||
body {
|
||||
font-family: '${fontFamily.join("','")}';
|
||||
font-size: ${fontSize}px;
|
||||
|
||||
${scrollPastEnd ? `
|
||||
padding-bottom: 90vh;
|
||||
box-sizing: border-box;
|
||||
`
|
||||
: ''}
|
||||
${RTL ? 'direction: rtl;' : ''}
|
||||
${RTL ? 'text-align: right;' : ''}
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
@@ -114,6 +119,8 @@ body {
|
||||
code {
|
||||
font-family: '${codeBlockFontFamily.join("','")}';
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
text-align: left;
|
||||
direction: ltr;
|
||||
}
|
||||
.lineNumber {
|
||||
${lineNumber && 'display: block !important;'}
|
||||
@@ -245,6 +252,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.saveAsHtmlHandler = () => this.handleSaveAsHtml()
|
||||
this.saveAsPdfHandler = () => this.handleSaveAsPdf()
|
||||
this.printHandler = () => this.handlePrint()
|
||||
this.resizeHandler = _.throttle(this.handleResize.bind(this), 100)
|
||||
|
||||
this.linkClickHandler = this.handleLinkClick.bind(this)
|
||||
this.initMarkdown = this.initMarkdown.bind(this)
|
||||
@@ -335,7 +343,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.getStyleParams()
|
||||
|
||||
const inlineStyles = buildStyle({
|
||||
@@ -346,9 +355,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
let body = this.markdown.render(noteContent)
|
||||
let body = this.refs.root.contentWindow.document.body.innerHTML
|
||||
body = attachmentManagement.fixLocalURLS(
|
||||
body,
|
||||
this.props.storagePath
|
||||
@@ -368,7 +378,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
|
||||
let styles = ''
|
||||
files.forEach(file => {
|
||||
styles += `<link rel="stylesheet" href="css/${path.basename(file)}">`
|
||||
styles += `<link rel="stylesheet" href="../css/${path.basename(file)}">`
|
||||
})
|
||||
|
||||
return `<html>
|
||||
@@ -423,7 +433,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
.then(res => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: `Exported to ${filename}`
|
||||
message: `Exported to ${filename}`,
|
||||
buttons: [i18n.__('Ok')]
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
@@ -538,6 +549,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
'scroll',
|
||||
this.scrollHandler
|
||||
)
|
||||
this.refs.root.contentWindow.addEventListener(
|
||||
'resize',
|
||||
this.resizeHandler
|
||||
)
|
||||
eventEmitter.on('export:save-text', this.saveAsTextHandler)
|
||||
eventEmitter.on('export:save-md', this.saveAsMdHandler)
|
||||
eventEmitter.on('export:save-html', this.saveAsHtmlHandler)
|
||||
@@ -576,6 +591,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
'scroll',
|
||||
this.scrollHandler
|
||||
)
|
||||
this.refs.root.contentWindow.removeEventListener(
|
||||
'resize',
|
||||
this.resizeHandler
|
||||
)
|
||||
eventEmitter.off('export:save-text', this.saveAsTextHandler)
|
||||
eventEmitter.off('export:save-md', this.saveAsMdHandler)
|
||||
eventEmitter.off('export:save-html', this.saveAsHtmlHandler)
|
||||
@@ -608,7 +627,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
prevProps.theme !== this.props.theme ||
|
||||
prevProps.scrollPastEnd !== this.props.scrollPastEnd ||
|
||||
prevProps.allowCustomCSS !== this.props.allowCustomCSS ||
|
||||
prevProps.customCSS !== this.props.customCSS
|
||||
prevProps.customCSS !== this.props.customCSS ||
|
||||
prevProps.RTL !== this.props.RTL
|
||||
) {
|
||||
this.applyStyle()
|
||||
needsRewriteIframe = true
|
||||
@@ -632,7 +652,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.props
|
||||
let { fontFamily, codeBlockFontFamily } = this.props
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
|
||||
@@ -658,7 +679,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,7 +694,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.getStyleParams()
|
||||
|
||||
this.getWindow().document.getElementById(
|
||||
@@ -686,7 +709,8 @@ export default class MarkdownPreview extends React.Component {
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
}
|
||||
|
||||
@@ -995,6 +1019,15 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleResize () {
|
||||
_.forEach(
|
||||
this.refs.root.contentWindow.document.querySelectorAll('svg[ratio]'),
|
||||
el => {
|
||||
el.setAttribute('height', el.clientWidth / el.getAttribute('ratio'))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
focus () {
|
||||
this.refs.root.focus()
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ class MarkdownSplitEditor extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const {config, value, storageKey, noteKey, linesHighlighted} = this.props
|
||||
const {config, value, storageKey, noteKey, linesHighlighted, RTL} = this.props
|
||||
const storage = findStorage(storageKey)
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
@@ -183,6 +183,7 @@ class MarkdownSplitEditor extends React.Component {
|
||||
enableMarkdownLint={config.editor.enableMarkdownLint}
|
||||
customMarkdownLintConfig={config.editor.customMarkdownLintConfig}
|
||||
deleteUnusedAttachments={config.editor.deleteUnusedAttachments}
|
||||
RTL={RTL}
|
||||
/>
|
||||
<div styleName='slider' style={{left: this.state.codeEditorWidthInPercent + '%'}} onMouseDown={e => this.handleMouseDown(e)} >
|
||||
<div styleName='slider-hitbox' />
|
||||
@@ -213,6 +214,7 @@ class MarkdownSplitEditor extends React.Component {
|
||||
customCSS={config.preview.customCSS}
|
||||
allowCustomCSS={config.preview.allowCustomCSS}
|
||||
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
||||
RTL={RTL}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { isArray, sortBy } from 'lodash'
|
||||
import invertColor from 'invert-color'
|
||||
import Emoji from 'react-emoji-render'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import { getTodoStatus } from 'browser/lib/getTodoStatus'
|
||||
import styles from './NoteItem.styl'
|
||||
@@ -87,7 +88,7 @@ const NoteItem = ({
|
||||
: <i styleName='item-title-icon' className='fa fa-fw fa-file-text-o' />}
|
||||
<div styleName='item-title'>
|
||||
{note.title.trim().length > 0
|
||||
? note.title
|
||||
? <Emoji text={note.title} />
|
||||
: <span styleName='item-title-empty'>{i18n.__('Empty note')}</span>}
|
||||
</div>
|
||||
<div styleName='item-middle'>
|
||||
|
||||
@@ -427,6 +427,9 @@ pre.fence
|
||||
canvas, svg
|
||||
max-width 100% !important
|
||||
|
||||
svg[ratio]
|
||||
width 100%
|
||||
|
||||
.gallery
|
||||
width 100%
|
||||
height 50vh
|
||||
@@ -447,6 +450,44 @@ pre.fence
|
||||
color $ui-text-color
|
||||
background-color $ui-tag-backgroundColor
|
||||
|
||||
.markdownIt-TOC-wrapper
|
||||
list-style none
|
||||
position fixed
|
||||
right 0
|
||||
top 0
|
||||
margin-left 15px
|
||||
z-index 1000
|
||||
transition transform .2s ease-in-out
|
||||
transform translateX(100%)
|
||||
|
||||
.markdownIt-TOC
|
||||
display block
|
||||
max-height 90vh
|
||||
overflow-y auto
|
||||
padding 25px
|
||||
padding-left 38px
|
||||
|
||||
&,
|
||||
&:before
|
||||
background-color $ui-dark-backgroundColor
|
||||
color: $ui-dark-text-color
|
||||
|
||||
&:hover
|
||||
transform translateX(-15px)
|
||||
|
||||
&:before
|
||||
content 'TOC'
|
||||
position absolute
|
||||
width 60px
|
||||
height 30px
|
||||
top 60px
|
||||
left -29px
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
transform-origin top left
|
||||
transform rotate(-90deg)
|
||||
|
||||
themeDarkBackground = darken(#21252B, 10%)
|
||||
themeDarkText = #f9f9f9
|
||||
themeDarkBorder = lighten(themeDarkBackground, 20%)
|
||||
@@ -514,6 +555,14 @@ body[data-theme="dark"]
|
||||
color $ui-dark-text-color
|
||||
background-color $ui-dark-tag-backgroundColor
|
||||
|
||||
.markdownIt-TOC-wrapper
|
||||
&,
|
||||
&:before
|
||||
background-color darken(themeDarkBackground, 5%)
|
||||
color themeDarkText
|
||||
|
||||
|
||||
themeSolarizedDarkBackground = $ui-solarized-dark-noteDetail-backgroundColor
|
||||
themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor
|
||||
themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%)
|
||||
themeSolarizedDarkTableHead = themeSolarizedDarkTableEven
|
||||
@@ -522,7 +571,7 @@ themeSolarizedDarkTableBorder = themeDarkBorder
|
||||
body[data-theme="solarized-dark"]
|
||||
color $ui-solarized-dark-text-color
|
||||
border-color themeDarkBorder
|
||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||
background-color themeSolarizedDarkBackground
|
||||
table
|
||||
thead
|
||||
tr
|
||||
@@ -557,6 +606,13 @@ body[data-theme="solarized-dark"]
|
||||
color $ui-solarized-dark-button--active-color
|
||||
background-color $ui-solarized-dark-button-backgroundColor
|
||||
|
||||
.markdownIt-TOC-wrapper
|
||||
&,
|
||||
&:before
|
||||
background-color darken(themeSolarizedDarkBackground, 15%)
|
||||
color themeDarkText
|
||||
|
||||
themeMonokaiBackground = $ui-monokai-noteDetail-backgroundColor
|
||||
themeMonokaiTableOdd = $ui-monokai-noteDetail-backgroundColor
|
||||
themeMonokaiTableEven = darken($ui-monokai-noteDetail-backgroundColor, 10%)
|
||||
themeMonokaiTableHead = themeMonokaiTableEven
|
||||
@@ -565,7 +621,7 @@ themeMonokaiTableBorder = themeDarkBorder
|
||||
body[data-theme="monokai"]
|
||||
color $ui-monokai-text-color
|
||||
border-color themeDarkBorder
|
||||
background-color $ui-monokai-noteDetail-backgroundColor
|
||||
background-color themeMonokaiBackground
|
||||
table
|
||||
thead
|
||||
tr
|
||||
@@ -603,6 +659,13 @@ body[data-theme="monokai"]
|
||||
color $ui-monokai-button--active-color
|
||||
background-color $ui-monokai-button-backgroundColor
|
||||
|
||||
.markdownIt-TOC-wrapper
|
||||
&,
|
||||
&:before
|
||||
background-color darken(themeMonokaiBackground, 15%)
|
||||
color themeDarkText
|
||||
|
||||
themeDraculaBackground = $ui-dracula-noteDetail-backgroundColor
|
||||
themeDraculaTableOdd = $ui-dracula-noteDetail-backgroundColor
|
||||
themeDraculaTableEven = darken($ui-dracula-noteDetail-backgroundColor, 10%)
|
||||
themeDraculaTableHead = themeDraculaTableEven
|
||||
@@ -611,7 +674,7 @@ themeDraculaTableBorder = themeDarkBorder
|
||||
body[data-theme="dracula"]
|
||||
color $ui-dracula-text-color
|
||||
border-color themeDarkBorder
|
||||
background-color $ui-dracula-noteDetail-backgroundColor
|
||||
background-color themeDraculaBackground
|
||||
table
|
||||
thead
|
||||
tr
|
||||
@@ -648,3 +711,9 @@ body[data-theme="dracula"]
|
||||
.prev, .next
|
||||
color $ui-dracula-button--active-color
|
||||
background-color $ui-dracula-button-backgroundColor
|
||||
|
||||
.markdownIt-TOC-wrapper
|
||||
&,
|
||||
&:before
|
||||
background-color darken(themeDraculaBackground, 15%)
|
||||
color themeDarkText
|
||||
|
||||
@@ -22,18 +22,40 @@ function getId () {
|
||||
function render (element, content, theme, enableHTMLLabel) {
|
||||
try {
|
||||
const height = element.attributes.getNamedItem('data-height')
|
||||
if (height && height.value !== 'undefined') {
|
||||
const isPredefined = height && height.value !== 'undefined'
|
||||
if (isPredefined) {
|
||||
element.style.height = height.value + 'vh'
|
||||
}
|
||||
const isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai' || theme === 'dracula'
|
||||
mermaidAPI.initialize({
|
||||
theme: isDarkTheme ? 'dark' : 'default',
|
||||
themeCSS: isDarkTheme ? darkThemeStyling : '',
|
||||
useMaxWidth: false,
|
||||
flowchart: { htmlLabels: enableHTMLLabel }
|
||||
flowchart: {
|
||||
htmlLabels: enableHTMLLabel
|
||||
},
|
||||
gantt: {
|
||||
useWidth: element.clientWidth
|
||||
}
|
||||
})
|
||||
mermaidAPI.render(getId(), content, (svgGraph) => {
|
||||
element.innerHTML = svgGraph
|
||||
|
||||
if (!isPredefined) {
|
||||
const el = element.firstChild
|
||||
const viewBox = el.getAttribute('viewBox').split(' ')
|
||||
|
||||
let ratio = viewBox[2] / viewBox[3]
|
||||
|
||||
if (el.style.maxWidth) {
|
||||
const maxWidth = parseFloat(el.style.maxWidth)
|
||||
|
||||
ratio *= el.parentNode.clientWidth / maxWidth
|
||||
}
|
||||
|
||||
el.setAttribute('ratio', ratio)
|
||||
el.setAttribute('height', el.parentNode.clientWidth / ratio)
|
||||
console.log(el)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
element.className = 'mermaid-error'
|
||||
|
||||
@@ -128,12 +128,19 @@ class Markdown {
|
||||
this.md.use(require('markdown-it-abbr'))
|
||||
this.md.use(require('markdown-it-sub'))
|
||||
this.md.use(require('markdown-it-sup'))
|
||||
this.md.use(markdownItTocAndAnchor, {
|
||||
toc: true,
|
||||
tocPattern: /\[TOC\]/i,
|
||||
anchorLink: false,
|
||||
appendIdToHeading: false
|
||||
|
||||
this.md.use(md => {
|
||||
markdownItTocAndAnchor(md, {
|
||||
toc: true,
|
||||
tocPattern: /\[TOC\]/i,
|
||||
anchorLink: false,
|
||||
appendIdToHeading: false
|
||||
})
|
||||
|
||||
md.renderer.rules.toc_open = () => '<div class="markdownIt-TOC-wrapper">'
|
||||
md.renderer.rules.toc_close = () => '</div>'
|
||||
})
|
||||
|
||||
this.md.use(require('./markdown-it-deflist'))
|
||||
this.md.use(require('./markdown-it-frontmatter'))
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
||||
import markdownToc from 'browser/lib/markdown-toc-generator'
|
||||
import queryString from 'query-string'
|
||||
import { replace } from 'connected-react-router'
|
||||
import ToggleDirectionButton from 'browser/main/Detail/ToggleDirectionButton'
|
||||
|
||||
class MarkdownNoteDetail extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -46,7 +47,8 @@ class MarkdownNoteDetail extends React.Component {
|
||||
isLockButtonShown: props.config.editor.type !== 'SPLIT',
|
||||
isLocked: false,
|
||||
editorType: props.config.editor.type,
|
||||
switchPreview: props.config.editor.switchPreview
|
||||
switchPreview: props.config.editor.switchPreview,
|
||||
RTL: false
|
||||
}
|
||||
|
||||
this.dispatchTimer = null
|
||||
@@ -61,6 +63,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
componentDidMount () {
|
||||
ee.on('topbar:togglelockbutton', this.toggleLockButton)
|
||||
ee.on('topbar:toggledirectionbutton', () => this.handleSwitchDirection())
|
||||
ee.on('topbar:togglemodebutton', () => {
|
||||
const reversedType = this.state.editorType === 'SPLIT' ? 'EDITOR_PREVIEW' : 'SPLIT'
|
||||
this.handleSwitchMode(reversedType)
|
||||
@@ -99,6 +102,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
componentWillUnmount () {
|
||||
ee.off('topbar:togglelockbutton', this.toggleLockButton)
|
||||
ee.on('topbar:toggledirectionbutton', this.handleSwitchDirection)
|
||||
ee.off('code:generate-toc', this.generateToc)
|
||||
if (this.saveQueue != null) this.saveNow()
|
||||
}
|
||||
@@ -354,6 +358,12 @@ class MarkdownNoteDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleSwitchDirection () {
|
||||
// If in split mode, hide the lock button
|
||||
const direction = this.state.RTL
|
||||
this.setState({ RTL: !direction })
|
||||
}
|
||||
|
||||
handleDeleteNote () {
|
||||
this.handleTrashButtonClick()
|
||||
}
|
||||
@@ -393,6 +403,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
onChange={this.handleUpdateContent.bind(this)}
|
||||
isLocked={this.state.isLocked}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
RTL={this.state.RTL}
|
||||
/>
|
||||
} else {
|
||||
return <MarkdownSplitEditor
|
||||
@@ -404,6 +415,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
linesHighlighted={note.linesHighlighted}
|
||||
onChange={this.handleUpdateContent.bind(this)}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
RTL={this.state.RTL}
|
||||
/>
|
||||
}
|
||||
}
|
||||
@@ -472,7 +484,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
</div>
|
||||
<div styleName='info-right'>
|
||||
<ToggleModeButton onClick={(e) => this.handleSwitchMode(e)} editorType={editorType} />
|
||||
|
||||
<ToggleDirectionButton onClick={(e) => this.handleSwitchDirection(e)} isRTL={this.state.RTL} />
|
||||
<StarButton
|
||||
onClick={(e) => this.handleStarButtonClick(e)}
|
||||
isActive={note.isStarred}
|
||||
@@ -518,6 +530,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
print={this.print}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
return (
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
.control-lockButton
|
||||
topBarButtonRight()
|
||||
position absolute
|
||||
right 225px
|
||||
right 265px
|
||||
&:hover .tooltip
|
||||
opacity 1
|
||||
|
||||
|
||||
26
browser/main/Detail/ToggleDirectionButton.js
Normal file
26
browser/main/Detail/ToggleDirectionButton.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './ToggleDirectionButton.styl'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
const ToggleDirectionButton = ({
|
||||
onClick, isRTL
|
||||
}) => (
|
||||
<div styleName='control-toggleModeButton'>
|
||||
<div styleName={isRTL ? 'active' : undefined} onClick={() => onClick()}>
|
||||
<img src={!isRTL ? '../resources/icon/icon-left-to-right.svg' : ''} />
|
||||
</div>
|
||||
<div styleName={!isRTL ? 'active' : undefined} onClick={() => onClick()}>
|
||||
<img src={!isRTL ? '' : '../resources/icon/icon-right-to-left.svg'} />
|
||||
</div>
|
||||
<span lang={i18n.locale} styleName='tooltip'>{i18n.__('Toggle Direction')}</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
ToggleDirectionButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
isRTL: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(ToggleDirectionButton, styles)
|
||||
85
browser/main/Detail/ToggleDirectionButton.styl
Normal file
85
browser/main/Detail/ToggleDirectionButton.styl
Normal file
@@ -0,0 +1,85 @@
|
||||
.control-toggleModeButton
|
||||
height 25px
|
||||
border-radius 50px
|
||||
background-color #F4F4F4
|
||||
width 52px
|
||||
display flex
|
||||
align-items center
|
||||
position: relative
|
||||
top 2px
|
||||
margin-left 5px
|
||||
.active
|
||||
background-color #1EC38B
|
||||
width 33px
|
||||
height 24px
|
||||
box-shadow 2px 0px 7px #eee
|
||||
z-index 1
|
||||
|
||||
div
|
||||
width 40px
|
||||
height 100%
|
||||
border-radius 50%
|
||||
display flex
|
||||
align-items center
|
||||
justify-content center
|
||||
cursor pointer
|
||||
|
||||
&:hover .tooltip
|
||||
opacity 1
|
||||
|
||||
.tooltip
|
||||
tooltip()
|
||||
position absolute
|
||||
pointer-events none
|
||||
top 33px
|
||||
left -10px
|
||||
z-index 200
|
||||
width 80px
|
||||
padding 5px
|
||||
line-height normal
|
||||
border-radius 2px
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
.tooltip:lang(ja)
|
||||
@extend .tooltip
|
||||
left -8px
|
||||
width 70px
|
||||
|
||||
body[data-theme="dark"]
|
||||
.control-fullScreenButton
|
||||
topBarButtonDark()
|
||||
|
||||
.control-toggleModeButton
|
||||
background-color #3A404C
|
||||
.active
|
||||
background-color #1EC38B
|
||||
box-shadow 2px 0px 7px #444444
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.control-toggleModeButton
|
||||
background-color #002B36
|
||||
.active
|
||||
background-color #1EC38B
|
||||
box-shadow 2px 0px 7px #222222
|
||||
|
||||
body[data-theme="monokai"]
|
||||
.control-toggleModeButton
|
||||
background-color #373831
|
||||
.active
|
||||
background-color #f92672
|
||||
box-shadow 2px 0px 7px #222222
|
||||
|
||||
body[data-theme="dracula"]
|
||||
.control-toggleModeButton
|
||||
background-color #44475a
|
||||
.active
|
||||
background-color #bd93f9
|
||||
box-shadow 2px 0px 7px #222222
|
||||
|
||||
.control-toggleModeButton
|
||||
-webkit-user-drag none
|
||||
user-select none
|
||||
> div img
|
||||
-webkit-user-drag none
|
||||
user-select none
|
||||
@@ -182,4 +182,4 @@ body[data-theme="default"]
|
||||
.SideNav ::-webkit-scrollbar-thumb
|
||||
background-color rgba(255, 255, 255, 0.3)
|
||||
|
||||
@import '../styles/Detail/TagSelect.styl'
|
||||
@import '../styles/Detail/TagSelect.styl'
|
||||
|
||||
@@ -31,6 +31,7 @@ export const DEFAULT_CONFIG = {
|
||||
hotkey: {
|
||||
toggleMain: OSX ? 'Command + Alt + L' : 'Super + Alt + E',
|
||||
toggleMode: OSX ? 'Command + Alt + M' : 'Ctrl + M',
|
||||
toggleDirection: OSX ? 'Command + Alt + Right' : 'Ctrl + Right',
|
||||
deleteNote: OSX ? 'Command + Shift + Backspace' : 'Ctrl + Shift + Backspace',
|
||||
pasteSmartly: OSX ? 'Command + Shift + V' : 'Ctrl + Shift + V',
|
||||
prettifyMarkdown: OSX ? 'Command + Shift + F' : 'Ctrl + Shift + F',
|
||||
@@ -75,7 +76,7 @@ export const DEFAULT_CONFIG = {
|
||||
customMarkdownLintConfig: DEFAULT_MARKDOWN_LINT_CONFIG,
|
||||
prettierConfig: ` {
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}`,
|
||||
|
||||
@@ -4,6 +4,9 @@ module.exports = {
|
||||
'toggleMode': () => {
|
||||
ee.emit('topbar:togglemodebutton')
|
||||
},
|
||||
'toggleDirection': () => {
|
||||
ee.emit('topbar:toggledirectionbutton')
|
||||
},
|
||||
'deleteNote': () => {
|
||||
ee.emit('hotkey:deletenote')
|
||||
},
|
||||
|
||||
@@ -30,7 +30,8 @@ class HotkeyTab extends React.Component {
|
||||
this.handleSettingError = (err) => {
|
||||
if (
|
||||
this.state.config.hotkey.toggleMain === '' ||
|
||||
this.state.config.hotkey.toggleMode === ''
|
||||
this.state.config.hotkey.toggleMode === '' ||
|
||||
this.state.config.hotkey.toggleDirection === ''
|
||||
) {
|
||||
this.setState({keymapAlert: {
|
||||
type: 'success',
|
||||
@@ -79,6 +80,7 @@ class HotkeyTab extends React.Component {
|
||||
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,
|
||||
prettifyMarkdown: this.refs.prettifyMarkdown.value,
|
||||
@@ -154,6 +156,17 @@ class HotkeyTab extends React.Component {
|
||||
/>
|
||||
</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'>
|
||||
|
||||
@@ -142,7 +142,7 @@ class InfoTab extends React.Component {
|
||||
>{i18n.__('Development')}</a>{i18n.__(' : Development configurations for Boostnote.')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('Copyright (C) 2017 - 2019 BoostIO')}
|
||||
{i18n.__('Copyright (C) 2017 - 2020 BoostIO')}
|
||||
</li>
|
||||
<li styleName='cc'>
|
||||
{i18n.__('License: GPL v3')}
|
||||
|
||||
Reference in New Issue
Block a user