feat(uxp-panel): fix hover tooltips + add compact list view toggle
Tooltips: the floating .tip-bubble used position:fixed, which UXP's engine does not render reliably, so tooltips never appeared. Switch to position:absolute (body never scrolls, so viewport coords still map), add scroll-offset compensation, and guard against UXP returning 0 for window.innerWidth/innerHeight. List view: add a toolbar toggle (grid vs compact list). List view shows a small 50x28 thumbnail with name/meta and an inline status chip per row, fitting many more clips on screen. Defaults to list, persists via localStorage when the host allows it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3430ef823e
commit
9d8adbbbc1
4 changed files with 77 additions and 5 deletions
|
|
@ -77,6 +77,9 @@
|
||||||
<select id="project-filter" class="filter-select" title="Filter by project">
|
<select id="project-filter" class="filter-select" title="Filter by project">
|
||||||
<option value="all">All Projects</option>
|
<option value="all">All Projects</option>
|
||||||
</select>
|
</select>
|
||||||
|
<div id="view-toggle-btn" role="button" tabindex="0" class="iconbtn iconbtn--sm" data-tip="Grid view" data-tip-pos="down-left" aria-label="Toggle layout">
|
||||||
|
<svg width="15" height="15" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11h5V5H4v6zm0 7h5v-6H4v6zm6 0h5v-6h-5v6zm6 0h5v-6h-5v6zm-6-7h5V5h-5v6zm6-6v6h5V5h-5z"/></svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Active sequence info bar -->
|
<!-- Active sequence info bar -->
|
||||||
|
|
|
||||||
|
|
@ -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 = '<svg width="15" height="15" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11h5V5H4v6zm0 7h5v-6H4v6zm6 0h5v-6h-5v6zm6 0h5v-6h-5v6zm-6-7h5V5h-5v6zm6-6v6h5V5h-5z"/></svg>';
|
||||||
|
const LIST_ICON = '<svg width="15" height="15" viewBox="0 0 24 24"><path fill="currentColor" d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/></svg>';
|
||||||
|
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() {
|
function syncConnectBtn() {
|
||||||
$('connect-btn').disabled = !$('server-url').value.trim() || !$('api-token').value.trim();
|
$('connect-btn').disabled = !$('server-url').value.trim() || !$('api-token').value.trim();
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +119,11 @@
|
||||||
$('tab-library').addEventListener('click', () => Library.switchTab('library'));
|
$('tab-library').addEventListener('click', () => Library.switchTab('library'));
|
||||||
$('tab-growing').addEventListener('click', () => Library.switchTab('growing'));
|
$('tab-growing').addEventListener('click', () => Library.switchTab('growing'));
|
||||||
|
|
||||||
|
const vt = $('view-toggle-btn');
|
||||||
|
if (vt) vt.addEventListener('click', () => {
|
||||||
|
applyViewMode(getViewMode() === 'list' ? 'grid' : 'list');
|
||||||
|
});
|
||||||
|
|
||||||
let searchTimer;
|
let searchTimer;
|
||||||
$('search-input').addEventListener('input', e => {
|
$('search-input').addEventListener('input', e => {
|
||||||
clearTimeout(searchTimer);
|
clearTimeout(searchTimer);
|
||||||
|
|
@ -488,6 +516,7 @@
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
enableDivDisabled();
|
enableDivDisabled();
|
||||||
|
applyViewMode(getViewMode());
|
||||||
wireConnectPane(); wireLibraryPane();
|
wireConnectPane(); wireLibraryPane();
|
||||||
wireExportPanel(); wireConformPanel(); wireRelinkPanel();
|
wireExportPanel(); wireConformPanel(); wireRelinkPanel();
|
||||||
showVersion();
|
showVersion();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
const r = el.getBoundingClientRect();
|
const r = el.getBoundingClientRect();
|
||||||
const t = tip.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 gap = 7;
|
||||||
const pos = el.getAttribute('data-tip-pos') || 'down';
|
const pos = el.getAttribute('data-tip-pos') || 'down';
|
||||||
let x, y;
|
let x, y;
|
||||||
|
|
@ -42,11 +46,12 @@
|
||||||
x = r.left + (r.width - t.width) / 2; y = r.bottom + gap;
|
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));
|
x = Math.max(4, Math.min(x, vw - t.width - 4));
|
||||||
y = Math.max(4, Math.min(y, vh - t.height - 4));
|
y = Math.max(4, Math.min(y, vh - t.height - 4));
|
||||||
tip.style.left = x + 'px';
|
tip.style.left = (x + sx) + 'px';
|
||||||
tip.style.top = y + 'px';
|
tip.style.top = (y + sy) + 'px';
|
||||||
tip.style.opacity = '1';
|
tip.style.opacity = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -454,6 +454,38 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
|
||||||
.status-ready { background: var(--success); color: #06120d; }
|
.status-ready { background: var(--success); color: #06120d; }
|
||||||
.status-error { background: var(--danger); color: #fff; }
|
.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 ────────────────────────────────────────────────── */
|
/* ── action dock ────────────────────────────────────────────────── */
|
||||||
.dock {
|
.dock {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
@ -606,8 +638,11 @@ input[type="search"]::-webkit-search-cancel-button { display: none; }
|
||||||
|
|
||||||
/* ── hover tooltip bubble (driven by src/tooltip.js) ────────────── */
|
/* ── hover tooltip bubble (driven by src/tooltip.js) ────────────── */
|
||||||
.tip-bubble {
|
.tip-bubble {
|
||||||
position: fixed;
|
/* UXP's engine does not reliably support position:fixed; absolute on a
|
||||||
z-index: 100;
|
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;
|
display: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue