blob: cf0c1be005fc0841954f8de6c653211680af3faf (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
<script lang="ts">
import { diffLines } from 'diff';
interface Props {
before: string;
after: string;
beforeLabel?: string;
afterLabel?: string;
maxHeight?: number;
}
let { before, after, beforeLabel = '原版本', afterLabel = '新版本', maxHeight = 480 }: Props = $props();
const parts = $derived(diffLines(before ?? '', after ?? ''));
const lines = $derived.by(() => {
const out: { t: 'a' | 'd' | 'c'; text: string }[] = [];
for (const p of parts) {
const pieces = p.value.replace(/\n$/, '').split('\n');
for (const piece of pieces) {
if (p.added) out.push({ t: 'a', text: piece });
else if (p.removed) out.push({ t: 'd', text: piece });
else out.push({ t: 'c', text: piece });
}
}
return out;
});
</script>
<div class="diff">
<div class="legend">
<span><i class="sw a"></i>新增({afterLabel})</span>
<span><i class="sw d"></i>删除({beforeLabel})</span>
</div>
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div class="body" style="max-height:{maxHeight}px" tabindex="0" aria-label="代码差异" role="region">
{#each lines as l, i (i)}
{#if l.t === 'a'}
<span class="ln add" aria-hidden="true"></span><span class="code add">+{l.text}</span>
{:else if l.t === 'd'}
<span class="ln del" aria-hidden="true"></span><span class="code del">−{l.text}</span>
{:else}
<span class="ln" aria-hidden="true"> </span><span class="code">{l.text}</span>
{/if}
{/each}
</div>
</div>
<style>
.diff .legend {
color: var(--text-3);
font-size: 0.8rem;
margin-bottom: 0.4rem;
display: flex;
gap: 1rem;
}
.sw { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; }
.sw.a { background: #c7f0e6; }
.sw.d { background: #fbd4d0; }
.body {
overflow: auto;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 0.5rem 0.7rem;
}
.body .code { font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap; word-break: break-all; display: inline-block; width: 100%; }
.add { background: #eafaf5; color: #14532d; }
.del { background: #fdf0ee; color: #7f1d1d; }
.ln { user-select: none; }
.code.add::before, .code.del::before { opacity: 0.6; }
</style>
|