feat(frontand/buttons): move multiselect into buttons = keep visible card/list selector

This commit is contained in:
Edouard Vanbelle
2026-04-15 22:17:13 +02:00
parent b1827c9f3d
commit 33165c6d5a
7 changed files with 66 additions and 136 deletions
-10
View File
@@ -37,15 +37,11 @@
.batch-selection-bar {
display: flex;
align-items: center;
justify-content: space-between;
background: var(--color-multiselect-bg);
color: var(--color-multiselect-text);
padding: 10px 20px;
border-radius: 12px;
margin: 0 0 12px;
height: 60px;
overflow: hidden;
transform: translateY(-8px);
transition:
opacity 0.2s,
max-height 0.25s,
@@ -55,12 +51,6 @@
pointer-events: auto;
}
.batch-bar-left {
display: flex;
align-items: center;
gap: 12px;
}
.batch-bar-close {
background: none;
border: none;
+1
View File
@@ -49,6 +49,7 @@
.action-buttons {
display: flex;
flex: auto;
gap: 12px;
}
+1 -36
View File
@@ -214,42 +214,7 @@
<h1 class="page-title" data-i18n="nav.files">Files</h1>
<div class="page-sticky-header" id="page-sticky-header">
<div class="actions-bar" id="actions-bar">
<div class="action-buttons" id="action-buttons">
<div class="upload-dropdown" id="upload-dropdown">
<button class="btn btn-primary" id="upload-btn">
<i class="fas fa-cloud-upload-alt"></i>
<span data-i18n="actions.upload">Upload</span>
<i class="fas fa-caret-down upload-caret"></i>
</button>
<div class="upload-dropdown-menu" id="upload-dropdown-menu">
<button class="upload-dropdown-item" id="upload-files-btn">
<i class="fas fa-file"></i>
<span data-i18n="actions.upload_files">Upload files</span>
</button>
<button class="upload-dropdown-item" id="upload-folder-btn">
<i class="fas fa-folder-open"></i>
<span data-i18n="actions.upload_folder">Upload folder</span>
</button>
</div>
</div>
<button class="btn btn-secondary" id="new-folder-btn">
<i class="fas fa-folder-plus"></i>
<span data-i18n="actions.new_folder">New folder</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
</div>
<div id="batch-selection-bar" class="batch-selection-bar hidden"></div>
<div class="actions-bar" id="actions-bar"><!-- content will be set up by JS --></div>
<div class="breadcrumb">
<span class="breadcrumb-item" data-i18n="breadcrumb.home">Home</span>
+1
View File
@@ -107,6 +107,7 @@ async function rebuildBreadCrumb() {
app.currentFolderInfo = currentFolderInfo;
}
// TODO split load() vs view()
/**
* Files view loading logic
*
+53 -36
View File
@@ -38,9 +38,51 @@ let uploadDropdownDocumentClickHandler = null;
let uploadDropdownBindingsController = null;
let actionsBarDelegationBound = false;
const _multiSelectButons = `
<div class="action-buttons batch-selection-bar hidden" id="multi-select-buttons">
<div class="list-header-checkbox">
<button class="batch-bar-close" id="batch-selection-close" title="Cancel selection">
<i class="fas fa-times"></i>
</button>
<span class="batch-bar-count" id="batch-bar-count"></span>
</div>
<div class="batch-selection-info">
<div class="batch-bar-actions">
<button class="batch-btn" id="batch-fav" title="Add to favorites" data-i18n-title="batch.add_favorites">
<i class="fas fa-star"></i>
<span data-i18n="batch.add_favorites">Add to favorites</span>
</button>
<button class="batch-btn" id="batch-move" title="Move or copy" data-i18n-title="batch.move_copy">
<i class="fas fa-arrows-alt"></i>
<span data-i18n="batch.move_copy">Move or copy</span>
</button>
<button class="batch-btn" id="batch-download" title="Download" data-i18n-title="actions.download">
<i class="fas fa-download"></i>
<span data-i18n="actions.download">Download</span>
</button>
<button class="batch-btn batch-btn-danger" id="batch-delete" title="Delete" data-i18-title="actions.delete">
<i class="fas fa-trash-alt"></i>
<span data-i18n="actions.delete">Delete</span>
</button>
</div>
</div>
</div>
`;
const _toggleButtons = `
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
`;
const ACTIONS_BAR_TEMPLATES = {
files: `
<div class="action-buttons">
<div class="action-buttons" id="default-buttons">
<div class="upload-dropdown" id="upload-dropdown">
<button class="btn btn-primary" id="upload-btn">
<i class="fas fa-cloud-upload-alt icon-mr"></i>
@@ -63,57 +105,32 @@ const ACTIONS_BAR_TEMPLATES = {
<span data-i18n="actions.new_folder">New folder</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
${_multiSelectButons}
${_toggleButtons}
`,
trash: `
<div class="action-buttons">
<div class="action-buttons" id="default-buttons">
<button class="btn btn-danger" id="empty-trash-btn">
<i class="fas fa-trash-alt"></i>
<span data-i18n="trash.empty_trash">Empty trash</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
${_toggleButtons}
`,
favorites: `
<div class="action-buttons"></div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
<div class="action-buttons" id="default-buttons"></div>
${_multiSelectButons}
${_toggleButtons}
`,
recent: `
<div class="action-buttons">
<div class="action-buttons" id="default-buttons">
<button class="btn btn-secondary" id="clear-recent-btn">
<i class="fas fa-broom icon-mr"></i>
<span data-i18n="actions.clear_recent">Clear recent</span>
</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" id="grid-view-btn" title="Grid view">
<i class="fas fa-th"></i>
</button>
<button class="toggle-btn" id="list-view-btn" title="List view">
<i class="fas fa-list"></i>
</button>
</div>
${_multiSelectButons}
${_toggleButtons}
`
};
+3
View File
@@ -1309,6 +1309,9 @@ const ui = {
filesList.classList.remove('hidden');
filesContainerError?.classList.add('hidden');
// apply hook as header changed
multiSelect.init();
},
showEmptyList() {
+7 -54
View File
@@ -230,51 +230,12 @@ const multiSelect = {
this._syncSelectAllCheckbox();
},
// ── Selection bar (replaces list-header when items selected) ────
/**
* Build the inner HTML for the selection bar that replaces the
* normal list-header columns (Name / Type / Size / Modified).
*/
_buildSelectionBarHTML() {
//FIXME: should support i18n lang change
return `
<div x-class="batch-bar-left" class="list-header-checkbox">
<button class="batch-bar-close" id="batch-grid-close" title="Cancel selection">
<i class="fas fa-times"></i>
</button>
<span class="batch-bar-count" id="batch-bar-count"></span>
</div>
<div class="batch-selection-info">
<div class="batch-bar-actions">
<button class="batch-btn" id="batch-fav" title="Add to favorites" data-i18n-title="batch.add_favorites">
<i class="fas fa-star"></i>
<span data-i18n="batch.add_favorites">Add to favorites</span>
</button>
<button class="batch-btn" id="batch-move" title="Move or copy" data-i18n-title="batch.move_copy">
<i class="fas fa-arrows-alt"></i>
<span data-i18n="batch.move_copy">Move or copy</span>
</button>
<button class="batch-btn" id="batch-download" title="Download" data-i18n-title="actions.download">
<i class="fas fa-download"></i>
<span data-i18n="actions.download">Download</span>
</button>
<button class="batch-btn batch-btn-danger" id="batch-delete" title="Delete" data-i18-title="actions.delete">
<i class="fas fa-trash-alt"></i>
<span data-i18n="actions.delete">Delete</span>
</button>
</div>
</div>
`;
},
/** Main UI sync — called after every selection change */
_syncUI() {
const n = this._selected.size;
const batchSelectionBar = document.getElementById('batch-selection-bar');
const actionsBar = document.getElementById('actions-bar');
const multiSelectButtons = document.getElementById('multi-select-buttons');
const defaultButtons = document.getElementById('default-buttons');
if (n > 0) {
this._barVisible = true;
@@ -282,16 +243,14 @@ const multiSelect = {
const countText = n === 1 ? this._t('batch.one_selected') || '1 item selected' : this._t('batch.n_selected', { count: n }) || `${n} items selected`;
document.getElementById('batch-bar-count').innerText = countText;
actionsBar.classList.add('hidden');
batchSelectionBar.classList.remove('hidden');
defaultButtons?.classList.add('hidden');
multiSelectButtons?.classList.remove('hidden');
} else {
this._barVisible = false;
// Hide grid bar
batchSelectionBar.classList.add('hidden');
if (actionsBar.dataset.mode !== 'hidden') actionsBar.classList.remove('hidden');
multiSelectButtons?.classList.add('hidden');
defaultButtons?.classList.remove('hidden');
}
// Sync individual item checkboxes
@@ -306,7 +265,7 @@ const multiSelect = {
const move = document.getElementById('batch-move');
const dl = document.getElementById('batch-download');
const fav = document.getElementById('batch-fav');
const closeBtn = document.getElementById('batch-grid-close');
const closeBtn = document.getElementById('batch-selection-close');
if (del) del.onclick = () => this.batchDelete();
if (move) move.onclick = () => this.batchMove();
if (dl) dl.onclick = () => this.batchDownload();
@@ -515,12 +474,6 @@ const multiSelect = {
if (e.key === 'Delete' && this.hasSelection) this.batchDelete();
});
const batchSelectionBar = document.getElementById('batch-selection-bar');
batchSelectionBar.innerHTML = this._buildSelectionBarHTML();
if (i18n?.translateElement) {
i18n.translateElement(batchSelectionBar);
}
this._wireBarButtons();
},