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)