add overlay variable diagnostics

This commit is contained in:
2026-10-25 05:36:50 +01:00
parent d095ddec03
commit 890c42e62f
2 changed files with 39 additions and 0 deletions
+22
View File
@@ -94,6 +94,7 @@
let overlaySavedSignature = '';
let overlayAutosaveAttemptedSignature = '';
let pendingOverlayDraft: { overlayName: string; overlaySlug: string; overlayHtml: string; overlayCss: string; overlayJavascript: string; overlayEnabled: boolean; overlayDisabledDesign: string } | null = null;
let overlayDiagnosticsOpen = false;
let overlayAutosaveTimer: number | undefined;
let oauthScopes: Record<'streamer' | 'bot', { connected: boolean; missing_scopes: string[]; reauthorization_required: boolean }> = {
streamer: { connected: false, missing_scopes: [], reauthorization_required: false },
@@ -724,6 +725,21 @@
return JSON.stringify({ overlayName, overlaySlug, overlayHtml, overlayCss, overlayJavascript, overlayEnabled, overlayDisabledDesign });
}
function overlayVariableWarnings() {
const warnings: string[] = [];
for (const [language, source] of [['HTML', overlayHtml], ['CSS', overlayCss], ['JAVASCRIPT', overlayJavascript]] as const) {
if (source.includes('${')) {
for (const match of source.match(/\$\{([^}]*)\}/g) || []) {
const name = match.slice(2, -1);
if (!/^[A-Za-z0-9_]+$/.test(name) || name.length === 0) warnings.push(`${language}: invalid variable ${match[0]}`);
else if (name !== 'username') warnings.push(`${language}: undefined variable ${match[0]}`);
}
if (source.split('${').length - 1 !== (source.match(/\$\{[^}]*\}/g) || []).length) warnings.push(`${language}: an opening variable marker has no closing }`);
}
}
return warnings;
}
function overlayDraftCacheKey(id: string) {
return `trixie.overlay.draft.${id}`;
}
@@ -1026,5 +1042,11 @@
<div class="settings-body"><span>A newer unsaved draft is available for this overlay.</span><div class="overlay-controls"><button class="primary" onclick={restorePendingOverlayDraft}>RESTORE LOCAL DRAFT</button><button class="secondary" onclick={discardPendingOverlayDraft}>DISCARD LOCAL DRAFT</button></div></div>
</section>
{/if}
{#if activeView === 'Overlays' && (selectedOverlayId || overlayName) && overlayVariableWarnings().length}
<section class="panel overlay-diagnostics-panel">
<div class="panel-header"><button class="diagnostics-toggle" onclick={() => (overlayDiagnosticsOpen = !overlayDiagnosticsOpen)} aria-expanded={overlayDiagnosticsOpen}>⚠ {overlayVariableWarnings().length} VARIABLE WARNING{overlayVariableWarnings().length === 1 ? '' : 'S'}</button></div>
{#if overlayDiagnosticsOpen}<div class="diagnostics-details">{#each overlayVariableWarnings() as warning}<div>{warning}</div>{/each}</div>{/if}
</section>
{/if}
</main>
</div>
+17
View File
@@ -931,3 +931,20 @@ label {
margin: 6px 0 10px 18px;
border-left: 2px solid var(--ui-line-focus);
}
.overlay-diagnostics-panel {
margin-top: 10px;
}
.diagnostics-toggle {
border: 0;
background: transparent;
color: var(--ui-error, #ff6b7a);
font: inherit;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.diagnostics-details {
padding: 10px;
color: var(--ui-error, #ff6b7a);
font-family: var(--font-mono);
font-size: 0.8rem;
}