synops/frontend/src/lib/components/traits/ChatTrait.svelte
vegard 263f63bec8 Trait-aware frontend: samlingssider med dynamiske trait-paneler (oppgave 13.2)
Samlingsnoder med `metadata.traits` rendres nå som egne sider på
/collection/[id]. Hvert trait-navn mappes til en dedikert Svelte-komponent
som viser relevant UI. Traits uten egen komponent vises med et generisk panel.

Komponenter for 9 traits: editor, chat, kanban, podcast, publishing,
rss, calendar, recording, transcription. Mottak-siden viser traits som
pills og lenker til samlingssiden.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:20:35 +00:00

55 lines
1.6 KiB
Svelte

<script lang="ts">
import type { Node } from '$lib/spacetime';
import { edgeStore, nodeStore } from '$lib/spacetime';
import TraitPanel from './TraitPanel.svelte';
interface Props {
collection: Node;
config: Record<string, unknown>;
userId?: string;
}
let { collection, config, userId }: Props = $props();
/** Communication nodes linked to this collection */
const chatNodes = $derived.by(() => {
const nodes: Node[] = [];
for (const edge of edgeStore.byTarget(collection.id)) {
if (edge.edgeType !== 'belongs_to') continue;
const node = nodeStore.get(edge.sourceId);
if (node && node.nodeKind === 'communication') {
nodes.push(node);
}
}
// Also check source edges (collection --has_channel--> communication)
for (const edge of edgeStore.bySource(collection.id)) {
if (edge.edgeType !== 'has_channel') continue;
const node = nodeStore.get(edge.targetId);
if (node && node.nodeKind === 'communication') {
nodes.push(node);
}
}
return nodes;
});
</script>
<TraitPanel name="chat" label="Samtaler" icon="💬">
{#snippet children()}
{#if chatNodes.length === 0}
<p class="text-sm text-gray-400">Ingen samtaler knyttet til denne samlingen.</p>
{:else}
<ul class="space-y-2">
{#each chatNodes as node (node.id)}
<li>
<a
href="/chat/{node.id}"
class="block rounded border border-gray-100 px-3 py-2 transition-colors hover:border-blue-300 hover:bg-blue-50"
>
<span class="text-sm font-medium text-gray-900">{node.title || 'Samtale'}</span>
</a>
</li>
{/each}
</ul>
{/if}
{/snippet}
</TraitPanel>