add overlay variable diagnostics
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user