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:
Punam Dahiya 2020-02-27 18:52:46 +00:00
parent 339fd6a4e3
commit 70fe96edd1
15 changed files with 787 additions and 2 deletions

View file

@ -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/

View file

@ -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/**",

View file

@ -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;
},

View file

@ -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
}]
};
/***/ })
/******/ ]);

View file

@ -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; }

View file

@ -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>

View file

@ -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"));

View file

@ -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;
}
}

View file

@ -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>
);
}
}

View file

@ -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>
);
};

View 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,
},
],
};

View file

@ -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)

View file

@ -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/ .",

View 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)],
});

View file

@ -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