Skip to content

Commit a684b67

Browse files
brc-ddVoVAllenkiaking
authored
feat: add code-group feature (#728) (#1560)
close #728 close #1242 Co-authored-by: "Jinjing.Zhou" <allenzhou@tensorchord.ai> Co-authored-by: Kia King Ishii <kia.king.08@gmail.com>
1 parent 2343bd1 commit a684b67

File tree

14 files changed

+343
-25
lines changed

14 files changed

+343
-25
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/__tests__/e2e/.vitepress/cache
12
/coverage
23
/src/client/shared.ts
34
/src/node/shared.ts

docs/guide/markdown.md

+68-7
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ export default {
371371

372372
```js
373373
export default {
374-
data () {
374+
data() {
375375
return {
376376
msg: 'Highlighted!' // [!code hl]
377377
}
@@ -381,7 +381,7 @@ export default {
381381

382382
## Focus in Code Blocks
383383

384-
Adding the `// [!code focus]` comment on a line will focus it and blur the other parts of the code.
384+
Adding the `// [!code focus]` comment on a line will focus it and blur the other parts of the code.
385385

386386
Additionally, you can define a number of lines to focus using `// [!code focus:<lines>]`.
387387

@@ -405,17 +405,17 @@ export default {
405405

406406
```js
407407
export default {
408-
data () {
408+
data() {
409409
return {
410410
msg: 'Focused!' // [!code focus]
411411
}
412412
}
413413
}
414414
```
415415

416-
## Colored diffs in Code Blocks
416+
## Colored Diffs in Code Blocks
417417

418-
Adding the `// [!code --]` or `// [!code ++]` comments on a line will create a diff of that line, while keeping the colors of the codeblock.
418+
Adding the `// [!code --]` or `// [!code ++]` comments on a line will create a diff of that line, while keeping the colors of the codeblock.
419419

420420
**Input**
421421

@@ -447,7 +447,7 @@ export default {
447447
}
448448
```
449449

450-
## Errors and warnings
450+
## Errors and Warnings in Code Blocks
451451

452452
Adding the `// [!code warning]` or `// [!code error]` comments on a line will color it accordingly.
453453

@@ -472,7 +472,7 @@ export default {
472472

473473
```js
474474
export default {
475-
data () {
475+
data() {
476476
return {
477477
msg: 'Error', // [!code error]
478478
msg: 'Warning' // [!code warning]
@@ -549,11 +549,72 @@ You can also specify the language inside the braces (`{}`) like this:
549549
<<< @/snippets/snippet.cs{c#}
550550

551551
<!-- with line highlighting: -->
552+
552553
<<< @/snippets/snippet.cs{1,2,4-6 c#}
553554
```
554555

555556
This is helpful if source language cannot be inferred from your file extension.
556557

558+
## Code Groups
559+
560+
You can group multiple code blocks like this:
561+
562+
**Input**
563+
564+
````md
565+
::: code-group
566+
567+
```js [config.js]
568+
/**
569+
* @type {import('vitepress').UserConfig}
570+
*/
571+
const config = {
572+
// ...
573+
}
574+
575+
export default config
576+
```
577+
578+
```ts [config.ts]
579+
import type { UserConfig } from 'vitepress'
580+
581+
const config: UserConfig = {
582+
// ...
583+
}
584+
585+
export default config
586+
```
587+
588+
:::
589+
````
590+
591+
**Output**
592+
593+
::: code-group
594+
595+
```js [config.js]
596+
/**
597+
* @type {import('vitepress').UserConfig}
598+
*/
599+
const config = {
600+
// ...
601+
}
602+
603+
export default config
604+
```
605+
606+
```ts [config.ts]
607+
import type { UserConfig } from 'vitepress'
608+
609+
const config: UserConfig = {
610+
// ...
611+
}
612+
613+
export default config
614+
```
615+
616+
:::
617+
557618
## Markdown File Inclusion
558619

559620
You can include a markdown file in another markdown file like this:

docs/test.md

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Code Groups
2+
3+
::: code-group
4+
5+
```txt-vue{1}
6+
{{ 1 + 1 }}
7+
```
8+
9+
```js [app.vue]
10+
<template>
11+
<NuxtLayout>
12+
<NuxtPage />
13+
</NuxtLayout>
14+
</template>
15+
```
16+
17+
<!-- kkk -->
18+
19+
```vue-html{3,4} [layouts/custom.vue]
20+
<template>
21+
<div>
22+
Some *custom* layout
23+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur imperdiet mi in nunc faucibus consequat.
24+
<slot />
25+
</div>
26+
</template>
27+
```
28+
29+
```js{1-3,5} [layouts/default.vue]
30+
export default {
31+
name: 'MyComponent'
32+
// ...
33+
}
34+
<template>
35+
<div>
36+
Some *custom* layout
37+
<slot />
38+
</div>
39+
</template>
40+
```
41+
42+
:::
43+
44+
- in list
45+
46+
- ::: code-group
47+
48+
```js
49+
printf('111')
50+
```
51+
52+
```python
53+
import torch as th
54+
print("Hello world")
55+
```
56+
57+
```
58+
import torch as th
59+
print("Hello world")
60+
```
61+
62+
:::
63+
64+
```
65+
.
66+
├─ index.md
67+
├─ foo
68+
│ ├─ index.md
69+
│ ├─ one.md
70+
│ └─ two.md
71+
└─ bar
72+
├─ index.md
73+
├─ three.md
74+
└─ four.md
75+
```
76+
77+
- ```md{1-3,5}
78+
[Home](/) <!-- sends the user to the root index.md -->
79+
[foo](/foo/) <!-- sends the user to index.html of directory foo -->
80+
[foo heading](./#heading) <!-- anchors user to a heading in the foo index file -->
81+
[bar - three](../bar/three) <!-- you can omit extention -->
82+
[bar - three](../bar/three.md) <!-- you can append .md -->
83+
[bar - four](../bar/four.html) <!-- or you can append .html -->
84+
```

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"@vue/devtools-api": "^6.4.5",
8585
"@vueuse/core": "^9.6.0",
8686
"body-scroll-lock": "4.0.0-beta.0",
87+
"nanoid": "3.3.4",
8788
"shiki": "^0.11.1",
8889
"vite": "^4.0.0",
8990
"vue": "^3.2.45"

pnpm-lock.yaml

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { inBrowser } from 'vitepress'
2+
3+
export function useCodeGroups() {
4+
if (inBrowser) {
5+
window.addEventListener('click', (e) => {
6+
const el = e.target as HTMLInputElement
7+
8+
if (el.matches('.vp-code-group input')) {
9+
// input <- .tabs <- .vp-code-group
10+
const group = el.parentElement?.parentElement
11+
const i = Array.from(group?.querySelectorAll('input') || []).indexOf(el)
12+
13+
const current = group?.querySelector('div[class*="language-"].active')
14+
const next = group?.querySelectorAll('div[class*="language-"]')?.[i]
15+
16+
if (current && next && current !== next) {
17+
current.classList.remove('active')
18+
next.classList.add('active')
19+
}
20+
}
21+
})
22+
}
23+
}

src/client/app/composables/copyCode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { inBrowser } from '../utils.js'
1+
import { inBrowser } from 'vitepress'
22

33
export function useCopyCode() {
44
if (inBrowser) {

src/client/app/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { dataSymbol, initData } from './data.js'
1717
import { Content } from './components/Content.js'
1818
import { ClientOnly } from './components/ClientOnly.js'
1919
import { useCopyCode } from './composables/copyCode.js'
20+
import { useCodeGroups } from './composables/codeGroups.js'
2021

2122
const NotFound = Theme.NotFound || (() => '404 Not Found')
2223

@@ -43,6 +44,8 @@ const VitePressApp = defineComponent({
4344

4445
// setup global copy code handler
4546
useCopyCode()
47+
// setup global code groups handler
48+
useCodeGroups()
4649

4750
if (Theme.setup) Theme.setup()
4851
return () => h(Theme.Layout)

src/client/theme-default/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import './styles/base.css'
44
import './styles/utils.css'
55
import './styles/components/custom-block.css'
66
import './styles/components/vp-code.css'
7+
import './styles/components/vp-code-group.css'
78
import './styles/components/vp-doc.css'
89
import './styles/components/vp-sponsor.css'
910

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
.vp-code-group {
2+
margin-top: 16px;
3+
}
4+
5+
.vp-code-group .tabs {
6+
position: relative;
7+
display: flex;
8+
margin-right: -24px;
9+
margin-left: -24px;
10+
padding: 0 12px;
11+
background-color: var(--vp-code-tab-bg);
12+
overflow: auto;
13+
}
14+
15+
.vp-code-group .tabs::after {
16+
position: absolute;
17+
right: 0;
18+
bottom: 0;
19+
left: 0;
20+
height: 1px;
21+
background-color: var(--vp-code-tab-divider);
22+
content: '';
23+
}
24+
25+
@media (min-width: 640px) {
26+
.vp-code-group .tabs {
27+
margin-right: 0;
28+
margin-left: 0;
29+
border-radius: 8px 8px 0 0;
30+
}
31+
}
32+
33+
.vp-code-group .tabs input {
34+
position: absolute;
35+
opacity: 0;
36+
pointer-events: none;
37+
}
38+
39+
.vp-code-group .tabs label {
40+
position: relative;
41+
display: inline-block;
42+
border-bottom: 1px solid transparent;
43+
padding: 0 12px;
44+
line-height: 48px;
45+
font-size: 14px;
46+
font-weight: 500;
47+
color: var(--vp-code-tab-text-color);
48+
background-color: var(--vp-code-tab-bg);
49+
white-space: nowrap;
50+
cursor: pointer;
51+
transition: color 0.25s;
52+
}
53+
54+
.vp-code-group .tabs label::after {
55+
position: absolute;
56+
right: 8px;
57+
bottom: -1px;
58+
left: 8px;
59+
z-index: 10;
60+
height: 1px;
61+
content: '';
62+
background-color: transparent;
63+
transition: background-color 0.25s;
64+
}
65+
66+
.vp-code-group label:hover {
67+
color: var(--vp-code-tab-hover-text-color);
68+
}
69+
70+
.vp-code-group input:checked + label {
71+
color: var(--vp-code-tab-active-text-color);
72+
}
73+
74+
.vp-code-group input:checked + label::after {
75+
background-color: var(--vp-code-tab-active-bar-color);
76+
}
77+
78+
.vp-code-group div[class*='language-'] {
79+
display: none;
80+
margin-top: 0 !important;
81+
border-top-left-radius: 0 !important;
82+
border-top-right-radius: 0 !important;
83+
}
84+
85+
.vp-code-group div[class*='language-'].active {
86+
display: block;
87+
}

0 commit comments

Comments
 (0)