Initial release 0.1.0

This commit is contained in:
hnzio committed 2026-10-21 14:50:31 +02:00
commit 9f97d8407a
52 files changed
+6774

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
import { getPieces, getShow } from '#lib/server/previews.js';
export function load() {
return { pieces: getPieces(), show: getShow() };
}
+141
View File
@@ -0,0 +1,141 @@
<script lang="ts">
import PreviewNotice from '#lib/components/PreviewNotice.svelte';
import { formatClock, formatDuration } from '#lib/format.js';
import { resolve } from '$app/paths';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
let mobilePane = $state<'fundus' | 'plan'>('plan');
let plannedCount = $derived(
data.show.sections.reduce(
(total, section) => total + section.usages.filter((usage) => !usage.isReserve).length,
0
)
);
</script>
<svelte:head><title>Sendungen | Sendewerk</title></svelte:head>
<div class="page-wrap builder-page">
<header class="page-heading show-heading">
<div>
<p class="eyebrow">Nächste Sendung · {data.show.startsAtBerlin} Uhr</p>
<h1>{data.show.title}</h1>
</div>
<div class="show-summary">
<div><strong>{plannedCount}</strong><span>Stücke</span></div>
<div>
<strong>{formatDuration(data.show.totalDurationSeconds)}</strong><span>Planzeit</span>
</div>
<a class="live-link" href={resolve('/live')}>Live-Vorschau <span>↗</span></a>
</div>
</header>
<PreviewNotice area="Sendungsbau" />
<div class="mobile-pane-switch" aria-label="Arbeitsbereich auswählen">
<button
class:active={mobilePane === 'fundus'}
type="button"
onclick={() => (mobilePane = 'fundus')}>Fundus</button
>
<button class:active={mobilePane === 'plan'} type="button" onclick={() => (mobilePane = 'plan')}
>Ablauf</button
>
</div>
<div class="builder-workspace">
<section
class="builder-pane source-pane"
class:mobile-hidden={mobilePane !== 'fundus'}
aria-labelledby="source-title"
>
<header class="pane-heading">
<div>
<p class="eyebrow">Quelle</p>
<h2 id="source-title">Sendefertiger Fundus</h2>
</div>
<span>{data.pieces.filter((piece) => piece.status === 'ready').length}</span>
</header>
<label class="compact-search">
<span aria-hidden="true">⌕</span><span class="sr-only">Fundus durchsuchen</span>
<input
type="search"
placeholder="Fundus durchsuchen"
disabled
title="Die vollständige Suche folgt in Etappe 3"
/>
</label>
<div class="source-list">
{#each data.pieces.filter((piece) => piece.status === 'ready') as piece (piece.id)}
<article class="source-card" style={`--category: ${piece.categoryColor}`}>
<div>
<span class="category-label"><i></i>{piece.category}</span><span
>{formatClock(piece.durationSeconds)}</span
>
</div>
<h3>{piece.title}</h3>
<p>{piece.format} · {piece.topics.join(', ')}</p>
</article>
{/each}
</div>
<div class="reserve-box">
<div>
<span aria-hidden="true">◇</span>
<div><strong>Reservebank</strong><small>1 Stück vorbereitet</small></div>
</div>
<p>„Pixelart, die nicht nostalgisch sein will“ wartet als Ersatz.</p>
</div>
</section>
<section
class="builder-pane run-pane"
class:mobile-hidden={mobilePane !== 'plan'}
aria-labelledby="run-title"
>
<header class="pane-heading">
<div>
<p class="eyebrow">Sendungsplan</p>
<h2 id="run-title">Ablauf</h2>
</div>
<span>{formatDuration(data.show.totalDurationSeconds)}</span>
</header>
<div class="run-list">
{#each data.show.sections as section, index (section.id)}
<article class="run-section" style={`--category: ${section.categoryColor}`}>
<header>
<div class="section-number">{String(index + 1).padStart(2, '0')}</div>
<div>
<span class="category-label"><i></i>{section.category}</span>
<h3>{section.name}</h3>
</div>
<strong>{formatClock(section.durationSeconds)}</strong>
</header>
{#if section.usages.filter((usage) => !usage.isReserve).length > 0}
<div class="usage-list">
{#each section.usages.filter((usage) => !usage.isReserve) as usage (usage.id)}
<div class="usage-row">
<span class="drag-hint" aria-hidden="true">⠿</span>
<div>
<strong>{usage.title}</strong><small
>{formatClock(usage.durationSeconds)} · Eigene Sendungskopie</small
>
</div>
<span class:current={usage.status === 'current'} class="usage-status"
>{usage.status === 'current' ? 'Aktuell' : 'Offen'}</span
>
</div>
{/each}
</div>
{:else}
<div class="section-placeholder">
Eigenständiger Spieleblock · keine Piece-Kopie nötig
</div>
{/if}
</article>
{/each}
</div>
</section>
</div>
</div>