Skip to content

Commit 83b8f44

Browse files
committed
feat: create overflow button in tabbar
1 parent 6dda8f2 commit 83b8f44

File tree

6 files changed

+202
-19
lines changed

6 files changed

+202
-19
lines changed

src/extensionsIntegrated/TabBar/helper.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ define(function (require, exports, module) {
1212
* Its only shown when tab bar is enabled and there is atleast one working file
1313
*
1414
* @param {$.Element} $tabBar - The tab bar element
15-
* @param {$.Element} $moreOptions - The more options element
15+
* @param {$.Element} $overflowButton - The overflow button element
1616
*/
17-
function _showTabBar($tabBar, $moreOptions) {
17+
function _showTabBar($tabBar, $overflowButton) {
1818
if ($tabBar) {
1919
$tabBar.show();
20+
if($overflowButton) {
21+
$overflowButton.show();
22+
}
2023
// when we add/remove something from the editor, the editor shifts up/down which leads to blank space
2124
// so we need to recompute the layout to make sure things are in the right place
2225
WorkspaceManager.recomputeLayout(true);
@@ -26,13 +29,17 @@ define(function (require, exports, module) {
2629
/**
2730
* Hides the tab bar.
2831
* Its hidden when tab bar feature is disabled or there are no working files
32+
* both the tab bar and the overflow button are to be hidden to hide the tab bar container
2933
*
3034
* @param {$.Element} $tabBar - The tab bar element
31-
* @param {$.Element} $moreOptions - The more options element
35+
* @param {$.Element} $overflowButton - The overflow button element
3236
*/
33-
function _hideTabBar($tabBar, $moreOptions) {
37+
function _hideTabBar($tabBar, $overflowButton) {
3438
if ($tabBar) {
3539
$tabBar.hide();
40+
if($overflowButton) {
41+
$overflowButton.hide();
42+
}
3643
WorkspaceManager.recomputeLayout(true);
3744
}
3845
}

src/extensionsIntegrated/TabBar/html/tabbar-pane.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
<div id="phoenix-tab-bar" class="phoenix-tab-bar">
33

44
</div>
5+
6+
<div id="overflow-button" class="overflow-button" title="Show hidden tabs">
7+
<i class="fa-solid fa-chevron-down"></i>
8+
</div>
59
</div>

src/extensionsIntegrated/TabBar/html/tabbar-second-pane.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
<div id="phoenix-tab-bar-2" class="phoenix-tab-bar">
33

44
</div>
5+
6+
<div id="overflow-button-2" class="overflow-button-2" title="Show hidden tabs">
7+
<i class="fa-solid fa-chevron-down"></i>
8+
</div>
59
</div>

src/extensionsIntegrated/TabBar/main.js

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ define(function (require, exports, module) {
1313
const Helper = require("./helper");
1414
const Preference = require("./preference");
1515
const MoreOptions = require("./more-options");
16+
const Overflow = require("./overflow");
1617
const TabBarHTML = require("text!./html/tabbar-pane.html");
1718
const TabBarHTML2 = require("text!./html/tabbar-second-pane.html");
1819

@@ -148,11 +149,11 @@ define(function (require, exports, module) {
148149
const $secondTabBar = $('#phoenix-tab-bar-2');
149150

150151
if (Global.firstPaneWorkingSet.length === 0 && ($('#phoenix-tab-bar'))) {
151-
Helper._hideTabBar($('#phoenix-tab-bar'));
152+
Helper._hideTabBar($('#phoenix-tab-bar'), $('#overflow-button'));
152153
}
153154

154155
if (Global.secondPaneWorkingSet.length === 0 && ($('#phoenix-tab-bar-2'))) {
155-
Helper._hideTabBar($('#phoenix-tab-bar-2'));
156+
Helper._hideTabBar($('#phoenix-tab-bar-2'), $('#overflow-button-2'));
156157
}
157158

158159
// get the count of tabs that we want to display in the tab bar (from preference settings)
@@ -188,6 +189,7 @@ define(function (require, exports, module) {
188189
// add each tab to the first pane's tab bar
189190
displayedEntries.forEach(function (entry) {
190191
$firstTabBar.append(createTab(entry));
192+
Overflow.toggleOverflowVisibility("first-pane");
191193
});
192194
}
193195

@@ -204,6 +206,7 @@ define(function (require, exports, module) {
204206

205207
displayedEntries2.forEach(function (entry) {
206208
$secondTabBar.append(createTab(entry));
209+
Overflow.toggleOverflowVisibility("second-pane");
207210
});
208211
}
209212
}
@@ -254,16 +257,6 @@ define(function (require, exports, module) {
254257
}
255258

256259

257-
/**
258-
* When any change is made to the working set, we just recreate the tab bar
259-
* The changes may be adding/removing a file or changing the active file
260-
*/
261-
function workingSetChanged() {
262-
cleanupTabBar();
263-
createTabBar();
264-
}
265-
266-
267260
/**
268261
* Handle close button click on tabs
269262
* This function will remove the file from the working set
@@ -375,9 +368,17 @@ define(function (require, exports, module) {
375368
EditorManager.on("activeEditorChange", createTabBar);
376369

377370
// when working set changes, recreate the tab bar
378-
MainViewManager.on("workingSetAdd", workingSetChanged);
379-
MainViewManager.on("workingSetRemove", workingSetChanged);
380-
MainViewManager.on("workingSetSort", workingSetChanged);
371+
// we listen to all of these events to ensure that the tab bar is always up to date
372+
// refer to `MainViewManager.js` for more details
373+
MainViewManager.on("workingSetAdd", createTabBar);
374+
MainViewManager.on("workingSetRemove", createTabBar);
375+
MainViewManager.on("workingSetSort", createTabBar);
376+
MainViewManager.on("workingSetMove", createTabBar);
377+
MainViewManager.on("workingSetAddList", createTabBar);
378+
MainViewManager.on("workingSetRemoveList", createTabBar);
379+
MainViewManager.on("workingSetUpdate", createTabBar);
380+
MainViewManager.on("_workingSetDisableAutoSort", createTabBar);
381+
381382

382383
// file dirty flag change handler
383384
DocumentManager.on("dirtyFlagChange", function (event, doc) {
@@ -443,5 +444,7 @@ define(function (require, exports, module) {
443444

444445
// handle when a single tab gets clicked
445446
handleTabClick();
447+
448+
Overflow.init();
446449
});
447450
});
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
define(function (require, exports, module) {
2+
3+
/**
4+
* This function determines which tabs are hidden in the tab bar due to overflow
5+
* and returns them as an array of tab data objects
6+
*
7+
* @param {String} paneId - The ID of the pane ("first-pane" or "second-pane")
8+
* @returns {Array} - Array of hidden tab data objects
9+
*/
10+
function _getListOfHiddenTabs(paneId) {
11+
// Select the appropriate tab bar based on pane ID
12+
const $currentTabBar = paneId === "first-pane"
13+
? $("#phoenix-tab-bar")
14+
: $("#phoenix-tab-bar-2");
15+
16+
// Need to access the DOM element to get its bounding rectangle
17+
const tabBarRect = $currentTabBar[0].getBoundingClientRect();
18+
19+
// Get the overflow button element
20+
const $overflowButton = paneId === "first-pane"
21+
? $("#overflow-button")
22+
: $("#overflow-button-2");
23+
24+
// Account for overflow button width in calculation
25+
const overflowButtonWidth = $overflowButton.is(":visible") ? $overflowButton.outerWidth() : 0;
26+
27+
const hiddenTabs = [];
28+
29+
// Examine each tab to determine if it's visible
30+
$currentTabBar.find('.tab').each(function () {
31+
const tabRect = this.getBoundingClientRect();
32+
33+
// A tab is considered hidden if it extends beyond the right edge of the tab bar
34+
// minus the width of the overflow button (if visible)
35+
const isVisible = tabRect.left >= tabBarRect.left &&
36+
tabRect.right <= (tabBarRect.right - overflowButtonWidth);
37+
38+
if (!isVisible) {
39+
// Extract and store information about the hidden tab
40+
const $tab = $(this);
41+
const tabData = {
42+
path: $tab.data('path'),
43+
name: $tab.find('.tab-name').text(),
44+
isActive: $tab.hasClass('active'),
45+
isDirty: $tab.hasClass('dirty'),
46+
$icon: $tab.find('.tab-icon').clone()
47+
};
48+
49+
hiddenTabs.push(tabData);
50+
}
51+
});
52+
53+
return hiddenTabs;
54+
}
55+
56+
function _getNamesFromTabsData(tabsData) {
57+
return tabsData.map(tab => tab.name);
58+
}
59+
60+
61+
/**
62+
* Toggles the visibility of the overflow button based on whether
63+
* there are any hidden tabs
64+
* Hidden tabs are tabs that are currently not visible in the tab bar
65+
*
66+
* @param {String} paneId - The ID of the pane ("first-pane" or "second-pane")
67+
*/
68+
function toggleOverflowVisibility(paneId) {
69+
const hiddenTabs = _getListOfHiddenTabs(paneId);
70+
71+
if (paneId === "first-pane") {
72+
// for the html elements, refer to ./html/tabbar-pane.html
73+
const $tabBar = $("#phoenix-tab-bar");
74+
const $overflowButton = $("#overflow-button");
75+
76+
if (hiddenTabs.length > 0) {
77+
$overflowButton.removeClass("hidden");
78+
} else {
79+
$overflowButton.addClass("hidden");
80+
}
81+
} else {
82+
// for the html elements, refer to ./html/tabbar-second-pane.html
83+
const $tabBar = $("#phoenix-tab-bar-2");
84+
const $overflowButton = $("#overflow-button-2");
85+
86+
if (hiddenTabs.length > 0) {
87+
$overflowButton.removeClass("hidden");
88+
} else {
89+
$overflowButton.addClass("hidden");
90+
}
91+
}
92+
}
93+
94+
function showOverflowMenu(paneId, x, y) {
95+
const hiddenTabs = _getListOfHiddenTabs(paneId);
96+
97+
98+
99+
}
100+
101+
102+
103+
104+
/**
105+
* To setup the handlers for the overflow menu
106+
*/
107+
function setupOverflowHandlers() {
108+
109+
$(document).on("click", "#overflow-button", function (e) {
110+
e.stopPropagation();
111+
showOverflowMenu("first-pane", e.pageX, e.pageY);
112+
});
113+
114+
$(document).on("click", "#overflow-button-2", function (e) {
115+
e.stopPropagation();
116+
showOverflowMenu("second-pane", e.pageX, e.pageY);
117+
});
118+
}
119+
120+
// initialize the handling of the overflow buttons
121+
function init() {
122+
setupOverflowHandlers();
123+
}
124+
125+
module.exports = {
126+
init,
127+
toggleOverflowVisibility
128+
};
129+
});

src/styles/Extn-TabBar.less

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,42 @@
2525
height: 0.25rem;
2626
}
2727

28+
.overflow-button,
29+
.overflow-button-2 {
30+
display: flex;
31+
align-items: center;
32+
height: 2rem;
33+
padding: 0 0.5rem;
34+
cursor: pointer;
35+
position: relative;
36+
z-index: 2;
37+
margin-left: auto;
38+
}
39+
40+
.overflow-button.hidden,
41+
.overflow-button-2.hidden {
42+
display: none;
43+
}
44+
45+
46+
.overflow-button:hover,
47+
.overflow-button-2:hover {
48+
background-color: #333;
49+
}
50+
51+
52+
.overflow-button::before,
53+
.overflow-button-2::before {
54+
content: "";
55+
position: absolute;
56+
top: 0;
57+
left: -1rem;
58+
width: 1rem;
59+
height: 100%;
60+
pointer-events: none;
61+
background: linear-gradient(to right, rgba(30, 30, 30, 0), #1E1E1E);
62+
}
63+
2864

2965
.tab {
3066
display: inline-flex;

0 commit comments

Comments
 (0)