Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit 5c640b1

Browse files
authored
Merge pull request #13 from hoiheart/develop
Add folding view
2 parents a53e4b5 + d17f8a2 commit 5c640b1

File tree

7 files changed

+101
-43
lines changed

7 files changed

+101
-43
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Here is the <a href="https://hoiheart.github.io/vue-diff/demo/index.html" target
3636
* Support multiple languages and can be extended
3737
* Support two themes (dark / light) and can be customized
3838
* Virtual scroll for large text comparison
39+
* Folding view (*Partial folding is not supported*)
3940

4041
## Install plugin
4142

@@ -93,6 +94,7 @@ Insert the diff component with props.
9394
:language="language"
9495
:prev="prev"
9596
:current="current"
97+
:folding="folding"
9698
:input-delay="0"
9799
:virtual-scroll="{ height: 500, lineMinHeight: 24, delay: 100 }"
98100
/>
@@ -108,6 +110,7 @@ Insert the diff component with props.
108110
| language | `string` | `plaintext` | | See <a href="#extend-languages">Extend languages</a>
109111
| prev | `string` | `''` | | Prev code |
110112
| current | `string` | `''` | | Current Code |
113+
| folding | `boolean` | `false` | | Folding not different |
111114
| inputDelay | `number` | `0` | | Setting up rendering debounce for changes for performance benefit (mode, prev, curr) |
112115
| virtualScroll | `boolean\|object` | `false` | | *Default value when setting true :*<br>`{ height: 500, lineMinHeight: 24, delay: 100 }`<br>See <a href="#virtual-scroll">virtual scroll</a> |
113116

