Merge pull request #5373 from zen-browser/new-onboarding

Implement Zen Welcome page
This commit is contained in:
mr. m
2025-02-17 19:13:21 +01:00
committed by GitHub
23 changed files with 756 additions and 1162 deletions

2
l10n

Submodule l10n updated: 19e2af33c4...c7fc158cf9

View File

@@ -75,8 +75,7 @@ pref("app.update.checkInstallTime.days", 6);
// CUSTOM ZEN PREFS
pref('zen.welcome-screen.enabled', true, sticky);
pref('zen.welcome-screen.seen', false);
pref('zen.welcome-screen.seen', false, sticky);
pref('zen.tabs.vertical', true);
pref('zen.tabs.vertical.right-side', false);

View File

@@ -36,6 +36,8 @@
gZenVerticalTabsManager.init();
gZenUIManager.init();
this._checkForWelcomePage();
document.l10n.setAttributes(document.getElementById('tabs-newtab-button'), 'tabs-toolbar-new-tab');
} catch (e) {
console.error('ZenThemeModifier: Error initializing browser layout', e);
@@ -117,6 +119,14 @@
gURLBar._initPasteAndGo();
gURLBar._initStripOnShare();
},
_checkForWelcomePage() {
if (!Services.prefs.getBoolPref('zen.welcome-screen.seen', false)) {
//Services.prefs.setBoolPref('zen.welcome-screen.seen', true);
console.log('ZenStartup: Show welcome page');
Services.scriptloader.loadSubScript('chrome://browser/content/zen-components/ZenWelcome.mjs', window);
}
},
};
ZenStartup.init();

View File

