feat: editor page props UI improvements + codemirror fix
This commit is contained in:
@@ -160,7 +160,7 @@
|
||||
v-icon(:color='helpShown ? `teal` : ``') mdi-help-circle
|
||||
span {{$t('editor:markup.markdownFormattingHelp')}}
|
||||
.editor-markdown-editor
|
||||
codemirror(ref='cm', v-model='code', :options='cmOptions', @ready='onCmReady', @input='onCmInput')
|
||||
textarea(ref='cm')
|
||||
transition(name='editor-markdown-preview')
|
||||
.editor-markdown-preview(v-if='previewShown')
|
||||
.editor-markdown-preview-content.contents(ref='editorPreviewContainer')
|
||||
@@ -188,7 +188,7 @@ import markdownHelp from './markdown/help.vue'
|
||||
// ========================================
|
||||
|
||||
// Code Mirror
|
||||
import { codemirror } from 'vue-codemirror'
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
|
||||
// Language
|
||||
@@ -261,6 +261,7 @@ function injectLineNumbers (tokens, idx, options, env, slf) {
|
||||
}
|
||||
md.renderer.rules.paragraph_open = injectLineNumbers
|
||||
md.renderer.rules.heading_open = injectLineNumbers
|
||||
md.renderer.rules.blockquote_open = injectLineNumbers
|
||||
|
||||
// ========================================
|
||||
// Vue Component
|
||||
@@ -268,7 +269,6 @@ md.renderer.rules.heading_open = injectLineNumbers
|
||||
|
||||
export default {
|
||||
components: {
|
||||
codemirror,
|
||||
markdownHelp
|
||||
},
|
||||
props: {
|
||||
@@ -280,22 +280,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
fabInsertMenu: false,
|
||||
code: this.$store.get('editor/content'),
|
||||
cmOptions: {
|
||||
tabSize: 2,
|
||||
mode: 'text/markdown',
|
||||
theme: 'wikijs-dark',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
line: true,
|
||||
styleActiveLine: true,
|
||||
highlightSelectionMatches: {
|
||||
annotateScrollbar: true
|
||||
},
|
||||
viewportMargin: 50,
|
||||
inputStyle: 'contenteditable',
|
||||
allowDropFileTypes: ['image/jpg', 'image/png', 'image/svg', 'image/jpeg', 'image/gif']
|
||||
},
|
||||
cm: null,
|
||||
cursorPos: { ch: 0, line: 1 },
|
||||
previewShown: true,
|
||||
previewHTML: '',
|
||||
@@ -303,9 +288,6 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cm() {
|
||||
return this.$refs.cm.codemirror
|
||||
},
|
||||
isMobile() {
|
||||
return this.$vuetify.breakpoint.smAndDown
|
||||
},
|
||||
@@ -325,53 +307,6 @@ export default {
|
||||
this.activeModal = ''
|
||||
this.helpShown = false
|
||||
},
|
||||
onCmReady(cm) {
|
||||
const keyBindings = {
|
||||
'F11' (cm) {
|
||||
cm.setOption('fullScreen', !cm.getOption('fullScreen'))
|
||||
},
|
||||
'Esc' (cm) {
|
||||
if (cm.getOption('fullScreen')) cm.setOption('fullScreen', false)
|
||||
}
|
||||
}
|
||||
_.set(keyBindings, `${CtrlKey}-S`, cm => {
|
||||
this.save()
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-B`, cm => {
|
||||
this.toggleMarkup({ start: `**` })
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-I`, cm => {
|
||||
this.toggleMarkup({ start: `*` })
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-Alt-Right`, cm => {
|
||||
let lvl = this.getHeaderLevel(cm)
|
||||
if (lvl >= 6) { lvl = 5 }
|
||||
this.setHeaderLine(lvl + 1)
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-Alt-Left`, cm => {
|
||||
let lvl = this.getHeaderLevel(cm)
|
||||
if (lvl <= 1) { lvl = 2 }
|
||||
this.setHeaderLine(lvl - 1)
|
||||
return false
|
||||
})
|
||||
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
cm.setSize(null, 'calc(100vh - 112px - 24px)')
|
||||
} else {
|
||||
cm.setSize(null, 'calc(100vh - 112px - 16px)')
|
||||
}
|
||||
cm.setOption('extraKeys', keyBindings)
|
||||
cm.on('cursorActivity', cm => {
|
||||
this.positionSync(cm)
|
||||
this.scrollSync(cm)
|
||||
})
|
||||
cm.on('paste', this.onCmPaste)
|
||||
this.onCmInput(this.code)
|
||||
},
|
||||
onCmInput: _.debounce(function (newContent) {
|
||||
linesMap = []
|
||||
this.$store.set('editor/content', newContent)
|
||||
@@ -497,7 +432,7 @@ export default {
|
||||
let currentLine = cm.getCursor().line
|
||||
if (currentLine < 3) {
|
||||
this.Velocity(this.$refs.editorPreview, 'stop', true)
|
||||
this.Velocity(this.$refs.editorPreview.firstChild, 'scroll', { offset: '-50', duration: 1000, container: this.$refs.editorPreview })
|
||||
this.Velocity(this.$refs.editorPreview.firstChild, 'scroll', { offset: '-50', duration: 1000, container: this.$refs.editorPreviewContainer })
|
||||
} else {
|
||||
let closestLine = _.findLast(linesMap, n => n <= currentLine)
|
||||
let destElm = this.$refs.editorPreview.querySelector(`[data-line='${closestLine}']`)
|
||||
@@ -513,9 +448,94 @@ export default {
|
||||
},
|
||||
toggleFullscreen () {
|
||||
this.cm.setOption('fullScreen', true)
|
||||
},
|
||||
refresh() {
|
||||
this.$nextTick(() => {
|
||||
this.cm.refresh()
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// Initialize CodeMirror
|
||||
|
||||
this.cm = CodeMirror.fromTextArea(this.$refs.cm, {
|
||||
tabSize: 2,
|
||||
mode: 'text/markdown',
|
||||
theme: 'wikijs-dark',
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
line: true,
|
||||
styleActiveLine: true,
|
||||
highlightSelectionMatches: {
|
||||
annotateScrollbar: true
|
||||
},
|
||||
viewportMargin: 50,
|
||||
inputStyle: 'contenteditable',
|
||||
allowDropFileTypes: ['image/jpg', 'image/png', 'image/svg', 'image/jpeg', 'image/gif']
|
||||
})
|
||||
this.cm.setValue(this.$store.get('editor/content'))
|
||||
this.cm.on('change', c => {
|
||||
this.$store.set('editor/content', c.getValue())
|
||||
this.onCmInput(this.$store.get('editor/content'))
|
||||
})
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
this.cm.setSize(null, 'calc(100vh - 112px - 24px)')
|
||||
} else {
|
||||
this.cm.setSize(null, 'calc(100vh - 112px - 16px)')
|
||||
}
|
||||
|
||||
// Set Keybindings
|
||||
|
||||
const keyBindings = {
|
||||
'F11' (c) {
|
||||
c.setOption('fullScreen', !c.getOption('fullScreen'))
|
||||
},
|
||||
'Esc' (c) {
|
||||
if (c.getOption('fullScreen')) c.setOption('fullScreen', false)
|
||||
}
|
||||
}
|
||||
_.set(keyBindings, `${CtrlKey}-S`, c => {
|
||||
this.save()
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-B`, c => {
|
||||
this.toggleMarkup({ start: `**` })
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-I`, c => {
|
||||
this.toggleMarkup({ start: `*` })
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-Alt-Right`, c => {
|
||||
let lvl = this.getHeaderLevel(c)
|
||||
if (lvl >= 6) { lvl = 5 }
|
||||
this.setHeaderLine(lvl + 1)
|
||||
return false
|
||||
})
|
||||
_.set(keyBindings, `${CtrlKey}-Alt-Left`, c => {
|
||||
let lvl = this.getHeaderLevel(c)
|
||||
if (lvl <= 1) { lvl = 2 }
|
||||
this.setHeaderLine(lvl - 1)
|
||||
return false
|
||||
})
|
||||
this.cm.setOption('extraKeys', keyBindings)
|
||||
|
||||
// Handle cursor movement
|
||||
|
||||
this.cm.on('cursorActivity', c => {
|
||||
this.positionSync(c)
|
||||
this.scrollSync(c)
|
||||
})
|
||||
|
||||
// Handle special paste
|
||||
|
||||
this.cm.on('paste', this.onCmPaste)
|
||||
|
||||
// Render initial preview
|
||||
|
||||
this.onCmInput(this.$store.get('editor/content'))
|
||||
this.refresh()
|
||||
|
||||
this.$root.$on('editorInsert', opts => {
|
||||
switch (opts.kind) {
|
||||
case 'IMAGE':
|
||||
@@ -718,10 +738,10 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
|
||||
background: mc('blue','800');
|
||||
}
|
||||
.cm-s-wikijs-dark .CodeMirror-line::selection, .cm-s-wikijs-dark .CodeMirror-line > span::selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::selection {
|
||||
background: mc('red', '500');
|
||||
background: mc('amber', '500');
|
||||
}
|
||||
.cm-s-wikijs-dark .CodeMirror-line::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span::-moz-selection, .cm-s-wikijs-dark .CodeMirror-line > span > span::-moz-selection {
|
||||
background: mc('red', '500');
|
||||
background: mc('amber', '500');
|
||||
}
|
||||
.cm-s-wikijs-dark .CodeMirror-gutters {
|
||||
background: darken(mc('grey','900'), 6%);
|
||||
|
Reference in New Issue
Block a user