forked from mirrors/gecko-dev
Bug 1616370 - Simplified welcome page r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D63406 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
339fd6a4e3
commit
70fe96edd1
15 changed files with 787 additions and 2 deletions
|
|
@ -47,6 +47,7 @@ browser/extensions/pdfjs/content/web
|
|||
browser/components/pocket/content/panels/js/tmpl.js
|
||||
|
||||
# Ignore newtab files
|
||||
browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js
|
||||
browser/components/newtab/data/
|
||||
browser/components/newtab/logs/
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ module.exports = {
|
|||
{
|
||||
// These files use fluent-dom to insert content
|
||||
"files": [
|
||||
"content-src/aboutwelcome/components/HeroText.jsx",
|
||||
"content-src/asrouter/templates/OnboardingMessage/**",
|
||||
"content-src/asrouter/templates/FirstRun/**",
|
||||
"content-src/asrouter/templates/Trailhead/**",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
"use strict";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
|
@ -20,6 +24,17 @@ ChromeUtils.defineModuleGetter(
|
|||
"resource:///modules/AboutNewTab.jsm"
|
||||
);
|
||||
|
||||
const PREF_SEPARATE_ABOUT_WELCOME = "browser.aboutwelcome.enabled";
|
||||
const SEPARATE_ABOUT_WELCOME_URL =
|
||||
"resource://activity-stream/aboutwelcome/aboutwelcome.html";
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"isSeparateAboutWelcome",
|
||||
PREF_SEPARATE_ABOUT_WELCOME,
|
||||
false
|
||||
);
|
||||
|
||||
const TOPIC_APP_QUIT = "quit-application-granted";
|
||||
const TOPIC_CONTENT_DOCUMENT_INTERACTIVE = "content-document-interactive";
|
||||
|
||||
|
|
@ -142,6 +157,14 @@ AboutNewTabService.prototype = {
|
|||
break;
|
||||
}
|
||||
|
||||
// Bail out early for separate about:welcome URL
|
||||
if (
|
||||
isSeparateAboutWelcome &&
|
||||
win.location.pathname.includes("welcome")
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
const onLoaded = () => {
|
||||
const debugString = this._activityStreamDebug ? "-dev" : "";
|
||||
|
||||
|
|
@ -254,6 +277,9 @@ AboutNewTabService.prototype = {
|
|||
* This is calculated in the same way the default URL is.
|
||||
*/
|
||||
get welcomeURL() {
|
||||
if (isSeparateAboutWelcome) {
|
||||
return SEPARATE_ABOUT_WELCOME_URL;
|
||||
}
|
||||
return this.defaultURL;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,448 @@
|
|||
/*!
|
||||
*
|
||||
* NOTE: This file is generated by webpack from aboutwelcome.jsx
|
||||
* using the npm bundle task.
|
||||
*
|
||||
*/
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) {
|
||||
/******/ if(mode & 1) value = __webpack_require__(value);
|
||||
/******/ if(mode & 8) return value;
|
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
||||
/******/ var ns = Object.create(null);
|
||||
/******/ __webpack_require__.r(ns);
|
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
||||
/******/ return ns;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
||||
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var _components_HeroText__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
||||
/* harmony import */ var _components_FxCards__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(7);
|
||||
/* 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/. */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||
sendTelemetry(ping) {// TBD: Handle telemetry messages
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
props
|
||||
} = this;
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "trailheadCards"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "trailheadCardsInner"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_HeroText__WEBPACK_IMPORTED_MODULE_2__["HeroText"], {
|
||||
title: props.title,
|
||||
subtitle: props.subtitle
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_FxCards__WEBPACK_IMPORTED_MODULE_3__["FxCards"], {
|
||||
cards: props.cards,
|
||||
sendTelemetry: this.sendTelemetry
|
||||
})));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AboutWelcome.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__["DEFAULT_WELCOME_CONTENT"];
|
||||
react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render(react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AboutWelcome, null), document.getElementById("root"));
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = React;
|
||||
|
||||
/***/ }),
|
||||
/* 2 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = ReactDOM;
|
||||
|
||||
/***/ }),
|
||||
/* 3 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HeroText", function() { return HeroText; });
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_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 HeroText = props => {
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h1", {
|
||||
className: "welcome-title",
|
||||
"data-l10n-id": props.title.string_id
|
||||
}), props.subtitle && props.subtitle.string_id && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", {
|
||||
className: "welcome-subtitle",
|
||||
"data-l10n-id": props.subtitle.string_id
|
||||
}));
|
||||
};
|
||||
|
||||
/***/ }),
|
||||
/* 4 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FxCards", function() { return FxCards; });
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var _asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
||||
/* harmony import */ var _asrouter_templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7);
|
||||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
|
||||
/* 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/. */
|
||||
|
||||
|
||||
|
||||
|
||||
class FxCards extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||
onCardAction(action) {
|
||||
let actionUpdates = {};
|
||||
let UTMTerm = "utm_term_separate_welcome";
|
||||
|
||||
if (action.type === "OPEN_URL") {
|
||||
let url = new URL(action.data.args);
|
||||
Object(_asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_1__["addUtmParams"])(url, UTMTerm);
|
||||
actionUpdates = {
|
||||
data: { ...action.data,
|
||||
args: url.toString()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].handleUserAction({
|
||||
data: { ...action,
|
||||
...actionUpdates
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
props
|
||||
} = this;
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: `trailheadCardGrid show`
|
||||
}, props.cards.map(card => react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_asrouter_templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_2__["OnboardingCard"], _extends({
|
||||
key: card.id,
|
||||
message: card,
|
||||
className: "trailheadCard",
|
||||
sendUserActionTelemetry: props.sendTelemetry,
|
||||
onAction: this.onCardAction,
|
||||
UISurface: "ABOUT_WELCOME"
|
||||
}, card)))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
/* 5 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BASE_PARAMS", function() { return BASE_PARAMS; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addUtmParams", function() { return addUtmParams; });
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* BASE_PARAMS keys/values can be modified from outside this file
|
||||
*/
|
||||
const BASE_PARAMS = {
|
||||
utm_source: "activity-stream",
|
||||
utm_campaign: "firstrun",
|
||||
utm_medium: "referral"
|
||||
};
|
||||
/**
|
||||
* Takes in a url as a string or URL object and returns a URL object with the
|
||||
* utm_* parameters added to it. If a URL object is passed in, the paraemeters
|
||||
* are added to it (the return value can be ignored in that case as it's the
|
||||
* same object).
|
||||
*/
|
||||
|
||||
function addUtmParams(url, utmTerm) {
|
||||
let returnUrl = url;
|
||||
|
||||
if (typeof returnUrl === "string") {
|
||||
returnUrl = new URL(url);
|
||||
}
|
||||
|
||||
Object.keys(BASE_PARAMS).forEach(key => {
|
||||
returnUrl.searchParams.append(key, BASE_PARAMS[key]);
|
||||
});
|
||||
returnUrl.searchParams.append("utm_term", utmTerm);
|
||||
return returnUrl;
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
/* 6 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OnboardingCard", function() { return OnboardingCard; });
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_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/. */
|
||||
|
||||
class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
const {
|
||||
props
|
||||
} = this;
|
||||
const ping = {
|
||||
event: "CLICK_BUTTON",
|
||||
message_id: props.id,
|
||||
id: props.UISurface
|
||||
};
|
||||
props.sendUserActionTelemetry(ping);
|
||||
props.onAction(props.content.primary_button.action, props.message);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
content
|
||||
} = this.props;
|
||||
const className = this.props.className || "onboardingMessage";
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: className
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: `onboardingMessageImage ${content.icon}`
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "onboardingContent"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", {
|
||||
className: "onboardingTitle",
|
||||
"data-l10n-id": content.title.string_id
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", {
|
||||
className: "onboardingText",
|
||||
"data-l10n-id": content.text.string_id
|
||||
})), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
|
||||
className: "onboardingButtonContainer"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
|
||||
"data-l10n-id": content.primary_button.label.string_id,
|
||||
className: "button onboardingButton",
|
||||
onClick: this.onClick
|
||||
}))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
/* 7 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AboutWelcomeUtils", function() { return AboutWelcomeUtils; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_WELCOME_CONTENT", function() { return DEFAULT_WELCOME_CONTENT; });
|
||||
/* 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 AboutWelcomeUtils = {
|
||||
handleUserAction({
|
||||
data: action
|
||||
}) {
|
||||
switch (action.type) {
|
||||
case "OPEN_URL":
|
||||
window.open(action.data.args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
const DEFAULT_WELCOME_CONTENT = {
|
||||
title: {
|
||||
string_id: "onboarding-welcome-header"
|
||||
},
|
||||
subtitle: {
|
||||
string_id: "onboarding-fullpage-welcome-subheader"
|
||||
},
|
||||
cards: [{
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-data-sync-title"
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-data-sync-text2"
|
||||
},
|
||||
icon: "devices",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-data-sync-button2"
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
addFlowParams: true,
|
||||
data: {
|
||||
args: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=activity-stream-firstrun&style=trailhead",
|
||||
where: "tabshifted"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
id: "TRAILHEAD_CARD_2",
|
||||
order: 1,
|
||||
blockOnClick: false
|
||||
}, {
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-firefox-monitor-title"
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-firefox-monitor-text2"
|
||||
},
|
||||
icon: "ffmonitor",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-firefox-monitor-button"
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://monitor.firefox.com/",
|
||||
where: "tabshifted"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
id: "TRAILHEAD_CARD_3",
|
||||
order: 2,
|
||||
blockOnClick: false
|
||||
}, {
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-mobile-phone-title"
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-mobile-phone-text"
|
||||
},
|
||||
icon: "mobile",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-mobile-phone-button"
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://www.mozilla.org/firefox/mobile/",
|
||||
where: "tabshifted"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
id: "TRAILHEAD_CARD_6",
|
||||
order: 6,
|
||||
blockOnClick: false
|
||||
}]
|
||||
};
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* 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/. */
|
||||
body {
|
||||
--grey-subtitle: $grey-60; }
|
||||
|
||||
.welcome-container {
|
||||
background: var(--trailhead-cards-background-color); }
|
||||
|
||||
.trailheadCardGrid {
|
||||
margin-top: 32px; }
|
||||
|
||||
.trailheadCards .welcome-title {
|
||||
margin-bottom: 5px;
|
||||
line-height: 52px; }
|
||||
|
||||
.trailheadCards .welcome-subtitle {
|
||||
font-size: 28px;
|
||||
font-weight: 200;
|
||||
margin: 6px 0 0;
|
||||
color: var(--grey-subtitle);
|
||||
line-height: 42px; }
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<!-- 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>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src resource: chrome:;">
|
||||
<title data-l10n-id="onboarding-welcome-header"></title>
|
||||
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png">
|
||||
<link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css">
|
||||
<link rel="stylesheet" href="resource://activity-stream/aboutwelcome/aboutwelcome.css">
|
||||
<link rel="localization" href="branding/brand.ftl"/>
|
||||
<link rel="localization" href="browser/branding/sync-brand.ftl"/>
|
||||
<link rel="localization" href="browser/branding/brandings.ftl"/>
|
||||
<link rel="localization" href="browser/newtab/onboarding.ftl"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" class="welcome-container" role="presentation">
|
||||
</div>
|
||||
<script src="resource://activity-stream/vendor/react.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react-dom.js"></script>
|
||||
<script src="resource://activity-stream/aboutwelcome/aboutwelcome.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { HeroText } from "./components/HeroText";
|
||||
import { FxCards } from "./components/FxCards";
|
||||
import { DEFAULT_WELCOME_CONTENT } from "../lib/aboutwelcome-utils";
|
||||
|
||||
class AboutWelcome extends React.PureComponent {
|
||||
sendTelemetry(ping) {
|
||||
// TBD: Handle telemetry messages
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
return (
|
||||
<div className="trailheadCards">
|
||||
<div className="trailheadCardsInner">
|
||||
<HeroText title={props.title} subtitle={props.subtitle} />
|
||||
<FxCards cards={props.cards} sendTelemetry={this.sendTelemetry} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AboutWelcome.defaultProps = DEFAULT_WELCOME_CONTENT;
|
||||
|
||||
ReactDOM.render(<AboutWelcome />, document.getElementById("root"));
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// sass-lint:disable no-css-comments
|
||||
/* 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/. */
|
||||
$grey-60: #4A4A4F;
|
||||
|
||||
body {
|
||||
--grey-subtitle: $grey-60;
|
||||
}
|
||||
|
||||
.welcome-container {
|
||||
background: var(--trailhead-cards-background-color);
|
||||
}
|
||||
|
||||
.trailheadCardGrid {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.trailheadCards {
|
||||
.welcome-title {
|
||||
margin-bottom: 5px;
|
||||
line-height: 52px;
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-size: 28px;
|
||||
font-weight: 200;
|
||||
margin: 6px 0 0;
|
||||
color: var(--grey-subtitle);
|
||||
line-height: 42px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from "react";
|
||||
import { addUtmParams } from "../../asrouter/templates/FirstRun/addUtmParams";
|
||||
import { OnboardingCard } from "../../asrouter/templates/OnboardingMessage/OnboardingMessage";
|
||||
import { AboutWelcomeUtils } from "../../lib/aboutwelcome-utils";
|
||||
|
||||
export class FxCards extends React.PureComponent {
|
||||
onCardAction(action) {
|
||||
let actionUpdates = {};
|
||||
let UTMTerm = "utm_term_separate_welcome";
|
||||
|
||||
if (action.type === "OPEN_URL") {
|
||||
let url = new URL(action.data.args);
|
||||
addUtmParams(url, UTMTerm);
|
||||
actionUpdates = { data: { ...action.data, args: url.toString() } };
|
||||
}
|
||||
|
||||
AboutWelcomeUtils.handleUserAction({
|
||||
data: { ...action, ...actionUpdates },
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={`trailheadCardGrid show`}>
|
||||
{props.cards.map(card => (
|
||||
<OnboardingCard
|
||||
key={card.id}
|
||||
message={card}
|
||||
className="trailheadCard"
|
||||
sendUserActionTelemetry={props.sendTelemetry}
|
||||
onAction={this.onCardAction}
|
||||
UISurface="ABOUT_WELCOME"
|
||||
{...card}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from "react";
|
||||
|
||||
export const HeroText = props => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<h1 className="welcome-title" data-l10n-id={props.title.string_id} />
|
||||
{props.subtitle && props.subtitle.string_id && (
|
||||
<h2
|
||||
className="welcome-subtitle"
|
||||
data-l10n-id={props.subtitle.string_id}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
104
browser/components/newtab/content-src/lib/aboutwelcome-utils.js
Normal file
104
browser/components/newtab/content-src/lib/aboutwelcome-utils.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* 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/. */
|
||||
|
||||
export const AboutWelcomeUtils = {
|
||||
handleUserAction({ data: action }) {
|
||||
switch (action.type) {
|
||||
case "OPEN_URL":
|
||||
window.open(action.data.args);
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_WELCOME_CONTENT = {
|
||||
title: {
|
||||
string_id: "onboarding-welcome-header",
|
||||
},
|
||||
subtitle: {
|
||||
string_id: "onboarding-fullpage-welcome-subheader",
|
||||
},
|
||||
cards: [
|
||||
{
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-data-sync-title",
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-data-sync-text2",
|
||||
},
|
||||
icon: "devices",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-data-sync-button2",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
addFlowParams: true,
|
||||
data: {
|
||||
args:
|
||||
"https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=activity-stream-firstrun&style=trailhead",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: "TRAILHEAD_CARD_2",
|
||||
order: 1,
|
||||
blockOnClick: false,
|
||||
},
|
||||
{
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-firefox-monitor-title",
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-firefox-monitor-text2",
|
||||
},
|
||||
icon: "ffmonitor",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-firefox-monitor-button",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://monitor.firefox.com/",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: "TRAILHEAD_CARD_3",
|
||||
order: 2,
|
||||
blockOnClick: false,
|
||||
},
|
||||
{
|
||||
content: {
|
||||
title: {
|
||||
string_id: "onboarding-mobile-phone-title",
|
||||
},
|
||||
text: {
|
||||
string_id: "onboarding-mobile-phone-text",
|
||||
},
|
||||
icon: "mobile",
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "onboarding-mobile-phone-button",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://www.mozilla.org/firefox/mobile/",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
id: "TRAILHEAD_CARD_6",
|
||||
order: 6,
|
||||
blockOnClick: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -6,6 +6,7 @@ browser.jar:
|
|||
% resource activity-stream %res/activity-stream/ contentaccessible=yes
|
||||
res/activity-stream/lib/ (./lib/*)
|
||||
res/activity-stream/common/ (./common/*)
|
||||
res/activity-stream/aboutwelcome/ (./aboutwelcome/content/*)
|
||||
res/activity-stream/vendor/Redux.jsm (./vendor/Redux.jsm)
|
||||
res/activity-stream/vendor/react.js (./vendor/react.js)
|
||||
res/activity-stream/vendor/react-dom.js (./vendor/react-dom.js)
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
"mochitest-debug": "(cd $npm_package_config_mc_dir && ./mach mochitest --jsdebugger browser/components/newtab/test/browser)",
|
||||
"bundle": "npm-run-all bundle:*",
|
||||
"bundle:webpack": "webpack --config webpack.system-addon.config.js",
|
||||
"bundle:css": "node-sass content-src/styles -o css",
|
||||
"bundle:welcomeBundle": "webpack --config webpack.aboutwelcome.config.js",
|
||||
"bundle:css": "node-sass content-src/styles -o css && node-sass content-src/aboutwelcome -o aboutwelcome/content",
|
||||
"bundle:html": "rimraf prerendered && node ./bin/render-activity-stream-html.js",
|
||||
"buildmc": "npm-run-all buildmc:*",
|
||||
"prebuildmc": "rimraf $npm_package_config_mc_dir/browser/components/newtab/",
|
||||
|
|
@ -108,6 +109,7 @@
|
|||
"startmc:watch": "npm run watchmc",
|
||||
"watchmc": "npm-run-all --parallel watchmc:*",
|
||||
"watchmc:webpack": "npm run bundle:webpack -- --env.development -w",
|
||||
"watchmc:welcomeBundle": "npm run bundle:welcomeBundle -- --env.development -w",
|
||||
"watchmc:css": "npm run bundle:css && npm run bundle:css -- --source-map-embed --source-map-contents -w",
|
||||
"importmc": "npm-run-all importmc:*",
|
||||
"importmc:src": "rsync --exclude-from .mcignore -a $npm_package_config_mc_dir/browser/components/newtab/ .",
|
||||
|
|
|
|||
24
browser/components/newtab/webpack.aboutwelcome.config.js
Normal file
24
browser/components/newtab/webpack.aboutwelcome.config.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* 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 path = require("path");
|
||||
const config = require("./webpack.system-addon.config.js");
|
||||
const webpack = require("webpack");
|
||||
const absolute = relPath => path.join(__dirname, relPath);
|
||||
const banner = `
|
||||
NOTE: This file is generated by webpack from aboutwelcome.jsx
|
||||
using the npm bundle task.
|
||||
`;
|
||||
module.exports = Object.assign({}, config(), {
|
||||
entry: absolute("content-src/aboutwelcome/aboutwelcome.jsx"),
|
||||
output: {
|
||||
path: absolute("aboutwelcome/content"),
|
||||
filename: "aboutwelcome.bundle.js",
|
||||
},
|
||||
externals: {
|
||||
react: "React",
|
||||
"react-dom": "ReactDOM",
|
||||
},
|
||||
plugins: [new webpack.BannerPlugin(banner)],
|
||||
});
|
||||
|
|
@ -15,7 +15,8 @@ scripts:
|
|||
# bundle: Build all assets for activity stream
|
||||
bundle:
|
||||
webpack: webpack --config webpack.system-addon.config.js
|
||||
css: node-sass content-src/styles -o css
|
||||
css: node-sass content-src/styles -o css && node-sass content-src/aboutwelcome -o aboutwelcome/content
|
||||
welcomeBundle: webpack --config webpack.aboutwelcome.config.js
|
||||
html: rimraf prerendered && node ./bin/render-activity-stream-html.js
|
||||
|
||||
# buildmc: Export code to mozilla central
|
||||
|
|
@ -51,6 +52,7 @@ scripts:
|
|||
watchmc:
|
||||
_parallel: true
|
||||
webpack: =>bundle:webpack -- --env.development -w
|
||||
welcomeBundle: =>bundle:welcomeBundle -- --env.development -w
|
||||
css: =>bundle:css && =>bundle:css -- --source-map-embed --source-map-contents -w
|
||||
|
||||
# importmc: Import changes from mc to github repo
|
||||
|
|
|
|||
Loading…
Reference in a new issue