@@ -1,5 +1,5 @@
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..1f051e8a1e8a58e8bb721196deecfa36f4089dd6 100644
index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..5225d0539aa7dabf81a8fd60af3e839f203d296c 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -32,6 +32,7 @@ ChromeUtils.defineESModuleGetters(this, {
@@ -10,23 +10,7 @@ index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..1f051e8a1e8a58e8bb721196deecfa36
DevToolsSocketStatus:
"resource://devtools/shared/security/DevToolsSocketStatus.sys.mjs",
DownloadUtils: "resource://gre/modules/DownloadUtils.sys.mjs",
@@ -632,6 +633,15 @@ XPCOMUtils.defineLazyPreferenceGetter(
false
);
+const ZEN_WELCOME_PATH = "zen-welcome";
+const ZEN_WELCOME_ELEMENT_ATTR = "zen-dialog-welcome-element";
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "ProfileService",
+ "@mozilla.org/toolkit/profile-service;1",
+ "nsIToolkitProfileService"
+);
+
customElements.setElementCreationCallback("screenshots-buttons", () => {
Services.scriptloader.loadSubScript(
"chrome://browser/content/screenshots/screenshots-buttons.js",
@@ -3440,6 +3450,10 @@ var XULBrowserWindow = {
@@ -3440,6 +3441,10 @@ var XULBrowserWindow = {
AboutReaderParent.updateReaderButton(gBrowser.selectedBrowser);
TranslationsParent.onLocationChange(gBrowser.selectedBrowser);
@@ -37,7 +21,7 @@ index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..1f051e8a1e8a58e8bb721196deecfa36
PictureInPicture.updateUrlbarToggle(gBrowser.selectedBrowser);
if (!gMultiProcessBrowser) {
@@ -4435,7 +4449,7 @@ nsBrowserAccess.prototype = {
@@ -4435,7 +4440,7 @@ nsBrowserAccess.prototype = {
// Passing a null-URI to only create the content window,
// and pass true for aSkipLoad to prevent loading of
// about:blank
@@ -46,7 +30,7 @@ index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..1f051e8a1e8a58e8bb721196deecfa36
null,
aParams,
aWhere,
@@ -4443,6 +4457,10 @@ nsBrowserAccess.prototype = {
@@ -4443,6 +4448,10 @@ nsBrowserAccess.prototype = {
aName,
true
);
@@ -57,16 +41,3 @@ index 019b168c1aeae7e1c97a3ae58c99a48a27f54134..1f051e8a1e8a58e8bb721196deecfa36
},
openURIInFrame: function browser_openURIInFrame(
@@ -7285,6 +7303,12 @@ var gDialogBox = {
parentElement.showModal();
this._didOpenHTMLDialog = true;
+ if (uri.includes(ZEN_WELCOME_PATH)) {
+ parentElement.setAttribute(ZEN_WELCOME_ELEMENT_ATTR, true);
+ } else if (parentElement.hasAttribute(ZEN_WELCOME_ELEMENT_ATTR)) {
+ parentElement.removeAttribute(ZEN_WELCOME_ELEMENT_ATTR);
+ }
+
// Disable menus and shortcuts.
this._updateMenuAndCommandState(false /* to disable */);

View File

@@ -24,6 +24,8 @@
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-compact-mode.css" />
<link rel="stylesheet" type="text/css" href="chrome://browser/skin/zen-icons/icons.css" />
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-branding.css" />
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-welcome.css" />
</linkset>
# Scripts used all over the browser

View File

@@ -24,6 +24,7 @@
content/browser/zen-components/ZenActorsManager.mjs (zen-components/ZenActorsManager.mjs)
content/browser/zen-components/ZenRices.mjs (zen-components/ZenRices.mjs)
content/browser/zen-components/ZenEmojies.mjs (zen-components/ZenEmojies.mjs)
content/browser/zen-components/ZenWelcome.mjs (zen-components/ZenWelcome.mjs)
content/browser/zen-styles/zen-theme.css (content/zen-styles/zen-theme.css)
content/browser/zen-styles/zen-buttons.css (content/zen-styles/zen-buttons.css)
@@ -47,11 +48,12 @@
content/browser/zen-styles/zen-gradient-generator.css (content/zen-styles/zen-gradient-generator.css)
content/browser/zen-styles/zen-rices.css (content/zen-styles/zen-rices.css)
content/browser/zen-styles/zen-branding.css (content/zen-styles/zen-branding.css)
content/browser/zen-styles/zen-welcome.css (content/zen-styles/zen-welcome.css)
content/browser/zen-styles/zen-panels/bookmarks.css (content/zen-styles/zen-panels/bookmarks.css)
content/browser/zen-styles/zen-panels/extensions.css (content/zen-styles/zen-panels/extensions.css)
content/browser/zen-styles/zen-panels/print.css (content/zen-styles/zen-panels/print.css)
content/browser/zen-styles/zen-panels/welcome.css (content/zen-styles/zen-panels/welcome.css)
content/browser/zen-styles/zen-panels/dialog.css (content/zen-styles/zen-panels/dialog.css)
* content/browser/zen-styles/zen-compact-mode.css (content/zen-styles/zen-compact-mode.css)

View File

@@ -31,6 +31,13 @@ xul|button:is(.expander-down) {
border-radius: 6px !important;
}
.footer-button {
transition: scale 0.2s;
&:active {
scale: 0.98;
}
}
@media (-moz-bool-pref: 'zen.theme.pill-button') {
:host(:is(.anonymous-content-host, notification-message)),
:root {

View File

@@ -0,0 +1,11 @@
/*
* 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 Welcome idalog override */
@media (prefers-color-scheme: dark) {
.dialogBox:not(.spotlightBox) {
border: 1px solid var(--zen-colors-border);
}
}

View File

@@ -1,33 +0,0 @@
/*
* 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 Welcome idalog override */
@media (prefers-color-scheme: dark) {
.dialogBox:not(.spotlightBox) {
border: 1px solid var(--zen-colors-border);
}
}
#window-modal-dialog[zen-dialog-welcome-element='true'] .dialogBox:not(.spotlightBox) {
margin: 0 !important;
}
#window-modal-dialog[zen-dialog-welcome-element='true'],
#window-modal-dialog[zen-dialog-welcome-element='true'] .dialogOverlay,
#window-modal-dialog[zen-dialog-welcome-element='true'] .dialogFrame,
#window-modal-dialog[zen-dialog-welcome-element='true'] .dialogBox {
width: 100% !important;
height: 100% !important;
max-height: none !important;
max-width: none !important;
}
#window-modal-dialog[zen-dialog-welcome-element='true'] {
--zen-welcome-dialog-space: 7px;
margin: 0 auto !important;
max-width: calc(100% - calc(var(--zen-welcome-dialog-space) * 2)) !important;
max-height: calc(100% - calc(var(--zen-welcome-dialog-space) * 2)) !important;
margin-top: var(--zen-welcome-dialog-space) !important;
}

View File

@@ -6,7 +6,7 @@
@import url('chrome://browser/content/zen-styles/zen-panels/bookmarks.css');
@import url('chrome://browser/content/zen-styles/zen-panels/extensions.css');
@import url('chrome://browser/content/zen-styles/zen-panels/print.css');
@import url('chrome://browser/content/zen-styles/zen-panels/welcome.css');
@import url('chrome://browser/content/zen-styles/zen-panels/dialog.css');
:root {
--panel-subview-body-padding: 2px 0;

View File

@@ -955,7 +955,8 @@
padding: 0;
}
#zen-essentials-container > .tabbrowser-tab {
#zen-essentials-container > .tabbrowser-tab,
#zen-welcome-initial-essentials-browser-sidebar-essentials .tabbrowser-tab {
--toolbarbutton-inner-padding: 0;
max-width: unset;
width: 100% !important;
@@ -1010,11 +1011,12 @@
background: transparent;
overflow: hidden;
position: relative;
--zen-essential-bg-margin: 2px;
&::before {
background: light-dark(rgba(255, 255, 255, 0.85), rgba(68, 64, 64, 0.85));
margin: 2px;
border-radius: calc(var(--border-radius-medium) - 2px);
margin: var(--zen-essential-bg-margin);
border-radius: calc(var(--border-radius-medium) - var(--zen-essential-bg-margin));
position: absolute;
inset: 0;
z-index: 0;

View File

@@ -163,7 +163,7 @@
background: transparent;
--zen-themed-toolbar-bg-transparent: transparent;
@media (-moz-bool-pref: 'zen.widget.windows.acrylic') {
--zen-themed-toolbar-bg-transparent: color-mix(in srgb, var(--zen-themed-toolbar-bg) 85%, transparent 15%);
--zen-themed-toolbar-bg-transparent: color-mix(in srgb, var(--zen-themed-toolbar-bg) 80%, transparent 20%);
}
}

View File

@@ -0,0 +1,236 @@
#zen-welcome,
#zen-welcome-start,
#zen-welcome-pages {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
-moz-window-dragging: drag;
}
:root[zen-welcome-stage] #zen-sidebar-splitter {
display: none;
}
#zen-welcome-start {
flex-direction: column;
-moz-window-dragging: drag;
--zen-primary-color: light-dark(black, white);
#zen-welcome-start-button {
opacity: 0;
list-style-image: url(chrome://browser/skin/zen-icons/forward.svg);
position: absolute;
bottom: 10%;
.button-icon {
filter: invert(1);
}
}
#zen-welcome-title {
text-align: center;
font-size: 5rem;
line-height: 1.1;
max-width: 50%;
font-weight: 500;
white-space: nowrap;
& > span {
display: block;
opacity: 0;
}
}
}
#zen-welcome-pages {
opacity: 0;
justify-content: start;
align-items: start;
display: none;
background: var(--zen-branding-bg);
border-radius: 1em;
overflow: hidden;
position: relative;
width: 60%;
height: 60%;
box-shadow: var(--zen-big-shadow);
#zen-welcome-page-sidebar {
flex-direction: column;
justify-content: space-between;
padding: 3.8rem;
width: 40%;
height: 100%;
overflow: hidden;
& #zen-welcome-heart {
width: 100%;
height: 100%;
opacity: 0;
color: var(--zen-primary-color);
fill: var(--zen-primary-color);
background-image: url(chrome://browser/skin/zen-icons/essential-add.svg);
background-size: 15%;
background-repeat: no-repeat;
background-position: center;
}
}
#zen-welcome-page-sidebar-buttons {
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%);
}
#zen-welcome-page-content {
background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
width: 60%;
height: 100%;
position: relative;
overflow: hidden;
justify-content: center;
align-items: center;
display: flex;
flex-direction: column;
gap: 1.6rem;
& 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;
&:hover {
box-shadow: var(--zen-big-shadow);
}
&:has(:checked) {
box-shadow: var(--zen-big-shadow);
border: 2px solid var(--zen-primary-color);
scale: 1.03;
}
}
#zen-welcome-initial-essentials-browser {
width: 70%;
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 {
width: 100%;
padding: 1.4rem;
gap: 1.2rem;
background: light-dark(rgba(255, 255, 255, 0.7), rgba(0, 0, 0, 0.4));
#zen-welcome-initial-essentials-browser-sidebar-win-buttons {
gap: 0.5rem;
align-items: center;
& > div {
width: 15px;
height: 15px;
border-radius: 50%;
background: var(--zen-toolbar-element-bg);
}
}
#zen-welcome-initial-essentials-browser-sidebar-essentials {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
visibility: visible;
& * {
visibility: visible;
}
& .extra-tab {
width: 100%;
height: 3rem;
border-radius: 0.8rem;
margin-top: 0.5rem;
background: var(--zen-toolbar-element-bg)
}
& .tabbrowser-tab {
--tab-min-height: 5rem !important;
min-width: 5rem !important;
transition: transform 0.1s;
position: relative;
&::after {
position: absolute;
content: "";
width: 1.6rem;
height: 1.6rem;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--zen-tab-icon);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
--border-radius-medium: 1rem;
&[visuallyselected] {
transform: scale(1.04);
& .tab-background {
--zen-essential-bg-margin: 3px;
box-shadow: var(--zen-big-shadow);
}
}
& .tab-background::after {
filter: blur(30px) !important;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,473 @@
{
function clearBrowserElements() {
for (const element of document.getElementById('browser').children) {
element.style.display = 'none';
}
}
function getMotion() {
return gZenUIManager.motion;
}
async function animate(...args) {
return getMotion().animate(...args);
}
function initializeZenWelcome() {
document.documentElement.setAttribute('zen-welcome-stage', 'true');
const XUL = `
<html:div id="zen-welcome">
<html:div id="zen-welcome-start">
<html:h1 class="zen-branding-title" id="zen-welcome-title"></html:h1>
<button class="footer-button primary" id="zen-welcome-start-button">
</button>
</html:div>
<hbox id="zen-welcome-pages">
<vbox id="zen-welcome-page-sidebar">
<vbox id="zen-welcome-page-sidebar-content">
</vbox>
<vbox id="zen-welcome-page-sidebar-buttons">
</vbox>
</vbox>
<html:div id="zen-welcome-page-content">
</html:div>
</hbox>
</html:div>
`;
const fragment = window.MozXULElement.parseXULToFragment(XUL);
document.getElementById('browser').appendChild(fragment);
window.MozXULElement.insertFTLIfNeeded('browser/zen-welcome.ftl');
}
class ZenWelcomePages {
constructor(pages) {
this._currentPage = -1;
this._pages = pages;
this.init();
this.next();
}
init() {
document.getElementById('zen-welcome-pages').style.display = 'flex';
document.getElementById('zen-welcome-start').remove();
window.maximize();
animate('#zen-welcome-pages', { opacity: [0, 1] }, { delay: 0.1 });
}
async fadeInTitles(page) {
const [title1, description1, description2] = await document.l10n.formatValues(page.text);
const titleElement = document.getElementById('zen-welcome-page-sidebar-content');
titleElement.innerHTML =
`<html:h1>${title1}</html:h1><html:p>${description1}</html:p>` +
(description2 ? `<html:p>${description2}</html:p>` : '');
await animate(
'#zen-welcome-page-sidebar-content > *',
{ x: ['150%', 0] },
{
delay: getMotion().stagger(0.05),
type: 'spring',
bounce: 0.2,
}
);
}
async fadeInButtons(page) {
const buttons = document.getElementById('zen-welcome-page-sidebar-buttons');
let i = 0;
for (const button of page.buttons) {
const buttonElement = document.createXULElement('button');
document.l10n.setAttributes(buttonElement, button.l10n);
if (i++ === 0) {
buttonElement.classList.add('primary');
}
buttonElement.classList.add('footer-button');
buttonElement.addEventListener('click', async () => {
const shouldSkip = await button.onclick();
if (shouldSkip) {
this.next();
}
});
buttons.appendChild(buttonElement);
}
await animate(
'#zen-welcome-page-sidebar-buttons button',
{ x: ['150%', 0] },
{
delay: getMotion().stagger(0.1, { startDelay: 0.4 }),
type: 'spring',
bounce: 0.2,
}
);
}
async fadeInContent() {
await animate(
'#zen-welcome-page-content > *',
{ opacity: [0, 1] },
{
delay: getMotion().stagger(0.1),
type: 'spring',
bounce: 0.2,
}
);
}
async fadeOutButtons() {
await animate(
'#zen-welcome-page-sidebar-buttons button',
{ x: [0, '-150%'] },
{
type: 'spring',
bounce: 0,
delay: getMotion().stagger(0.1, { startDelay: 0.5 }),
}
);
document.getElementById('zen-welcome-page-sidebar-buttons').innerHTML = '';
document.getElementById('zen-welcome-page-sidebar-content').innerHTML = '';
}
async fadeOutTitles() {
await animate(
'#zen-welcome-page-sidebar-content > *',
{ x: [0, '-150%'] },
{
delay: getMotion().stagger(0.05, { startDelay: 0.3 }),
type: 'spring',
bounce: 0,
}
);
}
async fadeOutContent() {
await animate(
'#zen-welcome-page-content > *',
{ opacity: [1, 0] },
{
delay: getMotion().stagger(0.05, { startDelay: 0.3 }),
type: 'spring',
bounce: 0,
duration: 0.2,
}
);
}
async next() {
if (this._currentPage !== -1) {
const previousPage = this._pages[this._currentPage];
await Promise.all([this.fadeOutTitles(), this.fadeOutButtons(), this.fadeOutContent()]);
await previousPage.fadeOut();
document.getElementById('zen-welcome-page-content').innerHTML = '';
}
this._currentPage++;
const currentPage = this._pages[this._currentPage];
if (!currentPage) {
this.finish();
return;
}
await Promise.all([this.fadeInTitles(currentPage), this.fadeInButtons(currentPage)]);
currentPage.fadeIn();
await this.fadeInContent();
}
async finish() {
await animate('#zen-welcome-page-content', { x: [0, '100%'] }, { bounce: 0 });
document.getElementById('zen-welcome-page-content').remove();
await this.animHeart();
await animate('#zen-welcome-pages', { opacity: [1, 0] });
document.getElementById('zen-welcome').remove();
document.documentElement.removeAttribute('zen-welcome-stage');
for (const element of document.getElementById('browser').children) {
element.style.opacity = 0;
element.style.removeProperty('display');
}
await animate('#browser > *', { opacity: [0, 1] });
gZenUIManager.showToast('zen-welcome-finished');
}
async animHeart() {
const heart = document.createElement('div');
heart.id = 'zen-welcome-heart';
const sidebar = document.getElementById('zen-welcome-page-sidebar');
sidebar.style.width = '100%';
sidebar.appendChild(heart);
await animate(
'#zen-welcome-heart',
{ opacity: [0, 1, 1, 1, 0], scale: [0.5, 1, 1.2, 1, 1.2] },
{
duration: 1.5,
delay: 0.2,
bounce: 0,
}
);
}
}
function getWelcomePages() {
return [
{
text: [
{
id: 'zen-welcome-import-title',
},
{
id: 'zen-welcome-import-description-1',
},
{
id: 'zen-welcome-import-description-2',
},
],
buttons: [
{
l10n: 'zen-welcome-import-button',
onclick: async () => {
MigrationUtils.showMigrationWizard(window, {
isStartupMigration: true,
});
document.querySelector('#zen-welcome-page-sidebar-buttons button').remove();
const newButton = document.querySelector('#zen-welcome-page-sidebar-buttons button');
newButton.classList.add('primary');
document.l10n.setAttributes(newButton, 'zen-welcome-next-action');
return false;
},
},
{
l10n: 'zen-welcome-skip-button',
onclick: async () => {
return true;
},
},
],
fadeIn() {
const xul = `
<html:label for="zen-welcome-set-default-browser">
<html:input type="radio" id="zen-welcome-set-default-browser" name="zen-welcome-set-default-browser"></html:input>
<html:span data-l10n-id="zen-welcome-set-default-browser"></html:span>
</html:label>
<html:label for="zen-welcome-dont-set-default-browser">
<html:input checked="true" type="radio" id="zen-welcome-dont-set-default-browser" name="zen-welcome-set-default-browser"></html:input>
<html:span data-l10n-id="zen-welcome-dont-set-default-browser"></html:span>
</html:label>
`;
const fragment = window.MozXULElement.parseXULToFragment(xul);
document.getElementById('zen-welcome-page-content').appendChild(fragment);
},
async fadeOut() {
const shouldSetDefault = document.getElementById('zen-welcome-set-default-browser').checked;
if (AppConstants.HAVE_SHELL_SERVICE && shouldSetDefault) {
let shellSvc = getShellService();
if (!shellSvc) {
return;
}
try {
await shellSvc.setDefaultBrowser(false);
} catch (ex) {
console.error(ex);
return;
}
}
},
},
{
text: [
{
id: 'zen-welcome-workspace-colors-title',
},
{
id: 'zen-welcome-workspace-colors-description',
},
],
buttons: [
{
l10n: 'zen-welcome-next-action',
onclick: async () => {
return true;
},
},
],
fadeIn() {},
fadeOut() {},
},
{
text: [
{
id: 'zen-welcome-initial-essentials-title',
},
{
id: 'zen-welcome-initial-essentials-description-1',
},
{
id: 'zen-welcome-initial-essentials-description-2',
},
],
buttons: [
{
l10n: 'zen-welcome-next-action',
onclick: async () => {
return true;
},
},
],
fadeIn() {
const xul = `
<hbox id="zen-welcome-initial-essentials-browser">
<vbox id="zen-welcome-initial-essentials-browser-sidebar">
<hbox id="zen-welcome-initial-essentials-browser-sidebar-win-buttons">
<html:div></html:div>
<html:div></html:div>
<html:div></html:div>
</hbox>
<html:div id="zen-welcome-initial-essentials-browser-sidebar-essentials">
<html:div class="tabbrowser-tab" fadein="" visuallyselected="" data-url="https://web.whatsapp.com" style="--zen-tab-icon: url('https://web.whatsapp.com/favicon.ico');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" visuallyselected="" data-url="https://discord.com" style="--zen-tab-icon: url('http://www.google.com/s2/favicons?domain=discord.com');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" data-url="https://reddit.com" style="--zen-tab-icon: url('https://www.redditstatic.com/desktop2x/img/favicon/favicon-96x96.png');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" data-url="https://slack.com/" style="--zen-tab-icon: url('https://a.slack-edge.com/80588/marketing/img/meta/favicon-32.png');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" visuallyselected="" data-url="https://google.com" style="--zen-tab-icon: url('https://www.google.com/s2/favicons?domain=google.com');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" data-url="https://twitter.com" style="--zen-tab-icon: url('https://abs.twimg.com/favicons/twitter.ico');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" data-url="https://notion.com" style="--zen-tab-icon: url('https://www.notion.so/front-static/favicon.ico');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" data-url="https://instagram.com" style="--zen-tab-icon: url('https://www.instagram.com/static/images/ico/favicon-192.png/68d99ba29cc8.png');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="tabbrowser-tab" fadein="" visuallyselected="" data-url="https://element.io" style="--zen-tab-icon: url('http://www.google.com/s2/favicons?domain=element.io');">
<stack class="tab-stack">
<html:div class="tab-background"></html:div>
</stack>
</html:div>
<html:div class="extra-tab"></html:div>
<html:div class="extra-tab"></html:div>
</html:div>
</vbox>
</hbox>
`;
const fragment = window.MozXULElement.parseXULToFragment(xul);
document.getElementById('zen-welcome-page-content').appendChild(fragment);
document.getElementById('zen-welcome-initial-essentials-browser-sidebar-essentials').addEventListener('click', async (event) => {
const tab = event.target.closest('.tabbrowser-tab');
if (!tab) {
return;
}
tab.toggleAttribute('visuallyselected');
});
},
fadeOut() {},
},
{
text: [
{
id: 'zen-welcome-start-browsing-title',
},
{
id: 'zen-welcome-start-browsing-description-1',
},
],
buttons: [
{
l10n: 'zen-welcome-start-browsing',
onclick: async () => {
return true;
},
},
],
fadeIn() {},
fadeOut() {},
},
];
}
async function animateInitialStage() {
const [title1, title2] = await document.l10n.formatValues([
{ id: 'zen-welcome-title-line1' },
{ id: 'zen-welcome-title-line2' },
]);
const titleElement = document.getElementById('zen-welcome-title');
titleElement.innerHTML = `<html:span>${title1}</html:span><html:span>${title2}</html:span>`;
await animate(
'#zen-welcome-title span',
{ opacity: [0, 1], y: [20, 0], filter: ['blur(2px)', 'blur(0px)'] },
{
delay: getMotion().stagger(0.6, { startDelay: 0.2 }),
type: 'spring',
stiffness: 300,
damping: 20,
mass: 1.8,
}
);
const button = document.getElementById('zen-welcome-start-button');
await animate(
button,
{ opacity: [0, 1], y: [20, 0], filter: ['blur(2px)', 'blur(0px)'] },
{
delay: 0.1,
type: 'spring',
stiffness: 300,
damping: 20,
mass: 1.8,
}
);
button.addEventListener('click', async () => {
await animate(
'#zen-welcome-title span, #zen-welcome-start-button',
{ opacity: [1, 0], y: [0, -10], filter: ['blur(0px)', 'blur(2px)'] },
{
type: 'spring',
ease: [0.755, 0.05, 0.855, 0.06],
bounce: 0.4,
delay: getMotion().stagger(0.4),
}
);
new ZenWelcomePages(getWelcomePages());
});
}
function centerWindowOnScreen() {
window.addEventListener(
'MozAfterPaint',
function () {
window.resizeTo(875, 560);
window.focus();
const appWin = window.docShell.treeOwner.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIAppWindow);
appWin.rollupAllPopups();
},
{ once: true }
);
}
function startZenWelcome() {
clearBrowserElements();
centerWindowOnScreen();
initializeZenWelcome();
animateInitialStage();
}
startZenWelcome();
}

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/BrowserGlue.sys.mjs b/browser/components/BrowserGlue.sys.mjs
index b888a753a7f23a9800fe04da51a4e6b898314ff2..35eea774e1ea4b1807ec65ebc767f423d81602bd 100644
index b888a753a7f23a9800fe04da51a4e6b898314ff2..a6a01cf035253b05ea7b20b434cf2002ff115d96 100644
--- a/browser/components/BrowserGlue.sys.mjs
+++ b/browser/components/BrowserGlue.sys.mjs
@@ -121,6 +121,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
@@ -18,28 +18,3 @@ index b888a753a7f23a9800fe04da51a4e6b898314ff2..35eea774e1ea4b1807ec65ebc767f423
// A channel for "remote troubleshooting" code...
let channel = new lazy.WebChannel(
"remote-troubleshooting",
@@ -4761,6 +4763,7 @@ BrowserGlue.prototype = {
},
async _maybeShowDefaultBrowserPrompt() {
+ this._ZenMaybeShowWelcomeScreen();
// Highest priority is about:welcome window modal experiment
// Second highest priority is the upgrade dialog, which can include a "primary
// browser" request and is limited in various ways, e.g., major upgrades.
@@ -5302,6 +5305,16 @@ BrowserGlue.prototype = {
"nsIObserver",
"nsISupportsWeakReference",
]),
+
+ _ZenMaybeShowWelcomeScreen() {
+ const welcomeEnabled = Services.prefs.getBoolPref("zen.welcome-screen.enabled", true)
+ const welcomeSeen = Services.prefs.getBoolPref("zen.welcome-screen.seen", false)
+ if (welcomeEnabled && !welcomeSeen) {
+ lazy.BrowserWindowTracker.getTopWindow().gDialogBox.open(
+ "chrome://browser/content/zen-welcome/welcome.html"
+ );
+ }
+ },
};
var ContentBlockingCategoriesPrefs = {

View File

@@ -1,38 +0,0 @@
diff --git a/browser/components/migration/MigrationUtils.sys.mjs b/browser/components/migration/MigrationUtils.sys.mjs
index 000b471ee6c93815dde61127b8974774d0abafb1..32ba8d40bab5e609fc76dfe97a952d5a7a300a71 100644
--- a/browser/components/migration/MigrationUtils.sys.mjs
+++ b/browser/components/migration/MigrationUtils.sys.mjs
@@ -576,12 +576,15 @@ class MigrationUtils {
* True if the source selection page of the wizard should be skipped.
* @param {string} [aOptions.profileId]
* An identifier for the profile to use when migrating.
+ * @param {boolean} [aOptions.zenBlocking=false]
+ * True if the migration wizard should block the main thread.
* @returns {Promise<undefined>}
* If an about:preferences tab can be opened, this will resolve when
* that tab has been switched to. Otherwise, this will resolve
* just after opening the top-level dialog window.
*/
showMigrationWizard(aOpener, aOptions) {
+ let zenShouldBlock = aOptions.zenBlocking || false;
// When migration is kicked off from about:welcome, there are
// a few different behaviors that we want to test, controlled
// by a preference that is instrumented for Nimbus. The pref
@@ -648,7 +651,7 @@ class MigrationUtils {
if (aboutWelcomeBehavior == "autoclose") {
return aOpener.openPreferences("general-migrate-autoclose");
} else if (aboutWelcomeBehavior == "standalone") {
- openStandaloneWindow(false /* blocking */);
+ openStandaloneWindow(zenShouldBlock /* blocking */);
return Promise.resolve();
}
}
@@ -657,7 +660,7 @@ class MigrationUtils {
// If somehow we failed to open about:preferences, fall back to opening
// the top-level window.
- openStandaloneWindow(false /* blocking */);
+ openStandaloneWindow(zenShouldBlock /* blocking */);
return Promise.resolve();
}

View File

@@ -1,12 +0,0 @@
diff --git a/browser/components/moz.build b/browser/components/moz.build
index 6cbb7ce0037c1457eeae5c331a996719691ebd6b..611707852198740c9b4103f5e2a66e8ee4099a21 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -27,6 +27,7 @@ with Files("controlcenter/**"):
DIRS += [
+ "zen-welcome",
"about",
"aboutlogins",
"aboutwelcome",

View File

@@ -1,7 +0,0 @@
# Important notes!
Inside browser.js, we hardcoded-ly detect the path name for `zen-welcome` so we can add special attributes to the welcome page. If this path name changes, the welcome page will not work properly.
Make sure to update the path name in browser.js if you change the path name of `zen-welcome`.
The constant that contains this path name is `ZEN_WELCOME_PATH`.

View File

@@ -1,9 +0,0 @@
# 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/.
browser.jar:
% content browser %content/browser/ contentaccessible=yes
content/browser/zen-welcome/welcome.html (welcome.html)
content/browser/zen-welcome/welcome.css (welcome.css)
content/browser/zen-welcome/welcome.js (welcome.js)

View File

@@ -1,4 +0,0 @@
# 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/.
JAR_MANIFESTS += ["jar.mn"]

View File

@@ -1,451 +0,0 @@
/*
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/.
*/
:root {
--noise: url('data:image/png;base64,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');
}
html {
width: 100%;
height: 100%;
}
body {
display: flex;
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
user-select: none;
}
body {
background: var(--zen-branding-bg);
}
#main-view {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
width: fit-content;
margin: auto;
}
#welcome .zen-branding-title,
#thanks .zen-branding-title {
text-align: center;
font-size: 7rem;
}
#buttons-footer {
margin-top: auto;
padding: 20px 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 2;
& button {
opacity: 0;
animation: fadeIn 0.5s ease-in-out forwards;
animation-delay: 0.8s;
}
& button:nth-child(2) {
animation-delay: 1s;
}
}
body:has(:is(#welcome, #thanks):not([hidden='true'])) {
& #buttons-footer {
justify-content: center;
position: fixed;
bottom: 40px;
margin: 0 auto;
& button {
background: var(--zen-branding-paper) !important;
color: var(--zen-branding-dark) !important;
}
}
}
:is(#theme, #search) > div:nth-child(2) {
width: 100%;
}
#main-view:has(:is(#welcome, #thanks):not([hidden='true'])) {
width: 100%;
& #back {
display: none;
}
}
button {
padding: 8px;
border-radius: 999px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
}
button.primary {
background: var(--zen-branding-bg-reverse) !important;
color: var(--zen-branding-bg) !important;
transition: background 0.2s ease-in-out;
&:hover {
background: color-mix(in srgb, var(--zen-branding-bg-reverse) 80%, transparent 20%) !important;
}
}
.page {
display: flex;
flex-direction: column;
justify-content: center;
width: -moz-available;
align-items: center;
margin: 32px;
}
h2 {
font-size: 17px;
font-weight: 600;
margin: 35px 0 20px 0;
line-height: 1;
}
.page-split:not([hidden='true']) {
flex-direction: column;
margin: auto;
justify-content: start;
}
.page-split:not(#import, #theme) > div:first-child {
margin-bottom: 20px;
}
:not(#theme) .card h3 {
margin: auto;
text-align: center;
}
#theme {
& > div:first-child p {
margin-bottom: 0 !important;
}
}
#theme .card[disabled='true'] {
opacity: 0.7;
cursor: not-allowed;
}
.cardGroup {
display: flex;
flex-wrap: wrap;
align-items: stretch;
gap: 8px;
margin-bottom: 8px;
}
.cardGroup .card {
width: 140px;
display: flex;
flex-direction: column;
align-items: center;
align-content: space-between;
border: 2px solid transparent !important;
transition: all 0.1s ease-in-out !important;
margin: 0 10px;
border-radius: 7px;
outline: none !important;
cursor: auto;
user-select: none;
}
.cardGroup .card.selected {
border: 2px solid var(--zen-colors-primary) !important;
transform: scale(1.1);
}
h1 {
font-size: 32px;
font-weight: 700;
margin: 16px 0 5px 0;
line-height: 1;
}
.page > div:nth-child(2) h1 {
margin-bottom: 15px;
margin-top: 10px;
font-size: 18px;
}
p {
font-size: 16px;
opacity: 0.8;
margin: 0;
margin-bottom: 30px;
}
#zen-logo {
-moz-context-properties: fill;
fill: currentColor;
display: inline-block;
height: 42px;
width: 42px;
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
}
.asset {
width: 500px;
padding-bottom: 32px;
}
@media (prefers-color-scheme: light) {
.dark-only {
display: none;
}
}
@media (prefers-color-scheme: dark) {
.light-only {
display: none;
}
}
input[type='checkbox'] {
display: inline-block;
vertical-align: middle;
}
#importNext {
margin-left: 30px;
color: var(--in-content-primary-button-background);
}
#themeNext,
#searchNext,
#thanksNext {
margin-top: 20px;
}
.page[hidden='true'] {
display: none;
}
.page:not([hidden='true']) {
display: flex;
}
.page:not([hidden='true']) > *:not(:has(.delay-animation)),
.delay-animation,
.delay-animation-2 {
opacity: 0;
animation: fadeIn 0.5s ease-in-out forwards;
}
#importBrowser {
width: 100%;
background: transparent !important;
border: 1px solid var(--zen-branding-bg-reverse);
color: var(--zen-branding-bg-reverse);
padding: 16px;
border-radius: 8px;
margin-bottom: 20px;
justify-content: start;
display: flex;
}
#layout {
text-align: center;
}
#layoutList {
display: flex;
gap: 20px;
& > [layout] {
display: flex;
flex-direction: column;
gap: 3px;
font-weight: 600;
cursor: pointer;
&[disabled='true'] {
opacity: 0.7;
cursor: not-allowed;
}
& img {
width: 250px;
border-radius: 10px;
border: 4px solid transparent;
}
&.selected img {
border: 4px solid var(--zen-colors-primary);
}
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translate3d(0, 40px, 0);
filter: blur(15px);
}
to {
opacity: 1;
filter: blur(0);
transform: translate3d(0, 0, 0);
}
}
/* There should be no more than 5 elements in a page */
.page:not([hidden='true']) > *:nth-child(2):not(:has(.delay-animation)) {
animation-delay: 0.2s;
}
.page:not([hidden='true']) > *:nth-child(3),
.delay-animation:nth-child(1) {
animation-delay: 0.4s;
}
.page:not([hidden='true']) > *:nth-child(4),
.delay-animation:nth-child(2) {
animation-delay: 0.6s;
}
.page:not([hidden='true']) > *:nth-child(5),
.delay-animation:nth-child(3),
.delay-animation-2:nth-child(1) {
animation-delay: 0.8s;
}
.page:not([hidden='true']) > *:nth-child(6),
.delay-animation:nth-child(4),
.delay-animation-2:nth-child(2) {
animation-delay: 1s;
}
#welcome {
& h1 {
animation-duration: 0.8s !important;
}
}
.card h3 {
margin-top: 10px;
}
#circular-progress {
--size: 220px;
--half-size: calc(var(--size) / 2);
--stroke-width: 20px;
--radius: calc((var(--size) - var(--stroke-width)) / 2);
--circumference: calc(var(--radius) * pi * 2);
--dash: calc((var(--progress) * var(--circumference)) / 100);
position: absolute;
top: 15px;
right: 10px;
width: 55px;
height: 40px;
}
#circular-progress circle {
cx: var(--half-size);
cy: var(--half-size);
r: var(--radius);
stroke-width: var(--stroke-width);
fill: none;
stroke-linecap: round;
}
#circular-progress circle.bg {
stroke: transparent;
}
#circular-progress circle.fg {
transform: rotate(-90deg);
transform-origin: var(--half-size) var(--half-size);
stroke-dasharray: var(--dash) calc(var(--circumference) - var(--dash));
transition: stroke-dasharray 0.3s linear 0s;
stroke: var(--zen-branding-coral);
}
#colorListWrapper {
display: flex;
align-items: center;
}
#colorListWrapper > div {
border-radius: 999px;
height: 20px;
width: 20px;
border: 3px solid transparent;
margin: 0 5px;
}
#colorListWrapper > div.selected {
border: 3px solid light-dark(#000, #fff);
}
#welcome,
#thanks {
justify-content: center;
}
#themeList {
display: flex;
flex-wrap: nowrap;
}
#themeList > svg {
border: 3px solid transparent;
border-radius: 15px;
height: -moz-available;
}
#themeList > svg.selected {
border: 3px solid var(--zen-colors-primary);
}
#searchList.cardGroup {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
#searchList .card {
width: -moz-available !important;
margin: 0;
display: flex;
flex-direction: row;
border-radius: 15px;
& h3 {
text-align: start;
margin: 0;
margin-left: 20px;
}
&.selected {
transform: scale(1.01);
}
& img {
width: 30px;
height: 30px;
border-radius: 15px;
}
}

