Compare commits

..

31 Commits

Author SHA1 Message Date
mr. m
7ce5fb77b9 no-bug: Update patches 2026-06-21 11:05:33 +02:00
mr. m
08acc6a39e Merge branch 'library' of https://github.com/zen-browser/desktop into library 2026-06-21 10:42:24 +02:00
mr. m
8ae271d982 Animate icons 2026-06-21 10:42:20 +02:00
mr. m
ba26c902fb Merge branch 'dev' into library
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-06-21 10:36:00 +02:00
Andrey Bochkarev
61e631902c gh-14131: Prevent sidebar from flickering when moving a tab (gh-14293)
Co-authored-by: mr. m <mr.m@tuta.com>
2026-06-20 17:18:41 +02:00
JustAdumbPrsn
89a50770a9 Adds library toolbar icon & adjustments to existing keyframes (#13950)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-06-17 13:48:56 +02:00
JustAdumbPrsn
036f764d2b Add Boosts animated icons and minor adjustments (#13938)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-05-29 16:05:49 +02:00
mr. m
2c11b9295e no-bug: Add animated icons 2026-05-29 14:35:48 +02:00
mr. m
d7839cdb91 Merge branch 'dev' into library 2026-05-28 09:14:19 +02:00
mr. m
67cef284dd Merge branch 'dev' into library
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-05-18 16:50:30 +02:00
mr. m
36df7e718f no-bug: Continue library work 2026-05-18 16:46:43 +02:00
mr. m
d5b88ead22 Merge branch 'dev' into library 2026-05-13 20:06:51 +02:00
mr. m
7261eb1688 no-bug: Added history search 2026-05-10 15:54:12 +02:00
mr. m
b5a251a92f Merge branch 'dev' into library
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-05-10 12:27:42 +02:00
JustAdumbPrsn
a217cacfef no-bug: Add basic UI, search implimentation (gh-12755)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-03-31 22:06:17 +02:00
mr. m
a56bcf3d9c no-bug: Small touches 2026-03-28 14:28:12 +01:00
mr. m
5963de1486 Merge branch 'library' of https://github.com/zen-browser/desktop into library 2026-03-28 10:27:18 +01:00
mr. m
57ad5c45e7 Merge branch 'dev' into library
Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-03-28 10:26:32 +01:00
JustAdumbPrsn
e6bebab10a change tab margin (i literally forgot to add 2px at bottom too)
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-03-13 12:34:32 +05:30
JustAdumbPrsn
a8820ed409 en-US locale .ftl for Zen-library
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-03-13 04:02:53 +05:30
JustAdumbPrsn
a82a7fb055 CSS for ZenLibrary but needs more changes :/
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-03-13 03:58:51 +05:30
JustAdumbPrsn
2be85a2890 UI, search (clicking item does nothing)
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-03-13 03:57:11 +05:30
JustAdumbPrsn
9301e1b64c Merge branch 'zen-browser:library' into library 2026-03-13 03:53:15 +05:30
mr. m
1e04f394a5 Merge branch 'dev' into library 2026-03-09 18:18:07 +01:00
JustAdumbPrsn
665f500925 feat: Implement Zen Library data backend (#12701) 2026-03-09 17:58:03 +01:00
JustAdumbPrsn
88ebf6e5da feat: improve section data backend
Signed-off-by: JustAdumbPrsn <73780892+JustAdumbPrsn@users.noreply.github.com>
2026-03-09 20:38:20 +05:30
mr. m
556beb01b0 feat: Add basic search component, b=no-bug, c=common 2026-03-08 12:09:31 +01:00
mr. m
48d5b32a5a feat: Improve transform detection, b=no-bug, c=common 2026-03-07 16:43:41 +01:00
mr. m
4682c8d545 feat: Add components to use, b=no-bug, c=no-component 2026-03-07 16:22:19 +01:00
mr. m
2c5fc47e74 Merge branch 'dev' into library 2026-03-07 12:29:53 +01:00
mr. m
237f0c0ea5 feat: Start implementing Zen Library, b=no-bug, c=common, folders 2026-03-06 10:16:05 +01:00
41 changed files with 4579 additions and 79 deletions

View File

@@ -20,6 +20,8 @@ files:
translation: browser/browser/preferences/zen-preferences.ftl translation: browser/browser/preferences/zen-preferences.ftl
- source: en-US/browser/browser/zen-folders.ftl - source: en-US/browser/browser/zen-folders.ftl
translation: browser/browser/zen-folders.ftl translation: browser/browser/zen-folders.ftl
- source: en-US/browser/browser/zen-library.ftl
translation: browser/browser/zen-library.ftl
- source: en-US/browser/browser/zen-boosts.ftl - source: en-US/browser/browser/zen-boosts.ftl
translation: browser/browser/zen-boosts.ftl translation: browser/browser/zen-boosts.ftl
- source: en-US/browser/browser/zen-space-routing.ftl - source: en-US/browser/browser/zen-space-routing.ftl

View File

@@ -0,0 +1,89 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
library-spaces-section-title = Spaces
library-downloads-section-title = Downloads
library-history-section-title = History
library-boosts-section-title = Boosts
library-search-placeholder =
.placeholder = Search…
library-history-search-placeholder =
.placeholder = Search History…
library-downloads-search-placeholder =
.placeholder = Search Downloads…
library-history-today = Today
library-history-yesterday = Yesterday
library-history-empty = No history found
library-downloads-empty = No downloads found
library-spaces-empty = No spaces available
library-boosts-empty = No boosts yet
library-search-no-results = No results
library-boosts-search-placeholder =
.placeholder = Search Boosts…
library-boost-toggle =
.tooltiptext = Toggle boost for this site
library-boost-context-edit =
.label = Edit Boost
library-boost-context-export =
.label = Export Boost
library-boost-context-delete =
.label = Delete Boost
library-filter-button = Filter
library-history-filter-all =
.label = All time
library-history-filter-today =
.label = Today
library-history-filter-yesterday =
.label = Yesterday
library-history-filter-last-7-days =
.label = Last 7 days
library-history-filter-last-30-days =
.label = Last 30 days
library-downloads-filter-all =
.label = All
library-downloads-filter-completed =
.label = Completed
library-downloads-filter-in-progress =
.label = In progress
library-downloads-filter-failed =
.label = Failed
library-downloads-filter-paused =
.label = Paused
library-item-context-open =
.label = Open
library-item-context-open-glance =
.label = Open in Glance
library-item-context-open-new-tab =
.label = Open in New Tab
library-item-context-open-new-window =
.label = Open in New Window
library-item-context-copy-url =
.label = Copy URL
library-item-context-delete-history =
.label = Forget About This Page
library-item-context-open-source =
.label = Open Source URL
library-item-context-remove =
.label = Remove from History
library-item-context-delete-file =
.label = Delete File
library-history-action-remove =
.tooltiptext = Forget About This Page
library-history-action-open-tab =
.tooltiptext = Open in New Tab
library-downloads-state-downloading = Downloading…
library-downloads-state-canceled = Canceled
library-downloads-state-failed = Failed
library-downloads-state-incomplete = Incomplete

View File

@@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
- name: zen.library.enabled
value: false

View File

@@ -1,5 +1,5 @@
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
index e7e94e13a990c154fb54bda4a3420ca00bdac009..8253b7d403734973729a5982cceafc12bab24f54 100644 index e7e94e13a990c154fb54bda4a3420ca00bdac009..e3b4846e1b198711d3e0047d38da1c1ed58a2ab2 100644
--- a/browser/base/content/navigator-toolbox.inc.xhtml --- a/browser/base/content/navigator-toolbox.inc.xhtml
+++ b/browser/base/content/navigator-toolbox.inc.xhtml +++ b/browser/base/content/navigator-toolbox.inc.xhtml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
@@ -55,3 +55,11 @@ index e7e94e13a990c154fb54bda4a3420ca00bdac009..8253b7d403734973729a5982cceafc12
<toolbar id="nav-bar" <toolbar id="nav-bar"
class="browser-toolbar chromeclass-location" class="browser-toolbar chromeclass-location"
@@ -202,7 +210,6 @@
<toolbartabstop/>
<html:moz-urlbar id="urlbar"
class="urlbar"
- popover="manual"
pageproxystate="invalid"
unifiedsearchbutton-available=""
sap-name="urlbar">

View File

@@ -20,4 +20,5 @@
#include ../../../zen/fonts/jar.inc.mn #include ../../../zen/fonts/jar.inc.mn
#include ../../../zen/boosts/jar.inc.mn #include ../../../zen/boosts/jar.inc.mn
#include ../../../zen/live-folders/jar.inc.mn #include ../../../zen/live-folders/jar.inc.mn
#include ../../../zen/library/jar.inc.mn
#include ../../../zen/space-routing/jar.inc.mn #include ../../../zen/space-routing/jar.inc.mn

View File

@@ -68,5 +68,7 @@
<command id="cmd_zenNewLiveFolder" /> <command id="cmd_zenNewLiveFolder" />
<command id="cmd_zenToggleLibrary" />
<command id="cmd_zenDuplicateTab" /> <command id="cmd_zenDuplicateTab" />
</commandset> </commandset>

View File

@@ -9,6 +9,7 @@
<link rel="localization" href="browser/zen-menubar.ftl"/> <link rel="localization" href="browser/zen-menubar.ftl"/>
<link rel="localization" href="browser/zen-vertical-tabs.ftl"/> <link rel="localization" href="browser/zen-vertical-tabs.ftl"/>
<link rel="localization" href="browser/zen-folders.ftl"/> <link rel="localization" href="browser/zen-folders.ftl"/>
<link rel="localization" href="browser/zen-library.ftl"/>
<link rel="localization" href="browser/zen-boosts.ftl"/> <link rel="localization" href="browser/zen-boosts.ftl"/>
<link rel="localization" href="browser/zen-live-folders.ftl"/> <link rel="localization" href="browser/zen-live-folders.ftl"/>
<link rel="localization" href="browser/zen-space-routing.ftl"/> <link rel="localization" href="browser/zen-space-routing.ftl"/>

View File

@@ -13,6 +13,7 @@
skipintoolbarset="true" skipintoolbarset="true"
context="toolbar-context-menu" context="toolbar-context-menu"
mode="icons"> mode="icons">
<toolbarbutton removable="true" class="chromeclass-toolbar-additional toolbarbutton-1 zen-sidebar-action-button" id="zen-library-button" command="cmd_zenToggleLibrary"></toolbarbutton>
<toolbarbutton removable="true" class="chromeclass-toolbar-additional toolbarbutton-1 zen-sidebar-action-button" id="zen-expand-sidebar-button" command="cmd_zenToggleSidebar" data-l10n-id="sidebar-zen-expand"></toolbarbutton> <toolbarbutton removable="true" class="chromeclass-toolbar-additional toolbarbutton-1 zen-sidebar-action-button" id="zen-expand-sidebar-button" command="cmd_zenToggleSidebar" data-l10n-id="sidebar-zen-expand"></toolbarbutton>
<zen-workspace-icons id="zen-workspaces-button" overflows="false" removable="false"></zen-workspace-icons> <zen-workspace-icons id="zen-workspaces-button" overflows="false" removable="false"></zen-workspace-icons>
<toolbarbutton removable="true" class="chromeclass-toolbar-additional toolbarbutton-1 zen-sidebar-action-button" id="zen-create-new-button" context="zenCreateNewPopup" data-l10n-id="sidebar-zen-create-new"></toolbarbutton> <toolbarbutton removable="true" class="chromeclass-toolbar-additional toolbarbutton-1 zen-sidebar-action-button" id="zen-create-new-button" context="zenCreateNewPopup" data-l10n-id="sidebar-zen-create-new"></toolbarbutton>

View File

@@ -1,8 +1,23 @@
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9ea21b6f6 100644 index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..b9a1cfe3a4a5035d9b06b0b3826a97c52cfcb39e 100644
--- a/browser/components/tabbrowser/content/tabs.js --- a/browser/components/tabbrowser/content/tabs.js
+++ b/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js
@@ -220,7 +220,7 @@ @@ -197,8 +197,12 @@
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_sidebarPositionStart",
- "sidebar.position_start",
- true
+ "zen.tabs.vertical.right-side",
+ true,
+ null,
+ newValue => {
+ return !newValue;
+ }
);
if (gMultiProcessBrowser) {
@@ -220,7 +224,7 @@
this.tooltip = "tabbrowser-tab-tooltip"; this.tooltip = "tabbrowser-tab-tooltip";
@@ -11,7 +26,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.tabDragAndDrop.init(); this.tabDragAndDrop.init();
} }
@@ -444,7 +444,7 @@ @@ -444,7 +448,7 @@
// and we're not hitting the scroll buttons. // and we're not hitting the scroll buttons.
if ( if (
event.button != 0 || event.button != 0 ||
@@ -20,7 +35,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
event.composedTarget.localName == "toolbarbutton" event.composedTarget.localName == "toolbarbutton"
) { ) {
return; return;
@@ -525,7 +525,6 @@ @@ -525,7 +529,6 @@
}); });
} }
} else if (isTabGroupLabel(event.target)) { } else if (isTabGroupLabel(event.target)) {
@@ -28,7 +43,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} else if ( } else if (
event.originalTarget.closest("scrollbox") && event.originalTarget.closest("scrollbox") &&
!Services.prefs.getBoolPref( !Services.prefs.getBoolPref(
@@ -561,6 +560,9 @@ @@ -561,6 +564,9 @@
} }
on_keydown(event) { on_keydown(event) {
@@ -38,7 +53,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
let { altKey, shiftKey } = event; let { altKey, shiftKey } = event;
let [accel, nonAccel] = let [accel, nonAccel] =
AppConstants.platform == "macosx" AppConstants.platform == "macosx"
@@ -755,7 +757,6 @@ @@ -755,7 +761,6 @@
this._updateCloseButtons(); this._updateCloseButtons();
if (!this.#animatingGroups.size) { if (!this.#animatingGroups.size) {
@@ -46,7 +61,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} }
document document
@@ -822,7 +823,7 @@ @@ -822,7 +827,7 @@
} }
get newTabButton() { get newTabButton() {
@@ -55,7 +70,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} }
get verticalMode() { get verticalMode() {
@@ -838,6 +839,7 @@ @@ -838,6 +843,7 @@
} }
get overflowing() { get overflowing() {
@@ -63,7 +78,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
return this.hasAttribute("overflow"); return this.hasAttribute("overflow");
} }
@@ -851,29 +853,56 @@ @@ -851,29 +857,56 @@
if (pinnedChildren?.at(-1)?.id == "pinned-tabs-container-periphery") { if (pinnedChildren?.at(-1)?.id == "pinned-tabs-container-periphery") {
pinnedChildren.pop(); pinnedChildren.pop();
} }
@@ -93,7 +108,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
+ } else if (!isTab(tab)) { + } else if (!isTab(tab)) {
+ tabs.splice(i, 1); + tabs.splice(i, 1);
+ } + }
} + }
+ }; + };
+ expandTabs(pinnedTabs); + expandTabs(pinnedTabs);
+ expandTabs(unpinnedChildren); + expandTabs(unpinnedChildren);
@@ -114,7 +129,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
+ // remove the separator from the list + // remove the separator from the list
+ allTabs.splice(i, 1); + allTabs.splice(i, 1);
+ i--; + i--;
+ } }
+ i++; + i++;
} }
- -
@@ -130,7 +145,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} }
get allSplitViews() { get allSplitViews() {
@@ -958,29 +987,28 @@ @@ -958,29 +991,28 @@
return this.#focusableItems; return this.#focusableItems;
} }
@@ -170,7 +185,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.#focusableItems = focusableItems; this.#focusableItems = focusableItems;
return this.#focusableItems; return this.#focusableItems;
@@ -993,6 +1021,7 @@ @@ -993,6 +1025,7 @@
* focusable (ex, we don't want the splitview container to be focusable, only its children). * focusable (ex, we don't want the splitview container to be focusable, only its children).
*/ */
get dragAndDropElements() { get dragAndDropElements() {
@@ -178,7 +193,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
if (this.#dragAndDropElements) { if (this.#dragAndDropElements) {
return this.#dragAndDropElements; return this.#dragAndDropElements;
} }
@@ -1063,6 +1092,7 @@ @@ -1063,6 +1096,7 @@
_invalidateCachedTabs() { _invalidateCachedTabs() {
this.#allTabs = null; this.#allTabs = null;
this._invalidateCachedVisibleTabs(); this._invalidateCachedVisibleTabs();
@@ -186,7 +201,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} }
_invalidateCachedVisibleTabs() { _invalidateCachedVisibleTabs() {
@@ -1082,7 +1112,8 @@ @@ -1082,7 +1116,8 @@
isContainerVerticalPinnedGrid(tab) { isContainerVerticalPinnedGrid(tab) {
return ( return (
@@ -196,7 +211,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
this.verticalMode && this.verticalMode &&
this.hasAttribute("expanded") && this.hasAttribute("expanded") &&
!this.expandOnHover !this.expandOnHover
@@ -1176,7 +1207,7 @@ @@ -1176,7 +1211,7 @@
if (node == null) { if (node == null) {
// We have a container for non-tab elements at the end of the scrollbox. // We have a container for non-tab elements at the end of the scrollbox.
@@ -205,7 +220,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
} }
node.before(tab); node.before(tab);
@@ -1271,7 +1302,7 @@ @@ -1271,7 +1306,7 @@
// There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and // There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and
// for when the tab strip is overflowed (which is shared by vertical and horizontal tabs); // for when the tab strip is overflowed (which is shared by vertical and horizontal tabs);
// Attach the long click popup to all of them. // Attach the long click popup to all of them.
@@ -214,7 +229,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
const newTab2 = this.newTabButton; const newTab2 = this.newTabButton;
const newTabVertical = document.getElementById( const newTabVertical = document.getElementById(
"vertical-tabs-newtab-button" "vertical-tabs-newtab-button"
@@ -1376,8 +1407,10 @@ @@ -1376,8 +1411,10 @@
*/ */
_handleTabSelect(aInstant) { _handleTabSelect(aInstant) {
let selectedTab = this.selectedItem; let selectedTab = this.selectedItem;
@@ -225,7 +240,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
selectedTab._notselectedsinceload = false; selectedTab._notselectedsinceload = false;
} }
@@ -1386,7 +1419,7 @@ @@ -1386,7 +1423,7 @@
* @param {boolean} [shouldScrollInstantly=false] * @param {boolean} [shouldScrollInstantly=false]
*/ */
#ensureTabIsVisible(tab, shouldScrollInstantly = false) { #ensureTabIsVisible(tab, shouldScrollInstantly = false) {
@@ -234,7 +249,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9
if (arrowScrollbox?.overflowing) { if (arrowScrollbox?.overflowing) {
arrowScrollbox.ensureElementIsVisible(tab, shouldScrollInstantly); arrowScrollbox.ensureElementIsVisible(tab, shouldScrollInstantly);
} }
@@ -1513,7 +1546,7 @@ @@ -1513,7 +1550,7 @@
} }
_notifyBackgroundTab(aTab) { _notifyBackgroundTab(aTab) {

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07ed57bd36 100644 index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..fdf4f8a89fc35a6cf214fb0213f6cd03fb88add9 100644
--- a/browser/components/urlbar/content/UrlbarInput.mjs --- a/browser/components/urlbar/content/UrlbarInput.mjs
+++ b/browser/components/urlbar/content/UrlbarInput.mjs +++ b/browser/components/urlbar/content/UrlbarInput.mjs
@@ -98,6 +98,13 @@ const lazy = XPCOMUtils.declareLazy({ @@ -98,6 +98,13 @@ const lazy = XPCOMUtils.declareLazy({
@@ -117,7 +117,12 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
startLayoutExtend() { startLayoutExtend() {
if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) { if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) {
// Do not expand if the Urlbar does not support being expanded or it is // Do not expand if the Urlbar does not support being expanded or it is
@@ -2954,6 +3023,13 @@ ${ @@ -2950,10 +3019,18 @@ ${
return;
}
+ this.setAttribute("popover", "manual");
this.#updateTextboxPosition();
this.toggleAttribute("breakout-extend", true); this.toggleAttribute("breakout-extend", true);
@@ -131,7 +136,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
// Enable the animation only after the first extend call to ensure it // Enable the animation only after the first extend call to ensure it
// doesn't run when opening a new window. // doesn't run when opening a new window.
if (!this.hasAttribute("breakout-extend-animate")) { if (!this.hasAttribute("breakout-extend-animate")) {
@@ -2981,6 +3057,29 @@ ${ @@ -2981,7 +3058,31 @@ ${
return; return;
} }
@@ -159,9 +164,11 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
+ this.removeAttribute("zen-floating-urlbar"); + this.removeAttribute("zen-floating-urlbar");
+ +
this.toggleAttribute("breakout-extend", false); this.toggleAttribute("breakout-extend", false);
+ this.removeAttribute("popover");
this.#updateTextboxPosition(); this.#updateTextboxPosition();
} }
@@ -3028,7 +3127,7 @@ ${
@@ -3028,7 +3129,7 @@ ${
forceUnifiedSearchButtonAvailable = false forceUnifiedSearchButtonAvailable = false
) { ) {
let prevState = this.getAttribute("pageproxystate"); let prevState = this.getAttribute("pageproxystate");
@@ -170,7 +177,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
this.setAttribute("pageproxystate", state); this.setAttribute("pageproxystate", state);
this._inputContainer.setAttribute("pageproxystate", state); this._inputContainer.setAttribute("pageproxystate", state);
this._identityBox?.setAttribute("pageproxystate", state); this._identityBox?.setAttribute("pageproxystate", state);
@@ -3309,10 +3408,12 @@ ${ @@ -3309,10 +3410,12 @@ ${
} }
this.style.top = px( this.style.top = px(
@@ -183,7 +190,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
); );
} }
@@ -3371,9 +3472,10 @@ ${ @@ -3371,9 +3474,10 @@ ${
return; return;
} }
@@ -195,7 +202,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
); );
this.style.setProperty( this.style.setProperty(
"--urlbar-height", "--urlbar-height",
@@ -3878,6 +3980,7 @@ ${ @@ -3878,6 +3982,7 @@ ${
} }
_toggleActionOverride(event) { _toggleActionOverride(event) {
@@ -203,7 +210,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
if ( if (
event.keyCode == KeyEvent.DOM_VK_SHIFT || event.keyCode == KeyEvent.DOM_VK_SHIFT ||
event.keyCode == KeyEvent.DOM_VK_ALT || event.keyCode == KeyEvent.DOM_VK_ALT ||
@@ -3990,8 +4093,8 @@ ${ @@ -3990,8 +4095,8 @@ ${
if (!this.#isAddressbar) { if (!this.#isAddressbar) {
return val; return val;
} }
@@ -214,7 +221,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
: val; : val;
// Only trim value if the directionality doesn't change to RTL and we're not // Only trim value if the directionality doesn't change to RTL and we're not
// showing a strikeout https protocol. // showing a strikeout https protocol.
@@ -4290,6 +4393,7 @@ ${ @@ -4290,6 +4395,7 @@ ${
resultDetails = null, resultDetails = null,
browser = this.window.gBrowser.selectedBrowser browser = this.window.gBrowser.selectedBrowser
) { ) {
@@ -222,7 +229,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
if (this.#isAddressbar) { if (this.#isAddressbar) {
this.#prepareAddressbarLoad( this.#prepareAddressbarLoad(
url, url,
@@ -4401,6 +4505,10 @@ ${ @@ -4401,6 +4507,10 @@ ${
} }
reuseEmpty = true; reuseEmpty = true;
} }
@@ -233,7 +240,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
if ( if (
where == "tab" && where == "tab" &&
reuseEmpty && reuseEmpty &&
@@ -4408,6 +4516,9 @@ ${ @@ -4408,6 +4518,9 @@ ${
) { ) {
where = "current"; where = "current";
} }
@@ -243,7 +250,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
return where; return where;
} }
@@ -4662,6 +4773,7 @@ ${ @@ -4662,6 +4775,7 @@ ${
this.setResultForCurrentValue(null); this.setResultForCurrentValue(null);
this.handleCommand(); this.handleCommand();
this.controller.clearLastQueryContextCache(); this.controller.clearLastQueryContextCache();
@@ -251,7 +258,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
this._suppressStartQuery = false; this._suppressStartQuery = false;
}); });
@@ -4669,7 +4781,6 @@ ${ @@ -4669,7 +4783,6 @@ ${
contextMenu.addEventListener("popupshowing", () => { contextMenu.addEventListener("popupshowing", () => {
// Close the results pane when the input field contextual menu is open, // Close the results pane when the input field contextual menu is open,
// because paste and go doesn't want a result selection. // because paste and go doesn't want a result selection.
@@ -259,7 +266,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
let controller = let controller =
this.document.commandDispatcher.getControllerForCommand("cmd_paste"); this.document.commandDispatcher.getControllerForCommand("cmd_paste");
@@ -4825,7 +4936,11 @@ ${ @@ -4825,7 +4938,11 @@ ${
if (!engineName && !source && !this.hasAttribute("searchmode")) { if (!engineName && !source && !this.hasAttribute("searchmode")) {
return; return;
} }
@@ -272,7 +279,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
if (this._searchModeIndicatorTitle) { if (this._searchModeIndicatorTitle) {
this._searchModeIndicatorTitle.textContent = ""; this._searchModeIndicatorTitle.textContent = "";
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id"); this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
@@ -5141,6 +5256,7 @@ ${ @@ -5141,6 +5258,7 @@ ${
this.document.l10n.setAttributes( this.document.l10n.setAttributes(
this.inputField, this.inputField,
@@ -280,7 +287,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
l10nId, l10nId,
l10nId == "urlbar-placeholder-with-name" l10nId == "urlbar-placeholder-with-name"
? { name: engineName } ? { name: engineName }
@@ -5264,6 +5380,11 @@ ${ @@ -5264,6 +5382,11 @@ ${
} }
_on_click(event) { _on_click(event) {
@@ -292,7 +299,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
switch (event.target) { switch (event.target) {
case this.inputField: case this.inputField:
case this._inputContainer: case this._inputContainer:
@@ -5356,7 +5477,7 @@ ${ @@ -5356,7 +5479,7 @@ ${
} }
} }
@@ -301,7 +308,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
this.view.autoOpen({ event }); this.view.autoOpen({ event });
} else { } else {
if (this._untrimOnFocusAfterKeydown) { if (this._untrimOnFocusAfterKeydown) {
@@ -5396,9 +5517,16 @@ ${ @@ -5396,9 +5519,16 @@ ${
} }
_on_mousedown(event) { _on_mousedown(event) {
@@ -319,7 +326,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
if ( if (
event.composedTarget != this.inputField && event.composedTarget != this.inputField &&
event.composedTarget != this._inputContainer event.composedTarget != this._inputContainer
@@ -5408,6 +5536,10 @@ ${ @@ -5408,6 +5538,10 @@ ${
this.focusedViaMousedown = !this.focused; this.focusedViaMousedown = !this.focused;
this.#preventClickSelectsAll = this.focused; this.#preventClickSelectsAll = this.focused;
@@ -330,7 +337,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
// Keep the focus status, since the attribute may be changed // Keep the focus status, since the attribute may be changed
// upon calling this.focus(). // upon calling this.focus().
@@ -5443,7 +5575,7 @@ ${ @@ -5443,7 +5577,7 @@ ${
} }
// Don't close the view when clicking on a tab; we may want to keep the // Don't close the view when clicking on a tab; we may want to keep the
// view open on tab switch, and the TabSelect event arrived earlier. // view open on tab switch, and the TabSelect event arrived earlier.
@@ -339,7 +346,7 @@ index 0fba59d62af9d3cd05bfee2cf84cd8b7cf9bfd6e..3997a5109267f378b59aa6510cbacd07
break; break;
} }
@@ -5732,7 +5864,7 @@ ${ @@ -5732,7 +5866,7 @@ ${
// When we are in actions search mode we can show more results so // When we are in actions search mode we can show more results so
// increase the limit. // increase the limit.
let maxResults = let maxResults =

View File

@@ -0,0 +1,69 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-library-icon" width="18" height="18" viewBox="4 4 18 18" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg">
<style>
@property --zen-triangle-anim { syntax: '&lt;number&gt;'; initial-value: 0; inherits: false; }
@property --zen-circle-anim { syntax: '&lt;number&gt;'; initial-value: 0; inherits: false; }
@keyframes StarForward {
0% { transform: rotate(0deg); }
100% { transform: rotate(120deg); }
}
@keyframes TriangleForward {
0% { --zen-triangle-anim: 0; }
100% { --zen-triangle-anim: 1; }
}
@keyframes CircleForward {
0% { --zen-circle-anim: 0; }
100% { --zen-circle-anim: 1; }
}
@keyframes GlowForward {
0% { opacity: 0; }
100% { opacity: 0.4; }
}
@keyframes GlowElementsForward {
0% { opacity: 0; }
100% { opacity: 0.5; }
}
.zen-library-star { transform-origin: 10px 10.2px; animation: StarForward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-triangle-group { transform-origin: 17px 9.2px; animation: TriangleForward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; transform: translate(calc(var(--zen-triangle-anim) * 2px), 0px) rotate(calc(var(--zen-triangle-anim) * 365deg)) scale(max(1 - var(--zen-triangle-anim) / 0.65, (var(--zen-triangle-anim) - 0.65) / 0.35)); }
.zen-library-circle { transform-origin: 0px 0px; animation: CircleForward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; transform: translate(calc(var(--zen-circle-anim) * 1px), calc(var(--zen-circle-anim) * -1.5px)) scale(max(0, max((var(--zen-circle-anim) - 0.75) / 0.25, min(1, 1 - (var(--zen-circle-anim) - 0.3) / 0.35)))); }
.zen-library-glow { filter: blur(2px); animation: GlowForward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-glow-element { filter: blur(2px); animation: GlowElementsForward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-glow-bg, .zen-library-glow-element { fill: transparent !important; stroke: none !important; }
.zen-library-glow-rays { stroke: transparent !important; fill: none !important; }
@media (prefers-color-scheme: dark) {
.zen-library-glow-bg, .zen-library-glow-element { fill: white !important; }
.zen-library-glow-rays { stroke: white !important; }
.zen-library-star:not(.zen-library-glow-element), .zen-library-circle:not(.zen-library-glow-element), .zen-library-triangle:not(.zen-library-glow-element) { fill: white !important; }
}
</style>
<defs>
<mask id="zen-library-box-mask">
<rect x="-10" y="-10" width="40" height="40" fill="white"/>
<rect x="-10" y="11.635" width="40" height="40" fill="black"/>
</mask>
</defs>
<g fill-rule="evenodd">
<g mask="url(#zen-library-box-mask)">
<path class="zen-library-star zen-library-glow-element" d="M 7.773 11.635 C 8.136 11.863 8.24 12.075 8.218 12.294 L 8.036 14.082 C 7.984 14.598 8.584 14.917 8.982 14.585 L 10.362 13.432 C 10.53 13.291 10.764 13.258 10.966 13.347 L 12.61 14.072 C 13.085 14.281 13.574 13.808 13.38 13.327 L 12.701 11.635 C 12.632 11.437 12.675 11.216 12.816 11.058 L 14.014 9.718 C 14.36 9.331 14.061 8.72 13.544 8.756 L 11.75 8.877 C 11.531 8.892 11.322 8.781 11.211 8.591 L 10.307 7.038 C 10.046 6.59 9.373 6.685 9.247 7.188 L 8.808 8.931 C 8.754 9.144 8.585 9.309 8.37 9.355 L 6.613 9.735 C 6.106 9.845 5.988 10.514 6.427 10.79 L 7.773 11.635 Z"/>
<path class="zen-library-star" d="M 7.773 11.635 C 8.136 11.863 8.24 12.075 8.218 12.294 L 8.036 14.082 C 7.984 14.598 8.584 14.917 8.982 14.585 L 10.362 13.432 C 10.53 13.291 10.764 13.258 10.966 13.347 L 12.61 14.072 C 13.085 14.281 13.574 13.808 13.38 13.327 L 12.701 11.635 C 12.632 11.437 12.675 11.216 12.816 11.058 L 14.014 9.718 C 14.36 9.331 14.061 8.72 13.544 8.756 L 11.75 8.877 C 11.531 8.892 11.322 8.781 11.211 8.591 L 10.307 7.038 C 10.046 6.59 9.373 6.685 9.247 7.188 L 8.808 8.931 C 8.754 9.144 8.585 9.309 8.37 9.355 L 6.613 9.735 C 6.106 9.845 5.988 10.514 6.427 10.79 L 7.773 11.635 Z"/>
</g>
<g transform="translate(14, 7.3)">
<circle class="zen-library-circle zen-library-glow-element" cx="0" cy="0" r="1.4"/>
<circle class="zen-library-circle" cx="0" cy="0" r="1"/>
</g>
<g class="zen-library-triangle-group">
<g transform="translate(17, 9.2)">
<path class="zen-library-triangle zen-library-glow-element" d="M -1.1 1.8 C -1.4 2.0, -1.7 1.8, -1.7 1.5 L -1.7 -1.5 C -1.7 -1.8, -1.4 -2.0, -1.1 -1.8 L 1.4 -0.4 C 1.7 -0.2, 1.7 0.2, 1.4 0.4 Z"/>
<path class="zen-library-triangle" d="M -1.1 1.8 C -1.4 2.0, -1.7 1.8, -1.7 1.5 L -1.7 -1.5 C -1.7 -1.8, -1.4 -2.0, -1.1 -1.8 L 1.4 -0.4 C 1.7 -0.2, 1.7 0.2, 1.4 0.4 Z"/>
</g>
</g>
<g class="zen-library-glow">
<path class="zen-library-glow-bg" d="M 6.6 6.6 L 8.04 12.7 L 17.96 12.7 L 19.4 6.6 Z"/>
<path class="zen-library-glow-rays" d="M 6.1 6.6 L 8.04 12.7 L 17.96 12.7 L 19.9 6.6"/>
</g>
<path class="zen-library-box" d="M 7.218 13.287 C 7.218 12.831 7.588 12.461 8.044 12.461 H 17.957 C 18.414 12.461 18.783 12.831 18.783 13.287 V 17.418 C 18.783 19.243 17.304 20.722 15.479 20.722 H 10.523 C 8.698 20.722 7.218 19.243 7.218 17.418 V 13.287 Z M 10.609 14.526 C 10.609 14.07 10.979 13.7 11.435 13.7 H 14.739 C 15.196 13.7 15.565 14.07 15.565 14.526 C 15.565 14.982 15.196 15.352 14.739 15.352 H 11.435 C 10.979 15.352 10.609 14.982 10.609 14.526 Z"/>
</g>
</svg>

View File

@@ -0,0 +1,81 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-boosts-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes zenBoostsCardTilt {
0%, 13.33% { transform: translate(61.889px, 63.143px) scale(1.1) rotate(-15deg); animation-timing-function: cubic-bezier(0.35, 0, 0.685, 1); }
37.77% { transform: translate(61.889px, 68.143px) scale(1.1) rotate(-23deg); animation-timing-function: cubic-bezier(0.25, 0, 0.7, 1); }
64.8% { transform: translate(61.889px, 55.143px) scale(1.1) rotate(-5.4deg); animation-timing-function: cubic-bezier(0.28, 0, 0.68, 1); }
87%, 100% { transform: translate(61.889px, 63.143px) scale(1.1) rotate(-15deg); }
}
@keyframes zenBoostsBrushRotate {
0%, 2.22% { transform: translate(18.247px, 109.504px) scale(1.1) rotate(0deg); animation-timing-function: cubic-bezier(0.6, 0, 0.7, 1); }
32% { transform: translate(18.247px, 112px) scale(1.1) rotate(12deg); animation-timing-function: cubic-bezier(0.3, 0, 0.6, 1); }
52% { transform: translate(18.247px, 97.957px) scale(1.1) rotate(-16.5deg); animation-timing-function: cubic-bezier(0.4, 0, 0.5, 1); }
80%, 100% { transform: translate(18.247px, 109.504px) scale(1.1) rotate(0deg); }
}
@keyframes zenBoostsStarLargeBounce {
0%, 20% { transform: translate(85.002px, 50.174px) rotate(2.014deg) scale(1); animation-timing-function: cubic-bezier(0.29, 0, 0.83, 1); }
33.3% { transform: translate(85.002px, 59px) rotate(2.014deg) scale(1); animation-timing-function: linear; }
42.2% { transform: translate(85.002px, 60.5px) rotate(2.014deg) scale(0); animation-timing-function: linear; }
53.3% { transform: translate(85.002px, 45px) rotate(2.014deg) scale(0); animation-timing-function: cubic-bezier(0.45, 0, 0.63, 1); }
62.2% { transform: translate(85.002px, 33.344px) rotate(2.014deg) scale(1); animation-timing-function: cubic-bezier(0.45, 0, 0.63, 1); }
88.8%, 100% { transform: translate(85.002px, 50.174px) rotate(2.014deg) scale(1); }
}
@keyframes zenBoostsStarSmallBounce {
0%, 26.6% { transform: translate(68.002px, 37.075px) rotate(2.014deg) scale(1); animation-timing-function: cubic-bezier(0.29, 0, 0.83, 1); }
44.8% { transform: translate(68.002px, 44.632px) rotate(2.014deg) scale(1); animation-timing-function: linear; }
55.5% { transform: translate(68.002px, 34px) rotate(2.014deg) scale(1); animation-timing-function: linear; }
64.4% { transform: translate(68.002px, 25px) rotate(2.014deg) scale(0); animation-timing-function: linear; }
75.5% { transform: translate(68.002px, 15px) rotate(2.014deg) scale(0); animation-timing-function: cubic-bezier(0.45, 0, 0.63, 1); }
84.4% { transform: translate(68.002px, 28px) rotate(2.014deg) scale(1); animation-timing-function: cubic-bezier(0.45, 0, 0.63, 1); }
93.3%, 100% { transform: translate(68.002px, 37.075px) rotate(2.014deg) scale(1); }
}
.zen-boosts-card { animation: zenBoostsCardTilt 0.583s forwards; }
.zen-boosts-brush { animation: zenBoostsBrushRotate 0.583s forwards; }
.zen-boosts-star-large { animation: zenBoostsStarLargeBounce 0.583s forwards; }
.zen-boosts-star-small { animation: zenBoostsStarSmallBounce 0.583s forwards; }
</style>
<defs>
<linearGradient id="zen-boosts-grad" gradientUnits="userSpaceOnUse" x1="64" y1="16" x2="64" y2="144">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
<mask id="zen-boosts-mask" maskContentUnits="userSpaceOnUse">
<rect x="-100" y="-100" width="300" height="300" fill="#fff"/>
<path fill="#000" stroke="#000" stroke-width="8" stroke-linejoin="round" d="M-3.79 54.121C-5.31 51.635-6.984 48.884-7.082 42.132L-7.073 42.091-7.063 42.051C-6.2 38.573-3.904 36.054-1.1 34.382L4.474 31.059C6.968 29.572 9.896 28.739 13.003 29.233 13.558 28.514 14.137 27.648 14.736 26.617L14.752 26.589 14.769 26.561C15.438 25.438 16.22 24.032 17.105 22.317 18.032 20.521 19.176 18.3 20.531 15.65 21.63 13.5 23.221 11.59 25.405 10.221 27.368 8.99 29.589 8.271 31.984 8.218L32.013 8.218C34.325 8.178 36.528 8.749 38.557 9.821 40.713 10.96 42.401 12.627 43.642 14.615L43.662 14.646 63.922 47.997C66.006 51.466 67.049 55.422 66.104 59.547 65.148 63.723 62.394 66.785 58.898 68.869L44.274 77.586C44.222 77.953 44.148 78.323 44.06 78.696 43.24 82.158 40.963 84.66 38.246 86.34L38.205 86.365 32.548 89.738C29.738 91.413 26.42 92.18 22.922 91.299 18.565 90.201 14.485 87.919 10.34 86.196 10.34 86.196 8.779 87.737 7.305 89.123 5.699 90.632 4.021 91.927 2.291 92.956-2.345 95.712-7.442 96.912-12.65 95.581-17.868 94.248-21.776 90.71-24.597 86.068-27.411 81.439-28.702 76.368-27.456 71.195-26.206 66.005-22.739 62.101-18.096 59.333-16.417 58.332-14.507 57.488-12.438 56.763L-12.4 56.75C-10.473 56.089-8.488 55.472-6.445 54.899-5.537 54.635-4.652 54.375-3.79 54.121Z"/>
</mask>
</defs>
<g class="zen-boosts-card" style="transform-origin: 0 0;" transform="translate(61.889 63.143) scale(1.1) rotate(-15)">
<g class="zen-boosts-card-anchor" transform="translate(-44 -44)">
<rect class="zen-boosts-bg" x="3.55" y="3.55" width="80.9" height="80.9" rx="12.45" fill="context-fill" fill-opacity="1"/>
<rect class="zen-boosts-gradient" x="3.55" y="3.55" width="80.9" height="80.9" rx="12.45" fill="url(#zen-boosts-grad)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<rect class="zen-boosts-border" width="88" height="88" rx="16" mask="url(#zen-boosts-mask)" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g class="zen-boosts-brush" style="transform-origin: 0 0;" transform="translate(18.247 109.504) scale(1.1)">
<g class="zen-boosts-brush-anchor" transform="translate(-15 -70)">
<g class="zen-boosts-brush-tip-translate" transform="translate(27.307 3.73)">
<path class="zen-boosts-bg" d="M0 28 6 14 12 0 44 34 26 54Z" fill="context-fill" fill-opacity="1"/>
<path class="zen-boosts-gradient" d="M0 28 6 14 12 0 44 34 26 54Z" fill="url(#zen-boosts-grad)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
</g>
<g class="zen-boosts-brush-silhouette-fills">
<path class="zen-boosts-bg" fill="context-fill" fill-opacity="1" d="M0 69.826C-0.023 66.459 1.467 63.29 4.469 60.318 5.501 59.296 6.814 58.264 8.409 57.219 10.027 56.174 11.717 55.176 13.476 54.154 15.235 53.132 16.877 52.158 18.472 51.229L22.377 48.617 15.024 41.373C13.546 39.91 12.795 38.354 12.772 36.706 12.772 35.034 13.5 33.479 14.954 32.04L19.563 27.478C21.017 26.039 22.577 25.33 24.242 25.353 26.219 25.381 26.531 25.828 28.992 27.547L56.964 55.303C58.465 56.766 59.215 58.322 59.215 59.97 59.238 61.595 58.535 63.139 57.104 64.602L52.46 69.199C51.029 70.615 49.47 71.311 47.781 71.288 46.092 71.288 44.52 70.557 43.066 69.094L35.748 61.816C34.904 62.814 34.012 64.091 33.074 65.647 32.136 67.203 31.15 68.862 30.118 70.627 29.109 72.392 28.078 74.063 27.022 75.642 25.99 77.244 24.946 78.555 23.89 79.577 20.888 82.549 17.686 84.023 14.285 84 10.884 83.977 7.658 82.444 4.609 79.403 1.56 76.385 0.023 73.193 0 69.826ZM56.257 54.603L54.309 52.669 68.012 38.552C68.669 37.902 68.997 37.182 68.997 36.393 68.997 35.604 68.633 34.849 67.906 34.129L41.764 8.289C41.412 7.941 41.048 7.754 40.673 7.731 40.321 7.708 39.993 7.825 39.688 8.08 39.407 8.312 39.196 8.695 39.055 9.229 38.211 12.294 37.495 14.917 36.909 17.099 36.323 19.281 35.712 21.244 35.079 22.985 34.446 24.726 33.636 26.444 32.651 28.139 31.689 29.811 31.369 29.906 31.369 29.906L28.992 27.547 26.531 25.828C27.258 24.69 28.147 22.962 28.64 21.871 29.133 20.757 29.578 19.514 29.977 18.144 30.399 16.751 30.845 15.079 31.314 13.129 31.783 11.156 32.358 8.718 33.038 5.816 33.39 4.307 34.023 3.088 34.938 2.159 35.853 1.207 36.909 0.569 38.105 0.244 39.325-0.081 40.556-0.081 41.799 0.244 43.042 0.546 44.168 1.184 45.177 2.159L72.832 29.567C74.92 31.657 75.975 33.85 75.998 36.149 76.045 38.447 75.049 40.607 73.008 42.627L58.083 56.603 56.257 54.603Z"/>
<path class="zen-boosts-gradient" fill="url(#zen-boosts-grad)" style="mix-blend-mode: overlay; opacity: 0.1;" d="M0 69.826C-0.023 66.459 1.467 63.29 4.469 60.318 5.501 59.296 6.814 58.264 8.409 57.219 10.027 56.174 11.717 55.176 13.476 54.154 15.235 53.132 16.877 52.158 18.472 51.229L22.377 48.617 15.024 41.373C13.546 39.91 12.795 38.354 12.772 36.706 12.772 35.034 13.5 33.479 14.954 32.04L19.563 27.478C21.017 26.039 22.577 25.33 24.242 25.353 26.219 25.381 26.531 25.828 28.992 27.547L56.964 55.303C58.465 56.766 59.215 58.322 59.215 59.97 59.238 61.595 58.535 63.139 57.104 64.602L52.46 69.199C51.029 70.615 49.47 71.311 47.781 71.288 46.092 71.288 44.52 70.557 43.066 69.094L35.748 61.816C34.904 62.814 34.012 64.091 33.074 65.647 32.136 67.203 31.15 68.862 30.118 70.627 29.109 72.392 28.078 74.063 27.022 75.642 25.99 77.244 24.946 78.555 23.89 79.577 20.888 82.549 17.686 84.023 14.285 84 10.884 83.977 7.658 82.444 4.609 79.403 1.56 76.385 0.023 73.193 0 69.826ZM56.257 54.603L54.309 52.669 68.012 38.552C68.669 37.902 68.997 37.182 68.997 36.393 68.997 35.604 68.633 34.849 67.906 34.129L41.764 8.289C41.412 7.941 41.048 7.754 40.673 7.731 40.321 7.708 39.993 7.825 39.688 8.08 39.407 8.312 39.196 8.695 39.055 9.229 38.211 12.294 37.495 14.917 36.909 17.099 36.323 19.281 35.712 21.244 35.079 22.985 34.446 24.726 33.636 26.444 32.651 28.139 31.689 29.811 31.369 29.906 31.369 29.906L28.992 27.547 26.531 25.828C27.258 24.69 28.147 22.962 28.64 21.871 29.133 20.757 29.578 19.514 29.977 18.144 30.399 16.751 30.845 15.079 31.314 13.129 31.783 11.156 32.358 8.718 33.038 5.816 33.39 4.307 34.023 3.088 34.938 2.159 35.853 1.207 36.909 0.569 38.105 0.244 39.325-0.081 40.556-0.081 41.799 0.244 43.042 0.546 44.168 1.184 45.177 2.159L72.832 29.567C74.92 31.657 75.975 33.85 75.998 36.149 76.045 38.447 75.049 40.607 73.008 42.627L58.083 56.603 56.257 54.603Z"/>
</g>
<path class="zen-boosts-border" fill-rule="evenodd" fill="context-stroke" d="M0 69.826C-0.023 66.459 1.467 63.29 4.469 60.318 5.501 59.296 6.814 58.264 8.409 57.219 10.027 56.174 11.717 55.176 13.476 54.154 15.235 53.132 16.877 52.158 18.472 51.229L22.377 48.617 15.024 41.373C13.546 39.91 12.795 38.354 12.772 36.706 12.772 35.034 13.5 33.479 14.954 32.04L19.563 27.478C21.017 26.039 22.577 25.33 24.242 25.353 26.219 25.381 26.531 25.828 28.992 27.547L56.964 55.303C58.465 56.766 59.215 58.322 59.215 59.97 59.238 61.595 58.535 63.139 57.104 64.602L52.46 69.199C51.029 70.615 49.47 71.311 47.781 71.288 46.092 71.288 44.52 70.557 43.066 69.094L35.748 61.816C34.904 62.814 34.012 64.091 33.074 65.647 32.136 67.203 31.15 68.862 30.118 70.627 29.109 72.392 28.078 74.063 27.022 75.642 25.99 77.244 24.946 78.555 23.89 79.577 20.888 82.549 17.686 84.023 14.285 84 10.884 83.977 7.658 82.444 4.609 79.403 1.56 76.385 0.023 73.193 0 69.826ZM20.618 38.308L29.133 46.701C29.86 47.398 30.188 48.187 30.118 49.069 30.048 49.951 29.625 50.799 28.851 51.612 28.171 52.309 27.034 53.11 25.439 54.015 23.844 54.92 22.037 55.931 20.02 57.045 18.026 58.159 16.044 59.355 14.074 60.632 12.104 61.909 10.427 63.232 9.043 64.602 7.425 66.181 6.615 67.887 6.615 69.721 6.638 71.555 7.471 73.297 9.113 74.945 10.778 76.57 12.525 77.383 14.355 77.383 16.208 77.406 17.945 76.617 19.563 75.015 20.97 73.645 22.307 71.985 23.574 70.035 24.864 68.085 26.072 66.122 27.198 64.149 28.324 62.152 29.344 60.377 30.259 58.821 31.197 57.242 32.007 56.116 32.687 55.443 33.508 54.654 34.364 54.235 35.255 54.189 36.146 54.119 36.956 54.444 37.683 55.164L46.127 63.557C46.971 64.416 47.804 64.404 48.625 63.522L51.299 60.875C52.12 60.039 52.132 59.216 51.334 58.403L25.79 33.154C25.415 32.759 25.016 32.574 24.594 32.597 24.172 32.597 23.762 32.794 23.363 33.189L20.618 35.836C19.774 36.649 19.774 37.472 20.618 38.308ZM11.294 72.855C10.473 72.042 10.063 71.068 10.063 69.93 10.063 68.792 10.473 67.818 11.294 67.005 12.115 66.192 13.101 65.786 14.25 65.786 15.399 65.786 16.384 66.192 17.205 67.005 18.026 67.818 18.437 68.792 18.437 69.93 18.437 71.068 18.026 72.042 17.205 72.855 16.384 73.668 15.399 74.074 14.25 74.074 13.101 74.074 12.115 73.668 11.294 72.855ZM56.257 54.603L54.309 52.669 68.012 38.552C68.669 37.902 68.997 37.182 68.997 36.393 68.997 35.604 68.633 34.849 67.906 34.129L41.764 8.289C41.412 7.941 41.048 7.754 40.673 7.731 40.321 7.708 39.993 7.825 39.688 8.08 39.407 8.312 39.196 8.695 39.055 9.229 38.211 12.294 37.495 14.917 36.909 17.099 36.323 19.281 35.712 21.244 35.079 22.985 34.446 24.726 33.636 26.444 32.651 28.139 31.689 29.811 31.369 29.906 31.369 29.906L28.992 27.547 26.531 25.828C27.258 24.69 28.147 22.962 28.64 21.871 29.133 20.757 29.578 19.514 29.977 18.144 30.399 16.751 30.845 15.079 31.314 13.129 31.783 11.156 32.358 8.718 33.038 5.816 33.39 4.307 34.023 3.088 34.938 2.159 35.853 1.207 36.909 0.569 38.105 0.244 39.325-0.081 40.556-0.081 41.799 0.244 43.042 0.546 44.168 1.184 45.177 2.159L72.832 29.567C74.92 31.657 75.975 33.85 75.998 36.149 76.045 38.447 75.049 40.607 73.008 42.627L58.083 56.603 56.257 54.603ZM50.455 37.786C52.425 35.836 54.138 33.7 55.592 31.378 57.07 29.056 57.973 26.352 58.301 23.264L66.041 30.89C65.15 32.004 63.93 33.142 62.382 34.303 60.834 35.441 59.216 36.463 57.527 37.368 55.862 38.25 54.36 38.878 53.023 39.249 51.709 39.62 50.818 39.573 50.349 39.109 49.927 38.714 49.962 38.274 50.455 37.786Z"/>
</g>
</g>
<g class="zen-boosts-star-small" style="transform-origin: 0 0;" transform="translate(68.002 37.075) rotate(2.014)">
<g class="zen-boosts-star-small-anchor" transform="translate(-8 -8)">
<path class="zen-boosts-border" d="M8 0C8 4.418 4.418 8 0 8 4.418 8 8 11.582 8 16 8 11.582 11.582 8 16 8 11.582 8 8 4.418 8 0Z" fill="context-stroke" stroke="context-stroke" stroke-width="3" stroke-linejoin="round"/>
</g>
</g>
<g class="zen-boosts-star-large" style="transform-origin: 0 0;" transform="translate(85.002 50.174) rotate(2.014)">
<g class="zen-boosts-star-large-anchor" transform="translate(-12 -12)">
<path class="zen-boosts-border" d="M12 0C12 6.627 6.627 12 0 12 6.627 12 12 17.373 12 24 12 17.373 17.373 12 24 12 17.373 12 12 6.627 12 0Z" fill="context-stroke" stroke="context-stroke" stroke-width="3" stroke-linejoin="round"/>
</g>
</g>
</svg>

View File

@@ -0,0 +1,32 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-boosts-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="zen-boosts-mask" maskContentUnits="userSpaceOnUse">
<rect x="-100" y="-100" width="300" height="300" fill="#fff"/>
<path fill="#000" stroke="#000" stroke-width="8" stroke-linejoin="round" d="M-3.79 54.121C-5.31 51.635-6.984 48.884-7.082 42.132L-7.073 42.091-7.063 42.051C-6.2 38.573-3.904 36.054-1.1 34.382L4.474 31.059C6.968 29.572 9.896 28.739 13.003 29.233 13.558 28.514 14.137 27.648 14.736 26.617L14.752 26.589 14.769 26.561C15.438 25.438 16.22 24.032 17.105 22.317 18.032 20.521 19.176 18.3 20.531 15.65 21.63 13.5 23.221 11.59 25.405 10.221 27.368 8.99 29.589 8.271 31.984 8.218L32.013 8.218C34.325 8.178 36.528 8.749 38.557 9.821 40.713 10.96 42.401 12.627 43.642 14.615L43.662 14.646 63.922 47.997C66.006 51.466 67.049 55.422 66.104 59.547 65.148 63.723 62.394 66.785 58.898 68.869L44.274 77.586C44.222 77.953 44.148 78.323 44.06 78.696 43.24 82.158 40.963 84.66 38.246 86.34L38.205 86.365 32.548 89.738C29.738 91.413 26.42 92.18 22.922 91.299 18.565 90.201 14.485 87.919 10.34 86.196 10.34 86.196 8.779 87.737 7.305 89.123 5.699 90.632 4.021 91.927 2.291 92.956-2.345 95.712-7.442 96.912-12.65 95.581-17.868 94.248-21.776 90.71-24.597 86.068-27.411 81.439-28.702 76.368-27.456 71.195-26.206 66.005-22.739 62.101-18.096 59.333-16.417 58.332-14.507 57.488-12.438 56.763L-12.4 56.75C-10.473 56.089-8.488 55.472-6.445 54.899-5.537 54.635-4.652 54.375-3.79 54.121Z"/>
</mask>
</defs>
<g transform="translate(61.889 63.143) scale(1.1) rotate(-15)">
<g transform="translate(-44 -44)">
<rect width="88" height="88" rx="16" mask="url(#zen-boosts-mask)" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g transform="translate(18.247 109.504) scale(1.1)">
<g transform="translate(-15 -70)">
<path fill-rule="evenodd" fill="context-stroke" d="M0 69.826C-0.023 66.459 1.467 63.29 4.469 60.318 5.501 59.296 6.814 58.264 8.409 57.219 10.027 56.174 11.717 55.176 13.476 54.154 15.235 53.132 16.877 52.158 18.472 51.229L22.377 48.617 15.024 41.373C13.546 39.91 12.795 38.354 12.772 36.706 12.772 35.034 13.5 33.479 14.954 32.04L19.563 27.478C21.017 26.039 22.577 25.33 24.242 25.353 26.219 25.381 26.531 25.828 28.992 27.547L56.964 55.303C58.465 56.766 59.215 58.322 59.215 59.97 59.238 61.595 58.535 63.139 57.104 64.602L52.46 69.199C51.029 70.615 49.47 71.311 47.781 71.288 46.092 71.288 44.52 70.557 43.066 69.094L35.748 61.816C34.904 62.814 34.012 64.091 33.074 65.647 32.136 67.203 31.15 68.862 30.118 70.627 29.109 72.392 28.078 74.063 27.022 75.642 25.99 77.244 24.946 78.555 23.89 79.577 20.888 82.549 17.686 84.023 14.285 84 10.884 83.977 7.658 82.444 4.609 79.403 1.56 76.385 0.023 73.193 0 69.826ZM20.618 38.308L29.133 46.701C29.86 47.398 30.188 48.187 30.118 49.069 30.048 49.951 29.625 50.799 28.851 51.612 28.171 52.309 27.034 53.11 25.439 54.015 23.844 54.92 22.037 55.931 20.02 57.045 18.026 58.159 16.044 59.355 14.074 60.632 12.104 61.909 10.427 63.232 9.043 64.602 7.425 66.181 6.615 67.887 6.615 69.721 6.638 71.555 7.471 73.297 9.113 74.945 10.778 76.57 12.525 77.383 14.355 77.383 16.208 77.406 17.945 76.617 19.563 75.015 20.97 73.645 22.307 71.985 23.574 70.035 24.864 68.085 26.072 66.122 27.198 64.149 28.324 62.152 29.344 60.377 30.259 58.821 31.197 57.242 32.007 56.116 32.687 55.443 33.508 54.654 34.364 54.235 35.255 54.189 36.146 54.119 36.956 54.444 37.683 55.164L46.127 63.557C46.971 64.416 47.804 64.404 48.625 63.522L51.299 60.875C52.12 60.039 52.132 59.216 51.334 58.403L25.79 33.154C25.415 32.759 25.016 32.574 24.594 32.597 24.172 32.597 23.762 32.794 23.363 33.189L20.618 35.836C19.774 36.649 19.774 37.472 20.618 38.308ZM11.294 72.855C10.473 72.042 10.063 71.068 10.063 69.93 10.063 68.792 10.473 67.818 11.294 67.005 12.115 66.192 13.101 65.786 14.25 65.786 15.399 65.786 16.384 66.192 17.205 67.005 18.026 67.818 18.437 68.792 18.437 69.93 18.437 71.068 18.026 72.042 17.205 72.855 16.384 73.668 15.399 74.074 14.25 74.074 13.101 74.074 12.115 73.668 11.294 72.855ZM56.257 54.603L54.309 52.669 68.012 38.552C68.669 37.902 68.997 37.182 68.997 36.393 68.997 35.604 68.633 34.849 67.906 34.129L41.764 8.289C41.412 7.941 41.048 7.754 40.673 7.731 40.321 7.708 39.993 7.825 39.688 8.08 39.407 8.312 39.196 8.695 39.055 9.229 38.211 12.294 37.495 14.917 36.909 17.099 36.323 19.281 35.712 21.244 35.079 22.985 34.446 24.726 33.636 26.444 32.651 28.139 31.689 29.811 31.369 29.906 31.369 29.906L28.992 27.547 26.531 25.828C27.258 24.69 28.147 22.962 28.64 21.871 29.133 20.757 29.578 19.514 29.977 18.144 30.399 16.751 30.845 15.079 31.314 13.129 31.783 11.156 32.358 8.718 33.038 5.816 33.39 4.307 34.023 3.088 34.938 2.159 35.853 1.207 36.909 0.569 38.105 0.244 39.325-0.081 40.556-0.081 41.799 0.244 43.042 0.546 44.168 1.184 45.177 2.159L72.832 29.567C74.92 31.657 75.975 33.85 75.998 36.149 76.045 38.447 75.049 40.607 73.008 42.627L58.083 56.603 56.257 54.603ZM50.455 37.786C52.425 35.836 54.138 33.7 55.592 31.378 57.07 29.056 57.973 26.352 58.301 23.264L66.041 30.89C65.15 32.004 63.93 33.142 62.382 34.303 60.834 35.441 59.216 36.463 57.527 37.368 55.862 38.25 54.36 38.878 53.023 39.249 51.709 39.62 50.818 39.573 50.349 39.109 49.927 38.714 49.962 38.274 50.455 37.786Z"/>
</g>
</g>
<g transform="translate(68.002 37.075) rotate(2.014)">
<g transform="translate(-8 -8)">
<path d="M8 0C8 4.418 4.418 8 0 8 4.418 8 8 11.582 8 16 8 11.582 11.582 8 16 8 11.582 8 8 4.418 8 0Z" fill="context-stroke" stroke="context-stroke" stroke-width="3" stroke-linejoin="round"/>
</g>
</g>
<g transform="translate(85.002 50.174) rotate(2.014)">
<g transform="translate(-12 -12)">
<path d="M12 0C12 6.627 6.627 12 0 12 6.627 12 12 17.373 12 24 12 17.373 17.373 12 24 12 17.373 12 12 6.627 12 0Z" fill="context-stroke" stroke="context-stroke" stroke-width="3" stroke-linejoin="round"/>
</g>
</g>
</svg>

View File

@@ -0,0 +1,36 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-downloads-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes zenDownloadsArrowBounce {
0% { transform: translateY(0px); d: path('M 64 45 L 64 83 M 50 69 L 64 83 L 78 69'); animation-timing-function: cubic-bezier(0.33, 0, 0.7, 1.28); }
31.43% { transform: translateY(10px); d: path('M 64 57 L 64 83 M 50 69 L 64 83 L 78 69'); animation-timing-function: cubic-bezier(0.44, 0.2, 0.44, 0.98); }
54.29% { transform: translateY(-10.83px); d: path('M 64 45 L 64 83 M 50 69 L 64 83 L 78 69'); animation-timing-function: cubic-bezier(0.45, -0.03, 0.83, 0.9); }
85.71% { transform: translateY(0.66px); d: path('M 64 45 L 64 83 M 50 69 L 64 83 L 78 69'); animation-timing-function: cubic-bezier(0.17, -0.98, 0.83, 0.83); }
100% { transform: translateY(0px); d: path('M 64 45 L 64 83 M 50 69 L 64 83 L 78 69'); }
}
@keyframes zenDownloadsCircleBounce {
0% { transform: translateY(0px); animation-timing-function: cubic-bezier(0.33, 0, 0.71, 2.31); }
31.43% { transform: translateY(2.5px); animation-timing-function: cubic-bezier(0.23, 0.15, 0.36, 0.97); }
54.29% { transform: translateY(-11.46px); animation-timing-function: cubic-bezier(0.48, -0.04, 0.83, 0.89); }
85.71% { transform: translateY(0.85px); animation-timing-function: cubic-bezier(0.17, -0.70, 0.83, 0.83); }
100% { transform: translateY(0px); }
}
.zen-downloads-circle-translate { animation: zenDownloadsCircleBounce 0.583s forwards; }
.zen-downloads-arrow { animation: zenDownloadsArrowBounce 0.583s forwards; }
</style>
<defs>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="20" x2="64" y2="148" id="zen-spaces-grad-front">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
</defs>
<g class="zen-downloads-circle-translate" style="transform-origin: 64px 64px;">
<circle class="zen-downloads-bg" cx="64" cy="64" r="47.5" fill="context-fill" fill-opacity="1"/>
<circle class="zen-downloads-gradient" cx="64" cy="64" r="47.5" fill="url(#zen-downloads-grad-front)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<circle class="zen-downloads-border" cx="64" cy="64" r="47.5" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
<path class="zen-downloads-arrow" d="M 64 45 L 64 83 M 50 69 L 64 83 L 78 69" stroke="context-stroke" stroke-width="7.1" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

View File

@@ -0,0 +1,8 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-downloads-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="64" cy="64" r="47.5" fill="none" stroke="context-stroke" stroke-width="7.1"/>
<path d="M 64 45 L 64 83 M 50 69 L 64 83 L 78 69" stroke="context-stroke" stroke-width="7.1" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

View File

@@ -0,0 +1,62 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-history-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes zenHistoryBodyTranslate {
0%, 31.43% { transform: translate(63.977px, 79.047px); animation-timing-function: cubic-bezier(0.16, 0.41, 0.34, 1); }
60% { transform: translate(63.977px, 63.253px); animation-timing-function: cubic-bezier(0.33, 0, 0.62, 0.55); }
77.14%, 100% { transform: translate(63.977px, 79.047px); }
}
@keyframes zenHistoryLid {
0% { transform: translate(63.977px, 37.148px) rotate(0deg) translate(-46.852px, -12.82px); animation-timing-function: cubic-bezier(0.21, 0, 0.56, 1); }
31.43% { transform: translate(63.977px, 51.609px) rotate(0deg) translate(-46.852px, -12.82px); animation-timing-function: cubic-bezier(0.38, 0, 0.55, 1); }
62.86% { transform: translate(63.977px, 17.08px) rotate(-6.93deg) translate(-46.852px, -12.82px); animation-timing-function: cubic-bezier(0.43, 0.14, 0.38, 1); }
82.86% { transform: translate(63.977px, 23.397px) rotate(4.2deg) translate(-46.852px, -12.82px); animation-timing-function: cubic-bezier(0.41, 0, 0.49, 1); }
100% { transform: translate(63.977px, 37.148px) rotate(0deg) translate(-46.852px, -12.82px); }
}
@keyframes zenHistoryDashTranslate {
0% { transform: translate(64px, 65px) scale(0.9, 1); animation-timing-function: cubic-bezier(0.33, 0, 0.7, 1.28); }
31.43% { transform: translate(64px, 79.461px) scale(0.8, 1); animation-timing-function: cubic-bezier(0.44, 0.2, 0.44, 0.98); }
54.29% { transform: translate(64px, 61.033px) scale(0.86, 1); animation-timing-function: cubic-bezier(0.45, -0.03, 0.83, 0.9); }
85.71% { transform: translate(64px, 65.66px) scale(0.9, 1); animation-timing-function: cubic-bezier(0.22, -0.9, 0.25, 1.25); }
100% { transform: translate(64px, 65px) scale(0.9, 1); }
}
.zen-history-body-translate { animation: zenHistoryBodyTranslate 0.583s forwards; }
.zen-history-lid { animation: zenHistoryLid 0.583s forwards; }
.zen-history-dash-translate { animation: zenHistoryDashTranslate 0.583s forwards; }
</style>
<defs>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="0" x2="64" y2="128" id="zen-history-grad-front">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
</defs>
<g class="zen-history-body-translate" style="transform-origin: 0 0; transform: translate(63.977px, 79.047px);">
<g transform="translate(-39.867, -30.328)">
<path class="zen-history-bg"
d="M 3.55 0 L 76.184 0 L 76.184 46.856 A 10.25 10.25 0 0 1 65.934 57.106 L 13.8 57.106 A 10.25 10.25 0 0 1 3.55 46.856 Z"
fill="context-fill" fill-opacity="1"/>
<path class="zen-history-gradient"
d="M 3.55 0 L 76.184 0 L 76.184 46.856 A 10.25 10.25 0 0 1 65.934 57.106 L 13.8 57.106 A 10.25 10.25 0 0 1 3.55 46.856 Z"
fill="url(#zen-history-grad-front)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<path class="zen-history-border"
d="M 3.55 0 L 76.184 0 L 76.184 46.856 A 10.25 10.25 0 0 1 65.934 57.106 L 13.8 57.106 A 10.25 10.25 0 0 1 3.55 46.856 Z"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g class="zen-history-lid" style="transform-origin: 0 0; transform: translate(63.977px, 37.148px) rotate(0deg) translate(-46.852px, -12.82px);">
<rect class="zen-history-bg" x="3.55" y="3.55" width="86.603" height="18.541" rx="6.05"
fill="context-fill" fill-opacity="1"/>
<rect class="zen-history-gradient" x="3.55" y="3.55" width="86.603" height="18.541" rx="6.05"
fill="url(#zen-history-grad-front)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<rect class="zen-history-border" x="3.55" y="3.55" width="86.603" height="18.541" rx="6.05"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
<g class="zen-history-dash-translate" style="transform-origin: 0 0; transform: translate(64px, 65px) scale(0.9, 1);">
<path class="zen-history-dash-path" fill="none"
d="M -16 0 L 16 0"
stroke="context-stroke" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

View File

@@ -0,0 +1,14 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-history-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(63.977, 79.047)">
<path d="M -36.317 -30.328 L 36.317 -30.328 L 36.317 16.528 A 10.25 10.25 0 0 1 26.067 26.778 L -26.067 26.778 A 10.25 10.25 0 0 1 -36.317 16.528 Z"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
<g transform="translate(17.125, 24.328)">
<rect x="3.55" y="3.55" width="86.603" height="18.541" rx="6.05" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
<path d="M 49.6 65 L 78.4 65" fill="none" stroke="context-stroke" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

View File

@@ -0,0 +1,74 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-media-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes zenMediaBackBounce {
0% { transform: translate(54.799px, 57.743px) rotate(-7deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1); }
24.41% { transform: translate(57.299px, 65.243px) rotate(3deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.3, 0, 0.8, 1); }
43.67% { transform: translate(56.16px, 47.803px) rotate(-18.58deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.16, 0, 0.8, 1); }
78.21% { transform: translate(55.25px, 54.3px) rotate(-3.2deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
100% { transform: translate(54.799px, 57.743px) rotate(-7deg) translate(-46.27px, -36.445px); }
}
@keyframes zenMediaFrontBounce {
0% { transform: translate(78.827px, 77.737px) rotate(0deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1); }
24.41% { transform: translate(78.827px, 80.737px) rotate(0deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.4, 0, 0.64, 1); }
55.88% { transform: translate(75.827px, 62.61px) rotate(9.32deg) translate(-46.27px, -36.445px); animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1); }
88.24% { transform: translate(78.827px, 77.737px) rotate(0deg) translate(-46.27px, -36.445px); animation-timing-function: linear; }
100% { transform: translate(78.827px, 77.737px) rotate(0deg) translate(-46.27px, -36.445px); }
}
@keyframes zenMediaSunBounce {
0% { transform: translate(64.76px, 67.886px) translate(-9.914px, -9.984px); animation-timing-function: cubic-bezier(0.32, 0, 0.67, 1); }
24.41% { transform: translate(64.76px, 73.606px) translate(-9.914px, -9.984px); animation-timing-function: linear; }
35.29% { transform: translate(64.76px, 73.606px) translate(-9.914px, -9.984px); animation-timing-function: cubic-bezier(0.35, 0, 0.76, 0.72); }
55.88% { transform: translate(61.737px, 51.974px) translate(-9.914px, -9.984px); animation-timing-function: cubic-bezier(0.21, -0.71, 0.45, 1); }
100% { transform: translate(64.76px, 67.886px) translate(-9.914px, -9.984px); }
}
.zen-media-back-card { animation: zenMediaBackBounce 0.583s forwards; }
.zen-media-front-card { animation: zenMediaFrontBounce 0.583s forwards; }
.zen-media-sun { animation: zenMediaSunBounce 0.583s forwards; }
</style>
<defs>
<mask id="zen-media-mask">
<rect x="-10" y="-10" width="148" height="148" fill="white"/>
<g class="zen-media-front-card-mask" transform="translate(78.827, 77.737) translate(-46.27, -36.445)">
<rect x="0" y="0" width="92.539" height="72.891" rx="12.812" fill="black"/>
</g>
</mask>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="0" x2="64" y2="128" id="zen-media-grad-back">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="0" x2="64" y2="128" id="zen-media-grad-front">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
</defs>
<g class="zen-media-back-wrapper" mask="url(#zen-media-mask)">
<g class="zen-media-back-card" transform="translate(54.799, 57.743) rotate(-7) translate(-46.27, -36.445)">
<rect class="zen-media-bg" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="context-fill" fill-opacity="1"/>
<rect class="zen-media-gradient" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="url(#zen-media-grad-back)" fill-opacity="1" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<rect class="zen-media-border" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g class="zen-media-front-card" transform="translate(78.827, 77.737) translate(-46.27, -36.445)">
<rect class="zen-media-bg" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="context-fill" fill-opacity="1"/>
<rect class="zen-media-gradient" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="url(#zen-media-grad-front)" fill-opacity="1" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<g class="zen-media-mountain" transform="translate(0.289, 32.609)">
<path class="zen-media-mountain-path" d="M7.432 21.147 L17.865 12.11 C19.665 10.596 21.373 9.862 23.173 9.862 C25.158 9.862 27.005 10.596 28.805 12.202 L36.191 18.853 L54.84 2.431 C56.779 0.734 58.81 0 61.072 0 C63.334 0 65.55 0.826 67.35 2.477 L84.568 18.67 L92 25.78 C92 35.23 87.153 40 77.551 40 L14.495 40 C4.801 40 0 35.275 0 25.78 Z"
fill="context-stroke"/>
</g>
<rect class="zen-media-border" x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
<g class="zen-media-sun" transform="translate(64.76, 67.886) translate(-9.914, -9.984)">
<circle class="zen-media-sun-path" cx="9.914" cy="9.984" r="9.914"
fill="context-stroke"/>
</g>
</svg>

View File

@@ -0,0 +1,22 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-media-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="zen-media-mask-inactive">
<rect x="-10" y="-10" width="148" height="148" fill="white"/>
<g transform="translate(78.827, 77.737) translate(-46.27, -36.445)">
<rect x="0" y="0" width="92.539" height="72.891" rx="12.812" fill="black"/>
</g>
</mask>
</defs>
<g mask="url(#zen-media-mask-inactive)">
<g transform="translate(54.799, 57.743) rotate(-7) translate(-46.27, -36.445)">
<rect x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g transform="translate(78.827, 77.737) translate(-46.27, -36.445)">
<rect x="3.55" y="3.55" width="85.439" height="65.791" rx="9.262" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</svg>

View File

@@ -0,0 +1,56 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-spaces-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
@keyframes zenSpacesBackBounce {
0% { transform: translate(51.28px, 61.69px) rotate(-17.5deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.21, 0, 0.56, 1); }
34.28% { transform: translate(56.28px, 72.19px) rotate(6deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.38, 0, 0.55, 1); }
62.86% { transform: translate(51.28px, 55.52px) rotate(-27.83deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.73, 0, 0.63, 1); }
100% { transform: translate(51.28px, 61.69px) rotate(-17.5deg) translate(-35.022px, -44.68px); }
}
@keyframes zenSpacesFrontBounce {
0% { transform: translate(77.02px, 75.93px) rotate(0deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.21, 0, 0.56, 1); }
31.43% { transform: translate(77.02px, 78.18px) rotate(-5deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.38, 0, 0.55, 1); }
54.28% { transform: translate(77.02px, 55.71px) rotate(28.96deg) translate(-35.022px, -44.68px); animation-timing-function: cubic-bezier(0.73, 0, 0.63, 1); }
100% { transform: translate(77.02px, 75.93px) rotate(0deg) translate(-35.022px, -44.68px); }
}
.zen-spaces-back-card { animation: zenSpacesBackBounce 0.583s forwards; }
.zen-spaces-front-card { animation: zenSpacesFrontBounce 0.583s forwards; }
</style>
<defs>
<mask id="zen-spaces-mask">
<rect x="-10" y="-10" width="148" height="148" fill="white"/>
<g class="zen-spaces-front-card" style="transform-origin: 0 0; transform: translate(77.02px, 75.93px) rotate(0deg) translate(-35.022px, -44.68px);">
<rect x="0" y="0" width="70.04" height="89.36" rx="14" fill="black"/>
</g>
</mask>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="20" x2="64" y2="148" id="zen-spaces-grad-back">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
<linearGradient gradientUnits="userSpaceOnUse" x1="64" y1="20" x2="64" y2="148" id="zen-spaces-grad-front">
<stop offset="0" stop-color="context-fill"/>
<stop offset="1" stop-color="context-stroke"/>
</linearGradient>
</defs>
<g class="zen-spaces-back-wrapper" mask="url(#zen-spaces-mask)">
<g class="zen-spaces-back-card" style="transform-origin: 0 0; transform: translate(51.28px, 61.69px) rotate(-17.5deg) translate(-35.022px, -44.68px);">
<rect class="zen-spaces-bg" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="context-fill" fill-opacity="1"/>
<rect class="zen-spaces-gradient" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="url(#zen-spaces-grad-back)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<rect class="zen-spaces-border" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g class="zen-spaces-front-card" style="transform-origin: 0 0; transform: translate(77.02px, 75.93px) rotate(0deg) translate(-35.022px, -44.68px);">
<rect class="zen-spaces-bg" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="context-fill" fill-opacity="1"/>
<rect class="zen-spaces-gradient" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="url(#zen-spaces-grad-front)" style="mix-blend-mode: overlay; opacity: 0.1;"/>
<rect class="zen-spaces-border" x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45"
fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</svg>

View File

@@ -0,0 +1,22 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-spaces-icon" width="28" height="28" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<mask id="zen-spaces-mask-inactive">
<rect x="-10" y="-10" width="148" height="148" fill="white"/>
<g style="transform-origin: 0 0; transform: translate(77.02px, 75.93px) translate(-35.022px, -44.68px);">
<rect x="0" y="0" width="70.04" height="89.36" rx="14" fill="black"/>
</g>
</mask>
</defs>
<g mask="url(#zen-spaces-mask-inactive)">
<g style="transform-origin: 0 0; transform: translate(51.28px, 61.69px) rotate(-17.5deg) translate(-35.022px, -44.68px);">
<rect x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</g>
<g style="transform-origin: 0 0; transform: translate(77.02px, 75.93px) translate(-35.022px, -44.68px);">
<rect x="3.55" y="3.55" width="62.94" height="82.26" rx="10.45" fill="none" stroke="context-stroke" stroke-width="7.1"/>
</g>
</svg>

View File

@@ -0,0 +1,68 @@
#filter dumbComments emptyLines substitution
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<svg class="zen-library-icon" width="18" height="18" viewBox="4 4 18 18" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg">
<style>
@property --zen-triangle-anim { syntax: '&lt;number&gt;'; initial-value: 1; inherits: false; }
@property --zen-circle-anim { syntax: '&lt;number&gt;'; initial-value: 1; inherits: false; }
@keyframes StarBackward {
0% { transform: rotate(120deg); }
100% { transform: rotate(0deg); }
}
@keyframes TriangleBackward {
0% { --zen-triangle-anim: 1; }
100% { --zen-triangle-anim: 0; }
}
@keyframes CircleBackward {
0% { --zen-circle-anim: 1; }
100% { --zen-circle-anim: 0; }
}
@keyframes GlowBackward {
0% { opacity: 0.4; }
100% { opacity: 0; }
}
@keyframes GlowElementsBackward {
0% { opacity: 0.5; }
100% { opacity: 0; }
}
.zen-library-star { transform-origin: 10px 10.2px; animation: StarBackward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-triangle-group { transform-origin: 17px 9.2px; animation: TriangleBackward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; transform: translate(calc(var(--zen-triangle-anim) * 2px), 0px) rotate(calc(var(--zen-triangle-anim) * 365deg)) scale(max(1 - var(--zen-triangle-anim) / 0.65, (var(--zen-triangle-anim) - 0.65) / 0.35)); }
.zen-library-circle { transform-origin: 0px 0px; animation: CircleBackward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; transform: translate(calc(var(--zen-circle-anim) * 1px), calc(var(--zen-circle-anim) * -1.5px)) scale(max(0, max((var(--zen-circle-anim) - 0.75) / 0.25, min(1, 1 - (var(--zen-circle-anim) - 0.3) / 0.35)))); }
.zen-library-glow { filter: blur(2px); animation: GlowBackward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-glow-element { filter: blur(2px); animation: GlowElementsBackward 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.zen-library-glow-bg, .zen-library-glow-element { fill: transparent !important; stroke: none !important; }
.zen-library-glow-rays { stroke: transparent !important; fill: none !important; }
@media (prefers-color-scheme: dark) {
.zen-library-glow-bg, .zen-library-glow-element { fill: white !important; }
.zen-library-glow-rays { stroke: white !important; }
}
</style>
<defs>
<mask id="zen-library-box-mask">
<rect x="-10" y="-10" width="40" height="40" fill="white"/>
<rect x="-10" y="11.635" width="40" height="40" fill="black"/>
</mask>
</defs>
<g fill-rule="evenodd">
<g mask="url(#zen-library-box-mask)">
<path class="zen-library-star zen-library-glow-element" d="M 7.773 11.635 C 8.136 11.863 8.24 12.075 8.218 12.294 L 8.036 14.082 C 7.984 14.598 8.584 14.917 8.982 14.585 L 10.362 13.432 C 10.53 13.291 10.764 13.258 10.966 13.347 L 12.61 14.072 C 13.085 14.281 13.574 13.808 13.38 13.327 L 12.701 11.635 C 12.632 11.437 12.675 11.216 12.816 11.058 L 14.014 9.718 C 14.36 9.331 14.061 8.72 13.544 8.756 L 11.75 8.877 C 11.531 8.892 11.322 8.781 11.211 8.591 L 10.307 7.038 C 10.046 6.59 9.373 6.685 9.247 7.188 L 8.808 8.931 C 8.754 9.144 8.585 9.309 8.37 9.355 L 6.613 9.735 C 6.106 9.845 5.988 10.514 6.427 10.79 L 7.773 11.635 Z"/>
<path class="zen-library-star" d="M 7.773 11.635 C 8.136 11.863 8.24 12.075 8.218 12.294 L 8.036 14.082 C 7.984 14.598 8.584 14.917 8.982 14.585 L 10.362 13.432 C 10.53 13.291 10.764 13.258 10.966 13.347 L 12.61 14.072 C 13.085 14.281 13.574 13.808 13.38 13.327 L 12.701 11.635 C 12.632 11.437 12.675 11.216 12.816 11.058 L 14.014 9.718 C 14.36 9.331 14.061 8.72 13.544 8.756 L 11.75 8.877 C 11.531 8.892 11.322 8.781 11.211 8.591 L 10.307 7.038 C 10.046 6.59 9.373 6.685 9.247 7.188 L 8.808 8.931 C 8.754 9.144 8.585 9.309 8.37 9.355 L 6.613 9.735 C 6.106 9.845 5.988 10.514 6.427 10.79 L 7.773 11.635 Z"/>
</g>
<g transform="translate(14, 6.2)">
<circle class="zen-library-circle zen-library-glow-element" cx="0" cy="0" r="1.4"/>
<circle class="zen-library-circle" cx="0" cy="0" r="1"/>
</g>
<g class="zen-library-triangle-group">
<g transform="translate(17, 9.2)">
<path class="zen-library-triangle zen-library-glow-element" d="M -1.1 1.8 C -1.4 2.0, -1.7 1.8, -1.7 1.5 L -1.7 -1.5 C -1.7 -1.8, -1.4 -2.0, -1.1 -1.8 L 1.4 -0.4 C 1.7 -0.2, 1.7 0.2, 1.4 0.4 Z"/>
<path class="zen-library-triangle" d="M -1.1 1.8 C -1.4 2.0, -1.7 1.8, -1.7 1.5 L -1.7 -1.5 C -1.7 -1.8, -1.4 -2.0, -1.1 -1.8 L 1.4 -0.4 C 1.7 -0.2, 1.7 0.2, 1.4 0.4 Z"/>
</g>
</g>
<g class="zen-library-glow">
<path class="zen-library-glow-bg" d="M 6.6 6.6 L 8.04 12.7 L 17.96 12.7 L 19.4 6.6 Z"/>
<path class="zen-library-glow-rays" d="M 6.1 6.6 L 8.04 12.7 L 17.96 12.7 L 19.9 6.6"/>
</g>
<path class="zen-library-box" d="M 7.218 13.287 C 7.218 12.831 7.588 12.461 8.044 12.461 H 17.957 C 18.414 12.461 18.783 12.831 18.783 13.287 V 17.418 C 18.783 19.243 17.304 20.722 15.479 20.722 H 10.523 C 8.698 20.722 7.218 19.243 7.218 17.418 V 13.287 Z M 10.609 14.526 C 10.609 14.07 10.979 13.7 11.435 13.7 H 14.739 C 15.196 13.7 15.565 14.07 15.565 14.526 C 15.565 14.982 15.196 15.352 14.739 15.352 H 11.435 C 10.979 15.352 10.609 14.982 10.609 14.526 Z"/>
</g>
</svg>

View File

@@ -309,7 +309,8 @@
display: none; display: none;
} }
#library-button { #library-button,
#zen-library-button {
list-style-image: url("library.svg") !important; list-style-image: url("library.svg") !important;
} }

View File

@@ -14,8 +14,8 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg) * skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg) * skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg) * skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg) * skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg) * skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg) * skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg) * skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
@@ -104,26 +104,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg) * skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg) * skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg) * skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg) * skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg) * skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg) * skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg) * skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg) * skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg) * skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg) * skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg) * skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg) * skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg) * skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg) * skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg) * skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg) * skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg) * skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg) * skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg) * skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg) * skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg) * skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg) * skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -164,8 +164,8 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg) * skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg) * skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg) * skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg) * skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg) * skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg) * skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg) * skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
@@ -254,26 +254,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg) * skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg) * skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg) * skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg) * skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg) * skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg) * skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg) * skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg) * skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg) * skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg) * skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg) * skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg) * skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg) * skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg) * skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg) * skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg) * skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg) * skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg) * skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg) * skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg) * skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg) * skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg) * skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -314,8 +314,8 @@
* skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg) * skin/classic/browser/zen-icons/autoplay-media-fill.svg (../shared/zen-icons/nucleo/autoplay-media-fill.svg)
* skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg) * skin/classic/browser/zen-icons/autoplay-media.svg (../shared/zen-icons/nucleo/autoplay-media.svg)
* skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg) * skin/classic/browser/zen-icons/back.svg (../shared/zen-icons/nucleo/back.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg) * skin/classic/browser/zen-icons/block.svg (../shared/zen-icons/nucleo/block.svg)
* skin/classic/browser/zen-icons/blocked-element.svg (../shared/zen-icons/nucleo/blocked-element.svg)
* skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg) * skin/classic/browser/zen-icons/bolt.svg (../shared/zen-icons/nucleo/bolt.svg)
* skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg) * skin/classic/browser/zen-icons/bookmark-hollow.svg (../shared/zen-icons/nucleo/bookmark-hollow.svg)
* skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg) * skin/classic/browser/zen-icons/bookmark-star-on-tray.svg (../shared/zen-icons/nucleo/bookmark-star-on-tray.svg)
@@ -404,26 +404,26 @@
* skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg) * skin/classic/browser/zen-icons/popup-fill.svg (../shared/zen-icons/nucleo/popup-fill.svg)
* skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg) * skin/classic/browser/zen-icons/popup.svg (../shared/zen-icons/nucleo/popup.svg)
* skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg) * skin/classic/browser/zen-icons/print.svg (../shared/zen-icons/nucleo/print.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg) * skin/classic/browser/zen-icons/private-window.svg (../shared/zen-icons/nucleo/private-window.svg)
* skin/classic/browser/zen-icons/privateBrowsing.svg (../shared/zen-icons/nucleo/privateBrowsing.svg)
* skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg) * skin/classic/browser/zen-icons/reader-mode.svg (../shared/zen-icons/nucleo/reader-mode.svg)
* skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg) * skin/classic/browser/zen-icons/reload.svg (../shared/zen-icons/nucleo/reload.svg)
* skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg) * skin/classic/browser/zen-icons/save.svg (../shared/zen-icons/nucleo/save.svg)
* skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg) * skin/classic/browser/zen-icons/screen-blocked.svg (../shared/zen-icons/nucleo/screen-blocked.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg) * skin/classic/browser/zen-icons/screen.svg (../shared/zen-icons/nucleo/screen.svg)
* skin/classic/browser/zen-icons/screenshot.svg (../shared/zen-icons/nucleo/screenshot.svg)
* skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg) * skin/classic/browser/zen-icons/search-glass.svg (../shared/zen-icons/nucleo/search-glass.svg)
* skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg) * skin/classic/browser/zen-icons/search-page.svg (../shared/zen-icons/nucleo/search-page.svg)
* skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg) * skin/classic/browser/zen-icons/security-broken.svg (../shared/zen-icons/nucleo/security-broken.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg) * skin/classic/browser/zen-icons/security-warning.svg (../shared/zen-icons/nucleo/security-warning.svg)
* skin/classic/browser/zen-icons/security.svg (../shared/zen-icons/nucleo/security.svg)
* skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg) * skin/classic/browser/zen-icons/send-to-device.svg (../shared/zen-icons/nucleo/send-to-device.svg)
* skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg) * skin/classic/browser/zen-icons/settings-fill.svg (../shared/zen-icons/nucleo/settings-fill.svg)
* skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg) * skin/classic/browser/zen-icons/settings.svg (../shared/zen-icons/nucleo/settings.svg)
* skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg) * skin/classic/browser/zen-icons/share.svg (../shared/zen-icons/nucleo/share.svg)
* skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg) * skin/classic/browser/zen-icons/sidebar-right.svg (../shared/zen-icons/nucleo/sidebar-right.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg) * skin/classic/browser/zen-icons/sidebar.svg (../shared/zen-icons/nucleo/sidebar.svg)
* skin/classic/browser/zen-icons/sidebars-right.svg (../shared/zen-icons/nucleo/sidebars-right.svg)
* skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg) * skin/classic/browser/zen-icons/sliders.svg (../shared/zen-icons/nucleo/sliders.svg)
* skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg) * skin/classic/browser/zen-icons/sparkles.svg (../shared/zen-icons/nucleo/sparkles.svg)
* skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg) * skin/classic/browser/zen-icons/spell-check.svg (../shared/zen-icons/nucleo/spell-check.svg)
@@ -453,14 +453,24 @@
* skin/classic/browser/zen-icons/zoom-out.svg (../shared/zen-icons/nucleo/zoom-out.svg) * skin/classic/browser/zen-icons/zoom-out.svg (../shared/zen-icons/nucleo/zoom-out.svg)
#endif #endif
* skin/classic/browser/zen-icons/urlbar-arrow.svg (../shared/zen-icons/common/urlbar-arrow.svg) * skin/classic/browser/zen-icons/urlbar-arrow.svg (../shared/zen-icons/common/urlbar-arrow.svg)
* skin/classic/browser/zen-icons/library/library-boosts-active.svg (../shared/zen-icons/common/library/library-boosts-active.svg)
* skin/classic/browser/zen-icons/library/library-boosts.svg (../shared/zen-icons/common/library/library-boosts.svg)
* skin/classic/browser/zen-icons/library/library-downloads-active.svg (../shared/zen-icons/common/library/library-downloads-active.svg)
* skin/classic/browser/zen-icons/library/library-downloads.svg (../shared/zen-icons/common/library/library-downloads.svg)
* skin/classic/browser/zen-icons/library/library-history-active.svg (../shared/zen-icons/common/library/library-history-active.svg)
* skin/classic/browser/zen-icons/library/library-history.svg (../shared/zen-icons/common/library/library-history.svg)
* skin/classic/browser/zen-icons/library/library-media-active.svg (../shared/zen-icons/common/library/library-media-active.svg)
* skin/classic/browser/zen-icons/library/library-media.svg (../shared/zen-icons/common/library/library-media.svg)
* skin/classic/browser/zen-icons/library/library-spaces-active.svg (../shared/zen-icons/common/library/library-spaces-active.svg)
* skin/classic/browser/zen-icons/library/library-spaces.svg (../shared/zen-icons/common/library/library-spaces.svg)
* skin/classic/browser/zen-icons/selectable/airplane.svg (../shared/zen-icons/common/selectable/airplane.svg) * skin/classic/browser/zen-icons/selectable/airplane.svg (../shared/zen-icons/common/selectable/airplane.svg)
* skin/classic/browser/zen-icons/selectable/american-football.svg (../shared/zen-icons/common/selectable/american-football.svg) * skin/classic/browser/zen-icons/selectable/american-football.svg (../shared/zen-icons/common/selectable/american-football.svg)
* skin/classic/browser/zen-icons/selectable/baseball.svg (../shared/zen-icons/common/selectable/baseball.svg) * skin/classic/browser/zen-icons/selectable/baseball.svg (../shared/zen-icons/common/selectable/baseball.svg)
* skin/classic/browser/zen-icons/selectable/basket.svg (../shared/zen-icons/common/selectable/basket.svg) * skin/classic/browser/zen-icons/selectable/basket.svg (../shared/zen-icons/common/selectable/basket.svg)
* skin/classic/browser/zen-icons/selectable/bed.svg (../shared/zen-icons/common/selectable/bed.svg) * skin/classic/browser/zen-icons/selectable/bed.svg (../shared/zen-icons/common/selectable/bed.svg)
* skin/classic/browser/zen-icons/selectable/bell.svg (../shared/zen-icons/common/selectable/bell.svg) * skin/classic/browser/zen-icons/selectable/bell.svg (../shared/zen-icons/common/selectable/bell.svg)
* skin/classic/browser/zen-icons/selectable/bookmark.svg (../shared/zen-icons/common/selectable/bookmark.svg)
* skin/classic/browser/zen-icons/selectable/book.svg (../shared/zen-icons/common/selectable/book.svg) * skin/classic/browser/zen-icons/selectable/book.svg (../shared/zen-icons/common/selectable/book.svg)
* skin/classic/browser/zen-icons/selectable/bookmark.svg (../shared/zen-icons/common/selectable/bookmark.svg)
* skin/classic/browser/zen-icons/selectable/briefcase.svg (../shared/zen-icons/common/selectable/briefcase.svg) * skin/classic/browser/zen-icons/selectable/briefcase.svg (../shared/zen-icons/common/selectable/briefcase.svg)
* skin/classic/browser/zen-icons/selectable/brush.svg (../shared/zen-icons/common/selectable/brush.svg) * skin/classic/browser/zen-icons/selectable/brush.svg (../shared/zen-icons/common/selectable/brush.svg)
* skin/classic/browser/zen-icons/selectable/bug.svg (../shared/zen-icons/common/selectable/bug.svg) * skin/classic/browser/zen-icons/selectable/bug.svg (../shared/zen-icons/common/selectable/bug.svg)
@@ -522,8 +532,8 @@
* skin/classic/browser/zen-icons/selectable/shapes.svg (../shared/zen-icons/common/selectable/shapes.svg) * skin/classic/browser/zen-icons/selectable/shapes.svg (../shared/zen-icons/common/selectable/shapes.svg)
* skin/classic/browser/zen-icons/selectable/shirt.svg (../shared/zen-icons/common/selectable/shirt.svg) * skin/classic/browser/zen-icons/selectable/shirt.svg (../shared/zen-icons/common/selectable/shirt.svg)
* skin/classic/browser/zen-icons/selectable/skull.svg (../shared/zen-icons/common/selectable/skull.svg) * skin/classic/browser/zen-icons/selectable/skull.svg (../shared/zen-icons/common/selectable/skull.svg)
* skin/classic/browser/zen-icons/selectable/squares.svg (../shared/zen-icons/common/selectable/squares.svg)
* skin/classic/browser/zen-icons/selectable/square.svg (../shared/zen-icons/common/selectable/square.svg) * skin/classic/browser/zen-icons/selectable/square.svg (../shared/zen-icons/common/selectable/square.svg)
* skin/classic/browser/zen-icons/selectable/squares.svg (../shared/zen-icons/common/selectable/squares.svg)
* skin/classic/browser/zen-icons/selectable/star-1.svg (../shared/zen-icons/common/selectable/star-1.svg) * skin/classic/browser/zen-icons/selectable/star-1.svg (../shared/zen-icons/common/selectable/star-1.svg)
* skin/classic/browser/zen-icons/selectable/star.svg (../shared/zen-icons/common/selectable/star.svg) * skin/classic/browser/zen-icons/selectable/star.svg (../shared/zen-icons/common/selectable/star.svg)
* skin/classic/browser/zen-icons/selectable/stats-chart.svg (../shared/zen-icons/common/selectable/stats-chart.svg) * skin/classic/browser/zen-icons/selectable/stats-chart.svg (../shared/zen-icons/common/selectable/stats-chart.svg)

