feat: discussion sub-tab navigation for annotation threads (#60) #63
@@ -333,8 +333,79 @@ $effect(() => {
|
|||||||
{m.history_compare_apply()}
|
{m.history_compare_apply()}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Diff panel for compare mode -->
|
||||||
|
{#if diffLoading}
|
||||||
|
<p class="font-sans text-xs text-gray-400">{m.history_loading()}</p>
|
||||||
|
{:else if noDiff}
|
||||||
|
<div
|
||||||
|
data-testid="history-diff"
|
||||||
|
class="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="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}
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Version list -->
|
<!-- Version list with inline diff below each selected item -->
|
||||||
<ul class="divide-y divide-brand-sand">
|
<ul class="divide-y divide-brand-sand">
|
||||||
{#each versions as v, i (v.id)}
|
{#each versions as v, i (v.id)}
|
||||||
<li>
|
<li>
|
||||||
@@ -367,80 +438,82 @@ $effect(() => {
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</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>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Diff panel -->
|
|
||||||
{#if diffLoading}
|
|
||||||
<p class="font-sans text-xs text-gray-400">{m.history_loading()}</p>
|
|
||||||
{:else if noDiff}
|
|
||||||
<div
|
|
||||||
data-testid="history-diff"
|
|
||||||
class="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="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}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user