fix(uxp-panel): Export chooser is a full-panel screen, not a clipped popup

The floating popup anchored to the rail button clipped at the panel edge
(the bottom option was cut off). Replace it with a full-panel screen that
takes over the whole panel: a header with close, and two large option
rows (Conform Timeline -> MAM, Local Export) with icon + description.
Conform still routes to the codec-picker panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Zac Gaetano 2026-05-28 23:57:54 -04:00
parent 3f203f326e
commit dac5213354
3 changed files with 93 additions and 42 deletions

View file

@ -140,10 +140,34 @@
</div><!-- /app -->
</section>
<!-- Export menu (anchored to the rail Export button, positioned in JS) -->
<div id="export-menu" class="menu menu--float hidden" role="menu">
<button id="menu-conform" class="menu-item" role="menuitem">Conform Timeline → MAM</button>
<button id="menu-local-export" class="menu-item" role="menuitem">Local Export</button>
<!-- Full-panel Export screen -->
<div id="export-screen" class="screen hidden">
<div class="screen-header">
<span class="screen-title">Export</span>
<button id="export-screen-close" class="btn btn-icon"></button>
</div>
<div class="screen-body">
<div id="opt-conform" role="button" tabindex="0" class="export-option">
<div class="eo-icon">
<svg width="22" height="22" viewBox="0 0 24 24"><path fill="currentColor" d="M3 17v2h6v-2H3zM3 5v2h10V5H3zm10 16v-2h8v-2h-8v-2h-2v6h2zM7 9v2H3v2h4v2h2V9H7zm14 4v-2H11v2h10zm-6-4h2V7h4V5h-4V3h-2v6z"/></svg>
</div>
<div class="eo-text">
<div class="eo-title">Conform Timeline → MAM</div>
<div class="eo-desc">Render the sequence to a chosen codec and push it to the MAM</div>
</div>
<span class="eo-arrow"></span>
</div>
<div id="opt-local-export" role="button" tabindex="0" class="export-option">
<div class="eo-icon">
<svg width="22" height="22" viewBox="0 0 24 24"><path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
</div>
<div class="eo-text">
<div class="eo-title">Local Export</div>
<div class="eo-desc">Trim the hi-res sources on the MAM, download and relink them in Premiere</div>
</div>
<span class="eo-arrow"></span>
</div>
</div>
</div>
<!-- ── (retired) Push Timeline Slide Panel — kept hidden/unused ──── -->

View file

@ -243,42 +243,18 @@
return projs.length === 1 ? projs[0].id : null;
}
// ── Export menu (single Export button → Conform / Local Export) ───
function _positionFloatMenu(menu, anchorEl) {
menu.classList.remove('hidden');
menu.style.visibility = 'hidden';
const r = anchorEl.getBoundingClientRect();
const m = menu.getBoundingClientRect();
const sx = window.pageXOffset || 0, sy = window.pageYOffset || 0;
const vw = window.innerWidth || document.documentElement.clientWidth || 99999;
const vh = window.innerHeight || document.documentElement.clientHeight || 99999;
let x = r.right + 6; // rail is on the left → open to the right
let y = r.top;
if (x + m.width > vw - 4) x = r.left - m.width - 6; // flip if no room
x = Math.max(4, Math.min(x, vw - m.width - 4));
y = Math.max(4, Math.min(y, vh - m.height - 4));
menu.style.left = (x + sx) + 'px';
menu.style.top = (y + sy) + 'px';
menu.style.visibility = 'visible';
}
// ── Export screen (full-panel chooser → Conform / Local Export) ──
function wireExportMenu() {
const btn = $('export-timeline-btn');
const menu = $('export-menu');
if (!btn || !menu) return;
if (menu.parentNode !== document.body) document.body.appendChild(menu);
let open = false;
const close = () => { open = false; menu.classList.add('hidden'); };
btn.addEventListener('click', (e) => {
e.stopPropagation();
if (open) { close(); return; }
open = true; _positionFloatMenu(menu, btn);
});
document.addEventListener('click', (e) => {
if (open && !menu.contains(e.target) && e.target !== btn && !btn.contains(e.target)) close();
});
$('menu-conform').addEventListener('click', () => { close(); openConformPanel(); });
$('menu-local-export').addEventListener('click', () => { close(); runLocalExport(); });
const btn = $('export-timeline-btn');
if (!btn) return;
const close = () => UI.setHidden('#export-screen', true);
btn.addEventListener('click', () => UI.setHidden('#export-screen', false));
const closeBtn = $('export-screen-close');
if (closeBtn) closeBtn.addEventListener('click', close);
const optConform = $('opt-conform');
if (optConform) optConform.addEventListener('click', () => { close(); openConformPanel(); });
const optLocal = $('opt-local-export');
if (optLocal) optLocal.addEventListener('click', () => { close(); runLocalExport(); });
}
// ── Upload highlighted bin file(s) (or file-picker fallback) ─────

View file

@ -227,9 +227,6 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
padding: 4px;
z-index: 50;
}
/* Floating variant: coordinates are set in JS (rail Export menu), so the
default top/right anchoring is cleared and it sits above everything. */
.menu--float { top: auto; right: auto; min-width: 184px; z-index: 1000; }
.menu-item {
display: block;
width: 100%;
@ -244,6 +241,60 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
}
.menu-item:hover { background: var(--hover-strong); }
/* ── full-panel screen (Export chooser) ─────────────────────────── */
.screen {
position: absolute;
inset: 0;
z-index: 60;
background: var(--bg-base);
display: flex;
flex-direction: column;
}
.screen.hidden { display: none; }
.screen-header {
display: flex;
align-items: center;
padding: 13px 13px 11px;
border-bottom: 1px solid var(--border-faint);
flex-shrink: 0;
}
.screen-title { flex: 1; font: 700 14px/1 var(--font-sans); color: var(--text-1); }
.screen-body {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding: 14px;
display: flex;
flex-direction: column;
gap: 10px;
}
.export-option {
display: flex;
align-items: center;
gap: 13px;
padding: 16px 14px;
background: var(--bg-surface);
border: 1px solid var(--border-faint);
border-radius: 10px;
cursor: pointer;
transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.export-option:hover { border-color: var(--accent-border); background: var(--bg-hover); }
.eo-icon {
width: 42px; height: 42px;
flex-shrink: 0;
border-radius: 10px;
background: var(--accent-subtle);
color: var(--accent-bright);
display: flex;
align-items: center;
justify-content: center;
}
.eo-text { flex: 1 1 auto; min-width: 0; }
.eo-title { font: 600 13px/1.3 var(--font-sans); color: var(--text-1); }
.eo-desc { font: 400 11px/1.4 var(--font-sans); color: var(--text-3); margin-top: 3px; }
.eo-arrow { flex-shrink: 0; color: var(--text-3); font-size: 22px; line-height: 1; }
.workspace { display: flex; flex: 1; min-height: 0; }
/* ── icon rail ──────────────────────────────────────────────────── */