Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/browser/app/profile/features.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pref('zen.welcome-screen.seen', false, sticky);
pref('zen.tabs.vertical', true);
pref('zen.tabs.vertical.right-side', false);
pref('zen.tabs.rename-tabs', true);
pref('zen.tabs.essentials.max', 12);
pref('zen.tabs.essentials.height', 0); // In vh units
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove zen.tabs.essentials.height, let's try to keep PRs centralized on fixing a specific problem

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addresses the problem identified...

Issue with overflowing over the window when there are too many

Did you have something else in mind for handling overflow?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add a max height for the essentials container and make it overflowable with CSS

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we encounter the same issue. There's no specific magic number for the height that makes sense for all users. It's highly dependent on the number of essentials, rows/width, and screen size.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if make it overflow, it can have a "random" number specified until we put this zen.tabs.essentials.height back, no?

Copy link
Author

@blakegearin blakegearin Jun 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PauloDaniel1993 I'm not sure I understand your question.

By default zen.tabs.essentials.height is not active. Essentials are added normally, and the height and rows adjust based on the width chosen by the user. Once it's changed to something other than 0, you get either expansion or scrolling depending on how many essentials there are and the screen height (since the number is vh units). There are screenshots in the description.

Because of this behavior, I don't think it makes sense to pick an arbitrary number. This would cause the code change from being passive and opt-in to something that will visually change how the essentials look for many users.

pref('zen.tabs.show-newtab-vertical', true);

pref('zen.ctrlTab.show-pending-tabs', false);
Expand Down
21 changes: 21 additions & 0 deletions src/zen/common/ZenUIManager.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ var gZenUIManager = {
'zen.urlbar.show-domain-only-in-sidebar',
true
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
'essentialsHeight',
'zen.tabs.essentials.height',
0,
this._updateEssentialsHeight.bind(this)
);

gURLBar._zenTrimURL = this.urlbarTrim.bind(this);

Expand Down Expand Up @@ -62,13 +69,27 @@ var gZenUIManager = {
SessionStore.promiseAllWindowsRestored.then(() => {
this._hasLoadedDOM = true;
this.updateTabsToolbar();
this._updateEssentialsHeight();
});

window.addEventListener('TabClose', this.onTabClose.bind(this));

gZenMediaController.init();
},

_updateEssentialsHeight() {
const essentialsWrapper = document.getElementById('zen-essentials');
if (!essentialsWrapper) return;

essentialsWrapper.style.setProperty('--zen-essentials-height', `${this.essentialsHeight}vh`);

if (this.essentialsHeight === 0) {
essentialsWrapper.setAttribute('data-essentials-height', '0');
} else {
essentialsWrapper.removeAttribute('data-essentials-height');
}
},

handleMouseDown(event) {
this._lastClickPosition = {
clientX: event.clientX,
Expand Down
14 changes: 12 additions & 2 deletions src/zen/tabs/ZenPinnedTabManager.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,18 @@
}

class ZenPinnedTabManager extends ZenDOMOperatedFeature {
MAX_ESSENTIALS_TABS = 12;

async init() {
if (!this.enabled) {
return;
}

XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'zenTabsEssentialsMax',
'zen.tabs.essentials.max',
12
);

this._canLog = Services.prefs.getBoolPref('zen.pinned-tab-manager.debug', false);
this.observer = new ZenPinnedTabsObserver();
this._initClosePinnedTabShortcut();
Expand All @@ -71,6 +77,10 @@
gZenWorkspaces._resolvePinnedInitialized();
}

get MAX_ESSENTIALS_TABS() {
return lazy.zenTabsEssentialsMax;
}

async onWorkspaceChange(newWorkspace, onInit) {
if (!this.enabled || PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
Expand Down
56 changes: 55 additions & 1 deletion src/zen/tabs/zen-tabs/vertical-tabs.css
Original file line number Diff line number Diff line change
Expand Up @@ -1253,19 +1253,31 @@

#zen-essentials {
z-index: 1;
overflow: hidden;

&:not([data-essentials-height="0"]) {
max-height: var(--zen-essentials-height);
}
}

/* Container for essential items (often pinned/favorite tabs) */
.zen-essentials-container {
will-change: transform;

padding-bottom: var(--zen-toolbox-padding);
overflow: hidden;
overflow-y: auto;
overflow-x: hidden;
gap: 4px;
transition:
max-height 0.3s ease-out,
grid-template-columns 0.3s ease-out;
opacity: 1;

#zen-essentials:not([data-essentials-height="0"]) & {
height: 100%;
max-height: var(--zen-essentials-height);
}

grid-template-columns: repeat(auto-fit, minmax(max(23.7%, 48px), 1fr));
&[data-hack-type='1'] {
grid-template-columns: repeat(auto-fit, minmax(max(30%, 48px), auto));
Expand Down Expand Up @@ -1303,6 +1315,48 @@
&[cloned] {
pointer-events: none;
}

&[overflowing] {
--zen-scrollbar-overflow-background: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.08));

&::before {
content: '';
position: sticky;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 1px;
opacity: 0;
pointer-events: none;
transition: opacity 0.1s;
background-color: var(--zen-scrollbar-overflow-background);
grid-column: 1 / -1;
}

&::after {
content: '';
position: sticky;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 1px;
opacity: 0;
pointer-events: none;
transition: opacity 0.1s;
background-color: var(--zen-scrollbar-overflow-background);
grid-column: 1 / -1;
}
}

&[overflowing]:not([scrolledtostart])::before {
opacity: 1;
}

&[overflowing]:not([scrolledtoend])::after {
opacity: 1;
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nearly identical to src/zen/workspaces/zen-workspaces.css (source)

}

/* Style tabs within the Essentials container (and a related welcome sidebar) */
Expand Down
35 changes: 35 additions & 0 deletions src/zen/workspaces/ZenWorkspaces.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,17 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
essentialsContainer.setAttribute('container', container);
document.getElementById('zen-essentials').appendChild(essentialsContainer);

this._updateEssentialsOverflow(essentialsContainer);

essentialsContainer.addEventListener('scroll', () => {
this._updateEssentialsOverflow(essentialsContainer);
});

const resizeObserver = new ResizeObserver(() => {
this._updateEssentialsOverflow(essentialsContainer);
});
resizeObserver.observe(essentialsContainer);

// Set an initial hidden state if the essentials section is not supposed
// to be shown on the current workspace
if (
Expand All @@ -441,6 +452,30 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
return essentialsContainer;
}

_updateEssentialsOverflow(container) {
const isOverflowing = container.scrollHeight > container.clientHeight;
const isAtStart = container.scrollTop === 0;
const isAtEnd = (container.scrollTop + container.clientHeight) >= (container.scrollHeight - 1);

if (isOverflowing) {
container.setAttribute('overflowing', 'true');
} else {
container.removeAttribute('overflowing');
}

if (isAtStart) {
container.setAttribute('scrolledtostart', 'true');
} else {
container.removeAttribute('scrolledtostart');
}

if (isAtEnd) {
container.setAttribute('scrolledtoend', 'true');
} else {
container.removeAttribute('scrolledtoend');
}
}

getCurrentEssentialsContainer() {
const currentWorkspace = this.getActiveWorkspaceFromCache();
return this.getEssentialsSection(currentWorkspace?.containerTabId);
Expand Down