Skip to content

feat: Zen Folders #9355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 50 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9ade18b
Start working on zen folders
octaviusz Jul 7, 2025
fe4ffab
Rework zen-folder SessionStore
octaviusz Jul 7, 2025
82e0041
Merge branch 'dev' into zen-folders
octaviusz Jul 7, 2025
5dba68b
Refactor restoreDataFromSessionStore
octaviusz Jul 7, 2025
3239778
fix linter
octaviusz Jul 7, 2025
10c20c3
Fix preserve folder order on restore
octaviusz Jul 8, 2025
41e01ef
Feat allow dragging tabs into zen-folder
octaviusz Jul 8, 2025
6c5fe10
Fix ensure collapsed folders are hidden on session restore
octaviusz Jul 8, 2025
575ace6
Feat store parentId nested folders
octaviusz Jul 9, 2025
66c66dd
Merge branch 'dev' into zen-folders
octaviusz Jul 9, 2025
19280c6
feat: Implement tabs list popup
octaviusz Jul 11, 2025
8a19713
refactor: Move tabs popup to `popups.inc`
octaviusz Jul 12, 2025
cd95327
feat: Implement drag-and-drop folder into folder
octaviusz Jul 12, 2025
5c5a351
Merge branch 'dev' into zen-folders
mr-cheffy Jul 13, 2025
1ae7d6c
feat: Improved UI for search panel, b=no-bug, c=folders
mr-cheffy Jul 13, 2025
e0335f8
fix: Add extra margin when animating collapsed folders, b=no-bug, c=f…
mr-cheffy Jul 13, 2025
4a5582f
Merge branch 'dev' into zen-folders
mr-cheffy Jul 13, 2025
3ca8d75
feat: Implement tab group rename and other UI changes, b=no-bug, c=fo…
mr-cheffy Jul 13, 2025
051bb91
Merge branch 'dev' into zen-folders
mr-cheffy Jul 13, 2025
e544154
feat: Add animated folder dots and adaptive search popup positioning
octaviusz Jul 14, 2025
d657263
Merge branch 'dev' into zen-folders
octaviusz Jul 15, 2025
09028a3
fix: resolve conflicts
octaviusz Jul 16, 2025
f6ed1ce
fix: Correct active state indication for collapsed folders
octaviusz Jul 16, 2025
8a1a328
feat: Allow folders to be double clicked, b=no-bug, c=common, folders
mr-cheffy Jul 16, 2025
a8dd3c0
fix: incorrect tab order
octaviusz Jul 16, 2025
a4728e7
Merge branch 'zen-folders' of github.com:octaviusz/desktop into zen-f…
octaviusz Jul 16, 2025
5b14b31
chore: Update prefs to the rust version, b=no-bug, c=folders
mr-cheffy Jul 16, 2025
eedced9
Merge branch 'dev' into zen-folders
mr-cheffy Jul 16, 2025
fa6dafa
fix: better handling of subfolders
octaviusz Jul 16, 2025
9fafd9c
Merge branch 'dev' into zen-folders
mr-cheffy Jul 16, 2025
2cf065f
chore: Improve dynamic spacing when drag and dropping and fixed split…
mr-cheffy Jul 16, 2025
1f3fc1d
Merge branch 'dev' into zen-folders
mr-cheffy Jul 16, 2025
35f9d80
feat: Empty tab and improve drag and drop
octaviusz Jul 18, 2025
e64b9f0
fix: add tab search event once
octaviusz Jul 18, 2025
3c9fafb
Merge branch 'dev' into zen-folders
octaviusz Jul 18, 2025
49aa7bf
fix: Empty tab should always be at first position
octaviusz Jul 18, 2025
0e69678
Merge branch 'dev' into zen-folders
mr-cheffy Jul 19, 2025
02660ed
feat: improve drag and drop interaction with folders
octaviusz Jul 20, 2025
8905ea2
feat: Improve drag-and-drop interaction for zen folders
octaviusz Jul 21, 2025
dc0e1c7
fix: Improve zen folder session restoration and visibility
octaviusz Jul 22, 2025
fea5d41
fix: Correct visible element indexing
octaviusz Jul 22, 2025
5a143d9
fix: Correct restore subfolder order
octaviusz Jul 23, 2025
8c36f43
feat: Use empty tabs and dont highlight current folder we currently a…
mr-cheffy Jul 23, 2025
a01e6cf
Merge branch 'dev' into zen-folders
octaviusz Jul 24, 2025
3c6d1d3
Merge branch 'dev' into zen-folders
octaviusz Jul 25, 2025
a2b20a3
feat: persist and restore split-view group state in subfolders
octaviusz Jul 27, 2025
a17bf25
fix: npm run pretty
octaviusz Jul 27, 2025
09381aa
Merge branch 'dev' into zen-folders
octaviusz Jul 27, 2025
613c6c4
fix: dropIndicator and transform for split-view-group
octaviusz Jul 27, 2025
71ebf5b
fix: Formatting
octaviusz Jul 27, 2025
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
10 changes: 10 additions & 0 deletions src/browser/base/content/zen-panels/popups.inc
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation"/>
<menuitem id="context_zenDeleteWorkspace" data-l10n-id="zen-workspaces-panel-context-delete" command="cmd_zenCtxDeleteWorkspace"/>
</menupopup>

