From 7b3d3f8b363c745a7bba8107b93f05b3d4bd4c5a Mon Sep 17 00:00:00 2001
From: Marcel
Date: Mon, 27 Apr 2026 21:43:20 +0200
Subject: [PATCH] feat(documents): inline relationship pills next to person
names
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replaces the standalone "Beziehung" badge at the bottom of the
metadata drawer's Personen column with small inline pills attached
to each personCard — sender gets labelFromA, the single receiver
gets labelFromB. Matches docs/specs/stammbaum-doc-badge-spec.html.
Drops the now-unused RelationshipBadge component.
Co-Authored-By: Claude Opus 4.7
---
.../components/DocumentMetadataDrawer.svelte | 24 ++++++++---------
.../DocumentMetadataDrawer.svelte.spec.ts | 19 ++++++++++++++
.../lib/components/RelationshipBadge.svelte | 26 -------------------
.../lib/components/RelationshipPill.svelte | 10 +++++++
4 files changed, 41 insertions(+), 38 deletions(-)
delete mode 100644 frontend/src/lib/components/RelationshipBadge.svelte
create mode 100644 frontend/src/lib/components/RelationshipPill.svelte
diff --git a/frontend/src/lib/components/DocumentMetadataDrawer.svelte b/frontend/src/lib/components/DocumentMetadataDrawer.svelte
index fd896f1c..4441fd53 100644
--- a/frontend/src/lib/components/DocumentMetadataDrawer.svelte
+++ b/frontend/src/lib/components/DocumentMetadataDrawer.svelte
@@ -3,7 +3,7 @@ import { m } from '$lib/paraglide/messages.js';
import { formatDate } from '$lib/utils/date';
import { formatDocumentStatus } from '$lib/utils/documentStatusLabel';
import { getInitials, personAvatarColor } from '$lib/utils/personFormat';
-import RelationshipBadge from '$lib/components/RelationshipBadge.svelte';
+import RelationshipPill from '$lib/components/RelationshipPill.svelte';
type Person = { id: string; firstName?: string | null; lastName: string; displayName: string };
type Tag = { id: string; name: string };
@@ -47,7 +47,7 @@ function getFullName(person: Person): string {
}
-{#snippet personCard(person: Person)}
+{#snippet personCard(person: Person, relationLabel: string | null = null)}
{getInitials(person.displayName)}
- {getFullName(person)}
+ {getFullName(person)}
+ {#if relationLabel}
+
+ {/if}
{/snippet}
@@ -98,7 +101,7 @@ function getFullName(person: Person): string {
{m.doc_details_field_sender()}
- {@render personCard(sender)}
+ {@render personCard(sender, inferredRelationship?.labelFromA ?? null)}
{/if}
{#if receivers.length > 0}
@@ -107,8 +110,11 @@ function getFullName(person: Person): string {
{m.doc_details_field_receivers()}
- {#each displayedReceivers as receiver (receiver.id)}
- {@render personCard(receiver)}
+ {#each displayedReceivers as receiver, i (receiver.id)}
+ {@render personCard(
+ receiver,
+ i === 0 ? (inferredRelationship?.labelFromB ?? null) : null
+ )}
{/each}
{#if hiddenReceiverCount > 0 && !showAllReceivers}
@@ -122,12 +128,6 @@ function getFullName(person: Person): string {
{/if}
{/if}
- {#if inferredRelationship}
-
- {/if}
{:else}
{m.doc_details_no_persons()}
diff --git a/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts b/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts
index aeda6bbe..07f3d4c5 100644
--- a/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts
+++ b/frontend/src/lib/components/DocumentMetadataDrawer.svelte.spec.ts
@@ -81,6 +81,25 @@ describe('DocumentMetadataDrawer — persons column', () => {
renderDrawer({ sender: null, receivers: [] });
await expect.element(page.getByText('Keine Personen zugeordnet')).toBeInTheDocument();
});
+
+ it('renders inferred relationship pills inline next to sender and receiver', async () => {
+ renderDrawer({
+ receivers: [receivers[0]],
+ inferredRelationship: { labelFromA: 'Elternteil', labelFromB: 'Kind' }
+ });
+
+ // Sender link contains its pill, receiver link contains its pill.
+ const senderLink = page.getByRole('link', { name: /Karl Müller.*Elternteil/i });
+ await expect.element(senderLink).toBeInTheDocument();
+ const receiverLink = page.getByRole('link', { name: /Anna Schmidt.*Kind/i });
+ await expect.element(receiverLink).toBeInTheDocument();
+ });
+
+ it('omits the pills when no inferred relationship is provided', async () => {
+ renderDrawer();
+ const elternteil = page.getByText('Elternteil');
+ expect(await elternteil.elements()).toHaveLength(0);
+ });
});
// ─── Tags column ─────────────────────────────────────────────────────────────
diff --git a/frontend/src/lib/components/RelationshipBadge.svelte b/frontend/src/lib/components/RelationshipBadge.svelte
deleted file mode 100644
index 8de6473f..00000000
--- a/frontend/src/lib/components/RelationshipBadge.svelte
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- {m.doc_details_field_relationship()}
-
-
-
{labelFromA}
-
-
{labelFromB}
-
-
diff --git a/frontend/src/lib/components/RelationshipPill.svelte b/frontend/src/lib/components/RelationshipPill.svelte
new file mode 100644
index 00000000..d447b326
--- /dev/null
+++ b/frontend/src/lib/components/RelationshipPill.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {label}
+