Browse Source

feat: add codeEditor component

Vben 3 years ago
parent
commit
a812685084

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -3,6 +3,7 @@
 ### ✨ Features
 
 - 新增图形编辑器示例
+- 新增代码编辑器(包含 Json 编辑器)
 
 ### ⚡ Performance Improvements
 

+ 2 - 0
package.json

@@ -39,6 +39,7 @@
     "@zxcvbn-ts/core": "^0.3.0",
     "ant-design-vue": "^2.1.2",
     "axios": "^0.21.1",
+    "codemirror": "^5.60.0",
     "cropperjs": "^1.5.11",
     "crypto-js": "^4.0.0",
     "echarts": "^5.1.0",
@@ -64,6 +65,7 @@
     "@commitlint/config-conventional": "^12.1.1",
     "@iconify/json": "^1.1.330",
     "@purge-icons/generated": "^0.7.0",
+    "@types/codemirror": "^0.0.109",
     "@types/crypto-js": "^4.0.1",
     "@types/fs-extra": "^9.0.11",
     "@types/inquirer": "^7.3.1",

+ 8 - 0
src/components/CodeEditor/index.ts

@@ -0,0 +1,8 @@
+import type { App } from 'vue';
+import codeEditor from './src/CodeEditor.vue';
+
+export const CodeEditor = Object.assign(codeEditor, {
+  install(app: App) {
+    app.component(codeEditor.name, codeEditor);
+  },
+});

+ 51 - 0
src/components/CodeEditor/src/CodeEditor.vue

@@ -0,0 +1,51 @@
+<template>
+  <div class="h-full">
+    <CodeMirrorEditor :value="getValue" @change="handleValueChange" :mode="mode" />
+  </div>
+</template>
+<script lang="ts">
+  import { defineComponent, computed } from 'vue';
+  import CodeMirrorEditor from './codemirror/CodeMirror.vue';
+  import { isString } from '/@/utils/is';
+
+  const MODE = {
+    JSON: 'application/json',
+    html: 'htmlmixed',
+    js: 'javascript',
+  };
+  export default defineComponent({
+    name: 'CodeEditor',
+    components: { CodeMirrorEditor },
+    props: {
+      value: {
+        type: [Object, String],
+      },
+      mode: {
+        type: String,
+        default: MODE.JSON,
+      },
+    },
+    emits: ['change'],
+    setup(props, { emit }) {
+      const getValue = computed(() => {
+        const { value, mode } = props;
+
+        if (mode === MODE.JSON) {
+          return isString(value)
+            ? JSON.stringify(JSON.parse(value), null, 2)
+            : JSON.stringify(value, null, 2);
+        }
+        return value;
+      });
+
+      function handleValueChange(v) {
+        emit('change', v);
+      }
+
+      return {
+        handleValueChange,
+        getValue,
+      };
+    },
+  });
+</script>

