The redesigned UXP panel (left icon rail, compact list-view toggle, hover tooltips, single Export menu) was committed only to redesign/panel-icon-rail and never merged, so main + the website kept serving the old blocky-button build under the same version number (2.2.2). That branch had diverged off an old main and is missing recent worker/HLS/NVENC/import work, so it can't be merged wholesale — cherry-pick just the plugin instead. - services/premiere-plugin-uxp: replace source with the redesigned panel (adds src/tooltip.js; reworks index.html + styles.css + src/*). Verified byte-identical to the build installed on BMG-PC-Edit. - web-ui/public/downloads/dragonflight-mam-2.2.2.ccx: swap the served artifact to the redesigned 34708-byte build (download link unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.6 KiB
JavaScript
78 lines
2.6 KiB
JavaScript
// Hover tooltips — v1
|
|
// Icon-first UI: every actionable control carries a [data-tip] label that
|
|
// surfaces on hover. UXP's CSS engine can't be trusted with
|
|
// `content: attr(data-tip)` on ::after, so we position a single floating
|
|
// bubble with plain DOM + getBoundingClientRect (both well supported).
|
|
|
|
(function () {
|
|
let bubble = null;
|
|
let timer = null;
|
|
|
|
function ensure() {
|
|
if (bubble) return bubble;
|
|
bubble = document.createElement('div');
|
|
bubble.className = 'tip-bubble';
|
|
document.body.appendChild(bubble);
|
|
return bubble;
|
|
}
|
|
|
|
function show(el) {
|
|
const text = el.getAttribute('data-tip');
|
|
if (!text) return;
|
|
const tip = ensure();
|
|
tip.textContent = text;
|
|
tip.style.display = 'block';
|
|
tip.style.opacity = '0';
|
|
|
|
const r = el.getBoundingClientRect();
|
|
const t = tip.getBoundingClientRect();
|
|
// position:absolute on a body-level node is offset from the document
|
|
// origin; add scroll offset (0 in practice, body doesn't scroll) for safety.
|
|
const sx = window.pageXOffset || document.documentElement.scrollLeft || 0;
|
|
const sy = window.pageYOffset || document.documentElement.scrollTop || 0;
|
|
const gap = 7;
|
|
const pos = el.getAttribute('data-tip-pos') || 'down';
|
|
let x, y;
|
|
|
|
if (pos === 'right') {
|
|
x = r.right + gap; y = r.top + (r.height - t.height) / 2;
|
|
} else if (pos === 'up') {
|
|
x = r.left + (r.width - t.width) / 2; y = r.top - t.height - gap;
|
|
} else if (pos === 'up-left') {
|
|
x = r.right - t.width; y = r.top - t.height - gap;
|
|
} else if (pos === 'down-left') {
|
|
x = r.right - t.width; y = r.bottom + gap;
|
|
} else {
|
|
x = r.left + (r.width - t.width) / 2; y = r.bottom + gap;
|
|
}
|
|
|
|
const vw = window.innerWidth || document.documentElement.clientWidth || 99999;
|
|
const vh = window.innerHeight || document.documentElement.clientHeight || 99999;
|
|
x = Math.max(4, Math.min(x, vw - t.width - 4));
|
|
y = Math.max(4, Math.min(y, vh - t.height - 4));
|
|
tip.style.left = (x + sx) + 'px';
|
|
tip.style.top = (y + sy) + 'px';
|
|
tip.style.opacity = '1';
|
|
}
|
|
|
|
function hide() {
|
|
clearTimeout(timer);
|
|
if (bubble) { bubble.style.opacity = '0'; bubble.style.display = 'none'; }
|
|
}
|
|
|
|
function bind(el) {
|
|
el.addEventListener('mouseenter', () => {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(() => show(el), 240);
|
|
});
|
|
el.addEventListener('mouseleave', hide);
|
|
el.addEventListener('click', hide);
|
|
}
|
|
|
|
function init() {
|
|
document.querySelectorAll('[data-tip]').forEach(bind);
|
|
}
|
|
|
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
else init();
|
|
})();
|