dev/App.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<select v-model="theme" id="theme" class="bg-gray-900 w-40 py-1 px-3 mr-4 rounded border border-gray-500 text-gray-300">
1313
<option :key="val" v-for="val in themes">{{ val }}</option>
1414
</select>
15+
<label for="folding" class="mr-2">Folding:</label>
16+
<input v-model="folding" type="checkbox" id="folding" class="form-checkbox" />
1517
</div>
1618
<div class="editor text-gray-100 mt-8">
1719
<section>
@@ -38,6 +40,7 @@
3840
:language="selected.language"
3941
:prev="prev"
4042
:current="current"
43+
:folding="folding"
4144
:input-delay="selected.inputDelay"
4245
:virtual-scroll="selected.virtualScroll"
4346
/>
@@ -57,6 +60,7 @@ export default defineComponent({
5760
const selected = ref<null|{}>(null)
5861
const themes = ref(['dark', 'light', 'custom'])
5962
const theme = ref('dark')
63+
const folding = ref(false)
6064
const list = ref([
6165
{
6266
key: 'javascript',
@@ -117,6 +121,7 @@ export default defineComponent({
117121
mode,
118122
themes,
119123
theme,
124+
folding,
120125
list,
121126
selected,
122127
prev,

src/Diff.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
:style="{ minHeight }"
1414
>
1515
<Line
16-
v-for="(data, index) in visible"
16+
v-for="(data, index) in list"
1717
:key="index"
1818
:mode="mode"
19+
:folding="folding"
1920
:language="language"
2021
:meta="meta[data.index]"
2122
:render="render[data.index]"
@@ -60,6 +61,10 @@ export default defineComponent({
6061
type: String,
6162
default: ''
6263
},
64+
folding: {
65+
type: Boolean,
66+
default: false
67+
},
6368
inputDelay: {
6469
type: Number,
6570
default: 0
@@ -80,7 +85,7 @@ export default defineComponent({
8085
...(typeof props.virtualScroll === 'object' ? toRaw(props.virtualScroll) : {})
8186
}
8287
})
83-
const { meta, render, visible } = useRender(props, viewer, scrollOptions)
88+
const { meta, render, list } = useRender(props, viewer, scrollOptions)
8489
const { minHeight } = useVirtualScroll(props, viewer, scrollOptions, meta)
8590
8691
const setLineHeight = (index: number, height: number) => {
@@ -90,13 +95,13 @@ export default defineComponent({
9095
}
9196
9297
return {
98+
list,
9399
meta,
94100
minHeight,
95101
render,
96102
scrollOptions,
97103
setLineHeight,
98-
viewer,
99-
visible
104+
viewer
100105
}
101106
}
102107
})

src/Line.vue

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,46 @@
77
<!-- split view -->
88
<template v-if="mode === 'split'">
99
<template :key="index" v-for="(line, index) in render">
10-
<div class="lineNum" :class="`vue-diff-cell-${line.type}`">
11-
{{ line.lineNum }}
10+
<template v-if="isFoldLine">
11+
<div class="lineNum vue-diff-cell-fold"></div>
12+
<div class="code vue-diff-cell-fold"></div>
13+
</template>
14+
<template v-else>
15+
<div class="lineNum" :class="`vue-diff-cell-${line.type}`">
16+
{{ line.lineNum }}
17+
</div>
18+
<div class="code" :class="`vue-diff-cell-${line.type}`">
19+
<Code
20+
:language="language"
21+
:code="setCode(line, render, index)"
22+
:scrollOptions="scrollOptions"
23+
@rendered="rendered"
24+
/>
25+
</div>
26+
</template>
27+
</template>
28+
</template>
29+
<!-- // split view -->
30+
<!-- unified view -->
31+
<template v-if="mode === 'unified'">
32+
<template v-if="isFoldLine">
33+
<div class="lineNum vue-diff-cell-fold"></div>
34+
<div class="code vue-diff-cell-fold"></div>
35+
</template>
36+
<template v-else>
37+
<div class="lineNum" :class="`vue-diff-cell-${render[0].type}`">
38+
{{ render[0].lineNum }}
1239
</div>
13-
<div class="code" :class="`vue-diff-cell-${line.type}`">
40+
<div class="code" :class="`vue-diff-cell-${render[0].type}`">
1441
<Code
1542
:language="language"
16-
:code="setCode(line, render, index)"
43+
:code="setCode(render[0])"
1744
:scrollOptions="scrollOptions"
1845
@rendered="rendered"
1946
/>
2047
</div>
2148
</template>
2249
</template>
23-
<!-- // split view -->
24-
<!-- unified view -->
25-
<template v-if="mode === 'unified'">
26-
<div class="lineNum" :class="`vue-diff-cell-${render[0].type}`">
27-
{{ render[0].lineNum }}
28-
</div>
29-
<div class="code" :class="`vue-diff-cell-${render[0].type}`">
30-
<Code
31-
:language="language"
32-
:code="setCode(render[0])"
33-
:scrollOptions="scrollOptions"
34-
@rendered="rendered"
35-
/>
36-
</div>
37-
</template>
3850
<!-- // unified view -->
3951
</div>
4052
</template>
@@ -57,6 +69,10 @@ export default defineComponent({
5769
type: String as PropType<Mode>,
5870
required: true
5971
},
72+
folding: {
73+
type: Boolean,
74+
default: false
75+
},
6076
language: {
6177
type: String,
6278
required: true
@@ -86,6 +102,7 @@ export default defineComponent({
86102
minHeight: props.scrollOptions.lineMinHeight + 'px'
87103
}
88104
})
105+
const isFoldLine = computed(() => props.folding && props.render[0].type === 'equal')
89106
90107
const setCode = (line: Line, render?: Lines, index?: number) => {
91108
if (!line.value) return '\n'
@@ -114,7 +131,7 @@ export default defineComponent({
114131
}, props.scrollOptions.delay))
115132
}
116133
117-
return { line, rendered, rowStyle, setCode }
134+
return { line, isFoldLine, rendered, rowStyle, setCode }
118135
}
119136
})
120137
</script>

src/hooks.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ interface Props {
1111
language: string;
1212
prev: string;
1313
current: string;
14+
folding: boolean;
1415
inputDelay: number;
1516
virtualScroll: boolean|VirtualScroll;
1617
}
1718

1819
export const useRender = (props: Props, viewer: Ref<null|HTMLElement>, scrollOptions: ComputedRef<false|VirtualScroll>) => {
1920
const render = ref<Array<Lines>>([])
2021
const meta = ref<Array<Meta>>([])
21-
const visible = computed(() => meta.value.filter(item => item.visible))
22+
const list = computed(() => meta.value.filter(item => {
23+
return props.folding ? !item.foldable && item.visible : item.visible
24+
}))
2225

2326
const setRender = () => {
2427
const result = renderLines(props.mode, props.prev, props.current)
@@ -27,25 +30,29 @@ export const useRender = (props: Props, viewer: Ref<null|HTMLElement>, scrollOpt
2730

2831
render.value.map((v, index: number) => {
2932
const item = meta.value[index]
33+
const foldable = props.folding && v[0].type === 'equal' && render.value[index - 1]?.[0].type === 'equal'
34+
35+
const values = {
36+
index,
37+
foldable,
38+
visible: true
39+
}
3040

3141
if (scrollOptions.value) {
3242
meta.value[index] = {
33-
index,
43+
...values,
3444
visible: item?.visible || false,
3545
top: item?.top || undefined,
3646
height: item?.height || scrollOptions.value.lineMinHeight
3747
}
3848
} else {
39-
meta.value[index] = {
40-
index,
41-
visible: true
42-
}
49+
meta.value[index] = { ...values }
4350
}
4451
})
4552
}
4653

4754
debouncedWatch(
48-
[() => props.mode, () => props.prev, () => props.current],
55+
[() => props.mode, () => props.prev, () => props.current, () => props.folding],
4956
setRender,
5057
{
5158
debounce: props.inputDelay,
@@ -56,7 +63,7 @@ export const useRender = (props: Props, viewer: Ref<null|HTMLElement>, scrollOpt
5663
return {
5764
meta,
5865
render,
59-
visible
66+
list
6067
}
6168
}
6269

@@ -65,7 +72,7 @@ export const useVirtualScroll = (props: Props, viewer: Ref<null|HTMLElement>, sc
6572
if (!scrollOptions.value) return undefined
6673
const reduce = meta.value.reduce((acc, curr) => {
6774
curr.top = acc
68-
return acc + (curr.height as number)
75+
return curr.foldable ? acc : acc + (curr.height as number)
6976
}, 0)
7077
return reduce + 'px'
7178
})
@@ -85,22 +92,22 @@ export const useVirtualScroll = (props: Props, viewer: Ref<null|HTMLElement>, sc
8592
}
8693

8794
curr.top = acc
88-
return acc + (curr.height as number)
95+
return curr.foldable ? acc : acc + (curr.height as number)
8996
}, 0)
9097
}
9198

99+
debouncedWatch(
100+
[() => props.mode, () => props.prev, () => props.current, () => props.folding],
101+
() => nextTick(setMeta),
102+
{
103+
debounce: props.inputDelay,
104+
immediate: true
105+
}
106+
)
107+
92108
onMounted(() => {
93109
if (!scrollOptions.value) return
94110
viewer.value?.addEventListener('scroll', useThrottleFn(setMeta, scrollOptions.value.delay))
95-
96-
debouncedWatch(
97-
[() => props.mode, () => props.prev, () => props.current],
98-
() => nextTick(setMeta),
99-
{
100-
debounce: props.inputDelay,
101-
immediate: true
102-
}
103-
)
104111
})
105112

106113
onBeforeUnmount(() => {

src/style.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,26 @@
8383
background-color: rgba(128, 128, 128, 0.1);
8484
}
8585

86+
.vue-diff-cell-fold {
87+
&.lineNum {
88+
opacity: 0.8;
89+
font-size: 0.8em;
90+
91+
&:before {
92+
content: ">";
93+
}
94+
}
95+
96+
&.code {
97+
text-align: center;
98+
99+
&:before {
100+
color: #999;
101+
content: "⋯⋯";
102+
}
103+
}
104+
}
105+
86106
pre {
87107
display: block;
88108
position: relative;

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type Diffs = Array<Diff>
2121

2222
export interface Meta {
2323
index: number;
24+
foldable: boolean;
2425
visible: boolean;
2526
top?: number;
2627
height?: number;

0 commit comments

Comments
 (0)