diff --git a/src/gui/src/UI/Dashboard/ContextMenu/ContextMenu.js b/src/gui/src/UI/Dashboard/ContextMenu/ContextMenu.js index fc12e720e..7f2ff167a 100644 --- a/src/gui/src/UI/Dashboard/ContextMenu/ContextMenu.js +++ b/src/gui/src/UI/Dashboard/ContextMenu/ContextMenu.js @@ -182,6 +182,14 @@ export default class ContextMenuModal { }; this.backdrop.addEventListener('click', this.backdropClickHandler); + // Prevent text selection and close on backdrop touch + this.backdrop.addEventListener('touchstart', (e) => { + if ( e.target === this.backdrop ) { + e.preventDefault(); + this.close(); + } + }, { passive: false }); + // Handle menu item clicks this.itemClickHandler = (e) => { if ( this.ignoreInteractions ) return; diff --git a/src/gui/src/UI/Dashboard/TabFiles.js b/src/gui/src/UI/Dashboard/TabFiles.js index 42a2781b8..f672ebe59 100644 --- a/src/gui/src/UI/Dashboard/TabFiles.js +++ b/src/gui/src/UI/Dashboard/TabFiles.js @@ -238,10 +238,18 @@ const TabFiles = { $(folderElement).addClass('context-menu-active'); const folderPath = folderElement.getAttribute('data-path'); const items = _this.generateFolderContextMenu(folderPath); - const menu = UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); - menu.onClose = () => { - $(folderElement).removeClass('context-menu-active'); - }; + + if ( window.isMobile.phone || window.isMobile.tablet ) { + const modal = new ContextMenuModal({ + onClose: () => $(folderElement).removeClass('context-menu-active'), + }); + modal.show(items, folderElement.getBoundingClientRect()); + } else { + const menu = UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); + menu.onClose = () => { + $(folderElement).removeClass('context-menu-active'); + }; + } }); // Make sidebar folders droppable @@ -448,7 +456,12 @@ const TabFiles = { }); _this.updateFooterStats(); const items = await _this.generateFolderContextMenu(); - UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); + if ( window.isMobile.phone || window.isMobile.tablet ) { + const modal = new ContextMenuModal(); + modal.show(items, e.target.getBoundingClientRect()); + } else { + UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); + } } }); @@ -1768,7 +1781,7 @@ const TabFiles = { const readdirArg = isPath ? { path: target, consistency: options.consistency || 'eventual' } : { uid: target, consistency: options.consistency || 'eventual' }; - const directoryContents = await window.puter.fs.readdir(readdirArg); + let directoryContents = await window.puter.fs.readdir(readdirArg); if ( ! directoryContents ) { this.hideSpinner(); this.renderingDirectory = false; @@ -1796,6 +1809,13 @@ const TabFiles = { this.updateSidebarSelection(); + // Filter out hidden files/folders and AppData in home directory + directoryContents = directoryContents.filter(file => { + if ( file.name.startsWith('.') ) return false; + if ( file.name === 'AppData' && this.currentPath === window.home_path ) return false; + return true; + }); + const isTrashFolder = this.currentPath === window.trash_path; this.updateActionButtons(isTrashFolder); @@ -2427,11 +2447,17 @@ const TabFiles = { e.stopPropagation(); const selectedRows = document.querySelectorAll('.files-tab .row.selected'); + let items; if ( selectedRows.length > 1 && el_item.classList.contains('selected') ) { - const items = await _this.generateMultiSelectContextMenu(selectedRows); - UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); + items = await _this.generateMultiSelectContextMenu(selectedRows); + } else { + items = await _this.generateContextMenuItems(el_item, file); + } + + if ( window.isMobile.phone || window.isMobile.tablet ) { + const modal = new ContextMenuModal(); + modal.show(items, el_item.getBoundingClientRect()); } else { - const items = await _this.generateContextMenuItems(el_item, file); UIContextMenu({ items: items, position: { left: e.pageX, top: e.pageY } }); } }); diff --git a/src/gui/src/css/dashboard.css b/src/gui/src/css/dashboard.css index 3046db08f..6320b1afd 100644 --- a/src/gui/src/css/dashboard.css +++ b/src/gui/src/css/dashboard.css @@ -517,13 +517,12 @@ body { } .dashboard .path-btn { - opacity: 0.4; + opacity: 0.6; width: 28px; cursor: pointer; border-radius: 5px; padding: 4px; background-color: transparent; - transition: background-color 0.3s ease-in-out; } .dashboard .path-btn:hover { @@ -636,6 +635,7 @@ body { flex-direction: column; padding-bottom: 30px; overflow-y: auto; + touch-action: pan-y; } .dashboard-section-files .row { @@ -647,6 +647,7 @@ body { align-items: center; font-size: 13px; color: var(--dashboard-text); + touch-action: pan-y; margin: 1px 2px; pointer-events: auto; float: unset; @@ -703,7 +704,7 @@ body { white-space: nowrap; overflow: hidden; max-width: unset; - color: currentColor; + color: currentColor !important; text-shadow: none; padding: 0 8px; margin: 0; @@ -2701,6 +2702,8 @@ body { opacity: 0; z-index: 9999999; transition: opacity 200ms ease-in-out; + -webkit-user-select: none; + user-select: none; } .context-menu-modal-backdrop.show {