View File

@@ -1,186 +0,0 @@
<!--
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/.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="color-scheme" content="light dark">
<meta name="referrer" content="no-referrer" />
<linkset>
<link
rel="stylesheet"
type="text/css"
href="chrome://global/skin/in-content/common.css"
/>
<link rel="stylesheet" href="chrome://global/skin/global.css" />
<link
rel="stylesheet"
href="chrome://browser/content/zen-welcome/welcome.css"
/>
<link
rel="stylesheet"
href="chrome://browser/content/zen-styles/zen-branding.css"
/>
<link rel="localization" href="branding/brand.ftl" />
<link rel="localization" href="browser/zen-welcome.ftl" />
</linkset>
<script src="chrome://browser/content/zenThemeModifier.js"></script>
</head>
<body class="gradient-background">
<img id="zen-logo" src="chrome://branding/content/about-logo.png" />
<div id="main-view">
<div class="page" id="welcome">
<h1 class="zen-branding-title" data-l10n-id="welcome-dialog-welcome-title-part-1"></h1>
<h1 class="zen-branding-title" data-l10n-id="welcome-dialog-welcome-title-part-2"></h1>
</div>
<div class="page page-split" id="import">
<div>
<h1 data-l10n-id="welcome-dialog-import"></h1>
<p data-l10n-id="welcome-dialog-import-subtext"></p>
</div>
<button
id="importBrowser"
data-l10n-id="welcome-dialog-import-action"
></button>
</div>
<div class="page page-split" id="theme">
<div>
<h1 data-l10n-id="welcome-dialog-theme"></h1>
<p data-l10n-id="welcome-dialog-theme-subtext"></p>
</div>
<div>
<h2 data-l10n-id="welcome-dialog-theme-header-1" class="delay-animation"></h2>
<div id="colorListWrapper" class="delay-animation">
</div>
<h2 data-l10n-id="welcome-dialog-theme-header-2" class="delay-animation"></h2>
<div id="themeList" class="cardGroup">
<svg viewBox="0 0 700 700" fill="none" xmlns="http://www.w3.org/2000/svg" class="delay-animation-2">
<g clip-path="url(#clip0_404_2706)">
<rect width="700" height="700" fill="#F4F4F4"/>
<g filter="url(#filter0_d_404_2706)">
<path d="M107 130C107 103.49 128.49 82 155 82H700V738H107V130Z" fill="white"/>
<path d="M155 82.5H699.5V737.5H107.5V130C107.5 103.766 128.766 82.5 155 82.5Z" stroke="black" stroke-opacity="0.2"/>
</g>
<mask id="path-3-inside-1_404_2706" fill="white">
<path d="M257 83H700V701H257V83Z"/>
</mask>
<path d="M257 83H700V701H257V83Z" fill="#F1F1F1"/>
<path d="M258 701V83H256V701H258Z" fill="black" fill-opacity="0.1" mask="url(#path-3-inside-1_404_2706)"/>
</g>
<defs>
<filter id="filter0_d_404_2706" x="103" y="82" width="601" height="664" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_404_2706"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_404_2706" result="shape"/>
</filter>
<clipPath id="clip0_404_2706">
<rect width="700" height="700" fill="white"/>
</clipPath>
</defs>
</svg>
<svg viewBox="0 0 700 700" fill="none" xmlns="http://www.w3.org/2000/svg" class="delay-animation-2">
<g clip-path="url(#clip0_404_2709)">
<rect width="700" height="700" fill="#515151"/>
<g filter="url(#filter0_d_404_2709)">
<path d="M107 130C107 103.49 128.49 82 155 82H700V727H107V130Z" fill="#717171"/>
<path d="M155 82.5H699.5V726.5H107.5V130C107.5 103.766 128.766 82.5 155 82.5Z" stroke="white" stroke-opacity="0.57"/>
</g>
<mask id="path-3-inside-1_404_2709" fill="white">
<path d="M257 83H700V701H257V83Z"/>
</mask>
<path d="M257 83H700V701H257V83Z" fill="#565656"/>
<path d="M258 701V83H256V701H258Z" fill="black" fill-opacity="0.1" mask="url(#path-3-inside-1_404_2709)"/>
</g>
<defs>
<filter id="filter0_d_404_2709" x="103" y="82" width="601" height="653" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_404_2709"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_404_2709" result="shape"/>
</filter>
<clipPath id="clip0_404_2709">
<rect width="700" height="700" fill="white"/>
</clipPath>
</defs>
</svg>
</div>
</div>
</div>
<div class="page page-split" id="layout">
<div>
<h1 data-l10n-id="welcome-dialog-layout"></h1>
<p data-l10n-id="welcome-dialog-layout-subtext"></p>
</div>
<div id="layoutList" class="cardGroup">
<hbox layout="single" class="selected delay-animation">
<img src="chrome://browser/content/zen-images/layouts/single-toolbar.png" />
<p data-l10n-id="welcome-dialog-layout-single-toolbar"></p>
</hbox>
<hbox layout="multiple" class="delay-animation">
<img src="chrome://browser/content/zen-images/layouts/multiple-toolbar.png" />
<p data-l10n-id="welcome-dialog-layout-multiple-toolbar"></p>
</hbox>
<hbox layout="collapsed" class="delay-animation">
<img src="chrome://browser/content/zen-images/layouts/collapsed.png" />
<p data-l10n-id="welcome-dialog-layout-collapsed-toolbar"></p>
</hbox>
</div>
</div>
<div class="page page-split" id="search">
<div>
<h1 data-l10n-id="welcome-dialog-search"></h1>
<p data-l10n-id="welcome-dialog-search-subtext"></p>
</div>
<div>
<div id="searchList" class="cardGroup"></div>
</div>
</div>
<div class="page" id="thanks">
<h1 class="zen-branding-title" data-l10n-id="welcome-dialog-thanks-title-part-1"></h1>
<h1 class="zen-branding-title" data-l10n-id="welcome-dialog-thanks-title-part-2"></h1>
</div>
<div id="buttons-footer">
<button
id="back"
data-l10n-id="welcome-dialog-back-action"
disabled
></button>
<button
id="next"
class="primary"
data-l10n-id="welcome-dialog-next-action"
></button>
</div>
</div>
<svg
width="250" height="250" viewBox="0 0 250 250"
id="circular-progress" style="--progress: 50"
>
<circle class="bg"></circle>
<circle class="fg"></circle>
</svg>
<script src="./welcome.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>
</body>
</html>

