{
var _tabsToPin = [];
var _tabsToPinEssentials = [];
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 = `
`;
const fragment = window.MozXULElement.parseXULToFragment(XUL);
document.getElementById('browser').appendChild(fragment);
window.MozXULElement.insertFTLIfNeeded('browser/zen-welcome.ftl');
}
function openInitialPinTab() {
const tabs = ['https://reddit.com/r/zen_browser', 'https://x.com/zen_browser'];
for (const url of tabs) {
const tab = window.gBrowser.addTrustedTab(url, {
inBackground: true,
});
_tabsToPin.push(tab);
}
}
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.2, duration: 0.2 });
}
async fadeInTitles(page) {
const [title1, description1, description2] = await document.l10n.formatValues(page.text);
const titleElement = document.getElementById('zen-welcome-page-sidebar-content');
titleElement.innerHTML =
`${title1}${description1}` +
(description2 ? `${description2}` : '');
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.4 }),
}
);
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];
const promises = [this.fadeOutTitles(), this.fadeOutButtons()];
if (!previousPage.dontFadeOut) {
promises.push(this.fadeOutContent());
}
await Promise.all(promises);
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() {
ZenWorkspaces.reorganizeTabsAfterWelcome();
await animate('#zen-welcome-page-content', { x: [0, '100%'] }, { bounce: 0 });
document.getElementById('zen-welcome-page-content').remove();
await this.animHeart();
this._pinRemainingTabs();
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');
}
gZenUIManager.updateTabsToolbar();
await animate('#browser > *', { opacity: [0, 1] });
gZenUIManager.showToast('zen-welcome-finished');
}
_pinRemainingTabs() {
for (const tab of _tabsToPin) {
gBrowser.pinTab(tab);
}
for (const tab of _tabsToPinEssentials) {
gZenPinnedTabManager.addToEssentials(tab);
}
}
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);
sidebar.setAttribute('animate-heart', 'true');
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 = `
`;
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-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 = `
`;
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() {
const selectedTabs = document
.getElementById('zen-welcome-initial-essentials-browser-sidebar-essentials')
.querySelectorAll('.tabbrowser-tab[visuallyselected]');
for (const tab of selectedTabs) {
const url = tab.getAttribute('data-url');
const createdTab = window.gBrowser.addTrustedTab(url, {
inBackground: true,
});
_tabsToPinEssentials.push(createdTab);
}
openInitialPinTab();
},
},
{
text: [
{
id: 'zen-welcome-workspace-colors-title',
},
{
id: 'zen-welcome-workspace-colors-description',
},
],
buttons: [
{
l10n: 'zen-welcome-next-action',
onclick: async () => {
return true;
},
},
],
fadeIn() {
const anchor = document.createElement('div');
anchor.id = 'zen-welcome-workspace-colors-anchor';
document.getElementById('zen-welcome-page-content').appendChild(anchor);
gZenThemePicker.panel.setAttribute('noautohide', 'true');
gZenThemePicker.panel.setAttribute('consumeoutsideclicks', 'false');
gZenThemePicker.panel.addEventListener(
'popupshowing',
() => {
const panelRect = gZenThemePicker.panel.getBoundingClientRect();
// 20 is the shadow width * 2
anchor.style.height = panelRect.height - 20 + 'px';
anchor.style.width = panelRect.width - 20 + 'px';
},
{ once: true }
);
PanelMultiView.openPopup(gZenThemePicker.panel, anchor, {
position: 'overlap',
});
},
dontFadeOut: true,
async fadeOut() {
gZenThemePicker.panel.removeAttribute('noautohide');
gZenThemePicker.panel.removeAttribute('consumeoutsideclicks');
await animate(gZenThemePicker.panel, { opacity: [1, 0] });
gZenThemePicker.panel.hidePopup();
gZenThemePicker.panel.removeAttribute('style');
},
},
{
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 = `${title1}${title2}`;
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();
window.moveTo(
screen.availLeft + (screen.availWidth - outerWidth) / 2,
screen.availTop + (screen.availHeight - outerHeight) / 2
);
},
{ once: true }
);
}
function startZenWelcome() {
clearBrowserElements();
centerWindowOnScreen();
initializeZenWelcome();
animateInitialStage();
}
startZenWelcome();
}