mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-05 19:08:18 +00:00
Implement drag-and-drop functionality for split view and refine CSS styles for better layout and visibility
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml
|
||||
index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc31cb4034 100644
|
||||
index 959c523b21c642f29353b9de37b3ce6b5505b01b..0d151ad345dde47467432196ed76f4320b4b92cc 100644
|
||||
--- a/browser/base/content/main-popupset.inc.xhtml
|
||||
+++ b/browser/base/content/main-popupset.inc.xhtml
|
||||
@@ -181,6 +181,10 @@
|
||||
@@ -206,6 +206,10 @@
|
||||
hidden="true"
|
||||
tabspecific="true"
|
||||
aria-labelledby="editBookmarkPanelTitle">
|
||||
@@ -13,7 +13,7 @@ index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc
|
||||
<box class="panel-header">
|
||||
<html:h1>
|
||||
<html:span id="editBookmarkPanelTitle"/>
|
||||
@@ -206,6 +210,7 @@
|
||||
@@ -231,6 +235,7 @@
|
||||
class="footer-button"/>
|
||||
</html:moz-button-group>
|
||||
</vbox>
|
||||
@@ -21,7 +21,7 @@ index e5f3424eaeeec0ba552537f167dd99e912216d94..4bdfcdb23fe9c44ad3d4de273c64f4cc
|
||||
</panel>
|
||||
</html:template>
|
||||
|
||||
@@ -535,6 +540,8 @@
|
||||
@@ -565,6 +570,8 @@
|
||||
|
||||
#include popup-notifications.inc.xhtml
|
||||
|
||||
|
@@ -248,3 +248,34 @@
|
||||
outline-color: var(--toolbarbutton-active-outline-color);
|
||||
}
|
||||
}
|
||||
|
||||
#zen-split-view-fake-browser {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--zen-native-inner-radius);
|
||||
box-shadow: var(--zen-big-shadow);
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
background: var(--zen-split-view-fake-icon);
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s;
|
||||
transition-delay: 0.1s;
|
||||
|
||||
@starting-style {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-size: x-small;
|
||||
|
||||
position: relative;
|
||||
|
||||
|
@@ -102,7 +102,7 @@ class ZenBrowserManagerSidebar extends ZenDOMOperatedFeature {
|
||||
syncPinnedState() {
|
||||
const sidebar = document.getElementById('zen-sidebar-web-panel');
|
||||
const pinButton = document.getElementById('zen-sidebar-web-panel-pinned');
|
||||
|
||||
|
||||
if (sidebar.hasAttribute('pinned')) {
|
||||
pinButton.setAttribute('pinned', 'true');
|
||||
} else {
|
||||
|
@@ -84,6 +84,10 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
this.initializeContextMenu();
|
||||
this.insertPageActionButton();
|
||||
this.insertIntoContextMenu();
|
||||
|
||||
// Add drag over listener to the browser view
|
||||
this.tabBrowserPanel.addEventListener('dragenter', this.onBrowserDragOverToSplit.bind(this));
|
||||
this.tabBrowserPanel.addEventListener('dragleave', this.onBrowserDragEndToSplit.bind(this));
|
||||
}
|
||||
|
||||
insertIntoContextMenu() {
|
||||
@@ -142,6 +146,111 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
}
|
||||
}
|
||||
|
||||
onBrowserDragOverToSplit(event) {
|
||||
var dt = event.dataTransfer;
|
||||
var draggedTab;
|
||||
if (dt.mozTypesAt(0)[0] == TAB_DROP_TYPE) {
|
||||
// tab copy or move
|
||||
draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
// not our drop then
|
||||
if (!draggedTab || gBrowser.selectedTab.hasAttribute('zen-empty-tab')) {
|
||||
return;
|
||||
}
|
||||
draggedTab.container._finishMoveTogetherSelectedTabs(draggedTab);
|
||||
}
|
||||
if (!draggedTab || this._canDrop || this._hasAnimated || this.fakeBrowser) {
|
||||
return;
|
||||
}
|
||||
const currentView = this._data[this.currentView];
|
||||
if (currentView?.tabs.length >= this.MAX_TABS) {
|
||||
return;
|
||||
}
|
||||
this._canDrop = true;
|
||||
// wait some time before showing the split view
|
||||
this._showSplitViewTimeout = setTimeout(() => {
|
||||
this._hasAnimated = true;
|
||||
const panelsWidth = gBrowser.tabbox.getBoundingClientRect().width;
|
||||
const halfWidth = panelsWidth / 2;
|
||||
this.fakeBrowser = document.createXULElement('vbox');
|
||||
const padding = Services.prefs.getIntPref('zen.theme.content-element-separation', 0);
|
||||
this.fakeBrowser.setAttribute('flex', '1');
|
||||
this.fakeBrowser.id = 'zen-split-view-fake-browser';
|
||||
gBrowser.tabbox.appendChild(this.fakeBrowser);
|
||||
this.fakeBrowser.style.setProperty('--zen-split-view-fake-icon', `url(${draggedTab.getAttribute('image')})`);
|
||||
Promise.all([
|
||||
gZenUIManager.motion.animate(
|
||||
gBrowser.tabbox,
|
||||
{
|
||||
paddingLeft: [0, `${halfWidth}px`],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
gZenUIManager.motion.animate(
|
||||
this.fakeBrowser,
|
||||
{
|
||||
width: [0, `${halfWidth - padding * 2}px`],
|
||||
marginLeft: [0, `${-(halfWidth - padding)}px`],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
]).then(() => {});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
onBrowserDragEndToSplit(event) {
|
||||
if (!this._canDrop) {
|
||||
return;
|
||||
}
|
||||
const panelsRect = gBrowser.tabbox.getBoundingClientRect();
|
||||
// this event is fired even though we are still in the "allowed" area
|
||||
if (event.target !== this.tabBrowserPanel) {
|
||||
return;
|
||||
}
|
||||
this._canDrop = false;
|
||||
if (this._showSplitViewTimeout) {
|
||||
clearTimeout(this._showSplitViewTimeout);
|
||||
}
|
||||
if (!this._hasAnimated) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
const panelsWidth = panelsRect.width;
|
||||
const halfWidth = panelsWidth / 2;
|
||||
const padding = Services.prefs.getIntPref('zen.theme.content-element-separation', 0);
|
||||
Promise.all([
|
||||
gZenUIManager.motion.animate(
|
||||
gBrowser.tabbox,
|
||||
{
|
||||
paddingLeft: [`${halfWidth}px`, 0],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
gZenUIManager.motion.animate(
|
||||
this.fakeBrowser,
|
||||
{
|
||||
width: [`${halfWidth - padding * 2}px`, 0],
|
||||
marginLeft: [`${-(halfWidth - padding)}px`, 0],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
easing: 'ease-out',
|
||||
}
|
||||
),
|
||||
]).then(() => {
|
||||
this._mayabeRemoveFakeBrowser();
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a SplitNode from its tree and the view
|
||||
* @param {SplitNode} toRemove
|
||||
@@ -699,6 +808,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
this.updateSplitView(tab);
|
||||
tab.linkedBrowser.docShellIsActive = true;
|
||||
}
|
||||
this._mayabeRemoveFakeBrowser();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1282,6 +1392,16 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
}
|
||||
};
|
||||
|
||||
_mayabeRemoveFakeBrowser() {
|
||||
if (this.fakeBrowser) {
|
||||
this.fakeBrowser.remove();
|
||||
this.fakeBrowser = null;
|
||||
gBrowser.tabbox.removeAttribute('style');
|
||||
delete this._canDrop;
|
||||
delete this._hasAnimated;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description moves the tab to the split view if dragged on a browser
|
||||
* @param event - The event
|
||||
@@ -1289,6 +1409,8 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
* @returns {boolean} true if the tab was moved to the split view
|
||||
*/
|
||||
moveTabToSplitView(event, draggedTab) {
|
||||
this._mayabeRemoveFakeBrowser();
|
||||
|
||||
const dropTarget = document.elementFromPoint(event.clientX, event.clientY);
|
||||
const browser = dropTarget?.closest('browser');
|
||||
|
||||
@@ -1336,24 +1458,22 @@ class ZenViewSplitter extends ZenDOMOperatedFeature {
|
||||
}
|
||||
} else {
|
||||
// Create new split view with layout based on drop position
|
||||
let gridType;
|
||||
switch (hoverSide) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
gridType = 'vsep';
|
||||
break;
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
gridType = 'hsep';
|
||||
break;
|
||||
default:
|
||||
gridType = 'grid';
|
||||
}
|
||||
let gridType = 'vsep';
|
||||
//switch (hoverSide) {
|
||||
// case 'left':
|
||||
// case 'right':
|
||||
// gridType = 'vsep';
|
||||
// break;
|
||||
// case 'top':
|
||||
// case 'bottom':
|
||||
// gridType = 'hsep';
|
||||
// break;
|
||||
// default:
|
||||
// gridType = 'grid';
|
||||
//}
|
||||
|
||||
// Put tabs in correct order based on drop side
|
||||
const tabs = ['left', 'top'].includes(hoverSide) ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab];
|
||||
|
||||
this.splitTabs(tabs, gridType);
|
||||
// Put tabs always as if it was dropped from the left
|
||||
this.splitTabs([draggedTab, droppedOnTab], gridType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@@ -1140,6 +1140,7 @@ menupopup > menuitem:is([type='checkbox']) .menu-iconic-left {
|
||||
}
|
||||
|
||||
#toolbar-context-toggle-vertical-tabs,
|
||||
#toolbar-context-customize-sidebar {
|
||||
display: none;
|
||||
#toolbar-context-customize-sidebar,
|
||||
#sidebarRevampSeparator {
|
||||
display: none !important;
|
||||
}
|
||||
|
Reference in New Issue
Block a user