diff --git a/web/src/lib/components/operations/OperationsDiffTab.svelte b/web/src/lib/components/operations/OperationsDiffTab.svelte index f110c07..11653bc 100644 --- a/web/src/lib/components/operations/OperationsDiffTab.svelte +++ b/web/src/lib/components/operations/OperationsDiffTab.svelte @@ -2,7 +2,7 @@ import type { RevisionDiff, RevisionPrefix, RevisionRow } from '$lib/api/types.js'; import { Button } from '$lib/components/ui/button/index.js'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card/index.js'; - import { ScrollArea } from '$lib/components/ui/scroll-area/index.js'; + import { sortRevisionDiffItems } from '$lib/sort-prefixes.js'; type Props = { revisions: RevisionRow[]; @@ -29,27 +29,52 @@ }: Props = $props(); /** Бэкенд отдаёт `prefixes.added` / `prefixes.removed`; верхний уровень added/removed — опционально. */ - function diffAdded(d: RevisionDiff | null): (string | RevisionPrefix)[] { + function diffAddedRaw(d: RevisionDiff | null): (string | RevisionPrefix)[] { if (!d) return []; if (d.prefixes && Array.isArray(d.prefixes.added)) return d.prefixes.added; if (Array.isArray(d.added)) return d.added; return []; } - function diffRemoved(d: RevisionDiff | null): (string | RevisionPrefix)[] { + function diffRemovedRaw(d: RevisionDiff | null): (string | RevisionPrefix)[] { if (!d) return []; if (d.prefixes && Array.isArray(d.prefixes.removed)) return d.prefixes.removed; if (Array.isArray(d.removed)) return d.removed; return []; } + + let addedSorted = $derived(diffData ? sortRevisionDiffItems(diffAddedRaw(diffData)) : []); + let removedSorted = $derived(diffData ? sortRevisionDiffItems(diffRemovedRaw(diffData)) : []); + + let scrollAddedEl: HTMLDivElement | null = $state(null); + let scrollRemovedEl: HTMLDivElement | null = $state(null); + let syncScrollLock = false; + + function syncFromAdded() { + if (syncScrollLock || !scrollAddedEl || !scrollRemovedEl) return; + syncScrollLock = true; + scrollRemovedEl.scrollTop = scrollAddedEl.scrollTop; + queueMicrotask(() => { + syncScrollLock = false; + }); + } + + function syncFromRemoved() { + if (syncScrollLock || !scrollAddedEl || !scrollRemovedEl) return; + syncScrollLock = true; + scrollAddedEl.scrollTop = scrollRemovedEl.scrollTop; + queueMicrotask(() => { + syncScrollLock = false; + }); + } - + Сравнение ревизий Выберите ID двух ревизий для сравнения - +