gh-15177: Improve on-boarding experience and new space form UX (gh-15178)

This commit is contained in:
mr. m
2026-08-31 02:52:10 +02:00
committed by GitHub
parent e89bd7796e
commit 67b6daaa0e
24 changed files with 1367 additions and 1115 deletions

View File

@@ -5,29 +5,28 @@
zen-welcome-title-line1 = Welcome to
zen-welcome-title-line2 = a calmer internet
zen-welcome-import-title = A Fresh Start, Same Bookmarks
zen-welcome-import-description-1 = Your bookmarks, history, and passwords are like a trail of breadcrumbs through the internet—dont leave them behind!
zen-welcome-import-description-2 = Easily bring them over from another browser and pick up right where you left off.
zen-welcome-import-button = Import now
zen-welcome-back = Back
zen-welcome-skip = Skip for now
zen-welcome-set-default-browser = Set { -brand-short-name } as your default browser
zen-welcome-dont-set-default-browser = DONT set { -brand-short-name } as your default browser
zen-welcome-import-title = Bring your stuff along.
zen-welcome-import-description = Import your bookmarks, history and passwords from another browser and pick up right where you left off.
zen-welcome-import-yes = <strong>YES</strong>, import from another browser.
zen-welcome-import-no = <strong>NO</strong>, start fresh.
zen-welcome-initial-essentials-title = Your Key Tabs, Always Within Reach
zen-welcome-initial-essentials-description-1 = Keep your most important tabs easily accessible and always at hand, no matter how many you open.
zen-welcome-initial-essentials-description-2 = Essential tabs are always visible, no matter what workspace you are in.
zen-welcome-default-browser-title = Make { -brand-short-name } your default?
zen-welcome-default-browser-description = Links from other apps will open in { -brand-short-name }. You can always change this later.
zen-welcome-set-default-browser = <strong>YES</strong>, make { -brand-short-name } default.
zen-welcome-dont-set-default-browser = <strong>NO</strong>, still exploring my options.
zen-welcome-workspace-colors-title = Your Workspaces, Your Colors
zen-welcome-workspace-colors-description = Personalize your browser by giving each workspace its own unique color identity.
zen-welcome-start-browsing-title = All set?<br/>
Lets get rolling!
zen-welcome-start-browsing-description-1 = Youre all set up and ready to go. Click the button below to start browsing with { -brand-short-name }.
zen-welcome-start-browsing = Dive in!
zen-welcome-default-search-title = Your Default Search Engine
zen-welcome-default-search-title = Pick your search engine.
zen-welcome-default-search-description = Choose your default search engine. You can always change it later!
zen-welcome-skip-button = Skip
zen-welcome-essentials-title = Choose the apps you use most.
zen-welcome-essentials-description = Select your favorite apps to keep them handy in your sidebar.
zen-welcome-finished = Your Zen has been set up correctly!
zen-welcome-workspace-colors-title = Your space, your colors.
zen-welcome-workspace-colors-description = Personalize your browser by giving each space its own unique color identity.
zen-welcome-start-browsing-title = All set? Lets get rolling!
zen-welcome-start-browsing-description-1 = Youre all set up and ready to go. Click the button below to start browsing with { -brand-short-name }.
zen-welcome-start-browsing = Dive in!

View File

