mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 1675127 - Remove code from ASRouter that shows the triplets (3 cards) at the top of the newtab page r=k88hudson,pdahiya,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D97213
This commit is contained in:
parent
96a85ab8c6
commit
199f6ebb12
@ -65,7 +65,6 @@ function templateHTML(options) {
|
||||
<link rel="stylesheet" href="chrome://activity-stream/content/css/activity-stream.css" />
|
||||
</head>
|
||||
<body class="activity-stream">
|
||||
<div id="header-asrouter-container" role="presentation"></div>
|
||||
<div id="root"></div>
|
||||
<div id="footer-asrouter-container" role="presentation"></div>${
|
||||
options.noscripts ? "" : scriptRender
|
||||
|
@ -12,9 +12,7 @@ import { NEWTAB_DARK_THEME } from "content-src/lib/constants";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { SnippetsTemplates } from "./templates/template-manifest";
|
||||
import { FirstRun } from "./templates/FirstRun/FirstRun";
|
||||
|
||||
const TEMPLATES_ABOVE_PAGE = ["extended_triplets"];
|
||||
const TEMPLATES_BELOW_SEARCH = ["simple_below_search_snippet"];
|
||||
|
||||
// Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
|
||||
@ -40,9 +38,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
||||
|
||||
this.state = { message: {} };
|
||||
if (props.document) {
|
||||
this.headerPortal = props.document.getElementById(
|
||||
"header-asrouter-container"
|
||||
);
|
||||
this.footerPortal = props.document.getElementById(
|
||||
"footer-asrouter-container"
|
||||
);
|
||||
@ -169,16 +164,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
||||
}
|
||||
|
||||
clearMessage(id) {
|
||||
// Request new set of dynamic triplet cards when click on a card CTA clear
|
||||
// message and 'id' matches one of the cards in message bundle
|
||||
if (
|
||||
this.state.message &&
|
||||
this.state.message.bundle &&
|
||||
this.state.message.bundle.find(card => card.id === id)
|
||||
) {
|
||||
this.requestMessage();
|
||||
}
|
||||
|
||||
if (id === this.state.message.id) {
|
||||
this.setState({ message: {} });
|
||||
}
|
||||
@ -323,35 +308,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
renderFirstRun() {
|
||||
const { message } = this.state;
|
||||
if (TEMPLATES_ABOVE_PAGE.includes(message.template)) {
|
||||
return (
|
||||
<ImpressionsWrapper
|
||||
id="FIRST_RUN"
|
||||
message={this.state.message}
|
||||
sendImpression={this.sendImpression}
|
||||
shouldSendImpressionOnUpdate={shouldSendImpressionOnUpdate}
|
||||
// This helps with testing
|
||||
document={this.props.document}
|
||||
>
|
||||
<FirstRun
|
||||
document={this.props.document}
|
||||
message={message}
|
||||
sendUserActionTelemetry={this.sendUserActionTelemetry}
|
||||
executeAction={ASRouterUtils.executeAction}
|
||||
onBlockById={ASRouterUtils.blockById}
|
||||
onDismiss={this.onDismiss}
|
||||
fxaEndpoint={this.props.fxaEndpoint}
|
||||
appUpdateChannel={this.props.appUpdateChannel}
|
||||
fetchFlowParams={this.fetchFlowParams}
|
||||
/>
|
||||
</ImpressionsWrapper>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { message } = this.state;
|
||||
if (!message.id) {
|
||||
@ -360,9 +316,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
||||
const shouldRenderBelowSearch = TEMPLATES_BELOW_SEARCH.includes(
|
||||
message.template
|
||||
);
|
||||
const shouldRenderInHeader = TEMPLATES_ABOVE_PAGE.includes(
|
||||
message.template
|
||||
);
|
||||
|
||||
return shouldRenderBelowSearch ? (
|
||||
// Render special below search snippets in place;
|
||||
@ -370,15 +323,14 @@ export class ASRouterUISurface extends React.PureComponent {
|
||||
{this.renderSnippets()}
|
||||
</div>
|
||||
) : (
|
||||
// For onboarding, regular snippets etc. we should render
|
||||
// everything in our footer container.
|
||||
// For regular snippets etc. we should render everything in our footer
|
||||
// container.
|
||||
ReactDOM.createPortal(
|
||||
<>
|
||||
{this.renderPreviewBanner()}
|
||||
{this.renderFirstRun()}
|
||||
{this.renderSnippets()}
|
||||
</>,
|
||||
shouldRenderInHeader ? this.headerPortal : this.footerPortal
|
||||
this.footerPortal
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -21,24 +21,11 @@ export class ModalOverlayWrapper extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.props.document.addEventListener("keydown", this.onKeyDown);
|
||||
this.props.document.body.classList.add("modal-open");
|
||||
this.header = this.props.document.getElementById(
|
||||
"header-asrouter-container"
|
||||
);
|
||||
|
||||
if (this.header) {
|
||||
this.props.document.getElementById("root").classList.add("modal-height");
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.document.removeEventListener("keydown", this.onKeyDown);
|
||||
this.props.document.body.classList.remove("modal-open");
|
||||
|
||||
if (this.header) {
|
||||
this.props.document
|
||||
.getElementById("root")
|
||||
.classList.remove("modal-height");
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -59,13 +46,6 @@ export class ModalOverlayWrapper extends React.PureComponent {
|
||||
id={props.id}
|
||||
role="dialog"
|
||||
>
|
||||
{props.hasDismissIcon && (
|
||||
<button
|
||||
className="icon icon-dismiss"
|
||||
onClick={props.onClose}
|
||||
data-l10n-id="onboarding-cards-dismiss"
|
||||
/>
|
||||
)}
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
@ -74,24 +54,3 @@ export class ModalOverlayWrapper extends React.PureComponent {
|
||||
}
|
||||
|
||||
ModalOverlayWrapper.defaultProps = { document: global.document };
|
||||
|
||||
export class ModalOverlay extends React.PureComponent {
|
||||
render() {
|
||||
const { title, button_label } = this.props;
|
||||
return (
|
||||
<ModalOverlayWrapper onClose={this.props.onDismissBundle}>
|
||||
<h2> {title} </h2>
|
||||
{this.props.children}
|
||||
<div className="footer">
|
||||
<button
|
||||
className="button primary modalButton"
|
||||
onClick={this.props.onDismissBundle}
|
||||
>
|
||||
{" "}
|
||||
{button_label}{" "}
|
||||
</button>
|
||||
</div>
|
||||
</ModalOverlayWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,6 @@ $modal-scrollbar-z-index: 1100;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-height {
|
||||
// "Welcome header" has 40px of padding and 36px font size that get neglected using position absolute
|
||||
// causing this to visually collide with the newtab searchbar
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
.modalOverlayInner {
|
||||
min-width: min-content;
|
||||
width: 100%;
|
||||
@ -54,23 +48,6 @@ $modal-scrollbar-z-index: 1100;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.icon-dismiss {
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 0;
|
||||
padding: 20px;
|
||||
fill: $white;
|
||||
position: absolute;
|
||||
|
||||
&:hover {
|
||||
background-color: $trailhead-purple;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 1px dotted;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: $grey-60;
|
||||
text-align: center;
|
||||
|
@ -7,16 +7,3 @@ First run help onboard new users by showing relevant messaging on about:welcome
|
||||
A full-page multistep experience that shows up on first run since Fx80 with browser.aboutwelcome.enabled pref as true.
|
||||
|
||||
Setting browser.aboutwelcome.enabled to false make first run looks like about:newtab and hides about:welcome
|
||||
|
||||
## Triplets
|
||||
The cards that show up above the new tab content on the first instance of new tab. Setting browser.aboutwelcome.enabled to false and trailhead.firstrun.newtab.triplets to one of values below hides multistage welcome and takes user straight to triplets on opening about:welcome page
|
||||
|
||||
* supercharge - Shows Sync, Monitor and Mobile onboarding cards. Supported in 71+.
|
||||
* payoff - Shows Monitor, Facbook Container and Firefox Send onboarding cards. Supported in 71 only.
|
||||
* mutidevice - Shows Pocket, Send Tabs and Mobile onboarding cards. Supported in 71 only.
|
||||
* privacy - Shows Private Browsing, Tracking Protection and Lockwise. Supported in 71 only.
|
||||
|
||||
In 72+
|
||||
* static - same experience as ‘supercharge’ triplet - with Sync, Monitor and Mobile onboarding cards
|
||||
* dynamic - Dynamic triplets showing three onboarding cards (Sync, Monitor and Private Browsing) that gets swapped with preselected list of cards that satisfies targeting rules. Preselected cards supported are Send Tab, Mobile and Lockwise.
|
||||
* dynamic_chrome - Dynamic triplets showing three onboarding cards (Chrome switchers, Sync and Monitor) that gets swapped with preselected list of cards that satisfies targeting rules. Preselected cards supported are Private Browsing, Send Tab, Mobile and Lockwise.
|
||||
|
@ -28,7 +28,6 @@ Please note that some targeting attributes require stricter controls on the tele
|
||||
* [sync](#sync)
|
||||
* [topFrecentSites](#topfrecentsites)
|
||||
* [totalBookmarksCount](#totalbookmarkscount)
|
||||
* [trailheadTriplet](#trailheadtriplet)
|
||||
* [usesFirefoxSync](#usesfirefoxsync)
|
||||
* [isFxAEnabled](#isFxAEnabled)
|
||||
* [xpinstallEnabled](#xpinstallEnabled)
|
||||
@ -443,10 +442,6 @@ Total number of bookmarks.
|
||||
declare const totalBookmarksCount: number;
|
||||
```
|
||||
|
||||
### `trailheadTriplet`
|
||||
|
||||
(67.05+ only) Experiment branch for "triplet" study
|
||||
|
||||
### `usesFirefoxSync`
|
||||
|
||||
Does the user use Firefox sync?
|
||||
|
@ -1,129 +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/. */
|
||||
|
||||
import React from "react";
|
||||
import { Triplets } from "./Triplets";
|
||||
import { BASE_PARAMS } from "./addUtmParams";
|
||||
|
||||
// Note: should match the transition time on .trailheadCards in _Trailhead.scss
|
||||
const TRANSITION_LENGTH = 500;
|
||||
|
||||
export const FLUENT_FILES = [
|
||||
"branding/brand.ftl",
|
||||
"browser/branding/brandings.ftl",
|
||||
"browser/branding/sync-brand.ftl",
|
||||
"browser/newtab/onboarding.ftl",
|
||||
];
|
||||
|
||||
export const helpers = {
|
||||
addFluent(document) {
|
||||
FLUENT_FILES.forEach(file => {
|
||||
const link = document.head.appendChild(document.createElement("link"));
|
||||
link.href = file;
|
||||
link.rel = "localization";
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export class FirstRun extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.didLoadFlowParams = false;
|
||||
|
||||
this.state = {
|
||||
didUserClearTriplets: false,
|
||||
flowParams: undefined,
|
||||
};
|
||||
|
||||
this.closeTriplets = this.closeTriplets.bind(this);
|
||||
|
||||
helpers.addFluent(this.props.document);
|
||||
// Update utm campaign parameters by appending channel for
|
||||
// differentiating campaign in amplitude
|
||||
if (this.props.appUpdateChannel) {
|
||||
BASE_PARAMS.utm_campaign += `-${this.props.appUpdateChannel}`;
|
||||
}
|
||||
}
|
||||
|
||||
get UTMTerm() {
|
||||
const { message } = this.props;
|
||||
let UTMTerm = message.utm_term || "";
|
||||
|
||||
UTMTerm =
|
||||
message.utm_term && message.trailheadTriplet
|
||||
? `${message.utm_term}-${message.trailheadTriplet}`
|
||||
: UTMTerm;
|
||||
return UTMTerm;
|
||||
}
|
||||
|
||||
async fetchFlowParams() {
|
||||
const { fxaEndpoint, fetchFlowParams } = this.props;
|
||||
|
||||
if (fxaEndpoint && this.UTMTerm && !this.didLoadFlowParams) {
|
||||
this.didLoadFlowParams = true;
|
||||
const flowParams = await fetchFlowParams({
|
||||
...BASE_PARAMS,
|
||||
entrypoint: "activity-stream-firstrun",
|
||||
form_type: "email",
|
||||
utm_term: this.UTMTerm,
|
||||
});
|
||||
this.setState({ flowParams });
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchFlowParams();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
// In case we didn't have FXA info immediately, try again when we receive it.
|
||||
this.fetchFlowParams();
|
||||
}
|
||||
|
||||
closeTriplets() {
|
||||
this.setState({ didUserClearTriplets: true });
|
||||
|
||||
// Closing triplets should prevent any future extended triplets from showing up
|
||||
setTimeout(() => {
|
||||
this.props.onBlockById("EXTENDED_TRIPLETS_1");
|
||||
}, TRANSITION_LENGTH);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props, state, UTMTerm } = this;
|
||||
const { sendUserActionTelemetry, executeAction, message } = props;
|
||||
|
||||
const { didUserClearTriplets, flowParams } = state;
|
||||
|
||||
const hasTriplets = Boolean(message.bundle && message.bundle.length);
|
||||
const triplets = hasTriplets ? message.bundle : null;
|
||||
const isTripletsContainerVisible = hasTriplets && !didUserClearTriplets;
|
||||
|
||||
// Allow 1) falsy to not render a header 2) default welcome header 3) custom header
|
||||
const tripletsHeaderId =
|
||||
message.tripletsHeaderId === undefined
|
||||
? "onboarding-welcome-header"
|
||||
: message.tripletsHeaderId;
|
||||
|
||||
return (
|
||||
<>
|
||||
{hasTriplets ? (
|
||||
<Triplets
|
||||
document={props.document}
|
||||
cards={triplets}
|
||||
headerId={tripletsHeaderId}
|
||||
showCardPanel={isTripletsContainerVisible}
|
||||
hideContainer={this.closeTriplets}
|
||||
sendUserActionTelemetry={sendUserActionTelemetry}
|
||||
UTMTerm={`${UTMTerm}-card`}
|
||||
flowParams={flowParams}
|
||||
onAction={executeAction}
|
||||
onBlockById={props.onBlockById}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,96 +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/. */
|
||||
|
||||
import React from "react";
|
||||
import { OnboardingCard } from "../../templates/OnboardingMessage/OnboardingMessage";
|
||||
import { addUtmParams } from "./addUtmParams";
|
||||
|
||||
export class Triplets extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onCardAction = this.onCardAction.bind(this);
|
||||
this.onHideContainer = this.onHideContainer.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
global.document.body.classList.add("inline-onboarding");
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.document.body.classList.remove("inline-onboarding");
|
||||
}
|
||||
|
||||
onCardAction(action, message) {
|
||||
let actionUpdates = {};
|
||||
const { flowParams, UTMTerm } = this.props;
|
||||
|
||||
if (action.type === "OPEN_URL") {
|
||||
let url = new URL(action.data.args);
|
||||
addUtmParams(url, UTMTerm);
|
||||
|
||||
if (action.addFlowParams) {
|
||||
url.searchParams.append("device_id", flowParams.deviceId);
|
||||
url.searchParams.append("flow_id", flowParams.flowId);
|
||||
url.searchParams.append("flow_begin_time", flowParams.flowBeginTime);
|
||||
}
|
||||
|
||||
actionUpdates = { data: { ...action.data, args: url.toString() } };
|
||||
}
|
||||
|
||||
this.props.onAction({ ...action, ...actionUpdates });
|
||||
// Only block if message is in dynamic triplets experiment
|
||||
if (message.blockOnClick) {
|
||||
this.props.onBlockById(message.id, { preloadedOnly: true });
|
||||
}
|
||||
}
|
||||
|
||||
onHideContainer() {
|
||||
const { sendUserActionTelemetry, cards, hideContainer } = this.props;
|
||||
hideContainer();
|
||||
sendUserActionTelemetry({
|
||||
event: "DISMISS",
|
||||
id: "onboarding-cards",
|
||||
message_id: cards.map(m => m.id).join(","),
|
||||
action: "onboarding_user_event",
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
cards,
|
||||
headerId,
|
||||
showCardPanel,
|
||||
sendUserActionTelemetry,
|
||||
} = this.props;
|
||||
return (
|
||||
<div
|
||||
className={`trailheadCards ${showCardPanel ? "expanded" : "collapsed"}`}
|
||||
>
|
||||
<div className="trailheadCardsInner" aria-hidden={!showCardPanel}>
|
||||
{headerId && <h1 data-l10n-id={headerId} />}
|
||||
<div className={`trailheadCardGrid${showCardPanel ? " show" : ""}`}>
|
||||
{cards.map(card => (
|
||||
<OnboardingCard
|
||||
key={card.id}
|
||||
message={card}
|
||||
className="trailheadCard"
|
||||
sendUserActionTelemetry={sendUserActionTelemetry}
|
||||
onAction={this.onCardAction}
|
||||
UISurface="TRAILHEAD"
|
||||
{...card}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{showCardPanel && (
|
||||
<button
|
||||
className="icon icon-dismiss"
|
||||
onClick={this.onHideContainer}
|
||||
data-l10n-id="onboarding-cards-dismiss"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
.trailheadCards {
|
||||
background: var(--trailhead-cards-background-color);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
// Note: should match TRANSITION_LENGTH in FirstRun.jsx
|
||||
transition: max-height 0.5s $photon-easing;
|
||||
|
||||
// This is needed for the transition to work, but will cut off content at the smallest breakpoint
|
||||
@media (min-width: $break-point-medium) {
|
||||
max-height: 1000px;
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 200;
|
||||
margin: 0 0 40px;
|
||||
color: var(--trailhead-header-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.trailheadCardsInner {
|
||||
margin: auto;
|
||||
padding: 40px $section-horizontal-padding;
|
||||
|
||||
@media (min-width: $break-point-medium) {
|
||||
width: $wrapper-max-width-medium;
|
||||
}
|
||||
|
||||
@media (min-width: $break-point-large) {
|
||||
width: $wrapper-max-width-large;
|
||||
}
|
||||
|
||||
@media (min-width: $break-point-widest) {
|
||||
width: $wrapper-max-width-widest;
|
||||
}
|
||||
|
||||
.icon-dismiss {
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 15px;
|
||||
padding: 15px;
|
||||
opacity: 0.75;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--newtab-element-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.trailheadCardGrid {
|
||||
display: grid;
|
||||
grid-gap: $base-gutter;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s;
|
||||
transition-delay: 0.1s;
|
||||
grid-auto-rows: 1fr;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (min-width: $break-point-medium) {
|
||||
grid-template-columns: repeat(auto-fit, $card-width);
|
||||
}
|
||||
|
||||
@media (min-width: $break-point-widest) {
|
||||
grid-template-columns: repeat(auto-fit, $card-width-large);
|
||||
}
|
||||
}
|
||||
|
||||
.trailheadCard {
|
||||
position: relative;
|
||||
background: var(--newtab-card-background-color);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--newtab-card-shadow);
|
||||
|
||||
font-size: 13px;
|
||||
padding: 20px 20px 60px;
|
||||
|
||||
@media (max-width: 865px) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: $break-point-widest) {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.onboardingTitle {
|
||||
font-weight: normal;
|
||||
color: var(--newtab-text-primary-color);
|
||||
margin: 10px 0 4px;
|
||||
font-size: 15px;
|
||||
|
||||
@media (min-width: $break-point-widest) {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.onboardingText {
|
||||
margin: 0 0 60px;
|
||||
color: var(--newtab-text-conditional-color);
|
||||
line-height: 1.5;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.onboardingButton {
|
||||
color: var(--newtab-text-conditional-color);
|
||||
background: var(--trailhead-card-button-background-color);
|
||||
border: 0;
|
||||
margin: 14px;
|
||||
min-width: 70%;
|
||||
padding: 6px 14px;
|
||||
white-space: pre-wrap;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
background: var(--trailhead-card-button-background-hover-color);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: dotted 1px;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--trailhead-card-button-background-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
.onboardingButtonContainer {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-stream.welcome {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.inline-onboarding {
|
||||
&.activity-stream.welcome {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.outer-wrapper {
|
||||
position: relative;
|
||||
display: block;
|
||||
|
||||
.prefs-button {
|
||||
button {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.asrouter-toggle {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error.active {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
animation: fade-down 450ms;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: $white;
|
||||
background-color: $red-60;
|
||||
position: absolute;
|
||||
inset-inline-start: 50px;
|
||||
top: -28px;
|
||||
border-radius: 2px;
|
||||
|
||||
&::before {
|
||||
inset-inline-start: 12px;
|
||||
background: $red-60;
|
||||
bottom: -8px;
|
||||
content: '.';
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-indent: -999px;
|
||||
transform: rotate(45deg);
|
||||
white-space: nowrap;
|
||||
width: 16px;
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-down {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
import { actionCreators as ac, actionTypes as at } from "common/Actions.jsm";
|
||||
import { ASRouterUtils } from "../../asrouter/asrouter-utils";
|
||||
import { connect } from "react-redux";
|
||||
import { ModalOverlay } from "../../asrouter/components/ModalOverlay/ModalOverlay";
|
||||
import React from "react";
|
||||
import { SimpleHashRouter } from "./SimpleHashRouter";
|
||||
|
||||
@ -489,9 +488,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
this.handleClearAllImpressionsByProvider = this.handleClearAllImpressionsByProvider.bind(
|
||||
this
|
||||
);
|
||||
this.findOtherBundledMessagesOfSameTemplate = this.findOtherBundledMessagesOfSameTemplate.bind(
|
||||
this
|
||||
);
|
||||
this.handleExpressionEval = this.handleExpressionEval.bind(this);
|
||||
this.onChangeTargetingParameters = this.onChangeTargetingParameters.bind(
|
||||
this
|
||||
@ -501,7 +497,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
);
|
||||
this.setAttribution = this.setAttribution.bind(this);
|
||||
this.onCopyTargetingParams = this.onCopyTargetingParams.bind(this);
|
||||
this.onPasteTargetingParams = this.onPasteTargetingParams.bind(this);
|
||||
this.onNewTargetingParams = this.onNewTargetingParams.bind(this);
|
||||
this.handleUpdateWNMessages = this.handleUpdateWNMessages.bind(this);
|
||||
this.handleForceWNP = this.handleForceWNP.bind(this);
|
||||
@ -521,11 +516,9 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
collapsedMessages: [],
|
||||
modifiedMessages: [],
|
||||
evaluationStatus: {},
|
||||
trailheadTriplet: "",
|
||||
stringTargetingParameters: null,
|
||||
newStringTargetingParameters: null,
|
||||
copiedToClipboard: false,
|
||||
pasteFromClipboard: false,
|
||||
attributionParameters: {
|
||||
source: "addons.mozilla.org",
|
||||
medium: "referral",
|
||||
@ -572,27 +565,11 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
}).then(this.setStateFromParent);
|
||||
}
|
||||
|
||||
findOtherBundledMessagesOfSameTemplate(template) {
|
||||
return this.state.messages.filter(
|
||||
msg => msg.template === template && msg.bundled
|
||||
);
|
||||
}
|
||||
|
||||
handleBlock(msg) {
|
||||
if (msg.bundled && msg.template !== "onboarding") {
|
||||
// If we are blocking a message that belongs to a bundle, block all other messages that are bundled of that same template
|
||||
let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
|
||||
return () => ASRouterUtils.blockBundle(bundle);
|
||||
}
|
||||
return () => ASRouterUtils.blockById(msg.id);
|
||||
}
|
||||
|
||||
handleUnblock(msg) {
|
||||
if (msg.bundled && msg.template !== "onboarding") {
|
||||
// If we are unblocking a message that belongs to a bundle, unblock all other messages that are bundled of that same template
|
||||
let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
|
||||
return () => ASRouterUtils.unblockBundle(bundle);
|
||||
}
|
||||
return () => ASRouterUtils.unblockById(msg.id);
|
||||
}
|
||||
|
||||
@ -827,14 +804,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
// Copy all clipboard data to targeting parameters
|
||||
onPasteTargetingParams(event) {
|
||||
this.setState(({ pasteFromClipboard }) => ({
|
||||
pasteFromClipboard: !pasteFromClipboard,
|
||||
newStringTargetingParameters: "",
|
||||
}));
|
||||
}
|
||||
|
||||
onNewTargetingParams(event) {
|
||||
this.setState({ newStringTargetingParameters: event.target.value });
|
||||
event.target.classList.remove("errorState");
|
||||
@ -1324,35 +1293,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
renderPasteModal() {
|
||||
if (!this.state.pasteFromClipboard) {
|
||||
return null;
|
||||
}
|
||||
const errors =
|
||||
this.refs.targetingParamsEval &&
|
||||
this.refs.targetingParamsEval.innerText.length;
|
||||
return (
|
||||
<ModalOverlay
|
||||
innerStyle="pasteModal"
|
||||
title="New targeting parameters"
|
||||
button_label={errors ? "Cancel" : "Done"}
|
||||
onDismissBundle={this.onPasteTargetingParams}
|
||||
>
|
||||
<div className="onboardingMessage">
|
||||
<p>
|
||||
<textarea
|
||||
onChange={this.onNewTargetingParams}
|
||||
value={this.state.newStringTargetingParameters}
|
||||
rows="20"
|
||||
cols="60"
|
||||
/>
|
||||
</p>
|
||||
<p ref="targetingParamsEval" />
|
||||
</div>
|
||||
</ModalOverlay>
|
||||
);
|
||||
}
|
||||
|
||||
renderTargetingParameters() {
|
||||
// There was no error and the result is truthy
|
||||
const success =
|
||||
@ -1412,13 +1352,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
? "Parameters copied!"
|
||||
: "Copy parameters"}
|
||||
</button>
|
||||
<button
|
||||
className="ASRouterButton secondary"
|
||||
onClick={this.onPasteTargetingParams}
|
||||
disabled={this.state.pasteFromClipboard}
|
||||
>
|
||||
Paste parameters
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{this.state.stringTargetingParameters &&
|
||||
@ -1686,19 +1619,6 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
return <p>No errors</p>;
|
||||
}
|
||||
|
||||
renderTrailheadInfo() {
|
||||
return (
|
||||
<table className="minimal-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Triplet branch</td>
|
||||
<td>{this.state.trailheadTriplet}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
renderWNPTests() {
|
||||
if (!this.state.messages) {
|
||||
return null;
|
||||
@ -1858,12 +1778,9 @@ export class ASRouterAdminInner extends React.PureComponent {
|
||||
</button>
|
||||
</h2>
|
||||
{this.state.providers ? this.renderProviders() : null}
|
||||
<h2>Trailhead</h2>
|
||||
{this.renderTrailheadInfo()}
|
||||
<h2>Messages</h2>
|
||||
{this.renderMessageFilter()}
|
||||
{this.renderMessages()}
|
||||
{this.renderPasteModal()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -176,6 +176,4 @@ input {
|
||||
@import '../asrouter/templates/SimpleBelowSearchSnippet/SimpleBelowSearchSnippet';
|
||||
@import '../asrouter/templates/SimpleSnippet/SimpleSnippet';
|
||||
@import '../asrouter/templates/SubmitFormSnippet/SubmitFormSnippet';
|
||||
@import '../asrouter/templates/OnboardingMessage/OnboardingMessage';
|
||||
@import '../asrouter/templates/FirstRun/Triplets';
|
||||
@import '../asrouter/templates/EOYSnippet/EOYSnippet';
|
||||
|
@ -93,13 +93,6 @@ body {
|
||||
--newtab-snippets-background-color: #{$white};
|
||||
--newtab-snippets-hairline-color: transparent;
|
||||
|
||||
// Trailhead
|
||||
--trailhead-header-text-color: #{$trailhead-purple};
|
||||
--trailhead-cards-background-color: #{$grey-20};
|
||||
--trailhead-card-button-background-color: #{$grey-90-10};
|
||||
--trailhead-card-button-background-hover-color: #{$grey-90-20};
|
||||
--trailhead-card-button-background-active-color: #{$grey-90-30};
|
||||
|
||||
&[lwt-newtab-brighttext] {
|
||||
// General styles
|
||||
--newtab-background-color: #{$grey-80};
|
||||
@ -171,12 +164,5 @@ body {
|
||||
// Snippets
|
||||
--newtab-snippets-background-color: #{$grey-70};
|
||||
--newtab-snippets-hairline-color: #{$white-10};
|
||||
|
||||
// Trailhead
|
||||
--trailhead-header-text-color: #{$white-60};
|
||||
--trailhead-cards-background-color: #{$grey-90-10};
|
||||
--trailhead-card-button-background-color: #{$grey-90-30};
|
||||
--trailhead-card-button-background-hover-color: #{$grey-90-50};
|
||||
--trailhead-card-button-background-active-color: #{$grey-90-70};
|
||||
}
|
||||
}
|
||||
|
@ -88,11 +88,6 @@ $about-welcome-gradient: linear-gradient(to bottom, $blue-70 40%, $aw-extra-blue
|
||||
$about-welcome-extra-links: #676F7E;
|
||||
$firefox-wordmark-default-color: #363959;
|
||||
$firefox-wordmark-darktheme-color: $white;
|
||||
$trailhead-violet: #7542E5;
|
||||
$trailhead-purple: #2B2156;
|
||||
$trailhead-purple-80: #36296D;
|
||||
$trailhead-blue-60: #0250BB;
|
||||
$trailhead-blue-70: #054096;
|
||||
|
||||
// New new tab experience colors.
|
||||
$newtab-background-button-default-color: rgba(223, 223, 223, 0.5);
|
||||
|
@ -79,12 +79,7 @@ body {
|
||||
--newtab-card-placeholder-color: #D7D7DB;
|
||||
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
|
||||
--newtab-snippets-background-color: #FFF;
|
||||
--newtab-snippets-hairline-color: transparent;
|
||||
--trailhead-header-text-color: #2B2156;
|
||||
--trailhead-cards-background-color: #EDEDF0;
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.2);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.3); }
|
||||
--newtab-snippets-hairline-color: transparent; }
|
||||
body[lwt-newtab-brighttext] {
|
||||
--newtab-background-color: #2A2A2E;
|
||||
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
|
||||
@ -137,12 +132,7 @@ body {
|
||||
--newtab-card-placeholder-color: #4A4A4F;
|
||||
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
|
||||
--newtab-snippets-background-color: #38383D;
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1);
|
||||
--trailhead-header-text-color: rgba(255, 255, 255, 0.6);
|
||||
--trailhead-cards-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.3);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.7); }
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
|
||||
|
||||
.icon {
|
||||
background-position: center center;
|
||||
@ -3581,9 +3571,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.modalOverlayOuter.active {
|
||||
display: flex; }
|
||||
|
||||
.modal-height {
|
||||
padding-top: 80px; }
|
||||
|
||||
.modalOverlayInner {
|
||||
min-width: min-content;
|
||||
width: 100%;
|
||||
@ -3604,17 +3591,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
border-radius: 0; } }
|
||||
.modalOverlayInner.active {
|
||||
display: block; }
|
||||
.modalOverlayInner .icon-dismiss {
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 0;
|
||||
padding: 20px;
|
||||
fill: #FFF;
|
||||
position: absolute; }
|
||||
.modalOverlayInner .icon-dismiss:hover {
|
||||
background-color: #2B2156; }
|
||||
.modalOverlayInner .icon-dismiss:focus {
|
||||
border: 1px dotted; }
|
||||
.modalOverlayInner h2 {
|
||||
color: #4A4A4F;
|
||||
text-align: center;
|
||||
@ -3987,305 +3963,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.submissionStatus .submitStatusTitle {
|
||||
font-size: 20px; }
|
||||
|
||||
.onboardingMessageImage.addons {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-addons@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.privatebrowsing {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-privatebrowsing@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.screenshots {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-screenshots@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.gift {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-gift@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.sync {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-sync@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.devices {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-devices.svg"); }
|
||||
|
||||
.onboardingMessageImage.fbcont {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-fbcont.svg"); }
|
||||
|
||||
.onboardingMessageImage.import {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-import.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffmonitor {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffmonitor.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffsend {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffsend.svg"); }
|
||||
|
||||
.onboardingMessageImage.lockwise {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-lockwise.svg"); }
|
||||
|
||||
.onboardingMessageImage.mobile {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-mobile.svg"); }
|
||||
|
||||
.onboardingMessageImage.pledge {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pledge.svg"); }
|
||||
|
||||
.onboardingMessageImage.pocket {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pocket.svg"); }
|
||||
|
||||
.onboardingMessageImage.private {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-private.svg"); }
|
||||
|
||||
.onboardingMessageImage.sendtab {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-sendtab.svg"); }
|
||||
|
||||
.onboardingMessageImage.tracking {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-tracking.svg"); }
|
||||
|
||||
.onboardingMessage {
|
||||
height: 340px;
|
||||
text-align: center;
|
||||
padding: 13px;
|
||||
font-weight: 200; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage {
|
||||
height: 170px;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #D7D7DB;
|
||||
display: flex;
|
||||
margin-bottom: 11px; }
|
||||
.onboardingMessage:last-child {
|
||||
border: 0; }
|
||||
.onboardingMessage .onboardingContent {
|
||||
padding-left: 10px;
|
||||
height: 100%; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-top: 0;
|
||||
line-height: 22px;
|
||||
font-size: 15px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage {
|
||||
height: 250px; } }
|
||||
.onboardingMessage .onboardingContent {
|
||||
height: 175px; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
color: #0C0C0D;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
color: #4A4A4F;
|
||||
margin-top: 0;
|
||||
height: 180px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 15px;
|
||||
line-height: 22px; }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-bottom: 0;
|
||||
height: 160px; } }
|
||||
.onboardingMessage .onboardingButton {
|
||||
background-color: rgba(12, 12, 13, 0.1);
|
||||
border: 0;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
margin-bottom: 23px;
|
||||
padding: 4px 0 6px;
|
||||
font-size: 15px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: right;
|
||||
margin-top: -105px;
|
||||
margin-inline-end: -10px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: none; } }
|
||||
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
|
||||
box-shadow: 0 0 0 5px #D7D7DB;
|
||||
transition: box-shadow 150ms; }
|
||||
.onboardingMessage::before {
|
||||
content: '';
|
||||
height: 230px;
|
||||
width: 1px;
|
||||
position: absolute;
|
||||
background-color: #D7D7DB;
|
||||
margin-top: 40px;
|
||||
margin-inline-start: 215px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage::before {
|
||||
content: none; } }
|
||||
.onboardingMessage:last-child::before {
|
||||
content: none; }
|
||||
|
||||
.onboardingMessageImage {
|
||||
height: 112px;
|
||||
width: 180px;
|
||||
background-size: auto 140px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block; }
|
||||
@media (max-width: 865px) {
|
||||
.onboardingMessageImage {
|
||||
height: 75px;
|
||||
min-width: 80px;
|
||||
background-size: 140px; } }
|
||||
|
||||
.trailheadCards {
|
||||
background: var(--trailhead-cards-background-color);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCards {
|
||||
max-height: 1000px; } }
|
||||
.trailheadCards.collapsed {
|
||||
max-height: 0; }
|
||||
.trailheadCards h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 200;
|
||||
margin: 0 0 40px;
|
||||
color: var(--trailhead-header-text-color); }
|
||||
|
||||
.trailheadCardsInner {
|
||||
margin: auto;
|
||||
padding: 40px 25px; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardsInner {
|
||||
width: 530px; } }
|
||||
@media (min-width: 866px) {
|
||||
.trailheadCardsInner {
|
||||
width: 786px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardsInner {
|
||||
width: 1042px; } }
|
||||
.trailheadCardsInner .icon-dismiss {
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 15px;
|
||||
padding: 15px;
|
||||
opacity: 0.75;
|
||||
position: absolute;
|
||||
top: 15px; }
|
||||
.trailheadCardsInner .icon-dismiss:hover, .trailheadCardsInner .icon-dismiss:focus {
|
||||
background-color: var(--newtab-element-active-color); }
|
||||
|
||||
.trailheadCardGrid {
|
||||
display: grid;
|
||||
grid-gap: 32px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s;
|
||||
transition-delay: 0.1s;
|
||||
grid-auto-rows: 1fr; }
|
||||
.trailheadCardGrid.show {
|
||||
opacity: 1; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 224px); } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 309px); } }
|
||||
|
||||
.trailheadCard {
|
||||
position: relative;
|
||||
background: var(--newtab-card-background-color);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--newtab-card-shadow);
|
||||
font-size: 13px;
|
||||
padding: 20px 20px 60px; }
|
||||
@media (max-width: 865px) {
|
||||
.trailheadCard {
|
||||
padding: 20px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard {
|
||||
font-size: 15px; } }
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-weight: normal;
|
||||
color: var(--newtab-text-primary-color);
|
||||
margin: 10px 0 4px;
|
||||
font-size: 15px; }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-size: 18px; } }
|
||||
.trailheadCard .onboardingText {
|
||||
margin: 0 0 60px;
|
||||
color: var(--newtab-text-conditional-color);
|
||||
line-height: 1.5;
|
||||
font-weight: 200; }
|
||||
.trailheadCard .onboardingButton {
|
||||
color: var(--newtab-text-conditional-color);
|
||||
background: var(--trailhead-card-button-background-color);
|
||||
border: 0;
|
||||
margin: 14px;
|
||||
min-width: 70%;
|
||||
padding: 6px 14px;
|
||||
white-space: pre-wrap; }
|
||||
.trailheadCard .onboardingButton:focus, .trailheadCard .onboardingButton:hover {
|
||||
box-shadow: none;
|
||||
background: var(--trailhead-card-button-background-hover-color); }
|
||||
.trailheadCard .onboardingButton:focus {
|
||||
outline: dotted 1px; }
|
||||
.trailheadCard .onboardingButton:active {
|
||||
background: var(--trailhead-card-button-background-active-color); }
|
||||
.trailheadCard .onboardingButtonContainer {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
|
||||
.activity-stream.welcome {
|
||||
overflow: hidden; }
|
||||
|
||||
.inline-onboarding.activity-stream.welcome {
|
||||
overflow-y: hidden; }
|
||||
|
||||
.inline-onboarding .outer-wrapper {
|
||||
position: relative;
|
||||
display: block; }
|
||||
.inline-onboarding .outer-wrapper .prefs-button button {
|
||||
position: absolute; }
|
||||
|
||||
.inline-onboarding .asrouter-toggle {
|
||||
position: absolute; }
|
||||
|
||||
.error {
|
||||
display: none; }
|
||||
|
||||
.error.active {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
animation: fade-down 450ms;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #D70022;
|
||||
position: absolute;
|
||||
inset-inline-start: 50px;
|
||||
top: -28px;
|
||||
border-radius: 2px; }
|
||||
.error.active::before {
|
||||
inset-inline-start: 12px;
|
||||
background: #D70022;
|
||||
bottom: -8px;
|
||||
content: '.';
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-indent: -999px;
|
||||
transform: rotate(45deg);
|
||||
white-space: nowrap;
|
||||
width: 16px;
|
||||
z-index: -1; }
|
||||
|
||||
@keyframes fade-down {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-15px); }
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0); } }
|
||||
|
||||
.EOYSnippetForm {
|
||||
margin: 10px 0 8px;
|
||||
align-self: start;
|
||||
|
@ -82,12 +82,7 @@ body {
|
||||
--newtab-card-placeholder-color: #D7D7DB;
|
||||
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
|
||||
--newtab-snippets-background-color: #FFF;
|
||||
--newtab-snippets-hairline-color: transparent;
|
||||
--trailhead-header-text-color: #2B2156;
|
||||
--trailhead-cards-background-color: #EDEDF0;
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.2);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.3); }
|
||||
--newtab-snippets-hairline-color: transparent; }
|
||||
body[lwt-newtab-brighttext] {
|
||||
--newtab-background-color: #2A2A2E;
|
||||
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
|
||||
@ -140,12 +135,7 @@ body {
|
||||
--newtab-card-placeholder-color: #4A4A4F;
|
||||
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
|
||||
--newtab-snippets-background-color: #38383D;
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1);
|
||||
--trailhead-header-text-color: rgba(255, 255, 255, 0.6);
|
||||
--trailhead-cards-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.3);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.7); }
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
|
||||
|
||||
.icon {
|
||||
background-position: center center;
|
||||
@ -3584,9 +3574,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.modalOverlayOuter.active {
|
||||
display: flex; }
|
||||
|
||||
.modal-height {
|
||||
padding-top: 80px; }
|
||||
|
||||
.modalOverlayInner {
|
||||
min-width: min-content;
|
||||
width: 100%;
|
||||
@ -3607,17 +3594,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
border-radius: 0; } }
|
||||
.modalOverlayInner.active {
|
||||
display: block; }
|
||||
.modalOverlayInner .icon-dismiss {
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 0;
|
||||
padding: 20px;
|
||||
fill: #FFF;
|
||||
position: absolute; }
|
||||
.modalOverlayInner .icon-dismiss:hover {
|
||||
background-color: #2B2156; }
|
||||
.modalOverlayInner .icon-dismiss:focus {
|
||||
border: 1px dotted; }
|
||||
.modalOverlayInner h2 {
|
||||
color: #4A4A4F;
|
||||
text-align: center;
|
||||
@ -3990,305 +3966,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.submissionStatus .submitStatusTitle {
|
||||
font-size: 20px; }
|
||||
|
||||
.onboardingMessageImage.addons {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-addons@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.privatebrowsing {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-privatebrowsing@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.screenshots {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-screenshots@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.gift {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-gift@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.sync {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-sync@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.devices {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-devices.svg"); }
|
||||
|
||||
.onboardingMessageImage.fbcont {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-fbcont.svg"); }
|
||||
|
||||
.onboardingMessageImage.import {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-import.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffmonitor {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffmonitor.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffsend {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffsend.svg"); }
|
||||
|
||||
.onboardingMessageImage.lockwise {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-lockwise.svg"); }
|
||||
|
||||
.onboardingMessageImage.mobile {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-mobile.svg"); }
|
||||
|
||||
.onboardingMessageImage.pledge {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pledge.svg"); }
|
||||
|
||||
.onboardingMessageImage.pocket {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pocket.svg"); }
|
||||
|
||||
.onboardingMessageImage.private {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-private.svg"); }
|
||||
|
||||
.onboardingMessageImage.sendtab {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-sendtab.svg"); }
|
||||
|
||||
.onboardingMessageImage.tracking {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-tracking.svg"); }
|
||||
|
||||
.onboardingMessage {
|
||||
height: 340px;
|
||||
text-align: center;
|
||||
padding: 13px;
|
||||
font-weight: 200; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage {
|
||||
height: 170px;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #D7D7DB;
|
||||
display: flex;
|
||||
margin-bottom: 11px; }
|
||||
.onboardingMessage:last-child {
|
||||
border: 0; }
|
||||
.onboardingMessage .onboardingContent {
|
||||
padding-left: 10px;
|
||||
height: 100%; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-top: 0;
|
||||
line-height: 22px;
|
||||
font-size: 15px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage {
|
||||
height: 250px; } }
|
||||
.onboardingMessage .onboardingContent {
|
||||
height: 175px; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
color: #0C0C0D;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
color: #4A4A4F;
|
||||
margin-top: 0;
|
||||
height: 180px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 15px;
|
||||
line-height: 22px; }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-bottom: 0;
|
||||
height: 160px; } }
|
||||
.onboardingMessage .onboardingButton {
|
||||
background-color: rgba(12, 12, 13, 0.1);
|
||||
border: 0;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
margin-bottom: 23px;
|
||||
padding: 4px 0 6px;
|
||||
font-size: 15px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: right;
|
||||
margin-top: -105px;
|
||||
margin-inline-end: -10px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: none; } }
|
||||
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
|
||||
box-shadow: 0 0 0 5px #D7D7DB;
|
||||
transition: box-shadow 150ms; }
|
||||
.onboardingMessage::before {
|
||||
content: '';
|
||||
height: 230px;
|
||||
width: 1px;
|
||||
position: absolute;
|
||||
background-color: #D7D7DB;
|
||||
margin-top: 40px;
|
||||
margin-inline-start: 215px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage::before {
|
||||
content: none; } }
|
||||
.onboardingMessage:last-child::before {
|
||||
content: none; }
|
||||
|
||||
.onboardingMessageImage {
|
||||
height: 112px;
|
||||
width: 180px;
|
||||
background-size: auto 140px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block; }
|
||||
@media (max-width: 865px) {
|
||||
.onboardingMessageImage {
|
||||
height: 75px;
|
||||
min-width: 80px;
|
||||
background-size: 140px; } }
|
||||
|
||||
.trailheadCards {
|
||||
background: var(--trailhead-cards-background-color);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCards {
|
||||
max-height: 1000px; } }
|
||||
.trailheadCards.collapsed {
|
||||
max-height: 0; }
|
||||
.trailheadCards h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 200;
|
||||
margin: 0 0 40px;
|
||||
color: var(--trailhead-header-text-color); }
|
||||
|
||||
.trailheadCardsInner {
|
||||
margin: auto;
|
||||
padding: 40px 25px; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardsInner {
|
||||
width: 530px; } }
|
||||
@media (min-width: 866px) {
|
||||
.trailheadCardsInner {
|
||||
width: 786px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardsInner {
|
||||
width: 1042px; } }
|
||||
.trailheadCardsInner .icon-dismiss {
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 15px;
|
||||
padding: 15px;
|
||||
opacity: 0.75;
|
||||
position: absolute;
|
||||
top: 15px; }
|
||||
.trailheadCardsInner .icon-dismiss:hover, .trailheadCardsInner .icon-dismiss:focus {
|
||||
background-color: var(--newtab-element-active-color); }
|
||||
|
||||
.trailheadCardGrid {
|
||||
display: grid;
|
||||
grid-gap: 32px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s;
|
||||
transition-delay: 0.1s;
|
||||
grid-auto-rows: 1fr; }
|
||||
.trailheadCardGrid.show {
|
||||
opacity: 1; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 224px); } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 309px); } }
|
||||
|
||||
.trailheadCard {
|
||||
position: relative;
|
||||
background: var(--newtab-card-background-color);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--newtab-card-shadow);
|
||||
font-size: 13px;
|
||||
padding: 20px 20px 60px; }
|
||||
@media (max-width: 865px) {
|
||||
.trailheadCard {
|
||||
padding: 20px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard {
|
||||
font-size: 15px; } }
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-weight: normal;
|
||||
color: var(--newtab-text-primary-color);
|
||||
margin: 10px 0 4px;
|
||||
font-size: 15px; }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-size: 18px; } }
|
||||
.trailheadCard .onboardingText {
|
||||
margin: 0 0 60px;
|
||||
color: var(--newtab-text-conditional-color);
|
||||
line-height: 1.5;
|
||||
font-weight: 200; }
|
||||
.trailheadCard .onboardingButton {
|
||||
color: var(--newtab-text-conditional-color);
|
||||
background: var(--trailhead-card-button-background-color);
|
||||
border: 0;
|
||||
margin: 14px;
|
||||
min-width: 70%;
|
||||
padding: 6px 14px;
|
||||
white-space: pre-wrap; }
|
||||
.trailheadCard .onboardingButton:focus, .trailheadCard .onboardingButton:hover {
|
||||
box-shadow: none;
|
||||
background: var(--trailhead-card-button-background-hover-color); }
|
||||
.trailheadCard .onboardingButton:focus {
|
||||
outline: dotted 1px; }
|
||||
.trailheadCard .onboardingButton:active {
|
||||
background: var(--trailhead-card-button-background-active-color); }
|
||||
.trailheadCard .onboardingButtonContainer {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
|
||||
.activity-stream.welcome {
|
||||
overflow: hidden; }
|
||||
|
||||
.inline-onboarding.activity-stream.welcome {
|
||||
overflow-y: hidden; }
|
||||
|
||||
.inline-onboarding .outer-wrapper {
|
||||
position: relative;
|
||||
display: block; }
|
||||
.inline-onboarding .outer-wrapper .prefs-button button {
|
||||
position: absolute; }
|
||||
|
||||
.inline-onboarding .asrouter-toggle {
|
||||
position: absolute; }
|
||||
|
||||
.error {
|
||||
display: none; }
|
||||
|
||||
.error.active {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
animation: fade-down 450ms;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #D70022;
|
||||
position: absolute;
|
||||
inset-inline-start: 50px;
|
||||
top: -28px;
|
||||
border-radius: 2px; }
|
||||
.error.active::before {
|
||||
inset-inline-start: 12px;
|
||||
background: #D70022;
|
||||
bottom: -8px;
|
||||
content: '.';
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-indent: -999px;
|
||||
transform: rotate(45deg);
|
||||
white-space: nowrap;
|
||||
width: 16px;
|
||||
z-index: -1; }
|
||||
|
||||
@keyframes fade-down {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-15px); }
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0); } }
|
||||
|
||||
.EOYSnippetForm {
|
||||
margin: 10px 0 8px;
|
||||
align-self: start;
|
||||
|
@ -79,12 +79,7 @@ body {
|
||||
--newtab-card-placeholder-color: #D7D7DB;
|
||||
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
|
||||
--newtab-snippets-background-color: #FFF;
|
||||
--newtab-snippets-hairline-color: transparent;
|
||||
--trailhead-header-text-color: #2B2156;
|
||||
--trailhead-cards-background-color: #EDEDF0;
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.2);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.3); }
|
||||
--newtab-snippets-hairline-color: transparent; }
|
||||
body[lwt-newtab-brighttext] {
|
||||
--newtab-background-color: #2A2A2E;
|
||||
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
|
||||
@ -137,12 +132,7 @@ body {
|
||||
--newtab-card-placeholder-color: #4A4A4F;
|
||||
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
|
||||
--newtab-snippets-background-color: #38383D;
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1);
|
||||
--trailhead-header-text-color: rgba(255, 255, 255, 0.6);
|
||||
--trailhead-cards-background-color: rgba(12, 12, 13, 0.1);
|
||||
--trailhead-card-button-background-color: rgba(12, 12, 13, 0.3);
|
||||
--trailhead-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
|
||||
--trailhead-card-button-background-active-color: rgba(12, 12, 13, 0.7); }
|
||||
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
|
||||
|
||||
.icon {
|
||||
background-position: center center;
|
||||
@ -3581,9 +3571,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.modalOverlayOuter.active {
|
||||
display: flex; }
|
||||
|
||||
.modal-height {
|
||||
padding-top: 80px; }
|
||||
|
||||
.modalOverlayInner {
|
||||
min-width: min-content;
|
||||
width: 100%;
|
||||
@ -3604,17 +3591,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
border-radius: 0; } }
|
||||
.modalOverlayInner.active {
|
||||
display: block; }
|
||||
.modalOverlayInner .icon-dismiss {
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 0;
|
||||
padding: 20px;
|
||||
fill: #FFF;
|
||||
position: absolute; }
|
||||
.modalOverlayInner .icon-dismiss:hover {
|
||||
background-color: #2B2156; }
|
||||
.modalOverlayInner .icon-dismiss:focus {
|
||||
border: 1px dotted; }
|
||||
.modalOverlayInner h2 {
|
||||
color: #4A4A4F;
|
||||
text-align: center;
|
||||
@ -3987,305 +3963,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
||||
.submissionStatus .submitStatusTitle {
|
||||
font-size: 20px; }
|
||||
|
||||
.onboardingMessageImage.addons {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-addons@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.privatebrowsing {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-privatebrowsing@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.screenshots {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-screenshots@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.gift {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-gift@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.sync {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/illustration-sync@2x.png"); }
|
||||
|
||||
.onboardingMessageImage.devices {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-devices.svg"); }
|
||||
|
||||
.onboardingMessageImage.fbcont {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-fbcont.svg"); }
|
||||
|
||||
.onboardingMessageImage.import {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-import.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffmonitor {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffmonitor.svg"); }
|
||||
|
||||
.onboardingMessageImage.ffsend {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-ffsend.svg"); }
|
||||
|
||||
.onboardingMessageImage.lockwise {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-lockwise.svg"); }
|
||||
|
||||
.onboardingMessageImage.mobile {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-mobile.svg"); }
|
||||
|
||||
.onboardingMessageImage.pledge {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pledge.svg"); }
|
||||
|
||||
.onboardingMessageImage.pocket {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-pocket.svg"); }
|
||||
|
||||
.onboardingMessageImage.private {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-private.svg"); }
|
||||
|
||||
.onboardingMessageImage.sendtab {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-sendtab.svg"); }
|
||||
|
||||
.onboardingMessageImage.tracking {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/trailhead/card-illo-tracking.svg"); }
|
||||
|
||||
.onboardingMessage {
|
||||
height: 340px;
|
||||
text-align: center;
|
||||
padding: 13px;
|
||||
font-weight: 200; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage {
|
||||
height: 170px;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #D7D7DB;
|
||||
display: flex;
|
||||
margin-bottom: 11px; }
|
||||
.onboardingMessage:last-child {
|
||||
border: 0; }
|
||||
.onboardingMessage .onboardingContent {
|
||||
padding-left: 10px;
|
||||
height: 100%; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-top: 0;
|
||||
line-height: 22px;
|
||||
font-size: 15px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage {
|
||||
height: 250px; } }
|
||||
.onboardingMessage .onboardingContent {
|
||||
height: 175px; }
|
||||
.onboardingMessage .onboardingContent > span > h3 {
|
||||
color: #0C0C0D;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 400; }
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
color: #4A4A4F;
|
||||
margin-top: 0;
|
||||
height: 180px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 15px;
|
||||
line-height: 22px; }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingContent > span > p {
|
||||
margin-bottom: 0;
|
||||
height: 160px; } }
|
||||
.onboardingMessage .onboardingButton {
|
||||
background-color: rgba(12, 12, 13, 0.1);
|
||||
border: 0;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
margin-bottom: 23px;
|
||||
padding: 4px 0 6px;
|
||||
font-size: 15px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: right;
|
||||
margin-top: -105px;
|
||||
margin-inline-end: -10px; } }
|
||||
@media (max-width: 650px) {
|
||||
.onboardingMessage .onboardingButton {
|
||||
float: none; } }
|
||||
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
|
||||
box-shadow: 0 0 0 5px #D7D7DB;
|
||||
transition: box-shadow 150ms; }
|
||||
.onboardingMessage::before {
|
||||
content: '';
|
||||
height: 230px;
|
||||
width: 1px;
|
||||
position: absolute;
|
||||
background-color: #D7D7DB;
|
||||
margin-top: 40px;
|
||||
margin-inline-start: 215px; }
|
||||
@media (max-width: 850px) {
|
||||
.onboardingMessage::before {
|
||||
content: none; } }
|
||||
.onboardingMessage:last-child::before {
|
||||
content: none; }
|
||||
|
||||
.onboardingMessageImage {
|
||||
height: 112px;
|
||||
width: 180px;
|
||||
background-size: auto 140px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
display: inline-block; }
|
||||
@media (max-width: 865px) {
|
||||
.onboardingMessageImage {
|
||||
height: 75px;
|
||||
min-width: 80px;
|
||||
background-size: 140px; } }
|
||||
|
||||
.trailheadCards {
|
||||
background: var(--trailhead-cards-background-color);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCards {
|
||||
max-height: 1000px; } }
|
||||
.trailheadCards.collapsed {
|
||||
max-height: 0; }
|
||||
.trailheadCards h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 200;
|
||||
margin: 0 0 40px;
|
||||
color: var(--trailhead-header-text-color); }
|
||||
|
||||
.trailheadCardsInner {
|
||||
margin: auto;
|
||||
padding: 40px 25px; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardsInner {
|
||||
width: 530px; } }
|
||||
@media (min-width: 866px) {
|
||||
.trailheadCardsInner {
|
||||
width: 786px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardsInner {
|
||||
width: 1042px; } }
|
||||
.trailheadCardsInner .icon-dismiss {
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
inset-inline-end: 15px;
|
||||
padding: 15px;
|
||||
opacity: 0.75;
|
||||
position: absolute;
|
||||
top: 15px; }
|
||||
.trailheadCardsInner .icon-dismiss:hover, .trailheadCardsInner .icon-dismiss:focus {
|
||||
background-color: var(--newtab-element-active-color); }
|
||||
|
||||
.trailheadCardGrid {
|
||||
display: grid;
|
||||
grid-gap: 32px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s;
|
||||
transition-delay: 0.1s;
|
||||
grid-auto-rows: 1fr; }
|
||||
.trailheadCardGrid.show {
|
||||
opacity: 1; }
|
||||
@media (min-width: 610px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 224px); } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCardGrid {
|
||||
grid-template-columns: repeat(auto-fit, 309px); } }
|
||||
|
||||
.trailheadCard {
|
||||
position: relative;
|
||||
background: var(--newtab-card-background-color);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--newtab-card-shadow);
|
||||
font-size: 13px;
|
||||
padding: 20px 20px 60px; }
|
||||
@media (max-width: 865px) {
|
||||
.trailheadCard {
|
||||
padding: 20px; } }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard {
|
||||
font-size: 15px; } }
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-weight: normal;
|
||||
color: var(--newtab-text-primary-color);
|
||||
margin: 10px 0 4px;
|
||||
font-size: 15px; }
|
||||
@media (min-width: 1122px) {
|
||||
.trailheadCard .onboardingTitle {
|
||||
font-size: 18px; } }
|
||||
.trailheadCard .onboardingText {
|
||||
margin: 0 0 60px;
|
||||
color: var(--newtab-text-conditional-color);
|
||||
line-height: 1.5;
|
||||
font-weight: 200; }
|
||||
.trailheadCard .onboardingButton {
|
||||
color: var(--newtab-text-conditional-color);
|
||||
background: var(--trailhead-card-button-background-color);
|
||||
border: 0;
|
||||
margin: 14px;
|
||||
min-width: 70%;
|
||||
padding: 6px 14px;
|
||||
white-space: pre-wrap; }
|
||||
.trailheadCard .onboardingButton:focus, .trailheadCard .onboardingButton:hover {
|
||||
box-shadow: none;
|
||||
background: var(--trailhead-card-button-background-hover-color); }
|
||||
.trailheadCard .onboardingButton:focus {
|
||||
outline: dotted 1px; }
|
||||
.trailheadCard .onboardingButton:active {
|
||||
background: var(--trailhead-card-button-background-active-color); }
|
||||
.trailheadCard .onboardingButtonContainer {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center; }
|
||||
|
||||
.activity-stream.welcome {
|
||||
overflow: hidden; }
|
||||
|
||||
.inline-onboarding.activity-stream.welcome {
|
||||
overflow-y: hidden; }
|
||||
|
||||
.inline-onboarding .outer-wrapper {
|
||||
position: relative;
|
||||
display: block; }
|
||||
.inline-onboarding .outer-wrapper .prefs-button button {
|
||||
position: absolute; }
|
||||
|
||||
.inline-onboarding .asrouter-toggle {
|
||||
position: absolute; }
|
||||
|
||||
.error {
|
||||
display: none; }
|
||||
|
||||
.error.active {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
animation: fade-down 450ms;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
background-color: #D70022;
|
||||
position: absolute;
|
||||
inset-inline-start: 50px;
|
||||
top: -28px;
|
||||
border-radius: 2px; }
|
||||
.error.active::before {
|
||||
inset-inline-start: 12px;
|
||||
background: #D70022;
|
||||
bottom: -8px;
|
||||
content: '.';
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
text-indent: -999px;
|
||||
transform: rotate(45deg);
|
||||
white-space: nowrap;
|
||||
width: 16px;
|
||||
z-index: -1; }
|
||||
|
||||
@keyframes fade-down {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-15px); }
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0); } }
|
||||
|
||||
.EOYSnippetForm {
|
||||
margin: 10px 0 8px;
|
||||
align-self: start;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,12 +37,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"],
|
||||
});
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"isSeparateAboutWelcome",
|
||||
"browser.aboutwelcome.enabled",
|
||||
true
|
||||
);
|
||||
const { actionCreators: ac } = ChromeUtils.import(
|
||||
"resource://activity-stream/common/Actions.jsm"
|
||||
);
|
||||
@ -63,11 +57,6 @@ const { AttributionCode } = ChromeUtils.import(
|
||||
"resource:///modules/AttributionCode.jsm"
|
||||
);
|
||||
|
||||
const TRAILHEAD_CONFIG = {
|
||||
DID_SEE_ABOUT_WELCOME_PREF: "trailhead.firstrun.didSeeAboutWelcome",
|
||||
DYNAMIC_TRIPLET_BUNDLE_LENGTH: 3,
|
||||
};
|
||||
|
||||
// List of hosts for endpoints that serve router messages.
|
||||
// Key is allowed host, value is a name for the endpoint host.
|
||||
const DEFAULT_ALLOWLIST_HOSTS = {
|
||||
@ -1021,7 +1010,6 @@ class _ASRouter {
|
||||
providerPrefs: ASRouterPreferences.providers,
|
||||
userPrefs: ASRouterPreferences.getAllUserPreferences(),
|
||||
targetingParameters,
|
||||
trailheadTriplet: ASRouterPreferences.trailheadTriplet,
|
||||
errors: this.errors,
|
||||
}));
|
||||
}
|
||||
@ -1097,10 +1085,6 @@ class _ASRouter {
|
||||
return Promise.resolve({ evaluationStatus });
|
||||
}
|
||||
|
||||
_orderBundle(bundle) {
|
||||
return bundle.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
|
||||
unblockAll() {
|
||||
return this.setState({ messageBlockList: [] });
|
||||
}
|
||||
@ -1160,97 +1144,6 @@ class _ASRouter {
|
||||
return true;
|
||||
}
|
||||
|
||||
async _getBundledMessages(originalMessage, trigger, force = false) {
|
||||
let result = [];
|
||||
let bundleLength;
|
||||
let bundleTemplate;
|
||||
let originalId;
|
||||
|
||||
if (originalMessage.includeBundle) {
|
||||
// The original message is not part of the bundle, so don't include it
|
||||
bundleLength = originalMessage.includeBundle.length;
|
||||
bundleTemplate = originalMessage.includeBundle.template;
|
||||
} else {
|
||||
// The original message is part of the bundle
|
||||
bundleLength = originalMessage.bundled;
|
||||
bundleTemplate = originalMessage.template;
|
||||
originalId = originalMessage.id;
|
||||
// Add in a copy of the first message
|
||||
result.push({
|
||||
content: originalMessage.content,
|
||||
id: originalMessage.id,
|
||||
order: originalMessage.order || 0,
|
||||
});
|
||||
}
|
||||
|
||||
// First, find all messages of same template. These are potential matching targeting candidates
|
||||
let bundledMessagesOfSameTemplate = this.state.messages.filter(
|
||||
msg =>
|
||||
msg.bundled &&
|
||||
msg.template === bundleTemplate &&
|
||||
msg.id !== originalId &&
|
||||
this.isUnblockedMessage(msg)
|
||||
);
|
||||
|
||||
if (force) {
|
||||
// Forcefully show the messages without targeting matching - this is for about:newtab#asrouter to show the messages
|
||||
for (const message of bundledMessagesOfSameTemplate) {
|
||||
result.push({ content: message.content, id: message.id });
|
||||
// Stop once we have enough messages to fill a bundle
|
||||
if (result.length === bundleLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Find all messages that matches the targeting context
|
||||
const allMessages = await this.handleMessageRequest({
|
||||
messages: bundledMessagesOfSameTemplate,
|
||||
triggerId: trigger && trigger.id,
|
||||
triggerContext: trigger && trigger.context,
|
||||
triggerParam: trigger && trigger.param,
|
||||
ordered: true,
|
||||
returnAll: true,
|
||||
});
|
||||
|
||||
if (allMessages && allMessages.length) {
|
||||
// Retrieve enough messages needed to fill a bundle
|
||||
// Only copy the content of the message (that's what the UI cares about)
|
||||
result = result.concat(
|
||||
allMessages.slice(0, bundleLength).map(message => ({
|
||||
content: message.content,
|
||||
id: message.id,
|
||||
order: message.order || 0,
|
||||
// This is used to determine whether to block when action is triggered
|
||||
// Only block for dynamic triplets experiment and when there are more messages available
|
||||
blockOnClick:
|
||||
ASRouterPreferences.trailheadTriplet.startsWith("dynamic") &&
|
||||
allMessages.length >
|
||||
TRAILHEAD_CONFIG.DYNAMIC_TRIPLET_BUNDLE_LENGTH,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we did not find enough messages to fill the bundle, do not send the bundle down
|
||||
if (result.length < bundleLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The bundle may have some extra attributes, like a header, or a dismiss button, so attempt to get those strings now
|
||||
// This is a temporary solution until we can use Fluent strings in the content process, in which case the content can
|
||||
// handle finding these strings on its own. See bug 1488973
|
||||
const extraTemplateStrings = await this._extraTemplateStrings(
|
||||
originalMessage
|
||||
);
|
||||
|
||||
return {
|
||||
bundle: this._orderBundle(result),
|
||||
...(extraTemplateStrings && { extraTemplateStrings }),
|
||||
provider: originalMessage.provider,
|
||||
template: originalMessage.template,
|
||||
};
|
||||
}
|
||||
|
||||
async _extraTemplateStrings(originalMessage) {
|
||||
let extraTemplateStrings;
|
||||
let localProvider = this._findProvider(originalMessage.provider);
|
||||
@ -1268,6 +1161,10 @@ class _ASRouter {
|
||||
}
|
||||
|
||||
routeCFRMessage(message, browser, trigger, force = false) {
|
||||
if (!message) {
|
||||
return { message: {} };
|
||||
}
|
||||
|
||||
switch (message.template) {
|
||||
case "whatsnew_panel_message":
|
||||
if (force) {
|
||||
@ -1318,33 +1215,7 @@ class _ASRouter {
|
||||
case "update_action":
|
||||
MomentsPageHub.executeAction(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async sendMessage(message, trigger, force, browser) {
|
||||
if (!message) {
|
||||
return { message: {} };
|
||||
} else if (message.bundled) {
|
||||
const bundle =
|
||||
(await this._getBundledMessages(message, trigger, force)) || {};
|
||||
return { message: bundle };
|
||||
} else if (message.includeBundle) {
|
||||
const bundledMessages = await this._getBundledMessages(
|
||||
message,
|
||||
message.includeBundle.trigger,
|
||||
force
|
||||
);
|
||||
return {
|
||||
message: {
|
||||
...message,
|
||||
trailheadTriplet: ASRouterPreferences.trailheadTriplet || "",
|
||||
bundle: bundledMessages && bundledMessages.bundle,
|
||||
},
|
||||
};
|
||||
}
|
||||
this.routeCFRMessage(message, browser, trigger, force);
|
||||
|
||||
return { message };
|
||||
}
|
||||
@ -1537,7 +1408,7 @@ class _ASRouter {
|
||||
}
|
||||
|
||||
setMessageById({ id, ...data }, force, browser) {
|
||||
return this.sendMessage(this.getMessageById(id), data, force, browser);
|
||||
return this.routeCFRMessage(this.getMessageById(id), browser, data, force);
|
||||
}
|
||||
|
||||
blockMessageById(idOrIds) {
|
||||
@ -1764,21 +1635,11 @@ class _ASRouter {
|
||||
} else {
|
||||
const telemetryObject = { tabId };
|
||||
TelemetryStopwatch.start("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||
// On new tab, send cards if they match and not part of default multistage onboarding experience;
|
||||
// othwerise send a snippet
|
||||
if (!isSeparateAboutWelcome) {
|
||||
message = await this.handleMessageRequest({
|
||||
template: "extended_triplets",
|
||||
});
|
||||
}
|
||||
// If no extended triplets message was returned, show snippets instead
|
||||
if (!message) {
|
||||
message = await this.handleMessageRequest({ provider: "snippets" });
|
||||
}
|
||||
message = await this.handleMessageRequest({ provider: "snippets" });
|
||||
TelemetryStopwatch.finish("MS_MESSAGE_REQUEST_TIME_MS", telemetryObject);
|
||||
}
|
||||
|
||||
return this.sendMessage(message, undefined, false, browser);
|
||||
return this.routeCFRMessage(message, browser, undefined, false);
|
||||
}
|
||||
|
||||
_recordReachEvent(message) {
|
||||
@ -1835,11 +1696,11 @@ class _ASRouter {
|
||||
);
|
||||
}
|
||||
|
||||
return this.sendMessage(
|
||||
return this.routeCFRMessage(
|
||||
nonReachMessages[0] || null,
|
||||
browser,
|
||||
trigger,
|
||||
false,
|
||||
browser
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@ -1867,7 +1728,6 @@ class _ASRouter {
|
||||
}
|
||||
}
|
||||
this._ASRouter = _ASRouter;
|
||||
this.TRAILHEAD_CONFIG = TRAILHEAD_CONFIG;
|
||||
|
||||
/**
|
||||
* ASRouter - singleton instance of _ASRouter that controls all messages
|
||||
@ -1875,9 +1735,4 @@ this.TRAILHEAD_CONFIG = TRAILHEAD_CONFIG;
|
||||
*/
|
||||
this.ASRouter = new _ASRouter();
|
||||
|
||||
const EXPORTED_SYMBOLS = [
|
||||
"_ASRouter",
|
||||
"ASRouter",
|
||||
"MessageLoaderUtils",
|
||||
"TRAILHEAD_CONFIG",
|
||||
];
|
||||
const EXPORTED_SYMBOLS = ["_ASRouter", "ASRouter", "MessageLoaderUtils"];
|
||||
|
@ -13,14 +13,6 @@ const PROVIDER_PREF_BRANCH =
|
||||
const DEVTOOLS_PREF =
|
||||
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
|
||||
const FXA_USERNAME_PREF = "services.sync.username";
|
||||
const FIRST_RUN_TRIPLET_PREF = "trailhead.firstrun.newtab.triplets";
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"trailheadTripletPref",
|
||||
FIRST_RUN_TRIPLET_PREF,
|
||||
""
|
||||
);
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
_initialized: false,
|
||||
@ -106,11 +98,6 @@ class _ASRouterPreferences {
|
||||
}, []);
|
||||
}
|
||||
|
||||
// istanbul ignore next
|
||||
get trailheadTriplet() {
|
||||
return trailheadTripletPref;
|
||||
}
|
||||
|
||||
get providers() {
|
||||
if (!this._initialized || this._providers === null) {
|
||||
const config = this._getProviderConfig();
|
||||
|
@ -420,9 +420,6 @@ const TargetingGetters = {
|
||||
get isFxAEnabled() {
|
||||
return isFxAEnabled;
|
||||
},
|
||||
get trailheadTriplet() {
|
||||
return ASRouterPreferences.trailheadTriplet;
|
||||
},
|
||||
get sync() {
|
||||
return {
|
||||
desktopDevices: clientsDevicesDesktop,
|
||||
|
@ -3,9 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
/* globals Localization */
|
||||
const { FX_MONITOR_OAUTH_CLIENT_ID } = ChromeUtils.import(
|
||||
"resource://gre/modules/FxAccountsCommon.js"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const L10N = new Localization([
|
||||
@ -16,289 +13,6 @@ const L10N = new Localization([
|
||||
]);
|
||||
|
||||
const ONBOARDING_MESSAGES = () => [
|
||||
{
|
||||
id: "EXTENDED_TRIPLETS_1",
|
||||
template: "extended_triplets",
|
||||
campaign: "firstrun_triplets",
|
||||
targeting:
|
||||
"trailheadTriplet && ((currentDate|date - profileAgeCreated) / 86400000) < 7",
|
||||
includeBundle: {
|
||||
length: 3,
|
||||
template: "onboarding",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
frequency: { lifetime: 5 },
|
||||
utm_term: "trailhead-cards",
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_1",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 3,
|
||||
content: {
|
||||
title: { string_id: "onboarding-tracking-protection-title2" },
|
||||
text: { string_id: "onboarding-tracking-protection-text2" },
|
||||
icon: "tracking",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-tracking-protection-button2" },
|
||||
action:
|
||||
Services.locale.appLocaleAsBCP47.substr(0, 2) === "en"
|
||||
? {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://mzl.la/ETPdefault",
|
||||
where: "tabshifted",
|
||||
},
|
||||
}
|
||||
: {
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
data: { category: "privacy-trackingprotection" },
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'privacy'",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_2",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 1,
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting:
|
||||
"(trailheadTriplet in ['supercharge', 'static'] || ( 'dynamic' in trailheadTriplet && usesFirefoxSync == false)) && isChinaRepack == false",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_3",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 2,
|
||||
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" },
|
||||
},
|
||||
},
|
||||
},
|
||||
// Use service oauth client_id to identify 'Firefox Monitor' service attached to Firefox Account
|
||||
// https://docs.telemetry.mozilla.org/datasets/fxa_metrics/attribution.html#service-attribution
|
||||
targeting: `(trailheadTriplet in ['supercharge', 'static', 'privacy'] || ('dynamic' in trailheadTriplet && !("${FX_MONITOR_OAUTH_CLIENT_ID}" in attachedFxAOAuthClients|mapToProperty('id')))) && isChinaRepack == false`,
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_4",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 3,
|
||||
content: {
|
||||
title: { string_id: "onboarding-browse-privately-title" },
|
||||
text: { string_id: "onboarding-browse-privately-text" },
|
||||
icon: "private",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-browse-privately-button" },
|
||||
action: { type: "OPEN_PRIVATE_BROWSER_WINDOW" },
|
||||
},
|
||||
},
|
||||
targeting: "'dynamic' in trailheadTriplet",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_5",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 5,
|
||||
content: {
|
||||
title: { string_id: "onboarding-firefox-send-title" },
|
||||
text: { string_id: "onboarding-firefox-send-text2" },
|
||||
icon: "ffsend",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-firefox-send-button" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://send.firefox.com/", where: "tabshifted" },
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'payoff' && isChinaRepack == false",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_6",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 6,
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting:
|
||||
"trailheadTriplet in ['supercharge', 'static'] || ('dynamic' in trailheadTriplet && sync.mobileDevices < 1)",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_7",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 4,
|
||||
content: {
|
||||
title: { string_id: "onboarding-send-tabs-title" },
|
||||
text: { string_id: "onboarding-send-tabs-text2" },
|
||||
icon: "sendtab",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-send-tabs-button" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args:
|
||||
"https://support.mozilla.org/kb/send-tab-firefox-desktop-other-devices",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "'dynamic' in trailheadTriplet",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_8",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 2,
|
||||
content: {
|
||||
title: { string_id: "onboarding-pocket-anywhere-title" },
|
||||
text: { string_id: "onboarding-pocket-anywhere-text2" },
|
||||
icon: "pocket",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-pocket-anywhere-button" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://getpocket.com/firefox_learnmore",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'multidevice' && isChinaRepack == false",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_9",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 7,
|
||||
content: {
|
||||
title: { string_id: "onboarding-lockwise-strong-passwords-title" },
|
||||
text: { string_id: "onboarding-lockwise-strong-passwords-text" },
|
||||
icon: "lockwise",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-lockwise-strong-passwords-button" },
|
||||
action: {
|
||||
type: "OPEN_ABOUT_PAGE",
|
||||
data: { args: "logins", where: "tabshifted" },
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "'dynamic' in trailheadTriplet && isChinaRepack == false",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_10",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 4,
|
||||
content: {
|
||||
title: { string_id: "onboarding-facebook-container-title" },
|
||||
text: { string_id: "onboarding-facebook-container-text2" },
|
||||
icon: "fbcont",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-facebook-container-button" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args:
|
||||
"https://addons.mozilla.org/firefox/addon/facebook-container/",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'payoff' && isChinaRepack == false",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_11",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 0,
|
||||
content: {
|
||||
title: { string_id: "onboarding-import-browser-settings-title" },
|
||||
text: { string_id: "onboarding-import-browser-settings-text" },
|
||||
icon: "import",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-import-browser-settings-button" },
|
||||
action: { type: "SHOW_MIGRATION_WIZARD" },
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'dynamic_chrome'",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "TRAILHEAD_CARD_12",
|
||||
template: "onboarding",
|
||||
bundled: 3,
|
||||
order: 1,
|
||||
content: {
|
||||
title: { string_id: "onboarding-personal-data-promise-title" },
|
||||
text: { string_id: "onboarding-personal-data-promise-text" },
|
||||
icon: "pledge",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-personal-data-promise-button" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://www.mozilla.org/firefox/privacy/",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
targeting: "trailheadTriplet == 'privacy'",
|
||||
trigger: { id: "showOnboarding" },
|
||||
},
|
||||
{
|
||||
id: "FXA_ACCOUNTS_BADGE",
|
||||
template: "toolbar_badge",
|
||||
|
@ -16,7 +16,6 @@
|
||||
<link rel="stylesheet" href="chrome://activity-stream/content/css/activity-stream.css" />
|
||||
</head>
|
||||
<body class="activity-stream">
|
||||
<div id="header-asrouter-container" role="presentation"></div>
|
||||
<div id="root"></div>
|
||||
<div id="footer-asrouter-container" role="presentation"></div>
|
||||
<script src="chrome://browser/content/contentSearchUI.js"></script>
|
||||
|
@ -16,7 +16,6 @@
|
||||
<link rel="stylesheet" href="chrome://activity-stream/content/css/activity-stream.css" />
|
||||
</head>
|
||||
<body class="activity-stream">
|
||||
<div id="header-asrouter-container" role="presentation"></div>
|
||||
<div id="root"></div>
|
||||
<div id="footer-asrouter-container" role="presentation"></div>
|
||||
</body>
|
||||
|
@ -16,7 +16,6 @@
|
||||
<link rel="stylesheet" href="chrome://activity-stream/content/css/activity-stream.css" />
|
||||
</head>
|
||||
<body class="activity-stream">
|
||||
<div id="header-asrouter-container" role="presentation"></div>
|
||||
<div id="root"></div>
|
||||
<div id="footer-asrouter-container" role="presentation"></div>
|
||||
<script src="chrome://browser/content/contentSearchUI.js"></script>
|
||||
|
@ -126,8 +126,6 @@ describe("ASRouter", () => {
|
||||
profileAgeReset: {},
|
||||
usesFirefoxSync: false,
|
||||
isFxAEnabled: true,
|
||||
trailheadInterrupt: "join",
|
||||
trailheadTriplet: "dynamic",
|
||||
sync: {
|
||||
desktopDevices: 0,
|
||||
mobileDevices: 0,
|
||||
@ -186,9 +184,6 @@ describe("ASRouter", () => {
|
||||
sandbox.spy(ASRouterPreferences, "uninit");
|
||||
sandbox.spy(ASRouterPreferences, "addListener");
|
||||
sandbox.spy(ASRouterPreferences, "removeListener");
|
||||
sandbox.stub(ASRouterPreferences, "trailheadTriplet").get(() => {
|
||||
return "test";
|
||||
});
|
||||
sandbox.replaceGetter(
|
||||
ASRouterPreferences,
|
||||
"personalizedCfrScores",
|
||||
@ -651,7 +646,6 @@ describe("ASRouter", () => {
|
||||
ASRouterPreferences.getAllUserPreferences()
|
||||
);
|
||||
assert.deepEqual(state.targetingParameters, {});
|
||||
assert.deepEqual(state.trailhead, ASRouterPreferences.trailhead);
|
||||
assert.deepEqual(state.errors, Router.errors);
|
||||
});
|
||||
it("should not send a message on a state change asrouter.devtoolsEnabled pref is on", async () => {
|
||||
@ -1521,26 +1515,6 @@ describe("ASRouter", () => {
|
||||
|
||||
assert.deepEqual(response.message, message);
|
||||
});
|
||||
it("should send an empty object message if no bundle is available", async () => {
|
||||
// force the only message to be a bundled message that needs 2 messages in the bundle
|
||||
await Router.setState({
|
||||
messages: [
|
||||
{
|
||||
id: "foo1",
|
||||
groups: ["snippets"],
|
||||
provider: "snippets",
|
||||
template: "simple_template",
|
||||
bundled: 2,
|
||||
content: { title: "Foo1", body: "Foo123-1" },
|
||||
},
|
||||
],
|
||||
});
|
||||
let response = await Router.sendNewTabMessage({
|
||||
tabId: 0,
|
||||
browser: {},
|
||||
});
|
||||
assert.deepEqual(response.message, {});
|
||||
});
|
||||
it("should send an empty object message if no messages are available", async () => {
|
||||
await Router.setState({ messages: [] });
|
||||
let response = await Router.sendNewTabMessage({
|
||||
@ -1609,89 +1583,6 @@ describe("ASRouter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle onboarding message provider", async () => {
|
||||
const handleMessageRequestStub = sandbox.stub(
|
||||
Router,
|
||||
"handleMessageRequest"
|
||||
);
|
||||
handleMessageRequestStub
|
||||
.withArgs({
|
||||
template: "extended_triplets",
|
||||
})
|
||||
.resolves({ id: "foo" });
|
||||
sandbox.stub(Router, "sendNewTabMessage").resolves();
|
||||
await Router.sendNewTabMessage({
|
||||
tabId: 0,
|
||||
browser: {},
|
||||
});
|
||||
|
||||
assert.calledOnce(Router.sendNewTabMessage);
|
||||
});
|
||||
it("should hide extended triplets by default when browser.aboutwelcome.enabled is true", async () => {
|
||||
const handleMessageRequestStub = sandbox.stub(
|
||||
Router,
|
||||
"handleMessageRequest"
|
||||
);
|
||||
handleMessageRequestStub
|
||||
.withArgs({
|
||||
template: "extended_triplets",
|
||||
})
|
||||
.resolves({ id: "foo" });
|
||||
await Router.sendNewTabMessage({
|
||||
tabId: 0,
|
||||
browser: {},
|
||||
});
|
||||
|
||||
assert.calledOnce(handleMessageRequestStub);
|
||||
assert.calledWithExactly(handleMessageRequestStub, {
|
||||
provider: "snippets",
|
||||
});
|
||||
});
|
||||
it("should show extended triplets when browser.aboutwelcome.enabled is false", async () => {
|
||||
globals.set({ isSeparateAboutWelcome: false });
|
||||
const handleMessageRequestStub = sandbox.stub(
|
||||
Router,
|
||||
"handleMessageRequest"
|
||||
);
|
||||
handleMessageRequestStub
|
||||
.withArgs({
|
||||
template: "extended_triplets",
|
||||
})
|
||||
.resolves({ id: "foo" });
|
||||
await Router.sendNewTabMessage({
|
||||
tabId: 0,
|
||||
browser: {},
|
||||
});
|
||||
|
||||
assert.calledOnce(handleMessageRequestStub);
|
||||
assert.calledWithExactly(handleMessageRequestStub, {
|
||||
template: "extended_triplets",
|
||||
});
|
||||
});
|
||||
it("should fallback to snippets if onboarding message provider returned none when browser.aboutwelcome.enabled is false", async () => {
|
||||
globals.set({ isSeparateAboutWelcome: false });
|
||||
const handleMessageRequestStub = sandbox.stub(
|
||||
Router,
|
||||
"handleMessageRequest"
|
||||
);
|
||||
handleMessageRequestStub
|
||||
.withArgs({
|
||||
template: "extended_triplets",
|
||||
})
|
||||
.resolves(null);
|
||||
await Router.sendNewTabMessage({
|
||||
tabId: 0,
|
||||
browser: {},
|
||||
});
|
||||
|
||||
assert.calledTwice(handleMessageRequestStub);
|
||||
assert.calledWithExactly(handleMessageRequestStub, {
|
||||
template: "extended_triplets",
|
||||
});
|
||||
assert.calledWithExactly(handleMessageRequestStub, {
|
||||
provider: "snippets",
|
||||
});
|
||||
});
|
||||
it("should record telemetry for message request duration", async () => {
|
||||
const startTelemetryStopwatch = sandbox.stub(
|
||||
global.TelemetryStopwatch,
|
||||
@ -1754,65 +1645,6 @@ describe("ASRouter", () => {
|
||||
});
|
||||
|
||||
describe("#setMessageById", async () => {
|
||||
it("should call _getBundledMessages if we request a message that needs to be bundled", async () => {
|
||||
sandbox.stub(Router, "_getBundledMessages").resolves();
|
||||
// forcefully pick a message which needs to be bundled (the second message in FAKE_LOCAL_MESSAGES)
|
||||
const [, testMessage] = Router.state.messages;
|
||||
await Router.setMessageById({ id: testMessage.id });
|
||||
assert.calledOnce(Router._getBundledMessages);
|
||||
});
|
||||
it("should properly pick another message of the same template if it is bundled; force = true", async () => {
|
||||
// forcefully pick a message which needs to be bundled (the second message in FAKE_LOCAL_MESSAGES)
|
||||
const [, testMessage1, testMessage2] = Router.state.messages;
|
||||
let response = await Router.setMessageById(
|
||||
{ id: testMessage1.id },
|
||||
true /* force */
|
||||
);
|
||||
|
||||
// Expected object should have some properties of the original message it picked (testMessage1)
|
||||
// plus the bundled content of the others that it picked of the same template (testMessage2)
|
||||
const expectedObj = {
|
||||
template: testMessage1.template,
|
||||
provider: testMessage1.provider,
|
||||
bundle: [
|
||||
{ content: testMessage1.content, id: testMessage1.id, order: 1 },
|
||||
{ content: testMessage2.content, id: testMessage2.id },
|
||||
],
|
||||
};
|
||||
|
||||
assert.deepEqual(response.message, expectedObj);
|
||||
});
|
||||
it("should properly pick another message of the same template if it is bundled; force = false", async () => {
|
||||
// forcefully pick a message which needs to be bundled (the second message in FAKE_LOCAL_MESSAGES)
|
||||
const [, testMessage1, testMessage2] = Router.state.messages;
|
||||
|
||||
ASRouterTargeting.findMatchingMessage.callsFake(({ messages }) => [
|
||||
messages[0],
|
||||
]);
|
||||
|
||||
let response = await Router.setMessageById(
|
||||
{ id: testMessage1.id },
|
||||
false
|
||||
);
|
||||
|
||||
// Expected object should have some properties of the original message it picked (testMessage1)
|
||||
// plus the bundled content of the others that it picked of the same template (testMessage2)
|
||||
const expectedObj = {
|
||||
template: testMessage1.template,
|
||||
provider: testMessage1.provider,
|
||||
bundle: [
|
||||
{ content: testMessage1.content, id: testMessage1.id, order: 1 },
|
||||
{
|
||||
content: testMessage2.content,
|
||||
id: testMessage2.id,
|
||||
order: 2,
|
||||
blockOnClick: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
assert.deepEqual(response.message, expectedObj);
|
||||
});
|
||||
it("should send an empty message if provided id did not resolve to a message", async () => {
|
||||
let response = await Router.setMessageById({ id: -1 }, true, {});
|
||||
assert.deepEqual(response.message, {});
|
||||
@ -1917,33 +1749,33 @@ describe("ASRouter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#sendMessage", () => {
|
||||
it("should allow for echoing back message modifications", async () => {
|
||||
describe("#routeCFRMessage", () => {
|
||||
it("should allow for echoing back message modifications", () => {
|
||||
const message = { somekey: "some value" };
|
||||
const data = { content: message };
|
||||
const browser = {};
|
||||
let msg = await Router.sendMessage(data.content, data, false, browser);
|
||||
let msg = Router.routeCFRMessage(data.content, browser, data, false);
|
||||
assert.deepEqual(msg.message, message);
|
||||
});
|
||||
it("should call CFRPageActions.forceRecommendation if the template is cfr_action and force is true", async () => {
|
||||
sandbox.stub(CFRPageActions, "forceRecommendation");
|
||||
const testMessage = { id: "foo", template: "cfr_doorhanger" };
|
||||
await Router.setState({ messages: [testMessage] });
|
||||
await Router.sendMessage(testMessage, null, true, {});
|
||||
Router.routeCFRMessage(testMessage, {}, null, true);
|
||||
|
||||
assert.calledOnce(CFRPageActions.forceRecommendation);
|
||||
});
|
||||
it("should call BookmarkPanelHub.forceShowMessage the provider is cfr-fxa", async () => {
|
||||
const testMessage = { id: "foo", template: "fxa_bookmark_panel" };
|
||||
await Router.setState({ messages: [testMessage] });
|
||||
await Router.sendMessage(testMessage, null, true, {});
|
||||
Router.routeCFRMessage(testMessage, {}, null, true);
|
||||
assert.calledOnce(FakeBookmarkPanelHub.forceShowMessage);
|
||||
});
|
||||
it("should call CFRPageActions.addRecommendation if the template is cfr_action and force is false", async () => {
|
||||
sandbox.stub(CFRPageActions, "addRecommendation");
|
||||
const testMessage = { id: "foo", template: "cfr_doorhanger" };
|
||||
await Router.setState({ messages: [testMessage] });
|
||||
await Router.sendMessage(testMessage, {}, false, {});
|
||||
Router.routeCFRMessage(testMessage, {}, {}, false);
|
||||
assert.calledOnce(CFRPageActions.addRecommendation);
|
||||
});
|
||||
});
|
||||
@ -1956,7 +1788,6 @@ describe("ASRouter", () => {
|
||||
providerPrefs: ASRouterPreferences.providers,
|
||||
userPrefs: ASRouterPreferences.getAllUserPreferences(),
|
||||
targetingParameters: {},
|
||||
trailheadTriplet: ASRouterPreferences.trailheadTriplet,
|
||||
errors: Router.errors,
|
||||
});
|
||||
|
||||
@ -2132,48 +1963,6 @@ describe("ASRouter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("_getBundledMessages", () => {
|
||||
it("should return a null bundle if we do not have enough messages to fill the bundle", async () => {
|
||||
// force the only message to be a bundled message that needs 2 messages in the bundle
|
||||
await Router.setState({
|
||||
messages: [
|
||||
{
|
||||
id: "foo1",
|
||||
template: "simple_template",
|
||||
bundled: 2,
|
||||
content: { title: "Foo1", body: "Foo123-1" },
|
||||
groups: ["bundle"],
|
||||
provider: "snippets",
|
||||
},
|
||||
],
|
||||
providers: [{ id: "snippets" }],
|
||||
});
|
||||
const bundle = await Router._getBundledMessages(Router.state.messages[0]);
|
||||
assert.equal(bundle, null);
|
||||
});
|
||||
it("should send down extra attributes in the bundle if they exist", async () => {
|
||||
sandbox.stub(Router, "_findProvider").returns({
|
||||
getExtraAttributes() {
|
||||
return Promise.resolve({ header: "header" });
|
||||
},
|
||||
});
|
||||
await Router.setState({
|
||||
messages: [
|
||||
{
|
||||
id: "foo1",
|
||||
template: "simple_template",
|
||||
bundled: 1,
|
||||
content: { title: "Foo1", body: "Foo123-1" },
|
||||
groups: ["snippets"],
|
||||
},
|
||||
],
|
||||
providers: [{ id: "snippets" }],
|
||||
});
|
||||
const result = await Router._getBundledMessages(Router.state.messages[0]);
|
||||
assert.equal(result.extraTemplateStrings.header, "header");
|
||||
});
|
||||
});
|
||||
|
||||
describe("forceAttribution", () => {
|
||||
let setReferrerUrl;
|
||||
beforeEach(() => {
|
||||
|
@ -87,7 +87,7 @@ describe("#CachedTargetingGetter", () => {
|
||||
const [
|
||||
m1,
|
||||
m2,
|
||||
m3,
|
||||
m3 = { id: "m3" },
|
||||
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
||||
const checkMessageTargetingStub = sandbox
|
||||
.stub(ASRouterTargeting, "checkMessageTargeting")
|
||||
@ -118,7 +118,7 @@ describe("#CachedTargetingGetter", () => {
|
||||
const [
|
||||
m1,
|
||||
m2,
|
||||
m3,
|
||||
m3 = { id: "m3" },
|
||||
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
||||
const checkMessageTargetingStub = sandbox
|
||||
.stub(ASRouterTargeting, "checkMessageTargeting")
|
||||
@ -149,7 +149,7 @@ describe("#CachedTargetingGetter", () => {
|
||||
const [
|
||||
m1,
|
||||
m2,
|
||||
m3,
|
||||
m3 = { id: "m3" },
|
||||
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
||||
const checkMessageTargetingStub = sandbox
|
||||
.stub(ASRouterTargeting, "checkMessageTargeting")
|
||||
|
@ -4,7 +4,7 @@ import docs from "content-src/asrouter/docs/targeting-attributes.md";
|
||||
// The following targeting parameters are either deprecated or should not be included in the docs for some reason.
|
||||
const SKIP_DOCS = [];
|
||||
// These are extra message context attributes via ASRouter.jsm
|
||||
const MESSAGE_CONTEXT_ATTRIBUTES = ["previousSessionEnd", "trailheadTriplet"];
|
||||
const MESSAGE_CONTEXT_ATTRIBUTES = ["previousSessionEnd"];
|
||||
|
||||
function getHeadingsFromDocs() {
|
||||
const re = /### `(\w+)`/g;
|
||||
|
@ -225,39 +225,6 @@ describe("ASRouterUISurface", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Triplet bundle Card", () => {
|
||||
it("should send NEW_TAB_MESSAGE_REQUEST if a bundle card id is blocked or cleared", async () => {
|
||||
sandbox.stub(ASRouterUtils, "sendMessage").resolves();
|
||||
const FAKE_TRIPLETS_BUNDLE_1 = [
|
||||
{
|
||||
id: "CARD_1",
|
||||
content: {
|
||||
title: { string_id: "onboarding-private-browsing-title" },
|
||||
text: { string_id: "onboarding-private-browsing-text" },
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-button-label-get-started" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://example.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
wrapper.setState({
|
||||
message: { bundle: FAKE_TRIPLETS_BUNDLE_1 },
|
||||
});
|
||||
|
||||
wrapper.instance().clearMessage("CARD_1");
|
||||
assert.calledOnce(ASRouterUtils.sendMessage);
|
||||
assert.calledWithExactly(ASRouterUtils.sendMessage, {
|
||||
type: "NEWTAB_MESSAGE_REQUEST",
|
||||
data: { endpoint: undefined },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("impressions", () => {
|
||||
function simulateVisibilityChange(value) {
|
||||
fakeDocument.visibilityState = value;
|
||||
|
@ -1,225 +0,0 @@
|
||||
import {
|
||||
FirstRun,
|
||||
FLUENT_FILES,
|
||||
} from "content-src/asrouter/templates/FirstRun/FirstRun";
|
||||
import { Triplets } from "content-src/asrouter/templates/FirstRun/Triplets";
|
||||
import { OnboardingMessageProvider } from "lib/OnboardingMessageProvider.jsm";
|
||||
import { mount } from "enzyme";
|
||||
import React from "react";
|
||||
|
||||
const FAKE_TRIPLETS_BUNDLE_1 = [
|
||||
{
|
||||
id: "CARD_1",
|
||||
content: {
|
||||
title: { string_id: "onboarding-private-browsing-title" },
|
||||
text: { string_id: "onboarding-private-browsing-text" },
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-button-label-get-started" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://example.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const FAKE_TRIPLETS_BUNDLE_2 = [
|
||||
{
|
||||
id: "CARD_2",
|
||||
content: {
|
||||
title: { string_id: "onboarding-data-sync-title" },
|
||||
text: { string_id: "onboarding-data-sync-text2" },
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-data-sync-button2" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://foo.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const FAKE_FLOW_PARAMS = {
|
||||
deviceId: "foo",
|
||||
flowId: "abc1",
|
||||
flowBeginTime: 1234,
|
||||
};
|
||||
|
||||
async function getTestMessage(id, requestNewBundle) {
|
||||
const message = (
|
||||
await OnboardingMessageProvider.getUntranslatedMessages()
|
||||
).find(msg => msg.id === id);
|
||||
|
||||
// Simulate dynamic triplets by returning a different bundle
|
||||
if (requestNewBundle) {
|
||||
return { ...message, bundle: FAKE_TRIPLETS_BUNDLE_2 };
|
||||
}
|
||||
return { ...message, bundle: FAKE_TRIPLETS_BUNDLE_1 };
|
||||
}
|
||||
|
||||
describe("<FirstRun>", () => {
|
||||
let wrapper;
|
||||
let message;
|
||||
let fakeDoc;
|
||||
let sandbox;
|
||||
let clock;
|
||||
let onBlockByIdStub;
|
||||
|
||||
async function setup() {
|
||||
sandbox = sinon.createSandbox();
|
||||
clock = sandbox.useFakeTimers();
|
||||
message = await getTestMessage("EXTENDED_TRIPLETS_1");
|
||||
fakeDoc = {
|
||||
body: document.createElement("body"),
|
||||
head: document.createElement("head"),
|
||||
createElement: type => document.createElement(type),
|
||||
getElementById: () => document.createElement("div"),
|
||||
activeElement: document.createElement("div"),
|
||||
};
|
||||
onBlockByIdStub = sandbox.stub();
|
||||
|
||||
sandbox
|
||||
.stub(global, "fetch")
|
||||
.withArgs("http://fake.com/endpoint")
|
||||
.resolves({
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: () => Promise.resolve(FAKE_FLOW_PARAMS),
|
||||
});
|
||||
|
||||
wrapper = mount(
|
||||
<FirstRun
|
||||
message={message}
|
||||
document={fakeDoc}
|
||||
dispatch={() => {}}
|
||||
sendUserActionTelemetry={() => {}}
|
||||
onBlockById={onBlockByIdStub}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(setup);
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should render", () => {
|
||||
assert.ok(wrapper);
|
||||
});
|
||||
describe("with triplets", () => {
|
||||
it("should render triplets", () => {
|
||||
assert.lengthOf(wrapper.find(Triplets), 1, "<Triplets>");
|
||||
});
|
||||
it("should show the card panel and the content on the Triplets", () => {
|
||||
const tripletsProps = wrapper.find(Triplets).props();
|
||||
assert.propertyVal(tripletsProps, "showCardPanel", true);
|
||||
});
|
||||
it("should set the UTM term to trailhead-cards-card (for the extended-triplet message)", () => {
|
||||
const tProps = wrapper.find(Triplets).props();
|
||||
assert.propertyVal(tProps, "UTMTerm", "trailhead-cards-card");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with no triplets", () => {
|
||||
it("should render empty", () => {
|
||||
message = { type: "FOO_123" };
|
||||
wrapper = mount(<FirstRun message={message} document={fakeDoc} />);
|
||||
|
||||
assert.isTrue(wrapper.isEmptyRender());
|
||||
});
|
||||
});
|
||||
|
||||
it("should pass along executeAction appropriately", () => {
|
||||
const stub = sandbox.stub();
|
||||
wrapper = mount(
|
||||
<FirstRun message={message} document={fakeDoc} executeAction={stub} />
|
||||
);
|
||||
assert.propertyVal(wrapper.find(Triplets).props(), "onAction", stub);
|
||||
});
|
||||
|
||||
it("should load flow params on mount if fxaEndpoint is defined", () => {
|
||||
const stub = sandbox.stub();
|
||||
wrapper = mount(
|
||||
<FirstRun
|
||||
message={message}
|
||||
document={fakeDoc}
|
||||
fetchFlowParams={stub}
|
||||
fxaEndpoint="https://foo.com"
|
||||
/>
|
||||
);
|
||||
assert.calledOnce(stub);
|
||||
});
|
||||
|
||||
it("should load flow params onUpdate if fxaEndpoint is not defined on mount and then later defined", () => {
|
||||
const stub = sandbox.stub();
|
||||
wrapper = mount(
|
||||
<FirstRun message={message} document={fakeDoc} fetchFlowParams={stub} />
|
||||
);
|
||||
assert.notCalled(stub);
|
||||
wrapper.setProps({ fxaEndpoint: "https://foo.com" });
|
||||
assert.calledOnce(stub);
|
||||
});
|
||||
|
||||
it("should not load flow params again onUpdate if they were already set", () => {
|
||||
const stub = sandbox.stub();
|
||||
wrapper = mount(
|
||||
<FirstRun
|
||||
message={message}
|
||||
document={fakeDoc}
|
||||
fetchFlowParams={stub}
|
||||
fxaEndpoint="https://foo.com"
|
||||
/>
|
||||
);
|
||||
wrapper.setProps({ foo: "bar" });
|
||||
wrapper.setProps({ foo: "baz" });
|
||||
assert.calledOnce(stub);
|
||||
});
|
||||
|
||||
it("should load fluent files on mount", () => {
|
||||
assert.lengthOf(fakeDoc.head.querySelectorAll("link"), FLUENT_FILES.length);
|
||||
});
|
||||
|
||||
it("should update didUserClearTriplets state to true on close of triplet", () => {
|
||||
assert.isFalse(wrapper.state().didUserClearTriplets);
|
||||
// Simulate calling close Triplets
|
||||
wrapper
|
||||
.find(Triplets)
|
||||
.find(".icon-dismiss")
|
||||
.simulate("click");
|
||||
assert.isTrue(wrapper.state().didUserClearTriplets);
|
||||
});
|
||||
|
||||
it("should hide triplets when closeTriplets is called and block extended triplets after 500ms", () => {
|
||||
// Simulate calling next scene
|
||||
wrapper
|
||||
.find(Triplets)
|
||||
.find(".icon-dismiss")
|
||||
.simulate("click");
|
||||
|
||||
assert.isFalse(
|
||||
wrapper
|
||||
.find(Triplets)
|
||||
.find(".trailheadCardGrid")
|
||||
.hasClass("show"),
|
||||
"Show triplet content"
|
||||
);
|
||||
|
||||
assert.notCalled(onBlockByIdStub);
|
||||
clock.tick(500);
|
||||
assert.calledWith(onBlockByIdStub, "EXTENDED_TRIPLETS_1");
|
||||
});
|
||||
|
||||
it("should update triplets card when cards in message bundle changes", async () => {
|
||||
let tripletsProps = wrapper.find(Triplets).props();
|
||||
assert.propertyVal(tripletsProps, "cards", FAKE_TRIPLETS_BUNDLE_1);
|
||||
|
||||
const messageWithNewBundle = await getTestMessage("TRAILHEAD_1", true);
|
||||
wrapper.setProps({ message: messageWithNewBundle });
|
||||
tripletsProps = wrapper.find(Triplets).props();
|
||||
assert.propertyVal(tripletsProps, "cards", FAKE_TRIPLETS_BUNDLE_2);
|
||||
});
|
||||
});
|
@ -1,156 +0,0 @@
|
||||
import { mount } from "enzyme";
|
||||
import { Triplets } from "content-src/asrouter/templates/FirstRun/Triplets";
|
||||
import { OnboardingCard } from "content-src/asrouter/templates/OnboardingMessage/OnboardingMessage";
|
||||
import React from "react";
|
||||
|
||||
const CARDS = [
|
||||
{
|
||||
id: "CARD_1",
|
||||
content: {
|
||||
title: { string_id: "onboarding-private-browsing-title" },
|
||||
text: { string_id: "onboarding-private-browsing-text" },
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: { string_id: "onboarding-button-label-get-started" },
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://example.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "CARD_2",
|
||||
content: {
|
||||
title: "Test title",
|
||||
text: "Test body text",
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: "Test button label",
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://example.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "CARD_3",
|
||||
content: {
|
||||
title: "Test title with no body text",
|
||||
icon: "icon",
|
||||
primary_button: {
|
||||
label: "Test button label with no body text",
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: { args: "https://example.com/" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe("<Triplets>", () => {
|
||||
let wrapper;
|
||||
let sandbox;
|
||||
let sendTelemetryStub;
|
||||
let onAction;
|
||||
let onHide;
|
||||
let onBlockById;
|
||||
|
||||
async function setup() {
|
||||
sandbox = sinon.createSandbox();
|
||||
sendTelemetryStub = sandbox.stub();
|
||||
onAction = sandbox.stub();
|
||||
onBlockById = sandbox.stub();
|
||||
onHide = sandbox.stub();
|
||||
|
||||
wrapper = mount(
|
||||
<Triplets
|
||||
cards={CARDS}
|
||||
showCardPanel={true}
|
||||
showContent={true}
|
||||
hideContainer={onHide}
|
||||
onAction={onAction}
|
||||
UTMTerm="trailhead-join-card"
|
||||
onBlockById={onBlockById}
|
||||
sendUserActionTelemetry={sendTelemetryStub}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(setup);
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should add an expanded class to container if props.showCardPanel is true", () => {
|
||||
wrapper.setProps({ showCardPanel: true });
|
||||
assert.isTrue(
|
||||
wrapper.find(".trailheadCards").hasClass("expanded"),
|
||||
"has .expanded)"
|
||||
);
|
||||
});
|
||||
it("should add a collapsed class to container if props.showCardPanel is true", () => {
|
||||
wrapper.setProps({ showCardPanel: false });
|
||||
assert.isFalse(
|
||||
wrapper.find(".trailheadCards").hasClass("expanded"),
|
||||
"has .expanded)"
|
||||
);
|
||||
});
|
||||
it("should send telemetry and call props.hideContainer when the dismiss button is clicked", () => {
|
||||
wrapper.find("button.icon-dismiss").simulate("click");
|
||||
assert.calledOnce(onHide);
|
||||
assert.calledWith(sendTelemetryStub, {
|
||||
event: "DISMISS",
|
||||
message_id: `${CARDS[0].id},${CARDS[1].id},${CARDS[2].id}`,
|
||||
id: "onboarding-cards",
|
||||
action: "onboarding_user_event",
|
||||
});
|
||||
});
|
||||
it("should add utm_* query params to card actions and send the right ping when a card button is clicked", () => {
|
||||
wrapper
|
||||
.find(OnboardingCard)
|
||||
.first()
|
||||
.find("button.onboardingButton")
|
||||
.simulate("click");
|
||||
assert.calledOnce(onAction);
|
||||
const url = onAction.firstCall.args[0].data.args;
|
||||
assert.equal(
|
||||
url,
|
||||
"https://example.com/?utm_source=activity-stream&utm_campaign=firstrun&utm_medium=referral&utm_term=trailhead-join-card"
|
||||
);
|
||||
assert.calledWith(sendTelemetryStub, {
|
||||
event: "CLICK_BUTTON",
|
||||
message_id: CARDS[0].id,
|
||||
id: "TRAILHEAD",
|
||||
});
|
||||
});
|
||||
it("should not call blockById by default when a card button is clicked", () => {
|
||||
wrapper
|
||||
.find(OnboardingCard)
|
||||
.first()
|
||||
.find("button.onboardingButton")
|
||||
.simulate("click");
|
||||
assert.notCalled(onBlockById);
|
||||
});
|
||||
it("should call blockById when blockOnClick on message is true", () => {
|
||||
CARDS[0].blockOnClick = true;
|
||||
wrapper
|
||||
.find(OnboardingCard)
|
||||
.first()
|
||||
.find("button.onboardingButton")
|
||||
.simulate("click");
|
||||
assert.calledOnce(onBlockById);
|
||||
assert.calledWith(onBlockById, CARDS[0].id);
|
||||
});
|
||||
it("Onboarding card without text content should hide onboardingText paragraph", () => {
|
||||
assert.lengthOf(
|
||||
wrapper
|
||||
.find(OnboardingCard)
|
||||
.last()
|
||||
.find("p.onboardingText"),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
@ -75,7 +75,7 @@ describe("ASRouterAdmin", () => {
|
||||
assert.equal(
|
||||
wrapper
|
||||
.find("h2")
|
||||
.at(2)
|
||||
.at(1)
|
||||
.text(),
|
||||
"Messages"
|
||||
);
|
||||
|
@ -11,9 +11,6 @@
|
||||
onboarding-welcome-header = Welcome to { -brand-short-name }
|
||||
onboarding-start-browsing-button-label = Start Browsing
|
||||
onboarding-not-now-button-label = Not now
|
||||
onboarding-cards-dismiss =
|
||||
.title = Dismiss
|
||||
.aria-label = Dismiss
|
||||
|
||||
## Custom Return To AMO onboarding strings
|
||||
|
||||
@ -120,62 +117,3 @@ onboarding-multistage-theme-description-alpenglow =
|
||||
.aria-description =
|
||||
Use a colorful appearance for buttons,
|
||||
menus, and windows.
|
||||
|
||||
## These strings belong to the individual onboarding messages.
|
||||
|
||||
## Each message has a title and a description of what the browser feature is.
|
||||
## Each message also has an associated button for the user to try the feature.
|
||||
## The string for the button is found above, in the UI strings section
|
||||
|
||||
onboarding-tracking-protection-title2 = Protection From Tracking
|
||||
onboarding-tracking-protection-text2 = { -brand-short-name } helps stop websites from tracking you online, making it harder for ads to follow you around the web.
|
||||
onboarding-tracking-protection-button2 = How it Works
|
||||
|
||||
onboarding-data-sync-title = Take Your Settings with You
|
||||
# "Sync" is short for synchronize.
|
||||
onboarding-data-sync-text2 = Sync your bookmarks, passwords, and more everywhere you use { -brand-product-name }.
|
||||
onboarding-data-sync-button2 = Sign in to { -sync-brand-short-name }
|
||||
|
||||
onboarding-firefox-monitor-title = Stay Alert to Data Breaches
|
||||
onboarding-firefox-monitor-text2 = { -monitor-brand-name } monitors if your email has appeared in a known data breach and alerts you if it appears in a new breach.
|
||||
onboarding-firefox-monitor-button = Sign Up for Alerts
|
||||
|
||||
onboarding-browse-privately-title = Browse Privately
|
||||
onboarding-browse-privately-text = Private Browsing clears your search and browsing history to keep it secret from anyone who uses your computer.
|
||||
onboarding-browse-privately-button = Open a Private Window
|
||||
|
||||
onboarding-firefox-send-title = Keep Your Shared Files Private
|
||||
onboarding-firefox-send-text2 = Upload your files to { -send-brand-name } to share them with end-to-end encryption and a link that automatically expires.
|
||||
onboarding-firefox-send-button = Try { -send-brand-name }
|
||||
|
||||
onboarding-mobile-phone-title = Get { -brand-product-name } on Your Phone
|
||||
onboarding-mobile-phone-text = Download { -brand-product-name } for iOS or Android and sync your data across devices.
|
||||
# "Mobile" is short for mobile/cellular phone, "Browser" is short for web
|
||||
# browser.
|
||||
onboarding-mobile-phone-button = Download Mobile Browser
|
||||
|
||||
onboarding-send-tabs-title = Instantly Send Yourself Tabs
|
||||
# "Send Tabs" refers to "Send Tab to Device" feature that appears when opening a
|
||||
# tab's context menu.
|
||||
onboarding-send-tabs-text2 = Easily share pages between your devices without having to copy links or leave the browser.
|
||||
onboarding-send-tabs-button = Start Using Send Tabs
|
||||
|
||||
onboarding-pocket-anywhere-title = Read and Listen Anywhere
|
||||
onboarding-pocket-anywhere-text2 = Save your favorite content offline with the { -pocket-brand-name } App and read, listen, and watch whenever it’s convenient for you.
|
||||
onboarding-pocket-anywhere-button = Try { -pocket-brand-name }
|
||||
|
||||
onboarding-lockwise-strong-passwords-title = Create and Store Strong Passwords
|
||||
onboarding-lockwise-strong-passwords-text = { -lockwise-brand-name } creates strong passwords on the spot and saves all of them in one place.
|
||||
onboarding-lockwise-strong-passwords-button = Manage Your Logins
|
||||
|
||||
onboarding-facebook-container-title = Set Boundaries with Facebook
|
||||
onboarding-facebook-container-text2 = { -facebook-container-brand-name } keeps your profile separate from everything else, making it harder for Facebook to target you with ads.
|
||||
onboarding-facebook-container-button = Add the Extension
|
||||
|
||||
onboarding-import-browser-settings-title = Import Your Bookmarks, Passwords, and More
|
||||
onboarding-import-browser-settings-text = Dive right in—easily bring your Chrome sites and settings with you.
|
||||
onboarding-import-browser-settings-button = Import Chrome Data
|
||||
|
||||
onboarding-personal-data-promise-title = Private by Design
|
||||
onboarding-personal-data-promise-text = { -brand-product-name } treats your data with respect by taking less of it, protecting it, and being clear about how we use it.
|
||||
onboarding-personal-data-promise-button = Read our Promise
|
||||
|
Loading…
Reference in New Issue
Block a user