|
18 | 18 |
|
19 | 19 | import { defineDocSearchConfig } from '@vuepress/plugin-docsearch/client'; |
20 | 20 | import { computed } from 'vue'; |
| 21 | +import { onMounted, nextTick } from 'vue'; |
21 | 22 | import { |
22 | 23 | defineClientConfig, |
23 | 24 | usePageData, |
@@ -52,6 +53,93 @@ export default defineClientConfig({ |
52 | 53 | lastTo = to.fullPath; |
53 | 54 | }); |
54 | 55 |
|
| 56 | + function addConvertSingleLineButton() { |
| 57 | + if (typeof document === 'undefined') return; |
| 58 | + |
| 59 | + const blocks = document.querySelectorAll<HTMLElement>('div[class*="language-sql"] pre'); |
| 60 | + const copyIcon = `<svg t="1773227012571" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7157" width="18px" height="18px"><path d="M860.253405 512.000461a431.238022 431.238022 0 0 0-139.308875-316.862415A40.958141 40.958141 0 1 0 665.702238 255.448908a348.144194 348.144194 0 0 1-202.691598 603.108619l30.718605-30.718605a41.019578 41.019578 0 0 0-57.904571-58.109362l-81.301909 81.301909a56.317443 56.317443 0 0 0 0 79.663583l81.301909 81.301909a40.97862 40.97862 0 0 0 57.955769-57.955769l-14.847326-14.796128A430.674847 430.674847 0 0 0 860.253405 512.000461zM350.01737 254.271362a40.958141 40.958141 0 0 0 57.955768 0l81.301909-81.301909a56.317443 56.317443 0 0 0 0-79.663583L407.973138 12.003961a40.97862 40.97862 0 0 0-57.955768 57.955768l16.74164 16.690443a430.060475 430.060475 0 0 0-227.31768 742.366296A40.958141 40.958141 0 0 0 194.683622 768.552013 348.144194 348.144194 0 0 1 378.688068 167.696092l-28.670698 28.619501a40.958141 40.958141 0 0 0 0 57.955769z" fill="#ffffff" p-id="7158"></path></svg>`; |
| 61 | + const tipContent = pageData.value.lang === 'zh-CN' ? '已转换为单行' : 'Converted as single line'; |
| 62 | + const hoverTipContent = pageData.value.lang === 'zh-CN' ? '转换为单行' : 'Convert as single line'; |
| 63 | + const copyTipContent = pageData.value.lang === 'zh-CN' ? '复制内容' : 'Copy content'; |
| 64 | + |
| 65 | + blocks.forEach((pre) => { |
| 66 | + if (pre.querySelector('.copy-one-line-btn')) return; |
| 67 | + |
| 68 | + const parentEl = pre.parentElement; |
| 69 | + if (!parentEl) return; |
| 70 | + const lineNumbers = parentEl.querySelector('div[class="line-numbers"]'); |
| 71 | + if (!lineNumbers) return; |
| 72 | + const copyBtn = parentEl.querySelector<HTMLElement>('button[class*="vp-copy-code-button"]'); |
| 73 | + if (!copyBtn) return; |
| 74 | + copyBtn.title = copyTipContent; |
| 75 | + |
| 76 | + const code = pre.querySelector('code'); |
| 77 | + if (!code) return; |
| 78 | + |
| 79 | + const copiedTooltip = document.createElement('div'); |
| 80 | + copiedTooltip.className = 'copy-one-line-tooltip'; |
| 81 | + pre.appendChild(copiedTooltip); |
| 82 | + |
| 83 | + const btn = document.createElement('button'); |
| 84 | + btn.innerHTML = copyIcon; |
| 85 | + btn.className = 'copy-one-line-btn'; |
| 86 | + btn.title = hoverTipContent; |
| 87 | + |
| 88 | + btn.onclick = () => { |
| 89 | + const text = code.innerText; |
| 90 | + const lines = text.split('\n'); |
| 91 | + |
| 92 | + const single = lines |
| 93 | + .map((line, i) => { |
| 94 | + const trimmed = line.trim(); |
| 95 | + if (!trimmed || trimmed === '') return ''; |
| 96 | + console.log('line', trimmed); |
| 97 | + if (i === lines.length - 1) return trimmed; |
| 98 | + if (trimmed.endsWith(';')) { |
| 99 | + return trimmed + '\n'; |
| 100 | + } |
| 101 | + if (trimmed.endsWith('\\')) { |
| 102 | + return trimmed.slice(0, -1) + ' '; |
| 103 | + } |
| 104 | + return trimmed + ' '; |
| 105 | + }) |
| 106 | + .join(''); |
| 107 | + |
| 108 | + const convertedSpan = single.split('\n').map((line) => `<span class="line"><span>${line}\n</span></span>`).join(''); |
| 109 | + const counter = single.split('\n').length; |
| 110 | + code.innerHTML = convertedSpan; |
| 111 | + if (lineNumbers) { |
| 112 | + const childCount = lineNumbers.children.length; |
| 113 | + for (let i = counter; i < childCount; i++) { |
| 114 | + const child = lineNumbers.children[0]; |
| 115 | + lineNumbers.removeChild(child); |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + btn.style.opacity = '80'; |
| 120 | + btn.style.backgroundColor = 'rgb(47, 53, 66)'; |
| 121 | + copiedTooltip.style.opacity = '100'; |
| 122 | + copiedTooltip.innerText = tipContent; |
| 123 | + |
| 124 | + setTimeout(() => { |
| 125 | + btn.style.backgroundColor = ''; |
| 126 | + copiedTooltip.innerText = ''; |
| 127 | + btn.style.visibility = 'hidden'; |
| 128 | + copiedTooltip.style.visibility = 'hidden'; |
| 129 | + }, 1500); |
| 130 | + }; |
| 131 | + pre.appendChild(btn); |
| 132 | + }); |
| 133 | + } |
| 134 | + |
| 135 | + onMounted(() => { |
| 136 | + nextTick(() => addConvertSingleLineButton()); |
| 137 | + }); |
| 138 | + |
| 139 | + router.afterEach(() => { |
| 140 | + nextTick(() => addConvertSingleLineButton()); |
| 141 | + }); |
| 142 | + |
55 | 143 | const docSearchConfig = computed(() => ({ |
56 | 144 | appId: 'JLT9R2YGAE', |
57 | 145 | apiKey: 'f1f30c0df04d74534e066d07786bce05', |
|
0 commit comments