зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1812690 - Pocket newtab enabling onboarding experience for new users seeing the Pocket section for the first time. r=gvn,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D174710
This commit is contained in:
Родитель
bbf1e58474
Коммит
42b6e74c81
|
@ -1634,6 +1634,10 @@ pref("browser.newtabpage.activity-stream.discoverystream.recs.personalized", fal
|
|||
// System pref to allow Pocket sponsored content personalization to be turned on/off.
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.spocs.personalized", true);
|
||||
|
||||
// Flip this once the user has dismissed the Pocket onboarding experience,
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.onboardingExperience.dismissed", false);
|
||||
pref("browser.newtabpage.activity-stream.discoverystream.onboardingExperience.enabled", false);
|
||||
|
||||
// User pref to show stories on newtab (feeds.system.topstories has to be set to true as well)
|
||||
pref("browser.newtabpage.activity-stream.feeds.section.topstories", true);
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ for (const type of [
|
|||
"FAKE_FOCUS_SEARCH",
|
||||
"FILL_SEARCH_TERM",
|
||||
"HANDOFF_SEARCH_TO_AWESOMEBAR",
|
||||
"HIDE_PERSONALIZE",
|
||||
"HIDE_PRIVACY_INFO",
|
||||
"INIT",
|
||||
"NEW_TAB_INIT",
|
||||
|
@ -127,6 +128,7 @@ for (const type of [
|
|||
"SET_PREF",
|
||||
"SHOW_DOWNLOAD_FILE",
|
||||
"SHOW_FIREFOX_ACCOUNTS",
|
||||
"SHOW_PERSONALIZE",
|
||||
"SHOW_PRIVACY_INFO",
|
||||
"SHOW_SEARCH",
|
||||
"SKIPPED_SIGNIN",
|
||||
|
|
|
@ -17,6 +17,7 @@ export const INITIAL_STATE = {
|
|||
initialized: false,
|
||||
locale: "",
|
||||
isForStartupCache: false,
|
||||
customizeMenuVisible: false,
|
||||
},
|
||||
ASRouter: { initialized: false },
|
||||
Snippets: { initialized: false },
|
||||
|
@ -108,6 +109,14 @@ function App(prevState = INITIAL_STATE.App, action) {
|
|||
return Object.assign({}, prevState, action.data || {}, {
|
||||
isForStartupCache: false,
|
||||
});
|
||||
case at.SHOW_PERSONALIZE:
|
||||
return Object.assign({}, prevState, {
|
||||
customizeMenuVisible: true,
|
||||
});
|
||||
case at.HIDE_PERSONALIZE:
|
||||
return Object.assign({}, prevState, {
|
||||
customizeMenuVisible: false,
|
||||
});
|
||||
default:
|
||||
return prevState;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ export class BaseContent extends React.PureComponent {
|
|||
this.handleOnKeyDown = this.handleOnKeyDown.bind(this);
|
||||
this.onWindowScroll = debounce(this.onWindowScroll.bind(this), 5);
|
||||
this.setPref = this.setPref.bind(this);
|
||||
this.state = { fixedSearch: false, customizeMenuVisible: false };
|
||||
this.state = { fixedSearch: false };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -140,13 +140,13 @@ export class BaseContent extends React.PureComponent {
|
|||
}
|
||||
|
||||
openCustomizationMenu() {
|
||||
this.setState({ customizeMenuVisible: true });
|
||||
this.props.dispatch({ type: at.SHOW_PERSONALIZE });
|
||||
this.props.dispatch(ac.UserEvent({ event: "SHOW_PERSONALIZE" }));
|
||||
}
|
||||
|
||||
closeCustomizationMenu() {
|
||||
if (this.state.customizeMenuVisible) {
|
||||
this.setState({ customizeMenuVisible: false });
|
||||
if (this.props.App.customizeMenuVisible) {
|
||||
this.props.dispatch({ type: at.HIDE_PERSONALIZE });
|
||||
this.props.dispatch(ac.UserEvent({ event: "HIDE_PERSONALIZE" }));
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ export class BaseContent extends React.PureComponent {
|
|||
render() {
|
||||
const { props } = this;
|
||||
const { App } = props;
|
||||
const { initialized } = App;
|
||||
const { initialized, customizeMenuVisible } = App;
|
||||
const prefs = props.Prefs.values;
|
||||
|
||||
const isDiscoveryStream =
|
||||
|
@ -180,7 +180,6 @@ export class BaseContent extends React.PureComponent {
|
|||
!pocketEnabled &&
|
||||
filteredSections.filter(section => section.enabled).length === 0;
|
||||
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
|
||||
const showCustomizationMenu = this.state.customizeMenuVisible;
|
||||
const enabledSections = {
|
||||
topSitesEnabled: prefs["feeds.topsites"],
|
||||
pocketEnabled: prefs["feeds.section.topstories"],
|
||||
|
@ -224,7 +223,7 @@ export class BaseContent extends React.PureComponent {
|
|||
enabledSections={enabledSections}
|
||||
pocketRegion={pocketRegion}
|
||||
mayHaveSponsoredTopSites={mayHaveSponsoredTopSites}
|
||||
showing={showCustomizationMenu}
|
||||
showing={customizeMenuVisible}
|
||||
/>
|
||||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions*/}
|
||||
<div className={outerClassName} onClick={this.closeCustomizationMenu}>
|
||||
|
|
|
@ -192,6 +192,7 @@ export class _DiscoveryStreamBase extends React.PureComponent {
|
|||
fourCardLayout={component.properties.fourCardLayout}
|
||||
compactGrid={component.properties.compactGrid}
|
||||
essentialReadsHeader={component.properties.essentialReadsHeader}
|
||||
onboardingExperience={component.properties.onboardingExperience}
|
||||
editorsPicksHeader={component.properties.editorsPicksHeader}
|
||||
recentSavesEnabled={this.props.DiscoveryStream.recentSavesEnabled}
|
||||
hideDescriptions={this.props.DiscoveryStream.hideDescriptions}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import { DSCard, PlaceholderDSCard } from "../DSCard/DSCard.jsx";
|
||||
import { DSEmptyState } from "../DSEmptyState/DSEmptyState.jsx";
|
||||
import { DSDismiss } from "content-src/components/DiscoveryStreamComponents/DSDismiss/DSDismiss";
|
||||
import { TopicsWidget } from "../TopicsWidget/TopicsWidget.jsx";
|
||||
import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
|
||||
import { FluentOrText } from "../../FluentOrText/FluentOrText.jsx";
|
||||
|
@ -13,6 +14,9 @@ import {
|
|||
} from "common/Actions.sys.mjs";
|
||||
import React, { useEffect, useState, useRef, useCallback } from "react";
|
||||
import { connect, useSelector } from "react-redux";
|
||||
const PREF_ONBOARDING_EXPERIENCE_DISMISSED =
|
||||
"discoverystream.onboardingExperience.dismissed";
|
||||
const INTERSECTION_RATIO = 0.5;
|
||||
const WIDGET_IDS = {
|
||||
TOPICS: 1,
|
||||
};
|
||||
|
@ -25,6 +29,99 @@ export function DSSubHeader({ children }) {
|
|||
);
|
||||
}
|
||||
|
||||
export function OnboardingExperience({
|
||||
children,
|
||||
dispatch,
|
||||
windowObj = global,
|
||||
}) {
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
const [maxHeight, setMaxHeight] = useState(null);
|
||||
const heightElement = useRef(null);
|
||||
|
||||
const onDismissClick = useCallback(() => {
|
||||
// We update this as state and redux.
|
||||
// The state update is for this newtab,
|
||||
// and the redux update is for other tabs, offscreen tabs, and future tabs.
|
||||
// We need the state update for this tab to support the transition.
|
||||
setDismissed(true);
|
||||
dispatch(ac.SetPref(PREF_ONBOARDING_EXPERIENCE_DISMISSED, true));
|
||||
dispatch(
|
||||
ac.DiscoveryStreamUserEvent({
|
||||
event: "BLOCK",
|
||||
source: "POCKET_ONBOARDING",
|
||||
})
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
const resizeObserver = new windowObj.ResizeObserver(() => {
|
||||
if (heightElement.current) {
|
||||
setMaxHeight(heightElement.current.offsetHeight);
|
||||
}
|
||||
});
|
||||
|
||||
const options = { threshold: INTERSECTION_RATIO };
|
||||
const intersectionObserver = new windowObj.IntersectionObserver(entries => {
|
||||
if (
|
||||
entries.some(
|
||||
entry =>
|
||||
entry.isIntersecting &&
|
||||
entry.intersectionRatio >= INTERSECTION_RATIO
|
||||
)
|
||||
) {
|
||||
dispatch(
|
||||
ac.DiscoveryStreamUserEvent({
|
||||
event: "IMPRESSION",
|
||||
source: "POCKET_ONBOARDING",
|
||||
})
|
||||
);
|
||||
// Once we have observed an impression, we can stop for this instance of newtab.
|
||||
intersectionObserver.unobserve(heightElement.current);
|
||||
}
|
||||
}, options);
|
||||
if (heightElement.current) {
|
||||
resizeObserver.observe(heightElement.current);
|
||||
intersectionObserver.observe(heightElement.current);
|
||||
setMaxHeight(heightElement.current.offsetHeight);
|
||||
}
|
||||
|
||||
// Return unmount callback to clean up observers.
|
||||
return () => {
|
||||
resizeObserver?.disconnect();
|
||||
intersectionObserver?.disconnect();
|
||||
};
|
||||
}, [dispatch, windowObj]);
|
||||
|
||||
const style = {};
|
||||
if (dismissed) {
|
||||
style.maxHeight = "0";
|
||||
style.opacity = "0";
|
||||
style.transition = "max-height 0.26s ease, opacity 0.26s ease";
|
||||
} else if (maxHeight) {
|
||||
style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
<div className="ds-onboarding-ref" ref={heightElement}>
|
||||
<div className="ds-onboarding">
|
||||
<DSDismiss
|
||||
onDismissClick={onDismissClick}
|
||||
extraClasses={`ds-onboarding-dismiss`}
|
||||
>
|
||||
<div className="ds-onboarding-graphic" />
|
||||
<header>
|
||||
<span className="icon icon-pocket" />
|
||||
<span data-l10n-id="newtab-pocket-onboarding-discover" />
|
||||
</header>
|
||||
<p data-l10n-id="newtab-pocket-onboarding-cta" />
|
||||
</DSDismiss>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function IntersectionObserver({
|
||||
children,
|
||||
windowObj = window,
|
||||
|
@ -204,6 +301,7 @@ export class _CardGrid extends React.PureComponent {
|
|||
compactGrid,
|
||||
essentialReadsHeader,
|
||||
editorsPicksHeader,
|
||||
onboardingExperience,
|
||||
widgets,
|
||||
recentSavesEnabled,
|
||||
hideDescriptions,
|
||||
|
@ -211,6 +309,8 @@ export class _CardGrid extends React.PureComponent {
|
|||
} = this.props;
|
||||
const { saveToPocketCard } = DiscoveryStream;
|
||||
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
|
||||
const isOnboardingExperienceDismissed =
|
||||
prefs[PREF_ONBOARDING_EXPERIENCE_DISMISSED];
|
||||
|
||||
const recs = this.props.data.recommendations.slice(0, items);
|
||||
const cards = [];
|
||||
|
@ -319,10 +419,13 @@ export class _CardGrid extends React.PureComponent {
|
|||
? `ds-card-grid-hybrid-layout`
|
||||
: ``;
|
||||
|
||||
const gridClassName = `ds-card-grid ds-card-grid-border ${hybridLayoutClassName} ${hideCardBackgroundClass} ${fourCardLayoutClass} ${hideDescriptionsClassName} ${compactGridClassName}`;
|
||||
const gridClassName = `ds-card-grid ${hybridLayoutClassName} ${hideCardBackgroundClass} ${fourCardLayoutClass} ${hideDescriptionsClassName} ${compactGridClassName}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isOnboardingExperienceDismissed && onboardingExperience && (
|
||||
<OnboardingExperience dispatch={this.props.dispatch} />
|
||||
)}
|
||||
{essentialReadsCards?.length > 0 && (
|
||||
<div className={gridClassName}>{essentialReadsCards}</div>
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,123 @@
|
|||
$col4-header-line-height: 20;
|
||||
$col4-header-font-size: 14;
|
||||
|
||||
.ds-onboarding,
|
||||
.ds-card-grid .ds-card {
|
||||
@include dark-theme-only {
|
||||
background: none;
|
||||
}
|
||||
|
||||
background: $white;
|
||||
border-radius: 4px;
|
||||
|
||||
&:not(.placeholder) {
|
||||
@include dark-theme-only {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
border-radius: $border-radius-new;
|
||||
box-shadow: $shadow-card;
|
||||
|
||||
.img-wrapper .img {
|
||||
img,
|
||||
.placeholder-image {
|
||||
border-radius: $border-radius-new $border-radius-new 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ds-onboarding-ref {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ds-onboarding {
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: 16px;
|
||||
@media (min-width: $break-point-medium) {
|
||||
padding-inline-end: 48px;
|
||||
}
|
||||
@media (min-width: $break-point-large) {
|
||||
padding-inline-end: 56px;
|
||||
}
|
||||
margin-bottom: 24px;
|
||||
display: inline-block;
|
||||
// This is to position the dismiss button to the right most of this element.
|
||||
position: relative;
|
||||
|
||||
.ds-dismiss {
|
||||
position: static;
|
||||
|
||||
.ds-dismiss-button {
|
||||
inset-inline-end: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
@include dark-theme-only {
|
||||
color: var(--newtab-background-color-primary);
|
||||
}
|
||||
display: flex;
|
||||
margin: 32px 0 8px;
|
||||
@media (min-width: $break-point-medium) {
|
||||
margin: 16px 0 8px;
|
||||
display: block;
|
||||
height: 24px;
|
||||
}
|
||||
font-size: 17px;
|
||||
line-height: 23.8px;
|
||||
font-weight: 600;
|
||||
color: $pocket-icon-fill;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0 16px;
|
||||
font-size: 13px;
|
||||
line-height: 19.5px;
|
||||
}
|
||||
|
||||
.icon-pocket {
|
||||
@include dark-theme-only {
|
||||
fill: var(--newtab-text-primary-color);
|
||||
}
|
||||
fill: $pocket-icon-fill;
|
||||
margin-top: 3px;
|
||||
margin-inline-end: 8px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
background-image: url('chrome://global/skin/icons/pocket.svg');
|
||||
@media (min-width: $break-point-medium) {
|
||||
margin-top: -5px;
|
||||
margin-inline-start: -2px;
|
||||
margin-inline-end: 15px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.ds-onboarding-graphic {
|
||||
background-image: url('chrome://activity-stream/content/data/content/assets/pocket-onboarding.avif');
|
||||
@media (min-resolution: 2x) {
|
||||
background-image: url('chrome://activity-stream/content/data/content/assets/pocket-onboarding@2x.avif');
|
||||
}
|
||||
border-radius: 8px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 120px;
|
||||
width: 200px;
|
||||
margin-inline-start: 54px;
|
||||
margin-bottom: 16px;
|
||||
float: inline-end;
|
||||
display: none;
|
||||
|
||||
@media (min-width: $break-point-large) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px;
|
||||
|
@ -20,32 +137,6 @@ $col4-header-font-size: 14;
|
|||
}
|
||||
}
|
||||
|
||||
.ds-card {
|
||||
@include dark-theme-only {
|
||||
background: none;
|
||||
}
|
||||
|
||||
background: $white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&.ds-card-grid-border {
|
||||
.ds-card:not(.placeholder) {
|
||||
@include dark-theme-only {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
border-radius: $border-radius-new;
|
||||
box-shadow: $shadow-card;
|
||||
|
||||
.img-wrapper .img {
|
||||
img,
|
||||
.placeholder-image {
|
||||
border-radius: $border-radius-new $border-radius-new 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ds-card-link:focus {
|
||||
@include ds-focus;
|
||||
transition: none;
|
||||
|
@ -193,8 +284,8 @@ $col4-header-font-size: 14;
|
|||
}
|
||||
}
|
||||
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card {
|
||||
&:not(.placeholder) {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
|
|
|
@ -23,9 +23,5 @@
|
|||
&:is(:hover, :focus, .active) {
|
||||
@include context-menu-button-hover;
|
||||
outline: none;
|
||||
|
||||
&.ds-card-grid-border {
|
||||
@include fade-in-card;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2625,6 +2625,127 @@ main.has-snippet {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ds-onboarding,
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding,
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-onboarding:not(.placeholder),
|
||||
.ds-card-grid .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding:not(.placeholder),
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img .placeholder-image,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.ds-onboarding-ref {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ds-onboarding {
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: 16px;
|
||||
margin-bottom: 24px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 48px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 56px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-dismiss {
|
||||
position: static;
|
||||
}
|
||||
.ds-onboarding .ds-dismiss .ds-dismiss-button {
|
||||
inset-inline-end: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
.ds-onboarding header {
|
||||
display: flex;
|
||||
margin: 32px 0 8px;
|
||||
font-size: 17px;
|
||||
line-height: 23.8px;
|
||||
font-weight: 600;
|
||||
color: #EF4056;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding header {
|
||||
color: var(--newtab-background-color-primary);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding header {
|
||||
margin: 16px 0 8px;
|
||||
display: block;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding p {
|
||||
margin: 8px 0 16px;
|
||||
font-size: 13px;
|
||||
line-height: 19.5px;
|
||||
}
|
||||
.ds-onboarding .icon-pocket {
|
||||
fill: #EF4056;
|
||||
margin-top: 3px;
|
||||
margin-inline-end: 8px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
background-image: url("chrome://global/skin/icons/pocket.svg");
|
||||
background-size: contain;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding .icon-pocket {
|
||||
fill: var(--newtab-text-primary-color);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding .icon-pocket {
|
||||
margin-top: -5px;
|
||||
margin-inline-start: -2px;
|
||||
margin-inline-end: 15px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding.avif");
|
||||
border-radius: 8px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 120px;
|
||||
width: 200px;
|
||||
margin-inline-start: 54px;
|
||||
margin-bottom: 16px;
|
||||
float: inline-end;
|
||||
display: none;
|
||||
}
|
||||
@media (min-resolution: 2x) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding@2x.avif");
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px;
|
||||
|
@ -2637,24 +2758,6 @@ main.has-snippet {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
.ds-card-grid .ds-card-link:focus {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
@ -2851,28 +2954,28 @@ main.has-snippet {
|
|||
}
|
||||
}
|
||||
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
|
||||
|
@ -3271,11 +3374,6 @@ main.has-snippet {
|
|||
transform: scale(1);
|
||||
transition-delay: 333ms;
|
||||
}
|
||||
.ds-card:is(:hover, :focus, .active).ds-card-grid-border,
|
||||
.ds-signup:is(:hover, :focus, .active).ds-card-grid-border {
|
||||
box-shadow: 0 0 0 5px var(--newtab-element-secondary-color);
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
|
||||
.ds-card {
|
||||
display: flex;
|
||||
|
|
|
@ -2629,6 +2629,127 @@ main.has-snippet {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ds-onboarding,
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding,
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-onboarding:not(.placeholder),
|
||||
.ds-card-grid .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding:not(.placeholder),
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img .placeholder-image,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.ds-onboarding-ref {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ds-onboarding {
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: 16px;
|
||||
margin-bottom: 24px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 48px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 56px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-dismiss {
|
||||
position: static;
|
||||
}
|
||||
.ds-onboarding .ds-dismiss .ds-dismiss-button {
|
||||
inset-inline-end: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
.ds-onboarding header {
|
||||
display: flex;
|
||||
margin: 32px 0 8px;
|
||||
font-size: 17px;
|
||||
line-height: 23.8px;
|
||||
font-weight: 600;
|
||||
color: #EF4056;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding header {
|
||||
color: var(--newtab-background-color-primary);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding header {
|
||||
margin: 16px 0 8px;
|
||||
display: block;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding p {
|
||||
margin: 8px 0 16px;
|
||||
font-size: 13px;
|
||||
line-height: 19.5px;
|
||||
}
|
||||
.ds-onboarding .icon-pocket {
|
||||
fill: #EF4056;
|
||||
margin-top: 3px;
|
||||
margin-inline-end: 8px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
background-image: url("chrome://global/skin/icons/pocket.svg");
|
||||
background-size: contain;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding .icon-pocket {
|
||||
fill: var(--newtab-text-primary-color);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding .icon-pocket {
|
||||
margin-top: -5px;
|
||||
margin-inline-start: -2px;
|
||||
margin-inline-end: 15px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding.avif");
|
||||
border-radius: 8px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 120px;
|
||||
width: 200px;
|
||||
margin-inline-start: 54px;
|
||||
margin-bottom: 16px;
|
||||
float: inline-end;
|
||||
display: none;
|
||||
}
|
||||
@media (min-resolution: 2x) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding@2x.avif");
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px;
|
||||
|
@ -2641,24 +2762,6 @@ main.has-snippet {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
.ds-card-grid .ds-card-link:focus {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
@ -2855,28 +2958,28 @@ main.has-snippet {
|
|||
}
|
||||
}
|
||||
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
|
||||
|
@ -3275,11 +3378,6 @@ main.has-snippet {
|
|||
transform: scale(1);
|
||||
transition-delay: 333ms;
|
||||
}
|
||||
.ds-card:is(:hover, :focus, .active).ds-card-grid-border,
|
||||
.ds-signup:is(:hover, :focus, .active).ds-card-grid-border {
|
||||
box-shadow: 0 0 0 5px var(--newtab-element-secondary-color);
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
|
||||
.ds-card {
|
||||
display: flex;
|
||||
|
|
|
@ -2625,6 +2625,127 @@ main.has-snippet {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ds-onboarding,
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding,
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-onboarding:not(.placeholder),
|
||||
.ds-card-grid .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding:not(.placeholder),
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-onboarding:not(.placeholder) .img-wrapper .img .placeholder-image,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.ds-onboarding-ref {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ds-onboarding {
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: 16px;
|
||||
margin-bottom: 24px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 48px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding {
|
||||
padding-inline-end: 56px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-dismiss {
|
||||
position: static;
|
||||
}
|
||||
.ds-onboarding .ds-dismiss .ds-dismiss-button {
|
||||
inset-inline-end: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
.ds-onboarding header {
|
||||
display: flex;
|
||||
margin: 32px 0 8px;
|
||||
font-size: 17px;
|
||||
line-height: 23.8px;
|
||||
font-weight: 600;
|
||||
color: #EF4056;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding header {
|
||||
color: var(--newtab-background-color-primary);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding header {
|
||||
margin: 16px 0 8px;
|
||||
display: block;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding p {
|
||||
margin: 8px 0 16px;
|
||||
font-size: 13px;
|
||||
line-height: 19.5px;
|
||||
}
|
||||
.ds-onboarding .icon-pocket {
|
||||
fill: #EF4056;
|
||||
margin-top: 3px;
|
||||
margin-inline-end: 8px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
background-image: url("chrome://global/skin/icons/pocket.svg");
|
||||
background-size: contain;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-onboarding .icon-pocket {
|
||||
fill: var(--newtab-text-primary-color);
|
||||
}
|
||||
@media (min-width: 610px) {
|
||||
.ds-onboarding .icon-pocket {
|
||||
margin-top: -5px;
|
||||
margin-inline-start: -2px;
|
||||
margin-inline-end: 15px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding.avif");
|
||||
border-radius: 8px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 120px;
|
||||
width: 200px;
|
||||
margin-inline-start: 54px;
|
||||
margin-bottom: 16px;
|
||||
float: inline-end;
|
||||
display: none;
|
||||
}
|
||||
@media (min-resolution: 2x) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/pocket-onboarding@2x.avif");
|
||||
}
|
||||
}
|
||||
@media (min-width: 866px) {
|
||||
.ds-onboarding .ds-onboarding-graphic {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px;
|
||||
|
@ -2637,24 +2758,6 @@ main.has-snippet {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.ds-card-grid .ds-card {
|
||||
background: #FFF;
|
||||
border-radius: 4px;
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid .ds-card {
|
||||
background: none;
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
[lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
background: var(--newtab-background-color-secondary);
|
||||
}
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img .placeholder-image {
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
.ds-card-grid .ds-card-link:focus {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
@ -2851,28 +2954,28 @@ main.has-snippet {
|
|||
}
|
||||
}
|
||||
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder),
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) {
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .ds-card-link:focus .img-wrapper .img img {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 3px var(--newtab-primary-action-background-dimmed), 0 0 0 1px var(--newtab-primary-action-background);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background.ds-card-grid-border .ds-card:not(.placeholder) .meta {
|
||||
.outer-wrapper .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta,
|
||||
.outer-wrapper.newtab-experience .ds-card-grid.ds-card-grid-hide-background .ds-card:not(.placeholder) .meta {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
|
||||
|
@ -3271,11 +3374,6 @@ main.has-snippet {
|
|||
transform: scale(1);
|
||||
transition-delay: 333ms;
|
||||
}
|
||||
.ds-card:is(:hover, :focus, .active).ds-card-grid-border,
|
||||
.ds-signup:is(:hover, :focus, .active).ds-card-grid-border {
|
||||
box-shadow: 0 0 0 5px var(--newtab-element-secondary-color);
|
||||
transition: box-shadow 150ms;
|
||||
}
|
||||
|
||||
.ds-card {
|
||||
display: flex;
|
||||
|
|
|
@ -152,6 +152,7 @@ for (const type of [
|
|||
"FAKE_FOCUS_SEARCH",
|
||||
"FILL_SEARCH_TERM",
|
||||
"HANDOFF_SEARCH_TO_AWESOMEBAR",
|
||||
"HIDE_PERSONALIZE",
|
||||
"HIDE_PRIVACY_INFO",
|
||||
"INIT",
|
||||
"NEW_TAB_INIT",
|
||||
|
@ -200,6 +201,7 @@ for (const type of [
|
|||
"SET_PREF",
|
||||
"SHOW_DOWNLOAD_FILE",
|
||||
"SHOW_FIREFOX_ACCOUNTS",
|
||||
"SHOW_PERSONALIZE",
|
||||
"SHOW_PRIVACY_INFO",
|
||||
"SHOW_SEARCH",
|
||||
"SKIPPED_SIGNIN",
|
||||
|
@ -8216,6 +8218,59 @@ class DSEmptyState extends (external_React_default()).PureComponent {
|
|||
}, this.renderState()));
|
||||
}
|
||||
|
||||
}
|
||||
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSDismiss/DSDismiss.jsx
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
class DSDismiss extends (external_React_default()).PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onDismissClick = this.onDismissClick.bind(this);
|
||||
this.onHover = this.onHover.bind(this);
|
||||
this.offHover = this.offHover.bind(this);
|
||||
this.state = {
|
||||
hovering: false
|
||||
};
|
||||
}
|
||||
|
||||
onDismissClick() {
|
||||
if (this.props.onDismissClick) {
|
||||
this.props.onDismissClick();
|
||||
}
|
||||
}
|
||||
|
||||
onHover() {
|
||||
this.setState({
|
||||
hovering: true
|
||||
});
|
||||
}
|
||||
|
||||
offHover() {
|
||||
this.setState({
|
||||
hovering: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let className = `ds-dismiss
|
||||
${this.state.hovering ? ` hovering` : ``}
|
||||
${this.props.extraClasses ? ` ${this.props.extraClasses}` : ``}`;
|
||||
return /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: className
|
||||
}, this.props.children, /*#__PURE__*/external_React_default().createElement("button", {
|
||||
className: "ds-dismiss-button",
|
||||
"data-l10n-id": "newtab-dismiss-button-tooltip",
|
||||
onHover: this.onHover,
|
||||
onClick: this.onDismissClick,
|
||||
onMouseEnter: this.onHover,
|
||||
onMouseLeave: this.offHover
|
||||
}, /*#__PURE__*/external_React_default().createElement("span", {
|
||||
className: "icon icon-dismiss"
|
||||
})));
|
||||
}
|
||||
|
||||
}
|
||||
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/TopicsWidget/TopicsWidget.jsx
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
|
@ -8352,6 +8407,9 @@ const TopicsWidget = (0,external_ReactRedux_namespaceObject.connect)(state => ({
|
|||
|
||||
|
||||
|
||||
|
||||
const PREF_ONBOARDING_EXPERIENCE_DISMISSED = "discoverystream.onboardingExperience.dismissed";
|
||||
const CardGrid_INTERSECTION_RATIO = 0.5;
|
||||
const WIDGET_IDS = {
|
||||
TOPICS: 1
|
||||
};
|
||||
|
@ -8364,6 +8422,88 @@ function DSSubHeader({
|
|||
className: "section-title-container"
|
||||
}, children));
|
||||
}
|
||||
function OnboardingExperience({
|
||||
children,
|
||||
dispatch,
|
||||
windowObj = __webpack_require__.g
|
||||
}) {
|
||||
const [dismissed, setDismissed] = (0,external_React_namespaceObject.useState)(false);
|
||||
const [maxHeight, setMaxHeight] = (0,external_React_namespaceObject.useState)(null);
|
||||
const heightElement = (0,external_React_namespaceObject.useRef)(null);
|
||||
const onDismissClick = (0,external_React_namespaceObject.useCallback)(() => {
|
||||
// We update this as state and redux.
|
||||
// The state update is for this newtab,
|
||||
// and the redux update is for other tabs, offscreen tabs, and future tabs.
|
||||
// We need the state update for this tab to support the transition.
|
||||
setDismissed(true);
|
||||
dispatch(actionCreators.SetPref(PREF_ONBOARDING_EXPERIENCE_DISMISSED, true));
|
||||
dispatch(actionCreators.DiscoveryStreamUserEvent({
|
||||
event: "BLOCK",
|
||||
source: "POCKET_ONBOARDING"
|
||||
}));
|
||||
}, [dispatch]);
|
||||
(0,external_React_namespaceObject.useEffect)(() => {
|
||||
const resizeObserver = new windowObj.ResizeObserver(() => {
|
||||
if (heightElement.current) {
|
||||
setMaxHeight(heightElement.current.offsetHeight);
|
||||
}
|
||||
});
|
||||
const options = {
|
||||
threshold: CardGrid_INTERSECTION_RATIO
|
||||
};
|
||||
const intersectionObserver = new windowObj.IntersectionObserver(entries => {
|
||||
if (entries.some(entry => entry.isIntersecting && entry.intersectionRatio >= CardGrid_INTERSECTION_RATIO)) {
|
||||
dispatch(actionCreators.DiscoveryStreamUserEvent({
|
||||
event: "IMPRESSION",
|
||||
source: "POCKET_ONBOARDING"
|
||||
})); // Once we have observed an impression, we can stop for this instance of newtab.
|
||||
|
||||
intersectionObserver.unobserve(heightElement.current);
|
||||
}
|
||||
}, options);
|
||||
|
||||
if (heightElement.current) {
|
||||
resizeObserver.observe(heightElement.current);
|
||||
intersectionObserver.observe(heightElement.current);
|
||||
setMaxHeight(heightElement.current.offsetHeight);
|
||||
} // Return unmount callback to clean up observers.
|
||||
|
||||
|
||||
return () => {
|
||||
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
||||
intersectionObserver === null || intersectionObserver === void 0 ? void 0 : intersectionObserver.disconnect();
|
||||
};
|
||||
}, [dispatch, windowObj]);
|
||||
const style = {};
|
||||
|
||||
if (dismissed) {
|
||||
style.maxHeight = "0";
|
||||
style.opacity = "0";
|
||||
style.transition = "max-height 0.26s ease, opacity 0.26s ease";
|
||||
} else if (maxHeight) {
|
||||
style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
|
||||
return /*#__PURE__*/external_React_default().createElement("div", {
|
||||
style: style
|
||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: "ds-onboarding-ref",
|
||||
ref: heightElement
|
||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: "ds-onboarding"
|
||||
}, /*#__PURE__*/external_React_default().createElement(DSDismiss, {
|
||||
onDismissClick: onDismissClick,
|
||||
extraClasses: `ds-onboarding-dismiss`
|
||||
}, /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: "ds-onboarding-graphic"
|
||||
}), /*#__PURE__*/external_React_default().createElement("header", null, /*#__PURE__*/external_React_default().createElement("span", {
|
||||
className: "icon icon-pocket"
|
||||
}), /*#__PURE__*/external_React_default().createElement("span", {
|
||||
"data-l10n-id": "newtab-pocket-onboarding-discover"
|
||||
})), /*#__PURE__*/external_React_default().createElement("p", {
|
||||
"data-l10n-id": "newtab-pocket-onboarding-cta"
|
||||
})))));
|
||||
}
|
||||
function CardGrid_IntersectionObserver({
|
||||
children,
|
||||
windowObj = window,
|
||||
|
@ -8537,6 +8677,7 @@ class _CardGrid extends (external_React_default()).PureComponent {
|
|||
compactGrid,
|
||||
essentialReadsHeader,
|
||||
editorsPicksHeader,
|
||||
onboardingExperience,
|
||||
widgets,
|
||||
recentSavesEnabled,
|
||||
hideDescriptions,
|
||||
|
@ -8546,6 +8687,7 @@ class _CardGrid extends (external_React_default()).PureComponent {
|
|||
saveToPocketCard
|
||||
} = DiscoveryStream;
|
||||
const showRecentSaves = prefs.showRecentSaves && recentSavesEnabled;
|
||||
const isOnboardingExperienceDismissed = prefs[PREF_ONBOARDING_EXPERIENCE_DISMISSED];
|
||||
const recs = this.props.data.recommendations.slice(0, items);
|
||||
const cards = [];
|
||||
let essentialReadsCards = [];
|
||||
|
@ -8638,8 +8780,10 @@ class _CardGrid extends (external_React_default()).PureComponent {
|
|||
const hideDescriptionsClassName = !hideDescriptions ? `ds-card-grid-include-descriptions` : ``;
|
||||
const compactGridClassName = compactGrid ? `ds-card-grid-compact` : ``;
|
||||
const hybridLayoutClassName = hybridLayout ? `ds-card-grid-hybrid-layout` : ``;
|
||||
const gridClassName = `ds-card-grid ds-card-grid-border ${hybridLayoutClassName} ${hideCardBackgroundClass} ${fourCardLayoutClass} ${hideDescriptionsClassName} ${compactGridClassName}`;
|
||||
return /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null, ((_essentialReadsCards = essentialReadsCards) === null || _essentialReadsCards === void 0 ? void 0 : _essentialReadsCards.length) > 0 && /*#__PURE__*/external_React_default().createElement("div", {
|
||||
const gridClassName = `ds-card-grid ${hybridLayoutClassName} ${hideCardBackgroundClass} ${fourCardLayoutClass} ${hideDescriptionsClassName} ${compactGridClassName}`;
|
||||
return /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null, !isOnboardingExperienceDismissed && onboardingExperience && /*#__PURE__*/external_React_default().createElement(OnboardingExperience, {
|
||||
dispatch: this.props.dispatch
|
||||
}), ((_essentialReadsCards = essentialReadsCards) === null || _essentialReadsCards === void 0 ? void 0 : _essentialReadsCards.length) > 0 && /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: gridClassName
|
||||
}, essentialReadsCards), showRecentSaves && /*#__PURE__*/external_React_default().createElement(RecentSavesContainer, {
|
||||
gridClassName: gridClassName,
|
||||
|
@ -8696,59 +8840,6 @@ const CardGrid = (0,external_ReactRedux_namespaceObject.connect)(state => ({
|
|||
Prefs: state.Prefs,
|
||||
DiscoveryStream: state.DiscoveryStream
|
||||
}))(_CardGrid);
|
||||
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSDismiss/DSDismiss.jsx
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
class DSDismiss extends (external_React_default()).PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onDismissClick = this.onDismissClick.bind(this);
|
||||
this.onHover = this.onHover.bind(this);
|
||||
this.offHover = this.offHover.bind(this);
|
||||
this.state = {
|
||||
hovering: false
|
||||
};
|
||||
}
|
||||
|
||||
onDismissClick() {
|
||||
if (this.props.onDismissClick) {
|
||||
this.props.onDismissClick();
|
||||
}
|
||||
}
|
||||
|
||||
onHover() {
|
||||
this.setState({
|
||||
hovering: true
|
||||
});
|
||||
}
|
||||
|
||||
offHover() {
|
||||
this.setState({
|
||||
hovering: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let className = `ds-dismiss
|
||||
${this.state.hovering ? ` hovering` : ``}
|
||||
${this.props.extraClasses ? ` ${this.props.extraClasses}` : ``}`;
|
||||
return /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: className
|
||||
}, this.props.children, /*#__PURE__*/external_React_default().createElement("button", {
|
||||
className: "ds-dismiss-button",
|
||||
"data-l10n-id": "newtab-dismiss-button-tooltip",
|
||||
onHover: this.onHover,
|
||||
onClick: this.onDismissClick,
|
||||
onMouseEnter: this.onHover,
|
||||
onMouseLeave: this.offHover
|
||||
}, /*#__PURE__*/external_React_default().createElement("span", {
|
||||
className: "icon icon-dismiss"
|
||||
})));
|
||||
}
|
||||
|
||||
}
|
||||
;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/CollectionCardGrid/CollectionCardGrid.jsx
|
||||
/* 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,
|
||||
|
@ -10561,6 +10652,7 @@ const INITIAL_STATE = {
|
|||
initialized: false,
|
||||
locale: "",
|
||||
isForStartupCache: false,
|
||||
customizeMenuVisible: false,
|
||||
},
|
||||
ASRouter: { initialized: false },
|
||||
Snippets: { initialized: false },
|
||||
|
@ -10652,6 +10744,14 @@ function App(prevState = INITIAL_STATE.App, action) {
|
|||
return Object.assign({}, prevState, action.data || {}, {
|
||||
isForStartupCache: false,
|
||||
});
|
||||
case actionTypes.SHOW_PERSONALIZE:
|
||||
return Object.assign({}, prevState, {
|
||||
customizeMenuVisible: true,
|
||||
});
|
||||
case actionTypes.HIDE_PERSONALIZE:
|
||||
return Object.assign({}, prevState, {
|
||||
customizeMenuVisible: false,
|
||||
});
|
||||
default:
|
||||
return prevState;
|
||||
}
|
||||
|
@ -13890,6 +13990,7 @@ class _DiscoveryStreamBase extends (external_React_default()).PureComponent {
|
|||
fourCardLayout: component.properties.fourCardLayout,
|
||||
compactGrid: component.properties.compactGrid,
|
||||
essentialReadsHeader: component.properties.essentialReadsHeader,
|
||||
onboardingExperience: component.properties.onboardingExperience,
|
||||
editorsPicksHeader: component.properties.editorsPicksHeader,
|
||||
recentSavesEnabled: this.props.DiscoveryStream.recentSavesEnabled,
|
||||
hideDescriptions: this.props.DiscoveryStream.hideDescriptions
|
||||
|
@ -14733,8 +14834,7 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
this.onWindowScroll = debounce(this.onWindowScroll.bind(this), 5);
|
||||
this.setPref = this.setPref.bind(this);
|
||||
this.state = {
|
||||
fixedSearch: false,
|
||||
customizeMenuVisible: false
|
||||
fixedSearch: false
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14773,8 +14873,8 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
}
|
||||
|
||||
openCustomizationMenu() {
|
||||
this.setState({
|
||||
customizeMenuVisible: true
|
||||
this.props.dispatch({
|
||||
type: actionTypes.SHOW_PERSONALIZE
|
||||
});
|
||||
this.props.dispatch(actionCreators.UserEvent({
|
||||
event: "SHOW_PERSONALIZE"
|
||||
|
@ -14782,9 +14882,9 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
}
|
||||
|
||||
closeCustomizationMenu() {
|
||||
if (this.state.customizeMenuVisible) {
|
||||
this.setState({
|
||||
customizeMenuVisible: false
|
||||
if (this.props.App.customizeMenuVisible) {
|
||||
this.props.dispatch({
|
||||
type: actionTypes.HIDE_PERSONALIZE
|
||||
});
|
||||
this.props.dispatch(actionCreators.UserEvent({
|
||||
event: "HIDE_PERSONALIZE"
|
||||
|
@ -14810,7 +14910,8 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
App
|
||||
} = props;
|
||||
const {
|
||||
initialized
|
||||
initialized,
|
||||
customizeMenuVisible
|
||||
} = App;
|
||||
const prefs = props.Prefs.values;
|
||||
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
|
||||
|
@ -14818,7 +14919,6 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
const pocketEnabled = prefs["feeds.section.topstories"] && prefs["feeds.system.topstories"];
|
||||
const noSectionsEnabled = !prefs["feeds.topsites"] && !pocketEnabled && filteredSections.filter(section => section.enabled).length === 0;
|
||||
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
|
||||
const showCustomizationMenu = this.state.customizeMenuVisible;
|
||||
const enabledSections = {
|
||||
topSitesEnabled: prefs["feeds.topsites"],
|
||||
pocketEnabled: prefs["feeds.section.topstories"],
|
||||
|
@ -14842,7 +14942,7 @@ class BaseContent extends (external_React_default()).PureComponent {
|
|||
enabledSections: enabledSections,
|
||||
pocketRegion: pocketRegion,
|
||||
mayHaveSponsoredTopSites: mayHaveSponsoredTopSites,
|
||||
showing: showCustomizationMenu
|
||||
showing: customizeMenuVisible
|
||||
}), /*#__PURE__*/external_React_default().createElement("div", {
|
||||
className: outerClassName,
|
||||
onClick: this.closeCustomizationMenu
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -73,6 +73,7 @@ A user event ping includes some basic metadata (tab id, addon version, etc.) as
|
|||
"SEARCH",
|
||||
"BLOCK",
|
||||
"DELETE",
|
||||
"IMPRESSION",
|
||||
"OPEN_NEW_WINDOW",
|
||||
"OPEN_PRIVATE_WINDOW",
|
||||
"BOOKMARK_DELETE",
|
||||
|
|
|
@ -396,6 +396,15 @@ const PREFS_CONFIG = new Map([
|
|||
value: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
"discoverystream.onboardingExperience.dismissed",
|
||||
{
|
||||
title: "Allows the user to dismiss the new Pocket onboarding experience",
|
||||
skipBroadcast: true,
|
||||
alsoToPreloaded: true,
|
||||
value: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
"discoverystream.region-basic-layout",
|
||||
{
|
||||
|
|
|
@ -661,6 +661,8 @@ class DiscoveryStreamFeed {
|
|||
|
||||
const pocketConfig =
|
||||
this.store.getState().Prefs.values?.pocketConfig || {};
|
||||
const onboardingExperience =
|
||||
this.isBff && pocketConfig.onboardingExperience;
|
||||
|
||||
let items = isBasicLayout ? 3 : 21;
|
||||
if (pocketConfig.fourCardLayout || pocketConfig.hybridLayout) {
|
||||
|
@ -742,6 +744,7 @@ class DiscoveryStreamFeed {
|
|||
this.locale.startsWith("en-") && pocketConfig.essentialReadsHeader,
|
||||
editorsPicksHeader:
|
||||
this.locale.startsWith("en-") && pocketConfig.editorsPicksHeader,
|
||||
onboardingExperience,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2208,6 +2211,7 @@ class DiscoveryStreamFeed {
|
|||
`compactGrid` Reduce the number of pixels between the Pocket cards.
|
||||
`essentialReadsHeader` Updates the Pocket section header and title to say "Today’s Essential Reads", moves the "Recommended by Pocket" header to the right side.
|
||||
`editorsPicksHeader` Updates the Pocket section header and title to say "Editor’s Picks", if used with essentialReadsHeader, creates a second section 2 rows down for editorsPicks.
|
||||
`onboardingExperience` Show new users some UI explaining Pocket above the Pocket section.
|
||||
*/
|
||||
getHardcodedLayout = ({
|
||||
spocsUrl = SPOCS_URL,
|
||||
|
@ -2227,6 +2231,7 @@ getHardcodedLayout = ({
|
|||
compactGrid = false,
|
||||
essentialReadsHeader = false,
|
||||
editorsPicksHeader = false,
|
||||
onboardingExperience = false,
|
||||
}) => ({
|
||||
lastUpdate: Date.now(),
|
||||
spocs: {
|
||||
|
@ -2324,6 +2329,7 @@ getHardcodedLayout = ({
|
|||
compactGrid,
|
||||
essentialReadsHeader,
|
||||
editorsPicksHeader,
|
||||
onboardingExperience,
|
||||
},
|
||||
widgets: {
|
||||
positions: widgetPositions.map(position => {
|
||||
|
|
|
@ -32,8 +32,16 @@ class PrefsFeed {
|
|||
onPrefChanged(name, value) {
|
||||
const prefItem = this._prefMap.get(name);
|
||||
if (prefItem) {
|
||||
let action = "BroadcastToContent";
|
||||
if (prefItem.skipBroadcast) {
|
||||
action = "OnlyToMain";
|
||||
if (prefItem.alsoToPreloaded) {
|
||||
action = "AlsoToPreloaded";
|
||||
}
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
ac[prefItem.skipBroadcast ? "OnlyToMain" : "BroadcastToContent"]({
|
||||
ac[action]({
|
||||
type: at.PREF_CHANGED,
|
||||
data: { name, value },
|
||||
})
|
||||
|
|
|
@ -99,11 +99,17 @@ describe("<BaseContent>", () => {
|
|||
it("should dispatch a user event when the customize menu is opened or closed", () => {
|
||||
const dispatch = sinon.stub();
|
||||
const wrapper = shallow(
|
||||
<BaseContent {...DEFAULT_PROPS} dispatch={dispatch} />
|
||||
<BaseContent
|
||||
{...DEFAULT_PROPS}
|
||||
dispatch={dispatch}
|
||||
App={{ customizeMenuVisible: true }}
|
||||
/>
|
||||
);
|
||||
wrapper.instance().openCustomizationMenu();
|
||||
assert.calledWith(dispatch, { type: "SHOW_PERSONALIZE" });
|
||||
assert.calledWith(dispatch, ac.UserEvent({ event: "SHOW_PERSONALIZE" }));
|
||||
wrapper.instance().closeCustomizationMenu();
|
||||
assert.calledWith(dispatch, { type: "HIDE_PERSONALIZE" });
|
||||
assert.calledWith(dispatch, ac.UserEvent({ event: "HIDE_PERSONALIZE" }));
|
||||
});
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
_CardGrid as CardGrid,
|
||||
IntersectionObserver,
|
||||
RecentSavesContainer,
|
||||
OnboardingExperience,
|
||||
DSSubHeader,
|
||||
} from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
|
||||
import { combineReducers, createStore } from "redux";
|
||||
|
@ -290,3 +291,78 @@ describe("<RecentSavesContainer>", () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<OnboardingExperience>", () => {
|
||||
let wrapper;
|
||||
let fakeWindow;
|
||||
let intersectEntries;
|
||||
let dispatch;
|
||||
let resizeCallback;
|
||||
|
||||
let fakeResizeObserver = class {
|
||||
constructor(callback) {
|
||||
resizeCallback = callback;
|
||||
}
|
||||
|
||||
observe() {}
|
||||
|
||||
unobserve() {}
|
||||
|
||||
disconnect() {}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
dispatch = sinon.stub();
|
||||
intersectEntries = [{ isIntersecting: true, intersectionRatio: 1 }];
|
||||
fakeWindow = {
|
||||
ResizeObserver: fakeResizeObserver,
|
||||
IntersectionObserver: buildIntersectionObserver(intersectEntries),
|
||||
};
|
||||
wrapper = mount(
|
||||
<WrapWithProvider state={{}}>
|
||||
<OnboardingExperience windowObj={fakeWindow} dispatch={dispatch} />
|
||||
</WrapWithProvider>
|
||||
).find(OnboardingExperience);
|
||||
});
|
||||
|
||||
it("should render a ds-onboarding", () => {
|
||||
assert.ok(wrapper.exists());
|
||||
assert.lengthOf(wrapper.find(".ds-onboarding"), 1);
|
||||
});
|
||||
|
||||
it("should dismiss on dismiss click", () => {
|
||||
wrapper.find(".ds-dismiss-button").simulate("click");
|
||||
|
||||
assert.calledWith(
|
||||
dispatch,
|
||||
ac.DiscoveryStreamUserEvent({
|
||||
event: "BLOCK",
|
||||
source: "POCKET_ONBOARDING",
|
||||
})
|
||||
);
|
||||
assert.calledWith(
|
||||
dispatch,
|
||||
ac.SetPref("discoverystream.onboardingExperience.dismissed", true)
|
||||
);
|
||||
assert.equal(wrapper.getDOMNode().style["max-height"], "0px");
|
||||
assert.equal(wrapper.getDOMNode().style.opacity, "0");
|
||||
});
|
||||
|
||||
it("should update max-height on resize", () => {
|
||||
sinon
|
||||
.stub(wrapper.find(".ds-onboarding-ref").getDOMNode(), "offsetHeight")
|
||||
.get(() => 123);
|
||||
resizeCallback();
|
||||
assert.equal(wrapper.getDOMNode().style["max-height"], "123px");
|
||||
});
|
||||
|
||||
it("should fire intersection events", () => {
|
||||
assert.calledWith(
|
||||
dispatch,
|
||||
ac.DiscoveryStreamUserEvent({
|
||||
event: "IMPRESSION",
|
||||
source: "POCKET_ONBOARDING",
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ describe("PrefsFeed", () => {
|
|||
["foo", 1],
|
||||
["bar", 2],
|
||||
["baz", { value: 1, skipBroadcast: true }],
|
||||
["qux", { value: 1, skipBroadcast: true, alsoToPreloaded: true }],
|
||||
]);
|
||||
feed = new PrefsFeed(FAKE_PREFS);
|
||||
const storage = {
|
||||
|
@ -262,6 +263,23 @@ describe("PrefsFeed", () => {
|
|||
})
|
||||
);
|
||||
});
|
||||
it("should send AlsoToPreloaded pref update if config for pref has skipBroadcast: true and alsoToPreloaded: true", async () => {
|
||||
feed.onPrefChanged("qux", {
|
||||
value: 2,
|
||||
skipBroadcast: true,
|
||||
alsoToPreloaded: true,
|
||||
});
|
||||
assert.calledWith(
|
||||
feed.store.dispatch,
|
||||
ac.AlsoToPreloaded({
|
||||
type: at.PREF_CHANGED,
|
||||
data: {
|
||||
name: "qux",
|
||||
value: { value: 2, skipBroadcast: true, alsoToPreloaded: true },
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
describe("#observe", () => {
|
||||
it("should call dispatch from observe", () => {
|
||||
feed.observe(undefined, global.Region.REGION_TOPIC);
|
||||
|
|
|
@ -240,6 +240,11 @@ newtab-pocket-pocket-firefox-family = { -pocket-brand-name } is part of the { -b
|
|||
newtab-pocket-save = Save
|
||||
newtab-pocket-saved = Saved
|
||||
|
||||
## Pocket content onboarding experience dialog and modal for new users seeing the Pocket section for the first time, shown as the first item in the Pocket section.
|
||||
|
||||
newtab-pocket-onboarding-discover = Discover the best of the web
|
||||
newtab-pocket-onboarding-cta = { -pocket-brand-name } explores a diverse range of publications to bring the most informative, inspirational, and trustworthy content right to your { -brand-product-name } browser.
|
||||
|
||||
## Error Fallback Content.
|
||||
## This message and suggested action link are shown in each section of UI that fails to render.
|
||||
|
||||
|
|
|
@ -479,6 +479,12 @@ pocketNewtab:
|
|||
browser.newtabpage.activity-stream.discoverystream.descLines
|
||||
description: >-
|
||||
Changes the maximum number of lines a description can be for Pocket cards on newtab.
|
||||
onboardingExperience:
|
||||
type: boolean
|
||||
fallbackPref: >-
|
||||
browser.newtabpage.activity-stream.discoverystream.onboardingExperience.enabled
|
||||
description: >-
|
||||
Enables an onboarding experience for Pocket section on newtab.
|
||||
essentialReadsHeader:
|
||||
type: boolean
|
||||
fallbackPref: >-
|
||||
|
|
Загрузка…
Ссылка в новой задаче