<panel id="zen-folder-tabs-popup" type="arrow" orient="vertical">
<hbox class="tabs-list-header">
<html:input id="zen-folder-tabs-list-search" placeholder="Search tabs" type="search"/>
<image class="zen-folder-tabs-list-search-icon" src="chrome://global/skin/icons/search-glass.svg"/>
</hbox>
<scrollbox class="zen-folder-tabs-list-scrollbox" flex="1">
<vbox id="zen-folder-tabs-list"></vbox>
</scrollbox>
</panel>
41 changes: 25 additions & 16 deletions src/browser/components/sessionstore/SessionStore-sys-mjs.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e586e4fbd 100644
index be029379c1..704db605e9 100644
--- a/browser/components/sessionstore/SessionStore.sys.mjs
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
@@ -2120,7 +2120,6 @@ var SessionStoreInternal = {
Expand All @@ -13,13 +13,13 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
@@ -2353,11 +2352,9 @@ var SessionStoreInternal = {
tabbrowser.selectedTab.label;
}

- if (AppConstants.platform != "macosx") {
// Until we decide otherwise elsewhere, this window is part of a series
// of closing windows to quit.
winData._shouldRestore = true;
- }

// Store the window's close date to figure out when each individual tab
// was closed. This timestamp should allow re-arranging data based on how
@@ -3303,7 +3300,7 @@ var SessionStoreInternal = {
Expand All @@ -30,7 +30,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
+ if (aTab == aWindow.FirefoxViewHandler.tab || aTab.hasAttribute("zen-empty-tab")) {
return;
}

@@ -4012,6 +4009,11 @@ var SessionStoreInternal = {
Math.min(tabState.index, tabState.entries.length)
);
Expand All @@ -40,7 +40,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
+ tabState.zenIsGlance = false;
+ tabState.zenGlanceId = null;
+ tabState.zenHasStaticLabel = false;

if (inBackground === false) {
aWindow.gBrowser.selectedTab = newTab;
@@ -4448,6 +4450,7 @@ var SessionStoreInternal = {
Expand All @@ -52,7 +52,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
skipLoad: true,
preferredRemoteType,
@@ -5303,7 +5306,7 @@ var SessionStoreInternal = {

for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
let tab = tabbrowser.tabs[i];
- if (homePages.includes(tab.linkedBrowser.currentURI.spec)) {
Expand All @@ -62,7 +62,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
}
@@ -5363,7 +5366,7 @@ var SessionStoreInternal = {
}

let workspaceID = aWindow.getWorkspaceID();
- if (workspaceID) {
+ if (workspaceID && !(this.isLastRestorableWindow() && AppConstants.platform == "macosx")) {
Expand All @@ -71,14 +71,14 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
},
@@ -5554,14 +5557,15 @@ var SessionStoreInternal = {
}

let tabbrowser = aWindow.gBrowser;
- let tabs = tabbrowser.tabs;
+ let tabs = aWindow.gZenWorkspaces.allStoredTabs;
/** @type {WindowStateData} */
let winData = this._windows[aWindow.__SSi];
let tabsData = (winData.tabs = []);

+ winData.splitViewData = aWindow.gZenViewSplitter?.storeDataForSessionStore();
// update the internal state data for this window
for (let tab of tabs) {
Expand All @@ -87,7 +87,15 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
continue;
}
let tabData = lazy.TabState.collect(tab, TAB_CUSTOM_VALUES.get(tab));
@@ -5580,8 +5584,8 @@ var SessionStoreInternal = {
@@ -5569,6 +5573,7 @@ var SessionStoreInternal = {
tabsData.push(tabData);
}

+ winData.folders = aWindow.gZenFolders?.storeDataForSessionStore() || [];
// update tab group state for this window
winData.groups = [];
for (let tabGroup of aWindow.gBrowser.tabGroups) {
@@ -5580,8 +5585,8 @@ var SessionStoreInternal = {
// We don't store the Firefox View tab in Session Store, so if it was the last selected "tab" when
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
// since it's only inserted into the tab strip after it's selected).
Expand All @@ -98,7 +106,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
winData.title = tabbrowser.tabs[0].label;
}
winData.selected = selectedIndex;
@@ -5693,8 +5697,8 @@ var SessionStoreInternal = {
@@ -5693,8 +5698,8 @@ var SessionStoreInternal = {
// selectTab represents.
let selectTab = 0;
if (overwriteTabs) {
Expand All @@ -108,17 +116,18 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
+ selectTab = Math.max(selectTab, 0);
selectTab = Math.min(selectTab, winData.tabs.length);
}
@@ -5737,6 +5741,7 @@ var SessionStoreInternal = {

@@ -5737,6 +5742,8 @@ var SessionStoreInternal = {
winData.tabs,
winData.groups ?? []
);
+ aWindow.gZenViewSplitter?.restoreDataFromSessionStore(winData.splitViewData);
+ aWindow.gZenFolders?.restoreDataFromSessionStore(winData.folders);
this._log.debug(
`restoreWindow, createTabsForSessionRestore returned ${tabs.length} tabs`
);
@@ -6286,6 +6291,22 @@ var SessionStoreInternal = {
@@ -6286,6 +6293,22 @@ var SessionStoreInternal = {

// Most of tabData has been restored, now continue with restoring
// attributes that may trigger external events.
+ if (tabData.zenEssential) {
Expand All @@ -137,6 +146,6 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e
+ if (tabData.zenDefaultUserContextId) {
+ tab.setAttribute("zenDefaultUserContextId", true);
+ }

if (tabData.pinned) {
tabbrowser.pinTab(tab);
29 changes: 20 additions & 9 deletions src/browser/components/tabbrowser/content/tab-js.patch
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,42 @@ index 793ba822f087f4d198c9876ed208ff16d8a41e3b..f0c4bc58d7d48491e0c0ab9eb3e915b1
".tab-label":
@@ -180,7 +183,7 @@
}

set _visuallySelected(val) {
- if (val == this.hasAttribute("visuallyselected")) {
+ if (val == this.hasAttribute("visuallyselected") || (!val && this.linkedBrowser?.closest('.browserSidebarContainer').classList.contains('zen-glance-background'))) {
return;
}

@@ -216,7 +219,7 @@
}

get visible() {
- return this.isOpen && !this.hidden && !this.group?.collapsed;
+ return this.isOpen && !this.hidden && !this.group?.collapsed && !this.hasAttribute("zen-empty-tab");
}

get hidden() {
@@ -287,7 +290,7 @@
return false;
}

- return true;
+ return !this.hasAttribute("zen-empty-tab");
}

get lastAccessed() {
@@ -364,8 +367,8 @@
}

get group() {
- if (this.parentElement?.tagName == "tab-group") {
- return this.parentElement;
+ if (gBrowser.isTabGroup(this.parentElement?.parentElement)) {
+ return this.parentElement.parentElement;
}
return null;
}
@@ -459,6 +462,8 @@
this.style.MozUserFocus = "ignore";
} else if (
Expand All @@ -72,7 +83,7 @@ index 793ba822f087f4d198c9876ed208ff16d8a41e3b..f0c4bc58d7d48491e0c0ab9eb3e915b1
@@ -513,6 +518,10 @@
this.style.MozUserFocus = "";
}

+ get glanceTab() {
+ return this.querySelector("tab[zen-glance-tab]");
+ }
Expand Down Expand Up @@ -101,7 +112,7 @@ index 793ba822f087f4d198c9876ed208ff16d8a41e3b..f0c4bc58d7d48491e0c0ab9eb3e915b1
+ gBrowser.tabContainer._blockDblClick = true;
+ }
}

on_dblclick(event) {
@@ -596,6 +614,8 @@
animate: true,
Expand All @@ -111,4 +122,4 @@ index 793ba822f087f4d198c9876ed208ff16d8a41e3b..f0c4bc58d7d48491e0c0ab9eb3e915b1
+ gZenPinnedTabManager._onTabResetPinButton(event, this, 'reset');
}
}

Loading