+ 125 - 0
src/components/CodeEditor/src/codemirror/CodeMirror.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="relative h-100 !h-full w-full overflow-hidden" ref="el"> </div>
+</template>
+
+<script lang="ts">
+  import {
+    ref,
+    onMounted,
+    onUnmounted,
+    watchEffect,
+    watch,
+    defineComponent,
+    unref,
+    nextTick,
+  } from 'vue';
+  import { useDebounceFn } from '@vueuse/core';
+  import { useAppStore } from '/@/store/modules/app';
+
+  import CodeMirror from 'codemirror';
+  import './codemirror.css';
+  import 'codemirror/theme/idea.css';
+  import 'codemirror/theme/material-palenight.css';
+
+  // modes
+  import 'codemirror/mode/javascript/javascript';
+  import 'codemirror/mode/css/css';
+  import 'codemirror/mode/htmlmixed/htmlmixed';
+  export default defineComponent({
+    props: {
+      mode: {
+        type: String,
+        default: 'application/json',
+      },
+      value: {
+        type: String,
+        default: '',
+      },
+      readonly: {
+        type: Boolean,
+        default: false,
+      },
+    },
+    emits: ['change'],
+    setup(props, { emit }) {
+      const el = ref();
+      let editor: Nullable<CodeMirror.Editor>;
+
+      const debounceRefresh = useDebounceFn(refresh, 100);
+      const appStore = useAppStore();
+
+      watch(
+        () => props.value,
+        async (v) => {
+          await nextTick();
+          const oldValue = editor?.getValue();
+          v && v !== oldValue && editor?.setValue(v);
+        },
+        { flush: 'post' }
+      );
+
+      watchEffect(() => {
+        editor?.setOption('mode', props.mode);
+      });
+
+      watch(
+        () => appStore.getDarkMode,
+        async () => {
+          setTheme();
+        },
+        {
+          immediate: true,
+        }
+      );
+
+      function setTheme() {
+        unref(editor)?.setOption(
+          'theme',
+          appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight'
+        );
+      }
+
+      function refresh() {
+        editor?.refresh();
+      }
+
+      async function init() {
+        const addonOptions = {
+          autoCloseBrackets: true,
+          autoCloseTags: true,
+          foldGutter: true,
+          gutters: ['CodeMirror-linenumbers'],
+        };
+
+        editor = CodeMirror(el.value!, {
+          value: '',
+          mode: props.mode,
+          readOnly: props.readonly,
+          tabSize: 2,
+          theme: 'material-palenight',
+          lineWrapping: true,
+          lineNumbers: true,
+          ...addonOptions,
+        });
+        editor?.setValue(props.value);
+        setTheme();
+        editor?.on('change', () => {
+          emit('change', editor?.getValue());
+        });
+      }
+
+      onMounted(async () => {
+        await nextTick();
+        init();
+        window.addEventListener('resize', debounceRefresh);
+        setTimeout(refresh, 50);
+      });
+
+      onUnmounted(() => {
+        window.removeEventListener('resize', debounceRefresh);
+        editor = null;
+      });
+      return { el };
+    },
+  });
+</script>

+ 21 - 0
src/components/CodeEditor/src/codemirror/codeMirror.ts

@@ -0,0 +1,21 @@
+import CodeMirror from 'codemirror';
+import './codemirror.css';
+import 'codemirror/theme/idea.css';
+import 'codemirror/theme/material-palenight.css';
+// import 'codemirror/addon/lint/lint.css';
+
+// modes
+import 'codemirror/mode/javascript/javascript';
+import 'codemirror/mode/css/css';
+import 'codemirror/mode/htmlmixed/htmlmixed';
+// addons
+// import 'codemirror/addon/edit/closebrackets';
+// import 'codemirror/addon/edit/closetag';
+// import 'codemirror/addon/comment/comment';
+// import 'codemirror/addon/fold/foldcode';
+// import 'codemirror/addon/fold/foldgutter';
+// import 'codemirror/addon/fold/brace-fold';
+// import 'codemirror/addon/fold/indent-fold';
+// import 'codemirror/addon/lint/json-lint';
+// import 'codemirror/addon/fold/comment-fold';
+export { CodeMirror };

+ 571 - 0
src/components/CodeEditor/src/codemirror/codemirror.css

