Initial release 0.1.0
This commit is contained in:
commit
9f97d8407a
52 files changed
+6774
No files matched your search
@@ -0,0 +1,5 @@
|
||||
import { getPieces, getShow } from '#lib/server/previews.js';
|
||||
|
||||
export function load() {
|
||||
return { pieces: getPieces(), show: getShow() };
|
||||
}
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user