Complete 0.7.1 fixes

This commit is contained in:
hnzio committed 2026-10-26 09:35:19 +01:00
1 parent a08b02c34b
commit 64f55a8b1f
26 files changed
+610 -168

No files matched your search

+8 -1
View File
@@ -15,6 +15,13 @@
)
);
let visible = $derived(filtered.slice(0, 120));
function openAndFocus(event: MouseEvent) {
if (menu.open) return;
event.preventDefault();
menu.open = true;
searchInput.focus({ preventScroll: true });
}
</script>
<div class="icon-picker">
@@ -25,7 +32,7 @@
if (menu.open) queueMicrotask(() => searchInput.focus());
}}
>
<summary><AppIcon name={name || 'circle'} /> Icon auswählen</summary>
<summary onclick={openAndFocus}><AppIcon name={name || 'circle'} /> Icon auswählen</summary>
<div class="icon-picker-popover">
<label
><span class="sr-only">Icons durchsuchen</span><input
@@ -62,7 +62,6 @@
</article>
{:else if content.mode === 'image'}
<article class="output-content output-image-only">
{#if content.topics.length}<p class="output-topics">{content.topics.join(' · ')}</p>{/if}
{#if imageSrc}<img src={imageSrc} alt={content.images?.[0]?.altText ?? content.title} />{/if}
</article>
{:else if content.mode === 'link'}
+32 -11
View File
@@ -27,11 +27,13 @@
shows,
shares,
fixedShowId = '',
catalogPanel = false,
form = null
}: {
shows: ShareShow[];
shares: ShareItem[];
fixedShowId?: string;
catalogPanel?: boolean;
form?: {
intent?: string;
error?: string;
@@ -104,18 +106,37 @@
}
</script>
<button
class="secondary-button share-dialog-trigger"
type="button"
onclick={() => dialog.showModal()}
>
<AppIcon name="link" /> Lesefreigaben
</button>
<dialog bind:this={dialog} class="share-management-dialog">
<section
class="quiet-panel share-management"
aria-labelledby={`share-title-${fixedShowId || 'all'}`}
{#if catalogPanel}
<section class="quiet-panel share-catalog-panel">
<div class="panel-heading">
<div>
<p class="eyebrow">Gastzugänge</p>
<h2>Lesefreigaben</h2>
</div>
<button
class="compact-add-button share-dialog-trigger"
type="button"
aria-label="Lesefreigaben"
onclick={() => dialog.showModal()}
>
<AppIcon name="link" /> Freigaben verwalten
</button>
</div>
<p class="catalog-note">
Sendungen gezielt als widerrufbaren Leselink mit wählbarem Informationsumfang teilen.
</p>
</section>
{:else}
<button
class="secondary-button share-dialog-trigger"
type="button"
onclick={() => dialog.showModal()}
>
<AppIcon name="link" /> Lesefreigaben
</button>
{/if}
<dialog bind:this={dialog} class="share-management-dialog">
<section class="share-management" aria-labelledby={`share-title-${fixedShowId || 'all'}`}>
<div class="panel-heading">
<div>
<p class="eyebrow">Gastzugänge</p>
+85 -41
View File
@@ -5,6 +5,7 @@
import InlineTitleEditor from './InlineTitleEditor.svelte';
import NavIcon from './NavIcon.svelte';
import PieceEditorDialog from './PieceEditorDialog.svelte';
import PresentationDisplay from './PresentationDisplay.svelte';
import type { PieceUsage } from '#lib/server/shows.js';
let {
@@ -32,6 +33,11 @@
untrack(() => ({ ...usage, tools: usage.tools.map((tool) => ({ ...tool })) }))
);
let dirty = $state(false);
let selectedSourceId = $state(
untrack(
() => usage.sources.find((source) => source.url === usage.presentationSourceUrl)?.id ?? ''
)
);
onMount(() => {
if (open) editor.showModal();
});
@@ -43,6 +49,16 @@
return Number((seconds / 60).toFixed(2));
}
function previewHtml(value: string) {
return value
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#039;')
.replaceAll('\n', '<br>');
}
function requestClose() {
if (dirty && !confirm('Ungespeicherte Änderungen verwerfen und Editor schließen?')) return;
dirty = false;
@@ -50,14 +66,46 @@
}
function presentationSourceChanged(event: Event) {
const index = Number((event.currentTarget as HTMLSelectElement).value);
const source = draft.sources[index];
selectedSourceId = (event.currentTarget as HTMLSelectElement).value;
const source = draft.sources.find((item) => item.id === selectedSourceId);
if (!source) return;
draft.presentationSourceLabel = source.label;
draft.presentationSourceUrl = source.url;
draft.presentationSourceTimecodeSeconds = source.timecodeSeconds;
}
let previewContent = $derived({
mode: draft.presentationMode,
topics: draft.topics.map((topic) => topic.name),
title: draft.outputTitle || draft.title,
html: previewHtml(draft.presentation),
source: draft.presentationSourceUrl
? {
label: draft.presentationSourceLabel,
url: draft.presentationSourceUrl,
timecodeSeconds: draft.presentationSourceTimecodeSeconds
}
: null,
previewTitle: draft.presentationTitle,
description: draft.presentationDescription,
imageUrl: draft.presentationMode === 'link' ? draft.presentationImageUrl : '',
siteName: draft.presentationSiteName,
provider: draft.presentationProvider,
providerId: draft.presentationProviderId,
embedUrl: '',
sources: [],
images: selectedMedia
? [{ id: selectedMedia.originalMediaId, altText: selectedMedia.altText }]
: []
});
let previewImageSrc = $derived(
selectedMedia && draft.presentationMode === 'text'
? '/media'
: selectedMedia && draft.presentationMode === 'image'
? `/media/${selectedMedia.originalMediaId}`
: ''
);
const enhanceEditor: SubmitFunction = async (input) => {
const finish = await enhanceCommand(input);
return async (result) => {
@@ -139,6 +187,26 @@
<details class="piece-meta-details">
<summary>Dauer und Einplanung</summary>
<div class="piece-meta-grid">
<label
>Vorbereitungsstatus<select
name="preparationStatus"
bind:value={draft.preparationStatus}
>
<option value="preparing">In Vorbereitung</option>
<option value="ready">Sendefertig</option>
</select></label
>
<label
>Vorbereitungsaufwand<select
name="preparationEffort"
bind:value={draft.preparationEffort}
>
<option value={null}>Nicht angegeben</option>
<option value="low">Gering</option>
<option value="medium">Mittel</option>
<option value="high">Hoch</option>
</select></label
>
<label
>Dauer in Minuten<input
name="durationMinutes"
@@ -275,12 +343,12 @@
<div class="presentation-settings">
<label class="wide-field"
>{draft.presentationMode === 'video' ? 'Video-URL' : 'Quelle/URL'}<select
bind:value={selectedSourceId}
onchange={presentationSourceChanged}
>
{#each draft.sources as source, index (source.id)}
<option value={index} selected={source.url === draft.presentationSourceUrl}
>{source.label || source.url}</option
>
<option value="">Quelle auswählen</option>
{#each draft.sources as source (source.id)}
<option value={source.id}>{source.label || source.url}</option>
{/each}
</select></label
>
@@ -332,16 +400,16 @@
class="usage-media-picker"
>
<legend>Hochgeladenes Präsentationsbild</legend>
<label
><input
type="radio"
checked={!draft.presentationMediaId}
onchange={() => {
draft.presentationMediaId = null;
dirty = true;
}}
/> Kein Bild</label
>
{#if draft.presentationMode === 'text'}<label
><input
type="radio"
checked={!draft.presentationMediaId}
onchange={() => {
draft.presentationMediaId = null;
dirty = true;
}}
/> Kein Bild</label
>{/if}
<div class="media-grid">
{#each draft.media as media (media.id)}<label class="media-presentation-choice"
><input
@@ -358,31 +426,7 @@
</div>
</fieldset>{/if}
<aside class="piece-presentation-preview" aria-label="Präsentationsvorschau">
<p class="output-kicker">Vorschau · {draft.presentationMode}</p>
<h4>{draft.outputTitle || draft.title}</h4>
{#if draft.presentationMode === 'text'}
<p class="preview-markdown-source">
{draft.presentation || 'Noch kein öffentlicher Text.'}
</p>
{#if selectedMedia}<img
src={`/media/${selectedMedia.originalMediaId}`}
alt={selectedMedia.altText}
/>{/if}
{:else if draft.presentationMode === 'image'}
{#if selectedMedia}<img
src={`/media/${selectedMedia.originalMediaId}`}
alt={selectedMedia.altText}
/>{/if}
{:else if draft.presentationMode === 'link'}
{#if draft.presentationImageUrl}<img src={draft.presentationImageUrl} alt="" />{/if}
<p>
{draft.presentationDescription ||
draft.presentationSourceUrl ||
'Noch keine Vorschauangaben.'}
</p>
{:else}
<p>{draft.presentationSourceUrl || 'Noch keine Video-URL ausgewählt.'}</p>
{/if}
<PresentationDisplay content={previewContent} imageSrc={previewImageSrc} />
</aside>
</div>
</section>