diff --git a/src/core/ui/canvas-toolbar.ts b/src/core/ui/canvas-toolbar.ts index 71f47770..e84d0495 100644 --- a/src/core/ui/canvas-toolbar.ts +++ b/src/core/ui/canvas-toolbar.ts @@ -80,6 +80,8 @@ export class CanvasToolbar { // Variables elements private variablesList: HTMLDivElement | null = null; private variablesEmpty: HTMLDivElement | null = null; + private variablesAddForm: HTMLDivElement | null = null; + private variablesAddInput: HTMLInputElement | null = null; // Label elements private resolutionLabel: HTMLSpanElement | null = null; @@ -234,7 +236,21 @@ export class CanvasToolbar {
Merge Fields - + +
+
No merge fields defined
@@ -260,6 +276,8 @@ export class CanvasToolbar { this.variablesList = this.container.querySelector("[data-variables-list]"); this.variablesEmpty = this.container.querySelector("[data-variables-empty]"); + this.variablesAddForm = this.container.querySelector("[data-variables-add-form]"); + this.variablesAddInput = this.container.querySelector("[data-variables-add-input]"); this.resolutionLabel = this.container.querySelector("[data-resolution-label]"); this.fpsLabel = this.container.querySelector("[data-fps-label]"); @@ -309,8 +327,28 @@ export class CanvasToolbar { // Variables - Add button this.variablesPopup?.querySelector('[data-action="add-variable"]')?.addEventListener("click", e => { e.stopPropagation(); - this.addVariable(); + this.showAddVariableForm(); + }); + this.variablesPopup?.querySelector('[data-action="confirm-add-variable"]')?.addEventListener("click", e => { + e.stopPropagation(); + this.commitAddVariable(); + }); + this.variablesPopup?.querySelector('[data-action="cancel-add-variable"]')?.addEventListener("click", e => { + e.stopPropagation(); + this.cancelAddVariable(); }); + this.variablesAddInput?.addEventListener("keydown", e => { + e.stopPropagation(); + if (e.isComposing) return; + if (e.key === "Enter") { + e.preventDefault(); + this.commitAddVariable(); + } else if (e.key === "Escape") { + e.preventDefault(); + this.cancelAddVariable(); + } + }); + this.variablesAddInput?.addEventListener("click", e => e.stopPropagation()); // Resolution preset clicks this.resolutionPopup?.querySelectorAll("[data-width]").forEach(item => { @@ -590,17 +628,48 @@ export class CanvasToolbar { }); } - private addVariable(): void { + private showAddVariableForm(): void { + if (!this.variablesAddForm || !this.variablesAddInput) return; + + this.variablesAddForm.hidden = false; + if (this.variablesEmpty) { + this.variablesEmpty.style.display = "none"; + } + this.variablesAddInput.value = ""; + this.variablesAddInput.focus(); + this.variablesAddInput.select(); + } + + /** Dismiss the add-variable form without registering a field. */ + private cancelAddVariable(): void { + if (!this.variablesAddForm || !this.variablesAddInput) return; + + this.variablesAddInput.value = ""; + this.variablesAddForm.hidden = true; + // Restore empty-state visibility from current field list + this.renderVariablesList(); + this.variablesPopup?.querySelector('[data-action="add-variable"]')?.focus(); + } + + /** Register a new merge field from the in-app form; empty/whitespace is a no-op. */ + private commitAddVariable(): void { const ssEdit = this.getShotstackEdit(); - if (!ssEdit) return; + if (!ssEdit || !this.variablesAddInput) return; - // eslint-disable-next-line no-alert -- Intentional use of prompt for quick variable name input - const name = prompt("Variable name:"); - if (!name || !name.trim()) return; + const name = this.variablesAddInput.value; + if (!name || !name.trim()) { + this.cancelAddVariable(); + return; + } const sanitizedName = name.trim().toUpperCase().replace(/\s+/g, "_"); ssEdit.mergeFields.register({ name: sanitizedName, defaultValue: "" }); + this.variablesAddInput.value = ""; + if (this.variablesAddForm) { + this.variablesAddForm.hidden = true; + } this.renderVariablesList(); + this.variablesPopup?.querySelector('[data-action="add-variable"]')?.focus(); } setResolution(width: number, height: number): void { diff --git a/src/styles/ui/canvas-toolbar.css b/src/styles/ui/canvas-toolbar.css index 8d80a629..d974ccf0 100644 --- a/src/styles/ui/canvas-toolbar.css +++ b/src/styles/ui/canvas-toolbar.css @@ -391,6 +391,55 @@ color: rgba(0, 0, 0, 0.8); } +/* Add-variable form */ +.ss-variables-add-form { + flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 8px; + padding: 4px 8px 8px; +} + +.ss-variables-add-form[hidden] { + display: none; +} + +.ss-variables-add-actions { + display: flex; + gap: 6px; + justify-content: flex-end; +} + +.ss-variables-add-confirm, +.ss-variables-add-cancel { + padding: 6px 10px; + border: none; + border-radius: 8px; + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: background 0.15s ease, color 0.15s ease; +} + +.ss-variables-add-confirm { + background: rgba(99, 102, 241, 0.12); + color: rgba(79, 70, 229, 0.95); +} + +.ss-variables-add-confirm:hover { + background: rgba(99, 102, 241, 0.2); +} + +.ss-variables-add-cancel { + background: rgba(0, 0, 0, 0.05); + color: rgba(0, 0, 0, 0.55); +} + +.ss-variables-add-cancel:hover { + background: rgba(0, 0, 0, 0.1); + color: rgba(0, 0, 0, 0.8); +} + /* THE scroll container - single source of scroll */ .ss-variables-list { flex: 1 1 auto;