mirror of
https://github.com/zen-browser/desktop.git
synced 2026-03-29 03:41:51 +00:00
Merge branch 'dev' of https://github.com/zen-browser/desktop into dev
This commit is contained in:
@@ -10,3 +10,12 @@
|
||||
|
||||
- name: zen.splitView.rearrange-hover-size
|
||||
value: 24
|
||||
|
||||
- name: zen.splitView.enable-drag-over-split
|
||||
value: true
|
||||
|
||||
- name: zen.splitView.drag-over-split-delayMC
|
||||
value: 300
|
||||
|
||||
- name: zen.splitView.drag-over-split-threshold
|
||||
value: 25
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
#changeSpaceTimer = null;
|
||||
#isAnimatingTabMove = false;
|
||||
|
||||
#dragOverSplit = {};
|
||||
|
||||
constructor(tabbrowserTabs) {
|
||||
super(tabbrowserTabs);
|
||||
|
||||
@@ -78,6 +80,24 @@
|
||||
Ci.nsIZenDragAndDrop
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"_dndSplitEnabled",
|
||||
"zen.splitView.enable-drag-over-split",
|
||||
true
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"_dndSplitThreshold",
|
||||
"zen.splitView.drag-over-split-threshold",
|
||||
25
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"_dndSplitDelay",
|
||||
"zen.splitView.drag-over-split-delayMC",
|
||||
300
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"_dndSwitchSpaceDelay",
|
||||
@@ -587,6 +607,7 @@
|
||||
return;
|
||||
}
|
||||
this.#handle_sidebarDragOver(event);
|
||||
this.#handle_tabDragOverToSplit(event);
|
||||
}
|
||||
|
||||
#shouldSwitchSpace(event) {
|
||||
@@ -655,6 +676,119 @@
|
||||
}
|
||||
}
|
||||
|
||||
#handle_tabDragOverToSplit(event) {
|
||||
if (!this._dndSplitEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dt = event.dataTransfer;
|
||||
const draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
const dragData = draggedTab._dragData;
|
||||
const movingTabsSet = dragData.movingTabsSet;
|
||||
const dropElement = event.target.closest(".tabbrowser-tab");
|
||||
|
||||
// TODO: After Cheff adds split view support for essentials, don't forget to remove the check
|
||||
if (
|
||||
!dropElement ||
|
||||
!isTab(dropElement) ||
|
||||
dropElement.hasAttribute("zen-essential") ||
|
||||
dropElement.hasAttribute("zen-glance-tab") ||
|
||||
dropElement?.group?.hasAttribute("split-view-group") ||
|
||||
movingTabsSet.size > 1
|
||||
) {
|
||||
this._clearDragOverSplit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
movingTabsSet.has(dropElement) ||
|
||||
!isTab(draggedTab) ||
|
||||
draggedTab?.group?.hasAttribute("split-view-group")
|
||||
) {
|
||||
this._clearDragOverSplit();
|
||||
return;
|
||||
}
|
||||
|
||||
const rect = window.windowUtils.getBoundsWithoutFlushing(dropElement);
|
||||
const { clientX, clientY } = event;
|
||||
const targetX = rect.x;
|
||||
const targetTop = rect.top;
|
||||
const targetWidth = rect.width;
|
||||
const targetHeight = rect.height;
|
||||
|
||||
const edgeZoneThreshold = this._dndSplitThreshold / 100;
|
||||
|
||||
const overlapRatioY = (clientY - targetTop) / targetHeight;
|
||||
const overlapRatioX = (clientX - targetX) / targetWidth;
|
||||
if (
|
||||
(overlapRatioX > edgeZoneThreshold && overlapRatioX < 1 - edgeZoneThreshold) ||
|
||||
overlapRatioY < edgeZoneThreshold ||
|
||||
overlapRatioY > 1 - edgeZoneThreshold
|
||||
) {
|
||||
this._clearDragOverSplit();
|
||||
return;
|
||||
}
|
||||
|
||||
const isLeft = clientX < targetX + targetWidth / 2;
|
||||
const dropSide = isLeft ? "left" : "right";
|
||||
|
||||
// If the drop side or element changes, clear dragOverSplit
|
||||
if (
|
||||
this.#dragOverSplit.data?.dropElement !== dropElement ||
|
||||
this.#dragOverSplit.data?.dropSide !== dropSide
|
||||
) {
|
||||
this._clearDragOverSplit();
|
||||
}
|
||||
|
||||
if (
|
||||
this.#dragOverSplit.timer &&
|
||||
this.#dragOverSplit.data?.dropElement === dropElement &&
|
||||
this.#dragOverSplit.data?.dropSide === dropSide
|
||||
) {
|
||||
// Timer already running for the same target and side, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
this.#dragOverSplit.data = {
|
||||
dropElement,
|
||||
dropSide,
|
||||
};
|
||||
this.#dragOverSplit.timer = setTimeout(() => {
|
||||
this.#createFakeTabSplit(dropElement, dropSide);
|
||||
}, this._dndSplitDelay);
|
||||
}
|
||||
|
||||
#createFakeTabSplit(dropElement, dropSide) {
|
||||
// Remove drop indicator
|
||||
this.clearDragOverVisuals();
|
||||
|
||||
// Remove any existing fake tab
|
||||
if (this.#dragOverSplit.fakeTab) {
|
||||
this.#dragOverSplit.fakeTab.remove();
|
||||
}
|
||||
|
||||
const element = document.createXULElement("zen-split-fake-tab");
|
||||
const firstChild = dropElement.firstChild;
|
||||
if (dropSide === "left") {
|
||||
firstChild.before(element);
|
||||
} else {
|
||||
firstChild.after(element);
|
||||
}
|
||||
|
||||
this.#dragOverSplit.fakeTab = element;
|
||||
}
|
||||
|
||||
_clearDragOverSplit() {
|
||||
if (this.#dragOverSplit.timer) {
|
||||
clearTimeout(this.#dragOverSplit.timer);
|
||||
}
|
||||
this.#dragOverSplit.fakeTab?.remove();
|
||||
|
||||
this.#dragOverSplit.timer = null;
|
||||
this.#dragOverSplit.fakeTab = null;
|
||||
this.#dragOverSplit.data = null;
|
||||
}
|
||||
|
||||
handle_windowDragEnter(event) {
|
||||
if (!this.#isMovingTab() || !this.#isOutOfWindow) {
|
||||
return;
|
||||
@@ -722,6 +856,17 @@
|
||||
gZenFolders.highlightGroupOnDragOver(null);
|
||||
super.handle_drop(event);
|
||||
this.#maybeClearVerticalPinnedGridDragOver();
|
||||
this.#handle_dropSwitchSpace(event);
|
||||
this.#handle_dropCreateSplit(event);
|
||||
this._clearDragOverSplit();
|
||||
}
|
||||
|
||||
handle_dragleave(event) {
|
||||
super.handle_dragleave(event);
|
||||
this._clearDragOverSplit();
|
||||
}
|
||||
|
||||
#handle_dropSwitchSpace(event) {
|
||||
const dt = event.dataTransfer;
|
||||
const activeWorkspace = gZenWorkspaces.activeWorkspace;
|
||||
let draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
@@ -745,6 +890,29 @@
|
||||
gZenWorkspaces.updateTabsContainers();
|
||||
}
|
||||
|
||||
#handle_dropCreateSplit(event) {
|
||||
const dragData = this.#dragOverSplit.data;
|
||||
const dt = event.dataTransfer;
|
||||
const draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
|
||||
if (!dragData || !draggedTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
const droppedOnTab = dragData.dropElement;
|
||||
const dropSide = dragData.dropSide;
|
||||
|
||||
// Clear any visuals and timer
|
||||
this._clearDragOverSplit();
|
||||
|
||||
const isLeft = dropSide === "left";
|
||||
gZenViewSplitter.splitTabs(
|
||||
isLeft ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab],
|
||||
"vsep",
|
||||
isLeft ? 0 : 1
|
||||
);
|
||||
}
|
||||
|
||||
handle_drop_transition(dropElement, draggedTab, movingTabs, dropBefore) {
|
||||
if (isTabGroupLabel(dropElement)) {
|
||||
dropElement = dropElement.group;
|
||||
@@ -874,6 +1042,7 @@
|
||||
super.handle_dragend(event);
|
||||
thisFromGlobal.clearDragOverVisuals();
|
||||
ownerGlobal.gZenPinnedTabManager.removeTabContainersDragoverClass();
|
||||
thisFromGlobal._clearDragOverSplit();
|
||||
this.#maybeClearVerticalPinnedGridDragOver();
|
||||
thisFromGlobal.originalDragImageArgs = [];
|
||||
window.removeEventListener("dragenter", thisFromGlobal.handle_windowDragEnter, {
|
||||
@@ -948,6 +1117,10 @@
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
#applyDragoverIndicator(event, dropElement, movingTabs, draggedTab) {
|
||||
// Doesn't show indicator when dragOverSplit
|
||||
if (this.#dragOverSplit.data) {
|
||||
return;
|
||||
}
|
||||
const separation = 4;
|
||||
const dropZoneSelector = ":is(.zen-drop-target)";
|
||||
let shouldPlayHapticFeedback = false;
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
%include zen-split-group.inc.css
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true'] {
|
||||
#tabbrowser-tabpanels[zen-split-view="true"] {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: calc(var(--zen-split-column-gap) * -1);
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true'] > *:not([zen-split='true']) {
|
||||
#tabbrowser-tabpanels[zen-split-view="true"] > *:not([zen-split="true"]) {
|
||||
flex: 0;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -25,11 +25,11 @@
|
||||
display: none;
|
||||
background-color: color-mix(in srgb, var(--zen-colors-secondary) 30%, transparent 70%);
|
||||
}
|
||||
#zen-splitview-dropzone[enabled='true'] {
|
||||
#zen-splitview-dropzone[enabled="true"] {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true'] > [zen-split='true'],
|
||||
#tabbrowser-tabpanels[zen-split-view="true"] > [zen-split="true"],
|
||||
#zen-splitview-dropzone {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.browserSidebarContainer[is-zen-split='true'],
|
||||
.browserSidebarContainer[is-zen-split="true"],
|
||||
#zen-splitview-dropzone {
|
||||
position: absolute !important;
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
margin-bottom: 0;
|
||||
margin-left: 0;
|
||||
|
||||
&.browserSidebarContainer:not([zen-split='true']) {
|
||||
&.browserSidebarContainer:not([zen-split="true"]) {
|
||||
margin-top: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -58,7 +58,7 @@
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true']:not(.zen-split-view-no-transition):not([zen-split-resizing]) > [zen-split='true'] {
|
||||
#tabbrowser-tabpanels[zen-split-view="true"]:not(.zen-split-view-no-transition):not([zen-split-resizing]) > [zen-split="true"] {
|
||||
--zen-active-split-outline-color: light-dark(var(--zen-primary-color), var(--button-background-color-primary));
|
||||
|
||||
transition: inset 0.09s ease-out !important;
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels[zen-split-view='true'] .browserSidebarContainer.deck-selected {
|
||||
#tabbrowser-tabpanels[zen-split-view="true"] .browserSidebarContainer.deck-selected {
|
||||
&:not(.zen-glance-overlay) {
|
||||
outline: 2px solid var(--zen-active-split-outline-color) !important;
|
||||
}
|
||||
@@ -84,8 +84,8 @@
|
||||
--zen-split-column-gap: calc(var(--zen-element-separation) + 1px);
|
||||
}
|
||||
|
||||
#tabbrowser-tabbox[zen-split-view='true'] {
|
||||
:root[zen-no-padding='true'] & {
|
||||
#tabbrowser-tabbox[zen-split-view="true"] {
|
||||
:root[zen-no-padding="true"] & {
|
||||
--zen-element-separation: 8px;
|
||||
}
|
||||
margin-right: calc(-1 * var(--zen-split-column-gap));
|
||||
@@ -121,7 +121,7 @@
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.zen-split-view-splitter[orient='horizontal'] {
|
||||
.zen-split-view-splitter[orient="horizontal"] {
|
||||
height: var(--zen-split-column-gap);
|
||||
cursor: ns-resize;
|
||||
}
|
||||
@@ -152,9 +152,7 @@
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
:root:not([inDOMFullscreen='true'])
|
||||
.browserSidebarContainer:hover
|
||||
.zen-view-splitter-header-container,
|
||||
:root:not([inDOMFullscreen="true"]) .browserSidebarContainer:hover .zen-view-splitter-header-container,
|
||||
.zen-view-splitter-header-container:hover {
|
||||
pointer-events: all;
|
||||
opacity: 1;
|
||||
@@ -204,24 +202,24 @@
|
||||
overflow: hidden;
|
||||
will-change: width, margin-left;
|
||||
|
||||
&[side='top'],
|
||||
&[side='bottom'] {
|
||||
&[side="top"],
|
||||
&[side="bottom"] {
|
||||
width: 100%;
|
||||
|
||||
&[has-split-view='true'] {
|
||||
|
||||
&[has-split-view="true"] {
|
||||
width: calc(100% - var(--zen-element-separation));
|
||||
}
|
||||
}
|
||||
|
||||
&[side='right'] {
|
||||
&[side="right"] {
|
||||
right: 0;
|
||||
|
||||
&[has-split-view='true'] {
|
||||
&[has-split-view="true"] {
|
||||
right: var(--zen-element-separation);
|
||||
}
|
||||
}
|
||||
|
||||
&[side='bottom'] {
|
||||
&[side="bottom"] {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
@@ -249,3 +247,10 @@
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
zen-split-fake-tab {
|
||||
border-radius: var(--tab-border-radius);
|
||||
background-color: color-mix(in srgb, var(--button-background-color-primary), transparent 40%);
|
||||
margin: var(--tab-block-margin);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user