Skip to content

Commit b5a297b

Browse files
committed
feat: quick access tab always shown on first
1 parent e06a7fc commit b5a297b

4 files changed

Lines changed: 67 additions & 111 deletions

File tree

src/nls/root/strings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ define({
15601560
"BOTTOM_PANEL_MINIMIZE": "Minimize Panel",
15611561
"BOTTOM_PANEL_SHOW": "Show Bottom Panel",
15621562
"BOTTOM_PANEL_HIDE_TOGGLE": "Hide Bottom Panel",
1563-
"BOTTOM_PANEL_DEFAULT_TITLE": "Tools",
1563+
"BOTTOM_PANEL_DEFAULT_TITLE": "Quick Access",
15641564
"BOTTOM_PANEL_DEFAULT_HEADING": "Open a Panel",
15651565
"BOTTOM_PANEL_OPEN_PANEL": "Open a Panel",
15661566
"BOTTOM_PANEL_MAXIMIZE": "Maximize Panel",

src/styles/Extn-BottomPanelTabs.less

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,7 @@
237237
/* Fix all collapsed tabs to the same width so the UI doesn't shake
238238
when switching active tab. The width matches the active tab's
239239
natural content (icon + close button) using fixed px since the
240-
icon has a fixed size. The Tools button (.bottom-panel-add-btn)
241-
is a separate element and keeps its natural "Tools" text width. */
240+
icon has a fixed size. */
242241
.bottom-panel-tab {
243242
min-width: 63px;
244243
box-sizing: border-box;
@@ -247,7 +246,7 @@
247246
.bottom-panel-tab:not(.active) .bottom-panel-tab-close-btn {
248247
display: none;
249248
}
250-
/* Default panel (Tools) tab: keep natural width and show its title
249+
/* Pinned Quick Access tab: keep natural width and show its title
251250
even in collapsed mode (other tabs collapse to icon-only). */
252251
.bottom-panel-tab.bottom-panel-tab-default {
253252
min-width: auto;
@@ -304,42 +303,14 @@
304303
}
305304
}
306305

307-
.bottom-panel-add-btn {
308-
display: flex;
309-
align-items: center;
310-
justify-content: center;
311-
padding: 0 10px;
312-
height: 2rem;
313-
min-width: 70px;
314-
line-height: 2rem;
315-
cursor: pointer;
316-
color: #888;
317-
font-size: 0.82rem;
318-
flex: 0 0 auto;
319-
white-space: nowrap;
320-
user-select: none;
321-
-webkit-user-drag: none;
322-
transition: color 0.12s ease, background-color 0.12s ease;
323-
324-
img {
325-
-webkit-user-drag: none;
326-
pointer-events: none;
327-
}
306+
/* Pinned Quick Access tab: subtle separator to distinguish it from regular tabs */
307+
.bottom-panel-tab.bottom-panel-tab-default {
308+
padding-right: 0.8rem;
309+
border-right: 1px solid rgba(0, 0, 0, 0.15);
328310

329311
.dark & {
330-
color: #777;
312+
border-right: 1px solid rgba(255, 255, 255, 0.1);
331313
}
332-
333-
&:hover {
334-
background-color: #e0e0e0;
335-
color: #333;
336-
337-
.dark & {
338-
background-color: #333;
339-
color: #eee;
340-
}
341-
}
342-
343314
}
344315

345316
.bottom-panel-tab-bar-actions {

src/view/DefaultPanelView.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,9 @@ define(function (require, exports, module) {
198198
}
199199
});
200200

201-
// Auto-hide when any other panel is shown; update drawer button state.
201+
// Update drawer button state when panels are shown.
202202
PanelView.on(PanelView.EVENT_PANEL_SHOWN, function (event, panelID) {
203-
if (panelID !== WorkspaceManager.DEFAULT_PANEL_ID) {
204-
_panel.hide();
205-
} else {
203+
if (panelID === WorkspaceManager.DEFAULT_PANEL_ID) {
206204
_updateButtonVisibility();
207205
}
208206
$drawerBtn.toggleClass("selected-button", panelID === WorkspaceManager.DEFAULT_PANEL_ID);

src/view/PanelView.js

Lines changed: 57 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ define(function (require, exports, module) {
108108
/** @type {string|null} The default/quick-access panel ID */
109109
let _defaultPanelId = null;
110110

111-
/** @type {jQueryObject} The "+" button inside the tab overflow area */
112-
let _$addBtn = null;
113-
114111
// --- Tab helper functions ---
115112

116113
/**
@@ -149,7 +146,7 @@ define(function (require, exports, module) {
149146
*/
150147
function _buildTab(panel, isActive) {
151148
let title = panel._tabTitle || _getPanelTitle(panel.panelID, panel.$panel);
152-
// Default panel (Tools) tab is not draggable — it's a fixed slot, not a user tab
149+
// Default panel (Quick Access) tab is pinned — not draggable, not closable
153150
const isDefault = panel.panelID === _defaultPanelId;
154151
let $tab = $('<div class="bottom-panel-tab"></div>')
155152
.toggleClass('bottom-panel-tab-default', isDefault)
@@ -163,18 +160,16 @@ define(function (require, exports, module) {
163160
$icon[0].style.webkitMaskImage = maskUrl;
164161
$tab.append($icon);
165162
$tab.append($('<span class="bottom-panel-tab-title"></span>').text(title));
166-
$tab.append($('<span class="bottom-panel-tab-close-btn">&times;</span>').attr('title', Strings.CLOSE));
163+
if (!isDefault) {
164+
$tab.append($('<span class="bottom-panel-tab-close-btn">&times;</span>').attr('title', Strings.CLOSE));
165+
}
167166
return $tab;
168167
}
169168

170169
function _updateBottomPanelTabBar() {
171170
if (!_$tabsOverflow) {
172171
return;
173172
}
174-
// Detach the add button before emptying to preserve its event handlers
175-
if (_$addBtn) {
176-
_$addBtn.detach();
177-
}
178173
_$tabsOverflow.empty();
179174

180175
_openIds.forEach(function (panelId) {
@@ -185,11 +180,6 @@ define(function (require, exports, module) {
185180
_$tabsOverflow.append(_buildTab(panel, panelId === _activeId));
186181
});
187182

188-
// Re-append the Tools button at the end
189-
if (_$addBtn) {
190-
_$tabsOverflow.append(_$addBtn);
191-
}
192-
_updateAddButtonVisibility();
193183
_checkTabOverflow();
194184
}
195185

@@ -226,13 +216,7 @@ define(function (require, exports, module) {
226216
return;
227217
}
228218
let $tab = _buildTab(panel, panelId === _activeId);
229-
// Insert before the Tools button so it stays at the end
230-
if (_$addBtn && _$addBtn.parent().length) {
231-
_$addBtn.before($tab);
232-
} else {
233-
_$tabsOverflow.append($tab);
234-
}
235-
_updateAddButtonVisibility();
219+
_$tabsOverflow.append($tab);
236220
_checkTabOverflow();
237221
}
238222

@@ -247,7 +231,6 @@ define(function (require, exports, module) {
247231
return;
248232
}
249233
_$tabsOverflow.find('.bottom-panel-tab[data-panel-id="' + panelId + '"]').remove();
250-
_updateAddButtonVisibility();
251234
_checkTabOverflow();
252235
}
253236

@@ -311,15 +294,21 @@ define(function (require, exports, module) {
311294
if (!draggedTab || this === draggedTab) {
312295
return;
313296
}
314-
// Don't allow dropping onto the default panel (Tools) tab
297+
// Don't allow dropping onto the pinned Quick Access tab
315298
if ($(this).data("panel-id") === _defaultPanelId) {
316299
return;
317300
}
318301
e.preventDefault();
319302
e.originalEvent.dataTransfer.dropEffect = "move";
320303
_$tabBar.find(".bottom-panel-tab").removeClass("drag-target");
321304
$(this).addClass("drag-target");
322-
updateIndicator(this, getDropPosition(this, e.originalEvent.clientX));
305+
let insertBefore = getDropPosition(this, e.originalEvent.clientX);
306+
// Can't insert before the first non-default tab (would go ahead of pinned tab)
307+
const targetIdx = _openIds.indexOf($(this).data("panel-id"));
308+
if (insertBefore && targetIdx <= 1) {
309+
insertBefore = false;
310+
}
311+
updateIndicator(this, insertBefore);
323312
});
324313

325314
_$tabBar.on("dragleave", ".bottom-panel-tab", function (e) {
@@ -350,6 +339,10 @@ define(function (require, exports, module) {
350339
if (!insertBefore) {
351340
newIdx++;
352341
}
342+
// Never place a tab before the pinned Quick Access tab at index 0
343+
if (newIdx < 1 && _defaultPanelId && _openIds[0] === _defaultPanelId) {
344+
newIdx = 1;
345+
}
353346
_openIds.splice(newIdx, 0, draggedId);
354347
cleanup();
355348
_updateBottomPanelTabBar();
@@ -503,23 +496,6 @@ define(function (require, exports, module) {
503496
});
504497
}
505498

506-
/**
507-
* Show or hide the "+" button based on whether the default panel is active.
508-
* The button is hidden when the default panel is the active tab (since
509-
* clicking "+" would be a no-op) and shown otherwise.
510-
* @private
511-
*/
512-
function _updateAddButtonVisibility() {
513-
if (!_$addBtn) {
514-
return;
515-
}
516-
if (_defaultPanelId && _activeId === _defaultPanelId) {
517-
_$addBtn.hide();
518-
} else {
519-
_$addBtn.show();
520-
}
521-
}
522-
523499
/**
524500
* Switch the active tab to the given panel. Does not show/hide the container.
525501
* @param {string} panelId
@@ -543,7 +519,6 @@ define(function (require, exports, module) {
543519
newPanel.$panel.addClass("active-bottom-panel");
544520
}
545521
_updateActiveTabHighlight();
546-
_updateAddButtonVisibility();
547522
}
548523

549524

@@ -567,6 +542,12 @@ define(function (require, exports, module) {
567542
this._tabTitle = _getPanelTitle(id, $panel, title);
568543
this._options = options || {};
569544
_panelMap[id] = this;
545+
546+
// Quick Access panel is pinned: always at index 0, always in the tab bar
547+
if (id === _defaultPanelId && _openIds.indexOf(id) === -1) {
548+
_openIds.unshift(id);
549+
_addTabToBar(id);
550+
}
570551
}
571552

572553
/**
@@ -666,8 +647,13 @@ define(function (require, exports, module) {
666647
exports.trigger(EVENT_PANEL_SHOWN, panelId);
667648
return;
668649
}
669-
// Not open: add to open set
670-
_openIds.push(panelId);
650+
// Not open: add to open set.
651+
// Quick Access panel is always pinned at index 0.
652+
if (panelId === _defaultPanelId) {
653+
_openIds.unshift(panelId);
654+
} else {
655+
_openIds.push(panelId);
656+
}
671657

672658
// Show container if it was hidden
673659
if (!_$container.is(":visible")) {
@@ -684,9 +670,26 @@ define(function (require, exports, module) {
684670
*/
685671
Panel.prototype.hide = function () {
686672
let panelId = this.panelID;
673+
674+
// Quick Access panel is pinned — it stays in _openIds and the tab bar.
675+
// Hiding it collapses the bottom panel container entirely.
676+
if (panelId === _defaultPanelId) {
677+
if (_activeId !== panelId) {
678+
return;
679+
}
680+
this.$panel.removeClass("active-bottom-panel");
681+
_activeId = null;
682+
_updateActiveTabHighlight();
683+
if (_$container) {
684+
restoreIfMaximized();
685+
Resizer.hide(_$container[0]);
686+
}
687+
exports.trigger(EVENT_PANEL_HIDDEN, panelId);
688+
return;
689+
}
690+
687691
let idx = _openIds.indexOf(panelId);
688692
if (idx === -1) {
689-
// Not open - no-op
690693
return;
691694
}
692695

@@ -700,10 +703,9 @@ define(function (require, exports, module) {
700703
if (wasActive && _openIds.length > 0) {
701704
let nextIdx = Math.min(idx, _openIds.length - 1);
702705
activatedId = _openIds[nextIdx];
703-
_activeId = null; // clear so _switchToTab runs
706+
_activeId = null;
704707
_switchToTab(activatedId);
705708
} else if (wasActive) {
706-
// No more tabs - hide the container
707709
_activeId = null;
708710
if (_$container) {
709711
restoreIfMaximized();
@@ -713,10 +715,8 @@ define(function (require, exports, module) {
713715

714716
_removeTabFromBar(panelId);
715717

716-
// Always fire HIDDEN for the closed panel first
717718
exports.trigger(EVENT_PANEL_HIDDEN, panelId);
718719

719-
// Then fire SHOWN for the newly activated tab, if any
720720
if (activatedId) {
721721
exports.trigger(EVENT_PANEL_SHOWN, activatedId);
722722
}
@@ -793,18 +793,11 @@ define(function (require, exports, module) {
793793
_recomputeLayout = recomputeLayoutFn;
794794
_defaultPanelId = defaultPanelId;
795795

796-
// Create the "Tools" button inside the scrollable tabs area.
797-
_$addBtn = $('<span class="bottom-panel-add-btn" draggable="false" title="' + Strings.BOTTOM_PANEL_DEFAULT_TITLE + '">'
798-
+ '<img class="app-drawer-tab-icon" draggable="false" src="styles/images/app-drawer.svg"'
799-
+ ' style="width:12px;height:12px;vertical-align:middle;margin-right:4px">'
800-
+ Strings.BOTTOM_PANEL_DEFAULT_TITLE + '</span>');
801-
_$tabsOverflow.append(_$addBtn);
802-
803796
// Tab bar click handlers
804797
_$tabBar.on("click", ".bottom-panel-tab-close-btn", function (e) {
805798
e.stopPropagation();
806799
let panelId = $(this).closest(".bottom-panel-tab").data("panel-id");
807-
if (panelId) {
800+
if (panelId && panelId !== _defaultPanelId) {
808801
let panel = _panelMap[panelId];
809802
if (panel) {
810803
panel.requestClose();
@@ -836,14 +829,6 @@ define(function (require, exports, module) {
836829
_showOverflowMenu();
837830
});
838831

839-
// "+" button opens the default/quick-access panel
840-
_$addBtn.on("click", function (e) {
841-
e.stopPropagation();
842-
if (_defaultPanelId && _panelMap[_defaultPanelId]) {
843-
_panelMap[_defaultPanelId].show();
844-
}
845-
});
846-
847832
// Hide-panel button collapses the container but keeps tabs intact.
848833
// Maximize state is preserved so the panel re-opens maximized.
849834
_$tabBar.on("click", ".bottom-panel-hide-btn", function (e) {
@@ -860,9 +845,8 @@ define(function (require, exports, module) {
860845
});
861846

862847
// Double-click on empty tab bar area toggles maximize.
863-
// Exclude tabs themselves, action buttons, and the add button.
864848
_$tabBar.on("dblclick", function (e) {
865-
if ($(e.target).closest(".bottom-panel-tab, .bottom-panel-tab-close-btn, .bottom-panel-hide-btn, .bottom-panel-maximize-btn, .bottom-panel-add-btn").length) {
849+
if ($(e.target).closest(".bottom-panel-tab, .bottom-panel-tab-close-btn, .bottom-panel-hide-btn, .bottom-panel-maximize-btn").length) {
866850
return;
867851
}
868852
_toggleMaximize();
@@ -1088,7 +1072,12 @@ define(function (require, exports, module) {
10881072
// Clear internal state BEFORE hiding the container so the
10891073
// panelCollapsed handler sees an empty _openIds and doesn't
10901074
// redundantly update the stacks.
1091-
_openIds = [];
1075+
// The Quick Access panel stays pinned at index 0.
1076+
if (_defaultPanelId) {
1077+
_openIds = [_defaultPanelId];
1078+
} else {
1079+
_openIds = [];
1080+
}
10921081
_activeId = null;
10931082

10941083
if (_$container && _$container.is(":visible")) {
@@ -1098,8 +1087,6 @@ define(function (require, exports, module) {
10981087

10991088
_updateBottomPanelTabBar();
11001089

1101-
// Fire one EVENT_PANEL_HIDDEN per panel for stack tracking.
1102-
// No intermediate EVENT_PANEL_SHOWN events are emitted.
11031090
for (let i = 0; i < closedIds.length; i++) {
11041091
exports.trigger(EVENT_PANEL_HIDDEN, closedIds[i]);
11051092
}

0 commit comments

Comments
 (0)