mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
Merge branch 'master' into master
This commit is contained in:
@@ -663,8 +663,8 @@ export default class CodeEditor extends React.Component {
|
||||
const checkMarkdownNoteIsOpen = mode === 'Boost Flavored Markdown'
|
||||
|
||||
return checkMarkdownNoteIsOpen ? {
|
||||
'getAnnotations': this.validatorOfMarkdown,
|
||||
'async': true
|
||||
getAnnotations: this.validatorOfMarkdown,
|
||||
async: true
|
||||
} : false
|
||||
}
|
||||
|
||||
@@ -679,10 +679,10 @@ export default class CodeEditor extends React.Component {
|
||||
return
|
||||
}
|
||||
const lintOptions = {
|
||||
'strings': {
|
||||
'content': text
|
||||
strings: {
|
||||
content: text
|
||||
},
|
||||
'config': lintConfigJson
|
||||
config: lintConfigJson
|
||||
}
|
||||
|
||||
return markdownlint(lintOptions, (err, result) => {
|
||||
|
||||
@@ -119,7 +119,7 @@ class MarkdownEditor extends React.Component {
|
||||
status: 'PREVIEW'
|
||||
}, () => {
|
||||
this.refs.preview.focus()
|
||||
this.refs.preview.scrollTo(cursorPosition.line)
|
||||
this.refs.preview.scrollToRow(cursorPosition.line)
|
||||
})
|
||||
eventEmitter.emit('topbar:togglelockbutton', this.state.status)
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
@@ -50,7 +51,6 @@ const CSS_FILES = [
|
||||
* @param {String} opts.theme
|
||||
* @param {Boolean} [opts.lineNumber] Should show line number
|
||||
* @param {Boolean} [opts.scrollPastEnd]
|
||||
* @param {Boolean} [opts.optimizeOverflowScroll] Should tweak body style to optimize overflow scrollbar display
|
||||
* @param {Boolean} [opts.allowCustomCSS] Should add custom css
|
||||
* @param {String} [opts.customCSS] Will be added to bottom, only if `opts.allowCustomCSS` is truthy
|
||||
* @returns {String}
|
||||
@@ -62,7 +62,6 @@ function buildStyle (opts) {
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
optimizeOverflowScroll,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
@@ -103,7 +102,12 @@ ${markdownStyle}
|
||||
body {
|
||||
font-family: '${fontFamily.join("','")}';
|
||||
font-size: ${fontSize}px;
|
||||
${scrollPastEnd ? 'padding-bottom: 90vh;' : ''}
|
||||
|
||||
${scrollPastEnd ? `
|
||||
padding-bottom: 90vh;
|
||||
box-sizing: border-box;
|
||||
`
|
||||
: ''}
|
||||
${optimizeOverflowScroll ? 'height: 100%;' : ''}
|
||||
${RTL ? 'direction: rtl;' : ''}
|
||||
${RTL ? 'text-align: right;' : ''}
|
||||
@@ -184,6 +188,10 @@ const scrollBarStyle = `
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece {
|
||||
background-color: inherit;
|
||||
}
|
||||
`
|
||||
const scrollBarDarkStyle = `
|
||||
::-webkit-scrollbar {
|
||||
@@ -193,6 +201,10 @@ const scrollBarDarkStyle = `
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece {
|
||||
background-color: inherit;
|
||||
}
|
||||
`
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
@@ -241,6 +253,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)
|
||||
@@ -346,7 +359,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
let body = this.markdown.render(noteContent)
|
||||
let body = this.refs.root.contentWindow.document.body.innerHTML
|
||||
body = attachmentManagement.fixLocalURLS(
|
||||
body,
|
||||
this.props.storagePath
|
||||
@@ -366,7 +379,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>
|
||||
@@ -421,7 +434,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 => {
|
||||
@@ -536,6 +550,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)
|
||||
@@ -574,6 +592,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)
|
||||
@@ -619,7 +641,7 @@ export default class MarkdownPreview extends React.Component {
|
||||
|
||||
// Should scroll to top after selecting another note
|
||||
if (prevProps.noteKey !== this.props.noteKey) {
|
||||
this.getWindow().scrollTo(0, 0)
|
||||
this.scrollTo(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,13 +708,11 @@ export default class MarkdownPreview extends React.Component {
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
optimizeOverflowScroll: true,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
this.getWindow().document.documentElement.style.overflowY = 'hidden'
|
||||
}
|
||||
|
||||
getCodeThemeLink (name) {
|
||||
@@ -1000,6 +1020,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()
|
||||
}
|
||||
@@ -1008,7 +1037,11 @@ export default class MarkdownPreview extends React.Component {
|
||||
return this.refs.root.contentWindow
|
||||
}
|
||||
|
||||
scrollTo (targetRow) {
|
||||
/**
|
||||
* @public
|
||||
* @param {Number} targetRow
|
||||
*/
|
||||
scrollToRow (targetRow) {
|
||||
const blocks = this.getWindow().document.querySelectorAll(
|
||||
'body>[data-line]'
|
||||
)
|
||||
@@ -1018,12 +1051,21 @@ export default class MarkdownPreview extends React.Component {
|
||||
const row = parseInt(block.getAttribute('data-line'))
|
||||
if (row > targetRow || index === blocks.length - 1) {
|
||||
block = blocks[index - 1]
|
||||
block != null && this.getWindow().scrollTo(0, block.offsetTop)
|
||||
block != null && this.scrollTo(0, block.offsetTop)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `document.body.scrollTo`
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
scrollTo (x, y) {
|
||||
this.getWindow().document.body.scrollTo(x, y)
|
||||
}
|
||||
|
||||
preventImageDroppedHandler (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@@ -1061,12 +1103,12 @@ export default class MarkdownPreview extends React.Component {
|
||||
if (posOfHash > -1) {
|
||||
const extractedId = linkHash.slice(posOfHash + 1)
|
||||
const targetId = mdurl.encode(extractedId)
|
||||
const targetElement = this.refs.root.contentWindow.document.getElementById(
|
||||
const targetElement = this.getWindow().document.getElementById(
|
||||
targetId
|
||||
)
|
||||
|
||||
if (targetElement != null) {
|
||||
this.getWindow().scrollTo(0, targetElement.offsetTop)
|
||||
this.scrollTo(0, targetElement.offsetTop)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -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'>
|
||||
|
||||
@@ -363,7 +363,10 @@ admonition_types = {
|
||||
danger: {color: #c2185b, icon: "block"},
|
||||
caution: {color: #ffa726, icon: "warning"},
|
||||
error: {color: #d32f2f, icon: "error_outline"},
|
||||
attention: {color: #455a64, icon: "priority_high"}
|
||||
question: {color: #64dd17, icon: "help_outline"},
|
||||
quote: {color: #9e9e9e, icon: "format_quote"},
|
||||
abstract: {color: #00b0ff, icon: "subject"},
|
||||
attention: {color: #455a64, icon: "priority_high"},
|
||||
}
|
||||
|
||||
for name, val in admonition_types
|
||||
@@ -424,6 +427,9 @@ pre.fence
|
||||
canvas, svg
|
||||
max-width 100% !important
|
||||
|
||||
svg[ratio]
|
||||
width 100%
|
||||
|
||||
.gallery
|
||||
width 100%
|
||||
height 50vh
|
||||
@@ -444,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%)
|
||||
@@ -511,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
|
||||
@@ -519,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
|
||||
@@ -554,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
|
||||
@@ -562,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
|
||||
@@ -600,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
|
||||
@@ -608,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
|
||||
@@ -645,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'
|
||||
|
||||
Reference in New Issue
Block a user