Browse Source

feat: adapt remaining markdown actions to monaco

NGPixel 2 years ago
parent
commit
51c4044509

+ 91 - 114
ux/src/components/EditorMarkdown.vue

@@ -192,14 +192,6 @@
           @click='toggleMarkup({ start: `<kbd>`, end: `</kbd>` })'
           )
           q-tooltip(anchor='top middle' self='bottom middle') {{ t('editor.markup.keyboardKey') }}
-        q-btn(
-          v-if='!state.previewShown'
-          icon='mdi-eye-arrow-right-outline'
-          padding='xs sm'
-          flat
-          @click='state.previewShown = true'
-          )
-          q-tooltip(anchor='top middle' self='bottom middle') {{ t('editor.togglePreviewPane') }}
       //--------------------------------------------------------
       //- MONACO EDITOR
       //--------------------------------------------------------
@@ -225,7 +217,7 @@
             @click='state.previewShown = false'
             )
             q-tooltip(anchor='top middle' self='bottom middle') {{ t('editor.togglePreviewPane') }}
-        .editor-markdown-preview-content.contents(ref='editorPreviewContainer')
+        .editor-markdown-preview-content.page-contents(ref='editorPreviewContainer')
           div(
             ref='editorPreview'
             v-html='pageStore.render'
@@ -240,7 +232,6 @@ import { get, flatten, last, times, startsWith, debounce } from 'lodash-es'
 import { DateTime } from 'luxon'
 import * as monaco from 'monaco-editor'
 import { Position, Range } from 'monaco-editor'
-import { WorkspaceEdit } from '../helpers/monacoTypes'
 
 import { useEditorStore } from 'src/stores/editor'
 import { usePageStore } from 'src/stores/page'
@@ -298,9 +289,9 @@ function insertAssetClb (opts) {
       break
     }
   }
-  insertAtCursor({ content })
+  insertAtCursor({ content, focus: false })
   setTimeout(() => {
-    cm.value.focus()
+    editor.focus()
   }, 500)
 }
 
