diff --git a/services/premiere-plugin-uxp/index.html b/services/premiere-plugin-uxp/index.html index ee19824..3601298 100644 --- a/services/premiere-plugin-uxp/index.html +++ b/services/premiere-plugin-uxp/index.html @@ -77,6 +77,9 @@ +
+ +
diff --git a/services/premiere-plugin-uxp/src/main.js b/services/premiere-plugin-uxp/src/main.js index 46d980d..71862bf 100644 --- a/services/premiere-plugin-uxp/src/main.js +++ b/services/premiere-plugin-uxp/src/main.js @@ -28,6 +28,29 @@ }); } + // Asset layout toggle: compact list (default) vs thumbnail grid. Persisted + // in localStorage when available (UXP host permitting), else session-only. + const GRID_ICON = ''; + const LIST_ICON = ''; + let _viewMode = null; + function getViewMode() { + if (_viewMode) return _viewMode; + try { _viewMode = localStorage.getItem('df_view_mode'); } catch (e) {} + return _viewMode || 'list'; + } + function applyViewMode(mode) { + _viewMode = mode === 'grid' ? 'grid' : 'list'; + try { localStorage.setItem('df_view_mode', _viewMode); } catch (e) {} + const isList = _viewMode === 'list'; + document.querySelectorAll('.asset-grid').forEach(g => g.classList.toggle('list-view', isList)); + const btn = $('view-toggle-btn'); + if (btn) { + // Show the icon for the layout a click switches TO. + btn.innerHTML = isList ? GRID_ICON : LIST_ICON; + btn.setAttribute('data-tip', isList ? 'Grid view' : 'List view'); + } + } + function syncConnectBtn() { $('connect-btn').disabled = !$('server-url').value.trim() || !$('api-token').value.trim(); } @@ -96,6 +119,11 @@ $('tab-library').addEventListener('click', () => Library.switchTab('library')); $('tab-growing').addEventListener('click', () => Library.switchTab('growing')); + const vt = $('view-toggle-btn'); + if (vt) vt.addEventListener('click', () => { + applyViewMode(getViewMode() === 'list' ? 'grid' : 'list'); + }); + let searchTimer; $('search-input').addEventListener('input', e => { clearTimeout(searchTimer); @@ -488,6 +516,7 @@ function init() { enableDivDisabled(); + applyViewMode(getViewMode()); wireConnectPane(); wireLibraryPane(); wireExportPanel(); wireConformPanel(); wireRelinkPanel(); showVersion(); diff --git a/services/premiere-plugin-uxp/src/tooltip.js b/services/premiere-plugin-uxp/src/tooltip.js index da66091..c198797 100644 --- a/services/premiere-plugin-uxp/src/tooltip.js +++ b/services/premiere-plugin-uxp/src/tooltip.js @@ -26,6 +26,10 @@ 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; @@ -42,11 +46,12 @@ x = r.left + (r.width - t.width) / 2; y = r.bottom + gap; } - const vw = window.innerWidth, vh = window.innerHeight; + 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 + 'px'; - tip.style.top = y + 'px'; + tip.style.left = (x + sx) + 'px'; + tip.style.top = (y + sy) + 'px'; tip.style.opacity = '1'; } diff --git a/services/premiere-plugin-uxp/styles.css b/services/premiere-plugin-uxp/styles.css index ce4ecf1..43b3a2a 100644 --- a/services/premiere-plugin-uxp/styles.css +++ b/services/premiere-plugin-uxp/styles.css @@ -454,6 +454,38 @@ input[type="search"]::-webkit-search-cancel-button { display: none; } .status-ready { background: var(--success); color: #06120d; } .status-error { background: var(--danger); color: #fff; } +/* ── compact list view (toolbar toggle) ─────────────────────────── */ +.asset-grid.list-view { gap: 2px; padding: 6px 8px; } +.asset-grid.list-view .asset-card { + flex: 1 1 100%; + max-width: 100%; + flex-direction: row; + align-items: center; + gap: 9px; + padding: 3px 8px 3px 3px; + border-radius: 6px; +} +.asset-grid.list-view .asset-thumb, +.asset-grid.list-view .asset-thumb-placeholder { + width: 50px; + height: 28px; + border-radius: 4px; +} +.asset-grid.list-view .asset-thumb-placeholder { font-size: 0; } +.asset-grid.list-view .asset-info { + order: 1; + flex: 1 1 auto; + min-width: 0; + padding: 0; + gap: 1px; +} +.asset-grid.list-view .asset-status { + order: 2; + position: static; + margin-left: auto; + flex-shrink: 0; +} + /* ── action dock ────────────────────────────────────────────────── */ .dock { flex-shrink: 0; @@ -606,8 +638,11 @@ input[type="search"]::-webkit-search-cancel-button { display: none; } /* ── hover tooltip bubble (driven by src/tooltip.js) ────────────── */ .tip-bubble { - position: fixed; - z-index: 100; + /* UXP's engine does not reliably support position:fixed; absolute on a + body-level node maps to the same coords because the panel body never + scrolls (only .asset-grid scrolls internally). */ + position: absolute; + z-index: 1000; display: none; pointer-events: none; white-space: nowrap;