From 6a8e4ac2509674ddb2ce02eef1b151a1b9bbdb84 Mon Sep 17 00:00:00 2001 From: Zac Date: Sun, 17 May 2026 22:43:55 -0400 Subject: [PATCH] fix(editor): show loading banner during auto-import so Edit feels responsive Clicking Edit on the preview modal worked, but the user only saw an empty editor for ~25s while the recovery + format-chooser cycle ran and the bridge waited for a stable project. Looked broken. Now: a centered top banner appears the moment the bridge detects ?asset=, reads Loading clip from Z-AMPP MAM, switches to Clip ready in media bin on success, or surfaces the failure. Project-stability gate tightened from 1500ms to 600ms so the import lands sooner. --- services/editor/apps/web/src/mam-bridge.ts | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/services/editor/apps/web/src/mam-bridge.ts b/services/editor/apps/web/src/mam-bridge.ts index 037ca98..eea894c 100644 --- a/services/editor/apps/web/src/mam-bridge.ts +++ b/services/editor/apps/web/src/mam-bridge.ts @@ -64,6 +64,23 @@ export async function pickFromMAM(): Promise { modal.querySelector('[data-close]')?.addEventListener('click', close); } +function showBanner(text: string): void { + let el = document.getElementById('zampp-import-banner'); + if (!el) { + el = document.createElement('div'); + el.id = 'zampp-import-banner'; + el.style.cssText = 'position:fixed;top:14px;left:50%;transform:translateX(-50%);background:rgba(31,58,208,0.95);color:#fff;font:500 13px/1.4 system-ui,sans-serif;padding:10px 18px;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,0.4);z-index:2147483647;display:flex;align-items:center;gap:10px;letter-spacing:0.02em'; + document.body.appendChild(el); + } + el.innerHTML = '' + text; + if (!document.getElementById('zampp-banner-keyframes')) { + const st = document.createElement('style'); st.id = 'zampp-banner-keyframes'; + st.textContent = '@keyframes zamppPulse{0%,100%{opacity:0.4}50%{opacity:1}}'; + document.head.appendChild(st); + } +} +function hideBanner(): void { const el = document.getElementById('zampp-import-banner'); if (el) el.remove(); } + export function initMAMBridge(): void { try { const qs = new URLSearchParams(window.location.search); @@ -72,6 +89,7 @@ export function initMAMBridge(): void { (window as any).__zamppPickFromMAM = pickFromMAM; const assetId = qs.get('asset'); if (!assetId) return; + showBanner('Loading clip from Z-AMPP MAM…'); // Auto-skip the startup chooser so MediaBridge initializes immediately. const clickMatching = (matches: string[]): boolean => { const btns = document.querySelectorAll('button,[role="button"],a'); @@ -101,14 +119,16 @@ export function initMAMBridge(): void { console.error('[mam-bridge] project never loaded'); return; } if (p.id !== lastProjectId) { lastProjectId = p.id; stableSince = Date.now(); setTimeout(() => tryImport(n + 1), 750); return; } - if (Date.now() - stableSince < 1500) { setTimeout(() => tryImport(n + 1), 500); return; } + if (Date.now() - stableSince < 600) { setTimeout(() => tryImport(n + 1), 500); return; } try { await importAsset(assetId); imported = true; console.log('[mam-bridge] imported', assetId, 'into project', p.id); + showBanner('Clip ready in media bin'); + setTimeout(hideBanner, 2500); } catch (e) { if (n < 80) setTimeout(() => tryImport(n + 1), 1000); - else console.error('[mam-bridge] import retries exhausted', e); + else { console.error('[mam-bridge] import retries exhausted', e); showBanner('Could not auto-import clip. Use Add Media instead.'); setTimeout(hideBanner, 6000); } } }; if (document.readyState === 'complete') tryImport();