@@ -313,15 +304,22 @@ function insertTable () {
 /**
 * Set current line as header
 */
-function setHeaderLine (lvl) {
-  const curLine = cm.value.doc.getCursor('head').line
-  let lineContent = cm.value.doc.getLine(curLine)
+function setHeaderLine (lvl, focus = true) {
+  const curLine = editor.getPosition().lineNumber
+  let lineContent = editor.getModel().getLineContent(curLine)
   const lineLength = lineContent.length
   if (startsWith(lineContent, '#')) {
     lineContent = lineContent.replace(/^(#+ )/, '')
   }
   lineContent = times(lvl, n => '#').join('') + ' ' + lineContent
-  cm.value.doc.replaceRange(lineContent, { line: curLine, ch: 0 }, { line: curLine, ch: lineLength })
+  editor.executeEdits('', [{
+    range: new Range(curLine, 1, curLine, lineLength + 1),
+    text: lineContent,
+    forceMoveMarkers: true
+  }])
+  if (focus) {
+    editor.focus()
+  }
 }
 
 /**
@@ -341,45 +339,68 @@ function getHeaderLevel (cm) {
 /**
 * Insert content at cursor
 */
-function insertAtCursor ({ content }) {
-  const cursor = cm.value.doc.getCursor('head')
-  cm.value.doc.replaceRange(content, cursor)
+function insertAtCursor ({ content, focus = true }) {
+  const cursor = editor.getPosition()
+  editor.executeEdits('', [{
+    range: new Range(cursor.lineNumber, cursor.column, cursor.lineNumber, cursor.column),
+    text: content,
+    forceMoveMarkers: true
+  }])
+  if (focus) {
+    editor.focus()
+  }
 }
 
 /**
 * Insert content after current line
 */
-function insertAfter ({ content, newLine }) {
-  const curLine = cm.value.doc.getCursor('to').line
-  const lineLength = cm.value.doc.getLine(curLine).length
-  cm.value.doc.replaceRange(newLine ? `\n${content}\n` : content, { line: curLine, ch: lineLength + 1 })
+function insertAfter ({ content, newLine, focus = true }) {
+  const curLine = editor.getPosition().lineNumber
+  editor.executeEdits('', [{
+    range: new Range(curLine + 1, 1, curLine + 1, 1),
+    text: newLine ? `\n${content}\n` : content,
+    forceMoveMarkers: true
+  }])
+  if (focus) {
+    editor.focus()
+  }
 }
 
 /**
 * Insert content before current line
 */
-function insertBeforeEachLine ({ content, after }) {
-  let lines = []
-  if (!cm.value.doc.somethingSelected()) {
-    lines.push(cm.value.doc.getCursor('head').line)
-  } else {
-    lines = flatten(cm.value.doc.listSelections().map(sl => {
-      const range = Math.abs(sl.anchor.line - sl.head.line) + 1
-      const lowestLine = (sl.anchor.line > sl.head.line) ? sl.head.line : sl.anchor.line
-      return times(range, l => l + lowestLine)
-    }))
-  }
-  lines.forEach(ln => {
-    let lineContent = cm.value.doc.getLine(ln)
-    const lineLength = lineContent.length
-    if (startsWith(lineContent, content)) {
-      lineContent = lineContent.substring(content.length)
+function insertBeforeEachLine ({ content, after, focus = true }) {
+  const edits = []
+  for (const selection of editor.getSelections()) {
+    const lineCount = selection.endLineNumber - selection.startLineNumber + 1
+    const lines = times(lineCount, l => l + selection.startLineNumber)
+    for (const line of lines) {
+      let lineContent = editor.getModel().getLineContent(line)
+      const lineLength = lineContent.length
+      if (startsWith(lineContent, content)) {
+        lineContent = lineContent.substring(content.length)
+      }
+      edits.push({
+        range: new Range(line, 1, line, lineLength + 1),
+        text: `${content}${lineContent}`,
+        forceMoveMarkers: true
+      })
     }
-    cm.value.doc.replaceRange(content + lineContent, { line: ln, ch: 0 }, { line: ln, ch: lineLength })
-  })
-  if (after) {
-    const lastLine = last(lines)
-    cm.value.doc.replaceRange(`\n${after}\n`, { line: lastLine, ch: cm.value.doc.getLine(lastLine).length + 1 })
+    if (after) {
+      const lastLine = last(lines)
+      const lineLength = editor.getModel().getLineContent(lastLine).length
+      edits.push({
+        range: new Range(lastLine, lineLength + 1, lastLine, lineLength + 1),
+        text: `\n${after}`,
+        forceMoveMarkers: true
+      })
+    }
+  }
+
+  editor.executeEdits('', edits)
+
+  if (focus) {
+    editor.focus()
   }
 }
 
@@ -387,7 +408,7 @@ function insertBeforeEachLine ({ content, after }) {
 * Insert an Horizontal Bar
 */
 function insertHorizontalBar () {
-  insertAfter({ content: '---', newLine: true })
+  insertAfter({ content: '\n---\n', newLine: true })
 }
 
 /**
@@ -442,7 +463,7 @@ onMounted(async () => {
       'editor.background': '#070a0d',
       'editor.lineHighlightBackground': '#0d1117',
       'editorLineNumber.foreground': '#546e7a',
-      'editorGutter.background': '#1e232a'
+      'editorGutter.background': '#0d1117'
     }
   })
 
@@ -455,7 +476,13 @@ onMounted(async () => {
     scrollBeyondLastLine: false,
     fontSize: 16,
     formatOnType: true,
-    lineNumbersMinChars: 3
+    lineNumbersMinChars: 3,
+    tabSize: 2,
+    padding: {
+      top: 10,
+      bottom: 10
+    },
+    wordWrap: 'on'
   })
 
   window.edd = editor
@@ -467,7 +494,7 @@ onMounted(async () => {
     id: 'markdown.extension.editing.toggleBold',
     keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB],
     label: 'Toggle bold',
-    precondition: '',
+    precondition: 'editorHasSelection',
     run (ed) {
       toggleMarkup({ start: '**' })
     }
@@ -479,12 +506,21 @@ onMounted(async () => {
     id: 'markdown.extension.editing.toggleItalic',
     keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI],
     label: 'Toggle italic',
-    precondition: '',
+    precondition: 'editorHasSelection',
     run (ed) {
       toggleMarkup({ start: '*' })
     }
   })
 
+  editor.addAction({
+    id: 'save',
+    keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
+    label: 'Save',
+    precondition: '',
+    run (ed) {
+    }
+  })
+
   editor.onDidChangeModelContent(debounce(ev => {
     editorStore.$patch({
       lastChangeTimestamp: DateTime.utc()
@@ -495,61 +531,10 @@ onMounted(async () => {
     processContent(pageStore.content)
   }, 500))
 
-  // -> Initialize CodeMirror
-  // cm.value = CodeMirror.fromTextArea(cmRef.value, {
-  //   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'],
-  //   // direction: siteConfig.rtl ? 'rtl' : 'ltr',
-  //   foldGutter: true,
-  //   gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
-  // })
-
-  // cm.value.setValue(pageStore.content)
-  // cm.value.on('change', c => {
-  //   editorStore.$patch({
-  //     lastChangeTimestamp: DateTime.utc()
-  //   })
-  //   pageStore.$patch({
-  //     content: c.getValue()
-  //   })
-  //   onCmInput(pageStore.content)
-  // })
-
-  // cm.value.setSize(null, '100%')
+  editor.focus()
 
   // -> Set Keybindings
   // const keyBindings = {
-  //   'F11' (c) {
-  //     c.setOption('fullScreen', !c.getOption('fullScreen'))
-  //   },
-  //   'Esc' (c) {
-  //     if (c.getOption('fullScreen')) {
-  //       c.setOption('fullScreen', false)
-  //     }
-  //   },
-  //   [`${CtrlKey}-S`] (c) {
-  //     // save()
-  //     return false
-  //   },
-  //   [`${CtrlKey}-B`] (c) {
-  //     toggleMarkup({ start: '**' })
-  //     return false
-  //   },
-  //   [`${CtrlKey}-I`] (c) {
-  //     toggleMarkup({ start: '*' })
-  //     return false
-  //   },
   //   [`${CtrlKey}-Alt-Right`] (c) {
   //     let lvl = getHeaderLevel(c)
   //     if (lvl >= 6) { lvl = 5 }
@@ -563,7 +548,6 @@ onMounted(async () => {
   //     return false
   //   }
   // }
-  // cm.value.setOption('extraKeys', keyBindings)
   // this.cm.on('inputRead', this.autocomplete)
 
   // // Handle cursor movement
@@ -575,13 +559,6 @@ onMounted(async () => {
   // // Handle special paste
   // this.cm.on('paste', this.onCmPaste)
 
-  // // Render initial preview
-  // processContent(pageStore.content)
-  // nextTick(() => {
-  //   cm.value.refresh()
-  //   cm.value.focus()
-  // })
-
   EVENT_BUS.on('insertAsset', insertAssetClb)
 
   // this.$root.$on('editorInsert', opts => {
@@ -619,9 +596,9 @@ onMounted(async () => {
 
 onBeforeUnmount(() => {
   EVENT_BUS.off('insertAsset', insertAssetClb)
-  // if (editor.value) {
-  // editor.value.destroy()
-  // }
+  if (editor) {
+    editor.dispose()
+  }
 })
 </script>
 
@@ -662,7 +639,7 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
     font-weight: 500;
   }
   &-preview {
-    flex: 1 1 50%;
+    flex: 0 1 50%;
     position: relative;
     height: $editor-height;
     overflow: hidden;
@@ -706,7 +683,7 @@ $editor-height-mobile: calc(100vh - 112px - 16px);
       height: $editor-height;
       overflow-y: scroll;
       padding: 1rem;
-      width: calc(100% + 17px);
+      max-width: calc(50vw - 57px);
       // -ms-overflow-style: none;
       // &::-webkit-scrollbar {
       //   width: 0px;

+ 19 - 8
ux/src/components/PageHeader.vue

@@ -106,14 +106,21 @@
         aria-label='Print'
         )
         q-tooltip Print
-    q-btn.q-mr-sm.acrylic-btn(
-      v-if='editorStore.isActive'
-      icon='las la-question-circle'
-      flat
-      color='grey'
-      :href='siteStore.docsBase + `/editor/${editorStore.editor}`'
-      target='_blank'
-      type='a'
+    template(v-if='editorStore.isActive')
+      q-btn.q-mr-sm.acrylic-btn(
+        icon='las la-question-circle'
+        flat
+        color='grey'
+        :href='siteStore.docsBase + `/editor/${editorStore.editor}`'
+        target='_blank'
+        type='a'
+      )
+      q-btn.q-mr-sm.acrylic-btn(
+        icon='las la-cog'
+        flat
+        color='grey'
+        :aria-label='t(`editor.settings`)'
+        @click='openEditorSettings'
       )
     template(v-if='editorStore.isActive || editorStore.hasPendingChanges')
       q-btn.acrylic-btn.q-mr-sm(
@@ -210,6 +217,10 @@ const editUrl = computed(() => {
 
 // METHODS
 
+function openEditorSettings () {
+  EVENT_BUS.emit('openEditorSettings')
+}
+
 async function discardChanges () {
   // Is it the home page in create mode?
   if (editorStore.mode === 'create' && pageStore.path === '' && pageStore.locale === 'en') {

+ 0 - 6
ux/src/css/app.scss

@@ -240,11 +240,5 @@ body::-webkit-scrollbar-thumb {
 // ------------------------------------------------------------------
 
 @import './animation.scss';
-
 @import 'v-network-graph/lib/style.css';
-
 @import './page-contents.scss';
-
-// @import '~codemirror/lib/codemirror.css';
-// @import '~codemirror/theme/elegant.css';
-// @import '~codemirror/theme/material-ocean.css';

+ 0 - 100
ux/src/css/codemirror.scss

@@ -1,100 +0,0 @@
-.cm-s-wikijs-dark.CodeMirror {
-  background: $dark-6;
-  color: #e0e0e0;
-}
-.cm-s-wikijs-dark div.CodeMirror-selected {
-  background: $teal-8;
-}
-.cm-s-wikijs-dark .cm-matchhighlight {
-  background: $teal-8;
-}
-.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: $blue-8;
-}
-.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: $blue-8;
-}
-.cm-s-wikijs-dark .CodeMirror-gutters {
-  background: $dark-3;
-  border-right: 1px solid $dark-2;
-}
-.cm-s-wikijs-dark .CodeMirror-guttermarker {
-  color: #ac4142;
-}
-.cm-s-wikijs-dark .CodeMirror-guttermarker-subtle {
-  color: #505050;
-}
-.cm-s-wikijs-dark .CodeMirror-linenumber {
-  color: $blue-grey-7;
-}
-.cm-s-wikijs-dark .CodeMirror-cursor {
-  border-left: 1px solid #b0b0b0;
-}
-.cm-s-wikijs-dark span.cm-comment {
-  color: $orange-8;
-}
-.cm-s-wikijs-dark span.cm-atom {
-  color: #aa759f;
-}
-.cm-s-wikijs-dark span.cm-number {
-  color: #aa759f;
-}
-.cm-s-wikijs-dark span.cm-property, .cm-s-wikijs-dark span.cm-attribute {
-  color: #90a959;
-}
-.cm-s-wikijs-dark span.cm-keyword {
-  color: #ac4142;
-}
-.cm-s-wikijs-dark span.cm-string {
-  color: #f4bf75;
-}
-.cm-s-wikijs-dark span.cm-variable {
-  color: #90a959;
-}
-.cm-s-wikijs-dark span.cm-variable-2 {
-  color: #6a9fb5;
-}
-.cm-s-wikijs-dark span.cm-def {
-  color: #d28445;
-}
-.cm-s-wikijs-dark span.cm-bracket {
-  color: #e0e0e0;
-}
-.cm-s-wikijs-dark span.cm-tag {
-  color: #ac4142;
-}
-.cm-s-wikijs-dark span.cm-link {
-  color: #aa759f;
-}
-.cm-s-wikijs-dark span.cm-error {
-  background: #ac4142;
-  color: #b0b0b0;
-}
-.cm-s-wikijs-dark .CodeMirror-activeline-background {
-  background: $dark-4;
-}
-.cm-s-wikijs-dark .CodeMirror-matchingbracket {
-  text-decoration: underline;
-  color: white !important;
-}
-
-.cm-s-wikijs-dark .CodeMirror-foldmarker {
-  margin-left: 10px;
-  display: inline-block;
-  background-color: rgba($amber-8, .3);
-  padding: 8px 5px;
-  color: $amber-5;
-  border-radius: 5px;
-  text-shadow: none;
-}
-
-.cm-s-wikijs-dark .CodeMirror-buttonmarker {
-  display: inline-block;
-  background-color: rgba($blue-5, .3);
-  border: 1px solid $blue-8;
-  padding: 1px 10px;
-  color: $blue-2 !important;
-  border-radius: 5px;
-  margin-left: 5px;
-  cursor: pointer;
-}

+ 1 - 17
ux/src/css/page-contents.scss

@@ -61,10 +61,6 @@
     }
   }
 
-  * + h1, * + h2, * + h3 {
-    border-top: 1px solid #DDD;
-  }
-
   h1 {
     font-size: 3em;
     font-weight: 500;
@@ -396,19 +392,7 @@
   }
 
   ul:not(.tabset-tabs):not(.contains-task-list) {
-    list-style: none;
-    > li::before {
-      position: absolute;
-      left: -1.1rem;
-      content: '\25b8';
-      color: mc('grey', '600');
-      width: 1.35rem;
-
-      @at-root .is-rtl & {
-        right: -1.1rem;
-        content: '\25C3';
-      }
-    }
+    list-style: square;
   }
   ol, ul:not(.tabset-tabs) {
     > li {

+ 1 - 0
ux/src/i18n/locales/en.json

@@ -1548,6 +1548,7 @@
   "editor.select.cannotChange": "This cannot be changed once the page is created.",
   "editor.select.customView": "or create a custom view?",
   "editor.select.title": "Which editor do you want to use for this page?",
+  "editor.settings": "Editor Settings",
   "editor.tableEditor.title": "Table Editor",
   "editor.togglePreviewPane": "Toggle Preview Pane",
   "editor.toggleScrollSync": "Toggle Scroll Sync",