From aa35441355f3151aeda74f66c2efed3f0d00be6d Mon Sep 17 00:00:00 2001 From: zyh Date: Fri, 16 Jun 2023 14:21:18 +0800 Subject: [PATCH] =?UTF-8?q?NEZ-2878=20feat=EF=BC=9A=E9=9B=86=E6=88=90?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B5=E9=9D=A2=E4=BB=A3=E7=A0=81=E5=9D=97?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E5=A4=8D=E5=88=B6=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../css/components/common/v-md-editor.scss | 21 +++++++ .../page/integration/integration.scss | 33 ---------- .../components/common/copy-code/copy-code.css | 49 +++++++++++++++ .../src/components/common/copy-code/index.js | 21 +++++++ .../components/common/copy-code/preview.js | 63 +++++++++++++++++++ .../copy-code/utils/markdown-it-copy-code.js | 21 +++++++ .../integration-tabs/configuration.vue | 6 +- nezha-fronted/src/entrance/app/main.js | 16 +++-- 8 files changed, 190 insertions(+), 40 deletions(-) create mode 100644 nezha-fronted/src/components/common/copy-code/copy-code.css create mode 100644 nezha-fronted/src/components/common/copy-code/index.js create mode 100644 nezha-fronted/src/components/common/copy-code/preview.js create mode 100644 nezha-fronted/src/components/common/copy-code/utils/markdown-it-copy-code.js diff --git a/nezha-fronted/src/assets/css/components/common/v-md-editor.scss b/nezha-fronted/src/assets/css/components/common/v-md-editor.scss index 1cd46d142..d12b90ed9 100644 --- a/nezha-fronted/src/assets/css/components/common/v-md-editor.scss +++ b/nezha-fronted/src/assets/css/components/common/v-md-editor.scss @@ -21,6 +21,27 @@ code{ color: $--color-text-regular; } + &.copy-code-mode .v-md-copy-code-btn{ + top: 1em; + right: 1em; + background: transparent; + box-shadow: none; + width: 16px; + height: 16px; + i{ + font-size: 16px; + color: $--color-text-regular; + } + } + } + blockquote{ + font-size: 13px; + font-weight: 600; + padding: 3px 15px; + margin-bottom: -1px; + color: $--color-text-regular; + border: 1px solid $--border-color-light; + background: $--alert-rule-background-color; } } } \ No newline at end of file diff --git a/nezha-fronted/src/assets/css/components/page/integration/integration.scss b/nezha-fronted/src/assets/css/components/page/integration/integration.scss index ae64e5615..a8a5550b3 100644 --- a/nezha-fronted/src/assets/css/components/page/integration/integration.scss +++ b/nezha-fronted/src/assets/css/components/page/integration/integration.scss @@ -241,39 +241,6 @@ height: 100%; overflow-y: auto; } - .integration-configuration-title{ - font-family: Roboto-Medium; - font-size: 14px; - color: $--color-text-primary; - line-height: 20px; - font-weight: 600; - margin-top: 10px; - } - .integration-configuration-msg{ - font-family: Roboto-Regular; - font-size: 14px; - color: $--color-text-regular; - line-height: 20px; - font-weight: 400; - margin-top: 6px; - } - .integration-configuration-pre{ - width: 100%; - overflow-y: auto; - box-sizing: border-box; - overflow-wrap: break-word; - word-break: break-word; - white-space: pre-wrap; - } - blockquote{ - font-size: 13px; - font-weight: 600; - padding: 3px 15px; - margin-bottom: -1px; - color: $--color-text-regular; - border: 1px solid $--border-color-light; - background: $--alert-rule-background-color; - } } .integration-dashboard{ diff --git a/nezha-fronted/src/components/common/copy-code/copy-code.css b/nezha-fronted/src/components/common/copy-code/copy-code.css new file mode 100644 index 000000000..dc04c87cc --- /dev/null +++ b/nezha-fronted/src/components/common/copy-code/copy-code.css @@ -0,0 +1,49 @@ +.v-md-pre-wrapper.copy-code-mode .v-md-copy-code-btn { + position: absolute; + top: 0.4em; + right: 0.4em; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 24px; + padding: 0; + color: #ddd; + font-size: 14px; + background-color: #666; + border: none; + border-radius: 6px; + outline: none; + box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); + visibility: hidden; + cursor: pointer; + opacity: 0; + transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out; + user-select: none; +} + +.v-md-pre-wrapper.copy-code-mode .v-md-copy-code-btn i { + display: inline-block; + color: inherit; + font-style: normal; + line-height: 0; + text-align: center; + text-transform: none; + vertical-align: -0.125em; + text-rendering: optimizeLegibility; + pointer-events: none; +} + +.v-md-pre-wrapper.copy-code-mode::before { + transition: 0.3s; +} + +.v-md-pre-wrapper.copy-code-mode:hover .v-md-copy-code-btn { + visibility: visible; + opacity: 1; +} + +.v-md-pre-wrapper.copy-code-mode:hover::before { + display: none; +} diff --git a/nezha-fronted/src/components/common/copy-code/index.js b/nezha-fronted/src/components/common/copy-code/index.js new file mode 100644 index 000000000..6749019d7 --- /dev/null +++ b/nezha-fronted/src/components/common/copy-code/index.js @@ -0,0 +1,21 @@ +'use strict' + +const _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = createCopyCodePlugin + +const _markdownItCopyCode = _interopRequireDefault(require('./utils/markdown-it-copy-code')) + +const _preview = _interopRequireDefault(require('./preview')) + +function createCopyCodePlugin () { + return { + install: function install (VMdEditor) { + VMdEditor.extendMarkdown(function (mdParser) { + mdParser.use(_markdownItCopyCode.default) + }) + VMdEditor.use((0, _preview.default)()) + } + } +} diff --git a/nezha-fronted/src/components/common/copy-code/preview.js b/nezha-fronted/src/components/common/copy-code/preview.js new file mode 100644 index 000000000..d48f622e9 --- /dev/null +++ b/nezha-fronted/src/components/common/copy-code/preview.js @@ -0,0 +1,63 @@ +'use strict' + +const _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') + +exports.__esModule = true +exports.default = createCopyCodePreview + +const _copyToClipboard = _interopRequireDefault(require('copy-to-clipboard')) + +function isCopyButton (el) { + return el.classList.contains('v-md-copy-code-btn') +} + +function findCodeWrapperEl (el) { + if (el.classList.contains('v-md-pre-wrapper')) { + return el + } + + return findCodeWrapperEl(el.parentNode) +} + +function getPreviewEl (el) { + const previewElClass = 'v-md-editor-preview' + return el.classList.contains(previewElClass) ? el : el.querySelector('.' + previewElClass) +} + +function createCopyCodePreview () { + return { + install: function install (VMdEditor) { + if (!VMdEditor.mixins) VMdEditor.mixins = [] + VMdEditor.mixins.push({ + mounted: function mounted () { + const _this = this + + this.$nextTick(function () { + const previewEl = getPreviewEl(_this.$el) + previewEl.addEventListener('click', _this.handleCopyCodeClick) + }) + }, + beforeDestroy: function beforeDestroy () { + const previewEl = getPreviewEl(this.$el) + previewEl.removeEventListener('click', this.handleCopyCodeClick) + }, + methods: { + handleCopyCodeClick: function handleCopyCodeClick (_ref) { + const target = _ref.target + + if (isCopyButton(target)) { + const codeWrapper = findCodeWrapperEl(target.parentNode) + + if (codeWrapper) { + const code = codeWrapper.querySelector('code').innerText; + // Set the MIME type of what you want to copy as. Use text/html to copy as HTML, text/plain to avoid inherited styles showing when pasted into rich text editor. + (0, _copyToClipboard.default)(code, { format: 'text/plain' }) + this.$emit('copy-code-success', code) + } + } + } + } + }) + } + } +} diff --git a/nezha-fronted/src/components/common/copy-code/utils/markdown-it-copy-code.js b/nezha-fronted/src/components/common/copy-code/utils/markdown-it-copy-code.js new file mode 100644 index 000000000..6ac4f06d5 --- /dev/null +++ b/nezha-fronted/src/components/common/copy-code/utils/markdown-it-copy-code.js @@ -0,0 +1,21 @@ +'use strict' + +// markdown-it plugin for generating copy code button. +// It depends on preWrapper plugin. + +/* eslint-disable max-len */ +module.exports = function (md) { + // === Start: 防止复制按钮不断被创建 === + if (!md.renderer.rules.originalFence) { + md.renderer.rules.originalFence = md.renderer.rules.fence + } + // === End: Patch === + const fence = md.renderer.rules.originalFence + + md.renderer.rules.fence = function () { + const rawCode = fence.apply(void 0, arguments) + const button = '\n ' + const finalCode = rawCode.replace('', button + '').replace('v-md-pre-wrapper', 'v-md-pre-wrapper copy-code-mode') + return finalCode + } +} diff --git a/nezha-fronted/src/components/page/integration/integration-tabs/configuration.vue b/nezha-fronted/src/components/page/integration/integration-tabs/configuration.vue index bc57d453e..7191032d1 100644 --- a/nezha-fronted/src/components/page/integration/integration-tabs/configuration.vue +++ b/nezha-fronted/src/components/page/integration/integration-tabs/configuration.vue @@ -1,7 +1,7 @@ @@ -17,7 +17,9 @@ export default { } }, methods: { - + handleCopyCodeSuccess (code) { + this.$message.success({ message: this.$t('overall.copySuccess') }) + } } } diff --git a/nezha-fronted/src/entrance/app/main.js b/nezha-fronted/src/entrance/app/main.js index 895bdc3b4..c1841a4b9 100644 --- a/nezha-fronted/src/entrance/app/main.js +++ b/nezha-fronted/src/entrance/app/main.js @@ -50,24 +50,30 @@ import VMdPreview from '@kangc/v-md-editor/lib/preview' import '@kangc/v-md-editor/lib/style/preview.css' import githubTheme from '@kangc/v-md-editor/lib/theme/github.js' import '@kangc/v-md-editor/lib/theme/style/github.css' +import hljs from 'highlight.js' +// markdown支持代码复制 +import createCopyCodePlugin from '@/components/common/copy-code/index' +import '@/components/common/copy-code/copy-code.css' +VMdPreview.use(githubTheme, { + Hljs: hljs +}) +VMdPreview.use(createCopyCodePlugin()) +Vue.use(VMdPreview) + // Pace.on("done", function() { // $self.isShowAuth = false; // Pace.off("done"); // }) // highlightjs -import hljs from 'highlight.js' // Pace.start(); -VMdPreview.use(githubTheme, { - Hljs: hljs -}) + Pace.options = { minTime: 100, ghostTime: 100, restartOnRequestAfter: 100 } window.Meta2d = Meta2d -Vue.use(VMdPreview) // Vue.use(Pace) Vue.use(VueIntro)