View File

@@ -1,354 +0,0 @@
// 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/.
const { XPCOMUtils } = ChromeUtils.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetters(this, {
AddonManager: 'resource://gre/modules/AddonManager.jsm',
MigrationUtils: 'resource:///modules/MigrationUtils.jsm',
});
ChromeUtils.defineModuleGetter(this, 'ExtensionSettingsStore', 'resource://gre/modules/ExtensionSettingsStore.jsm');
Services.scriptloader.loadSubScript('chrome://browser/content/ZenUIManager.mjs');
const kWelcomeSeenPref = 'zen.welcome-screen.seen';
// =============================================================================
// Util stuff copied from browser/components/preferences/search.js
class EngineStore {
constructor() {
this._engines = [];
}
async init() {
const visibleEngines = await Services.search.getVisibleEngines();
this.initSpecificEngine(visibleEngines);
}
getEngine() {
return this._engines;
}
initSpecificEngine(engines) {
for (const engine of engines) {
try {
this._engines.push(this._cloneEngine(engine));
} catch (e) {
// Ignore engines that throw an exception when cloning.
console.error(e);
}
}
}
getEngineByName(name) {
return this._engines.find((engine) => engine.name == name);
}
_cloneEngine(aEngine) {
const clonedObj = {};
for (const i of ['name', 'alias', '_iconURI', 'hidden']) {
clonedObj[i] = aEngine[i];
}
clonedObj.originalEngine = aEngine;
return clonedObj;
}
async getDefaultEngine() {
let engineName = await Services.search.getDefault();
return this.getEngineByName(engineName._name);
}
async setDefaultEngine(engine) {
await Services.search.setDefault(engine.originalEngine, Ci.nsISearchService.CHANGE_REASON_USER);
}
}
// =============================================================================
const sleep = (duration) => new Promise((resolve) => setTimeout(resolve, duration));
class Page {
/**
* A basic controller for individual pages
* @param {string} id The id of the element that represents this page.
*/
constructor(id) {
this.element = document.getElementById(id);
}
/**
*
* @param {Pages} pages The pages wrapper
*/
setPages(pages) {
this.pages = pages;
}
hide() {
this.element.setAttribute('hidden', 'true');
}
show() {
this.element.removeAttribute('hidden');
}
}
class Themes extends Page {
constructor(id) {
super(id);
this.loadThemes();
}
async loadThemes() {
window.addEventListener('DOMContentLoaded', this.setColorBar);
await sleep(1000);
const themes = (await AddonManager.getAddonsByTypes(['theme'])).filter((theme) => theme.id !== 'default-theme@mozilla.org');
const themeList = document.getElementById('themeList');
const themeElements = ['firefox-compact-light@mozilla.org', 'firefox-compact-dark@mozilla.org'];
themeElements.forEach((theme, i) => {
let container = themeList.children[i];
container.addEventListener(
'click',
(() => {
if (container.hasAttribute('disabled')) {
return;
}
for (const el of themeList.children) {
el.classList.remove('selected');
}
container.classList.add('selected');
themes.find((t) => t.id === theme).enable();
}).bind(this, i, container, theme)
);
if (themes.find((t) => t.id === theme).isActive) {
container.classList.add('selected');
}
});
}
setColorBar() {
const colorList = document.getElementById('colorListWrapper');
const colors = ['#aac7ff', '#74d7cb', '#a0d490', '#dec663', '#ffb787', '#ffb1c0', '#ddbfc3', '#f6b0ea', '#d4bbff'];
colors.forEach((color) => {
const container = document.createElement('div');
container.classList.add('color');
container.style.backgroundColor = color;
container.setAttribute('data-color', color);
container.addEventListener(
'click',
(() => {
Services.prefs.setStringPref('zen.theme.accent-color', color);
colorList.querySelectorAll('.selected').forEach((el) => el.classList.remove('selected'));
container.classList.add('selected');
}).bind(this, color, container)
);
colorList.appendChild(container);
});
}
}
class Layout extends Page {
constructor(id) {
super(id);
this.loadLayouts();
}
loadLayouts() {
const kExtendedSidebar = 'zen.view.sidebar-expanded';
const kSingleToolbar = 'zen.view.use-single-toolbar';
for (const layout of document.getElementById('layoutList').children) {
layout.addEventListener('click', () => {
if (layout.hasAttribute('disabled')) {
return;
}
for (const el of document.getElementById('layoutList').children) {
el.classList.remove('selected');
}
layout.classList.add('selected');
Services.prefs.setBoolPref(kExtendedSidebar, layout.getAttribute('layout') != 'collapsed');
Services.prefs.setBoolPref(kSingleToolbar, layout.getAttribute('layout') == 'single');
});
}
}
}
class Thanks extends Page {
constructor(id) {
super(id);
// Thanks :)
}
}
class Search extends Page {
constructor(id) {
super(id);
this.store = new EngineStore();
this.searchList = [];
this.loadSearch();
}
async loadSearch() {
await sleep(1100);
await this.store.init();
const defaultEngine = await Services.search.getDefault();
const searchElements = document.getElementById('searchList');
this.store.getEngine().forEach(async (search) => {
const container = await this.loadSpecificSearch(search, defaultEngine);
searchElements.appendChild(container);
this.searchList.push(container);
});
}
/**
* @returns {HTMLDivElement}
*/
async loadSpecificSearch(search, defaultSearch) {
const container = document.createElement('div');
container.classList.add('card');
container.classList.add('card-no-hover');
if (search.name == defaultSearch._name) {
container.classList.add('selected');
}
container.addEventListener('click', () => {
this.searchList.forEach((el) => el.classList.remove('selected'));
container.classList.add('selected');
this.store.setDefaultEngine(search);
});
const img = document.createElement('img');
img.src = await search.originalEngine.getIconURL();
const name = document.createElement('h3');
name.textContent = search.name;
container.appendChild(img);
container.appendChild(name);
return container;
}
}
class Import extends Page {
constructor(id) {
super(id);
const importButton = document.getElementById('importBrowser');
importButton.addEventListener('click', async () => {
MigrationUtils.showMigrationWizard(window, {
zenBlocking: true,
});
});
}
}
class Pages {
/**
* A wrapper around all pages
* @param {Page[]} pages The pages
*/
constructor(pages) {
this.pages = pages;
this.currentPage = 0;
this.pages.forEach((page) => page.setPages(this));
this._displayCurrentPage();
this.nextEl = document.getElementById(`next`);
this.prevEl = document.getElementById(`back`);
this.nextEl.addEventListener('click', () => {
this.next();
this.prevEl.removeAttribute('disabled');
});
this.prevEl.addEventListener('click', () => {
this.currentPage--;
this._displayCurrentPage();
if (this.pages.currentPage === 1) {
this.prevEl.setAttribute('disabled', 'true');
}
for (const button of document.getElementById('buttons-footer').children) {
button.style.display = 'none';
// Re-animate the buttons
setTimeout(() => {
button.style.removeProperty('display');
});
}
});
}
next() {
this.currentPage++;
document.getElementById('main-view').setAttribute('data-page', this.currentPage);
if (this.currentPage >= this.pages.length) {
// We can use internal js apis to close the window. We also want to set
// the settings api for welcome seen to false to stop it showing again
Services.prefs.setBoolPref(kWelcomeSeenPref, true);
close();
return;
}
for (const button of document.getElementById('buttons-footer').children) {
button.style.display = 'none';
// Re-animate the buttons
setTimeout(() => {
button.style.removeProperty('display');
});
}
this._displayCurrentPage();
}
_displayCurrentPage() {
let progress = document.getElementById('circular-progress');
progress.style.setProperty('--progress', ((this.currentPage + 1) / this.pages.length) * 100);
for (const page of this.pages) {
page.hide();
}
if (this.currentPage >= 1) {
document.body.classList.remove('gradient-background');
} else {
document.body.classList.add('gradient-background');
}
this.pages[this.currentPage].show();
}
}
const pages = new Pages([
new Page('welcome'),
new Themes('theme'),
new Layout('layout'),
new Import('import'),
new Search('search'),
new Thanks('thanks'),
]);