@@ -0,0 +1,571 @@
+/* BASICS */
+
+.CodeMirror {
+  --base: #545281;
+  --comment: hsl(210, 25%, 60%);
+  --keyword: #af4ab1;
+  --variable: #0055d1;
+  --function: #c25205;
+  --string: #2ba46d;
+  --number: #c25205;
+  --tags: #d00;
+  --qualifier: #ff6032;
+  --important: var(--string);
+
+  height: auto;
+  height: 100%;
+  font-family: var(--font-code);
+  direction: ltr;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+  padding: 4px 0; /* Vertical padding around content */
+}
+
+.CodeMirror pre {
+  padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler,
+.CodeMirror-gutter-filler {
+  background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+  white-space: nowrap;
+  background-color: transparent;
+  border-right: 1px solid #ddd;
+}
+
+.CodeMirror-linenumber {
+  min-width: 20px;
+  padding: 0 3px 0 5px;
+  color: var(--comment);
+  text-align: right;
+  white-space: nowrap;
+  opacity: 0.6;
+}
+
+.CodeMirror-guttermarker {
+  color: black;
+}
+
+.CodeMirror-guttermarker-subtle {
+  color: #999;
+}
+
+/* FOLD GUTTER */
+
+.CodeMirror-foldmarker {
+  font-family: arial;
+  line-height: 0.3;
+  color: #414141;
+  text-shadow: #f96 1px 1px 2px, #f96 -1px -1px 2px, #f96 1px -1px 2px, #f96 -1px 1px 2px;
+  cursor: pointer;
+}
+
+.CodeMirror-foldgutter {
+  width: 0.7em;
+}
+
+.CodeMirror-foldgutter-open,
+.CodeMirror-foldgutter-folded {
+  cursor: pointer;
+}
+
+.CodeMirror-foldgutter-open::after,
+.CodeMirror-foldgutter-folded::after {
+  position: relative;
+  top: -0.1em;
+  display: inline-block;
+  font-size: 0.8em;
+  content: '>';
+  opacity: 0.8;
+  transform: rotate(90deg);
+  transition: transform 0.2s;
+}
+
+.CodeMirror-foldgutter-folded::after {
+  transform: none;
+}
+
+/* CURSOR */
+
+.CodeMirror-cursor {
+  width: 0;
+  border-right: none;
+  border-left: 1px solid black;
+}
+
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+
+.cm-fat-cursor .CodeMirror-cursor {
+  width: auto;
+  background: #7e7;
+  border: 0 !important;
+}
+
+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-fat-cursor-mark {
+  background-color: rgba(20, 255, 20, 0.5);
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  background-color: #7e7;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+}
+@-moz-keyframes blink {
+  0% {
+  }
+
+  50% {
+    background-color: transparent;
+  }
+
+  100% {
+  }
+}
+@-webkit-keyframes blink {
+  0% {
+  }
+
+  50% {
+    background-color: transparent;
+  }
+
+  100% {
+  }
+}
+@keyframes blink {
+  0% {
+  }
+
+  50% {
+    background-color: transparent;
+  }
+
+  100% {
+  }
+}
+
+.cm-tab {
+  display: inline-block;
+  text-decoration: inherit;
+}
+
+.CodeMirror-rulers {
+  position: absolute;
+  top: -50px;
+  right: 0;
+  bottom: -20px;
+  left: 0;
+  overflow: hidden;
+}
+
+.CodeMirror-ruler {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  border-left: 1px solid #ccc;
+}
+
+/* DEFAULT THEME */
+.cm-s-default.CodeMirror {
+  background-color: transparent;
+}
+
+.cm-s-default .cm-header {
+  color: blue;
+}
+
+.cm-s-default .cm-quote {
+  color: #090;
+}
+
+.cm-negative {
+  color: #d44;
+}
+
+.cm-positive {
+  color: #292;
+}
+
+.cm-header,
+.cm-strong {
+  font-weight: bold;
+}
+
+.cm-em {
+  font-style: italic;
+}
+
+.cm-link {
+  text-decoration: underline;
+}
+
+.cm-strikethrough {
+  text-decoration: line-through;
+}
+
+.cm-s-default .cm-atom,
+.cm-s-default .cm-def,
+.cm-s-default .cm-property,
+.cm-s-default .cm-variable-2,
+.cm-s-default .cm-variable-3,
+.cm-s-default .cm-punctuation {
+  color: var(--base);
+}
+
+.cm-s-default .cm-hr,
+.cm-s-default .cm-comment {
+  color: var(--comment);
+}
+
+.cm-s-default .cm-attribute,
+.cm-s-default .cm-keyword {
+  color: var(--keyword);
+}
+
+.cm-s-default .cm-variable {
+  color: var(--variable);
+}
+
+.cm-s-default .cm-bracket,
+.cm-s-default .cm-tag {
+  color: var(--tags);
+}
+
+.cm-s-default .cm-number {
+  color: var(--number);
+}
+
+.cm-s-default .cm-string,
+.cm-s-default .cm-string-2 {
+  color: var(--string);
+}
+
+.cm-s-default .cm-type {
+  color: #085;
+}
+
+.cm-s-default .cm-meta {
+  color: #555;
+}
+
+.cm-s-default .cm-qualifier {
+  color: var(--qualifier);
+}
+
+.cm-s-default .cm-builtin {
+  color: #7539ff;
+}
+
+.cm-s-default .cm-link {
+  color: var(--flash);
+}
+
+.cm-s-default .cm-error {
+  color: #ff008c;
+}
+
+.cm-invalidchar {
+  color: #ff008c;
+}
+
+.CodeMirror-composing {
+  border-bottom: 2px solid;
+}
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {
+  color: #0b0;
+}
+
+div.CodeMirror span.CodeMirror-nonmatchingbracket {
+  color: #a22;
+}
+
+.CodeMirror-matchingtag {
+  background: rgba(255, 150, 0, 0.3);
+}
+
+.CodeMirror-activeline-background {
+  background: #e8f2ff;
+}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+  position: relative;
+  overflow: hidden;
+  background: white;
+}
+
+.CodeMirror-scroll {
+  position: relative;
+  height: 100%;
+  padding-bottom: 30px;
+  margin-right: -30px;
+
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px;
+  overflow: scroll !important; /* Things will break if this is overridden */
+  outline: none; /* Prevent dragging from highlighting the element */
+}
+
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actual scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar,
+.CodeMirror-hscrollbar,
+.CodeMirror-scrollbar-filler,
+.CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+
+.CodeMirror-vscrollbar {
+  top: 0;
+  right: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+
+.CodeMirror-hscrollbar {
+  bottom: 0;
+  left: 0;
+  overflow-x: scroll;
+  overflow-y: hidden;
+}
+
+.CodeMirror-scrollbar-filler {
+  right: 0;
+  bottom: 0;
+}
+
+.CodeMirror-gutter-filler {
+  bottom: 0;
+  left: 0;
+}
+
+.CodeMirror-gutters {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 3;
+  min-height: 100%;
+}
+
+.CodeMirror-gutter {
+  display: inline-block;
+  height: 100%;
+  margin-bottom: -30px;
+  white-space: normal;
+  vertical-align: top;
+}
+
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  z-index: 4;
+}
+
+.CodeMirror-gutter-elt {
+  position: absolute;
+  z-index: 4;
+  cursor: default;
+}
+
+.CodeMirror-gutter-wrapper ::selection {
+  background-color: transparent;
+}
+
+.CodeMirror-gutter-wrapper ::-moz-selection {
+  background-color: transparent;
+}
+
+.CodeMirror-lines {
+  min-height: 1px; /* prevents collapsing before first draw */
+  cursor: text;
+}
+
+.CodeMirror pre {
+  position: relative;
+  z-index: 2;
+  margin: 0;
+  overflow: visible;
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+  color: inherit;
+  word-wrap: normal;
+  white-space: pre;
+  background: transparent;
+  border-width: 0;
+
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0;
+  -webkit-border-radius: 0;
+  border-radius: 0;
+  -webkit-tap-highlight-color: transparent;
+  -webkit-font-variant-ligatures: contextual;
+  font-variant-ligatures: contextual;
+}
+
+.CodeMirror-wrap pre {
+  word-break: normal;
+  word-wrap: break-word;
+  white-space: pre-wrap;
+}
+
+.CodeMirror-linebackground {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 0;
+}
+
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  padding: 0.1px; /* Force widget margins to stay inside of the container */
+}
+
+.CodeMirror-rtl pre {
+  direction: rtl;
+}
+
+.CodeMirror-code {
+  outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+.CodeMirror-cursor {
+  position: absolute;
+  pointer-events: none;
+}
+
+.CodeMirror-measure pre {
+  position: static;
+}
+
+div.CodeMirror-cursors {
+  position: relative;
+  z-index: 3;
+  visibility: hidden;
+}
+
+div.CodeMirror-dragcursors {
+  visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+
+.CodeMirror-selected {
+  background: #d9d9d9;
+}
+
+.CodeMirror-focused .CodeMirror-selected {
+  background: #d7d4f0;
+}
+
+.CodeMirror-crosshair {
+  cursor: crosshair;
+}
+
+.CodeMirror-line::selection,
+.CodeMirror-line > span::selection,
+.CodeMirror-line > span > span::selection {
+  background: #d7d4f0;
+}
+
+.CodeMirror-line::-moz-selection,
+.CodeMirror-line > span::-moz-selection,
+.CodeMirror-line > span > span::-moz-selection {
+  background: #d7d4f0;
+}
+
+.cm-searching {
+  background-color: #ffa;
+  background-color: rgba(255, 255, 0, 0.4);
+}
+
+/* Used to force a border model for a node */
+.cm-force-border {
+  padding-right: 0.1px;
+}
+
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack::after {
+  content: '';
+}
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext {
+  background: none;
+}

+ 1 - 1
src/components/FlowChart/index.ts

@@ -1,4 +1,4 @@
-import { App } from 'vue';
+import type { App } from 'vue';
 import dataDialog from './src/DataDialog.vue';
 import flowChart from './src/index.vue';
 

File diff suppressed because it is too large
+ 57 - 0
src/components/FlowChart/src/index.css


+ 1 - 1
src/components/FlowChart/src/index.vue

@@ -19,7 +19,7 @@
   import { toLogicFlowData } from './adpterForTurbo';
 
   import '@logicflow/core/dist/style/index.css';
-  import '@logicflow/extension/lib/style/index.css';
+  import './index.css';
   export default defineComponent({
     name: 'FlowChart',
     components: { FlowChartToolbar },

+ 35 - 1
src/components/Tinymce/src/Editor.vue

@@ -12,6 +12,40 @@
 </template>
 
 <script lang="ts">
+  import tinymce from 'tinymce/tinymce';
+  import 'tinymce/themes/silver';
+
+  import 'tinymce/icons/default/icons';
+  import 'tinymce/plugins/advlist';
+  import 'tinymce/plugins/anchor';
+  import 'tinymce/plugins/autolink';
+  import 'tinymce/plugins/autosave';
+  import 'tinymce/plugins/code';
+  import 'tinymce/plugins/codesample';
+  import 'tinymce/plugins/directionality';
+  import 'tinymce/plugins/fullscreen';
+  import 'tinymce/plugins/hr';
+  import 'tinymce/plugins/insertdatetime';
+  import 'tinymce/plugins/link';
+  import 'tinymce/plugins/lists';
+  import 'tinymce/plugins/media';
+  import 'tinymce/plugins/nonbreaking';
+  import 'tinymce/plugins/noneditable';
+  import 'tinymce/plugins/pagebreak';
+  import 'tinymce/plugins/paste';
+  import 'tinymce/plugins/preview';
+  import 'tinymce/plugins/print';
+  import 'tinymce/plugins/save';
+  import 'tinymce/plugins/searchreplace';
+  import 'tinymce/plugins/spellchecker';
+  import 'tinymce/plugins/tabfocus';
+  // import 'tinymce/plugins/table';
+  import 'tinymce/plugins/template';
+  import 'tinymce/plugins/textpattern';
+  import 'tinymce/plugins/visualblocks';
+  import 'tinymce/plugins/visualchars';
+  import 'tinymce/plugins/wordcount';
+
   import {
     defineComponent,
     computed,
@@ -25,7 +59,7 @@
 
   import ImgUpload from './ImgUpload.vue';
 
-  import { tinymce, toolbar, plugins } from './tinymce';
+  import { toolbar, plugins } from './tinymce';
 
   import { buildShortUUID } from '/@/utils/uuid';
   import { bindHandlers } from './helper';

+ 0 - 36
src/components/Tinymce/src/tinymce.ts

@@ -1,37 +1,3 @@
-import tinymce from 'tinymce/tinymce';
-import 'tinymce/themes/silver';
-
-import 'tinymce/icons/default/icons';
-import 'tinymce/plugins/advlist';
-import 'tinymce/plugins/anchor';
-import 'tinymce/plugins/autolink';
-import 'tinymce/plugins/autosave';
-import 'tinymce/plugins/code';
-import 'tinymce/plugins/codesample';
-import 'tinymce/plugins/directionality';
-import 'tinymce/plugins/fullscreen';
-import 'tinymce/plugins/hr';
-import 'tinymce/plugins/insertdatetime';
-import 'tinymce/plugins/link';
-import 'tinymce/plugins/lists';
-import 'tinymce/plugins/media';
-import 'tinymce/plugins/nonbreaking';
-import 'tinymce/plugins/noneditable';
-import 'tinymce/plugins/pagebreak';
-import 'tinymce/plugins/paste';
-import 'tinymce/plugins/preview';
-import 'tinymce/plugins/print';
-import 'tinymce/plugins/save';
-import 'tinymce/plugins/searchreplace';
-import 'tinymce/plugins/spellchecker';
-import 'tinymce/plugins/tabfocus';
-// import 'tinymce/plugins/table';
-import 'tinymce/plugins/template';
-import 'tinymce/plugins/textpattern';
-import 'tinymce/plugins/visualblocks';
-import 'tinymce/plugins/visualchars';
-import 'tinymce/plugins/wordcount';
-
 // Any plugins you want to setting has to be imported
 // Detail plugins list see https://www.tinymce.com/docs/plugins/
 // Custom builds see https://www.tinymce.com/download/custom-builds/
@@ -45,5 +11,3 @@ export const toolbar = [
   'fontsizeselect lineheight searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample',
   'hr bullist numlist link  preview anchor pagebreak insertdatetime media  forecolor backcolor fullscreen',
 ];
-
-export { tinymce };

+ 1 - 0
src/locales/lang/en/routes/demo/editor.ts

@@ -1,5 +1,6 @@
 export default {
   editor: 'Editor',
+  jsonEditor: 'Json editor',
   markdown: 'Markdown editor',
 
   tinymce: 'Rich text',

+ 1 - 0
src/locales/lang/zh_CN/routes/demo/editor.ts

@@ -1,5 +1,6 @@
 export default {
   editor: '编辑器',
+  jsonEditor: 'Json编辑器',
   markdown: 'markdown编辑器',
 
   tinymce: '富文本',

+ 13 - 1
src/router/menus/modules/demo/comp.ts

@@ -6,7 +6,9 @@ const menu: MenuModule = {
   menu: {
     name: t('routes.demo.comp.comp'),
     path: '/comp',
-
+    tag: {
+      dot: true,
+    },
     children: [
       {
         path: 'basic',
@@ -181,8 +183,18 @@ const menu: MenuModule = {
       {
         name: t('routes.demo.editor.editor'),
         path: 'editor',
+        tag: {
+          dot: true,
+        },
         children: [
           {
+            path: 'json',
+            name: t('routes.demo.editor.jsonEditor'),
+            tag: {
+              content: 'new',
+            },
+          },
+          {
             path: 'markdown',
             name: t('routes.demo.editor.markdown'),
             children: [

+ 8 - 0
src/router/routes/modules/demo/comp.ts

@@ -304,6 +304,14 @@ const comp: AppRouteModule = {
       },
       children: [
         {
+          path: 'json',
+          component: () => import('/@/views/demo/editor/json/index.vue'),
+          name: 'JsonEditorDemo',
+          meta: {
+            title: t('routes.demo.editor.jsonEditor'),
+          },
+        },
+        {
           path: 'markdown',
           component: getParentLayout('MarkdownDemo'),
           name: 'MarkdownDemo',

+ 78 - 0
src/views/demo/editor/json/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <PageWrapper title="代码编辑器组件示例" contentFullHeight fixedHeight contentBackground>
+    <template #extra>
+      <RadioGroup button-style="solid" v-model:value="modeValue" @change="handleModeChange">
+        <RadioButton value="application/json"> json数据 </RadioButton>
+        <RadioButton value="htmlmixed"> html代码 </RadioButton>
+        <RadioButton value="javascript"> javascript代码 </RadioButton>
+      </RadioGroup>
+    </template>
+    <CodeEditor v-model:value="value" :mode="modeValue" />
+  </PageWrapper>
+</template>
+<script lang="ts">
+  import { defineComponent, ref } from 'vue';
+  import { CodeEditor } from '/@/components/CodeEditor';
+  import { PageWrapper } from '/@/components/Page';
+  import { Radio } from 'ant-design-vue';
+
+  const jsonData =
+    '{"name":"BeJson","url":"http://www.xxx.com","page":88,"isNonProfit":true,"address":{"street":"科技园路.","city":"江苏苏州","country":"中国"},"links":[{"name":"Google","url":"http://www.xxx.com"},{"name":"Baidu","url":"http://www.xxx.com"},{"name":"SoSo","url":"http://www.xxx.com"}]}';
+
+  const jsData = `
+      (() => {
+        var htmlRoot = document.getElementById('htmlRoot');
+        var theme = window.localStorage.getItem('__APP__DARK__MODE__');
+        if (htmlRoot && theme) {
+          htmlRoot.setAttribute('data-theme', theme);
+          theme = htmlRoot = null;
+        }
+      })();
+  `;
+
+  const htmlData = `
+     <!DOCTYPE html>
+<html lang="en" id="htmlRoot">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <title><%= title %></title>
+    <link rel="icon" href="/favicon.ico" />
+  </head>
+  <body>
+    <div id="app">
+    </div>
+  </body>
+</html>
+  `;
+  export default defineComponent({
+    components: { CodeEditor, PageWrapper, RadioButton: Radio.Button, RadioGroup: Radio.Group },
+    setup() {
+      const modeValue = ref('application/json');
+      const value = ref(jsonData);
+
+      function handleModeChange(e: ChangeEvent) {
+        const mode = e.target.value;
+        if (mode === 'application/json') {
+          value.value = jsonData;
+          return;
+        }
+        if (mode === 'htmlmixed') {
+          value.value = htmlData;
+          return;
+        }
+        if (mode === 'javascript') {
+          value.value = jsData;
+          return;
+        }
+      }
+
+      return { value, modeValue, handleModeChange };
+    },
+  });
+</script>

+ 1 - 0
vite.config.ts

@@ -58,6 +58,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
       proxy: createProxy(VITE_PROXY),
     },
     build: {
+      minify: 'esbuild',
       target: 'es2015',
       outDir: OUTPUT_DIR,
       terserOptions: {

+ 25 - 1
yarn.lock

@@ -1301,11 +1301,23 @@
   resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669"
   integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==
 
+"@types/codemirror@^0.0.109":
+  version "0.0.109"
+  resolved "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.109.tgz#89d575ff1c7b462c4c3b8654f8bb38e5622e9036"
+  integrity sha512-cSdiHeeLjvGn649lRTNeYrVCDOgDrtP+bDDSFDd1TF+i0jKGPDRozno2NOJ9lTniso+taiv4kiVS8dgM8Jm5lg==
+  dependencies:
+    "@types/tern" "*"
+
 "@types/crypto-js@^4.0.1":
   version "4.0.1"
   resolved "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.1.tgz#3a4bd24518b0e6c5940da4e2659eeb2ef0806963"
   integrity sha512-6+OPzqhKX/cx5xh+yO8Cqg3u3alrkhoxhE5ZOdSEv0DOzJ13lwJ6laqGU0Kv6+XDMFmlnGId04LtY22PsFLQUw==
 
+"@types/estree@*":
+  version "0.0.47"
+  resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
+  integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==
+
 "@types/estree@0.0.39":
   version "0.0.39"
   resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -1477,6 +1489,13 @@
   resolved "https://registry.npmjs.org/@types/svgo/-/svgo-1.3.5.tgz#18a0166fbcdfbfc7f17d0491da2ea07ee397d3f9"
   integrity sha512-y9Pw8IK50OqFRDpdI9Is29KlWiENVW9FDvlTmGHelvTfR2brYFJbsClvulZfeq6YKacFrDsG9a39w0kJZdHLaw==
 
+"@types/tern@*":
+  version "0.23.3"
+  resolved "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz#4b54538f04a88c9ff79de1f6f94f575a7f339460"
+  integrity sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w==
+  dependencies:
+    "@types/estree" "*"
+
 "@types/through@*":
   version "0.0.30"
   resolved "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
@@ -2610,6 +2629,11 @@ coa@^2.0.2:
     chalk "^2.4.1"
     q "^1.1.2"
 
+codemirror@^5.60.0:
+  version "5.60.0"
+  resolved "https://registry.npmjs.org/codemirror/-/codemirror-5.60.0.tgz#00a8cfd287d5d8737ceb73987f04aee2fe5860da"
+  integrity sha512-AEL7LhFOlxPlCL8IdTcJDblJm8yrAGib7I+DErJPdZd4l6imx8IMgKK3RblVgBQqz3TZJR4oknQ03bz+uNjBYA==
+
 codepage@~1.14.0:
   version "1.14.0"
   resolved "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz#8cbe25481323559d7d307571b0fff91e7a1d2f99"
@@ -7729,7 +7753,7 @@ rollup-plugin-visualizer@5.3.4:
     source-map "^0.7.3"
     yargs "^16.2.0"
 
-rollup@^2.25.0, rollup@^2.38.5, rollup@^2.44.0:
+rollup@^2.25.0, rollup@^2.38.5, rollup@^2.44.0, rollup@^2.45.2:
   version "2.45.2"
   resolved "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48"
   integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==

Some files were not shown because too many files changed in this diff