mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-05 19:08:18 +00:00
Enhance Zen Tab Reordering: Add drag-and-drop between tab containers (normal tabs, pinned and essentials)
This commit enhances the drag-and-drop functionality in Zen, allowing users to seamlessly reorder tabs between the pinned tabs, essential tabs, and regular tab containers. The changes include: - Added `moveToAnotherTabContainerIfNecessary` and `applyDragoverClass` methods to `ZenPinnedTabManager` to handle tab movement and visual feedback during drag-and-drop. - Updated `tabs.js` to integrate with the new methods, correctly handling tab pinning and unpinning, and essential tab toggling during reordering. - Added CSS classes and styles to visually indicate the drop position (before or after) a target tab during the drag operation. This improves user experience and clarity.
This commit is contained in:
@@ -1069,3 +1069,29 @@
|
||||
%include vertical-tabs-topbuttons-fix.css
|
||||
}
|
||||
}
|
||||
|
||||
#vertical-pinned-tabs-container .tabbrowser-tab,
|
||||
#tabbrowser-arrowscrollbox .tabbrowser-tab,
|
||||
#zen-essentials-container .tabbrowser-tab {
|
||||
transition: box-shadow 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
/* Vertical tabs reordering indicators */
|
||||
#vertical-pinned-tabs-container .tabbrowser-tab.drag-over-before,
|
||||
#tabbrowser-arrowscrollbox .tabbrowser-tab.drag-over-before {
|
||||
box-shadow: 0 3px 6px -2px var(--toolbarbutton-active-background, rgba(0, 0, 255, 0.2));
|
||||
}
|
||||
|
||||
#vertical-pinned-tabs-container .tabbrowser-tab.drag-over-after,
|
||||
#tabbrowser-arrowscrollbox .tabbrowser-tab.drag-over-after {
|
||||
box-shadow: 0 -3px 6px -2px var(--toolbarbutton-active-background, rgba(0, 0, 255, 0.2));
|
||||
}
|
||||
|
||||
/* Horizontal tabs reordering indicators */
|
||||
#zen-essentials-container .tabbrowser-tab.drag-over-before {
|
||||
box-shadow: 3px 0 6px -2px var(--toolbarbutton-active-background, rgba(0, 255, 0, 0.2));
|
||||
}
|
||||
|
||||
#zen-essentials-container .tabbrowser-tab.drag-over-after {
|
||||
box-shadow: -3px 0 6px -2px var(--toolbarbutton-active-background, rgba(0, 255, 0, 0.2));
|
||||
}
|
||||
|
@@ -557,8 +557,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
addToEssentials() {
|
||||
const tabs = TabContextMenu.contextTab.multiselected ? gBrowser.selectedTabs : [TabContextMenu.contextTab];
|
||||
addToEssentials(tab) {
|
||||
const tabs = tab ? [tab] : TabContextMenu.contextTab.multiselected ? gBrowser.selectedTabs : [TabContextMenu.contextTab];
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
const tab = tabs[i];
|
||||
tab.setAttribute('zen-essential', 'true');
|
||||
@@ -575,8 +575,8 @@
|
||||
gZenUIManager.updateTabsToolbar();
|
||||
}
|
||||
|
||||
removeEssentials() {
|
||||
const tabs = TabContextMenu.contextTab.multiselected ? gBrowser.selectedTabs : [TabContextMenu.contextTab];
|
||||
removeEssentials(tab) {
|
||||
const tabs = tab ? [tab] : TabContextMenu.contextTab.multiselected ? gBrowser.selectedTabs : [TabContextMenu.contextTab];
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
const tab = tabs[i];
|
||||
tab.removeAttribute('zen-essential');
|
||||
@@ -640,6 +640,133 @@
|
||||
document.getElementById('context_unpinSelectedTabs').hidden || contextTab.getAttribute('zen-essential');
|
||||
document.getElementById('context_zen-pinned-tab-separator').hidden = !isVisible;
|
||||
}
|
||||
|
||||
moveToAnotherTabContainerIfNecessary(event, draggedTab) {
|
||||
const pinnedTabsTarget = event.target.closest("#vertical-pinned-tabs-container");
|
||||
const essentialTabsTarget = event.target.closest("#zen-essentials-container");
|
||||
const tabsTarget = event.target.closest("#tabbrowser-arrowscrollbox");
|
||||
|
||||
let moved = false;
|
||||
let isVertical = true;
|
||||
|
||||
// Check for pinned tabs container
|
||||
if (pinnedTabsTarget) {
|
||||
if (!draggedTab.pinned) {
|
||||
gBrowser.pinTab(draggedTab);
|
||||
moved = true;
|
||||
} else if (draggedTab.hasAttribute("zen-essential")) {
|
||||
this.removeEssentials(draggedTab);
|
||||
gBrowser.pinTab(draggedTab);
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
// Check for essentials container
|
||||
else if (essentialTabsTarget) {
|
||||
if (!draggedTab.hasAttribute("zen-essential")) {
|
||||
this.addToEssentials(draggedTab);
|
||||
moved = true;
|
||||
isVertical = false;
|
||||
}
|
||||
}
|
||||
// Check for normal tabs container
|
||||
else if (tabsTarget) {
|
||||
if (draggedTab.pinned && !draggedTab.hasAttribute("zen-essential")) {
|
||||
gBrowser.unpinTab(draggedTab);
|
||||
moved = true;
|
||||
} else if (draggedTab.hasAttribute("zen-essential")) {
|
||||
this.removeEssentials(draggedTab);
|
||||
moved = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the tab was moved, adjust its position relative to the target tab
|
||||
if (moved) {
|
||||
const targetTab = event.target.closest(".tabbrowser-tab");
|
||||
if (targetTab) {
|
||||
const rect = targetTab.getBoundingClientRect();
|
||||
let newIndex = targetTab._tPos;
|
||||
|
||||
if (isVertical) {
|
||||
const middleY = targetTab.screenY + rect.height / 2;
|
||||
if (event.screenY > middleY) {
|
||||
newIndex++;
|
||||
}
|
||||
} else {
|
||||
const middleX = targetTab.screenX + rect.width / 2;
|
||||
if (event.screenX > middleX) {
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
gBrowser.moveTabTo(draggedTab, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return moved;
|
||||
}
|
||||
|
||||
removeTabContainersDragoverClass() {
|
||||
document
|
||||
.querySelectorAll(".tabbrowser-tab.drag-over-before, .tabbrowser-tab.drag-over-after")
|
||||
.forEach(tab => {
|
||||
tab.classList.remove("drag-over-before", "drag-over-after");
|
||||
});
|
||||
}
|
||||
|
||||
applyDragoverClass(event, draggedTab) {
|
||||
this.removeTabContainersDragoverClass();
|
||||
|
||||
const pinnedTabsTarget = event.target.closest("#vertical-pinned-tabs-container");
|
||||
const essentialTabsTarget = event.target.closest("#zen-essentials-container");
|
||||
const tabsTarget = event.target.closest("#tabbrowser-arrowscrollbox");
|
||||
const targetTab = event.target.closest(".tabbrowser-tab");
|
||||
|
||||
// If there's no valid target tab, nothing to do
|
||||
if (!targetTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldAddDragOverElement = false;
|
||||
let isVertical = true;
|
||||
|
||||
// Decide whether we should show a dragover class for the given target
|
||||
if (pinnedTabsTarget) {
|
||||
if (!draggedTab.pinned || draggedTab.hasAttribute("zen-essential")) {
|
||||
shouldAddDragOverElement = true;
|
||||
}
|
||||
} else if (essentialTabsTarget) {
|
||||
if (!draggedTab.hasAttribute("zen-essential")) {
|
||||
shouldAddDragOverElement = true;
|
||||
isVertical = false;
|
||||
}
|
||||
} else if (tabsTarget) {
|
||||
if (draggedTab.pinned || draggedTab.hasAttribute("zen-essential")) {
|
||||
shouldAddDragOverElement = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldAddDragOverElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate middle to decide 'before' or 'after'
|
||||
const rect = targetTab.getBoundingClientRect();
|
||||
|
||||
if (isVertical) {
|
||||
const middleY = targetTab.screenY + rect.height / 2;
|
||||
if (event.screenY > middleY) {
|
||||
targetTab.classList.add("drag-over-before");
|
||||
} else {
|
||||
targetTab.classList.add("drag-over-after");
|
||||
}
|
||||
} else {
|
||||
const middleX = targetTab.screenX + rect.width / 2;
|
||||
if (event.screenX > middleX) {
|
||||
targetTab.classList.add("drag-over-before");
|
||||
} else {
|
||||
targetTab.classList.add("drag-over-after");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.gZenPinnedTabManager = new ZenPinnedTabManager();
|
||||
|
Reference in New Issue
Block a user