View File

@@ -53,12 +53,15 @@ do_common_icons() {
echo "Working on $filename" echo "Working on $filename"
echo "* skin/classic/browser/zen-icons/$filename (../shared/zen-icons/common/$filename) " >> jar.inc.mn echo "* skin/classic/browser/zen-icons/$filename (../shared/zen-icons/common/$filename) " >> jar.inc.mn
done done
for filename in common/selectable/*.svg; do # go through all subdirectories of common and do the same
# remove the os/ prefix for dir in common/*/; do
add_header_to_file $filename display_dir=$(basename $dir)
filename=$(basename $filename) for filename in $dir/*.svg; do
echo "Working on $filename" add_header_to_file $filename
echo "* skin/classic/browser/zen-icons/selectable/$filename (../shared/zen-icons/common/selectable/$filename) " >> jar.inc.mn filename=$(basename $filename)
echo "Working on $filename"
echo "* skin/classic/browser/zen-icons/$display_dir/$filename (../shared/zen-icons/common/$display_dir/$filename) " >> jar.inc.mn
done
done done
} }

View File

@@ -28,6 +28,7 @@
"chrome://browser/content/zen-components/ZenEmojiPicker.mjs", "chrome://browser/content/zen-components/ZenEmojiPicker.mjs",
"chrome://browser/content/zen-components/ZenLiveFoldersUI.mjs", "chrome://browser/content/zen-components/ZenLiveFoldersUI.mjs",
"chrome://browser/content/zen-components/ZenDownloadAnimation.mjs", "chrome://browser/content/zen-components/ZenDownloadAnimation.mjs",
"moz-src:///zen/library/ZenLibraryButton.mjs",
]; ];
for (let script of scripts) { for (let script of scripts) {

View File

@@ -795,3 +795,162 @@
display: none; display: none;
} }
} }
#zen-library-button {
position: relative;
}
#zen-library-button::after {
content: "";
position: absolute;
top: 1px;
right: 1px;
width: 12px;
height: 12px;
border-radius: 50%;
background:
conic-gradient(
var(--zen-colors-primary, currentColor)
calc(var(--zen-library-button-progress, 0) * 360deg),
color-mix(in srgb, currentColor 25%, transparent) 0
);
mask: radial-gradient(circle, transparent 3.5px, black 4px);
pointer-events: none;
opacity: 0;
transform: scale(0.6);
transition:
opacity 0.18s ease,
transform 0.18s cubic-bezier(0.32, 0.72, 0, 1);
}
#zen-library-button[downloading]::after {
opacity: 1;
transform: scale(1);
}
@keyframes zen-library-button-spin {
to {
transform: rotate(360deg);
}
}
#zen-library-button[downloading-indeterminate]::after {
background: conic-gradient(
var(--zen-colors-primary, currentColor) 0deg 90deg,
color-mix(in srgb, currentColor 20%, transparent) 90deg 360deg
);
animation: zen-library-button-spin 1.05s linear infinite;
}
#zen-library-button[downloading]::before {
content: "";
position: absolute;
top: 5px;
right: 5px;
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--zen-colors-primary, currentColor);
pointer-events: none;
}
/*
* Stack of recent download tiles inserted just before
* #zen-sidebar-foot-buttons. Visible only while hovering the library button
* (or the stack itself). Anchored to the bottom of #navigator-toolbox so it
* floats above the tab strip without pushing layout.
*/
#navigator-toolbox {
position: relative;
}
.zen-library-button-panel {
position: absolute;
left: 0;
right: 0;
bottom: var(--zen-library-stack-bottom-offset, 42px);
z-index: 2;
padding: 6px 8px;
opacity: 0;
transform: translateY(8px);
pointer-events: none;
}
.zen-library-button-panel[data-state="open"] {
pointer-events: auto;
}
/* Fade the bottom of the tab strip so it doesn't visually collide with
* the floating download stack. The fade region scales with the actual
* stack height (published from JS as --zen-library-stack-height). */
#tabbrowser-tabs[zen-library-stack-open="true"] {
mask-image: linear-gradient(to bottom, black var(--zen-library-stack-height), black 50%, transparent calc(100% - var(--zen-library-stack-height) + 20px));
transition: mask-image 0.18s ease;
}
.zen-library-button-panel-list {
display: flex;
flex-direction: column;
gap: 2px;
}
.zen-library-button-panel-empty {
padding: 12px 10px;
text-align: center;
font-size: 12px;
opacity: 0.6;
}
.zen-library-button-panel-row {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 8px;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.12s ease;
}
.zen-library-button-panel-row:hover {
background: color-mix(in srgb, currentColor 10%, transparent);
}
.zen-library-button-panel-icon {
flex-shrink: 0;
width: 32px;
height: 32px;
border-radius: 6px;
}
.zen-library-button-panel-labels {
display: flex;
flex: 1;
min-width: 0;
flex-direction: column;
gap: 2px;
}
.zen-library-button-panel-name {
margin: 0;
font-size: 12.5px;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
}
.zen-library-button-panel-row[data-file-deleted] .zen-library-button-panel-name {
text-decoration: line-through;
opacity: 0.6;
}
.zen-library-button-panel-status {
margin: 0;
font-size: 10.5px;
opacity: 0.65;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: none;
}

