155 lines
5.2 KiB
Svelte
155 lines
5.2 KiB
Svelte
<script lang="ts">
|
|
import { resolve } from '$app/paths';
|
|
import { formatClock } from '#lib/format.js';
|
|
import type { PageProps } from './$types';
|
|
|
|
let { data, form }: PageProps = $props();
|
|
const statusLabel = {
|
|
ready: 'Sendefertig',
|
|
preparing: 'In Vorbereitung',
|
|
inbox: 'Eingang',
|
|
archived: 'Archiviert'
|
|
};
|
|
</script>
|
|
|
|
<svelte:head><title>Fundus | Sendewerk</title></svelte:head>
|
|
|
|
<div class="page-wrap">
|
|
<header class="page-heading split-heading">
|
|
<div>
|
|
<h1>Fundus</h1>
|
|
<p class="page-intro">Vorbereitete Inhalte für kommende Sendungen.</p>
|
|
</div>
|
|
<div class="heading-stat" aria-label={`${data.pieces.length} gefundene Inhalte`}>
|
|
<strong>{data.pieces.length}</strong><span>Inhalte</span>
|
|
</div>
|
|
</header>
|
|
{#if form?.error}<div class="form-message error" role="alert">{form.error}</div>{/if}
|
|
{#if form?.success}<div class="form-message success" role="status">{form.success}</div>{/if}
|
|
|
|
<details class="template-picker">
|
|
<summary>Neues Piece anlegen</summary>
|
|
<div class="template-grid">
|
|
{#each data.templates as template (template.id)}
|
|
<form method="POST" action="?/create">
|
|
<input type="hidden" name="template" value={template.id} />
|
|
<button type="submit"
|
|
><strong>{template.name}</strong><span>{template.description}</span></button
|
|
>
|
|
</form>
|
|
{/each}
|
|
</div>
|
|
</details>
|
|
|
|
<form class="library-filters" method="GET" aria-label="Fundus durchsuchen und filtern">
|
|
<label class="search-field"
|
|
><span aria-hidden="true">⌕</span><span class="sr-only">Fundus durchsuchen</span><input
|
|
name="q"
|
|
type="search"
|
|
value={data.filters.query}
|
|
placeholder="Titel, Quelle oder Thema suchen"
|
|
/></label
|
|
>
|
|
<label
|
|
><span>Status</span><select name="status"
|
|
><option value="">Alle</option><option
|
|
value="ready"
|
|
selected={data.filters.status === 'ready'}>Sendefertig</option
|
|
><option value="preparing" selected={data.filters.status === 'preparing'}>In Arbeit</option
|
|
></select
|
|
></label
|
|
>
|
|
<label
|
|
><span>Format</span><select name="format"
|
|
><option value="">Alle</option>{#each data.taxonomy.formats as item (item.id)}<option
|
|
value={item.id}
|
|
selected={data.filters.formatId === item.id}>{item.name}</option
|
|
>{/each}</select
|
|
></label
|
|
>
|
|
<label
|
|
><span>Thema</span><select name="topic"
|
|
><option value="">Alle</option>{#each data.taxonomy.topics as item (item.id)}<option
|
|
value={item.id}
|
|
selected={data.filters.topicId === item.id}>{item.name}</option
|
|
>{/each}</select
|
|
></label
|
|
>
|
|
<label
|
|
><span>Abschnitt</span><select name="category"
|
|
><option value="">Alle</option>{#each data.taxonomy.categories as item (item.id)}<option
|
|
value={item.id}
|
|
selected={data.filters.categoryId === item.id}>{item.name}</option
|
|
>{/each}</select
|
|
></label
|
|
>
|
|
<button class="secondary-button" type="submit">Anwenden</button>
|
|
<a class="text-link" href={resolve('/fundus')}>Zurücksetzen</a>
|
|
</form>
|
|
|
|
{#if data.pieces.length}
|
|
<div class="piece-grid">
|
|
{#each data.pieces as piece (piece.id)}
|
|
<article
|
|
class="piece-card"
|
|
style={`--category: ${piece.categories[0]?.color ?? '#8b8f98'}`}
|
|
>
|
|
{#if piece.mediaId}<img
|
|
class="piece-thumbnail"
|
|
src={`/media/${piece.mediaId}`}
|
|
alt=""
|
|
/>{:else}<span class="piece-thumbnail piece-thumbnail-placeholder" aria-hidden="true"
|
|
>S</span
|
|
>{/if}
|
|
<div class="piece-primary">
|
|
<h2><a href={resolve('/fundus/[id]', { id: piece.id })}>{piece.title}</a></h2>
|
|
<p>{piece.summary || 'Noch keine Kurzbeschreibung.'}</p>
|
|
</div>
|
|
<div class="piece-classification">
|
|
<span class="category-label"
|
|
><i></i>{piece.categories.map((item) => item.name).join(', ') || 'Offen'}</span
|
|
>
|
|
<div class="piece-tags">
|
|
<span>{piece.format}</span>{#each piece.topics as topic (topic.id)}<span
|
|
>{topic.name}</span
|
|
>{/each}
|
|
</div>
|
|
</div>
|
|
<div class="piece-state">
|
|
<span class:ready={piece.status === 'ready'} class="status-label"
|
|
>{statusLabel[piece.status]}</span
|
|
><span class="piece-facts"
|
|
><span><b>{formatClock(piece.durationSeconds)}</b> geplant</span><span
|
|
>{piece.sourceCount} {piece.sourceCount === 1 ? 'Quelle' : 'Quellen'}</span
|
|
></span
|
|
>
|
|
</div>
|
|
<div class="piece-actions">
|
|
<a class="text-link" href={resolve('/fundus/[id]', { id: piece.id })}>Bearbeiten</a>
|
|
<form method="POST" action="?/duplicate">
|
|
<input type="hidden" name="pieceId" value={piece.id} /><button
|
|
class="text-button"
|
|
type="submit">Duplizieren</button
|
|
>
|
|
</form>
|
|
<form method="POST" action="?/archive">
|
|
<input type="hidden" name="pieceId" value={piece.id} /><input
|
|
type="hidden"
|
|
name="revision"
|
|
value={piece.revision}
|
|
/><button class="text-button danger-text" type="submit">Archivieren</button>
|
|
</form>
|
|
</div>
|
|
</article>
|
|
{/each}
|
|
</div>
|
|
{:else}
|
|
<div class="empty-state">
|
|
<span aria-hidden="true">⌕</span>
|
|
<h2>Kein passendes Piece</h2>
|
|
<p>Andere Filter wählen oder ein neues Piece anlegen.</p>
|
|
<a class="secondary-button" href={resolve('/fundus')}>Filter zurücksetzen</a>
|
|
</div>
|
|
{/if}
|
|
</div>
|