feat(frontend): show history diff inline below the selected version
Instead of rendering the diff at the bottom of the list (requiring the user to scroll down), it now appears directly below whichever version item was clicked. Compare-mode diff stays at the bottom of the compare form where it makes sense, since it is not tied to a specific list item. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -333,46 +333,8 @@ $effect(() => {
|
|||||||
{m.history_compare_apply()}
|
{m.history_compare_apply()}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
|
||||||
<!-- Version list -->
|
|
||||||
<ul class="divide-y divide-brand-sand">
|
|
||||||
{#each versions as v, i (v.id)}
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
onclick={() => selectVersion(v.id)}
|
|
||||||
data-testid="history-version"
|
|
||||||
class="w-full py-2 text-left transition hover:bg-brand-sand/30 {selectedVersionId ===
|
|
||||||
v.id
|
|
||||||
? 'border-l-2 border-brand-mint pl-2'
|
|
||||||
: 'pl-0'}"
|
|
||||||
>
|
|
||||||
<div class="flex items-baseline justify-between gap-2">
|
|
||||||
<span class="font-sans text-xs font-medium text-brand-navy">
|
|
||||||
Version {i + 1}
|
|
||||||
</span>
|
|
||||||
<span class="font-sans text-[10px] text-gray-400">
|
|
||||||
{formatDateTime(v.savedAt)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="font-sans text-[11px] text-gray-500">{v.editorName}</span>
|
|
||||||
{#if v.changedFields && v.changedFields.length > 0}
|
|
||||||
<div class="mt-1 flex flex-wrap gap-1">
|
|
||||||
{#each v.changedFields as field (field)}
|
|
||||||
<span
|
|
||||||
class="rounded bg-brand-sand/50 px-1.5 py-0.5 font-sans text-[10px] tracking-wide text-gray-500 uppercase"
|
|
||||||
>
|
|
||||||
{fieldLabels[field] ? fieldLabels[field]() : field}
|
|
||||||
</span>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Diff panel -->
|
<!-- Diff panel for compare mode -->
|
||||||
{#if diffLoading}
|
{#if diffLoading}
|
||||||
<p class="font-sans text-xs text-gray-400">{m.history_loading()}</p>
|
<p class="font-sans text-xs text-gray-400">{m.history_loading()}</p>
|
||||||
{:else if noDiff}
|
{:else if noDiff}
|
||||||
@@ -442,5 +404,116 @@ $effect(() => {
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<!-- Version list with inline diff below each selected item -->
|
||||||
|
<ul class="divide-y divide-brand-sand">
|
||||||
|
{#each versions as v, i (v.id)}
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
onclick={() => selectVersion(v.id)}
|
||||||
|
data-testid="history-version"
|
||||||
|
class="w-full py-2 text-left transition hover:bg-brand-sand/30 {selectedVersionId ===
|
||||||
|
v.id
|
||||||
|
? 'border-l-2 border-brand-mint pl-2'
|
||||||
|
: 'pl-0'}"
|
||||||
|
>
|
||||||
|
<div class="flex items-baseline justify-between gap-2">
|
||||||
|
<span class="font-sans text-xs font-medium text-brand-navy">
|
||||||
|
Version {i + 1}
|
||||||
|
</span>
|
||||||
|
<span class="font-sans text-[10px] text-gray-400">
|
||||||
|
{formatDateTime(v.savedAt)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="font-sans text-[11px] text-gray-500">{v.editorName}</span>
|
||||||
|
{#if v.changedFields && v.changedFields.length > 0}
|
||||||
|
<div class="mt-1 flex flex-wrap gap-1">
|
||||||
|
{#each v.changedFields as field (field)}
|
||||||
|
<span
|
||||||
|
class="rounded bg-brand-sand/50 px-1.5 py-0.5 font-sans text-[10px] tracking-wide text-gray-500 uppercase"
|
||||||
|
>
|
||||||
|
{fieldLabels[field] ? fieldLabels[field]() : field}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Diff shown inline below the selected version -->
|
||||||
|
{#if selectedVersionId === v.id}
|
||||||
|
{#if diffLoading}
|
||||||
|
<p class="pb-3 pl-2 font-sans text-xs text-gray-400">{m.history_loading()}</p>
|
||||||
|
{:else if noDiff}
|
||||||
|
<div
|
||||||
|
data-testid="history-diff"
|
||||||
|
class="mb-2 rounded-sm border border-brand-sand bg-white p-4 font-serif text-sm text-gray-400 italic"
|
||||||
|
>
|
||||||
|
{m.history_diff_no_changes()}
|
||||||
|
</div>
|
||||||
|
{:else if diffEntries.length > 0}
|
||||||
|
<div
|
||||||
|
data-testid="history-diff"
|
||||||
|
class="mb-2 space-y-4 rounded-sm border border-brand-sand bg-white p-4"
|
||||||
|
>
|
||||||
|
{#each diffEntries as entry (entry.field)}
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="mb-1.5 block font-sans text-[10px] font-bold tracking-wide text-gray-400 uppercase"
|
||||||
|
>{entry.label}</span
|
||||||
|
>
|
||||||
|
{#if entry.kind === 'text'}
|
||||||
|
<p class="font-serif text-sm leading-relaxed">
|
||||||
|
{#each entry.parts as part, partIdx (partIdx)}
|
||||||
|
{#if part.added}
|
||||||
|
<span class="bg-green-50 text-green-700">{part.value}</span>
|
||||||
|
{:else if part.removed}
|
||||||
|
<span class="bg-red-50 text-red-600 line-through">{part.value}</span>
|
||||||
|
{:else}
|
||||||
|
<span>{part.value}</span>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</p>
|
||||||
|
{:else if entry.kind === 'scalar'}
|
||||||
|
<div class="flex items-center gap-2 font-serif text-sm">
|
||||||
|
<span class="text-red-600 line-through">{entry.oldVal || '—'}</span>
|
||||||
|
<svg
|
||||||
|
class="h-3 w-3 flex-shrink-0 text-gray-400"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span class="text-green-700">{entry.newVal || '—'}</span>
|
||||||
|
</div>
|
||||||
|
{:else if entry.kind === 'relation'}
|
||||||
|
<div class="flex flex-wrap gap-1.5">
|
||||||
|
{#each entry.removed as item (item)}
|
||||||
|
<span
|
||||||
|
class="rounded bg-red-50 px-1.5 py-0.5 font-sans text-[11px] text-red-600 line-through"
|
||||||
|
>{item}</span
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
{#each entry.added as item (item)}
|
||||||
|
<span
|
||||||
|
class="rounded bg-green-50 px-1.5 py-0.5 font-sans text-[11px] text-green-700"
|
||||||
|
>{item}</span
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user