View File

@@ -9,7 +9,7 @@ export const ZenCustomizableUI = new (class {
TYPE_TOOLBAR = "toolbar"; TYPE_TOOLBAR = "toolbar";
defaultSidebarIcons = [ defaultSidebarIcons = [
"downloads-button", Services.prefs.getBoolPref("zen.library.enabled") ? "zen-library-button" : "downloads-button",
"zen-workspaces-button", "zen-workspaces-button",
"zen-create-new-button", "zen-create-new-button",
]; ];

View File

@@ -7,11 +7,14 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
const lazy = {}; const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, { ChromeUtils.defineESModuleGetters(lazy, {
CustomizableUI: "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs",
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
}); });
class nsZenUIMigration { class nsZenUIMigration {
PREF_NAME = "zen.ui.migration.version"; PREF_NAME = "zen.ui.migration.version";
PREF_LIBRARY_REPLACED_DOWNLOADS =
"zen.ui.migration.library-button-replaced-downloads";
MIGRATION_VERSION = 6; MIGRATION_VERSION = 6;
init(isNewProfile) { init(isNewProfile) {
@@ -22,6 +25,14 @@ class nsZenUIMigration {
console.error("ZenUIMigration: Error during migration", e); console.error("ZenUIMigration: Error during migration", e);
} }
} }
try {
this.#maybeReplaceDownloadsWithLibrary(isNewProfile);
} catch (e) {
console.error(
"ZenUIMigration: Error replacing downloads with library button",
e
);
}
this.clearVariables(); this.clearVariables();
if (this.shouldRestart) { if (this.shouldRestart) {
Services.startup.quit( Services.startup.quit(
@@ -50,6 +61,28 @@ class nsZenUIMigration {
this._migrationVersion = this.MIGRATION_VERSION; this._migrationVersion = this.MIGRATION_VERSION;
} }
#maybeReplaceDownloadsWithLibrary(isNewProfile) {
if (
Services.prefs.getBoolPref(this.PREF_LIBRARY_REPLACED_DOWNLOADS, false)
) {
return;
}
if (!isNewProfile) {
const placement =
lazy.CustomizableUI.getPlacementOfWidget("downloads-button");
if (placement?.area === "zen-sidebar-foot-buttons") {
const { position } = placement;
lazy.CustomizableUI.removeWidgetFromArea("downloads-button");
lazy.CustomizableUI.addWidgetToArea(
"zen-library-button",
"zen-sidebar-foot-buttons",
position
);
}
}
Services.prefs.setBoolPref(this.PREF_LIBRARY_REPLACED_DOWNLOADS, true);
}
_migrateV1() { _migrateV1() {
// If there's an userChrome.css or userContent.css existing, we set // If there's an userChrome.css or userContent.css existing, we set
// 'toolkit.legacyUserProfileCustomizations.stylesheets' back to true // 'toolkit.legacyUserProfileCustomizations.stylesheets' back to true

View File

@@ -133,6 +133,12 @@ document.addEventListener(
gZenWorkspaces.unloadAllOtherWorkspaces(); gZenWorkspaces.unloadAllOtherWorkspaces();
break; break;
} }
case "cmd_zenToggleLibrary": {
const { ZenLibrary } = ChromeUtils.importESModule(
"moz-src:///zen/library/ZenLibrary.mjs",
{ global: "current" }
);
ZenLibrary.toggle();
case "cmd_zenOpenSpaceRoutingSettings": { case "cmd_zenOpenSpaceRoutingSettings": {
gZenSpaceRoutingManager.openSpaceRoutingDialog(window); gZenSpaceRoutingManager.openSpaceRoutingDialog(window);
break; break;

View File

@@ -147,10 +147,20 @@ class nsZenDownloadAnimationElement extends HTMLElement {
return Services.prefs.getBoolPref("zen.tabs.vertical.right-side"); return Services.prefs.getBoolPref("zen.tabs.vertical.right-side");
} }
get #downloadButton() {
const ids = ["zen-library-button", "downloads-button"];
for (const id of ids) {
const button = document.getElementById(id);
if (button && this.#isElementVisible(button)) {
return button;
}
}
return null;
}
#determineEndPosition() { #determineEndPosition() {
const downloadsButton = document.getElementById("downloads-button"); const downloadsButton = this.#downloadButton;
const isDownloadButtonVisible = const isDownloadButtonVisible = downloadsButton !== null;
downloadsButton && this.#isElementVisible(downloadsButton);
let endPosition = { clientX: 0, clientY: 0 }; let endPosition = { clientX: 0, clientY: 0 };

View File

@@ -723,8 +723,11 @@
const { isNearLeftEdge, isNearRightEdge } = const { isNearLeftEdge, isNearRightEdge } =
this.#shouldSwitchSpace(event); this.#shouldSwitchSpace(event);
if (isNearLeftEdge || isNearRightEdge) { if (isNearLeftEdge || isNearRightEdge) {
if (!this.#changeSpaceTimer) { if (!this.#changeSpaceTimer && !this.#isOutOfWindow) {
this.#changeSpaceTimer = setTimeout(() => { this.#changeSpaceTimer = setTimeout(() => {
if (this.#isOutOfWindow) {
return;
}
this.clearDragOverVisuals(); this.clearDragOverVisuals();
gZenWorkspaces gZenWorkspaces
.changeWorkspaceShortcut( .changeWorkspaceShortcut(
@@ -956,8 +959,10 @@
if (ownerGlobal?.gZenCompactModeManager) { if (ownerGlobal?.gZenCompactModeManager) {
// Sometimes, dragend doesn't always get called when dragging // Sometimes, dragend doesn't always get called when dragging
// to different windows, see gh-8643. // to different windows, see gh-8643.
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged; requestAnimationFrame(() => {
ownerGlobal.gZenCompactModeManager._clearAllHoverStates(); delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
});
} }
this.clearSpaceSwitchTimer(); this.clearSpaceSwitchTimer();
gZenFolders.highlightGroupOnDragOver(null); gZenFolders.highlightGroupOnDragOver(null);

View File

@@ -0,0 +1,529 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
import { html } from "chrome://global/content/vendor/lit.all.mjs";
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
let lazy = {};
let gZenLibraryInstance = null;
const PREVIOUS_TAB_PREF = "zen.library.previous-tab";
ChromeUtils.defineESModuleGetters(
lazy,
{
ZenLibrarySections: "moz-src:///zen/library/ZenLibrarySections.mjs",
},
{ global: "current" }
);
ChromeUtils.defineLazyGetter(lazy, "l10n", function () {
return new Localization(["browser/zen-library.ftl"], true);
});
ChromeUtils.defineLazyGetter(lazy, "appContentWrapper", function () {
return document.getElementById("zen-appcontent-wrapper");
});
/**
* The ZenLibrary class is responsible for managing the UI for the library feature.
* This feature allows users to view and manage their browsing history, downloads,
* spaces, and other related data in a unified interface.
*/
export class ZenLibrary extends MozLitElement {
static #ANIMATION_DURATION = 280;
static #ANIMATION_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
static #TOOLBOX_OPEN_TRANSFORM = "scale(0.96)";
static #TOOLBOX_OPEN_OPACITY = "-0.5";
#initialized = false;
#resizeObserver = null;
#sections = [];
#activeAnimations = new Set();
#animating = false;
_deletionIdleCallbackId = null;
static properties = {
_activeTab: { type: String },
};
static queries = {
_content: "#zen-library-content",
_tabs: { all: "#zen-library-sidebar-tabs > .library-tab" },
_header: "#zen-library-sidebar-header",
};
createRenderRoot() {
return this;
}
constructor() {
super();
this._iconKeys = {};
this.activeTab = Services.prefs.getStringPref(PREVIOUS_TAB_PREF, "") || "history";
}
set activeTab(value) {
if (this.activeTab === value) {
return;
}
this._iconKeys[value] = Date.now();
this._activeTab = value;
Services.prefs.setStringPref(PREVIOUS_TAB_PREF, value);
}
get activeTab() {
return this._activeTab;
}
connectedCallback() {
super.connectedCallback();
if (this.#initialized) {
return;
}
window.addEventListener("keydown", this);
// Add connected call back and make `appContentWrapper` transform translate the oposite of this element
this.#resizeObserver = new ResizeObserver(() => {
if (gZenWorkspaces._swipeManager._swipeState.librarySwiping) {
return;
}
let translateX = this.#computeWrapperTargetPx();
lazy.appContentWrapper.style.transform = `translateX(${translateX}px)`;
});
this.#resizeObserver.observe(this);
for (const Section of Object.values(lazy.ZenLibrarySections)) {
let section = new Section();
this.#sections.push(section);
}
this.#initialized = true;
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener("keydown", this);
for (const section of this.#sections) {
section.remove();
}
this.#sections = [];
if (this.#resizeObserver) {
this.#resizeObserver.disconnect();
this.#resizeObserver = null;
}
this.#initialized = false;
}
firstUpdated() {
super.firstUpdated?.();
this._header.appendChild(
gZenVerticalTabsManager.actualWindowButtons.cloneNode(true)
);
}
render() {
return html`
<link
rel="stylesheet"
href="chrome://browser/content/zen-styles/zen-library.css"
/>
<vbox id="zen-library-sidebar">
<vbox id="zen-library-sidebar-header"></vbox>
<vbox id="zen-library-sidebar-tabs">
${Object.values(lazy.ZenLibrarySections).map(
Section => html`
<vbox
class="zen-library-tab"
?active=${this.activeTab === Section.id}
@click=${() => {
this._iconKeys[Section.id] = Date.now();
if (this.activeTab !== Section.id) {
this.activeTab = Section.id;
} else {
this.requestUpdate();
}
}}
>
${this.activeTab === Section.id
? html`<img
src=${`chrome://browser/skin/zen-icons/library/library-${Section.id}-active.svg?t=${this._iconKeys[Section.id]}`}
/>`
: html`<img
src=${`chrome://browser/skin/zen-icons/library/library-${Section.id}.svg`}
/>`}
<label>${lazy.l10n.formatValueSync(Section.label)}</label>
</vbox>
`
)}
</vbox>
<vbox id="zen-library-sidebar-footer"></vbox>
</vbox>
<vbox
id="zen-library-content"
flex="1"
?large-content=${lazy.ZenLibrarySections[this.activeTab].largeContent}
>
${this.#sections.find(section => section.constructor.id === this.activeTab)}
</vbox>
`;
}
handleEvent(event) {
switch (event.type) {
case "keydown": {
if (event.key === "Escape" && this.isOpen) {
ZenLibrary.toggle();
}
break;
}
}
}
get isOpen() {
return this.hasAttribute("open");
}
/** True when a live library instance exists and is in the open state. */
static get isOpen() {
return gZenLibraryInstance?.isOpen ?? false;
}
static getInstance() {
if (!gZenLibraryInstance) {
gZenLibraryInstance = new ZenLibrary();
gNavToolbox.before(gZenLibraryInstance);
}
return gZenLibraryInstance;
}
static clearInstance() {
if (gZenLibraryInstance) {
gZenLibraryInstance._deletionIdleCallbackId = null;
gZenLibraryInstance.remove();
gZenLibraryInstance = null;
}
}
static toggle() {
if (gZenLibraryInstance?.#animating) {
return;
}
window.docShell.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIAppWindow)
.rollupAllPopups();
let instance = this.getInstance();
instance.toggleAttribute("open");
if (instance.isOpen) {
if (instance._deletionIdleCallbackId) {
cancelIdleCallback(instance._deletionIdleCallbackId);
instance._deletionIdleCallbackId = null;
}
gNavToolbox.setAttribute("zen-library-open", "true");
instance.#animateOpen();
} else {
gNavToolbox.removeAttribute("zen-library-open");
// #animateClose schedules the instance disposal itself once the slide-
// out finishes, so we don't queue an idle callback eagerly here — that
// would otherwise race the animation and yank the element out of the
// DOM mid-slide.
instance.#animateClose();
}
}
#cancelActiveAnimations() {
for (const anim of this.#activeAnimations) {
try {
anim.cancel();
} catch {
/* already settled */
}
}
this.#activeAnimations.clear();
}
#animate(element, keyframes) {
const anim = element.animate(keyframes, {
duration: ZenLibrary.#ANIMATION_DURATION,
easing: ZenLibrary.#ANIMATION_EASING,
fill: "forwards",
});
this.#activeAnimations.add(anim);
anim.finished.then(
() => this.#activeAnimations.delete(anim),
() => this.#activeAnimations.delete(anim)
);
return anim;
}
/**
* Mirrors the ResizeObserver's math but returns the translateX (px) instead
* of writing it inline. Used when the observer hasn't fired yet (re-opens
* on the same instance) or when we need a target without side effects.
*/
#computeWrapperTargetPx() {
const isRightSide = gZenVerticalTabsManager._prefsRightSide;
let translateX = this.getBoundingClientRect()[
isRightSide ? "left" : "right"
];
const contentPosition = window.windowUtils.getBoundsWithoutFlushing(
lazy.appContentWrapper
)[isRightSide ? "right" : "left"];
const existingTransform = new DOMMatrix(
lazy.appContentWrapper.style.transform
).m41;
translateX = translateX - contentPosition + existingTransform;
return isRightSide ? -translateX : translateX;
}
async #animateOpen() {
this.#animating = true;
try {
this.#cancelActiveAnimations();
await new Promise(r => requestAnimationFrame(r));
if (!this.isOpen || !this.isConnected) {
return;
}
// Re-opens on the same instance won't trigger the observer (library
// size is unchanged), so fall back to computing the target ourselves.
let wrapperTarget = lazy.appContentWrapper.style.transform;
if (!wrapperTarget) {
wrapperTarget = `translateX(${this.#computeWrapperTargetPx()}px)`;
}
lazy.appContentWrapper.style.transform = "";
this.#animate(this, [
{ transform: "translateX(-100%)", opacity: 0 },
{ transform: "translateX(0)", opacity: 1 },
]);
this.#animate(gNavToolbox, [
{ transform: "scale(1)", opacity: 1 },
{
transform: ZenLibrary.#TOOLBOX_OPEN_TRANSFORM,
opacity: ZenLibrary.#TOOLBOX_OPEN_OPACITY,
},
]);
const wrapperAnim = this.#animate(lazy.appContentWrapper, [
{ transform: "translateX(0)" },
{ transform: wrapperTarget },
]);
try {
await wrapperAnim.finished;
} catch {
return;
}
if (!this.isOpen) {
return;
}
// Persist the final transform inline so the resize observer's
// diff math keeps working after the animation ends.
wrapperAnim.commitStyles();
wrapperAnim.cancel();
this.#activeAnimations.delete(wrapperAnim);
} finally {
this.#animating = false;
}
}
/**
* Prepare the library for swipe-driven state changes. Works whether the
* library is currently open (close swipe) or closed (open swipe). After
* this resolves, callers drive `updateSwipeProgress(0..1)` directly until
* `finishSwipe(targetOpen)` commits or reverts.
*/
static async beginSwipe() {
// Refuse to enter swipe mode while a non-swipe animation is still
// running; let it finish so the start/end states are well-defined.
if (gZenLibraryInstance?.#animating) {
return;
}
const instance = this.getInstance();
if (instance._deletionIdleCallbackId) {
cancelIdleCallback(instance._deletionIdleCallbackId);
instance._deletionIdleCallbackId = null;
}
instance.#cancelActiveAnimations();
const wasOpen = instance.hasAttribute("open");
if (wasOpen) {
// Library is already open; the wrapper's current inline transform IS
// the target — no remeasure needed.
instance._swipeWrapperTargetPx =
new DOMMatrix(lazy.appContentWrapper.style.transform).m41 ||
instance.#computeWrapperTargetPx();
} else {
// Measure the open-state wrapper target without flashing: temporarily
// mark [open] so layout reflects the open position, then revert.
instance.setAttribute("open", "true");
instance.style.visibility = "hidden";
await new Promise(r => requestAnimationFrame(r));
instance._swipeWrapperTargetPx = instance.#computeWrapperTargetPx();
instance.style.visibility = "";
instance.removeAttribute("open");
lazy.appContentWrapper.style.transform = "";
}
instance._swipeActive = true;
// Initialize visual state to match the current attribute.
ZenLibrary.updateSwipeProgress(wasOpen ? 1 : 0);
}
/**
* Sets the library, toolbox, and content-wrapper styles to a fraction
* (0..1) of the way to fully open. Must be preceded by `beginSwipe()`.
*
* @param {number} progress
*/
static updateSwipeProgress(progress) {
const instance = gZenLibraryInstance;
if (!instance?._swipeActive) {
return;
}
const p = Math.max(0, Math.min(1, progress));
instance.style.transform = `translateX(${(-1 + p) * 100}%)`;
instance.style.opacity = String(p);
const targetOpacity = Number(ZenLibrary.#TOOLBOX_OPEN_OPACITY);
gNavToolbox.style.setProperty(
"transform",
`scale(${1 - p * 0.04})`,
"important"
);
gNavToolbox.style.setProperty(
"opacity",
String(1 - p * (1 - targetOpacity)),
"important"
);
lazy.appContentWrapper.style.setProperty(
"transform",
`translateX(${p * (instance._swipeWrapperTargetPx ?? 0)}px)`,
"important"
);
instance._swipeProgress = p;
}
/**
* Finish a swipe gesture. If `targetOpen` is true, animate the remaining
* distance to fully open; otherwise animate to fully closed and dispose
* the instance like a normal close.
*
* @param {boolean} targetOpen
*/
static async finishSwipe(targetOpen) {
const instance = gZenLibraryInstance;
if (!instance?._swipeActive) {
return;
}
instance._swipeActive = false;
const libFromTransform = instance.style.transform;
const libFromOpacity = instance.style.opacity;
const tbFromTransform = gNavToolbox.style.transform;
const tbFromOpacity = gNavToolbox.style.opacity;
const wrapperFromX = new DOMMatrix(lazy.appContentWrapper.style.transform)
.m41;
// Hand off styling to WAAPI by clearing the inline styles we set during
// the swipe; the keyframes restore the from-state on their first frame.
instance.style.transform = "";
instance.style.opacity = "";
gNavToolbox.style.transform = "";
gNavToolbox.style.opacity = "";
lazy.appContentWrapper.style.transform = "";
if (targetOpen) {
instance.setAttribute("open", "true");
gNavToolbox.setAttribute("zen-library-open", "true");
instance.#animate(instance, [
{ transform: libFromTransform, opacity: libFromOpacity },
{ transform: "translateX(0)", opacity: 1 },
]);
instance.#animate(gNavToolbox, [
{ transform: tbFromTransform, opacity: tbFromOpacity },
{
transform: ZenLibrary.#TOOLBOX_OPEN_TRANSFORM,
opacity: ZenLibrary.#TOOLBOX_OPEN_OPACITY,
},
]);
const wrapperAnim = instance.#animate(lazy.appContentWrapper, [
{ transform: `translateX(${wrapperFromX}px)` },
{ transform: `translateX(${instance._swipeWrapperTargetPx}px)` },
]);
try {
await wrapperAnim.finished;
if (instance.isOpen) {
wrapperAnim.commitStyles();
wrapperAnim.cancel();
instance.#activeAnimations.delete(wrapperAnim);
}
} catch {
/* cancelled by a follow-up toggle */
}
} else {
instance.removeAttribute("open");
gNavToolbox.removeAttribute("zen-library-open");
instance.#animate(instance, [
{ transform: libFromTransform, opacity: libFromOpacity },
{ transform: "translateX(-100%)", opacity: 0 },
]);
instance.#animate(gNavToolbox, [
{ transform: tbFromTransform, opacity: tbFromOpacity },
{ transform: "scale(1)", opacity: 1 },
]);
instance.#animate(lazy.appContentWrapper, [
{ transform: `translateX(${wrapperFromX}px)` },
{ transform: "translateX(0)" },
]);
if (!instance._deletionIdleCallbackId) {
instance._deletionIdleCallbackId = requestIdleCallback(() => {
ZenLibrary.clearInstance();
});
}
}
}
async #animateClose() {
this.#animating = true;
try {
this.#cancelActiveAnimations();
const wrapperCurrent =
lazy.appContentWrapper.style.transform ||
getComputedStyle(lazy.appContentWrapper).transform ||
"translateX(0)";
lazy.appContentWrapper.style.transform = "";
const libAnim = this.#animate(this, [
{ transform: "translateX(0)", opacity: 1 },
{ transform: "translateX(-100%)", opacity: 0 },
]);
this.#animate(gNavToolbox, [
{
transform: ZenLibrary.#TOOLBOX_OPEN_TRANSFORM,
opacity: ZenLibrary.#TOOLBOX_OPEN_OPACITY,
},
{ transform: "scale(1)", opacity: 1 },
]);
this.#animate(lazy.appContentWrapper, [
{ transform: wrapperCurrent },
{ transform: "translateX(0)" },
]);
try {
await libAnim.finished;
} catch {
// Cancelled by a follow-up open before the slide finished.
return;
}
// If the user re-opened in the meantime, leave the live instance alone.
if (this.isOpen) {
return;
}
if (!this._deletionIdleCallbackId) {
this._deletionIdleCallbackId = requestIdleCallback(() => {
ZenLibrary.clearInstance();
});
}
} finally {
this.#animating = false;
}
}
}
customElements.define("zen-library", ZenLibrary);

