From a8f5a6d3bc929721621e022b8966ebfa4eaf07be Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 27 Mar 2025 03:22:43 -0400 Subject: [PATCH] Double root empty folder fix, side bar drag zone adjusted --- README.md | 20 +- dragAndDrop.js | 669 ++++++++++++++++++++++++----------------------- folderManager.js | 22 +- 3 files changed, 364 insertions(+), 347 deletions(-) diff --git a/README.md b/README.md index 318f86f..10ec74e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ https://github.com/user-attachments/assets/179e6940-5798-4482-9a69-696f806c37de changelogs available here: -FileRise - Multi File Upload Editor is a lightweight, secure, self-hosted web application for uploading, syntax highlight editing, drag & drop and managing files. Built with an Apache/PHP backend and a modern JavaScript (ES6 modules) frontend, it offers a responsive, dynamic file management interface. It serves as an alternative to solutions like FileGator TinyFileManager or ProjectSend, providing an easy-to-setup experience ideal for document management, image galleries, firmware file hosting, and more. +FileRise is a lightweight, secure, self-hosted web application for uploading, syntax-highlight editing, drag & drop file management, and more. Built with an Apache/PHP backend and a modern JavaScript (ES6 modules) frontend, it offers a responsive and dynamic interface designed to simplify file handling. As an alternative to solutions like FileGator, TinyFileManager, or ProjectSend, FileRise provides an easy-to-set-up experience ideal for document management, image galleries, firmware hosting, and other file-intensive applications. --- @@ -49,7 +49,7 @@ FileRise - Multi File Upload Editor is a lightweight, secure, self-hosted web ap - **Move Files:** Move selected files to a different folder, automatically generating a unique filename if needed to avoid data loss. - **Download Files as ZIP:** Download selected files as a ZIP archive. Users can specify a custom name for the ZIP file via a modal dialog. - **Extract Zip:** When one or more ZIP files are selected, users can extract the archive(s) directly into the current folder. - - **Drag & Drop:** Easily move files by selecting them from the file list and simply dragging them onto your desired folder in the folder tree or breadcrumb. When you drop the files onto a folder, the system automatically moves them, updating your file organization in one seamless action. + - **Drag & Drop (File Movement):** Easily move files by selecting them from the file list and dragging them onto your desired folder in the folder tree or breadcrumb. When you drop the files onto a folder, the system automatically moves them, updating your file organization in one seamless action. - **Enhanced Context Menu & Keyboard Shortcuts:** - **Right-Click Context Menu:** - A custom context menu appears on right-clicking within the file list. @@ -126,6 +126,16 @@ FileRise - Multi File Upload Editor is a lightweight, secure, self-hosted web ap - The trash modal displays details such as file name, uploader/deleter, and the trashed date/time. - Material icons with tooltips visually represent the restore and delete actions. +- **Drag & Drop Cards with Dedicated Drop Zones:** + - **Sidebar Drop Zone:** + - Cards (such as the upload card or folder management card) can be dragged into a dedicated sidebar drop zone for quick access to frequently used operations. + - The sidebar drop zone expands dynamically to accept drops anywhere within its visual area. + - **Top Bar Drop Zone:** + - A top drop zone is available for reordering or managing cards quickly. + - Dragging a card to the top drop zone provides immediate visual feedback, ensuring a fluid and customizable workflow. + - **Seamless Interaction:** + - Both drop zones support smooth drag and drop interactions with animations and pointer event adjustments to prevent interference, ensuring that cards can be dropped reliably regardless of screen position. + --- ## Screenshots @@ -214,6 +224,12 @@ For users who prefer containerization, a Docker image is available docker pull error311/filerise-docker:latest ``` + macos M series: + + ```bash + docker pull --platform linux/x86_64 error311/filerise-docker:latest + ``` + 2. **Run the Container:** ```bash diff --git a/dragAndDrop.js b/dragAndDrop.js index a4574b5..2d5c11d 100644 --- a/dragAndDrop.js +++ b/dragAndDrop.js @@ -2,354 +2,363 @@ // Moves cards into the sidebar based on the saved order in localStorage. export function loadSidebarOrder() { - const sidebar = document.getElementById('sidebarDropArea'); - if (!sidebar) return; - const orderStr = localStorage.getItem('sidebarOrder'); - if (orderStr) { - const order = JSON.parse(orderStr); - if (order.length > 0) { - // Ensure main wrapper is visible. - const mainWrapper = document.querySelector('.main-wrapper'); - if (mainWrapper) { - mainWrapper.style.display = 'flex'; - } - // For each saved ID, move the card into the sidebar. - order.forEach(id => { - const card = document.getElementById(id); - if (card && card.parentNode.id !== 'sidebarDropArea') { - sidebar.appendChild(card); - // Animate vertical slide for sidebar card - animateVerticalSlide(card); - } - }); + const sidebar = document.getElementById('sidebarDropArea'); + if (!sidebar) return; + const orderStr = localStorage.getItem('sidebarOrder'); + if (orderStr) { + const order = JSON.parse(orderStr); + if (order.length > 0) { + // Ensure main wrapper is visible. + const mainWrapper = document.querySelector('.main-wrapper'); + if (mainWrapper) { + mainWrapper.style.display = 'flex'; } - } - updateSidebarVisibility(); - } - - // Internal helper: update sidebar visibility based on its content. - function updateSidebarVisibility() { - const sidebar = document.getElementById('sidebarDropArea'); - if (sidebar) { - const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); - if (cards.length > 0) { - sidebar.classList.add('active'); - sidebar.style.display = 'block'; - } else { - sidebar.classList.remove('active'); - sidebar.style.display = 'none'; - } - // Save the current order in localStorage. - saveSidebarOrder(); - } - } - - // Internal helper: update top zone layout (center a card if one column is empty). - function updateTopZoneLayout() { - const leftCol = document.getElementById('leftCol'); - const rightCol = document.getElementById('rightCol'); - - const leftIsEmpty = !leftCol.querySelector('#uploadCard'); - const rightIsEmpty = !rightCol.querySelector('#folderManagementCard'); - - if (leftIsEmpty && !rightIsEmpty) { - leftCol.style.display = 'none'; - rightCol.style.margin = '0 auto'; - } else if (rightIsEmpty && !leftIsEmpty) { - rightCol.style.display = 'none'; - leftCol.style.margin = '0 auto'; - } else { - leftCol.style.display = ''; - rightCol.style.display = ''; - leftCol.style.margin = ''; - rightCol.style.margin = ''; - } - } - - // When a card is being dragged, if the top drop zone is empty, set its min-height. - function addTopZoneHighlight() { - const topZone = document.getElementById('uploadFolderRow'); - if (topZone) { - topZone.classList.add('highlight'); - if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { - topZone.style.minHeight = '375px'; - } - } - } - - // When the drag ends, remove the extra min-height. - function removeTopZoneHighlight() { - const topZone = document.getElementById('uploadFolderRow'); - if (topZone) { - topZone.classList.remove('highlight'); - topZone.style.minHeight = ''; - } - } - - // Vertical slide/fade animation helper. - // It sets an initial vertical offset (30px down) and opacity 0, then animates to normal position and full opacity. - function animateVerticalSlide(card) { - card.style.transform = 'translateY(30px)'; - card.style.opacity = '0'; - // Force reflow. - card.offsetWidth; - requestAnimationFrame(() => { - card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; - card.style.transform = 'translateY(0)'; - card.style.opacity = '1'; - }); - setTimeout(() => { - card.style.transition = ''; - card.style.transform = ''; - card.style.opacity = ''; - }, 310); - } - - // Internal helper: insert card into sidebar at a proper position based on event.clientY. - function insertCardInSidebar(card, event) { - const sidebar = document.getElementById('sidebarDropArea'); - if (!sidebar) return; - const existingCards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); - let inserted = false; - for (const currentCard of existingCards) { - const rect = currentCard.getBoundingClientRect(); - const midY = rect.top + rect.height / 2; - if (event.clientY < midY) { - sidebar.insertBefore(card, currentCard); - inserted = true; - break; - } - } - if (!inserted) { - sidebar.appendChild(card); - } - // Ensure card fills the sidebar. - card.style.width = '100%'; - animateVerticalSlide(card); - } - - // Internal helper: save the current sidebar card order to localStorage. - function saveSidebarOrder() { - const sidebar = document.getElementById('sidebarDropArea'); - if (sidebar) { - const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); - const order = Array.from(cards).map(card => card.id); - localStorage.setItem('sidebarOrder', JSON.stringify(order)); - } - } - - // Helper: move cards from sidebar back to the top drop area when on small screens. - function moveSidebarCardsToTop() { - if (window.innerWidth < 1205) { - const sidebar = document.getElementById('sidebarDropArea'); - if (!sidebar) return; - const cards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); - cards.forEach(card => { - const orig = document.getElementById(card.dataset.originalContainerId); - if (orig) { - orig.appendChild(card); + // For each saved ID, move the card into the sidebar. + order.forEach(id => { + const card = document.getElementById(id); + if (card && card.parentNode.id !== 'sidebarDropArea') { + sidebar.appendChild(card); + // Animate vertical slide for sidebar card animateVerticalSlide(card); } }); - updateSidebarVisibility(); - updateTopZoneLayout(); } } - - // Listen for window resize to automatically move sidebar cards back to top on small screens. - window.addEventListener('resize', function () { - if (window.innerWidth < 1205) { - moveSidebarCardsToTop(); - } - }); - - // This function ensures the top drop zone (#uploadFolderRow) has a stable width when empty. - function ensureTopZonePlaceholder() { - const topZone = document.getElementById('uploadFolderRow'); - if (!topZone) return; - if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { - let placeholder = topZone.querySelector('.placeholder'); - if (!placeholder) { - placeholder = document.createElement('div'); - placeholder.className = 'placeholder'; - placeholder.style.visibility = 'hidden'; - placeholder.style.display = 'block'; - placeholder.style.width = '100%'; - placeholder.style.height = '375px'; - topZone.appendChild(placeholder); - } + updateSidebarVisibility(); +} + +// Internal helper: update sidebar visibility based on its content. +function updateSidebarVisibility() { + const sidebar = document.getElementById('sidebarDropArea'); + if (sidebar) { + const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); + if (cards.length > 0) { + sidebar.classList.add('active'); + sidebar.style.display = 'block'; } else { - const placeholder = topZone.querySelector('.placeholder'); - if (placeholder) placeholder.remove(); + sidebar.classList.remove('active'); + sidebar.style.display = 'none'; + } + // Save the current order in localStorage. + saveSidebarOrder(); + } +} + +// Internal helper: update top zone layout (center a card if one column is empty). +function updateTopZoneLayout() { + const leftCol = document.getElementById('leftCol'); + const rightCol = document.getElementById('rightCol'); + + const leftIsEmpty = !leftCol.querySelector('#uploadCard'); + const rightIsEmpty = !rightCol.querySelector('#folderManagementCard'); + + if (leftIsEmpty && !rightIsEmpty) { + leftCol.style.display = 'none'; + rightCol.style.margin = '0 auto'; + } else if (rightIsEmpty && !leftIsEmpty) { + rightCol.style.display = 'none'; + leftCol.style.margin = '0 auto'; + } else { + leftCol.style.display = ''; + rightCol.style.display = ''; + leftCol.style.margin = ''; + rightCol.style.margin = ''; + } +} + +// When a card is being dragged, if the top drop zone is empty, set its min-height. +function addTopZoneHighlight() { + const topZone = document.getElementById('uploadFolderRow'); + if (topZone) { + topZone.classList.add('highlight'); + if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { + topZone.style.minHeight = '375px'; } } - - // This sets up all drag-and-drop event listeners for cards. - export function initDragAndDrop() { - function run() { - const draggableCards = document.querySelectorAll('#uploadCard, #folderManagementCard'); - draggableCards.forEach(card => { - if (!card.dataset.originalContainerId) { - card.dataset.originalContainerId = card.parentNode.id; - } - const header = card.querySelector('.card-header'); - if (header) { - header.classList.add('drag-header'); - } - - let isDragging = false; - let dragTimer = null; - let offsetX = 0, offsetY = 0; - let initialLeft, initialTop; - - if (header) { - header.addEventListener('mousedown', function (e) { - e.preventDefault(); - const card = this.closest('.card'); - const rect = card.getBoundingClientRect(); - const originX = ((e.clientX - rect.left) / rect.width) * 100; - const originY = ((e.clientY - rect.top) / rect.height) * 100; - card.style.transformOrigin = `${originX}% ${originY}%`; - dragTimer = setTimeout(() => { - isDragging = true; - card.classList.add('dragging'); - addTopZoneHighlight(); - const rect = card.getBoundingClientRect(); - initialLeft = rect.left + window.pageXOffset; - initialTop = rect.top + window.pageYOffset; - offsetX = e.pageX - initialLeft; - offsetY = e.pageY - initialTop; - document.body.appendChild(card); - card.style.position = 'absolute'; - card.style.left = initialLeft + 'px'; - card.style.top = initialTop + 'px'; - card.style.width = rect.width + 'px'; - card.style.zIndex = '10000'; - const sidebar = document.getElementById('sidebarDropArea'); - if (sidebar) { - sidebar.classList.add('active'); - sidebar.style.display = 'block'; - sidebar.classList.add('highlight'); - } - }, 500); - }); - header.addEventListener('mouseup', function () { - clearTimeout(dragTimer); - }); - } - - document.addEventListener('mousemove', function (e) { - if (isDragging) { - card.style.left = (e.pageX - offsetX) + 'px'; - card.style.top = (e.pageY - offsetY) + 'px'; - } - }); - - document.addEventListener('mouseup', function (e) { - if (isDragging) { - isDragging = false; - card.classList.remove('dragging'); - removeTopZoneHighlight(); +} + +// When the drag ends, remove the extra min-height. +function removeTopZoneHighlight() { + const topZone = document.getElementById('uploadFolderRow'); + if (topZone) { + topZone.classList.remove('highlight'); + topZone.style.minHeight = ''; + } +} + +// Vertical slide/fade animation helper. +function animateVerticalSlide(card) { + card.style.transform = 'translateY(30px)'; + card.style.opacity = '0'; + // Force reflow. + card.offsetWidth; + requestAnimationFrame(() => { + card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; + card.style.transform = 'translateY(0)'; + card.style.opacity = '1'; + }); + setTimeout(() => { + card.style.transition = ''; + card.style.transform = ''; + card.style.opacity = ''; + }, 310); +} + +// Internal helper: insert card into sidebar at a proper position based on event.clientY. +function insertCardInSidebar(card, event) { + const sidebar = document.getElementById('sidebarDropArea'); + if (!sidebar) return; + const existingCards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); + let inserted = false; + for (const currentCard of existingCards) { + const rect = currentCard.getBoundingClientRect(); + const midY = rect.top + rect.height / 2; + if (event.clientY < midY) { + sidebar.insertBefore(card, currentCard); + inserted = true; + break; + } + } + if (!inserted) { + sidebar.appendChild(card); + } + // Ensure card fills the sidebar. + card.style.width = '100%'; + animateVerticalSlide(card); +} + +// Internal helper: save the current sidebar card order to localStorage. +function saveSidebarOrder() { + const sidebar = document.getElementById('sidebarDropArea'); + if (sidebar) { + const cards = sidebar.querySelectorAll('#uploadCard, #folderManagementCard'); + const order = Array.from(cards).map(card => card.id); + localStorage.setItem('sidebarOrder', JSON.stringify(order)); + } +} + +// Helper: move cards from sidebar back to the top drop area when on small screens. +function moveSidebarCardsToTop() { + if (window.innerWidth < 1205) { + const sidebar = document.getElementById('sidebarDropArea'); + if (!sidebar) return; + const cards = Array.from(sidebar.querySelectorAll('#uploadCard, #folderManagementCard')); + cards.forEach(card => { + const orig = document.getElementById(card.dataset.originalContainerId); + if (orig) { + orig.appendChild(card); + animateVerticalSlide(card); + } + }); + updateSidebarVisibility(); + updateTopZoneLayout(); + } +} + +// Listen for window resize to automatically move sidebar cards back to top on small screens. +window.addEventListener('resize', function () { + if (window.innerWidth < 1205) { + moveSidebarCardsToTop(); + } +}); + +// This function ensures the top drop zone (#uploadFolderRow) has a stable width when empty. +function ensureTopZonePlaceholder() { + const topZone = document.getElementById('uploadFolderRow'); + if (!topZone) return; + if (topZone.querySelectorAll('#uploadCard, #folderManagementCard').length === 0) { + let placeholder = topZone.querySelector('.placeholder'); + if (!placeholder) { + placeholder = document.createElement('div'); + placeholder.className = 'placeholder'; + placeholder.style.visibility = 'hidden'; + placeholder.style.display = 'block'; + placeholder.style.width = '100%'; + placeholder.style.height = '375px'; + topZone.appendChild(placeholder); + } + } else { + const placeholder = topZone.querySelector('.placeholder'); + if (placeholder) placeholder.remove(); + } +} + +// This sets up all drag-and-drop event listeners for cards. +export function initDragAndDrop() { + function run() { + const draggableCards = document.querySelectorAll('#uploadCard, #folderManagementCard'); + draggableCards.forEach(card => { + if (!card.dataset.originalContainerId) { + card.dataset.originalContainerId = card.parentNode.id; + } + const header = card.querySelector('.card-header'); + if (header) { + header.classList.add('drag-header'); + } + + let isDragging = false; + let dragTimer = null; + let offsetX = 0, offsetY = 0; + let initialLeft, initialTop; + + if (header) { + header.addEventListener('mousedown', function (e) { + e.preventDefault(); + const card = this.closest('.card'); + const rect = card.getBoundingClientRect(); + const originX = ((e.clientX - rect.left) / rect.width) * 100; + const originY = ((e.clientY - rect.top) / rect.height) * 100; + card.style.transformOrigin = `${originX}% ${originY}%`; + dragTimer = setTimeout(() => { + isDragging = true; + card.classList.add('dragging'); + // Disable pointer events on the card so it doesn't block drop detection. + card.style.pointerEvents = 'none'; + addTopZoneHighlight(); const sidebar = document.getElementById('sidebarDropArea'); if (sidebar) { - sidebar.classList.remove('highlight'); + sidebar.classList.add('active'); + sidebar.style.display = 'block'; + sidebar.classList.add('highlight'); + // Force the sidebar to have a tall drop zone while dragging. + sidebar.style.height = '800px'; } - - const leftCol = document.getElementById('leftCol'); - const rightCol = document.getElementById('rightCol'); - let droppedInSidebar = false; - let droppedInTop = false; - - const sidebarElem = document.getElementById('sidebarDropArea'); - if (sidebarElem) { - const rect = sidebarElem.getBoundingClientRect(); - if ( - e.clientX >= rect.left && - e.clientX <= rect.right && - e.clientY >= rect.top && - e.clientY <= rect.bottom - ) { - insertCardInSidebar(card, e); - droppedInSidebar = true; - sidebarElem.blur(); + const rect = card.getBoundingClientRect(); + initialLeft = rect.left + window.pageXOffset; + initialTop = rect.top + window.pageYOffset; + offsetX = e.pageX - initialLeft; + offsetY = e.pageY - initialTop; + document.body.appendChild(card); + card.style.position = 'absolute'; + card.style.left = initialLeft + 'px'; + card.style.top = initialTop + 'px'; + card.style.width = rect.width + 'px'; + card.style.zIndex = '10000'; + }, 500); + }); + header.addEventListener('mouseup', function () { + clearTimeout(dragTimer); + }); + } + + document.addEventListener('mousemove', function (e) { + if (isDragging) { + card.style.left = (e.pageX - offsetX) + 'px'; + card.style.top = (e.pageY - offsetY) + 'px'; + } + }); + + document.addEventListener('mouseup', function (e) { + if (isDragging) { + isDragging = false; + // Re-enable pointer events on the card. + card.style.pointerEvents = ''; + card.classList.remove('dragging'); + removeTopZoneHighlight(); + const sidebar = document.getElementById('sidebarDropArea'); + if (sidebar) { + sidebar.classList.remove('highlight'); + // Remove the forced height once the drag ends. + sidebar.style.height = ''; + } + + const leftCol = document.getElementById('leftCol'); + const rightCol = document.getElementById('rightCol'); + let droppedInSidebar = false; + let droppedInTop = false; + + const sidebarElem = document.getElementById('sidebarDropArea'); + if (sidebarElem) { + // Instead of using elementsFromPoint, use a virtual drop zone. + const rect = sidebarElem.getBoundingClientRect(); + // Define a drop zone from the top of the sidebar to 1000px below its top. + const dropZoneBottom = rect.top + 800; + if ( + e.clientX >= rect.left && + e.clientX <= rect.right && + e.clientY >= rect.top && + e.clientY <= dropZoneBottom + ) { + insertCardInSidebar(card, e); + droppedInSidebar = true; + sidebarElem.blur(); + } + } + + const topRow = document.getElementById('uploadFolderRow'); + if (!droppedInSidebar && topRow) { + const rect = topRow.getBoundingClientRect(); + if ( + e.clientX >= rect.left && + e.clientX <= rect.right && + e.clientY >= rect.top && + e.clientY <= rect.bottom + ) { + let container; + if (card.id === 'uploadCard') { + container = document.getElementById('leftCol'); + } else if (card.id === 'folderManagementCard') { + container = document.getElementById('rightCol'); + } + if (container) { + ensureTopZonePlaceholder(); + container.appendChild(card); + droppedInTop = true; + + container.style.position = 'relative'; + card.style.position = 'absolute'; + card.style.left = '0px'; + + // Animate vertical slide/fade. + card.style.transform = 'translateY(30px)'; + card.style.opacity = '0'; + + card.offsetWidth; // Force reflow. + + requestAnimationFrame(() => { + card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; + card.style.transform = 'translateY(0)'; + card.style.opacity = '1'; + }); + + setTimeout(() => { + card.style.position = ''; + container.style.position = ''; + card.style.transition = ''; + card.style.transform = ''; + card.style.opacity = ''; + card.style.width = ''; + }, 310); } } - - const topRow = document.getElementById('uploadFolderRow'); - if (!droppedInSidebar && topRow) { - const rect = topRow.getBoundingClientRect(); - if ( - e.clientX >= rect.left && - e.clientX <= rect.right && - e.clientY >= rect.top && - e.clientY <= rect.bottom - ) { - let container; - if (card.id === 'uploadCard') { - container = document.getElementById('leftCol'); - } else if (card.id === 'folderManagementCard') { - container = document.getElementById('rightCol'); - } - if (container) { - ensureTopZonePlaceholder(); - container.appendChild(card); - droppedInTop = true; - - container.style.position = 'relative'; - card.style.position = 'absolute'; - card.style.left = '0px'; - - // For top drop, animate vertical slide/fade. - card.style.transform = 'translateY(30px)'; - card.style.opacity = '0'; - - card.offsetWidth; // Force reflow. - - requestAnimationFrame(() => { - card.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; - card.style.transform = 'translateY(0)'; - card.style.opacity = '1'; - }); - - setTimeout(() => { - card.style.position = ''; - container.style.position = ''; - card.style.transition = ''; - card.style.transform = ''; - card.style.opacity = ''; - // Ensure the card returns to full width (via CSS: width: 100%) - card.style.width = ''; - }, 310); - } - } - } - - if (droppedInSidebar || droppedInTop) { + } + + if (droppedInSidebar || droppedInTop) { + card.style.position = ''; + card.style.left = ''; + card.style.top = ''; + card.style.zIndex = ''; + } else { + const orig = document.getElementById(card.dataset.originalContainerId); + if (orig) { + orig.appendChild(card); card.style.position = ''; card.style.left = ''; card.style.top = ''; card.style.zIndex = ''; - } else { - const orig = document.getElementById(card.dataset.originalContainerId); - if (orig) { - orig.appendChild(card); - card.style.position = ''; - card.style.left = ''; - card.style.top = ''; - card.style.zIndex = ''; - card.style.width = ''; - } + card.style.width = ''; } - updateTopZoneLayout(); - updateSidebarVisibility(); } - }); + updateTopZoneLayout(); + updateSidebarVisibility(); + } }); - } - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', run); - } else { - run(); - } - } \ No newline at end of file + }); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', run); + } else { + run(); + } +} \ No newline at end of file diff --git a/folderManager.js b/folderManager.js index 45ad395..f357c56 100644 --- a/folderManager.js +++ b/folderManager.js @@ -63,8 +63,6 @@ function getParentFolder(folder) { // Breadcrumb Functions // ---------------------- // Render breadcrumb for a normalized folder path. -// For example, if window.currentFolder is "Folder1/Folder1SubFolder2", -// this will return: Root / Folder1 / Folder1SubFolder2. function renderBreadcrumb(normalizedFolder) { if (normalizedFolder === "root") { return `Root`; @@ -307,16 +305,10 @@ export async function loadFolderTree(selectedFolder) { } let html = `
- [-] - (Root) -
`; - if (folders.length === 0) { - html += ``; - } else { + [-] + (Root) + `; + if (folders.length > 0) { const tree = buildFolderTree(folders); html += renderFolderTree(tree, "", "block"); } @@ -730,14 +722,14 @@ document.addEventListener("click", function () { hideFolderManagerContextMenu(); }); -document.addEventListener("DOMContentLoaded", function() { - document.addEventListener("keydown", function(e) { +document.addEventListener("DOMContentLoaded", function () { + document.addEventListener("keydown", function (e) { // Skip if the user is typing in an input, textarea, or contentEditable element. const tag = e.target.tagName.toLowerCase(); if (tag === "input" || tag === "textarea" || e.target.isContentEditable) { return; } - + // On macOS, "Delete" is typically reported as "Backspace" (keyCode 8) if (e.key === "Delete" || e.key === "Backspace" || e.keyCode === 46 || e.keyCode === 8) { // Ensure a folder is selected and it isn't the root folder.