Merge pull request #238 from EdouardVanbelle/feat/drag-n-drop-in-breadcrumb

feat: drag 'n drop into the breadcrumb
This commit is contained in:
Dionisio Pozo
2026-03-25 18:18:57 +01:00
committed by GitHub
2 changed files with 73 additions and 35 deletions
+6
View File
@@ -12,6 +12,7 @@
.breadcrumb-item { .breadcrumb-item {
padding: 2px 4px; padding: 2px 4px;
border-radius: 4px; border-radius: 4px;
border: 2px solid transparent;
transition: background 0.15s, color 0.15s; transition: background 0.15s, color 0.15s;
} }
@@ -20,6 +21,11 @@
color: #5a6f8a; color: #5a6f8a;
} }
.breadcrumb-link.drop-target {
background-color: rgba(255, 193, 7, 0.1);
border: 2px dashed #ffc107;
}
.breadcrumb-link:hover { .breadcrumb-link:hover {
text-decoration: underline; text-decoration: underline;
color: #ff5e3a; color: #ff5e3a;
+67 -35
View File
@@ -516,34 +516,15 @@ const ui = {
} }
breadcrumb.appendChild(homeIcon); breadcrumb.appendChild(homeIcon);
// -- Root/Home folder name (if available) -- // -- Root/Home folder name (if available) is always the first element of the breadcrumb --
// TODO clarify the difference between homeIcon & this first element
if (window.app.userHomeFolderName) { if (window.app.userHomeFolderName) {
const separator1 = document.createElement('span'); if (path.length === 0 || path[0].id !== window.app.userHomeFolderId) {
separator1.className = 'breadcrumb-separator'; path.unshift({ name: window.app.userHomeFolderName, id: window.app.userHomeFolderId});
separator1.textContent = '>';
breadcrumb.appendChild(separator1);
const rootFolderItem = document.createElement('span');
rootFolderItem.className = 'breadcrumb-item';
rootFolderItem.textContent = window.app.userHomeFolderName;
// If we're at the home folder level (no deeper navigation), show as current
if (path.length === 0) {
rootFolderItem.classList.add('breadcrumb-current');
} else {
// Otherwise clickable to go back to home
rootFolderItem.classList.add('breadcrumb-link');
rootFolderItem.addEventListener('click', () => {
window.app.breadcrumbPath = [];
window.app.currentPath = window.app.userHomeFolderId;
self.updateBreadcrumb();
window.loadFiles();
});
} }
breadcrumb.appendChild(rootFolderItem);
} }
// -- Intermediate + current segments -- // -- Root/Home + Intermediate + current segments --
path.forEach((segment, index) => { path.forEach((segment, index) => {
const isLast = index === path.length - 1; const isLast = index === path.length - 1;
@@ -557,6 +538,7 @@ const ui = {
const item = document.createElement('span'); const item = document.createElement('span');
item.className = 'breadcrumb-item'; item.className = 'breadcrumb-item';
item.textContent = segment.name; item.textContent = segment.name;
item.dataset.folderId = segment.id;
if (!isLast) { if (!isLast) {
// Intermediate segment: clickable – truncate path to this level // Intermediate segment: clickable – truncate path to this level
@@ -567,6 +549,40 @@ const ui = {
self.updateBreadcrumb(); self.updateBreadcrumb();
window.loadFiles(); window.loadFiles();
}); });
// can drag files on this folder
// dragover – only folders are valid drop targets
item.addEventListener('dragover', (e) => {
const card = e.target.closest("span");
if (!card || !card.dataset.folderId) return;
e.preventDefault();
card.classList.add('drop-target');
});
// dragleave
item.addEventListener('dragleave', (e) => {
console.log( "dragleave ",e );
const card = e.target.closest("span");
if (!card || !card.dataset.folderId) return;
card.classList.remove('drop-target');
});
// drop – only folders accept drops
item.addEventListener('drop', async (e) => {
const card = e.target.closest("span");
if (!card) return;
const targetFolderId = card.dataset.folderId;
if (!targetFolderId) return;
e.preventDefault();
card.classList.remove('drop-target');
const id = e.dataTransfer.getData('text/plain');
const isFolder =
e.dataTransfer.getData('application/oxicloud-folder') === 'true';
await self.move( id, isFolder, targetFolderId);
});
} else { } else {
// Last segment: current location, not clickable // Last segment: current location, not clickable
item.classList.add('breadcrumb-current'); item.classList.add('breadcrumb-current');
@@ -575,6 +591,32 @@ const ui = {
}); });
}, },
// TODO: support multiple elements to move ? (API does)
/**
* proceed to the drag & drop
* @param {string} sourceId to move (can be a uniq object or)
* @param {boolean} sourceIsAFolder
* @param {string} targetFolderId
*/
async move(sourceId, sourceIsAFolder, targetFolderId) {
if (!sourceId) return;
console.log(`request move ${ sourceIsAFolder ? "folder": "file"} ${sourceId} to folder ${targetFolderId}`);
if (sourceIsAFolder) {
if (sourceId === targetFolderId) {
alert("You cannot move a folder to itself");
return;
}
// TODO: handle errors...
await fileOps.moveFolder(sourceId, targetFolderId);
} else {
// TODO: handle errors...
await fileOps.moveFile(sourceId, targetFolderId);
}
},
/** /**
* Check if a file can be previewed in the viewer * Check if a file can be previewed in the viewer
* @param {Object} file - File object with mime_type property * @param {Object} file - File object with mime_type property
@@ -951,17 +993,7 @@ const ui = {
const isFolder = const isFolder =
e.dataTransfer.getData('application/oxicloud-folder') === 'true'; e.dataTransfer.getData('application/oxicloud-folder') === 'true';
if (id) { await self.move( id, isFolder, targetFolderId);
if (isFolder) {
if (id === targetFolderId) {
alert("You cannot move a folder to itself");
return;
}
await fileOps.moveFolder(id, targetFolderId);
} else {
await fileOps.moveFile(id, targetFolderId);
}
}
}); });
} }
}, },