View File

@@ -0,0 +1,556 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
DownloadsCommon:
"moz-src:///browser/components/downloads/DownloadsCommon.sys.mjs",
DownloadsViewUI:
"moz-src:///browser/components/downloads/DownloadsViewUI.sys.mjs",
DownloadUtils: "resource://gre/modules/DownloadUtils.sys.mjs",
FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
});
const RECENT_KEEP = 5;
// Mouse can stray this far past the panel/button before we dismiss the stack.
const HOVER_TOLERANCE_TOP_PX = 100;
const HOVER_TOLERANCE_SIDE_PX = 40;
/**
* Per-window controller for the toolbar Library button:
* - Watches downloads and overlays a progress ring on the button while
* anything is in flight (indeterminate spinner when total bytes are
* unknown).
* - Pops a small panel with the most recent finished/active downloads
* when the user hovers the button.
*/
class nsZenLibraryButton extends nsZenDOMOperatedFeature {
#button = null;
#downloads = null;
#view = null;
#active = new Set();
#recent = [];
#panel = null;
#closeAnim = null;
#trackingMouse = false;
#contextMenuOpen = false;
init() {
this.#button = document.getElementById("zen-library-button");
if (!this.#button) {
return;
}
this.#setupDownloads();
this.#button.addEventListener("mouseenter", this);
window.addEventListener("unload", this, { once: true });
}
handleEvent(event) {
switch (event.type) {
case "mouseenter":
this.#onEnter();
break;
case "mousemove":
this.#checkMousePosition(event);
break;
case "unload":
this.#button?.removeEventListener("mouseenter", this);
this.#detachMouseTracking();
if (this.#downloads && this.#view) {
this.#downloads.removeView(this.#view);
}
break;
}
}
#setupDownloads() {
this.#downloads = lazy.DownloadsCommon.getData(window, true);
this.#view = {
onDownloadAdded: dl => {
if (!dl.stopped) {
this.#active.add(dl);
} else if (dl.succeeded) {
this.#pushRecent(dl);
}
this.#updateRing();
this.#refreshPanel();
},
onDownloadChanged: dl => {
if (dl.stopped) {
this.#active.delete(dl);
if (dl.succeeded) {
this.#pushRecent(dl);
}
} else {
this.#active.add(dl);
}
this.#updateRing();
this.#refreshPanel();
},
onDownloadRemoved: dl => {
this.#active.delete(dl);
this.#recent = this.#recent.filter(d => d !== dl);
this.#updateRing();
this.#refreshPanel();
},
};
this.#downloads.addView(this.#view);
}
#pushRecent(dl) {
if (!this.#recent.includes(dl)) {
this.#recent.unshift(dl);
this.#recent = this.#recent.slice(0, RECENT_KEEP);
}
}
/** Update the conic-gradient progress + indeterminate state on the button. */
#updateRing() {
if (!this.#button) {
return;
}
if (this.#active.size === 0) {
this.#button.removeAttribute("downloading");
this.#button.removeAttribute("downloading-indeterminate");
this.#button.style.removeProperty("--zen-library-button-progress");
return;
}
let total = 0;
let current = 0;
let hasUnknown = false;
for (const dl of this.#active) {
if (dl.hasProgress && dl.totalBytes > 0) {
total += dl.totalBytes;
current += dl.currentBytes;
} else {
hasUnknown = true;
}
}
this.#button.setAttribute("downloading", "true");
if (hasUnknown || total === 0) {
this.#button.setAttribute("downloading-indeterminate", "true");
this.#button.style.removeProperty("--zen-library-button-progress");
} else {
this.#button.removeAttribute("downloading-indeterminate");
const ratio = Math.max(0, Math.min(1, current / total));
this.#button.style.setProperty(
"--zen-library-button-progress",
String(ratio)
);
}
}
#ensurePanel() {
if (this.#panel) {
return this.#panel;
}
const stack = document.createElement("div");
stack.id = "zen-library-button-panel";
stack.classList.add("zen-library-button-panel");
stack.dataset.state = "closed";
const list = document.createElement("div");
list.className = "zen-library-button-panel-list";
stack.appendChild(list);
const host = document.getElementById("zen-sidebar-foot-buttons");
host.before(stack);
this.#panel = stack;
return stack;
}
#refreshPanel() {
if (!this.#panel || this.#panel.dataset.state !== "open") {
return;
}
this.#populatePanel();
}
#populatePanel() {
const items = [
...Array.from(this.#active),
...this.#recent.filter(d => !this.#active.has(d)),
].slice(0, RECENT_KEEP);
if (!items.length) {
return;
}
const panel = this.#ensurePanel();
const list = panel.querySelector(".zen-library-button-panel-list");
list.replaceChildren();
for (const dl of items) {
list.appendChild(this.#renderRow(dl));
}
}
#renderRow(dl) {
const row = document.createElement("div");
row.className = "zen-library-button-panel-row";
if (this.#isFileMissing(dl)) {
row.dataset.fileDeleted = "true";
}
row.addEventListener("click", () => {
if (dl.succeeded) {
lazy.DownloadsCommon.openDownload(dl).catch(console.error);
} else if (dl.source?.url) {
window.openTrustedLinkIn(dl.source.url, "tab");
}
});
row.addEventListener("contextmenu", e => this.#showContextMenu(e, dl));
const icon = document.createElement("img");
icon.className = "zen-library-button-panel-icon";
icon.alt = "";
icon.src = dl.target?.path
? `moz-icon://${dl.target.path}?size=16`
: "moz-icon://.unknown?size=16";
row.appendChild(icon);
const labels = document.createElement("div");
labels.className = "zen-library-button-panel-labels";
const display = lazy.DownloadsViewUI.getDisplayName(dl);
const name = typeof display === "string" ? display : dl.source?.url || "";
const label = document.createXULElement("label");
label.className = "zen-library-button-panel-name";
label.textContent = name;
labels.appendChild(label);
const sublabel = document.createXULElement("label");
sublabel.className = "zen-library-button-panel-status";
sublabel.textContent = this.#statusFor(dl);
labels.appendChild(sublabel);
row.appendChild(labels);
return row;
}
/** True when the on-disk file is gone (deleted / moved). */
#isFileMissing(dl) {
if (!dl) {
return false;
}
if (dl.deleted) {
return true;
}
return dl.succeeded && dl.target?.exists === false;
}
#statusFor(dl) {
const C = lazy.DownloadsCommon;
const state = C.stateOfDownload(dl);
if (state === C.DOWNLOAD_DOWNLOADING) {
const total = dl.hasProgress ? dl.totalBytes : -1;
const [status] = lazy.DownloadUtils.getDownloadStatus(
dl.currentBytes,
total,
dl.speed
);
return status;
}
if (state === C.DOWNLOAD_FINISHED) {
return (
lazy.DownloadsViewUI.getSizeWithUnits(dl) ||
C.strings.sizeUnknown ||
""
);
}
if (state === C.DOWNLOAD_PAUSED) {
return C.strings.statePaused || "Paused";
}
if (state === C.DOWNLOAD_FAILED) {
return C.strings.stateFailed || "Failed";
}
if (state === C.DOWNLOAD_CANCELED) {
return C.strings.stateCanceled || "Canceled";
}
return "";
}
/**
* Right-click → small XUL menupopup mirroring the relevant subset of
* Firefox's `downloadsContextMenu` (built dynamically so we can react to
* each row's current state). Reuses `browser/downloads.ftl` strings.
*/
#showContextMenu(event, dl) {
event.preventDefault();
event.stopPropagation();
const C = lazy.DownloadsCommon;
const state = C.stateOfDownload(dl);
const isFinished = state === C.DOWNLOAD_FINISHED;
const isActive =
state === C.DOWNLOAD_DOWNLOADING || state === C.DOWNLOAD_PAUSED;
const fileExists = isFinished && dl.target?.exists !== false && !dl.deleted;
const sourceUrl = dl.source?.originalUrl || dl.source?.url;
const items = [];
if (state === C.DOWNLOAD_DOWNLOADING) {
items.push({
l10nId: "downloads-cmd-pause",
onClick: () => dl.cancel().catch(() => {}),
});
} else if (state === C.DOWNLOAD_PAUSED) {
items.push({
l10nId: "downloads-cmd-resume",
onClick: () => dl.start?.().catch(() => {}),
});
}
if (fileExists) {
items.push({
l10nId: "downloads-cmd-show-menuitem-2",
onClick: () => {
try {
const file = new lazy.FileUtils.File(dl.target.path);
C.showDownloadedFile(file);
} catch (ex) {
console.error(ex);
}
},
});
}
if (sourceUrl) {
items.push({
l10nId: "downloads-cmd-go-to-download-page",
onClick: () => window.openTrustedLinkIn(sourceUrl, "tab"),
});
items.push({
l10nId: "downloads-cmd-copy-download-link",
onClick: () => {
const helper = Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(Ci.nsIClipboardHelper);
helper.copyString(sourceUrl);
},
});
}
items.push({ separator: true });
if (fileExists) {
items.push({
l10nId: "downloads-cmd-delete-file",
onClick: () => {
C.deleteDownloadFiles(
dl,
lazy.DownloadsViewUI.clearHistoryOnDelete
).catch(console.error);
},
});
}
if (!isActive) {
items.push({
l10nId: "downloads-cmd-remove-from-history",
onClick: () => C.deleteDownload(dl).catch(console.error),
});
}
if (!items.some(i => !i.separator)) {
return;
}
const popupSet = document.getElementById("mainPopupSet");
const popup = document.createXULElement("menupopup");
for (const item of items) {
if (item.separator) {
if (
!popup.lastChild ||
popup.lastChild.tagName === "menuseparator"
) {
continue;
}
popup.appendChild(document.createXULElement("menuseparator"));
continue;
}
const mi = document.createXULElement("menuitem");
mi.setAttribute("data-l10n-id", item.l10nId);
mi.addEventListener(
"command",
() => {
try {
item.onClick?.();
} catch (ex) {
console.error(ex);
}
},
{ once: true }
);
popup.appendChild(mi);
}
// Drop a trailing separator if any.
while (popup.lastChild?.tagName === "menuseparator") {
popup.lastChild.remove();
}
// Pin the hover panel open for the lifetime of the context menu — the
// popup briefly steals focus and would otherwise let the mouse-distance
// check dismiss the stack mid-interaction.
this.#contextMenuOpen = true;
popup.addEventListener(
"popuphidden",
() => {
this.#contextMenuOpen = false;
popup.remove();
// Re-evaluate distance now that the popup is gone.
if (this.#panel?.dataset.state === "open") {
this.#checkMousePosition();
}
},
{ once: true }
);
popupSet.appendChild(popup);
popup.openPopupAtScreen(event.screenX, event.screenY, true);
}
#onEnter() {
if (this.#active.size === 0 && this.#recent.length === 0) {
return;
}
// Customize mode can move the button out of the sidebar's foot toolbar —
// the inline stack only makes sense when it's still there.
if (!this.#button.closest("#zen-sidebar-foot-buttons")) {
return;
}
// Interrupt a pending close so we reuse the same element instead of
// racing a tear-down.
this.#closeAnim?.cancel();
this.#closeAnim = null;
const panel = this.#ensurePanel();
this.#populatePanel();
panel.dataset.state = "open";
this.#updateMaskHeight(panel);
panel.animate(
[
{ opacity: 0, transform: "translateY(8px)" },
{ opacity: 1, transform: "translateY(0)" },
],
{
duration: 180,
easing: "cubic-bezier(0.32, 0.72, 0, 1)",
fill: "forwards",
id: "zen-library-stack-open",
}
);
this.#attachMouseTracking();
}
/**
* Publish the panel's rendered height as a CSS variable on the tab strip
* so the strip's mask gradient fades over exactly the area the stack
* occupies (instead of a hardcoded amount).
*/
#updateMaskHeight(panel) {
const tabs = window.gBrowser?.tabContainer;
if (!tabs) {
return;
}
requestAnimationFrame(() => {
if (!panel.isConnected) {
return;
}
const h = Math.ceil(panel.getBoundingClientRect().height);
tabs.style.setProperty("--zen-library-stack-height", `${h}px`);
tabs.setAttribute("zen-library-stack-open", "true");
});
}
#attachMouseTracking() {
if (this.#trackingMouse) {
return;
}
window.addEventListener("mousemove", this, true);
this.#trackingMouse = true;
}
#detachMouseTracking() {
if (!this.#trackingMouse) {
return;
}
window.removeEventListener("mousemove", this, true);
this.#trackingMouse = false;
}
/**
* Hide the stack when the cursor moves outside a tolerance zone around the
* panel + button: HOVER_TOLERANCE_TOP_PX above, HOVER_TOLERANCE_SIDE_PX on
* either side (and the same below). Pinned open while a context menu is up.
*/
#checkMousePosition(event) {
if (this.#contextMenuOpen || !this.#panel) {
return;
}
if (this.#panel.dataset.state !== "open") {
this.#detachMouseTracking();
return;
}
const x = event?.clientX ?? -Infinity;
const y = event?.clientY ?? -Infinity;
const panelRect = this.#panel.getBoundingClientRect();
const buttonRect = this.#button?.getBoundingClientRect();
const left =
Math.min(panelRect.left, buttonRect?.left ?? panelRect.left) -
HOVER_TOLERANCE_SIDE_PX;
const right =
Math.max(panelRect.right, buttonRect?.right ?? panelRect.right) +
HOVER_TOLERANCE_SIDE_PX;
const top = panelRect.top - HOVER_TOLERANCE_TOP_PX;
const bottom =
Math.max(panelRect.bottom, buttonRect?.bottom ?? panelRect.bottom) +
HOVER_TOLERANCE_SIDE_PX;
if (x < left || x > right || y < top || y > bottom) {
this.#hide();
}
}
#hide() {
if (!this.#panel || this.#closeAnim) {
return;
}
this.#detachMouseTracking();
const tabs = window.gBrowser?.tabContainer;
tabs?.removeAttribute("zen-library-stack-open");
const panel = this.#panel;
panel.dataset.state = "closed";
const anim = panel.animate(
[
{ opacity: 1, transform: "translateY(0)" },
{ opacity: 0, transform: "translateY(8px)" },
],
{
duration: 140,
easing: "cubic-bezier(0.32, 0.72, 0, 1)",
fill: "forwards",
id: "zen-library-stack-close",
}
);
this.#closeAnim = anim;
anim.finished.then(
() => {
if (this.#closeAnim !== anim) {
return;
}
panel.remove();
if (this.#panel === panel) {
this.#panel = null;
}
this.#closeAnim = null;
tabs?.style.removeProperty("--zen-library-stack-height");
},
() => {
/* cancelled — re-entered while closing */
}
);
}
}
new nsZenLibraryButton();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
content/browser/zen-styles/zen-library.css (../../zen/library/zen-library.css)

