Skip to content

Commit ceb24ea

Browse files
devvaannshabose
authored andcommitted
feat: add support to maximize/restore bottom panel window
1 parent 37b1f92 commit ceb24ea

4 files changed

Lines changed: 195 additions & 2 deletions

File tree

src/nls/root/strings.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,8 @@ define({
12561256
"BOTTOM_PANEL_HIDE_TOGGLE": "Hide Bottom Panel",
12571257
"BOTTOM_PANEL_DEFAULT_TITLE": "Quick Access",
12581258
"BOTTOM_PANEL_DEFAULT_HEADING": "Open a Panel",
1259+
"BOTTOM_PANEL_MAXIMIZE": "Maximize Panel",
1260+
"BOTTOM_PANEL_RESTORE": "Restore Panel Size",
12591261

12601262
"CMD_FIND_DOCUMENT_SYMBOLS": "Find Document Symbols",
12611263
"CMD_FIND_PROJECT_SYMBOLS": "Find Project Symbols",

src/styles/Extn-BottomPanelTabs.less

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,36 @@
203203
flex: 0 0 auto;
204204
}
205205

206+
.bottom-panel-maximize-btn {
207+
display: flex;
208+
align-items: center;
209+
justify-content: center;
210+
width: 1.6rem;
211+
height: 1.4rem;
212+
margin-right: 0.15rem;
213+
border-radius: 3px;
214+
cursor: pointer;
215+
color: #666;
216+
font-size: 0.7rem;
217+
-webkit-text-stroke: 0.4px;
218+
line-height: 1;
219+
transition: color 0.12s ease, background-color 0.12s ease;
220+
221+
.dark & {
222+
color: #aaa;
223+
}
224+
225+
&:hover {
226+
background-color: rgba(0, 0, 0, 0.1);
227+
color: #333;
228+
229+
.dark & {
230+
background-color: rgba(255, 255, 255, 0.12);
231+
color: #eee;
232+
}
233+
}
234+
}
235+
206236
.bottom-panel-hide-btn {
207237
display: flex;
208238
align-items: center;

src/view/PanelView.js

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ define(function (require, exports, module) {
7070
/** @type {string|null} The panel ID of the currently visible (active) tab */
7171
let _activeId = null;
7272

73+
/** @type {boolean} Whether the bottom panel is currently maximized */
74+
let _isMaximized = false;
75+
76+
/** @type {number|null} The panel height before maximize, for restore */
77+
let _preMaximizeHeight = null;
78+
79+
/** @type {jQueryObject} The editor holder element, passed from WorkspaceManager */
80+
let _$editorHolder = null;
81+
82+
/** @type {function} recomputeLayout callback from WorkspaceManager */
83+
let _recomputeLayout = null;
84+
7385
// --- Tab helper functions ---
7486

7587
/**
@@ -324,6 +336,7 @@ define(function (require, exports, module) {
324336
// No more tabs - hide the container
325337
_activeId = null;
326338
if (_$container) {
339+
restoreIfMaximized();
327340
Resizer.hide(_$container[0]);
328341
}
329342
}
@@ -389,11 +402,15 @@ define(function (require, exports, module) {
389402
* @param {jQueryObject} $container The bottom panel container element.
390403
* @param {jQueryObject} $tabBar The tab bar element inside the container.
391404
* @param {jQueryObject} $tabsOverflow The scrollable area holding tab elements.
405+
* @param {jQueryObject} $editorHolder The editor holder element (for maximize height calculation).
406+
* @param {function} recomputeLayoutFn Callback to trigger workspace layout recomputation.
392407
*/
393-
function init($container, $tabBar, $tabsOverflow) {
408+
function init($container, $tabBar, $tabsOverflow, $editorHolder, recomputeLayoutFn) {
394409
_$container = $container;
395410
_$tabBar = $tabBar;
396411
_$tabsOverflow = $tabsOverflow;
412+
_$editorHolder = $editorHolder;
413+
_recomputeLayout = recomputeLayoutFn;
397414

398415
// Tab bar click handlers
399416
_$tabBar.on("click", ".bottom-panel-tab-close-btn", function (e) {
@@ -421,9 +438,129 @@ define(function (require, exports, module) {
421438
_$tabBar.on("click", ".bottom-panel-hide-btn", function (e) {
422439
e.stopPropagation();
423440
if (_$container.is(":visible")) {
441+
restoreIfMaximized();
424442
Resizer.hide(_$container[0]);
425443
}
426444
});
445+
446+
// Maximize/restore toggle button
447+
_$tabBar.on("click", ".bottom-panel-maximize-btn", function (e) {
448+
e.stopPropagation();
449+
_toggleMaximize();
450+
});
451+
452+
// Double-click on tab bar toggles maximize (exclude action buttons)
453+
_$tabBar.on("dblclick", function (e) {
454+
if ($(e.target).closest(".bottom-panel-tab-close-btn, .bottom-panel-hide-btn, .bottom-panel-maximize-btn").length) {
455+
return;
456+
}
457+
_toggleMaximize();
458+
});
459+
}
460+
461+
/**
462+
* Toggle maximize/restore of the bottom panel.
463+
* @private
464+
*/
465+
function _toggleMaximize() {
466+
if (!_$container || !_$container.is(":visible")) {
467+
return;
468+
}
469+
if (_isMaximized) {
470+
_restorePanel();
471+
} else {
472+
_maximizePanel();
473+
}
474+
}
475+
476+
/**
477+
* Maximize the bottom panel to fill all available vertical space.
478+
* @private
479+
*/
480+
function _maximizePanel() {
481+
_preMaximizeHeight = _$container.height();
482+
let maxHeight = _$editorHolder.height() + _$container.height();
483+
_$container.height(maxHeight);
484+
_isMaximized = true;
485+
_updateMaximizeButton();
486+
if (_recomputeLayout) {
487+
_recomputeLayout();
488+
}
489+
}
490+
491+
/**
492+
* Restore the bottom panel to its pre-maximize height.
493+
* @private
494+
*/
495+
function _restorePanel() {
496+
if (_preMaximizeHeight !== null) {
497+
_$container.height(_preMaximizeHeight);
498+
}
499+
_isMaximized = false;
500+
_preMaximizeHeight = null;
501+
_updateMaximizeButton();
502+
if (_recomputeLayout) {
503+
_recomputeLayout();
504+
}
505+
}
506+
507+
/**
508+
* Update the maximize button icon and tooltip based on current state.
509+
* @private
510+
*/
511+
function _updateMaximizeButton() {
512+
if (!_$tabBar) {
513+
return;
514+
}
515+
let $btn = _$tabBar.find(".bottom-panel-maximize-btn");
516+
let $icon = $btn.find("i");
517+
if (_isMaximized) {
518+
$icon.removeClass("fa-up-right-and-down-left-from-center")
519+
.addClass("fa-down-left-and-up-right-to-center");
520+
$btn.attr("title", Strings.BOTTOM_PANEL_RESTORE);
521+
} else {
522+
$icon.removeClass("fa-down-left-and-up-right-to-center")
523+
.addClass("fa-up-right-and-down-left-from-center");
524+
$btn.attr("title", Strings.BOTTOM_PANEL_MAXIMIZE);
525+
}
526+
}
527+
528+
/**
529+
* Exit maximize state without resizing (for external callers like drag-resize).
530+
* Clears internal maximize state and resets the button icon.
531+
*/
532+
function exitMaximizeOnResize() {
533+
if (!_isMaximized) {
534+
return;
535+
}
536+
_isMaximized = false;
537+
_preMaximizeHeight = null;
538+
_updateMaximizeButton();
539+
}
540+
541+
/**
542+
* Restore the container's CSS height to the pre-maximize value and clear maximize state.
543+
* Must be called BEFORE Resizer.hide() so the Resizer reads the correct height.
544+
* If not maximized, this is a no-op.
545+
*/
546+
function restoreIfMaximized() {
547+
if (!_isMaximized) {
548+
return;
549+
}
550+
if (_preMaximizeHeight !== null) {
551+
_$container.height(_preMaximizeHeight);
552+
}
553+
_isMaximized = false;
554+
_preMaximizeHeight = null;
555+
_updateMaximizeButton();
556+
}
557+
558+
/**
559+
* Returns true if the bottom panel is currently maximized.
560+
* @return {boolean}
561+
*/
562+
function isMaximized() {
563+
return _isMaximized;
427564
}
428565

429566
/**
@@ -459,6 +596,7 @@ define(function (require, exports, module) {
459596
_activeId = null;
460597

461598
if (_$container && _$container.is(":visible")) {
599+
restoreIfMaximized();
462600
Resizer.hide(_$container[0]);
463601
}
464602

@@ -480,6 +618,9 @@ define(function (require, exports, module) {
480618
exports.init = init;
481619
exports.getOpenBottomPanelIDs = getOpenBottomPanelIDs;
482620
exports.hideAllOpenPanels = hideAllOpenPanels;
621+
exports.exitMaximizeOnResize = exitMaximizeOnResize;
622+
exports.restoreIfMaximized = restoreIfMaximized;
623+
exports.isMaximized = isMaximized;
483624
//events
484625
exports.EVENT_PANEL_HIDDEN = EVENT_PANEL_HIDDEN;
485626
exports.EVENT_PANEL_SHOWN = EVENT_PANEL_SHOWN;

src/view/WorkspaceManager.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ define(function (require, exports, module) {
215215
// FIXME (issue #4564) Workaround https://github.com/codemirror/CodeMirror/issues/1787
216216
triggerUpdateLayout();
217217

218+
// Re-apply maximize height when the window resizes so the panel stays maximized
219+
if (PanelView.isMaximized() && $bottomPanelContainer && $bottomPanelContainer.is(":visible")) {
220+
let maxHeight = $editorHolder.height() + $bottomPanelContainer.height();
221+
$bottomPanelContainer.height(maxHeight);
222+
triggerUpdateLayout();
223+
}
224+
218225
if (!windowResizing) {
219226
windowResizing = true;
220227

@@ -357,6 +364,10 @@ define(function (require, exports, module) {
357364
let $bottomPanelTabBar = $('<div id="bottom-panel-tab-bar"></div>');
358365
let $bottomPanelTabsOverflow = $('<div class="bottom-panel-tabs-overflow"></div>');
359366
let $tabBarActions = $('<div class="bottom-panel-tab-bar-actions"></div>');
367+
$tabBarActions.append(
368+
$('<span class="bottom-panel-maximize-btn"><i class="fa-solid fa-up-right-and-down-left-from-center"></i></span>')
369+
.attr('title', Strings.BOTTOM_PANEL_MAXIMIZE)
370+
);
360371
$tabBarActions.append(
361372
$('<span class="bottom-panel-hide-btn"><i class="fa-solid fa-chevron-down"></i></span>')
362373
.attr('title', Strings.BOTTOM_PANEL_HIDE)
@@ -368,7 +379,8 @@ define(function (require, exports, module) {
368379
$bottomPanelContainer.hide();
369380

370381
// Initialize PanelView with container DOM references and tab bar click handlers
371-
PanelView.init($bottomPanelContainer, $bottomPanelTabBar, $bottomPanelTabsOverflow);
382+
PanelView.init($bottomPanelContainer, $bottomPanelTabBar, $bottomPanelTabsOverflow,
383+
$editorHolder, recomputeLayout);
372384

373385
// Create status bar chevron toggle for bottom panel
374386
$statusBarPanelToggle = $('<div id="status-panel-toggle" class="indicator global-indicator"><i class="fa-solid fa-chevron-up"></i></div>')
@@ -378,6 +390,7 @@ define(function (require, exports, module) {
378390
$statusBarPanelToggle.on("click", function () {
379391
_statusBarToggleInProgress = true;
380392
if ($bottomPanelContainer.is(":visible")) {
393+
PanelView.restoreIfMaximized();
381394
Resizer.hide($bottomPanelContainer[0]);
382395
triggerUpdateLayout();
383396
} else if (PanelView.getOpenBottomPanelIDs().length > 0) {
@@ -394,7 +407,13 @@ define(function (require, exports, module) {
394407
200, false, undefined, true);
395408
listenToResize($bottomPanelContainer);
396409

410+
// Exit maximize state when the user manually drags the resizer
411+
$bottomPanelContainer.on("panelResizeEnd", function () {
412+
PanelView.exitMaximizeOnResize();
413+
});
414+
397415
$bottomPanelContainer.on("panelCollapsed", function () {
416+
PanelView.exitMaximizeOnResize();
398417
$statusBarPanelToggle.find("i")
399418
.removeClass("fa-chevron-down")
400419
.addClass("fa-chevron-up");
@@ -609,6 +628,7 @@ define(function (require, exports, module) {
609628
function _handleEscapeKey() {
610629
// Collapse the entire bottom panel container, keeping all tabs intact
611630
if ($bottomPanelContainer && $bottomPanelContainer.is(":visible")) {
631+
PanelView.restoreIfMaximized();
612632
Resizer.hide($bottomPanelContainer[0]);
613633
triggerUpdateLayout();
614634
return true;

0 commit comments

Comments
 (0)