feat(code): add line-number prop (#3242)

* feat(code): add line-numbers property

* chore(code): cleanup comments
This commit is contained in:
Jonson Petard 2022-07-11 00:43:14 +08:00 committed by GitHub
parent 3aa0c8a6c2
commit 93ba2b2f7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 161 additions and 9 deletions

View File

@ -38,6 +38,7 @@ The following code shows how to set hljs of Code. Importing highlight.js on dema
basic.vue
inline.vue
softwrap.vue
line-numbers.vue
```
## API
@ -52,3 +53,4 @@ softwrap.vue
| trim | `boolean` | `true` | Whether to display trimmed code. | |
| inline | `boolean` | `false` | Whether the code is displayed as inline. | |
| word-wrap | `boolean` | `false` | Whether to display word-wrapped code. | 2.24.0 |
| line-numbers | `boolean` | `false` | Whether to display line numbers. | |

View File

@ -0,0 +1,29 @@
<markdown>
# Line Numbers
It can show line numbers in the code block.
</markdown>
<template>
<div style="overflow: auto">
<n-code :code="code" language="cpp" line-numbers />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
code: `#include <bits/stdc++.h>
using namespace std;
int main() {
cout << "It is always morning somewhere in the world." << endl;
return 0;
}`
}
}
})
</script>

View File

@ -39,6 +39,7 @@ basic.vue
inline.vue
softwrap.vue
loop-debug.vue
line-numbers.vue
```
## API
@ -53,3 +54,4 @@ loop-debug.vue
| trim | `boolean` | `true` | 是否显示 trim 后的代码 | |
| inline | `boolean` | `false` | 使用行内样式 | |
| word-wrap | `boolean` | `false` | 代码过长时是否自动换行 | 2.24.0 |
| line-numbers | `boolean` | `false` | 是否显示行号 | |

View File

@ -0,0 +1,29 @@
<markdown>
# 显示行号
可以在代码块左侧显示行号
</markdown>
<template>
<div style="overflow: auto">
<n-code :code="code" language="cpp" line-numbers />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
return {
code: `#include <bits/stdc++.h>
using namespace std;
int main() {
cout << "最孤独的人最亲切,受过伤的人总是笑的最灿烂。" << "—— 素媛" << endl;
return 0;
}`
}
}
})
</script>

View File

@ -36,6 +36,7 @@ export const codeProps = {
uri: Boolean,
inline: Boolean,
wordWrap: Boolean,
lineNumbers: Boolean,
// In n-log, we only need to mount code's style for highlight
internalFontSize: Number,
internalNoHighlight: Boolean
@ -67,6 +68,20 @@ export default defineComponent({
language
}).value
}
// reference: https://www.yangdx.com/2020/04/144.html
const addLineNumbersForCode = (html: string): string => {
let num = 1
html += '<span class="ln-eof"></span>'
html = html.replace(/\r\n|\r|\n/g, function (a) {
num++
const text = (' ' + String(num)).slice(-4) // 最大支持到千位数
return a + '<span class="ln-num" data-num="' + text + '"></span>'
})
html = '<span class="ln-num" data-num=" 1"></span>' + html
html = '<span class="ln-bg"></span>' + html
return html
}
const setCode = (): void => {
if (slots.default) return
const { value: codeEl } = codeRef
@ -78,7 +93,11 @@ export default defineComponent({
if (language) {
const html = createCodeHtml(language, code, props.trim)
if (html !== null) {
codeEl.innerHTML = props.inline ? html : `<pre>${html}</pre>`
codeEl.innerHTML = props.inline
? html
: `<pre ${props.lineNumbers ? 'class="hljsln"' : ''}>${
props.lineNumbers ? addLineNumbersForCode(html) : html
}</pre>`
return
}
}
@ -88,10 +107,20 @@ export default defineComponent({
}
const maybePreEl = codeEl.children[0]
if (maybePreEl && maybePreEl.tagName === 'PRE') {
maybePreEl.textContent = code
if (props.lineNumbers) {
maybePreEl.classList.add('hljsln')
maybePreEl.innerHTML = addLineNumbersForCode(code)
} else {
maybePreEl.textContent = code
}
} else {
const warp = document.createElement('pre')
warp.textContent = code
if (props.lineNumbers) {
warp.classList.add('hljsln')
warp.innerHTML = code
} else {
warp.textContent = code
}
codeEl.innerHTML = ''
codeEl.appendChild(warp)
}
@ -124,7 +153,9 @@ export default defineComponent({
'hue-5': $6,
'hue-5-2': $7,
'hue-6': $8,
'hue-6-2': $9
'hue-6-2': $9,
'padding-color': $10,
'line-number-color': $11
}
} = themeRef.value
const { internalFontSize } = props
@ -142,7 +173,9 @@ export default defineComponent({
'--n-hue-5': $6,
'--n-hue-5-2': $7,
'--n-hue-6': $8,
'--n-hue-6-2': $9
'--n-hue-6-2': $9,
'--n-padding-color': $10,
'--n-line-number-color': $11
}
})
const themeClassHandle = inlineThemeDisabled

View File

@ -97,6 +97,57 @@ export default c([
}`,
`${codeClass} .hljs-link {
text-decoration: underline;
}`,
// 行号显示
`.hljsln {
position: relative;
display: block;
padding-left: 3.1em !important;
}`,
`.hljsln::-webkit-scrollbar {
height: 15px;
}`,
`.hljsln::-webkit-scrollbar-thumb {
background: #666;
}`,
`.hljsln::-webkit-scrollbar-thumb:hover {
background: #797979;
}`,
`.hljsln::-webkit-scrollbar-thumb:active {
background: #949494;
}`,
`.hljsln .ln-bg {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 2.4em;
height: 100%;
background: var(--n-padding-color);
}`,
`.hljsln .ln-num {
position: absolute;
z-index: 2;
left: 0;
width: 2.4em;
height: 1em;
text-align: center;
display: inline-block;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}`,
`.hljsln .ln-num::before {
color: var(--n-line-number-color);
font-style: normal;
font-weight: normal;
content: attr(data-num);
}`,
`.hljsln .ln-eof {
display: inline-block;
}`
]
}

View File

@ -5,7 +5,7 @@ const codeDark: CodeTheme = {
name: 'Code',
common: commonDark,
self (vars) {
const { textColor2, fontSize, fontWeightStrong } = vars
const { textColor2, fontSize, fontWeightStrong, textColor3 } = vars
return {
textColor: textColor2,
fontSize,
@ -19,7 +19,10 @@ const codeDark: CodeTheme = {
'hue-5': '#e06c75',
'hue-5-2': '#be5046',
'hue-6': '#d19a66',
'hue-6-2': '#e6c07b'
'hue-6-2': '#e6c07b',
// line-number styles
'padding-color': 'rgb(39, 39, 39)',
'line-number-color': textColor3
}
}
}

View File

@ -3,7 +3,7 @@ import type { ThemeCommonVars } from '../../_styles/common'
import { Theme } from '../../_mixins/use-theme'
const self = (vars: ThemeCommonVars) => {
const { textColor2, fontSize, fontWeightStrong } = vars
const { textColor2, fontSize, fontWeightStrong, textColor3 } = vars
return {
textColor: textColor2,
fontSize,
@ -17,7 +17,10 @@ const self = (vars: ThemeCommonVars) => {
'hue-5': '#e45649',
'hue-5-2': '#c91243',
'hue-6': '#986801',
'hue-6-2': '#c18401'
'hue-6-2': '#c18401',
// line-number styles
'padding-color': 'rgb(243, 243, 243)',
'line-number-color': textColor3
}
}