View File

@@ -0,0 +1,9 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MOZ_SRC_FILES += [
"ZenLibrary.mjs",
"ZenLibraryButton.mjs",
"ZenLibrarySections.mjs",
]

View File

@@ -0,0 +1,635 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
zen-library {
@media (-moz-platform: windows) {
--border-radius-medium: 6px;
--tab-border-radius: 4px;
}
@media (-moz-platform: macos) {
--border-radius-medium: 14px;
--tab-border-radius: 8px;
font-size: 1rem; /* Slightly larger font on macOS */
}
display: flex;
position: absolute;
height: 100%;
transform: translateX(-100%);
opacity: 0;
will-change: transform, opacity;
z-index: 2;
}
zen-library[open] {
transform: translateX(0);
opacity: 1;
z-index: 9;
}
/* Layout Components */
#zen-library-sidebar {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 84px;
height: 100%;
padding: 8px;
background: rgba(255, 255, 255, 0.05);
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 50px;
border-right: 1px solid rgba(0,0,0,.08);
-moz-window-dragging: drag;
}
#zen-library-content {
display: flex;
width: 27rem;
max-width: 80vh;
overflow: hidden;
transition: width 0.15s ease-in-out;
&[large-content] {
width: 75rem;
}
& > * {
/*
* Fixed width so inner content does not stretch or squish while the
* outer container animates. flex-shrink: 0 prevents flexbox from
* compressing it below this value during the width transition.
*/
display: flex;
flex-direction: column;
width: 27rem;
min-width: 27rem;
flex-shrink: 0;
overflow: hidden;
}
}
/* Sidebar Tabs */
#zen-library-sidebar-tabs {
display: flex;
flex-direction: column;
gap: 8px;
-moz-window-dragging: no-drag;
}
.zen-library-tab {
display: flex;
position: relative;
justify-content: center;
align-items: center;
padding: 12px 0;
background: transparent;
font-weight: 600;
flex-direction: column;
gap: 4px;
&::before {
content: "";
position: absolute;
inset: 0;
border-radius: 6px;
transition: transform 0.1s ease-in-out;
}
&:hover::before {
background: color-mix(in srgb, currentColor 5%, transparent);
}
&[active]::before {
background: color-mix(in srgb, currentColor 10%, transparent);
}
& img {
width: 28px;
height: 28px;
fill: rgba(255, 255, 255, 0.8);
stroke: var(--zen-colors-primary);
-moz-context-properties: fill, stroke;
}
}
/* Search Bar */
.search-bar {
display: flex;
align-items: center;
flex-shrink: 0;
gap: 4px;
margin: 8px 6px;
padding: 0;
@media (-moz-platform: macos) {
font-size: 1rem; /* Slightly larger font on macOS */
}
}
.search-urlbar {
display: flex;
position: relative;
flex: 1;
align-items: stretch;
min-width: 0;
height: 38px;
margin-inline: 2px;
background: transparent;
border-radius: var(--border-radius-medium);
}
.search-urlbar-background {
position: absolute;
inset: 0;
background: var(--zen-toolbar-element-bg);
border-radius: var(--border-radius-medium);
pointer-events: none;
}
.search-urlbar:hover .search-urlbar-background {
background: var(--zen-toolbar-element-bg-hover);
}
.search-input-container {
display: flex;
position: relative;
flex: 1;
align-items: center;
min-width: 0;
gap: 0;
padding-inline: var(--urlbar-icon-padding, 9px);
padding-block: var(--urlbar-padding-block, 4px);
overflow: hidden;
& .search-icon {
width: 18px;
height: 18px;
margin-inline-end: 6px;
padding: 4px;
flex-shrink: 0;
fill: currentColor;
opacity: 0.5;
-moz-context-properties: fill, fill-opacity;
}
& .search-input {
flex: 1;
min-width: 0;
height: calc(var(--urlbar-height, 38px) - 2 * var(--urlbar-padding-block, 4px));
margin: 0;
padding: 0;
background: transparent;
border: none;
outline: none;
color: var(--toolbar-field-color, rgba(0,0,0,0.8));
font-weight: 500;
line-height: var(--tab-label-line-height);
&::placeholder {
color: inherit;
opacity: 0.5;
}
}
&:focus-within .search-input {
color: var(--toolbar-field-focus-color, light-dark(black, rgb(251,251,254)));
}
}
.search-filter-button {
display: flex;
align-items: center;
flex-shrink: 0;
gap: 4px;
height: var(--urlbar-height, 38px);
margin-inline: 2px;
padding: 0 8px;
background: var(--zen-toolbar-element-bg);
border: none;
border-radius: var(--border-radius-medium);
color: inherit;
font-weight: 500;
line-height: var(--tab-label-line-height);
fill: currentColor;
fill-opacity: 0.5;
-moz-context-properties: fill, fill-opacity;
& label {
opacity: .8;
}
&:hover,
&[open] {
background: var(--zen-toolbar-element-bg-hover);
}
&:active {
background: var(--toolbarbutton-active-background, color-mix(in srgb, light-dark(#101010,#e2e2e2) 7%, transparent 93%));
}
}
/* List */
.search-results {
display: flex;
flex: 1;
flex-direction: column;
align-items: stretch;
padding: 10px;
padding-top: 0 !important;
overflow-y: auto;
scrollbar-width: auto;
scrollbar-color: color-mix(in srgb, currentColor 35%, transparent 65%) transparent;
-moz-window-dragging: drag;
@media (-moz-platform: macos) {
font-size: 1.25rem; /* Slightly larger font on macOS */
}
&:not([scrolled-to-top]) {
box-shadow: inset 0 10px 10px -10px var(--zen-toolbar-element-bg);
}
}
/* unfinished */
.library-date-separator {
display: flex;
align-items: center;
flex-shrink: 0;
gap: 8px;
padding: 4px;
padding-top: 12px;
font-size: .9em;
font-weight: 500;
letter-spacing: 0.05em;
opacity: 0.65;
/* I am not sure if we should keep the separator line or not, I'll ask cheffy later */
/*&::after {
content: "";
flex: 1;
height: 1px;
opacity: 0.5;
background: var(--toolbarseparator-color);
}*/
}
.library-item {
--tab-label-mask-size: 1em;
display: flex;
align-items: stretch;
appearance: none;
background-color: transparent;
border-width: 0;
border-radius: 0;
color: inherit;
color-scheme: unset;
overflow: clip;
}
.library-item-stack {
display: grid;
position: relative;
width: 100%;
-moz-window-dragging: no-drag;
}
.library-item-background {
position: absolute;
inset: 0;
min-height: var(--tab-min-height);
background-color: transparent;
border-radius: var(--border-radius-medium) !important;
outline: var(--tab-outline);
outline-offset: var(--tab-outline-offset);
overflow: hidden;
}
.library-item:hover .library-item-background {
background-color: var(--tab-hover-background-color);
outline-color: var(--tab-hover-outline-color);
}
.library-item-content {
display: flex;
position: relative;
align-items: center;
min-width: 0;
padding: 0 10px;
overflow: clip;
height: 56px;
}
.library-item-icon-stack {
display: flex;
position: relative;
align-items: center;
justify-content: center;
}
.library-item-icon-image {
flex-shrink: 0;
width: 18px;
height: 18px;
margin-inline-start: calc(var(--toolbarbutton-inner-padding) / 2);
margin-inline-end: calc(var(--toolbarbutton-inner-padding) * 1.5);
padding: 0;
border-radius: 4px;
fill: currentColor;
-moz-context-properties: fill, stroke;
}
.library-download-progress {
display: flex;
position: relative;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
margin-inline-start: calc(var(--toolbarbutton-inner-padding) / 2);
margin-inline-end: calc(var(--toolbarbutton-inner-padding) * 1.5);
padding: 0;
appearance: none;
background: transparent;
border: none;
border-radius: 50%;
color: currentColor;
.library-item-stack:hover & {
color: var(--zen-colors-primary);
}
& > svg {
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity 0.12s ease;
}
}
.library-download-progress-ring .track {
fill: none;
stroke: color-mix(in srgb, currentColor 22%, transparent);
stroke-width: 1.8;
}
.library-download-progress-ring .arc {
fill: none;
stroke: currentColor;
stroke-width: 1.8;
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: 50% 50%;
transition: stroke-dashoffset 0.25s linear;
}
.library-download-progress[data-progress="indeterminate"] .arc {
stroke-dasharray: 14 50 !important;
animation: zen-library-download-spin 1.2s linear infinite;
}
@keyframes zen-library-download-spin {
from {
transform: rotate(-90deg);
}
to {
transform: rotate(270deg);
}
}
.library-download-progress-cancel {
opacity: 0;
}
.library-download-progress-cancel line {
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
}
.library-item-stack:hover .library-download-progress-ring .arc,
.library-item-stack:hover .library-download-progress-ring .track {
opacity: 0;
}
.library-item-stack:hover .library-download-progress-cancel {
opacity: 1;
}
.library-item-label-container {
display: flex;
flex: 1;
flex-direction: column;
min-width: 0;
opacity: 1;
direction: ltr;
mask-image: linear-gradient(to left, transparent, black var(--tab-label-mask-size));
overflow: hidden;
gap: 4px;
}
.library-item-label {
margin-inline: 0;
white-space: nowrap;
line-height: 1;
}
.library-item[file-missing] .library-item-label {
text-decoration: line-through;
opacity: 0.6;
}
/* finished (i hope so) */
.library-item-sublabel {
margin: 0;
font-size: 11px;
white-space: nowrap;
opacity: 0.6; /* what opacity should i keep? */
pointer-events: none;
overflow: hidden;
}
.library-item-side {
display: flex;
flex-direction: column;
flex-shrink: 0;
align-items: flex-end;
justify-content: center;
gap: 2px;
margin-inline-start: 8px;
padding-inline-end: 4px;
text-align: end;
white-space: nowrap;
opacity: 0.65;
pointer-events: none;
}
.library-item-side-top {
font-size: 0.85em;
}
.library-item-side-bottom {
font-size: x-small;
opacity: 0.85;
}
.library-item-actions {
display: none;
flex-shrink: 0;
align-items: center;
gap: 4px;
margin-inline-start: 8px;
}
.library-item:hover .library-item-actions,
.library-item:focus-within .library-item-actions {
display: flex;
}
.library-item-action-button {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 6px;
appearance: none;
background: transparent;
border: none;
border-radius: calc(var(--border-radius-medium) - 6px);
color: inherit;
fill: currentColor;
-moz-context-properties: fill, fill-opacity;
& img {
width: 18px;
height: 18px;
opacity: 0.75;
pointer-events: none;
}
&:hover {
background: color-mix(in srgb, currentColor 12%, transparent);
}
&:hover img {
opacity: 1;
}
}
.empty-state {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
font-size: 2em;
font-weight: 600;
opacity: 0.5;
}
/* Boosts section */
.library-boost-item .library-item-content {
gap: 6px;
}
.library-boost-icon {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
margin-inline-end: 8px;
background: rgba(255, 255, 255, 0.8);
box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.15);
border-radius: 12px;
position: relative;
overflow: hidden;
}
.library-boost-icon-image {
width: 24px;
height: 24px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.05);
padding: 7.5px;
}
/* Slashed-out look when inactive — mirrors the screenshot's first row. */
.library-boost-icon[inactive] {
opacity: 0.5;
}
.library-boost-icon[inactive]::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(
to bottom right,
transparent calc(50% - 1px),
currentColor calc(50% - 1px),
currentColor calc(50% + 1px),
transparent calc(50% + 1px)
);
pointer-events: none;
}
.library-boost-toggle {
display: inline-flex;
position: relative;
flex-shrink: 0;
align-items: center;
width: 36px;
height: 22px;
padding: 2px;
appearance: none;
background: color-mix(in srgb, currentColor 18%, transparent);
border: none;
border-radius: 999px;
opacity: 0;
transition:
background-color 0.18s ease,
opacity 0.12s ease;
}
/* Stays visible while it represents an "on" state so the user still sees
* which boosts are enabled at a glance; otherwise reveal on row hover. */
.library-boost-item:hover .library-boost-toggle,
.library-boost-toggle:focus-visible {
opacity: 1;
}
.library-boost-item .library-item-content {
padding-left: 6px;
}
.library-boost-toggle[checked] {
background: var(--zen-colors-primary);
}
.library-boost-toggle-thumb {
display: block;
width: 18px;
height: 18px;
background: light-dark(white, rgba(255, 255, 255, 0.95));
border-radius: 50%;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transition: transform 0.18s cubic-bezier(0.32, 0.72, 0, 1);
pointer-events: none;
}
.library-boost-toggle[checked] .library-boost-toggle-thumb {
transform: translateX(14px);
}

