Simplify download folder browser by removing manual path rows and preserving scroll position
- Remove 'Use model root' and 'Use typed folder' manual rows from the folder browser - Remove category badge and folder browser header elements - Add nested scroll element detection for scroll delta handling - Preserve scroll position when re-rendering the folder browser on toggle
This commit is contained in:
@@ -5690,23 +5690,6 @@
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
.mr-folder-browser-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.075);
|
||||
background: rgba(255,255,255,0.025);
|
||||
}
|
||||
.mr-folder-browser-title {
|
||||
color: var(--mr-text);
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.mr-folder-browser-subtitle,
|
||||
.mr-folder-browser-category,
|
||||
.mr-folder-browser-preview-label,
|
||||
.mr-folder-browser-root-path,
|
||||
.mr-folder-browser-count,
|
||||
@@ -5715,16 +5698,6 @@
|
||||
font-size: 10px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.mr-folder-browser-category {
|
||||
max-width: 160px;
|
||||
padding: 3px 7px;
|
||||
border: 1px solid rgba(255,255,255,0.09);
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.035);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.mr-folder-browser-preview {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
@@ -5750,8 +5723,7 @@
|
||||
.mr-folder-browser-root + .mr-folder-browser-root {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.mr-folder-browser-root-head,
|
||||
.mr-folder-browser-manual {
|
||||
.mr-folder-browser-root-head {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
color: var(--mr-text);
|
||||
@@ -5767,7 +5739,6 @@
|
||||
padding: 6px 8px;
|
||||
}
|
||||
.mr-folder-browser-root-head:hover,
|
||||
.mr-folder-browser-manual:hover,
|
||||
.mr-folder-browser-row:hover {
|
||||
background: rgba(114,211,138,0.095);
|
||||
}
|
||||
@@ -5874,22 +5845,6 @@
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.045);
|
||||
}
|
||||
.mr-folder-browser-manual {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
}
|
||||
.mr-folder-browser-manual-title {
|
||||
color: var(--mr-text);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.mr-folder-browser-manual-path {
|
||||
color: var(--mr-text-muted);
|
||||
font-size: 10px;
|
||||
word-break: break-all;
|
||||
}
|
||||
.mr-folder-browser-empty {
|
||||
padding: 24px 12px;
|
||||
color: var(--mr-text-muted);
|
||||
|
||||
@@ -1492,20 +1492,25 @@ export const downloadTargetMethods = {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const nestedScrollEl = event.target?.closest?.('.mr-folder-browser-scroll');
|
||||
const targetScrollEl = nestedScrollEl && scrollEl.contains(nestedScrollEl)
|
||||
? nestedScrollEl
|
||||
: scrollEl;
|
||||
|
||||
const maxScrollTop = Math.max(0, scrollEl.scrollHeight - scrollEl.clientHeight);
|
||||
const maxScrollTop = Math.max(0, targetScrollEl.scrollHeight - targetScrollEl.clientHeight);
|
||||
if (maxScrollTop <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const nextScrollTop = Math.min(
|
||||
maxScrollTop,
|
||||
Math.max(0, scrollEl.scrollTop + deltaY)
|
||||
Math.max(0, targetScrollEl.scrollTop + deltaY)
|
||||
);
|
||||
|
||||
scrollEl.scrollTop = nextScrollTop;
|
||||
targetScrollEl.scrollTop = nextScrollTop;
|
||||
}, { passive: false });
|
||||
},
|
||||
|
||||
@@ -1760,7 +1765,11 @@ export const downloadTargetMethods = {
|
||||
.join('');
|
||||
};
|
||||
|
||||
const renderDownloadFolderBrowser = (targetEl, folders, filterText, onSelect) => {
|
||||
const renderDownloadFolderBrowser = (targetEl, folders, filterText, onSelect, options = {}) => {
|
||||
const previousScrollEl = options.preserveScroll
|
||||
? targetEl.querySelector('.mr-folder-browser-scroll')
|
||||
: null;
|
||||
const previousScrollTop = previousScrollEl ? previousScrollEl.scrollTop : 0;
|
||||
const rawFilter = String(filterText || '').trim();
|
||||
const filter = rawFilter.toLowerCase();
|
||||
const normalizedFilter = filter.replace(/[\/]+/g, '\\');
|
||||
@@ -1807,22 +1816,6 @@ export const downloadTargetMethods = {
|
||||
|| selectedValue
|
||||
|| this.getDownloadTargetBaseDirectory(category)
|
||||
|| '';
|
||||
const hasExactTypedMatch = rawFilter
|
||||
? folderEntries.some(entry => entry.value.toLowerCase() === normalizeSubfolderPath(rawFilter).toLowerCase())
|
||||
: true;
|
||||
const typedPath = normalizeSubfolderPath(rawFilter);
|
||||
const clearRow = selectedValue
|
||||
? `<button class="mr-folder-browser-manual" type="button" data-browser-action="select" data-value="" data-base-directory="">
|
||||
<span class="mr-folder-browser-manual-title">Use model root</span>
|
||||
<span class="mr-folder-browser-manual-path">${this.escapeHtml(this.getDownloadTargetBaseDirectory(category) || 'Category root')}</span>
|
||||
</button>`
|
||||
: '';
|
||||
const manualRow = typedPath && !hasExactTypedMatch
|
||||
? `<button class="mr-folder-browser-manual" type="button" data-browser-action="select" data-value="${encodeURIComponent(typedPath)}" data-base-directory="">
|
||||
<span class="mr-folder-browser-manual-title">Use typed folder</span>
|
||||
<span class="mr-folder-browser-manual-path">${this.escapeHtml(typedPath)}</span>
|
||||
</button>`
|
||||
: '';
|
||||
const rootHtml = rootGroups.map(group => {
|
||||
const tree = buildFolderTree(group.entries);
|
||||
const stateKey = `root:${group.key}`;
|
||||
@@ -1854,24 +1847,25 @@ export const downloadTargetMethods = {
|
||||
|
||||
targetEl.classList.add('mr-download-folder-browser');
|
||||
targetEl.innerHTML = `
|
||||
<div class="mr-folder-browser-head">
|
||||
<div>
|
||||
<div class="mr-folder-browser-title">Browse folders</div>
|
||||
<div class="mr-folder-browser-subtitle">${filteredEntries.length} of ${folderEntries.length} folders</div>
|
||||
</div>
|
||||
<div class="mr-folder-browser-category">${this.escapeHtml(this.getCategoryDisplayName(category))}</div>
|
||||
</div>
|
||||
<div class="mr-folder-browser-preview">
|
||||
<span class="mr-folder-browser-preview-label">Target folder path</span>
|
||||
<span class="mr-folder-browser-preview-path">${this.escapeHtml(previewPath)}</span>
|
||||
</div>
|
||||
${clearRow}
|
||||
${manualRow}
|
||||
<div class="mr-folder-browser-scroll">
|
||||
${rootHtml || `<div class="mr-folder-browser-empty">No folders match this filter.</div>`}
|
||||
</div>
|
||||
`;
|
||||
showFloatingSubfolderList();
|
||||
if (options.preserveScroll) {
|
||||
const restoreScrollPosition = () => {
|
||||
const scrollEl = targetEl.querySelector('.mr-folder-browser-scroll');
|
||||
if (!scrollEl) return;
|
||||
const maxScrollTop = Math.max(0, scrollEl.scrollHeight - scrollEl.clientHeight);
|
||||
scrollEl.scrollTop = Math.min(previousScrollTop, maxScrollTop);
|
||||
};
|
||||
restoreScrollPosition();
|
||||
requestAnimationFrame(restoreScrollPosition);
|
||||
}
|
||||
|
||||
targetEl.querySelectorAll('[data-browser-action="toggle"]').forEach(button => {
|
||||
button.addEventListener('mousedown', (event) => {
|
||||
@@ -1884,7 +1878,9 @@ export const downloadTargetMethods = {
|
||||
} else {
|
||||
expandedSet.add(stateKey);
|
||||
}
|
||||
renderDownloadFolderBrowser(targetEl, folders, filterText, onSelect);
|
||||
renderDownloadFolderBrowser(targetEl, folders, filterText, onSelect, {
|
||||
preserveScroll: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user