mirror of
https://github.com/zen-browser/desktop.git
synced 2026-07-02 15:23:10 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce5fb77b9 | ||
|
|
08acc6a39e | ||
|
|
8ae271d982 | ||
|
|
ba26c902fb | ||
|
|
89a50770a9 | ||
|
|
036f764d2b | ||
|
|
2c11b9295e | ||
|
|
d7839cdb91 | ||
|
|
67cef284dd | ||
|
|
36df7e718f | ||
|
|
d5b88ead22 | ||
|
|
7261eb1688 | ||
|
|
b5a251a92f | ||
|
|
a217cacfef | ||
|
|
a56bcf3d9c | ||
|
|
5963de1486 | ||
|
|
57ad5c45e7 | ||
|
|
e6bebab10a | ||
|
|
a8820ed409 | ||
|
|
a82a7fb055 | ||
|
|
2be85a2890 | ||
|
|
9301e1b64c | ||
|
|
1e04f394a5 | ||
|
|
665f500925 | ||
|
|
88ebf6e5da | ||
|
|
556beb01b0 | ||
|
|
48d5b32a5a | ||
|
|
4682c8d545 | ||
|
|
2c5fc47e74 | ||
|
|
237f0c0ea5 |
@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
|||||||
|
|
||||||
### Firefox Versions
|
### Firefox Versions
|
||||||
|
|
||||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `152.0.3`! 🚀
|
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `152.0.1`! 🚀
|
||||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 152.0.3`!
|
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 152.0.1`!
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
b223f3727a037a7b8a0f36f34bfe8c4622a7f387
|
2960f4c1ce58d289d3b9ec885695f0017d2636ab
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -19,19 +19,13 @@ tab-context-zen-add-essential-badge = { $num } / { $max }
|
|||||||
tab-context-zen-remove-essential =
|
tab-context-zen-remove-essential =
|
||||||
.label = Remove from Essentials
|
.label = Remove from Essentials
|
||||||
.accesskey = R
|
.accesskey = R
|
||||||
tab-context-zen-edit-pinned-page =
|
tab-context-zen-replace-pinned-url-with-current =
|
||||||
.label =
|
.label =
|
||||||
{ $isEssential ->
|
{ $isEssential ->
|
||||||
[true] Edit Essential URL
|
[true] Replace Essential URL with Current
|
||||||
*[false] Edit Pinned URL
|
*[false] Replace Pinned URL with Current
|
||||||
}
|
}
|
||||||
.accesskey = P
|
|
||||||
tab-context-zen-replace-pinned-url-with-current =
|
|
||||||
.label = Replace with Current URL
|
|
||||||
.accesskey = C
|
.accesskey = C
|
||||||
tab-context-zen-edit-pinned-url =
|
|
||||||
.label = Edit...
|
|
||||||
.accesskey = E
|
|
||||||
tab-context-zen-edit-title =
|
tab-context-zen-edit-title =
|
||||||
.label = Change Label...
|
.label = Change Label...
|
||||||
tab-context-zen-edit-icon =
|
tab-context-zen-edit-icon =
|
||||||
@@ -61,10 +55,6 @@ zen-general-confirm =
|
|||||||
.label = Confirm
|
.label = Confirm
|
||||||
|
|
||||||
zen-pinned-tab-replaced = Pinned tab URL has been replaced with the current URL!
|
zen-pinned-tab-replaced = Pinned tab URL has been replaced with the current URL!
|
||||||
zen-pinned-tab-url-edited = Pinned tab URL has been updated!
|
|
||||||
zen-pinned-tab-url-invalid = That doesn't look like a valid URL.
|
|
||||||
zen-pinned-tab-edit-url-title = Edit Pinned URL
|
|
||||||
zen-pinned-tab-edit-url-label = Enter the URL this pinned tab should point to:
|
|
||||||
zen-tabs-renamed = Tab has been successfully renamed!
|
zen-tabs-renamed = Tab has been successfully renamed!
|
||||||
zen-background-tab-opened-toast = New background tab opened!
|
zen-background-tab-opened-toast = New background tab opened!
|
||||||
zen-workspace-renamed-toast = Workspace has been successfully renamed!
|
zen-workspace-renamed-toast = Workspace has been successfully renamed!
|
||||||
|
|||||||
89
locales/en-US/browser/browser/zen-library.ftl
Normal file
89
locales/en-US/browser/browser/zen-library.ftl
Normal 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
|
||||||
@@ -25,9 +25,3 @@ zen-space-routing-open-in = Open In
|
|||||||
zen-space-routing-url = URL
|
zen-space-routing-url = URL
|
||||||
|
|
||||||
zen-space-routing-tab-routed-toast = New tab opened in { $targetWorkspace }
|
zen-space-routing-tab-routed-toast = New tab opened in { $targetWorkspace }
|
||||||
tab-context-zen-add-domain-to-sr =
|
|
||||||
.label =
|
|
||||||
{ $tabCount ->
|
|
||||||
[one] Add Route for Domain
|
|
||||||
*[other] Add Route for Domains
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,4 +2,5 @@
|
|||||||
# 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/.
|
||||||
|
|
||||||
category browser-window-delayed-startup resource:///modules/zen/spacerouting/ZenSpaceRoutingManager.sys.mjs gZenSpaceRoutingManager.onDelayedBrowserStartup
|
- name: zen.library.enabled
|
||||||
|
value: false
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
diff --git a/browser/base/content/aboutDialog.css b/browser/base/content/aboutDialog.css
|
|
||||||
index 017125bc2510e5f5e317a5e78c40d6aa9ded76ca..d343d8c62a2251e3c3a33ae8f2ab9c4c68218c22 100644
|
|
||||||
--- a/browser/base/content/aboutDialog.css
|
|
||||||
+++ b/browser/base/content/aboutDialog.css
|
|
||||||
@@ -135,6 +135,13 @@
|
|
||||||
margin: 0 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
+#trademark {
|
|
||||||
+ font-size: xx-small;
|
|
||||||
+ text-align: center;
|
|
||||||
+ margin-block: 10px;
|
|
||||||
+ color: var(--text-color-deemphasized);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#currentChannel {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/base/content/aboutDialog.xhtml b/browser/base/content/aboutDialog.xhtml
|
diff --git a/browser/base/content/aboutDialog.xhtml b/browser/base/content/aboutDialog.xhtml
|
||||||
index 3ffd464b960a4299a7dd0cd87e4fc2f781b9d593..7a831c8ee2b73bb89bf8a82ac24958b55c16a5aa 100644
|
index 3ffd464b960a4299a7dd0cd87e4fc2f781b9d593..ef9f42d1f0196902b4af31f4496891fcd6319831 100644
|
||||||
--- a/browser/base/content/aboutDialog.xhtml
|
--- a/browser/base/content/aboutDialog.xhtml
|
||||||
+++ b/browser/base/content/aboutDialog.xhtml
|
+++ b/browser/base/content/aboutDialog.xhtml
|
||||||
@@ -102,10 +102,6 @@
|
@@ -102,10 +102,6 @@
|
||||||
@@ -39,8 +39,8 @@ index 3ffd464b960a4299a7dd0cd87e4fc2f781b9d593..7a831c8ee2b73bb89bf8a82ac24958b5
|
|||||||
<label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"/>
|
<label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"/>
|
||||||
- <label is="text-link" class="bottom-link" href="https://www.mozilla.org/about/legal/terms/firefox/" data-l10n-id="bottom-links-terms"/>
|
- <label is="text-link" class="bottom-link" href="https://www.mozilla.org/about/legal/terms/firefox/" data-l10n-id="bottom-links-terms"/>
|
||||||
- <label is="text-link" class="bottom-link" href="https://www.mozilla.org/privacy/firefox/?utm_source=firefox-browser&utm_medium=firefox-desktop&utm_campaign=about-dialog" data-l10n-id="bottom-links-privacy"/>
|
- <label is="text-link" class="bottom-link" href="https://www.mozilla.org/privacy/firefox/?utm_source=firefox-browser&utm_medium=firefox-desktop&utm_campaign=about-dialog" data-l10n-id="bottom-links-privacy"/>
|
||||||
+ <label is="text-link" class="bottom-link" href="about:rights" data-l10n-id="bottom-links-terms"/>
|
+ <label is="text-link" class="bottom-link" href="about:rights" data-l10n-id="bottomLinks-rights"/>
|
||||||
+ <label is="text-link" class="bottom-link" href="https://www.zen-browser.app/privacy-policy/" data-l10n-id="bottom-links-privacy"/>
|
+ <label is="text-link" class="bottom-link" href="https://www.zen-browser.app/privacy-policy/" data-l10n-id="bottomLinks-privacy"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
<description id="trademark" data-l10n-id="trademarkInfo"></description>
|
<description id="trademark" data-l10n-id="trademarkInfo"></description>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
<command id="cmd_zenToggleTabsOnRight" />
|
<command id="cmd_zenToggleTabsOnRight" />
|
||||||
|
|
||||||
<command id="cmd_zenReplacePinnedUrlWithCurrent" />
|
<command id="cmd_zenReplacePinnedUrlWithCurrent" />
|
||||||
<command id="cmd_zenEditPinnedUrl" />
|
|
||||||
<command id="cmd_contextZenAddToEssentials" />
|
<command id="cmd_contextZenAddToEssentials" />
|
||||||
<command id="cmd_contextZenRemoveFromEssentials" />
|
<command id="cmd_contextZenRemoveFromEssentials" />
|
||||||
|
|
||||||
@@ -69,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>
|
||||||
|
|||||||
@@ -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"/>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d83330c265dfc 100644
|
index 08b5b56e069d038d72c87355920c4ce8a55ed805..555ffd4772d9d4903491fdff9f3682852f8a52bd 100644
|
||||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||||
@@ -511,6 +511,7 @@
|
@@ -511,6 +511,7 @@
|
||||||
@@ -523,15 +523,12 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
if (tabs.length > 1 || !tabs[0].selected) {
|
if (tabs.length > 1 || !tabs[0].selected) {
|
||||||
this._updateTabsAfterInsert();
|
this._updateTabsAfterInsert();
|
||||||
@@ -4866,11 +5030,17 @@
|
@@ -4866,11 +5030,14 @@
|
||||||
if (ownerTab) {
|
if (ownerTab) {
|
||||||
tab.owner = ownerTab;
|
tab.owner = ownerTab;
|
||||||
}
|
}
|
||||||
+ if ((!tab.pinned && tabGroup?.isZenFolder && !Services.prefs.getBoolPref('zen.folders.owned-tabs-in-folder')) || (tabGroup && tabGroup.hasAttribute("split-view-group"))) {
|
+ if ((!tab.pinned && tabGroup?.isZenFolder && !Services.prefs.getBoolPref('zen.folders.owned-tabs-in-folder')) || (tabGroup && tabGroup.hasAttribute("split-view-group"))) {
|
||||||
+ tabGroup = null;
|
+ tabGroup = null;
|
||||||
+ }
|
|
||||||
+ if (openerTab?.hasAttribute("zen-glance-tab")) {
|
|
||||||
+ openerTab = gZenGlanceManager.getTabOrGlanceParent(openerTab);
|
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
// Ensure we have an index if one was not provided.
|
// Ensure we have an index if one was not provided.
|
||||||
@@ -542,7 +539,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (
|
if (
|
||||||
!bulkOrderedOpen &&
|
!bulkOrderedOpen &&
|
||||||
((openerTab &&
|
((openerTab &&
|
||||||
@@ -4882,7 +5052,7 @@
|
@@ -4882,7 +5049,7 @@
|
||||||
let lastRelatedTab =
|
let lastRelatedTab =
|
||||||
openerTab && this._lastRelatedTabMap.get(openerTab);
|
openerTab && this._lastRelatedTabMap.get(openerTab);
|
||||||
let previousTab = lastRelatedTab || openerTab || this.selectedTab;
|
let previousTab = lastRelatedTab || openerTab || this.selectedTab;
|
||||||
@@ -551,7 +548,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
tabGroup = previousTab.group;
|
tabGroup = previousTab.group;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -4898,7 +5068,7 @@
|
@@ -4898,7 +5065,7 @@
|
||||||
previousTab.splitview
|
previousTab.splitview
|
||||||
) + 1;
|
) + 1;
|
||||||
} else if (previousTab.visible) {
|
} else if (previousTab.visible) {
|
||||||
@@ -560,7 +557,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
} else if (previousTab == FirefoxViewHandler.tab) {
|
} else if (previousTab == FirefoxViewHandler.tab) {
|
||||||
elementIndex = 0;
|
elementIndex = 0;
|
||||||
}
|
}
|
||||||
@@ -4926,14 +5096,14 @@
|
@@ -4926,14 +5093,14 @@
|
||||||
}
|
}
|
||||||
// Ensure index is within bounds.
|
// Ensure index is within bounds.
|
||||||
if (tab.pinned) {
|
if (tab.pinned) {
|
||||||
@@ -579,7 +576,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
if (pinned && !itemAfter?.pinned) {
|
if (pinned && !itemAfter?.pinned) {
|
||||||
itemAfter = null;
|
itemAfter = null;
|
||||||
@@ -4950,7 +5120,7 @@
|
@@ -4950,7 +5117,7 @@
|
||||||
|
|
||||||
this.tabContainer._invalidateCachedTabs();
|
this.tabContainer._invalidateCachedTabs();
|
||||||
|
|
||||||
@@ -588,7 +585,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (
|
if (
|
||||||
(this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
|
(this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
|
||||||
this.isSplitViewWrapper(itemAfter)
|
this.isSplitViewWrapper(itemAfter)
|
||||||
@@ -4981,7 +5151,11 @@
|
@@ -4981,7 +5148,11 @@
|
||||||
const tabContainer = pinned
|
const tabContainer = pinned
|
||||||
? this.tabContainer.pinnedTabsContainer
|
? this.tabContainer.pinnedTabsContainer
|
||||||
: this.tabContainer;
|
: this.tabContainer;
|
||||||
@@ -600,7 +597,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tab.group?.collapsed) {
|
if (tab.group?.collapsed) {
|
||||||
@@ -4996,6 +5170,7 @@
|
@@ -4996,6 +5167,7 @@
|
||||||
if (pinned) {
|
if (pinned) {
|
||||||
this._updateTabBarForPinnedTabs();
|
this._updateTabBarForPinnedTabs();
|
||||||
}
|
}
|
||||||
@@ -608,7 +605,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
TabBarVisibility.update();
|
TabBarVisibility.update();
|
||||||
}
|
}
|
||||||
@@ -5544,6 +5719,7 @@
|
@@ -5544,6 +5716,7 @@
|
||||||
telemetrySource,
|
telemetrySource,
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
@@ -616,7 +613,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
|
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
|
||||||
// can be considered equivalent to closing the window.
|
// can be considered equivalent to closing the window.
|
||||||
if (
|
if (
|
||||||
@@ -5633,6 +5809,7 @@
|
@@ -5633,6 +5806,7 @@
|
||||||
if (lastToClose) {
|
if (lastToClose) {
|
||||||
this.removeTab(lastToClose, aParams);
|
this.removeTab(lastToClose, aParams);
|
||||||
}
|
}
|
||||||
@@ -624,7 +621,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@@ -5678,6 +5855,14 @@
|
@@ -5678,6 +5852,14 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +636,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
let isVisibleTab = aTab.visible;
|
let isVisibleTab = aTab.visible;
|
||||||
// We have to sample the tab width now, since _beginRemoveTab might
|
// We have to sample the tab width now, since _beginRemoveTab might
|
||||||
// end up modifying the DOM in such a way that aTab gets a new
|
// end up modifying the DOM in such a way that aTab gets a new
|
||||||
@@ -5685,6 +5870,9 @@
|
@@ -5685,6 +5867,9 @@
|
||||||
// state).
|
// state).
|
||||||
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
|
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
|
||||||
let isLastTab = this.#isLastTabInWindow(aTab);
|
let isLastTab = this.#isLastTabInWindow(aTab);
|
||||||
@@ -649,7 +646,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (
|
if (
|
||||||
!this._beginRemoveTab(aTab, {
|
!this._beginRemoveTab(aTab, {
|
||||||
closeWindowFastpath: true,
|
closeWindowFastpath: true,
|
||||||
@@ -5696,13 +5884,14 @@
|
@@ -5696,13 +5881,14 @@
|
||||||
telemetrySource,
|
telemetrySource,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
@@ -665,7 +662,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
let lockTabSizing =
|
let lockTabSizing =
|
||||||
!this.tabContainer.verticalMode &&
|
!this.tabContainer.verticalMode &&
|
||||||
!aTab.pinned &&
|
!aTab.pinned &&
|
||||||
@@ -5733,7 +5922,13 @@
|
@@ -5733,7 +5919,13 @@
|
||||||
// We're not animating, so we can cancel the animation stopwatch.
|
// We're not animating, so we can cancel the animation stopwatch.
|
||||||
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
||||||
aTab._closeTimeAnimTimerId = null;
|
aTab._closeTimeAnimTimerId = null;
|
||||||
@@ -680,7 +677,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5867,7 +6062,7 @@
|
@@ -5867,7 +6059,7 @@
|
||||||
closeWindowWithLastTab != null
|
closeWindowWithLastTab != null
|
||||||
? closeWindowWithLastTab
|
? closeWindowWithLastTab
|
||||||
: !window.toolbar.visible ||
|
: !window.toolbar.visible ||
|
||||||
@@ -689,7 +686,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
if (closeWindow) {
|
if (closeWindow) {
|
||||||
// We've already called beforeunload on all the relevant tabs if we get here,
|
// We've already called beforeunload on all the relevant tabs if we get here,
|
||||||
@@ -5891,6 +6086,7 @@
|
@@ -5891,6 +6083,7 @@
|
||||||
|
|
||||||
newTab = true;
|
newTab = true;
|
||||||
}
|
}
|
||||||
@@ -697,7 +694,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
aTab._endRemoveArgs = [closeWindow, newTab];
|
aTab._endRemoveArgs = [closeWindow, newTab];
|
||||||
|
|
||||||
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
||||||
@@ -5931,13 +6127,7 @@
|
@@ -5931,13 +6124,7 @@
|
||||||
aTab._mouseleave();
|
aTab._mouseleave();
|
||||||
|
|
||||||
if (newTab) {
|
if (newTab) {
|
||||||
@@ -712,7 +709,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
} else {
|
} else {
|
||||||
TabBarVisibility.update();
|
TabBarVisibility.update();
|
||||||
}
|
}
|
||||||
@@ -6070,6 +6260,7 @@
|
@@ -6070,6 +6257,7 @@
|
||||||
this.tabs[i]._tPos = i;
|
this.tabs[i]._tPos = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,7 +717,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (!this._windowIsClosing) {
|
if (!this._windowIsClosing) {
|
||||||
// update tab close buttons state
|
// update tab close buttons state
|
||||||
this.tabContainer._updateCloseButtons();
|
this.tabContainer._updateCloseButtons();
|
||||||
@@ -6255,6 +6446,7 @@
|
@@ -6255,6 +6443,7 @@
|
||||||
memory_after: await getTotalMemoryUsage(),
|
memory_after: await getTotalMemoryUsage(),
|
||||||
time_to_unload_in_ms: timeElapsed,
|
time_to_unload_in_ms: timeElapsed,
|
||||||
});
|
});
|
||||||
@@ -728,7 +725,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6300,6 +6492,7 @@
|
@@ -6300,6 +6489,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let excludeTabs = new Set(aExcludeTabs);
|
let excludeTabs = new Set(aExcludeTabs);
|
||||||
@@ -736,7 +733,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
// If this tab has a successor, it should be selectable, since
|
// If this tab has a successor, it should be selectable, since
|
||||||
// hiding or closing a tab removes that tab as a successor.
|
// hiding or closing a tab removes that tab as a successor.
|
||||||
@@ -6312,15 +6505,22 @@
|
@@ -6312,15 +6502,22 @@
|
||||||
!excludeTabs.has(aTab.owner) &&
|
!excludeTabs.has(aTab.owner) &&
|
||||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
||||||
) {
|
) {
|
||||||
@@ -761,7 +758,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
let tab = this.tabContainer.findNextTab(aTab, {
|
let tab = this.tabContainer.findNextTab(aTab, {
|
||||||
direction: 1,
|
direction: 1,
|
||||||
filter: _tab => remainingTabs.includes(_tab),
|
filter: _tab => remainingTabs.includes(_tab),
|
||||||
@@ -6334,7 +6534,7 @@
|
@@ -6334,7 +6531,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tab) {
|
if (tab) {
|
||||||
@@ -770,7 +767,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If no qualifying visible tab was found, see if there is a tab in
|
// If no qualifying visible tab was found, see if there is a tab in
|
||||||
@@ -6355,7 +6555,7 @@
|
@@ -6355,7 +6552,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +776,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
_blurTab(aTab) {
|
_blurTab(aTab) {
|
||||||
@@ -6366,7 +6566,7 @@
|
@@ -6366,7 +6563,7 @@
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
* False if swapping isn't permitted, true otherwise.
|
* False if swapping isn't permitted, true otherwise.
|
||||||
*/
|
*/
|
||||||
@@ -788,7 +785,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
// Do not allow transfering a private tab to a non-private window
|
// Do not allow transfering a private tab to a non-private window
|
||||||
// and vice versa.
|
// and vice versa.
|
||||||
if (
|
if (
|
||||||
@@ -6420,6 +6620,7 @@
|
@@ -6420,6 +6617,7 @@
|
||||||
// fire the beforeunload event in the process. Close the other
|
// fire the beforeunload event in the process. Close the other
|
||||||
// window if this was its last tab.
|
// window if this was its last tab.
|
||||||
if (
|
if (
|
||||||
@@ -796,7 +793,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
!remoteBrowser._beginRemoveTab(aOtherTab, {
|
!remoteBrowser._beginRemoveTab(aOtherTab, {
|
||||||
adoptedByTab: aOurTab,
|
adoptedByTab: aOurTab,
|
||||||
closeWindowWithLastTab: true,
|
closeWindowWithLastTab: true,
|
||||||
@@ -6431,7 +6632,7 @@
|
@@ -6431,7 +6629,7 @@
|
||||||
// If this is the last tab of the window, hide the window
|
// If this is the last tab of the window, hide the window
|
||||||
// immediately without animation before the docshell swap, to avoid
|
// immediately without animation before the docshell swap, to avoid
|
||||||
// about:blank being painted.
|
// about:blank being painted.
|
||||||
@@ -805,7 +802,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (closeWindow) {
|
if (closeWindow) {
|
||||||
let win = aOtherTab.documentGlobal;
|
let win = aOtherTab.documentGlobal;
|
||||||
win.windowUtils.suppressAnimation(true);
|
win.windowUtils.suppressAnimation(true);
|
||||||
@@ -6565,11 +6766,13 @@
|
@@ -6565,11 +6763,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish tearing down the tab that's going away.
|
// Finish tearing down the tab that's going away.
|
||||||
@@ -819,7 +816,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
this.setTabTitle(aOurTab);
|
this.setTabTitle(aOurTab);
|
||||||
|
|
||||||
@@ -6771,10 +6974,10 @@
|
@@ -6771,10 +6971,10 @@
|
||||||
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +829,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
aTab.selected ||
|
aTab.selected ||
|
||||||
aTab.closing ||
|
aTab.closing ||
|
||||||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
||||||
@@ -6834,7 +7037,8 @@
|
@@ -6834,7 +7034,8 @@
|
||||||
* @param {object} [aOptions={}]
|
* @param {object} [aOptions={}]
|
||||||
* Key-value pairs that will be serialized into the features string.
|
* Key-value pairs that will be serialized into the features string.
|
||||||
*/
|
*/
|
||||||
@@ -842,7 +839,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
if (this.tabs.length == 1) {
|
if (this.tabs.length == 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -6851,7 +7055,7 @@
|
@@ -6851,7 +7052,7 @@
|
||||||
// tell a new window to take the "dropped" tab
|
// tell a new window to take the "dropped" tab
|
||||||
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||||
args.appendElement(aTab.splitview ?? aTab);
|
args.appendElement(aTab.splitview ?? aTab);
|
||||||
@@ -851,7 +848,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
private: PrivateBrowsingUtils.isWindowPrivate(window),
|
private: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||||
features: Object.entries(aOptions)
|
features: Object.entries(aOptions)
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
@@ -6859,6 +7063,8 @@
|
@@ -6859,6 +7060,8 @@
|
||||||
openerWindow: window,
|
openerWindow: window,
|
||||||
args,
|
args,
|
||||||
});
|
});
|
||||||
@@ -860,7 +857,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6971,7 +7177,7 @@
|
@@ -6971,7 +7174,7 @@
|
||||||
* `true` if element is a `<tab-group>`
|
* `true` if element is a `<tab-group>`
|
||||||
*/
|
*/
|
||||||
isTabGroup(element) {
|
isTabGroup(element) {
|
||||||
@@ -869,7 +866,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7056,8 +7262,8 @@
|
@@ -7056,8 +7259,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow mixing pinned and unpinned tabs.
|
// Don't allow mixing pinned and unpinned tabs.
|
||||||
@@ -880,7 +877,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
} else {
|
} else {
|
||||||
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
||||||
}
|
}
|
||||||
@@ -7103,8 +7309,8 @@
|
@@ -7103,8 +7306,8 @@
|
||||||
this.#handleTabMove(
|
this.#handleTabMove(
|
||||||
element,
|
element,
|
||||||
() => {
|
() => {
|
||||||
@@ -891,7 +888,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
neighbor = neighbor.group;
|
neighbor = neighbor.group;
|
||||||
}
|
}
|
||||||
if (neighbor?.splitview) {
|
if (neighbor?.splitview) {
|
||||||
@@ -7115,6 +7321,12 @@
|
@@ -7115,6 +7318,12 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -904,7 +901,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
if (movingForwards && neighbor) {
|
if (movingForwards && neighbor) {
|
||||||
neighbor.after(element);
|
neighbor.after(element);
|
||||||
@@ -7173,23 +7385,31 @@
|
@@ -7173,23 +7382,31 @@
|
||||||
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
||||||
if (this.isTabGroupLabel(targetElement)) {
|
if (this.isTabGroupLabel(targetElement)) {
|
||||||
targetElement = targetElement.group;
|
targetElement = targetElement.group;
|
||||||
@@ -942,7 +939,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
} else if (!element.pinned && targetElement && targetElement.pinned) {
|
} else if (!element.pinned && targetElement && targetElement.pinned) {
|
||||||
// If the caller asks to move an unpinned element next to a pinned
|
// If the caller asks to move an unpinned element next to a pinned
|
||||||
// tab, move the unpinned element to be the first unpinned element
|
// tab, move the unpinned element to be the first unpinned element
|
||||||
@@ -7202,12 +7422,35 @@
|
@@ -7202,12 +7419,35 @@
|
||||||
// move the tab group right before the first unpinned tab.
|
// move the tab group right before the first unpinned tab.
|
||||||
// 4. Moving a tab group and the first unpinned tab is grouped:
|
// 4. Moving a tab group and the first unpinned tab is grouped:
|
||||||
// move the tab group right before the first unpinned tab's tab group.
|
// move the tab group right before the first unpinned tab's tab group.
|
||||||
@@ -979,7 +976,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
// We want to include the splitview wrapper if it's the targetElement, but
|
// We want to include the splitview wrapper if it's the targetElement, but
|
||||||
// not in the case where we want to reverse tabs within the same splitview.
|
// not in the case where we want to reverse tabs within the same splitview.
|
||||||
@@ -7216,6 +7459,7 @@
|
@@ -7216,6 +7456,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let getContainer = () =>
|
let getContainer = () =>
|
||||||
@@ -987,7 +984,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
element.pinned
|
element.pinned
|
||||||
? this.tabContainer.pinnedTabsContainer
|
? this.tabContainer.pinnedTabsContainer
|
||||||
: this.tabContainer;
|
: this.tabContainer;
|
||||||
@@ -7224,11 +7468,15 @@
|
@@ -7224,11 +7465,15 @@
|
||||||
element,
|
element,
|
||||||
() => {
|
() => {
|
||||||
if (moveBefore) {
|
if (moveBefore) {
|
||||||
@@ -1004,7 +1001,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
metricsContext
|
metricsContext
|
||||||
@@ -7302,11 +7550,15 @@
|
@@ -7302,11 +7547,15 @@
|
||||||
* @param {TabMetricsContext} [metricsContext]
|
* @param {TabMetricsContext} [metricsContext]
|
||||||
*/
|
*/
|
||||||
moveTabToExistingGroup(aTab, aGroup, metricsContext) {
|
moveTabToExistingGroup(aTab, aGroup, metricsContext) {
|
||||||
@@ -1023,7 +1020,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
if (aTab.group && aTab.group.id === aGroup.id) {
|
if (aTab.group && aTab.group.id === aGroup.id) {
|
||||||
return;
|
return;
|
||||||
@@ -7378,6 +7630,7 @@
|
@@ -7378,6 +7627,7 @@
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
tabIndex: tab._tPos,
|
tabIndex: tab._tPos,
|
||||||
@@ -1031,7 +1028,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
};
|
};
|
||||||
if (tab.visible) {
|
if (tab.visible) {
|
||||||
state.elementIndex = tab.elementIndex;
|
state.elementIndex = tab.elementIndex;
|
||||||
@@ -7409,7 +7662,7 @@
|
@@ -7409,7 +7659,7 @@
|
||||||
let changedSplitView =
|
let changedSplitView =
|
||||||
previousTabState.splitViewId != currentTabState.splitViewId;
|
previousTabState.splitViewId != currentTabState.splitViewId;
|
||||||
|
|
||||||
@@ -1040,7 +1037,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
tab.dispatchEvent(
|
tab.dispatchEvent(
|
||||||
new CustomEvent("TabMove", {
|
new CustomEvent("TabMove", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
@@ -7456,6 +7709,10 @@
|
@@ -7456,6 +7706,10 @@
|
||||||
|
|
||||||
moveActionCallback();
|
moveActionCallback();
|
||||||
|
|
||||||
@@ -1051,7 +1048,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
// Clear tabs cache after moving nodes because the order of tabs may have
|
// Clear tabs cache after moving nodes because the order of tabs may have
|
||||||
// changed.
|
// changed.
|
||||||
this.tabContainer._invalidateCachedTabs();
|
this.tabContainer._invalidateCachedTabs();
|
||||||
@@ -7506,7 +7763,22 @@
|
@@ -7506,7 +7760,22 @@
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
* The new tab in the current window, null if the tab couldn't be adopted.
|
* The new tab in the current window, null if the tab couldn't be adopted.
|
||||||
*/
|
*/
|
||||||
@@ -1075,7 +1072,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
// Swap the dropped tab with a new one we create and then close
|
// Swap the dropped tab with a new one we create and then close
|
||||||
// it in the other window (making it seem to have moved between
|
// it in the other window (making it seem to have moved between
|
||||||
// windows). We also ensure that the tab we create to swap into has
|
// windows). We also ensure that the tab we create to swap into has
|
||||||
@@ -7549,6 +7821,8 @@
|
@@ -7549,6 +7818,8 @@
|
||||||
}
|
}
|
||||||
params.skipLoad = true;
|
params.skipLoad = true;
|
||||||
let newTab = this.addWebTab("about:blank", params);
|
let newTab = this.addWebTab("about:blank", params);
|
||||||
@@ -1084,7 +1081,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
aTab.container.tabDragAndDrop.finishAnimateTabMove();
|
aTab.container.tabDragAndDrop.finishAnimateTabMove();
|
||||||
|
|
||||||
@@ -8259,7 +8533,7 @@
|
@@ -8259,7 +8530,7 @@
|
||||||
// preventDefault(). It will still raise the window if appropriate.
|
// preventDefault(). It will still raise the window if appropriate.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1090,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
window.focus();
|
window.focus();
|
||||||
aEvent.preventDefault();
|
aEvent.preventDefault();
|
||||||
}
|
}
|
||||||
@@ -8276,7 +8550,6 @@
|
@@ -8276,7 +8547,6 @@
|
||||||
|
|
||||||
on_TabGroupCollapse(aEvent) {
|
on_TabGroupCollapse(aEvent) {
|
||||||
aEvent.target.tabs.forEach(tab => {
|
aEvent.target.tabs.forEach(tab => {
|
||||||
@@ -1101,7 +1098,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8630,7 +8903,9 @@
|
@@ -8630,7 +8900,9 @@
|
||||||
|
|
||||||
let filter = this._tabFilters.get(tab);
|
let filter = this._tabFilters.get(tab);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
@@ -1111,7 +1108,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
|
|
||||||
let listener = this._tabListeners.get(tab);
|
let listener = this._tabListeners.get(tab);
|
||||||
if (listener) {
|
if (listener) {
|
||||||
@@ -9435,6 +9710,7 @@
|
@@ -9435,6 +9707,7 @@
|
||||||
aWebProgress.isTopLevel
|
aWebProgress.isTopLevel
|
||||||
) {
|
) {
|
||||||
this.mTab.setAttribute("busy", "true");
|
this.mTab.setAttribute("busy", "true");
|
||||||
@@ -1119,7 +1116,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
||||||
this.mTab._notselectedsinceload = !this.mTab.selected;
|
this.mTab._notselectedsinceload = !this.mTab.selected;
|
||||||
}
|
}
|
||||||
@@ -9515,6 +9791,7 @@
|
@@ -9515,6 +9788,7 @@
|
||||||
// known defaults. Note we use the original URL since about:newtab
|
// known defaults. Note we use the original URL since about:newtab
|
||||||
// redirects to a prerendered page.
|
// redirects to a prerendered page.
|
||||||
const shouldRemoveFavicon =
|
const shouldRemoveFavicon =
|
||||||
@@ -1127,7 +1124,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
!this.mBrowser.mIconURL &&
|
!this.mBrowser.mIconURL &&
|
||||||
!ignoreBlank &&
|
!ignoreBlank &&
|
||||||
!(originalLocation.spec in FAVICON_DEFAULTS);
|
!(originalLocation.spec in FAVICON_DEFAULTS);
|
||||||
@@ -9689,13 +9966,6 @@
|
@@ -9689,13 +9963,6 @@
|
||||||
this.mBrowser.originalURI = aRequest.originalURI;
|
this.mBrowser.originalURI = aRequest.originalURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,7 +1138,7 @@ index 08b5b56e069d038d72c87355920c4ce8a55ed805..87f41c8583c26f364530def5bd5d8333
|
|||||||
}
|
}
|
||||||
|
|
||||||
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
|
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
|
||||||
@@ -10587,7 +10857,8 @@ var TabContextMenu = {
|
@@ -10587,7 +10854,8 @@ var TabContextMenu = {
|
||||||
);
|
);
|
||||||
contextUnpinSelectedTabs.hidden =
|
contextUnpinSelectedTabs.hidden =
|
||||||
!this.contextTab.pinned || !this.multiselected;
|
!this.contextTab.pinned || !this.multiselected;
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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: '<number>'; initial-value: 0; inherits: false; }
|
||||||
|
@property --zen-circle-anim { syntax: '<number>'; 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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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: '<number>'; initial-value: 1; inherits: false; }
|
||||||
|
@property --zen-circle-anim { syntax: '<number>'; 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>
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,4 +16,3 @@ category app-startup nsBrowserGlue @mozilla.org/browser/browserglue;1 applicatio
|
|||||||
#include common/Components.manifest
|
#include common/Components.manifest
|
||||||
#include sessionstore/SessionComponents.manifest
|
#include sessionstore/SessionComponents.manifest
|
||||||
#include live-folders/LiveFoldersComponents.manifest
|
#include live-folders/LiveFoldersComponents.manifest
|
||||||
#include space-routing/SpaceRoutingComponents.manifest
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -6,29 +6,29 @@ import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components
|
|||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const SVG_ICONS = [
|
const SVG_ICONS = [
|
||||||
"airplane.svg", "american-football.svg", "baseball.svg", "basket.svg",
|
"airplane.svg", "american-football.svg", "baseball.svg", "basket.svg",
|
||||||
"bed.svg", "bell.svg", "bookmark.svg", "book.svg",
|
"bed.svg", "bell.svg", "bookmark.svg", "book.svg",
|
||||||
"briefcase.svg", "brush.svg", "bug.svg", "build.svg",
|
"briefcase.svg", "brush.svg", "bug.svg", "build.svg",
|
||||||
"cafe.svg", "call.svg", "card.svg", "chat.svg",
|
"cafe.svg", "call.svg", "card.svg", "chat.svg",
|
||||||
"checkbox.svg", "circle.svg", "cloud.svg", "code.svg",
|
"checkbox.svg", "circle.svg", "cloud.svg", "code.svg",
|
||||||
"coins.svg", "construct.svg", "cutlery.svg", "egg.svg",
|
"coins.svg", "construct.svg", "cutlery.svg", "egg.svg",
|
||||||
"extension-puzzle.svg", "eye.svg", "fast-food.svg", "fish.svg",
|
"extension-puzzle.svg", "eye.svg", "fast-food.svg", "fish.svg",
|
||||||
"flag.svg", "flame.svg", "flask.svg", "folder.svg",
|
"flag.svg", "flame.svg", "flask.svg", "folder.svg",
|
||||||
"game-controller.svg", "globe-1.svg", "globe.svg", "grid-2x2.svg",
|
"game-controller.svg", "globe-1.svg", "globe.svg", "grid-2x2.svg",
|
||||||
"grid-3x3.svg", "heart.svg", "ice-cream.svg", "image.svg",
|
"grid-3x3.svg", "heart.svg", "ice-cream.svg", "image.svg",
|
||||||
"inbox.svg", "key.svg", "layers.svg", "leaf.svg",
|
"inbox.svg", "key.svg", "layers.svg", "leaf.svg",
|
||||||
"lightning.svg", "location.svg", "lock-closed.svg", "logo-rss.svg",
|
"lightning.svg", "location.svg", "lock-closed.svg", "logo-rss.svg",
|
||||||
"logo-usd.svg", "mail.svg", "map.svg", "megaphone.svg",
|
"logo-usd.svg", "mail.svg", "map.svg", "megaphone.svg",
|
||||||
"moon.svg", "music.svg", "navigate.svg", "nuclear.svg",
|
"moon.svg", "music.svg", "navigate.svg", "nuclear.svg",
|
||||||
"page.svg", "palette.svg", "paw.svg", "people.svg",
|
"page.svg", "palette.svg", "paw.svg", "people.svg",
|
||||||
"pizza.svg", "planet.svg", "present.svg", "rocket.svg",
|
"pizza.svg", "planet.svg", "present.svg", "rocket.svg",
|
||||||
"school.svg", "shapes.svg", "shirt.svg", "skull.svg",
|
"school.svg", "shapes.svg", "shirt.svg", "skull.svg",
|
||||||
"squares.svg", "square.svg", "star-1.svg", "star.svg",
|
"squares.svg", "square.svg", "star-1.svg", "star.svg",
|
||||||
"stats-chart.svg", "sun.svg", "tada.svg", "terminal.svg",
|
"stats-chart.svg", "sun.svg", "tada.svg", "terminal.svg",
|
||||||
"ticket.svg", "time.svg", "trash.svg", "triangle.svg",
|
"ticket.svg", "time.svg", "trash.svg", "triangle.svg",
|
||||||
"video.svg", "volume-high.svg", "wallet.svg", "warning.svg",
|
"video.svg", "volume-high.svg", "wallet.svg", "warning.svg",
|
||||||
"water.svg", "weight.svg",
|
"water.svg", "weight.svg",
|
||||||
];
|
];
|
||||||
|
|
||||||
class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
||||||
#panel;
|
#panel;
|
||||||
@@ -47,7 +47,6 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
|||||||
init() {
|
init() {
|
||||||
this.#panel = document.getElementById("PanelUI-zen-emojis-picker");
|
this.#panel = document.getElementById("PanelUI-zen-emojis-picker");
|
||||||
this.#panel.addEventListener("popupshowing", this);
|
this.#panel.addEventListener("popupshowing", this);
|
||||||
this.#panel.addEventListener("popupshown", this);
|
|
||||||
this.#panel.addEventListener("popuphidden", this);
|
this.#panel.addEventListener("popuphidden", this);
|
||||||
this.#panel.addEventListener("command", this);
|
this.#panel.addEventListener("command", this);
|
||||||
this.searchInput.addEventListener("input", this);
|
this.searchInput.addEventListener("input", this);
|
||||||
@@ -58,9 +57,6 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
|||||||
case "popupshowing":
|
case "popupshowing":
|
||||||
this.#onPopupShowing(event);
|
this.#onPopupShowing(event);
|
||||||
break;
|
break;
|
||||||
case "popupshown":
|
|
||||||
this.#onPopupShown(event);
|
|
||||||
break;
|
|
||||||
case "popuphidden":
|
case "popuphidden":
|
||||||
this.#onPopupHidden(event);
|
this.#onPopupHidden(event);
|
||||||
break;
|
break;
|
||||||
@@ -107,20 +103,17 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
|||||||
return document.getElementById("PanelUI-zen-emojis-picker-search");
|
return document.getElementById("PanelUI-zen-emojis-picker-search");
|
||||||
}
|
}
|
||||||
|
|
||||||
#changePage(toSvg = false, { animate = true } = {}) {
|
#changePage(toSvg = false) {
|
||||||
const pages = document.getElementById("PanelUI-zen-emojis-picker-pages");
|
|
||||||
const itemToScroll = toSvg
|
const itemToScroll = toSvg
|
||||||
? this.svgList
|
? this.svgList
|
||||||
: pages.querySelector('[emojis="true"]');
|
: document
|
||||||
if (animate) {
|
.getElementById("PanelUI-zen-emojis-picker-pages")
|
||||||
itemToScroll.scrollIntoView({
|
.querySelector('[emojis="true"]');
|
||||||
behavior: "smooth",
|
itemToScroll.scrollIntoView({
|
||||||
block: "nearest",
|
behavior: "smooth",
|
||||||
inline: "start",
|
block: "nearest",
|
||||||
});
|
inline: "start",
|
||||||
} else {
|
});
|
||||||
pages.scrollLeft = toSvg ? itemToScroll.offsetLeft : 0;
|
|
||||||
}
|
|
||||||
const button = document.getElementById(
|
const button = document.getElementById(
|
||||||
`PanelUI-zen-emojis-picker-change-${toSvg ? "svg" : "emojis"}`
|
`PanelUI-zen-emojis-picker-change-${toSvg ? "svg" : "emojis"}`
|
||||||
);
|
);
|
||||||
@@ -187,6 +180,9 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
|||||||
});
|
});
|
||||||
emojiList.appendChild(item);
|
emojiList.appendChild(item);
|
||||||
}
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.searchInput.focus();
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
const svgList = this.svgList;
|
const svgList = this.svgList;
|
||||||
for (const icon of SVG_ICONS) {
|
for (const icon of SVG_ICONS) {
|
||||||
@@ -203,23 +199,14 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#onPopupShown(event) {
|
|
||||||
if (event.target !== this.#panel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const allowEmojis = !this.#panel.hasAttribute("only-svg-icons");
|
|
||||||
if (allowEmojis) {
|
|
||||||
this.searchInput.focus({ preventScroll: true });
|
|
||||||
}
|
|
||||||
this.#changePage(false, { animate: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
#onPopupHidden(event) {
|
#onPopupHidden(event) {
|
||||||
if (event.target !== this.#panel) {
|
if (event.target !== this.#panel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.#clearEmojis();
|
this.#clearEmojis();
|
||||||
|
|
||||||
|
this.#changePage(false);
|
||||||
|
|
||||||
const emojiList = this.emojiList;
|
const emojiList = this.emojiList;
|
||||||
emojiList.innerHTML = "";
|
emojiList.innerHTML = "";
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ export class ZenSpaceRoutingNavigation extends ZenUIComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The tab we spawn for a route must be allowed to load once without being
|
||||||
|
// redirected again, regardless of when its workspace attribute lands.
|
||||||
|
if (aBrowser._zenSkipNavRouteOnce) {
|
||||||
|
aBrowser._zenSkipNavRouteOnce = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let uri;
|
let uri;
|
||||||
try {
|
try {
|
||||||
uri = aRequest.QueryInterface(Ci.nsIChannel).URI;
|
uri = aRequest.QueryInterface(Ci.nsIChannel).URI;
|
||||||
@@ -73,49 +80,16 @@ export class ZenSpaceRoutingNavigation extends ZenUIComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentWorkspaceId = tab.getAttribute("zen-workspace-id");
|
const currentWorkspaceId = tab.getAttribute("zen-workspace-id");
|
||||||
const targetWorkspaceId =
|
if (
|
||||||
win.gZenSpaceRoutingManager.getRedirectTargetWorkspaceId(
|
!win.gZenSpaceRoutingManager.shouldRedirectNavigation(
|
||||||
uri.spec,
|
uri.spec,
|
||||||
currentWorkspaceId,
|
currentWorkspaceId,
|
||||||
win
|
win
|
||||||
);
|
)
|
||||||
if (!targetWorkspaceId) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A brand-new tab whose very first real navigation this is (a
|
|
||||||
// target="_blank" link, window.open(), or a freshly opened tab) is still
|
|
||||||
// showing its initial about:blank document. There is nothing to preserve,
|
|
||||||
// so rather than cancelling the load and spawning a duplicate tab - which
|
|
||||||
// would leave this one behind empty - just move this very tab into the
|
|
||||||
// destination space and let the in-flight load finish in place.
|
|
||||||
const isInitialDocument =
|
|
||||||
aBrowser.browsingContext?.currentWindowGlobal?.isInitialDocument ?? false;
|
|
||||||
if (isInitialDocument) {
|
|
||||||
const wasSelected = tab.selected;
|
|
||||||
// Defer so we don't mutate the tab strip from inside a progress notification.
|
|
||||||
win.setTimeout(() => {
|
|
||||||
if (!tab.isConnected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gBrowser.selectedTab = tab.owner;
|
|
||||||
win.gZenWorkspaces.moveTabToWorkspace(tab, targetWorkspaceId);
|
|
||||||
if (wasSelected) {
|
|
||||||
const targetWorkspace =
|
|
||||||
win.gZenWorkspaces.getWorkspaceFromId(targetWorkspaceId);
|
|
||||||
if (targetWorkspace) {
|
|
||||||
win.gZenWorkspaces.lastSelectedWorkspaceTabs[targetWorkspaceId] =
|
|
||||||
tab;
|
|
||||||
win.gZenWorkspaces.changeWorkspace(targetWorkspace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An already-loaded page is navigating in place. Preserve it in its current
|
|
||||||
// tab and re-open the destination in a new routed tab instead.
|
|
||||||
//
|
|
||||||
// Under Fission the parent-side aRequest is a RemoteWebProgress stand-in
|
// Under Fission the parent-side aRequest is a RemoteWebProgress stand-in
|
||||||
// whose cancel()/loadInfo throw NS_ERROR_NOT_IMPLEMENTED (the real channel
|
// whose cancel()/loadInfo throw NS_ERROR_NOT_IMPLEMENTED (the real channel
|
||||||
// lives in the content process). Stop the in-place load through the browser,
|
// lives in the content process). Stop the in-place load through the browser,
|
||||||
@@ -137,14 +111,13 @@ export class ZenSpaceRoutingNavigation extends ZenUIComponent {
|
|||||||
|
|
||||||
// Defer so we don't mutate the tab strip from inside a progress notification.
|
// Defer so we don't mutate the tab strip from inside a progress notification.
|
||||||
win.setTimeout(() => {
|
win.setTimeout(() => {
|
||||||
gBrowser.addTab(urlToOpen, {
|
const newTab = gBrowser.addTab(urlToOpen, {
|
||||||
triggeringPrincipal: principal,
|
triggeringPrincipal: principal,
|
||||||
ownerTab: tab.isConnected ? tab : null,
|
ownerTab: tab.isConnected ? tab : null,
|
||||||
// The user was actively navigating this tab, so follow the navigation
|
|
||||||
// into the routed tab instead of opening it in the background (addTab
|
|
||||||
// defaults inBackground to true).
|
|
||||||
inBackground: false,
|
|
||||||
});
|
});
|
||||||
|
if (newTab?.linkedBrowser) {
|
||||||
|
newTab.linkedBrowser._zenSkipNavRouteOnce = true;
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ document.addEventListener(
|
|||||||
case "cmd_zenReplacePinnedUrlWithCurrent":
|
case "cmd_zenReplacePinnedUrlWithCurrent":
|
||||||
gZenPinnedTabManager.replacePinnedUrlWithCurrent();
|
gZenPinnedTabManager.replacePinnedUrlWithCurrent();
|
||||||
break;
|
break;
|
||||||
case "cmd_zenEditPinnedUrl":
|
|
||||||
gZenPinnedTabManager.editPinnedUrl();
|
|
||||||
break;
|
|
||||||
case "cmd_contextZenAddToEssentials":
|
case "cmd_contextZenAddToEssentials":
|
||||||
gZenPinnedTabManager.addToEssentials();
|
gZenPinnedTabManager.addToEssentials();
|
||||||
break;
|
break;
|
||||||
@@ -136,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;
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|
||||||
|
|||||||
@@ -53,10 +53,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
|
|||||||
#setupEventListeners() {
|
#setupEventListeners() {
|
||||||
window.addEventListener("TabClose", this.onTabClose.bind(this));
|
window.addEventListener("TabClose", this.onTabClose.bind(this));
|
||||||
window.addEventListener("TabSelect", this.onLocationChange.bind(this));
|
window.addEventListener("TabSelect", this.onLocationChange.bind(this));
|
||||||
window.addEventListener(
|
|
||||||
"MozDOMFullscreen:Entered",
|
|
||||||
this.onFullscreenEntered.bind(this)
|
|
||||||
);
|
|
||||||
|
|
||||||
document
|
document
|
||||||
.getElementById("tabbrowser-tabpanels")
|
.getElementById("tabbrowser-tabpanels")
|
||||||
@@ -1418,23 +1414,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle DOM Fullscreen request while inside glance
|
|
||||||
*
|
|
||||||
* @param {Event} event - The MozDOMFullscreen:Entered event
|
|
||||||
*/
|
|
||||||
onFullscreenEntered(event) {
|
|
||||||
const browser = this.#currentBrowser;
|
|
||||||
|
|
||||||
if (!browser) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.target === browser) {
|
|
||||||
this.fullyOpenGlance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage tab close for glance tabs
|
* Manage tab close for glance tabs
|
||||||
*
|
*
|
||||||
|
|||||||
529
src/zen/library/ZenLibrary.mjs
Normal file
529
src/zen/library/ZenLibrary.mjs
Normal 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);
|
||||||
556
src/zen/library/ZenLibraryButton.mjs
Normal file
556
src/zen/library/ZenLibraryButton.mjs
Normal 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();
|
||||||
1789
src/zen/library/ZenLibrarySections.mjs
Normal file
1789
src/zen/library/ZenLibrarySections.mjs
Normal file
File diff suppressed because it is too large
Load Diff
5
src/zen/library/jar.inc.mn
Normal file
5
src/zen/library/jar.inc.mn
Normal 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)
|
||||||
9
src/zen/library/moz.build
Normal file
9
src/zen/library/moz.build
Normal 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",
|
||||||
|
]
|
||||||
635
src/zen/library/zen-library.css
Normal file
635
src/zen/library/zen-library.css
Normal 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);
|
||||||
|
}
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ DIRS += [
|
|||||||
"sessionstore",
|
"sessionstore",
|
||||||
"share",
|
"share",
|
||||||
"spaces",
|
"spaces",
|
||||||
|
"library",
|
||||||
"space-routing",
|
"space-routing",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1232,38 +1232,19 @@ class nsZenWindowSync {
|
|||||||
activeIndex = Math.min(activeIndex, entries.length - 1);
|
activeIndex = Math.min(activeIndex, entries.length - 1);
|
||||||
activeIndex = Math.max(activeIndex, 0);
|
activeIndex = Math.max(activeIndex, 0);
|
||||||
let entryToUse = (entries[activeIndex] || entries[0]) ?? null;
|
let entryToUse = (entries[activeIndex] || entries[0]) ?? null;
|
||||||
this.#setPinnedInitialState(
|
const initialState = {
|
||||||
aTab,
|
entry: {
|
||||||
{ url: entryToUse?.url, title: entryToUse?.title },
|
url: entryToUse?.url,
|
||||||
image
|
title: entryToUse?.title,
|
||||||
);
|
},
|
||||||
});
|
image,
|
||||||
}
|
};
|
||||||
|
this.#runOnAllWindows(null, win => {
|
||||||
/**
|
const targetTab = this.getItemFromWindow(win, aTab.id);
|
||||||
* Sets the canonical pinned URL for a tab across all windows. Used to let the
|
if (targetTab) {
|
||||||
* user edit a pinned tab's URL directly.
|
targetTab._zenPinnedInitialState = initialState;
|
||||||
*
|
}
|
||||||
* @param {object} aTab - The tab to set the pinned URL for.
|
});
|
||||||
* @param {string} aUrl - The URL to store as the canonical pinned URL.
|
|
||||||
* @param {string} [aImage] - Optional Icon to store.
|
|
||||||
*/
|
|
||||||
setPinnedUrl(aTab, aUrl, aImage) {
|
|
||||||
this.log(`Setting pinned url for tab ${aTab.id}`);
|
|
||||||
this.#setPinnedInitialState(
|
|
||||||
aTab,
|
|
||||||
{ url: aUrl, title: aTab.zenStaticLabel },
|
|
||||||
aImage
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#setPinnedInitialState(aTab, aEntry, aImage) {
|
|
||||||
const initialState = { entry: aEntry, image: aImage };
|
|
||||||
this.#runOnAllWindows(null, win => {
|
|
||||||
const targetTab = this.getItemFromWindow(win, aTab.id);
|
|
||||||
if (targetTab) {
|
|
||||||
targetTab._zenPinnedInitialState = initialState;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,58 +18,6 @@ class nsZenSpaceRoutingManager {
|
|||||||
this.#readFromDisk();
|
this.#readFromDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto invoked for every window on delayed startup
|
|
||||||
*
|
|
||||||
* @param {nsIDOMWindow} window - The browser window that just started up
|
|
||||||
*/
|
|
||||||
onDelayedBrowserStartup(window) {
|
|
||||||
const element = window.MozXULElement.parseXULToFragment(`
|
|
||||||
<menuseparator/>
|
|
||||||
<menuitem id="context_zen-add-domain-to-routing"
|
|
||||||
data-lazy-l10n-id="tab-context-zen-add-domain-to-sr"
|
|
||||||
data-l10n-args='{"tabCount": 1}'/>
|
|
||||||
`);
|
|
||||||
window.document.getElementById("context_undoCloseTab").after(element);
|
|
||||||
|
|
||||||
window.document
|
|
||||||
.getElementById("context_zen-add-domain-to-routing")
|
|
||||||
.addEventListener("command", this.#onAddSelectedToRouting.bind(this));
|
|
||||||
window.document
|
|
||||||
.getElementById("tabContextMenu")
|
|
||||||
.addEventListener(
|
|
||||||
"popupshowing",
|
|
||||||
this.#updateTabCloseCountState.bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the "context_zen-add-domain-to-routing" command
|
|
||||||
* to reflect the number of selected tabs, when applicable.
|
|
||||||
*
|
|
||||||
* @param {Event} event - The event param
|
|
||||||
*/
|
|
||||||
#updateTabCloseCountState(event) {
|
|
||||||
const window = event.target.documentGlobal;
|
|
||||||
window.document.l10n.setArgs(
|
|
||||||
window.document.getElementById("context_zen-add-domain-to-routing"),
|
|
||||||
{ tabCount: window.gBrowser.selectedTabs.length }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for whenever the menuitem command is ran
|
|
||||||
*
|
|
||||||
* @param {Event} event - The event parameter
|
|
||||||
*/
|
|
||||||
#onAddSelectedToRouting(event) {
|
|
||||||
const window = event.target.documentGlobal;
|
|
||||||
const tabs = window.TabContextMenu.contextTab.multiselected
|
|
||||||
? window.gBrowser.selectedTabs
|
|
||||||
: [window.TabContextMenu.contextTab];
|
|
||||||
this.addRouteForSelected(tabs, window);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback that will be executed from tabbrowser.js
|
* Callback that will be executed from tabbrowser.js
|
||||||
* This method can be used to stop the tab from being created.
|
* This method can be used to stop the tab from being created.
|
||||||
@@ -104,7 +52,7 @@ class nsZenSpaceRoutingManager {
|
|||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
const targetWorkspace =
|
const targetWorkspace =
|
||||||
win.gZenWorkspaces.getWorkspaceFromId(targetRoute);
|
win?.gZenWorkspaces?.getWorkspaceFromId(targetRoute);
|
||||||
|
|
||||||
if (targetWorkspace) {
|
if (targetWorkspace) {
|
||||||
userContextId = targetWorkspace.containerTabId;
|
userContextId = targetWorkspace.containerTabId;
|
||||||
@@ -159,26 +107,8 @@ class nsZenSpaceRoutingManager {
|
|||||||
* @returns {boolean} True when the navigation should open in a new routed tab
|
* @returns {boolean} True when the navigation should open in a new routed tab
|
||||||
*/
|
*/
|
||||||
shouldRedirectNavigation(uriString, currentWorkspaceId, win) {
|
shouldRedirectNavigation(uriString, currentWorkspaceId, win) {
|
||||||
return !!this.getRedirectTargetWorkspaceId(
|
|
||||||
uriString,
|
|
||||||
currentWorkspaceId,
|
|
||||||
win
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the destination space for an in-place top-level navigation, or
|
|
||||||
* null when the navigation should be left alone (no rule, the destination is
|
|
||||||
* "most-recent-space", the tab already lives there, or the space is gone).
|
|
||||||
*
|
|
||||||
* @param {string} uriString - The destination URI
|
|
||||||
* @param {string|null} currentWorkspaceId - The zen-workspace-id of the navigating tab
|
|
||||||
* @param {Window} win - The owning browser window
|
|
||||||
* @returns {string|null} The target workspace id, or null to leave the navigation in place
|
|
||||||
*/
|
|
||||||
getRedirectTargetWorkspaceId(uriString, currentWorkspaceId, win) {
|
|
||||||
if (!win?.gZenWorkspaces?.workspaceEnabled) {
|
if (!win?.gZenWorkspaces?.workspaceEnabled) {
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetRoute = this.routeUri(uriString, { fromExternal: false });
|
const targetRoute = this.routeUri(uriString, { fromExternal: false });
|
||||||
@@ -188,13 +118,11 @@ class nsZenSpaceRoutingManager {
|
|||||||
targetRoute === "most-recent-space" ||
|
targetRoute === "most-recent-space" ||
|
||||||
targetRoute === currentWorkspaceId
|
targetRoute === currentWorkspaceId
|
||||||
) {
|
) {
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only redirect when the destination space actually exists.
|
// Only redirect when the destination space actually exists.
|
||||||
return win.gZenWorkspaces.getWorkspaceFromId(targetRoute)
|
return !!win.gZenWorkspaces.getWorkspaceFromId(targetRoute);
|
||||||
? targetRoute
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -475,37 +403,6 @@ class nsZenSpaceRoutingManager {
|
|||||||
this.#file.data.defaultRouteExternal = routeType;
|
this.#file.data.defaultRouteExternal = routeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new route for all given tabs
|
|
||||||
*
|
|
||||||
* @param {Array<object>} selectedTabs - The tabs that should be routed
|
|
||||||
* @param {Window} parentWindow - The window from which this is being executed
|
|
||||||
*/
|
|
||||||
addRouteForSelected(selectedTabs, parentWindow) {
|
|
||||||
const newRoute = this.createNewRoute();
|
|
||||||
let routeReference = "";
|
|
||||||
|
|
||||||
if (selectedTabs.length == 1) {
|
|
||||||
newRoute.matchType = "contains";
|
|
||||||
routeReference = selectedTabs[0].linkedBrowser.currentURI.host;
|
|
||||||
} else {
|
|
||||||
newRoute.matchType = "regex";
|
|
||||||
routeReference = "(";
|
|
||||||
for (let i = 0; i < selectedTabs.length; i++) {
|
|
||||||
const domain = selectedTabs[i].linkedBrowser.currentURI.host;
|
|
||||||
routeReference += domain.replaceAll(".", "\.");
|
|
||||||
if (i != selectedTabs.length - 1) {
|
|
||||||
routeReference += "|";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
routeReference += ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
newRoute.reference = routeReference;
|
|
||||||
this.updateRoute(newRoute);
|
|
||||||
this.openSpaceRoutingDialog(parentWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves all routes. The list of
|
* Saves all routes. The list of
|
||||||
* routes is stripped of empty routes
|
* routes is stripped of empty routes
|
||||||
|
|||||||
@@ -1507,26 +1507,18 @@ class nsZenWorkspaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
const newtabPlacement = Services.prefs.getBoolPref(
|
|
||||||
"zen.view.show-newtab-button-top",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
const insertElement = newtabPlacement
|
|
||||||
? container.firstChild
|
|
||||||
: container.lastChild;
|
|
||||||
|
|
||||||
if (tab.group?.hasAttribute("split-view-group")) {
|
if (tab.group?.hasAttribute("split-view-group")) {
|
||||||
gBrowser.zenHandleTabMove(tab.group, () => {
|
gBrowser.zenHandleTabMove(tab.group, () => {
|
||||||
for (const subTab of tab.group.tabs) {
|
for (const subTab of tab.group.tabs) {
|
||||||
subTab.setAttribute("zen-workspace-id", workspaceID);
|
subTab.setAttribute("zen-workspace-id", workspaceID);
|
||||||
}
|
}
|
||||||
container.insertBefore(tab.group, insertElement);
|
container.insertBefore(tab.group, container.lastChild);
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gBrowser.zenHandleTabMove(tab, () => {
|
gBrowser.zenHandleTabMove(tab, () => {
|
||||||
tab.setAttribute("zen-workspace-id", workspaceID);
|
tab.setAttribute("zen-workspace-id", workspaceID);
|
||||||
container.insertBefore(tab, insertElement);
|
container.insertBefore(tab, container.lastChild);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// also change glance tab if it's the same tab
|
// also change glance tab if it's the same tab
|
||||||
@@ -2298,12 +2290,12 @@ class nsZenWorkspaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onBeforeTabSelect(aTab) {
|
onBeforeTabSelect(aTab) {
|
||||||
if (this.#inChangingWorkspace || !aTab) {
|
if (this.#inChangingWorkspace) {
|
||||||
// Just in case, Let's not do these checks while we are
|
// Just in case, Let's not do these checks while we are
|
||||||
// in the middle of changing workspace,
|
// in the middle of changing workspace,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const tabSpace = aTab.getAttribute("zen-workspace-id");
|
const tabSpace = aTab?.getAttribute("zen-workspace-id");
|
||||||
if (
|
if (
|
||||||
tabSpace &&
|
tabSpace &&
|
||||||
tabSpace !== this.activeWorkspace &&
|
tabSpace !== this.activeWorkspace &&
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -1240,17 +1240,13 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
*/
|
*/
|
||||||
contextSplitTabs(otherTabHint = null) {
|
contextSplitTabs(otherTabHint = null) {
|
||||||
let tabs;
|
let tabs;
|
||||||
let currentTab = gZenGlanceManager.getTabOrGlanceParent(
|
let currentTab = TabContextMenu.contextTab || gBrowser.selectedTab;
|
||||||
TabContextMenu.contextTab || gBrowser.selectedTab
|
|
||||||
);
|
|
||||||
if (currentTab.multiselected) {
|
if (currentTab.multiselected) {
|
||||||
tabs = gBrowser.selectedTabs;
|
tabs = gBrowser.selectedTabs;
|
||||||
} else if (!currentTab.selected && !currentTab.splitView) {
|
} else if (!currentTab.selected && !currentTab.splitView) {
|
||||||
tabs = [
|
tabs = [
|
||||||
currentTab,
|
currentTab,
|
||||||
...gBrowser.selectedTabs.filter(
|
...gBrowser.selectedTabs.filter(t => t !== currentTab),
|
||||||
t => t !== currentTab && !t.hasAttribute("zen-glance-tab")
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
tabs = [currentTab];
|
tabs = [currentTab];
|
||||||
|
|||||||
@@ -246,66 +246,6 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
gZenUIManager.showToast("zen-pinned-tab-replaced");
|
gZenUIManager.showToast("zen-pinned-tab-replaced");
|
||||||
}
|
}
|
||||||
|
|
||||||
async editPinnedUrl(tab = undefined) {
|
|
||||||
tab ??= TabContextMenu.contextTab;
|
|
||||||
if (!tab || !tab.pinned) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialUrl =
|
|
||||||
tab._zenPinnedInitialState?.entry?.url ||
|
|
||||||
tab.linkedBrowser?.currentURI?.spec;
|
|
||||||
const [title, label] = await document.l10n.formatValues([
|
|
||||||
{ id: "zen-pinned-tab-edit-url-title" },
|
|
||||||
{ id: "zen-pinned-tab-edit-url-label" },
|
|
||||||
]);
|
|
||||||
const result = { value: initialUrl ?? "" };
|
|
||||||
const confirmed = Services.prompt.prompt(
|
|
||||||
window,
|
|
||||||
title,
|
|
||||||
label,
|
|
||||||
result,
|
|
||||||
null,
|
|
||||||
{ value: false }
|
|
||||||
);
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let uri;
|
|
||||||
try {
|
|
||||||
uri = Services.uriFixup.getFixupURIInfo(
|
|
||||||
result.value.trim(),
|
|
||||||
Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
|
|
||||||
).preferredURI;
|
|
||||||
} catch (_) {}
|
|
||||||
if (!uri) {
|
|
||||||
gZenUIManager.showToast("zen-pinned-tab-url-invalid");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const url = uri.spec;
|
|
||||||
|
|
||||||
// Skip when the value wasn't actually changed from what was prefilled.
|
|
||||||
if (!url || url === initialUrl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const image = tab.zenStaticIcon || (await this.#getCachedFavicon(uri));
|
|
||||||
window.gZenWindowSync.setPinnedUrl(tab, url, image);
|
|
||||||
this.#resetTabToStoredState(tab);
|
|
||||||
gZenUIManager.showToast("zen-pinned-tab-url-edited");
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getCachedFavicon(uri) {
|
|
||||||
try {
|
|
||||||
const favicon = await PlacesUtils.favicons.getFaviconForPage(uri);
|
|
||||||
return favicon?.dataURI?.spec;
|
|
||||||
} catch (ex) {
|
|
||||||
console.error("Failed to get favicon for edited pinned url:", ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_initClosePinnedTabShortcut() {
|
_initClosePinnedTabShortcut() {
|
||||||
let cmdClose = document.getElementById("cmd_close");
|
let cmdClose = document.getElementById("cmd_close");
|
||||||
|
|
||||||
@@ -605,20 +545,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
const elements = window.MozXULElement.parseXULToFragment(`
|
const elements = window.MozXULElement.parseXULToFragment(`
|
||||||
<menuseparator id="context_zen-pinned-tab-separator" hidden="true"/>
|
<menuseparator id="context_zen-pinned-tab-separator" hidden="true"/>
|
||||||
<menu id="context_zen-edit-pinned-page"
|
<menuitem id="context_zen-replace-pinned-url-with-current"
|
||||||
data-lazy-l10n-id="tab-context-zen-edit-pinned-page"
|
data-lazy-l10n-id="tab-context-zen-replace-pinned-url-with-current"
|
||||||
data-l10n-args="{"isEssential":""}"
|
data-l10n-args="{"isEssential":""}"
|
||||||
hidden="true">
|
hidden="true"
|
||||||
<menupopup>
|
command="cmd_zenReplacePinnedUrlWithCurrent"/>
|
||||||
<menuitem id="context_zen-replace-pinned-url-with-current"
|
|
||||||
data-lazy-l10n-id="tab-context-zen-replace-pinned-url-with-current"
|
|
||||||
data-l10n-args="{"isEssential":""}"
|
|
||||||
command="cmd_zenReplacePinnedUrlWithCurrent"/>
|
|
||||||
<menuitem id="context_zen-edit-pinned-url"
|
|
||||||
data-lazy-l10n-id="tab-context-zen-edit-pinned-url"
|
|
||||||
command="cmd_zenEditPinnedUrl"/>
|
|
||||||
</menupopup>
|
|
||||||
</menu>
|
|
||||||
<menuitem id="context_zen-reset-pinned-tab"
|
<menuitem id="context_zen-reset-pinned-tab"
|
||||||
data-lazy-l10n-id="tab-context-zen-reset-pinned-tab"
|
data-lazy-l10n-id="tab-context-zen-reset-pinned-tab"
|
||||||
data-l10n-args="{"isEssential":""}"
|
data-l10n-args="{"isEssential":""}"
|
||||||
@@ -688,24 +619,15 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
const zenResetPinnedTab = document.getElementById(
|
const zenResetPinnedTab = document.getElementById(
|
||||||
"context_zen-reset-pinned-tab"
|
"context_zen-reset-pinned-tab"
|
||||||
);
|
);
|
||||||
const zenEditPinnedPage = document.getElementById(
|
|
||||||
"context_zen-edit-pinned-page"
|
|
||||||
);
|
|
||||||
const zenReplacePinnedUrl = document.getElementById(
|
const zenReplacePinnedUrl = document.getElementById(
|
||||||
"context_zen-replace-pinned-url-with-current"
|
"context_zen-replace-pinned-url-with-current"
|
||||||
);
|
);
|
||||||
[zenResetPinnedTab, zenEditPinnedPage].forEach(element => {
|
[zenResetPinnedTab, zenReplacePinnedUrl].forEach(element => {
|
||||||
if (element) {
|
if (element) {
|
||||||
element.hidden = !isVisible;
|
element.hidden = !isVisible;
|
||||||
|
document.l10n.setArgs(element, { isEssential });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
[zenResetPinnedTab, zenEditPinnedPage, zenReplacePinnedUrl].forEach(
|
|
||||||
element => {
|
|
||||||
if (element) {
|
|
||||||
document.l10n.setArgs(element, { isEssential });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
zenAddEssential.hidden = isEssential || !!contextTab.group;
|
zenAddEssential.hidden = isEssential || !!contextTab.group;
|
||||||
document.l10n
|
document.l10n
|
||||||
.formatValue("tab-context-zen-add-essential-badge", {
|
.formatValue("tab-context-zen-add-essential-badge", {
|
||||||
@@ -935,7 +857,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove # from the URL
|
// Remove # and ? from the URL
|
||||||
const pinUrl = tab._zenPinnedInitialState.entry.url.split("#")[0];
|
const pinUrl = tab._zenPinnedInitialState.entry.url.split("#")[0];
|
||||||
const currentUrl = location.split("#")[0];
|
const currentUrl = location.split("#")[0];
|
||||||
// Add an indicator that the pin has been changed
|
// Add an indicator that the pin has been changed
|
||||||
@@ -975,14 +897,10 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
} else {
|
} else {
|
||||||
tab.setAttribute("zen-pinned-changed", "true");
|
tab.setAttribute("zen-pinned-changed", "true");
|
||||||
}
|
}
|
||||||
if (tab._zenPinnedInitialState.image) {
|
tab.style.setProperty(
|
||||||
tab.style.setProperty(
|
"--zen-original-tab-icon",
|
||||||
"--zen-original-tab-icon",
|
`url(${tab._zenPinnedInitialState.image})`
|
||||||
`url(${tab._zenPinnedInitialState.image})`
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
tab.style.removeProperty("--zen-original-tab-icon");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTabContainersDragoverClass(hideIndicator = true) {
|
removeTabContainersDragoverClass(hideIndicator = true) {
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ prefs = ["zen.workspaces.separate-essentials=false"]
|
|||||||
|
|
||||||
["browser_pinned_created.js"]
|
["browser_pinned_created.js"]
|
||||||
|
|
||||||
["browser_pinned_edit_url.js"]
|
|
||||||
|
|
||||||
["browser_pinned_nounload_reset.js"]
|
["browser_pinned_nounload_reset.js"]
|
||||||
|
|
||||||
["browser_pinned_reset_button.js"]
|
["browser_pinned_reset_button.js"]
|
||||||
|
|||||||
@@ -1,384 +0,0 @@
|
|||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
async function pinTab(url) {
|
|
||||||
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
|
||||||
gBrowser.pinTab(tab);
|
|
||||||
await gBrowser.TabStateFlusher.flush(tab.linkedBrowser);
|
|
||||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
||||||
await new Promise(r => setTimeout(r, 500));
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XPCOM service methods can't be stubbed in place (non-configurable), so we
|
|
||||||
// swap the whole service object out for a mock and restore it afterwards.
|
|
||||||
function mockPrompt(value) {
|
|
||||||
const original = Services.prompt;
|
|
||||||
Services.prompt = {
|
|
||||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptService]),
|
|
||||||
prompt(win, title, label, result) {
|
|
||||||
if (value === null) {
|
|
||||||
return false; // user cancelled
|
|
||||||
}
|
|
||||||
result.value = value;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return () => {
|
|
||||||
Services.prompt = original;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mockFavicons(faviconSpec) {
|
|
||||||
const original = PlacesUtils.favicons;
|
|
||||||
const mock = {
|
|
||||||
callCount: 0,
|
|
||||||
defaultFavicon: { spec: "data:image/png;base64,DEFAULT" },
|
|
||||||
getFaviconForPage() {
|
|
||||||
mock.callCount++;
|
|
||||||
return Promise.resolve(
|
|
||||||
faviconSpec ? { dataURI: { spec: faviconSpec } } : null
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
PlacesUtils.favicons = mock;
|
|
||||||
return {
|
|
||||||
mock,
|
|
||||||
restore: () => {
|
|
||||||
PlacesUtils.favicons = original;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_SurvivesRebuild() {
|
|
||||||
// Pinned tab at url1 (loaded), then select a different tab (unfocus it).
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const other = await BrowserTestUtils.openNewForegroundTab(
|
|
||||||
gBrowser,
|
|
||||||
"https://example.com/other"
|
|
||||||
);
|
|
||||||
|
|
||||||
const editedUrl = "https://example.com/edited";
|
|
||||||
const restorePrompt = mockPrompt(editedUrl);
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
// Close + re-open rebuilds the tab: the in-memory _zenPinnedInitialState is
|
|
||||||
// gone and gets reconstructed from the persisted session via
|
|
||||||
// setPinnedTabState (exactly what #onSessionStoreInitialized does).
|
|
||||||
delete tab._zenPinnedInitialState;
|
|
||||||
await window.gZenWindowSync.setPinnedTabState(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
editedUrl,
|
|
||||||
"After the tab is rebuilt, the pinned URL should still be the edited one"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(other);
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_ActiveTabNavigates() {
|
|
||||||
// Editing the active (focused) pinned tab applies the new URL immediately:
|
|
||||||
// the live tab navigates to it (matching Arc's behavior).
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
Assert.equal(gBrowser.selectedTab, tab, "the pinned tab should be active");
|
|
||||||
|
|
||||||
const editedUrl = "https://example.com/edited";
|
|
||||||
const restorePrompt = mockPrompt(editedUrl);
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
|
||||||
() => tab.linkedBrowser.currentURI.spec === editedUrl,
|
|
||||||
"the active pinned tab to navigate to the edited URL"
|
|
||||||
);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab.linkedBrowser.currentURI.spec,
|
|
||||||
editedUrl,
|
|
||||||
"Editing the active pinned tab should navigate it to the new URL"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(
|
|
||||||
async function test_EditPinnedUrl_FaviconLookupErrorLeavesImageEmpty() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons(null);
|
|
||||||
// Simulate a Places DB failure so #getCachedFavicon hits its catch branch.
|
|
||||||
favicons.mock.getFaviconForPage = () =>
|
|
||||||
Promise.reject(new Error("simulated favicon DB failure"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
"https://example.org/edited",
|
|
||||||
"The URL should still be updated when the favicon lookup fails"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!tab._zenPinnedInitialState.image,
|
|
||||||
"The image should be left empty (populated by the next navigation)"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_UpdatesUrlAndFavicon() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const faviconSpec = "data:image/png;base64,iVBORw0KGgo=";
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons(faviconSpec);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
"https://example.org/edited",
|
|
||||||
"The pinned URL should be updated to the edited value"
|
|
||||||
);
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.image,
|
|
||||||
faviconSpec,
|
|
||||||
"The stored icon should be the cached favicon for the new URL"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_NoCachedFaviconLeavesImageEmpty() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons(null); // no cached favicon for the new URL
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
ok(
|
|
||||||
!tab._zenPinnedInitialState.image,
|
|
||||||
"Without a cached favicon the image is left empty, not the default; the " +
|
|
||||||
"next navigation captures the real icon"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_ClearsStaleTitle() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
ok(
|
|
||||||
!tab._zenPinnedInitialState.entry.title,
|
|
||||||
"The previous title is cleared so the new page's title is used on load"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_KeepsCustomLabel() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
tab.zenStaticLabel = "My Pinned Tab";
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.title,
|
|
||||||
"My Pinned Tab",
|
|
||||||
"An explicit custom label is preserved across a URL edit"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
delete tab.zenStaticLabel;
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_KeepsCustomIcon() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const customIcon = "data:image/svg+xml,custom-icon";
|
|
||||||
tab.zenStaticIcon = customIcon;
|
|
||||||
const restorePrompt = mockPrompt("https://example.org/edited");
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
"https://example.org/edited",
|
|
||||||
"The pinned URL should still be updated when a custom icon is set"
|
|
||||||
);
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.image,
|
|
||||||
customIcon,
|
|
||||||
"A user-set custom icon should be preserved, not overridden by a favicon"
|
|
||||||
);
|
|
||||||
Assert.equal(
|
|
||||||
favicons.mock.callCount,
|
|
||||||
0,
|
|
||||||
"Favicon lookup should be skipped when a custom icon is set"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
delete tab.zenStaticIcon;
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_InvalidUrlKeepsState() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const originalUrl = tab._zenPinnedInitialState.entry.url;
|
|
||||||
const restorePrompt = mockPrompt(" "); // whitespace only -> not a valid URL
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
originalUrl,
|
|
||||||
"The pinned URL should be unchanged for invalid input"
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
!tab.hasAttribute("zen-pinned-changed"),
|
|
||||||
"The tab should not be marked as changed for invalid input"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_CancelKeepsState() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const originalUrl = tab._zenPinnedInitialState.entry.url;
|
|
||||||
const restorePrompt = mockPrompt(null); // user cancels the dialog
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
originalUrl,
|
|
||||||
"The pinned URL should be unchanged when the dialog is cancelled"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_FixesSchemeTypo() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const restorePrompt = mockPrompt("htps://example.org/typo");
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
tab._zenPinnedInitialState.entry.url,
|
|
||||||
"https://example.org/typo",
|
|
||||||
"A mistyped scheme (htps://) should be auto-fixed to https://"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_AddsMissingScheme() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
const restorePrompt = mockPrompt("example.org/no-scheme");
|
|
||||||
const favicons = mockFavicons("data:image/png;base64,iVBORw0KGgo=");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
const stored = tab._zenPinnedInitialState.entry.url;
|
|
||||||
ok(
|
|
||||||
/^https?:\/\//.test(stored),
|
|
||||||
`A scheme should be prepended when omitted (got "${stored}")`
|
|
||||||
);
|
|
||||||
ok(
|
|
||||||
stored.endsWith("example.org/no-scheme"),
|
|
||||||
`Host and path should be preserved (got "${stored}")`
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
restorePrompt();
|
|
||||||
favicons.restore();
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_EditPinnedUrl_PrefillsWithStoredUrl() {
|
|
||||||
const tab = await pinTab("https://example.com/1");
|
|
||||||
// The stored pinned URL differs from the live browser URL (e.g. it was pinned
|
|
||||||
// as http but the server redirected the tab to https).
|
|
||||||
tab._zenPinnedInitialState = {
|
|
||||||
entry: { url: "http://example.com/pinned" },
|
|
||||||
image: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
let prefilled;
|
|
||||||
const originalPrompt = Services.prompt;
|
|
||||||
Services.prompt = {
|
|
||||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptService]),
|
|
||||||
prompt(win, title, label, result) {
|
|
||||||
prefilled = result.value;
|
|
||||||
return false; // cancel, we only care about the prefilled value
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await gZenPinnedTabManager.editPinnedUrl(tab);
|
|
||||||
|
|
||||||
Assert.equal(
|
|
||||||
prefilled,
|
|
||||||
"http://example.com/pinned",
|
|
||||||
"The edit dialog should prefill with the stored pinned URL, not the live browser URL"
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
Services.prompt = originalPrompt;
|
|
||||||
await BrowserTestUtils.removeTab(tab);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
"binaryName": "zen",
|
"binaryName": "zen",
|
||||||
"version": {
|
"version": {
|
||||||
"product": "firefox",
|
"product": "firefox",
|
||||||
"version": "152.0.3",
|
"version": "152.0.1",
|
||||||
"candidate": "152.0.3",
|
"candidate": "152.0.1",
|
||||||
"candidateBuild": 1
|
"candidateBuild": 1
|
||||||
},
|
},
|
||||||
"buildOptions": {
|
"buildOptions": {
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"brandShortName": "Zen",
|
"brandShortName": "Zen",
|
||||||
"brandFullName": "Zen Browser",
|
"brandFullName": "Zen Browser",
|
||||||
"release": {
|
"release": {
|
||||||
"displayVersion": "1.21.4b",
|
"displayVersion": "1.21.3b",
|
||||||
"github": {
|
"github": {
|
||||||
"repo": "zen-browser/desktop"
|
"repo": "zen-browser/desktop"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user