View File

@@ -1,6 +1,7 @@
// This Source Code Form is subject to the terms of the Mozilla Public // This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
const lazy = {}; const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, { ChromeUtils.defineESModuleGetters(lazy, {
NetUtil: "resource://gre/modules/NetUtil.sys.mjs", NetUtil: "resource://gre/modules/NetUtil.sys.mjs",

View File

@@ -19,5 +19,6 @@ DIRS += [
"sessionstore", "sessionstore",
"share", "share",
"spaces", "spaces",
"library",
"space-routing", "space-routing",
] ]

View File

@@ -4,6 +4,14 @@
const lazy = {}; const lazy = {};
ChromeUtils.defineESModuleGetters(
lazy,
{
ZenLibrary: "moz-src:///zen/library/ZenLibrary.mjs",
},
{ global: "current" }
);
ChromeUtils.defineLazyGetter(lazy, "browserBackgroundElement", () => { ChromeUtils.defineLazyGetter(lazy, "browserBackgroundElement", () => {
return document.getElementById("zen-browser-background"); return document.getElementById("zen-browser-background");
}); });
@@ -12,6 +20,11 @@ ChromeUtils.defineLazyGetter(lazy, "toolbarBackgroundElement", () => {
return document.getElementById("zen-toolbar-background"); return document.getElementById("zen-toolbar-background");
}); });
// Distance (in swipe-translate units, after the configured multiplier) that
// corresponds to a fully open library. Crossing this on swipe-end commits.
const LIBRARY_SWIPE_FULL_DISTANCE_FACTOR = 0.6;
const LIBRARY_SWIPE_COMMIT_THRESHOLD = 0.3;
export class ZenSpacesSwipe { export class ZenSpacesSwipe {
_swipeState = { _swipeState = {
isGestureActive: false, isGestureActive: false,
@@ -115,14 +128,25 @@ export class ZenSpacesSwipe {
isGestureActive: true, isGestureActive: true,
lastDelta: 0, lastDelta: 0,
direction: null, direction: null,
librarySwiping: false,
libraryStartProgress: 0,
libraryProgress: 0,
}; };
Services.prefs.setBoolPref("zen.swipe.is-fast-swipe", true); Services.prefs.setBoolPref("zen.swipe.is-fast-swipe", true);
} }
_handleSwipeUpdate(event) { /** True when the active workspace is the first one in the cached list. */
const ws = gZenWorkspaces; #isAtFirstWorkspace() {
const workspaces = gZenWorkspaces.getWorkspaces();
const active = gZenWorkspaces.getActiveWorkspaceFromCache();
return workspaces.indexOf(active) === 0;
}
if (!ws.workspaceEnabled || !this._swipeState?.isGestureActive) { _handleSwipeUpdate(event) {
if (
!gZenWorkspaces.workspaceEnabled ||
!this._swipeState?.isGestureActive
) {
return; return;
} }
@@ -150,13 +174,45 @@ export class ZenSpacesSwipe {
} }
if (Math.abs(delta) > 0.9) { if (Math.abs(delta) > 0.9) {
delete ws._hasAnimatedBackgrounds; delete gZenWorkspaces._hasAnimatedBackgrounds;
this._swipeState.direction = delta > 0 ? "left" : "right"; this._swipeState.direction = delta > 0 ? "left" : "right";
} }
// The library can hijack the swipe in two cases:
// - Already open → swipe leftwards (translateX < 0) closes it.
// - Closed and on the first workspace → swipe rightwards (translateX > 0)
// opens it from the left edge.
const libraryOpen = lazy.ZenLibrary.isOpen;
const wantsClose = libraryOpen && translateX < 0;
const wantsOpen =
!libraryOpen && translateX > 0 && this.#isAtFirstWorkspace();
if (wantsOpen || wantsClose || this._swipeState.librarySwiping) {
if (!this._swipeState.librarySwiping) {
this._swipeState.librarySwiping = true;
this._swipeState.libraryStartProgress = libraryOpen ? 1 : 0;
// Fire-and-forget; the first update before measurement completes
// re-applies the current start progress, which is already visible.
lazy.ZenLibrary.beginSwipe();
}
const deltaProgress =
translateX / (stripWidth * LIBRARY_SWIPE_FULL_DISTANCE_FACTOR);
const progress = Math.max(
0,
Math.min(1, this._swipeState.libraryStartProgress + deltaProgress)
);
this._swipeState.libraryProgress = progress;
lazy.ZenLibrary.updateSwipeProgress(progress);
// Skip the workspace-strip translate while the library owns the swipe.
return;
}
// Apply a translateX to the tab strip to give the user feedback on the swipe // Apply a translateX to the tab strip to give the user feedback on the swipe
const currentWorkspace = ws.getActiveWorkspaceFromCache(); const currentWorkspace = gZenWorkspaces.getActiveWorkspaceFromCache();
ws._organizeWorkspaceStripLocations(currentWorkspace, true, translateX); gZenWorkspaces._organizeWorkspaceStripLocations(
currentWorkspace,
true,
translateX
);
} }
async _handleSwipeEnd(event) { async _handleSwipeEnd(event) {
@@ -167,6 +223,17 @@ export class ZenSpacesSwipe {
} }
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
// If the swipe was driving the library, commit to whichever side of the
// threshold the progress landed on and don't change workspace.
if (this._swipeState.librarySwiping) {
const targetOpen =
this._swipeState.libraryProgress >= LIBRARY_SWIPE_COMMIT_THRESHOLD;
delete this._swipeState.librarySwiping;
await lazy.ZenLibrary.finishSwipe(targetOpen);
return;
}
const isRTL = document.documentElement.matches(":-moz-locale-dir(rtl)"); const isRTL = document.documentElement.matches(":-moz-locale-dir(rtl)");
const moveForward = const moveForward =
(event.direction === SimpleGestureEvent.DIRECTION_RIGHT) !== isRTL; (event.direction === SimpleGestureEvent.DIRECTION_RIGHT) !== isRTL;
@@ -179,6 +246,10 @@ export class ZenSpacesSwipe {
onSwipeGestureAnimationEnd() { onSwipeGestureAnimationEnd() {
const ws = gZenWorkspaces; const ws = gZenWorkspaces;
if (this._swipeState.librarySwiping) {
lazy.ZenLibrary.finishSwipe(false);
}
// Reset swipe state // Reset swipe state
this._swipeState = { this._swipeState = {
isGestureActive: false, isGestureActive: false,