Add live template preview (auto-updates as you type)
All checks were successful
Validate / Hassfest (push) Successful in 4s

Preview now piggybacks on the validation debounce call — when the
template renders successfully, the result is shown in a collapsible
<details> section below the editor. Removes the manual Preview button
since it's now automatic. Preview hides when there are errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 20:51:04 +03:00
parent afb8be8101
commit 3c893d6dbf

View File

@@ -35,6 +35,8 @@
slotErrors = { ...slotErrors, [slotKey]: '' };
slotErrorLines = { ...slotErrorLines, [slotKey]: null };
slotErrorTypes = { ...slotErrorTypes, [slotKey]: '' };
const { [slotKey]: _, ...rest } = slotPreview;
slotPreview = rest;
return;
}
@@ -45,6 +47,13 @@
slotErrors = { ...slotErrors, [slotKey]: res.error || '' };
slotErrorLines = { ...slotErrorLines, [slotKey]: res.error_line || null };
slotErrorTypes = { ...slotErrorTypes, [slotKey]: res.error_type || '' };
// Live preview: show rendered result when no error
if (res.rendered) {
slotPreview = { ...slotPreview, [slotKey]: res.rendered };
} else {
const { [slotKey]: _, ...rest } = slotPreview;
slotPreview = rest;
}
} catch {
// Network error, don't show as template error
slotErrors = { ...slotErrors, [slotKey]: '' };
@@ -180,10 +189,6 @@
<div class="flex items-center justify-between mb-1">
<label class="text-xs text-[var(--color-muted-foreground)]">{t(`templateConfig.${slot.label}`)}</label>
<div class="flex items-center gap-2">
{#if (slot.rows || 2) > 2}
<button type="button" onclick={() => previewSlot(slot.key)}
class="text-xs text-[var(--color-muted-foreground)] hover:underline">{t('templateConfig.preview')}</button>
{/if}
{#if varsRef[slot.key]}
<button type="button" onclick={() => showVarsFor = slot.key}
class="text-xs text-[var(--color-muted-foreground)] hover:underline">{t('templateConfig.variables')}</button>
@@ -199,10 +204,13 @@
<p class="mt-1 text-xs" style="color: var(--color-error-fg);">✕ {t('common.syntaxError')}: {slotErrors[slot.key]}{slotErrorLines[slot.key] ? ` (${t('common.line')} ${slotErrorLines[slot.key]})` : ''}</p>
{/if}
{/if}
{#if slotPreview[slot.key]}
<div class="mt-1 p-2 bg-[var(--color-muted)] rounded text-sm">
<pre class="whitespace-pre-wrap">{slotPreview[slot.key]}</pre>
</div>
{#if slotPreview[slot.key] && !slotErrors[slot.key]}
<details class="mt-1">
<summary class="text-xs text-[var(--color-muted-foreground)] cursor-pointer hover:underline">{t('templateConfig.preview')}</summary>
<div class="mt-1 p-2 bg-[var(--color-muted)] rounded text-sm">
<pre class="whitespace-pre-wrap">{slotPreview[slot.key]}</pre>
</div>
</details>
{/if}
{:else}
<input bind:value={(form as any)[slot.key]}