Use combobox for target type selector, refresh previews on change
All checks were successful
Validate / Hassfest (push) Successful in 3s

- Replace toggle buttons with <select> dropdown for target type
- Add refreshAllPreviews() that immediately re-renders all open
  previews when target type changes (no 800ms debounce)
- validateSlot() now accepts optional immediate flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 21:13:53 +03:00
parent 4babaddd87
commit c5a3521b14

View File

@@ -28,7 +28,7 @@
let slotErrorTypes = $state<Record<string, string>>({});
let validateTimers: Record<string, ReturnType<typeof setTimeout>> = {};
function validateSlot(slotKey: string, template: string) {
function validateSlot(slotKey: string, template: string, immediate = false) {
// Clear previous timer
if (validateTimers[slotKey]) clearTimeout(validateTimers[slotKey]);
if (!template) {
@@ -40,8 +40,7 @@
return;
}
// Debounce 800ms
validateTimers[slotKey] = setTimeout(async () => {
const doValidate = async () => {
try {
const res = await api('/template-configs/preview-raw', { method: 'POST', body: JSON.stringify({ template, target_type: previewTargetType }) });
slotErrors = { ...slotErrors, [slotKey]: res.error || '' };
@@ -60,7 +59,21 @@
slotErrorLines = { ...slotErrorLines, [slotKey]: null };
slotErrorTypes = { ...slotErrorTypes, [slotKey]: '' };
}
}, 800);
};
if (immediate) { doValidate(); }
else { validateTimers[slotKey] = setTimeout(doValidate, 800); }
}
function refreshAllPreviews() {
// Re-validate and re-preview all slots that have content (immediate, no debounce)
for (const group of templateSlots) {
for (const slot of group.slots) {
const template = (form as any)[slot.key];
if (template && slot.key !== 'date_format') {
validateSlot(slot.key, template, true);
}
}
}
}
const defaultForm = () => ({
@@ -181,17 +194,12 @@
<!-- Target type selector for preview -->
<div class="flex items-center gap-2">
<label class="text-sm font-medium">{t('templateConfig.previewAs')}:</label>
<div class="flex gap-1">
<button type="button" onclick={() => previewTargetType = 'telegram'}
class="px-3 py-1 text-xs rounded-md transition-colors {previewTargetType === 'telegram' ? 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)]' : 'bg-[var(--color-muted)] text-[var(--color-muted-foreground)]'}">
Telegram
</button>
<button type="button" onclick={() => previewTargetType = 'webhook'}
class="px-3 py-1 text-xs rounded-md transition-colors {previewTargetType === 'webhook' ? 'bg-[var(--color-primary)] text-[var(--color-primary-foreground)]' : 'bg-[var(--color-muted)] text-[var(--color-muted-foreground)]'}">
Webhook
</button>
</div>
<label for="preview-target" class="text-sm font-medium">{t('templateConfig.previewAs')}:</label>
<select id="preview-target" bind:value={previewTargetType} onchange={refreshAllPreviews}
class="px-2 py-1 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]">
<option value="telegram">Telegram</option>
<option value="webhook">Webhook</option>
</select>
</div>
{#each templateSlots as group}