diff --git a/web/package-lock.json b/web/package-lock.json index a86443f5..8173f706 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@toast-ui/editor": "^3.1.5", + "codemirror": "^5.65.16", "core-js": "^3.6.5", "element-ui": "^2.15.1", "highlight.js": "^10.7.3", @@ -5009,6 +5010,11 @@ "node": ">= 4.0" } }, + "node_modules/codemirror": { + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + }, "node_modules/codepage": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", @@ -21021,6 +21027,11 @@ "q": "^1.1.2" } }, + "codemirror": { + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + }, "codepage": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", diff --git a/web/package.json b/web/package.json index a326b00f..4f0bc4d8 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@toast-ui/editor": "^3.1.5", + "codemirror": "^5.65.16", "core-js": "^3.6.5", "element-ui": "^2.15.1", "highlight.js": "^10.7.3", diff --git a/web/src/assets/icon-font/iconfont.css b/web/src/assets/icon-font/iconfont.css index caf31fde..a7b6d1bc 100644 --- a/web/src/assets/icon-font/iconfont.css +++ b/web/src/assets/icon-font/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 2479351 */ - src: url('iconfont.woff2?t=1711432586441') format('woff2'), - url('iconfont.woff?t=1711432586441') format('woff'), - url('iconfont.ttf?t=1711432586441') format('truetype'); + src: url('iconfont.woff2?t=1711536835850') format('woff2'), + url('iconfont.woff?t=1711536835850') format('woff'), + url('iconfont.ttf?t=1711536835850') format('truetype'); } .iconfont { @@ -13,6 +13,14 @@ -moz-osx-font-smoothing: grayscale; } +.icongeshihua:before { + content: "\e7a3"; +} + +.iconyuanma:before { + content: "\e658"; +} + .icongundongtiao:before { content: "\e670"; } diff --git a/web/src/assets/icon-font/iconfont.ttf b/web/src/assets/icon-font/iconfont.ttf index 6d3d2a22..530a259c 100644 Binary files a/web/src/assets/icon-font/iconfont.ttf and b/web/src/assets/icon-font/iconfont.ttf differ diff --git a/web/src/assets/icon-font/iconfont.woff b/web/src/assets/icon-font/iconfont.woff index fca7f01b..670ceb03 100644 Binary files a/web/src/assets/icon-font/iconfont.woff and b/web/src/assets/icon-font/iconfont.woff differ diff --git a/web/src/assets/icon-font/iconfont.woff2 b/web/src/assets/icon-font/iconfont.woff2 index 8e5aa788..f330a8bb 100644 Binary files a/web/src/assets/icon-font/iconfont.woff2 and b/web/src/assets/icon-font/iconfont.woff2 differ diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index 7f48c5dc..16da1f1e 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -152,7 +152,8 @@ export default { closeMiniMap: 'Close mini map', readonly: 'Change to eadonly', edit: 'Change to edit', - backToRoot: 'Back to root node' + backToRoot: 'Back to root node', + changeSourceCodeEdit: 'Switch to source code editing mode' }, nodeHyperlink: { title: 'Link', @@ -317,5 +318,15 @@ export default { }, other: { loading: 'Loading, please wait...' + }, + sourceCodeEdit: { + sourceCodeTip: 'It is not recommended to modify the style in rich text mode because it requires synchronous modification of data and HTML structure.', + format: 'Format', + copy: 'Copy', + confirm: 'Complete', + close: 'Close', + formatErrorTip: 'The JSON format is incorrect. Please check and try again', + copyTip: 'Copied to clipboard', + formatTip: 'Format complete' } } diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index 09ca7cad..b0e50ee2 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -150,7 +150,8 @@ export default { closeMiniMap: '关闭小地图', readonly: '切换为只读模式', edit: '切换为编辑模式', - backToRoot: '回到根节点' + backToRoot: '回到根节点', + changeSourceCodeEdit: '切换为源码编辑模式' }, nodeHyperlink: { title: '超链接', @@ -311,5 +312,15 @@ export default { }, other: { loading: '正在加载,请稍后...' + }, + sourceCodeEdit: { + sourceCodeTip: '富文本模式下不建议修改样式,因为需要同步修改数据及html结构。', + format: '格式化', + copy: '复制', + confirm: '完成', + close: '关闭', + formatErrorTip: 'JSON格式有误,请检查后再试', + copyTip: '已复制到剪贴板', + formatTip: '格式化完成' } } diff --git a/web/src/pages/Edit/components/Edit.vue b/web/src/pages/Edit/components/Edit.vue index 205b8208..1b0ef38b 100644 --- a/web/src/pages/Edit/components/Edit.vue +++ b/web/src/pages/Edit/components/Edit.vue @@ -24,6 +24,7 @@ + @@ -83,6 +84,7 @@ import handleClipboardText from '@/utils/handleClipboardText' import Scrollbar from './Scrollbar.vue' import exampleData from 'simple-mind-map/example/exampleData' import FormulaSidebar from './FormulaSidebar.vue' +import SourceCodeEdit from './SourceCodeEdit.vue' // 注册插件 MindMap.usePlugin(MiniMap) @@ -134,7 +136,8 @@ export default { NodeIconToolbar, OutlineEdit, Scrollbar, - FormulaSidebar + FormulaSidebar, + SourceCodeEdit }, data() { return { diff --git a/web/src/pages/Edit/components/NavigatorToolbar.vue b/web/src/pages/Edit/components/NavigatorToolbar.vue index 819c79c4..1033a3a1 100644 --- a/web/src/pages/Edit/components/NavigatorToolbar.vue +++ b/web/src/pages/Edit/components/NavigatorToolbar.vue @@ -80,6 +80,15 @@ @click="toggleDark" > +
+ +
+
+
@@ -141,7 +150,7 @@ export default { this.lang = getLang() }, methods: { - ...mapMutations(['setLocalConfig', 'setIsReadonly']), + ...mapMutations(['setLocalConfig', 'setIsReadonly', 'setIsOutlineEdit']), readonlyChange() { this.setIsReadonly(!this.isReadonly) @@ -198,6 +207,10 @@ export default { backToRoot() { this.mindMap.renderer.setRootNodeCenter() + }, + + openSourceCodeEdit() { + this.setIsOutlineEdit(true) } } } diff --git a/web/src/pages/Edit/components/OutlineSidebar.vue b/web/src/pages/Edit/components/OutlineSidebar.vue index 0f3f7779..96402649 100644 --- a/web/src/pages/Edit/components/OutlineSidebar.vue +++ b/web/src/pages/Edit/components/OutlineSidebar.vue @@ -35,7 +35,6 @@ export default { computed: { ...mapState({ isDark: state => state.localConfig.isDark, - isOutlineEdit: state => state.isOutlineEdit, activeSidebar: state => state.activeSidebar }) }, diff --git a/web/src/pages/Edit/components/SourceCodeEdit.vue b/web/src/pages/Edit/components/SourceCodeEdit.vue new file mode 100644 index 00000000..29ca2e1a --- /dev/null +++ b/web/src/pages/Edit/components/SourceCodeEdit.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/web/src/store.js b/web/src/store.js index 3f035dec..895cc9f4 100644 --- a/web/src/store.js +++ b/web/src/store.js @@ -25,7 +25,8 @@ const store = new Vuex.Store({ }, activeSidebar: '', // 当前显示的侧边栏 isOutlineEdit: false, // 是否是大纲编辑模式 - isReadonly: false // 是否只读 + isReadonly: false, // 是否只读 + isSourceCodeEdit: false// 是否是源码编辑模式 }, mutations: { // 设置思维导图数据 @@ -60,7 +61,12 @@ const store = new Vuex.Store({ // 设置是否只读 setIsReadonly(state, data) { state.isReadonly = data - } + }, + + // 设置源码编辑模式 + setIsOutlineEdit(state, data) { + state.isSourceCodeEdit = data + }, }, actions: { // 设置初始思维导图数据 diff --git a/web/src/utils/index.js b/web/src/utils/index.js index 6f5386eb..0c8bbcb5 100644 --- a/web/src/utils/index.js +++ b/web/src/utils/index.js @@ -47,3 +47,13 @@ export const fileToBuffer = file => { reader.readAsArrayBuffer(file) }) } + +// 复制文本到剪贴板 +export const copy = (text) => { + const input = document.createElement('input') + input.setAttribute('value', text) + document.body.appendChild(input) + input.select() + document.execCommand('copy') + document.body.removeChild(input) +}