@@ -14,14 +14,14 @@
<panelview id="PanelUI-zen-gradient-generator-view" class="PanelUI-subView zen-theme-picker" role="document" mainview-with-header="true" has-custom-header="true">
<hbox class="zen-theme-picker-gradient">
<hbox id="PanelUI-zen-gradient-generator-scheme">
<button id="PanelUI-zen-gradient-generator-scheme-auto" class="subviewbutton"/>
<button id="PanelUI-zen-gradient-generator-scheme-light" class="subviewbutton"/>
<button id="PanelUI-zen-gradient-generator-scheme-dark" class="subviewbutton"/>
<button id="PanelUI-zen-gradient-generator-scheme-auto" class="no-squircles subviewbutton"/>
<button id="PanelUI-zen-gradient-generator-scheme-light" class="no-squircles subviewbutton"/>
<button id="PanelUI-zen-gradient-generator-scheme-dark" class="no-squircles subviewbutton"/>
</hbox>
<hbox id="PanelUI-zen-gradient-generator-color-actions">
<button id="PanelUI-zen-gradient-generator-color-add" class="subviewbutton" />
<button id="PanelUI-zen-gradient-generator-color-remove" class="subviewbutton" />
<button id="PanelUI-zen-gradient-generator-color-toggle-algo" class="subviewbutton" />
<button id="PanelUI-zen-gradient-generator-color-add" class="no-squircles subviewbutton" />
<button id="PanelUI-zen-gradient-generator-color-remove" class="no-squircles subviewbutton" />
<button id="PanelUI-zen-gradient-generator-color-toggle-algo" class="no-squircles subviewbutton" />
</hbox>
<label data-l10n-id="zen-panel-ui-gradient-click-to-add" id="PanelUI-zen-gradient-generator-color-click-to-add"></label>
</hbox>
@@ -29,82 +29,82 @@
<toolbarbutton id="PanelUI-zen-gradient-generator-color-page-left" class="toolbarbutton-1" disabled="true" />
<hbox id="PanelUI-zen-gradient-generator-color-pages">
<hbox>
<box data-lightness="90" data-algo="float" data-num-dots="1" data-position="240,240" style="background: #f4efdf;"></box>
<box data-lightness="80" data-algo="float" data-num-dots="1" data-position="233,157" style="background: #f0b8cd;"></box>
<box data-lightness="80" data-algo="float" data-num-dots="1" data-position="236,111" style="background: #e9c3e3;"></box>
<box data-lightness="70" data-algo="float" data-num-dots="1" data-position="234,173" style="background: #da7682;"></box>
<box data-lightness="70" data-algo="float" data-num-dots="1" data-position="220,187" style="background: #eb8570;"></box>
<box data-lightness="60" data-algo="float" data-num-dots="1" data-position="225,237" style="background: #dcce7f;"></box>
<box data-lightness="60" data-algo="float" data-num-dots="1" data-position="147,195" style="background: #5becad;"></box>
<box data-lightness="50" data-algo="float" data-num-dots="1" data-position="81,84" style="background: #919bb5;"></box>
<box class="no-squircles" data-lightness="90" data-algo="float" data-num-dots="1" data-position="240,240" style="background: #f4efdf;"></box>
<box class="no-squircles" data-lightness="80" data-algo="float" data-num-dots="1" data-position="233,157" style="background: #f0b8cd;"></box>
<box class="no-squircles" data-lightness="80" data-algo="float" data-num-dots="1" data-position="236,111" style="background: #e9c3e3;"></box>
<box class="no-squircles" data-lightness="70" data-algo="float" data-num-dots="1" data-position="234,173" style="background: #da7682;"></box>
<box class="no-squircles" data-lightness="70" data-algo="float" data-num-dots="1" data-position="220,187" style="background: #eb8570;"></box>
<box class="no-squircles" data-lightness="60" data-algo="float" data-num-dots="1" data-position="225,237" style="background: #dcce7f;"></box>
<box class="no-squircles" data-lightness="60" data-algo="float" data-num-dots="1" data-position="147,195" style="background: #5becad;"></box>
<box class="no-squircles" data-lightness="50" data-algo="float" data-num-dots="1" data-position="81,84" style="background: #919bb5;"></box>
</hbox>
<hbox>
<box data-lightness="90" data-algo="analogous" data-num-dots="3" data-position="240,240"
<box class="no-squircles" data-lightness="90" data-algo="analogous" data-num-dots="3" data-position="240,240"
style="--c1: rgb(245, 237, 214); --c2: rgb(221, 243, 216); --c3: rgb(243, 216, 225);" />
<box data-lightness="85" data-algo="analogous" data-num-dots="3" data-position="233,157"
<box class="no-squircles" data-lightness="85" data-algo="analogous" data-num-dots="3" data-position="233,157"
style="--c1: rgb(243, 190, 222); --c2: rgb(247, 222, 186); --c3: rgb(223, 195, 238);" />
<box data-lightness="80" data-algo="analogous" data-num-dots="3" data-position="236,111"
<box class="no-squircles" data-lightness="80" data-algo="analogous" data-num-dots="3" data-position="236,111"
style="--c1: rgb(229, 179, 228); --c2: rgb(236, 172, 178); --c3: rgb(197, 185, 223);" />
<box data-lightness="70" data-algo="analogous" data-num-dots="3" data-position="234,173"
<box class="no-squircles" data-lightness="70" data-algo="analogous" data-num-dots="3" data-position="234,173"
style="--c1: rgb(235, 122, 159); --c2: rgb(239, 239, 118); --c3: rgb(210, 133, 224);" />
<box data-lightness="70" data-algo="analogous" data-num-dots="3" data-position="220,187"
<box class="no-squircles" data-lightness="70" data-algo="analogous" data-num-dots="3" data-position="220,187"
style="--c1: rgb(242, 115, 123); --c2: rgb(175, 242, 115); --c3: rgb(230, 125, 232);" />
<box data-lightness="60" data-algo="analogous" data-num-dots="3" data-position="225,237"
<box class="no-squircles" data-lightness="60" data-algo="analogous" data-num-dots="3" data-position="225,237"
style="--c1: rgb(221, 205, 85); --c2: rgb(97, 212, 94); --c3: rgb(215, 91, 124);" />
<box data-lightness="60" data-algo="analogous" data-num-dots="3" data-position="147,195"
<box class="no-squircles" data-lightness="60" data-algo="analogous" data-num-dots="3" data-position="147,195"
style="--c1: rgb(75, 231, 210); --c2: rgb(84, 175, 222); --c3: rgb(62, 244, 112);" />
<box data-lightness="55" data-algo="analogous" data-num-dots="3" data-position="81,84"
<box class="no-squircles" data-lightness="55" data-algo="analogous" data-num-dots="3" data-position="81,84"
style="--c1: rgb(122, 132, 158); --c2: rgb(137, 117, 164); --c3: rgb(116, 162, 164);" />
</hbox>
<hbox>
<box data-lightness="10" data-algo="float" data-num-dots="1" data-position="171,72" style="background:rgb(93, 86, 106);"></box>
<box data-lightness="40" data-algo="float" data-num-dots="1" data-position="265,79" style="background: #997096;"></box>
<box data-lightness="35" data-algo="float" data-num-dots="1" data-position="301,176" style="background: #956066;"></box>
<box data-lightness="30" data-algo="float" data-num-dots="1" data-position="237,210" style="background: #9c6645;"></box>
<box data-lightness="30" data-algo="float" data-num-dots="1" data-position="91,228" style="background: #517b6c;"></box>
<box data-lightness="25" data-algo="float" data-num-dots="1" data-position="67,159" style="background: #576e75;"></box>
<box data-lightness="20" data-algo="float" data-num-dots="1" data-position="314,235" style="background:rgb(131, 109, 95);"></box>
<box data-lightness="20" data-algo="float" data-num-dots="1" data-position="118,215" style="background: #447464;"></box>
<box class="no-squircles" data-lightness="10" data-algo="float" data-num-dots="1" data-position="171,72" style="background:rgb(93, 86, 106);"></box>
<box class="no-squircles" data-lightness="40" data-algo="float" data-num-dots="1" data-position="265,79" style="background: #997096;"></box>
<box class="no-squircles" data-lightness="35" data-algo="float" data-num-dots="1" data-position="301,176" style="background: #956066;"></box>
<box class="no-squircles" data-lightness="30" data-algo="float" data-num-dots="1" data-position="237,210" style="background: #9c6645;"></box>
<box class="no-squircles" data-lightness="30" data-algo="float" data-num-dots="1" data-position="91,228" style="background: #517b6c;"></box>
<box class="no-squircles" data-lightness="25" data-algo="float" data-num-dots="1" data-position="67,159" style="background: #576e75;"></box>
<box class="no-squircles" data-lightness="20" data-algo="float" data-num-dots="1" data-position="314,235" style="background:rgb(131, 109, 95);"></box>
<box class="no-squircles" data-lightness="20" data-algo="float" data-num-dots="1" data-position="118,215" style="background: #447464;"></box>
</hbox>
<hbox>
<box data-lightness="10" data-algo="analogous" data-num-dots="3" data-position="171,72"
<box class="no-squircles" data-lightness="10" data-algo="analogous" data-num-dots="3" data-position="171,72"
style="--c1: rgb(23, 17, 34); --c2: rgb(37, 14, 35); --c3: rgb(18, 22, 33);" />
<box data-lightness="40" data-algo="analogous" data-num-dots="3" data-position="265,79"
<box class="no-squircles" data-lightness="40" data-algo="analogous" data-num-dots="3" data-position="265,79"
style="--c1: rgb(128, 76, 124); --c2: rgb(141, 63, 66); --c3: rgb(97, 88, 116);" />
<box data-lightness="35" data-algo="analogous" data-num-dots="3" data-position="301,176"
<box class="no-squircles" data-lightness="35" data-algo="analogous" data-num-dots="3" data-position="301,176"
style="--c1: rgb(122, 56, 64); --c2: rgb(126, 121, 52); --c3: rgb(111, 68, 110);" />
<box data-lightness="30" data-algo="analogous" data-num-dots="3" data-position="237,210"
<box class="no-squircles" data-lightness="30" data-algo="analogous" data-num-dots="3" data-position="237,210"
style="--c1: rgb(131, 65, 22); --c2: rgb(64, 128, 25); --c3: rgb(122, 31, 91);" />
<box data-lightness="30" data-algo="analogous" data-num-dots="3" data-position="91,228"
<box class="no-squircles" data-lightness="30" data-algo="analogous" data-num-dots="3" data-position="91,228"
style="--c1: rgb(45, 108, 85); --c2: rgb(52, 85, 101); --c3: rgb(52, 118, 35);" />
<box data-lightness="25" data-algo="analogous" data-num-dots="3" data-position="67,159"
<box class="no-squircles" data-lightness="25" data-algo="analogous" data-num-dots="3" data-position="67,159"
style="--c1: rgb(45, 74, 83); --c2: rgb(46, 50, 81); --c3: rgb(38, 90, 65);" />
<box data-lightness="20" data-algo="analogous" data-num-dots="3" data-position="314,235"
<box class="no-squircles" data-lightness="20" data-algo="analogous" data-num-dots="3" data-position="314,235"
style="--c1: rgb(64, 47, 38); --c2: rgb(55, 64, 38); --c3: rgb(59, 43, 52);" />
<box data-lightness="20" data-algo="analogous" data-num-dots="3" data-position="118,215"
<box class="no-squircles" data-lightness="20" data-algo="analogous" data-num-dots="3" data-position="118,215"
style="--c1: rgb(22, 80, 61); --c2: rgb(26, 60, 76); --c3: rgb(27, 87, 15);" />
</hbox>
<hbox>
# Start from black to white in a span on 8 steps and.
# They must all go from the middle to the right side. They must always stay verically centered.
# And reach to 180 on the right side, meaning we must divide the width in 16 segments.
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="340,180" style="background: rgb(224, 224, 224);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="337.5,180" style="background: rgb(224, 224, 224);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="315,180" style="background: rgb(192, 192, 192);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="292.5,180" style="background: rgb(160, 160, 160);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="270,180" style="background: rgb(128, 128, 128);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="247.5,180" style="background: rgb(96, 96, 96);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="225,180" style="background: rgb(64, 64, 64);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="202.5,180" style="background: rgb(32, 32, 32);"></box>
<box data-type="explicit-black-white" data-algo="float" data-num-dots="1"
<box class="no-squircles" data-type="explicit-black-white" data-algo="float" data-num-dots="1"
data-position="180,180" style="background: rgb(0, 0, 0);"></box>
</hbox>
</hbox>

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js
index a76699af75252bec31e17b562463c37236cbbfe5..6355a6ee92754846ffcdd123ac49545d520470c7 100644
index 94612d8e28af58fcb04914440348b899a0a1e08f..da3b1ffd09745d09589283356d1001dbfb76a468 100644
--- a/browser/components/preferences/preferences.js
+++ b/browser/components/preferences/preferences.js
@@ -132,6 +132,7 @@ ChromeUtils.defineLazyGetter(this, "gSubDialog", function () {
@@ -10,7 +10,7 @@ index a76699af75252bec31e17b562463c37236cbbfe5..6355a6ee92754846ffcdd123ac49545d
],
resizeCallback: async ({ title, frame }) => {
// Search within main document and highlight matched keyword.
@@ -462,6 +463,8 @@ const CONFIG_PANES = Object.freeze({
@@ -471,6 +472,8 @@ const CONFIG_PANES = Object.freeze({
tabsBrowsing: {
l10nId: "tabs-browsing-section",
groupIds: [
@@ -19,7 +19,7 @@ index a76699af75252bec31e17b562463c37236cbbfe5..6355a6ee92754846ffcdd123ac49545d
"browserLayout",
"tabs",
"pageNavigation",
@@ -509,7 +512,7 @@ function register_module(categoryName, categoryObject) {
@@ -518,7 +521,7 @@ function register_module(categoryName, categoryObject) {
}
this._initted = true;
let template = document.getElementById("template-" + categoryName);
@@ -28,7 +28,7 @@ index a76699af75252bec31e17b562463c37236cbbfe5..6355a6ee92754846ffcdd123ac49545d
// Replace the template element with the nodes inside of it.
template.replaceWith(template.content);
@@ -553,6 +556,10 @@ function init_all() {
@@ -562,6 +565,10 @@ function init_all() {
register_module("paneHome", gHomePane);
register_module("paneSearch", gSearchPane);
register_module("panePrivacy", gPrivacyPane);

View File

@@ -1,9 +1,18 @@
diff --git a/browser/installer/windows/nsis/uninstaller.nsi b/browser/installer/windows/nsis/uninstaller.nsi
old mode 100755
new mode 100644
index becbb0f70c84eb7f2d9bff5a3aedcbb7a78a61cf..05835d2088ab631316a25a9f0728898bd7998d8d
index becbb0f70c84eb7f2d9bff5a3aedcbb7a78a61cf..a23a8a1b160932368377fc841b501df9355918db
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -150,7 +150,7 @@ OutFile "helper.exe"
!endif
ShowUnInstDetails nevershow
-!define URLUninstallSurvey "https://qsurvey.mozilla.com/s3/FF-Desktop-Post-Uninstall?channel=${UpdateChannel}&version=${AppVersion}&osversion="
+!define URLUninstallSurvey "https://links.zen-browser.app/uninstall-feedback?osversion="
; Support for the profile refresh feature
!define URLProfileRefreshHelp "https://support.mozilla.org/kb/refresh-firefox-reset-add-ons-and-settings"
@@ -516,6 +516,7 @@ Section "Uninstall"
${un.RegCleanFileHandler} ".svg" "FirefoxHTML-$AppUserModelID"
${un.RegCleanFileHandler} ".webp" "FirefoxHTML-$AppUserModelID"

View File

@@ -812,7 +812,8 @@
#toolbar-context-toggle-vertical-tabs,
#toolbar-context-customize-sidebar,
#sidebarRevampSeparator {
#sidebarRevampSeparator,
.fxa-menu-sign-in-promo-image {
display: none !important;
}

View File

@@ -543,6 +543,10 @@ window.gZenUIManager = {
return false;
}
if (document.documentElement.hasAttribute("zen-welcome-stage")) {
return false;
}
const shouldOpenURLBar =
overridePreferance ||
(gZenVerticalTabsManager._canReplaceNewTab &&
@@ -1282,7 +1286,7 @@ window.gZenVerticalTabsManager = {
if (!this._hasSetSingleToolbar) {
height = AppConstants.platform == "macosx" ? 34 : 32;
} else if (!gURLBar.hasAttribute("breakout-extend")) {
height = 36;
height = 38;
}
if (typeof height !== "undefined") {
gURLBar.style.setProperty("--urlbar-height", `${height}px`);

View File

@@ -136,6 +136,11 @@
& #identity-box {
margin-inline-end: 0 !important;
&[pageproxystate="invalid"] {
margin-inline-end: -4px !important;
}
&.chromeUI:not([pageproxystate="invalid"]) #identity-icon-box {
border-radius: 10px !important;
}

View File

@@ -286,7 +286,7 @@
* 1. If the native radius - the separation is less than 4px, use 4px.
* 2. Otherwise, use the the calculated value (inner radius = outer radius - separation).
*/
max(5px, calc(var(--zen-border-radius) - var(--zen-element-separation) / 2))
max(5px, calc((var(--zen-border-radius) - var(--zen-element-separation) / 2) * var(--zen-squircle-value)))
);
/** Other theme-related styles */

View File

@@ -109,7 +109,7 @@
if (AppConstants.platform == "macosx") {
const targetRadius = window.matchMedia("(-moz-mac-tahoe-theme)")
.matches
? 14
? 12
: 10;
document.documentElement.style.setProperty(
"--zen-border-radius",

View File

@@ -3,8 +3,7 @@
- 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/.
-->
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="192" height="192">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
<path d="M0 0 C46.53 0 93.06 0 141 0 C140.31337286 6.17964422 139.55249061 11.27288504 137.70605469 17.05029297 C137.47297387 17.80257864 137.23989305 18.55486431 136.99974918 19.32994652 C136.23144234 21.80315256 135.45168558 24.27258703 134.671875 26.7421875 C134.12437759 28.49738282 133.57765617 30.25282037 133.03166199 32.00848389 C131.87637142 35.71831589 130.71622139 39.42657597 129.55197144 43.13360596 C127.74764855 48.8788063 125.95370897 54.62720979 124.16235352 60.37646484 C123.86778165 61.32180147 123.57320978 62.2671381 123.26971149 63.24112129 C122.67820023 65.13942545 122.08671887 67.03773892 121.49526787 68.93606186 C120.61596105 71.75702774 119.73559404 74.57766091 118.85499573 77.39822388 C113.93371601 93.16794093 109.12231506 108.96839561 104.39160156 124.79638672 C104.15798416 125.57612854 103.92436676 126.35587036 103.68367004 127.15924072 C103.08515835 129.15844483 102.48956633 131.15852242 101.89428711 133.15869141 C101 136 101 136 100 138 C53.47 138 6.94 138 -41 138 C-40.30154873 133.1108411 -39.57595592 129.15411541 -38.15258789 124.53222656 C-37.57916405 122.65642914 -37.57916405 122.65642914 -36.99415588 120.74273682 C-36.57039663 119.37534329 -36.14656076 118.0079735 -35.72265625 116.640625 C-35.27348999 115.1778587 -34.82480765 113.71494372 -34.37657166 112.25189209 C-33.18301778 108.36047716 -31.98331296 104.47098593 -30.78216553 100.58190918 C-29.63602455 96.86810525 -28.49491032 93.15276556 -27.35351562 89.4375 C-24.23585848 79.29161092 -21.11791678 69.14580929 -18 59 C-12.06 39.53 -6.12 20.06 0 0 Z " fill="#C00002" transform="translate(51,54)"/>
<path d="M0 0 C18.3328319 -0.77792059 36.66127963 -1.35606988 55.00715542 -1.70980167 C63.53040721 -1.87858134 72.04320263 -2.10845198 80.55981445 -2.48950195 C142.46067644 -5.20608208 142.46067644 -5.20608208 159.53827381 9.52021503 C166.76889916 16.3955246 173.28323862 24.18336817 178 33 C178 34.32 178 35.64 178 37 C159.57187597 37.07007601 141.14378652 37.12298126 122.71555805 37.15543652 C114.15904092 37.17090649 105.60260658 37.19199848 97.04614258 37.22631836 C89.58846853 37.25621675 82.13085443 37.27557406 74.67312211 37.28226548 C70.72416302 37.28617701 66.77537545 37.29537225 62.82647133 37.31719017 C59.10909816 37.33756234 55.39196707 37.34383237 51.67454338 37.33932304 C49.66086617 37.34054104 47.64721527 37.35667936 45.63360596 37.3732605 C44.43192276 37.36913651 43.23023956 37.36501251 41.99214172 37.36076355 C40.42831993 37.36491162 40.42831993 37.36491162 38.83290577 37.36914349 C32.93264951 36.60030705 29.62184448 32.77709579 25.875 28.5 C19.58131594 21.47164064 12.89888852 14.86095567 6.14794922 8.2734375 C5.35146973 7.48839844 4.55499023 6.70335937 3.734375 5.89453125 C3.01475586 5.19175049 2.29513672 4.48896973 1.55371094 3.76489258 C0 2 0 2 0 0 Z " fill="#C00002" transform="translate(14,0)"/>
<path d="M0 0 C3.791582 0.9478955 4.61038031 1.2276371 7.22387695 3.72460938 C7.82742508 4.29610718 8.43097321 4.86760498 9.05281067 5.4564209 C9.69151596 6.0792395 10.33022125 6.70205811 10.98828125 7.34375 C11.65087448 7.98687134 12.31346771 8.62999268 12.99613953 9.29260254 C14.39307302 10.6568359 15.78562095 12.02557232 17.17407227 13.3984375 C19.30020941 15.4879213 21.45839054 17.54016287 23.61914062 19.59375 C24.97349069 20.92491308 26.32577572 22.25818109 27.67578125 23.59375 C28.64902092 24.50368713 28.64902092 24.50368713 29.641922 25.43200684 C32.90021798 28.73979232 33.96335392 30.20963715 34.18457031 34.98071289 C32.79621492 42.01530122 30.50352034 48.87563397 28.37109375 55.71484375 C27.89774106 57.25373642 27.42510459 58.79284955 26.95314026 60.33216858 C25.70895014 64.38330864 24.4551733 68.43141814 23.19927979 72.47894287 C21.95200374 76.50438366 20.71357304 80.53254149 19.47460938 84.56054688 C18.02569311 89.27038853 16.5746843 93.97953307 15.11288452 98.68539429 C12.90227206 105.80473144 10.71371664 112.92808223 8.60595703 120.07861328 C8.0605703 121.91064049 8.0605703 121.91064049 7.50416565 123.77967834 C6.83459768 126.03485094 6.17462453 128.29290282 5.52598572 130.55418396 C5.23389725 131.5321846 4.94180878 132.51018524 4.64086914 133.51782227 C4.39422012 134.36594986 4.14757111 135.21407745 3.89344788 136.08790588 C3.59861008 136.71889694 3.30377228 137.349888 3 138 C2.01 138.33 1.02 138.66 0 139 C0 93.13 0 47.26 0 0 Z " fill="#C00002" transform="translate(0,15)"/>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -26,7 +26,8 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
const hasAnyFilterEnabled =
(this.state.options.authorMe ?? false) ||
(this.state.options.assignedMe ?? true) ||
(this.state.options.reviewRequested ?? false);
(this.state.options.reviewRequested ?? false) ||
(this.state.options.includeDrafts ?? true);
if (!hasAnyFilterEnabled) {
return "zen-live-folder-github-no-filter";

View File

@@ -353,7 +353,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
// Add elements in a circular pattern, where the center is the center of the wrapper
for (let i = 0; i < 16; i++) {
const dot = document.createElement("div");
dot.classList.add("zen-theme-picker-texture-dot");
dot.classList.add("zen-theme-picker-texture-dot", "no-squircles");
const position = (i / 16) * Math.PI * 2 + wrapperWidth;
dot.style.left = `${Math.cos(position) * 50 + 50}%`;
dot.style.top = `${Math.sin(position) * 50 + 50}%`;
@@ -361,6 +361,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
}
this._textureHandler = document.createElement("div");
this._textureHandler.id = "PanelUI-zen-gradient-generator-texture-handler";
this._textureHandler.classList.add("no-squircles");
this._textureHandler.addEventListener(
"mousedown",
this.onTextureHandlerMouseDown.bind(this)
@@ -598,7 +599,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
color.position || this.calculateInitialPosition([r, g, b]);
const dotPad = this.panel.querySelector(".zen-theme-picker-gradient");
dot.classList.add("zen-theme-picker-dot");
dot.classList.add("zen-theme-picker-dot", "no-squircles");
dot.style.left = `${x}px`;
dot.style.top = `${y}px`;

View File

@@ -10,6 +10,7 @@ ChromeUtils.defineLazyGetter(lazy, "l10n", () => {
class nsZenWorkspaceCreation extends MozXULElement {
#wasInCollapsedMode = false;
#urlbarDimmed = false;
promiseInitialized = new Promise(resolve => {
this.resolveInitialized = resolve;
@@ -77,16 +78,56 @@ class nsZenWorkspaceCreation extends MozXULElement {
return this.getAttribute("previous-workspace-id");
}
get elementsToAnimate() {
return [
this.querySelector(".zen-workspace-creation-title"),
this.querySelector(".zen-workspace-creation-label").parentElement,
this.querySelector(".zen-workspace-creation-name-wrapper"),
this.querySelector(".zen-workspace-creation-profile-wrapper"),
this.querySelector(".zen-workspace-creation-edit-theme-button"),
this.createButton.parentNode,
this.cancelButton,
];
get #spaceSwitchDuration() {
return (
Services.prefs.getIntPref("zen.workspaces.switch-animation-duration") /
1000
);
}
#dimUrlbar() {
if (this.#urlbarDimmed || !gZenVerticalTabsManager._hasSetSingleToolbar) {
return;
}
this.#urlbarDimmed = true;
const animation = gZenUIManager.motion.animate(
gURLBar,
{
opacity: [1, 0],
},
{
duration: this.#spaceSwitchDuration,
type: "spring",
bounce: 0,
}
);
if (gReduceMotion) {
animation.complete();
}
}
#restoreUrlbar() {
if (!this.#urlbarDimmed) {
return;
}
this.#urlbarDimmed = false;
const animation = gZenUIManager.motion.animate(
gURLBar,
{
opacity: [0, 1],
},
{
duration: this.#spaceSwitchDuration,
type: "spring",
bounce: 0,
}
);
if (gReduceMotion) {
animation.complete();
}
animation.then(() => {
gURLBar.style.removeProperty("opacity");
});
}
connectedCallback() {
@@ -109,10 +150,6 @@ class nsZenWorkspaceCreation extends MozXULElement {
".zen-workspace-creation-cancel-button"
);
for (const element of this.elementsToAnimate) {
element.style.opacity = 0;
}
this.#wasInCollapsedMode =
document.documentElement.getAttribute("zen-sidebar-expanded") !== "true";
@@ -128,7 +165,7 @@ class nsZenWorkspaceCreation extends MozXULElement {
this.handleZenWorkspacesChange.bind(this);
for (const element of this.parentElement.children) {
if (element !== this) {
if (element !== this && !element.hidden) {
element.hidden = true;
this.#hiddenElements.push(element);
}
@@ -207,48 +244,15 @@ class nsZenWorkspaceCreation extends MozXULElement {
document.getElementById("zen-sidebar-splitter").style.pointerEvents =
"none";
gZenUIManager.motion
.animate(
[gBrowser.tabContainer, gURLBar],
{
opacity: [1, 0],
},
{
duration: 0.3,
type: "spring",
bounce: 0,
}
)
.then(() => {
gBrowser.tabContainer.style.visibility = "collapse";
if (gZenVerticalTabsManager._hasSetSingleToolbar) {
document.getElementById("nav-bar").style.visibility = "collapse";
}
this.style.visibility = "visible";
gZenCompactModeManager.getAndApplySidebarWidth({});
this.resolveInitialized();
let animation = gZenUIManager.motion.animate(
this.elementsToAnimate,
{
y: [20, 0],
opacity: [0, 1],
filter: ["blur(2px)", "blur(0)"],
},
{
duration: 0.6,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05, { startDelay: 0.2 }),
}
);
if (gReduceMotion) {
animation.complete();
}
animation.then(() => {
this.inputName.focus();
gZenWorkspaces.workspaceElement(this.workspaceId).hidden = false;
});
});
gZenCompactModeManager.getAndApplySidebarWidth({});
this.#dimUrlbar();
this.resolveInitialized();
}
disconnectedCallback() {
if (gZenWorkspaces.creatingWorkspaceId === this.workspaceId) {
gZenWorkspaces.creatingWorkspaceId = null;
}
}
async onCreateButtonCommand() {
@@ -258,7 +262,7 @@ class nsZenWorkspaceCreation extends MozXULElement {
workspace.containerTabId = this.currentProfile;
await gZenWorkspaces.saveWorkspace(workspace);
await this.#cleanup();
this.#cleanup();
gZenWorkspaces._organizeWorkspaceStripLocations(workspace, true);
gZenWorkspaces.updateTabsContainers();
@@ -268,6 +272,7 @@ class nsZenWorkspaceCreation extends MozXULElement {
async onCancelButtonCommand() {
document.documentElement.removeAttribute("zen-creating-workspace");
this.#restoreUrlbar();
await gZenWorkspaces.changeWorkspaceWithID(this.previousWorkspaceId);
}
@@ -332,34 +337,18 @@ class nsZenWorkspaceCreation extends MozXULElement {
}
finishSetup() {
this.inputName.focus();
gZenWorkspaces.addChangeListeners(this.handleZenWorkspacesChangeBind, {
once: true,
});
}
async handleZenWorkspacesChange() {
this.#cleanup();
await gZenWorkspaces.removeWorkspace(this.workspaceId);
await this.#cleanup();
}
async #cleanup() {
if (!gReduceMotion) {
await gZenUIManager.motion.animate(
this.elementsToAnimate.reverse(),
{
y: [0, 20],
opacity: [1, 0],
filter: ["blur(0)", "blur(2px)"],
},
{
duration: 0.4,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05),
}
);
}
#cleanup() {
document.getElementById("zen-sidebar-splitter").style.pointerEvents = "";
gZenWorkspaces.removeChangeListeners(this.handleZenWorkspacesChangeBind);
@@ -377,41 +366,23 @@ class nsZenWorkspaceCreation extends MozXULElement {
document.documentElement.removeAttribute("zen-creating-workspace");
gBrowser.tabContainer.style.visibility = "";
gBrowser.tabContainer.style.opacity = 0;
if (gZenVerticalTabsManager._hasSetSingleToolbar) {
document.getElementById("nav-bar").style.visibility = "";
gURLBar.style.opacity = 0;
}
this.remove();
this.#restoreUrlbar();
const workspace = gZenWorkspaces.getActiveWorkspace();
gZenWorkspaces._organizeWorkspaceStripLocations(workspace);
gZenWorkspaces.updateTabsContainers();
await gZenUIManager.motion.animate(
[gBrowser.tabContainer, gURLBar],
{
opacity: [0, 1],
},
{
duration: 0.3,
type: "spring",
bounce: 0,
}
);
gBrowser.tabContainer.style.opacity = "";
if (gZenVerticalTabsManager._hasSetSingleToolbar) {
gURLBar.style.opacity = "";
}
for (const element of this.#hiddenElements) {
// Give the space back its own contents.
const revealedElements = this.#hiddenElements;
this.#hiddenElements = [];
for (const element of revealedElements) {
element.hidden = false;
}
this.#hiddenElements = [];
// Now that the form is gone the space owns its essentials again.
const workspace = gZenWorkspaces.getActiveWorkspace();
gZenWorkspaces._organizeWorkspaceStripLocations(workspace);
gZenWorkspaces.updateTabsContainers();
// The essentials slid away when we arrived, slide them back in.
gZenWorkspaces.restoreEssentialsPosition();
gZenUIManager.updateTabsToolbar();
}
}

View File

@@ -40,6 +40,13 @@ class nsZenWorkspaces {
#inChangingWorkspace = false;
draggedElement = null;
/**
* The space currently showing the creation form, if any. It shows the form
* instead of tabs and essentials, so it never owns an essentials section.
* Cleared by the form element once it is removed from the DOM.
*/
creatingWorkspaceId = null;
#hasInitialized = false;
#canDebug = Services.prefs.getBoolPref("zen.workspaces.debug", false);
@@ -345,10 +352,7 @@ class nsZenWorkspaces {
}
get shouldAnimateEssentials() {
return (
this.containerSpecificEssentials ||
document.documentElement.hasAttribute("zen-creating-workspace")
);
return this.containerSpecificEssentials || !!this.creatingWorkspaceId;
}
get activeWorkspaceElement() {
@@ -458,9 +462,6 @@ class nsZenWorkspaces {
workspaceWrapper.active = true;
}
if (document.documentElement.hasAttribute("zen-creating-workspace")) {
workspaceWrapper.hidden = true; // Hide workspace while creating it
}
container.appendChild(workspaceWrapper);
this.#organizeTabsToWorkspaceSections(workspace, workspaceWrapper, tabs);
workspaceWrapper.checkPinsExistence();
@@ -911,6 +912,9 @@ class nsZenWorkspaces {
// Wait for the next event loop to ensure that the startup focus logic by
// firefox has finished doing it's thing.
setTimeout(() => {
if (document.documentElement.hasAttribute("zen-welcome-stage")) {
return;
}
if (gZenVerticalTabsManager._canReplaceNewTab && shownEmptyTab) {
BrowserCommands.openTab();
} else if (shownEmptyTab || initialTabWasEmpty) {
@@ -1236,7 +1240,7 @@ class nsZenWorkspaces {
}
}
saveWorkspace(workspaceData) {
saveWorkspace(workspaceData, { insertAfterId = null } = {}) {
if (this.privateWindowOrDisabled) {
return;
}
@@ -1244,8 +1248,13 @@ class nsZenWorkspaces {
const index = workspacesData.findIndex(
ws => ws.uuid === workspaceData.uuid
);
const insertAfterIndex = insertAfterId
? workspacesData.findIndex(ws => ws.uuid === insertAfterId)
: -1;
if (index !== -1) {
workspacesData[index] = workspaceData;
} else if (insertAfterIndex !== -1) {
workspacesData.splice(insertAfterIndex + 1, 0, workspaceData);
} else {
workspacesData.push(workspaceData);
}
@@ -1426,6 +1435,7 @@ class nsZenWorkspaces {
const previousWorkspace = this.getActiveWorkspace();
document.documentElement.setAttribute("zen-creating-workspace", "true");
await this.createAndSaveWorkspace("Space", undefined, false, 0, {
insertAfterId: previousWorkspace?.uuid,
beforeChangeCallback: async workspace => {
createForm = document.createXULElement("zen-workspace-creation");
createForm.setAttribute("workspace-id", workspace.uuid);
@@ -1433,7 +1443,18 @@ class nsZenWorkspaces {
"previous-workspace-id",
previousWorkspace?.uuid || ""
);
gBrowser.tabContainer.after(createForm);
this.creatingWorkspaceId = workspace.uuid;
const spaceElement = this.workspaceElement(workspace.uuid);
// No essentials sit above the form, so there's no room to reserve for
// them. The switch animation needs a value to
// animate the padding from.
spaceElement.style.paddingTop = "0px";
spaceElement.appendChild(createForm);
// Keep the strip sitting on the previous space so that the new one,
// together with its creation form, slides in like any other space.
if (previousWorkspace) {
this._organizeWorkspaceStripLocations(previousWorkspace, true);
}
await createForm.promiseInitialized;
},
});
@@ -1803,10 +1824,6 @@ class nsZenWorkspaces {
justMove = false,
offsetPixels = 0
) {
if (document.documentElement.hasAttribute("zen-creating-workspace")) {
// If we are creating a workspace, we don't want to animate the strip
return;
}
this._organizingWorkspaceStrip = true;
const workspaces = this.getWorkspaces();
let workspaceIndex = workspaces.findIndex(w => w.uuid === workspace.uuid);
@@ -1827,6 +1844,7 @@ class nsZenWorkspaces {
}
const workspaceContextId = workspace.containerTabId;
const nextWorkspaceContextId = workspaces[nextSpaceIdx]?.containerTabId;
const isCreatingWorkspace = workspace.uuid === this.creatingWorkspaceId;
for (const otherWorkspace of workspaces) {
const element = this.workspaceElement(otherWorkspace.uuid);
let diff = workspaces.indexOf(otherWorkspace) - workspaceIndex;
@@ -1843,8 +1861,9 @@ class nsZenWorkspaces {
// Get the next workspace contextId, if it's the same, dont apply offsetPixels
// if it's not we do apply it
if (
container.getAttribute("container") != workspace.containerTabId &&
this.shouldAnimateEssentials
isCreatingWorkspace ||
(container.getAttribute("container") != workspace.containerTabId &&
this.shouldAnimateEssentials)
) {
container.setAttribute("hidden", "true");
} else {
@@ -1919,6 +1938,40 @@ class nsZenWorkspaces {
delete this._organizingWorkspaceStrip;
}
/**
* Slide the essentials back from wherever a creation form parked them.
*/
restoreEssentialsPosition() {
const duration =
Services.prefs.getIntPref("zen.workspaces.switch-animation-duration") /
1000;
for (const container of document.querySelectorAll(
"#zen-essentials .zen-essentials-container"
)) {
const existingTransform = container.style.transform;
const parkedOffset = parseFloat(existingTransform.split("(")[1]) || 0;
if (!parkedOffset || gReduceMotion) {
container.style.removeProperty("transform");
continue;
}
gZenUIManager.motion
.animate(
container,
{
transform: [existingTransform, "translateX(0%)"],
},
{
type: "spring",
bounce: 0,
duration,
}
)
.then(() => {
container.style.removeProperty("transform");
});
}
}
updateWorkspaceIndicator(currentWorkspace, workspaceIndicator) {
if (!workspaceIndicator) {
return;
@@ -1992,17 +2045,21 @@ class nsZenWorkspaces {
const isGoingLeft = diff < 0;
const essentialsAnimData = [];
if (shouldAnimate && this.shouldAnimateEssentials && previousWorkspace) {
const containerIds = new Map();
const creatingWorkspaceId = this.creatingWorkspaceId;
const essentialsElements = new Map();
for (const workspace of workspaces) {
const containerId = workspace.containerTabId;
if (!containerIds.has(containerId)) {
containerIds.set(containerId, []);
if (workspace.uuid === creatingWorkspaceId) {
continue;
}
containerIds.get(containerId).push(workspace);
const element = this.getEssentialsSection(workspace.containerTabId);
if (!essentialsElements.has(element)) {
essentialsElements.set(element, []);
}
essentialsElements.get(element).push(workspace);
}
for (const [containerId, spaces] of containerIds) {
for (const [element, spaces] of essentialsElements) {
essentialsAnimData.push({
element: this.getEssentialsSection(containerId),
element,
workspaces: spaces,
});
}
@@ -2143,6 +2200,7 @@ class nsZenWorkspaces {
existingOffset = currentTransform || (isGoingLeft ? -100 : 100);
newOffset = 0;
}
data.finalOffset = newOffset;
const newTransform = `translateX(${newOffset}%)`;
let existingTransform = `translateX(${existingOffset}%)`;
if (shouldAnimate) {
@@ -2181,6 +2239,12 @@ class nsZenWorkspaces {
document.documentElement.removeAttribute("animating-background");
if (shouldAnimate) {
for (const data of essentialsAnimData) {
if (this.creatingWorkspaceId && data.finalOffset) {
// The space being created has no essentials of its own, leave the
// ones we just slid away parked off screen instead of snapping them
// back under the creation form.
continue;
}
data.element.style.removeProperty("transform");
}
this._alwaysAnimatePaddingTop = true;
@@ -2527,7 +2591,9 @@ class nsZenWorkspaces {
icon = undefined,
dontChange = false,
containerTabId = 0,
{ beforeChangeCallback } = { beforeChangeCallback: null } // Callback to run before changing workspace
// beforeChangeCallback runs before changing workspace, insertAfterId places
// the new space right after an existing one instead of at the end.
{ beforeChangeCallback = null, insertAfterId = null } = {}
) {
if (!this.workspaceEnabled) {
return null;
@@ -2548,7 +2614,7 @@ class nsZenWorkspaces {
this.#createWorkspaceTabsSection(workspaceData, extraTabs);
this._organizeWorkspaceStripLocations(workspaceData);
}
this.saveWorkspace(workspaceData);
this.saveWorkspace(workspaceData, { insertAfterId });
if (!dontChange) {
if (beforeChangeCallback) {
try {
@@ -2670,6 +2736,11 @@ class nsZenWorkspaces {
workspacesIds.push(originalWorkspaceId);
}
for (const workspaceId of workspacesIds) {
if (workspaceId === this.creatingWorkspaceId) {
// The space being created shows the creation form instead of its
// essentials, so it doesn't reserve any room for them.
continue;
}
const workspaceElement = this.workspaceElement(workspaceId);
const workspaceObject = this.getWorkspaceFromId(workspaceId);
if (!workspaceElement || !workspaceObject) {

View File

@@ -6,9 +6,10 @@
zen-workspace-creation {
flex: 1;
max-width: calc(var(--zen-sidebar-width) - var(--zen-toolbox-padding));
padding: 3px;
visibility: collapse;
flex-direction: column;
min-height: 0;
width: 100%;
padding: 3px var(--zen-toolbox-padding);
& .zen-workspace-creation {
justify-content: center;

View File

@@ -324,7 +324,10 @@ zen-workspace {
overflow: hidden;
color: var(--toolbox-textcolor);
--tab-background-color-selected: color-mix(in srgb, light-dark(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.18)) 95%, var(--zen-primary-color)) !important;
--tab-background-color-selected: light-dark(
color-mix(in srgb, rgba(255, 255, 255, 0.8) 98%, var(--zen-primary-color)),
color-mix(in srgb, rgba(255, 255, 255, 0.18) 95%, var(--zen-primary-color))
) !important;
--tab-box-shadow-selected: 0 0.8px 1.5px 0px light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.05)) !important;
--tab-selected-textcolor: color-mix(in srgb, var(--toolbox-textcolor) 95%, var(--zen-primary-color)) !important;

View File

@@ -139,7 +139,7 @@ export class ZenSpacesSyncEngine extends SyncEngine {
}
get version() {
return 1;
return 3;
}
get syncPriority() {

View File

@@ -103,7 +103,7 @@
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
& #urlbar-container[breakout="true"]:has(#urlbar[zen-floating-urlbar="true"]) {
--urlbar-container-height: 36px !important;
--urlbar-height: 36px !important;
--urlbar-height: 38px !important;
}
& #nav-bar {
@@ -284,8 +284,12 @@
--focus-outline-color: transparent;
@media (-moz-platform: windows) {
font-size: 14px;
}
@media (-moz-platform: macos) {
font-size: 1.25rem; /* Slightly larger font on macOS */
font-size: 1.25rem;
}
--tab-inner-inline-margin: 0;
@@ -558,7 +562,7 @@
}
& #zen-essentials {
--tab-min-height: 44px;
--tab-min-height: 46px;
}
&[zen-right-side="true"] {
@@ -1149,8 +1153,7 @@
}
}
.tabbrowser-tab[zen-essential="true"],
#zen-welcome-initial-essentials-browser-sidebar-essentials .tabbrowser-tab {
.tabbrowser-tab[zen-essential="true"] {
--toolbarbutton-padding-inner: 0;
max-width: unset;
width: 100% !important;

View File

@@ -11,191 +11,195 @@ ChromeUtils.defineESModuleGetters(lazy, {
/* eslint-disable mozilla/no-arbitrary-setTimeout */
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function currentPageContent() {
return document.querySelector(
"#zen-welcome-page-content > .zen-welcome-page:not([exiting])"
);
}
add_task(async function test_Welcome_Steps() {
const selectedTab = gBrowser.selectedTab;
await new Promise(resolve => {
setTimeout(async () => {
await waitForFocus();
await EventUtils.synthesizeMouseAtCenter(
document.getElementById("zen-welcome-start-button"),
{}
);
setTimeout(() => {
resolve();
}, 4000); // Wait for the transition to complete
}, 2000); // Give tons of time for the welcome start button to be clicked
});
await wait(2000); // Give tons of time for the welcome start button to be clicked
await waitForFocus();
await EventUtils.synthesizeMouseAtCenter(
document.getElementById("zen-welcome-start-button"),
{}
);
await wait(1500); // Wait for the transition to complete
ok(true, "Welcome start button clicked successfully");
Assert.equal(
Assert.notEqual(
window.windowState,
window.STATE_MAXIMIZED,
"Window should be maximized after clicking the welcome start button"
"Window should not be maximized by the welcome screen"
);
const welcomeContent = document.getElementById("zen-welcome-page-content");
for (const button of document.querySelectorAll(
"#zen-welcome-page-sidebar-buttons button"
)) {
Assert.notStrictEqual(
getComputedStyle(button).pointerEvents,
"none",
`Button with l10n-id "${button.getAttribute("data-l10n-id")}" should be clickable`
);
}
await goNextWelcomePage("zen-welcome-skip-button");
ok(true, "Welcome Import Step Test Finished");
Assert.greater(
welcomeContent.children.length,
0,
"Welcome page content should have children after clicking next action"
const backButton = document.getElementById("zen-welcome-back");
ok(
backButton.hasAttribute("disabled"),
"Back button should be hidden on the first page"
);
Assert.equal(
currentPageContent().querySelectorAll(".zen-welcome-option").length,
2,
"Import page should offer two options"
);
for (const child of welcomeContent.children) {
ok(
child.querySelector("img").getAttribute("src").includes("blob:"),
"Welcome page content should have an image with a base64 data URL"
);
}
await EventUtils.synthesizeMouseAtCenter(welcomeContent.children[1], {});
await new Promise(resolve => {
setTimeout(async () => {
let engineName = await lazy.SearchService.getDefault();
const selectedLabel = welcomeContent.children[1];
ok(
selectedLabel.querySelector("input").checked,
"The selected label should be checked"
);
Assert.equal(
engineName.name,
selectedLabel.querySelector("label").textContent.trim(),
"The default search engine should match the selected label"
);
resolve();
}, 100); // Wait for the transition to complete
});
await goNextWelcomePage("zen-generic-next");
ok(true, "Welcome Search Step Test Finished");
ok(true, "Welcome Import Step Test Finished");
await new Promise(resolve => {
setTimeout(async () => {
const essentials = welcomeContent.querySelector(
"#zen-welcome-initial-essentials-browser-sidebar-essentials"
).children;
Assert.greater(
essentials.length,
3,
"Welcome page content should have more than 3 essentials after clicking next action"
);
await EventUtils.synthesizeMouseAtCenter(essentials[0], {});
await EventUtils.synthesizeMouseAtCenter(essentials[2], {});
ok(
essentials[0].hasAttribute("visuallyselected"),
"The first essential should be visually selected"
);
ok(
!essentials[1].hasAttribute("visuallyselected"),
"The second essential should be visually selected"
);
ok(
essentials[2].hasAttribute("visuallyselected"),
"The third essential should be visually selected"
);
const urlsToCheck = [
essentials[0].getAttribute("data-url"),
essentials[2].getAttribute("data-url"),
];
for (const url of urlsToCheck) {
ok(
url.startsWith("https://"),
`The URL "${url}" should start with "https://"`
);
}
await goNextWelcomePage("zen-generic-next");
await new Promise(r => {
setTimeout(async () => {
for (const url of urlsToCheck) {
ok(
await PlacesUtils.history.hasVisits(url),
`The URL "${url}" should have visits in history`
);
}
r();
}, 1000); // Wait for the transition to complete
});
resolve();
}, 1000); // Wait for the transition to complete
});
ok(
!backButton.hasAttribute("disabled"),
"Back button should be visible after the first page"
);
await EventUtils.synthesizeMouseAtCenter(backButton, {});
await wait(800);
ok(
backButton.hasAttribute("disabled"),
"Going back should return to the first page"
);
await goNextWelcomePage("zen-generic-next");
await goNextWelcomePage("zen-generic-next");
ok(true, "Welcome Theme Step Test Finished");
let options = currentPageContent().querySelectorAll(".zen-welcome-option");
Assert.greater(
options.length,
0,
"Search page should list the available engines"
);
for (const option of options) {
ok(
option.querySelector("img").getAttribute("src").includes("blob:"),
"Each engine option should have an image with a blob URL"
);
}
await EventUtils.synthesizeMouseAtCenter(options[1], {});
await wait(100);
let engineName = await lazy.SearchService.getDefault();
ok(
options[1].querySelector("input").checked,
"The selected option should be checked"
);
Assert.equal(
engineName.name,
options[1].querySelector(".zen-welcome-option-label").textContent.trim(),
"The default search engine should match the selected option"
);
await goNextWelcomePage("zen-generic-next");
ok(true, "Welcome Search Step Test Finished");
const essentials = currentPageContent().querySelectorAll(
"#zen-welcome-essentials .zen-welcome-essential"
);
Assert.greater(
essentials.length,
3,
"Welcome page content should have more than 3 essentials"
);
await EventUtils.synthesizeMouseAtCenter(essentials[0], {});
await EventUtils.synthesizeMouseAtCenter(essentials[2], {});
ok(
essentials[0].hasAttribute("selected"),
"The first essential should be selected"
);
ok(
!essentials[1].hasAttribute("selected"),
"The second essential should not be selected"
);
ok(
essentials[2].hasAttribute("selected"),
"The third essential should be selected"
);
const urlsToCheck = [essentials[0].dataset.url, essentials[2].dataset.url];
for (const url of urlsToCheck) {
ok(
url.startsWith("https://"),
`The URL "${url}" should start with "https://"`
);
}
await goNextWelcomePage("zen-generic-next");
ok(true, "Welcome Essentials Step Test Finished");
options = currentPageContent().querySelectorAll(".zen-welcome-option");
Assert.equal(options.length, 2, "Default browser page should have 2 options");
await EventUtils.synthesizeMouseAtCenter(options[0], {});
ok(
options[0].querySelector("input").checked,
"Clicking the option should check its radio"
);
// Don't actually change the default browser in the test.
await EventUtils.synthesizeMouseAtCenter(options[1], {});
await goNextWelcomePage("zen-generic-next");
ok(true, "Welcome Default Browser Step Test Finished");
await goNextWelcomePage("zen-welcome-start-browsing");
ok(true, "Welcome Finish Step Test Finished");
await new Promise(resolve => {
setTimeout(async () => {
Assert.greater(
gBrowser._numZenEssentials,
3,
"There should be more than 3 Zen Essentials after the welcome process"
);
Assert.equal(
gBrowser.tabs.filter(
tab => tab.pinned && !tab.hasAttribute("zen-essential")
).length,
3,
"There should be 3 pinned tabs after the welcome process"
);
await wait(3000); // Wait for the finish animation to complete
gBrowser.selectedTab = selectedTab;
const groups = gBrowser.tabGroups;
Assert.equal(
groups.length,
1,
"There should be one tab group after the welcome process"
);
const group = groups[0];
Assert.equal(
group.tabs.length,
3,
"The first tab group should have 3 tabs after the welcome process"
for (const url of urlsToCheck) {
ok(
await PlacesUtils.history.hasVisits(url),
`The URL "${url}" should have visits in history`
);
}
Assert.equal(
gBrowser._numZenEssentials,
2,
"There should be 2 Essentials after the welcome process"
);
Assert.equal(
gBrowser.tabs.filter(
tab => tab.pinned && !tab.hasAttribute("zen-essential")
).length,
2,
"There should be 2 pinned tabs after the welcome process"
);
gBrowser.selectedTab = selectedTab;
const groups = gBrowser.tabGroups;
Assert.equal(
groups.length,
1,
"There should be one tab group after the welcome process"
);
const group = groups[0];
Assert.equal(
group.tabs.length,
2,
"The first tab group should have 2 tabs after the welcome process"
);
Assert.equal(
group.label,
"zen basics",
'The first tab group should be labeled "zen basics" after the welcome process'
);
for (const tab of gBrowser.tabs) {
if (tab.hasAttribute("zen-empty-tab")) {
continue;
}
if (tab.pinned && !tab.hasAttribute("zen-essential")) {
ok(
tab.hasAttribute("zen-workspace-id"),
"Pinned tabs should have a zen-workspace-id attribute"
);
Assert.equal(
group.label,
"zen basics",
'The first tab group should be labeled "zen basics" after the welcome process'
tab.group,
group,
"Pinned tabs should belong to the first tab group"
);
for (const tab of gBrowser.tabs) {
if (tab.hasAttribute("zen-empty-tab")) {
continue;
}
if (tab.pinned) {
if (!tab.hasAttribute("zen-essential")) {
ok(
tab.hasAttribute("zen-workspace-id"),
"Pinned tabs should have a zen-workspace-id attribute"
);
Assert.equal(
tab.group,
group,
"Pinned tabs should belong to the first tab group"
);
}
}
}
group.delete();
resolve();
}, 3000); // Wait for the transition to complete
});
}
}
group.delete();
for (const tab of gBrowser.tabs) {
if (tab.pinned) {
gBrowser.removeTab(tab);

View File

@@ -16,7 +16,7 @@ async function goNextWelcomePage(l10nId) {
setTimeout(() => {
resolve();
}, 0);
}, 3000); // Wait for the transition to complete
}, 800); // Wait for the transition to complete
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,3 +4,4 @@
content/browser/zen-components/ZenWelcome.mjs (../../zen/welcome/ZenWelcome.mjs)
content/browser/zen-styles/zen-welcome.css (../../zen/welcome/zen-welcome.css)
content/browser/zen-videos/welcome-background.mp4 (../../zen/welcome/welcome-background.mp4)

Binary file not shown.

View File

@@ -15,6 +15,21 @@
-moz-window-dragging: drag;
}
#zen-welcome {
position: relative;
isolation: isolate;
}
#zen-welcome-video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: none;
will-change: opacity;
}
:root[zen-welcome-stage] {
min-width: 875px;
min-height: 560px;
@@ -24,32 +39,111 @@
}
}
#zen-welcome {
--zen-welcome-accent: light-dark(
oklch(from var(--zen-primary-color) clamp(0.35, l, 0.6) c h),
oklch(from var(--zen-primary-color) clamp(0.7, l, 0.85) c h)
);
--zen-welcome-accent-button: light-dark(
oklch(from var(--zen-primary-color) clamp(0.35, l, 0.6) c h),
oklch(from var(--zen-primary-color) clamp(0.55, l, 0.7) c h)
);
--zen-welcome-sidebar-bg: light-dark(#ffffff, #1c1c1e);
--zen-welcome-content-bg: light-dark(#f6f6f8f5, #2b2b30ed);
--zen-welcome-surface-bg: light-dark(#ffffff, #1c1c1e);
--zen-welcome-tile-bg: light-dark(#ececee, #333338);
--zen-welcome-border: light-dark(
rgba(0, 0, 0, 0.14),
rgba(255, 255, 255, 0.16)
);
--zen-welcome-text-secondary: light-dark(
rgba(0, 0, 0, 0.6),
rgba(255, 255, 255, 0.6)
);
}
.zen-welcome-button {
appearance: none;
border: none;
border-radius: 12px;
padding: 1.2rem 1rem;
background: transparent;
color: var(--zen-welcome-accent);
font: inherit;
font-size: 1.2rem;
font-weight: 600;
cursor: pointer;
will-change: transform;
transition: scale 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
&:hover {
scale: 1.03;
filter: brightness(1.1);
}
&:active {
scale: 1;
}
&.primary {
background: var(--zen-welcome-accent-button);
color: white;
&:hover {
filter: brightness(1.1);
}
}
}
#zen-welcome-start {
flex-direction: column;
-moz-window-dragging: drag;
--zen-primary-color: light-dark(black, white);
color: white;
#zen-welcome-start-button {
opacity: 0;
list-style-image: url(chrome://browser/skin/zen-icons/forward.svg);
position: absolute;
bottom: 10%;
padding: 1em !important;
min-width: 100px;
background: rgb(62, 115, 62) !important;
fill: white !important;
will-change: transform;
transition: scale 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
&:hover {
scale: 1.03;
filter: brightness(1.1);
}
&:active {
scale: 1;
transform: none;
}
}
#zen-welcome-title {
text-align: center;
font-size: 5rem;
line-height: 1.1;
font-size: 5.2rem;
font-weight: 700;
line-height: 1.05;
letter-spacing: -0.03em;
max-width: 50%;
font-weight: 500;
white-space: nowrap;
/* Layered (transformed) glyphs are drawn with grayscale AA on macOS;
* use it for the whole title so animating characters don't look bolder. */
-moz-osx-font-smoothing: grayscale;
transform: translateY(-5%);
& > span {
display: block;
}
.zen-welcome-char {
display: inline-block;
opacity: 0;
will-change: transform;
}
}
}
@@ -57,28 +151,18 @@
#zen-welcome-pages {
-moz-window-dragging: no-drag;
opacity: 0;
justify-content: start;
align-items: start;
display: none;
background: var(--zen-branding-bg);
border-radius: 1em;
justify-content: start;
align-items: stretch;
background: var(--zen-welcome-content-bg);
color: light-dark(#111111, #ffffff);
border-radius: 1.4rem;
position: relative;
width: 60%;
height: 60%;
box-shadow: var(--zen-big-shadow);
width: 86%;
height: 82%;
box-shadow: 0 3px 8px rgba(0,0,0,.05);
overflow: hidden;
/* Small screens */
@media (max-width: 1400px) {
width: 80%;
height: 80%;
}
@media (max-width: 1200px) {
width: 90%;
height: 90%;
}
@media (max-width: 1000px) {
width: 100%;
height: 100%;
@@ -86,218 +170,338 @@
}
#zen-welcome-page-sidebar {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 3.8rem;
width: 40%;
width: 38%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
padding: 4rem 3.8rem 3.6rem;
box-sizing: border-box;
overflow: hidden;
background: var(--zen-welcome-sidebar-bg);
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.05);
}
& #zen-welcome-heart {
width: 100%;
height: 100%;
opacity: 0;
color: currentColor;
#zen-welcome-back {
align-self: flex-start;
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0 0 2.2rem;
padding: 0;
appearance: none;
border: none;
background: none;
font: inherit;
font-size: 1.1rem;
font-weight: 600;
color: var(--zen-welcome-accent);
&::before {
content: "";
width: 16px;
height: 16px;
background: url(chrome://browser/skin/zen-icons/back.svg) center / contain
no-repeat;
-moz-context-properties: fill;
fill: currentColor;
-moz-context-properties: fill, fill-opacity;
background-image: url(chrome://browser/skin/zen-icons/essential-add.svg);
background-size: 15%;
background-repeat: no-repeat;
background-position: center;
}
&[animate-heart] {
overflow: hidden;
&[disabled] {
visibility: hidden;
}
}
#zen-welcome-page-sidebar-content {
flex: 1;
position: relative;
}
.zen-welcome-text {
position: absolute;
inset: 0;
& > * {
opacity: 0;
will-change: transform, opacity;
}
& h1 {
margin: 0 0 2.4rem;
font-size: 3rem;
font-weight: 700;
line-height: 1.1;
letter-spacing: -0.02em;
}
& p {
margin: 0 0 1.2rem;
font-size: 1.25rem;
line-height: 1.6;
color: var(--zen-welcome-text-secondary);
}
}
#zen-welcome-page-sidebar-buttons {
display: flex;
flex-direction: column;
gap: 10px;
}
#zen-welcome-page-sidebar-content {
& h1 {
font-size: xx-large;
font-weight: 600;
margin-bottom: 1rem;
}
& p {
margin: 0 0 1.1rem 0;
color: light-dark(rgba(0, 0, 0, 0.6), rgba(255, 255, 255, 0.6));
}
& > * {
transform: translate(300%);
}
}
& button {
justify-content: center;
align-items: center;
transform: translate(300%);
gap: 1rem;
}
#zen-welcome-page-content {
background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
width: 60%;
max-width: 80rem;
height: 100%;
flex: 1;
position: relative;
height: 100%;
overflow: hidden;
justify-content: center;
align-items: center;
&::before {
content: "";
position: absolute;
inset: 0;
z-index: 0;
background-image: url(chrome://browser/content/zen-images/grain-bg.png);
opacity: 0.3;
mix-blend-mode: overlay;
pointer-events: none;
}
}
.zen-welcome-page {
position: absolute;
inset: 0;
opacity: 0;
display: flex;
flex-direction: column;
gap: 1.6rem;
justify-content: center;
align-items: center;
gap: 2.5rem;
padding: 3rem 4rem;
box-sizing: border-box;
&[select-engine="true"] {
display: grid;
grid-template-columns: 1fr 1fr;
box-sizing: border-box;
padding: 5rem;
&[exiting] {
pointer-events: none;
}
& > label {
opacity: 0;
transition:
scale 0.1s,
box-shadow 0.1s;
padding: 1.5rem 1.1rem;
border-radius: 0.6rem;
width: 50%;
gap: 0.8rem;
display: flex;
border: 2px solid var(--zen-colors-border);
background: light-dark(rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0.4));
align-items: center;
&[page="essentials"] {
justify-content: flex-end;
align-items: flex-end;
padding: 3rem 0 0 6rem;
}
&:hover {
box-shadow: var(--zen-big-shadow);
&[page="search"] {
justify-content: safe center;
overflow-y: auto;
padding-top: 6rem;
padding-bottom: 6rem;
mask-image: linear-gradient(
transparent,
black 6rem,
black calc(100% - 6rem),
transparent
);
.zen-welcome-option {
max-width: 24rem;
min-height: 7.5rem;
padding: 0 0 0 1.8rem;
overflow: hidden;
font-weight: 600;
}
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
&:has(:checked) {
box-shadow: var(--zen-big-shadow);
border: 2px solid var(--zen-primary-color);
scale: 1.03;
.engine-icon-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
align-self: stretch;
flex-shrink: 0;
width: 34%;
margin-left: auto;
overflow: hidden;
background: var(--zen-welcome-tile-bg);
}
}
&[select-engine="true"] > label {
flex-direction: column;
font-weight: 600;
aspect-ratio: 1 / 0.7;
align-items: center;
width: 60%;
justify-self: center;
align-self: center;
justify-content: space-around;
}
/* 3 or more engines */
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
&[select-engine="true"]:has(label:nth-of-type(3)) > label {
height: 50%;
}
#zen-welcome-workspace-colors-anchor {
width: 1px;
height: 1px;
}
#zen-welcome-initial-essentials-browser {
min-width: 70%;
min-height: 80%;
display: flex;
margin-left: auto;
margin-top: auto;
border-top-left-radius: 1.2em;
box-shadow: var(--zen-big-shadow);
background: light-dark(rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.2));
padding-right: 20%;
overflow: hidden;
opacity: 0;
border: 1px solid var(--zen-colors-border);
border-bottom-width: 0;
border-right-width: 0;
#zen-welcome-initial-essentials-browser-sidebar {
.engine-icon-backdrop {
position: absolute;
inset: 0;
width: 100%;
padding: 1.4rem;
gap: 1.2rem;
background: light-dark(rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0.4));
height: 100%;
object-fit: cover;
scale: 3;
filter: blur(30px) saturate(1.8);
opacity: 0.2;
}
#zen-welcome-initial-essentials-browser-sidebar-win-buttons {
gap: 0.5rem;
align-items: center;
.engine-icon {
position: relative;
width: 26px;
height: 26px;
border-radius: 10px;
}
& > div {
width: 15px;
height: 15px;
border-radius: 50%;
background: var(--zen-toolbar-element-bg);
}
}
.zen-welcome-option-label {
order: -1;
padding-right: 1rem;
}
#zen-welcome-initial-essentials-browser-sidebar-essentials {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
visibility: visible;
.zen-welcome-option-radio {
order: -2;
}
}
}
& * {
visibility: visible;
}
.zen-welcome-option {
display: flex;
align-items: center;
gap: 1rem;
width: 100%;
max-width: 30rem;
padding: 1.8rem 1.9rem;
font-size: 1.3rem;
box-sizing: border-box;
border-radius: 20px;
border: 1px solid var(--zen-welcome-border);
background: var(--zen-welcome-surface-bg);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
cursor: pointer;
will-change: transform;
transition: scale 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
& .extra-tab {
width: 100%;
height: 4rem;
border-radius: var(--border-radius-large);
margin-top: 0.5rem;
background: var(--zen-toolbar-element-bg);
grid-column: span 3;
}
&:hover {
scale: 1.03;
}
& .tabbrowser-tab {
--tab-min-height: 6rem !important;
min-width: 5rem !important;
transition: transform 0.1s;
position: relative;
& input {
display: none;
}
&::after {
position: absolute;
content: "";
width: 1.8rem;
height: 1.8rem;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--zen-essential-tab-icon);
background-position: center;
background-size: contain;
background-repeat: no-repeat;
border-radius: 4px;
}
& strong {
font-weight: 700;
}
--border-radius-medium: 1rem;
& .engine-icon {
width: 28px;
height: 28px;
border-radius: 6px;
}
&[visuallyselected] {
transform: scale(1.06);
}
.zen-welcome-option-radio {
position: relative;
flex-shrink: 0;
width: 22px;
height: 22px;
box-sizing: border-box;
border-radius: 50%;
border: 1px solid
light-dark(rgba(0, 0, 0, 0.45), rgba(255, 255, 255, 0.5));
& .tab-background {
margin: 0 !important;
}
&::after {
content: "";
position: absolute;
inset: 3px;
border-radius: 50%;
background: currentColor;
opacity: 0;
}
}
& .tab-background::after {
filter: blur(30px) brightness(1.2);
}
}
/* stylelint-disable-next-line stylelint-plugin-mozilla/no-has-selector */
&:has(:checked) {
scale: 1.03;
border-color: var(--zen-welcome-accent);
color: var(--zen-welcome-accent);
.zen-welcome-option-radio {
border-color: currentColor;
&::after {
opacity: 1;
}
}
}
}
#zen-welcome-workspace-colors-anchor {
width: 1px;
height: 1px;
}
.zen-welcome-mock-browser {
width: 92%;
height: 100%;
border-top-left-radius: 2.4rem;
background: light-dark(#e3e3e5, #232326);
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.12);
overflow: hidden;
.zen-welcome-mock-browser-sidebar {
display: flex;
flex-direction: column;
gap: 1.6rem;
width: 80%;
height: 100%;
padding: 2.6rem 2.4rem;
box-sizing: border-box;
background: var(--zen-welcome-surface-bg);
}
.zen-welcome-mock-browser-dots {
display: flex;
gap: 1rem;
margin-bottom: 0.6rem;
& > div {
width: 22px;
height: 22px;
border-radius: 50%;
background: var(--zen-welcome-tile-bg);
}
}
#zen-welcome-essentials {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.zen-welcome-essential {
appearance: none;
aspect-ratio: 1;
padding: 0;
border-radius: 2rem;
border: 3px solid transparent;
background: var(--zen-welcome-tile-bg) var(--zen-welcome-app-icon)
center / 35% no-repeat;
cursor: pointer;
will-change: transform;
transition: scale 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
&:hover,
&[selected] {
scale: 1.04;
}
&[selected] {
background-color: color-mix(
in srgb,
var(--zen-welcome-app-color) 22%,
var(--zen-welcome-surface-bg)
);
border-color: color-mix(
in srgb,
var(--zen-welcome-app-color) 60%,
transparent
);
}
}
.zen-welcome-mock-tab {
flex-shrink: 0;
height: 4.5rem;
border-radius: 1.6rem;
background: var(--zen-welcome-tile-bg);
}
}
}