Bug 1897232 - Add nested wallpaper categories. r=home-newtab-reviewers,nbarrett,aminomancer

Differential Revision: https://phabricator.services.mozilla.com/D211895
This commit is contained in:
Amy Churchwell 2024-06-04 19:31:03 +00:00
parent de08e3c67c
commit cc7c900717
16 changed files with 742 additions and 140 deletions

View file

@ -334,6 +334,7 @@ for (const type of [
"UPDATE_PINNED_SEARCH_SHORTCUTS",
"UPDATE_SEARCH_SHORTCUTS",
"UPDATE_SECTION_PREFS",
"WALLPAPERS_CATEGORY_SET",
"WALLPAPERS_FEATURE_HIGHLIGHT_COUNTER_INCREMENT",
"WALLPAPERS_FEATURE_HIGHLIGHT_SEEN",
"WALLPAPERS_SET",

View file

@ -160,6 +160,7 @@ for (const type of [
"UPDATE_PINNED_SEARCH_SHORTCUTS",
"UPDATE_SEARCH_SHORTCUTS",
"UPDATE_SECTION_PREFS",
"WALLPAPERS_CATEGORY_SET",
"WALLPAPERS_FEATURE_HIGHLIGHT_COUNTER_INCREMENT",
"WALLPAPERS_FEATURE_HIGHLIGHT_SEEN",
"WALLPAPERS_SET",

View file

@ -104,6 +104,7 @@ export const INITIAL_STATE = {
Wallpapers: {
wallpaperList: [],
highlightSeenCounter: 0,
categories: [],
},
Weather: {
initialized: false,
@ -872,6 +873,8 @@ function Wallpapers(prevState = INITIAL_STATE.Wallpapers, action) {
...prevState,
highlightSeenCounter: action.data,
};
case at.WALLPAPERS_CATEGORY_SET:
return { ...prevState, categories: action.data };
default:
return prevState;
}

View file

@ -354,6 +354,7 @@ export class BaseContent extends React.PureComponent {
const activeWallpaper =
prefs[`newtabWallpapers.wallpaper-${this.state.colorMode}`];
const wallpapersEnabled = prefs["newtabWallpapers.enabled"];
const wallpapersV2Enabled = prefs["newtabWallpapers.v2.enabled"];
const weatherEnabled = prefs.showWeather;
const { pocketConfig } = prefs;
@ -408,7 +409,7 @@ export class BaseContent extends React.PureComponent {
]
.filter(v => v)
.join(" ");
if (wallpapersEnabled) {
if (wallpapersEnabled || wallpapersV2Enabled) {
this.updateWallpaper();
}
@ -423,6 +424,7 @@ export class BaseContent extends React.PureComponent {
setPref={this.setPref}
enabledSections={enabledSections}
wallpapersEnabled={wallpapersEnabled}
wallpapersV2Enabled={wallpapersV2Enabled}
activeWallpaper={activeWallpaper}
pocketRegion={pocketRegion}
mayHaveSponsoredTopSites={mayHaveSponsoredTopSites}

View file

@ -6,6 +6,7 @@ import React from "react";
import { actionCreators as ac } from "common/Actions.mjs";
import { SafeAnchor } from "../../DiscoveryStreamComponents/SafeAnchor/SafeAnchor";
import { WallpapersSection } from "../../WallpapersSection/WallpapersSection";
import { WallpaperCategories } from "../../WallpapersSection/WallpaperCategories";
export class ContentSection extends React.PureComponent {
constructor(props) {
@ -101,6 +102,7 @@ export class ContentSection extends React.PureComponent {
openPreferences,
spocMessageVariant,
wallpapersEnabled,
wallpapersV2Enabled,
activeWallpaper,
setPref,
} = this.props;
@ -119,13 +121,20 @@ export class ContentSection extends React.PureComponent {
<div className="home-section">
{wallpapersEnabled && (
<div className="wallpapers-section">
<h2 data-l10n-id="newtab-wallpaper-title"></h2>
<WallpapersSection
setPref={setPref}
activeWallpaper={activeWallpaper}
/>
</div>
)}
{wallpapersV2Enabled && (
<div className="wallpapers-section">
<WallpaperCategories
setPref={setPref}
activeWallpaper={activeWallpaper}
/>
</div>
)}
<div id="shortcuts-section" className="section">
<moz-toggle
id="shortcuts-toggle"

View file

@ -68,6 +68,7 @@ export class _CustomizeMenu extends React.PureComponent {
setPref={this.props.setPref}
enabledSections={this.props.enabledSections}
wallpapersEnabled={this.props.wallpapersEnabled}
wallpapersV2Enabled={this.props.wallpapersV2Enabled}
activeWallpaper={this.props.activeWallpaper}
pocketRegion={this.props.pocketRegion}
mayHaveSponsoredTopSites={this.props.mayHaveSponsoredTopSites}

View file

@ -0,0 +1,171 @@
/* 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 { connect } from "react-redux";
import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
import { CSSTransition } from "react-transition-group";
export class _WallpaperCategories extends React.PureComponent {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleReset = this.handleReset.bind(this);
this.handleCategory = this.handleCategory.bind(this);
this.handleBack = this.handleBack.bind(this);
this.prefersHighContrastQuery = null;
this.prefersDarkQuery = null;
this.state = {
activeCategory: null,
};
}
componentDidMount() {
this.prefersDarkQuery = globalThis.matchMedia(
"(prefers-color-scheme: dark)"
);
}
handleChange(event) {
const { id } = event.target;
const prefs = this.props.Prefs.values;
const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
this.props.setPref(`newtabWallpapers.wallpaper-${colorMode}`, id);
this.handleUserEvent({
selected_wallpaper: id,
hadPreviousWallpaper: !!this.props.activeWallpaper,
});
// bug 1892095
if (
prefs["newtabWallpapers.wallpaper-dark"] === "" &&
colorMode === "light"
) {
this.props.setPref(
"newtabWallpapers.wallpaper-dark",
id.replace("light", "dark")
);
}
if (
prefs["newtabWallpapers.wallpaper-light"] === "" &&
colorMode === "dark"
) {
this.props.setPref(
`newtabWallpapers.wallpaper-light`,
id.replace("dark", "light")
);
}
}
handleReset() {
const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
this.props.setPref(`newtabWallpapers.wallpaper-${colorMode}`, "");
this.handleUserEvent({
selected_wallpaper: "none",
hadPreviousWallpaper: !!this.props.activeWallpaper,
});
}
handleCategory = event => {
this.setState({ activeCategory: event.target.id });
};
handleBack() {
this.setState({ activeCategory: null });
}
// Record user interaction when changing wallpaper and reseting wallpaper to default
handleUserEvent(data) {
this.props.dispatch(
ac.OnlyToMain({
type: at.WALLPAPER_CLICK,
data,
})
);
}
render() {
const { wallpaperList, categories } = this.props.Wallpapers;
const { activeWallpaper } = this.props;
const { activeCategory } = this.state;
const filteredWallpapers = wallpaperList.filter(
wallpaper => wallpaper.category === activeCategory
);
return (
<div>
<h2 data-l10n-id="newtab-wallpaper-title">Wallpapers</h2>
<button
className="wallpapers-reset"
onClick={this.handleReset}
data-l10n-id="newtab-wallpaper-reset"
/>
<fieldset className="category-list">
{categories.map(category => {
const firstWallpaper = wallpaperList.find(
wallpaper => wallpaper.category === category
);
const title = firstWallpaper ? firstWallpaper.title : "";
return (
<>
<input
key={category}
id={category}
onClick={this.handleCategory}
className={`wallpaper-input ${title}`}
/>
<label>{category}</label>
</>
);
})}
</fieldset>
<CSSTransition
in={!!activeCategory}
timeout={300}
classNames="wallpaper-list"
unmountOnExit={true}
>
<section className="category wallpaper-list">
<button onClick={this.handleBack}>back arrow</button>
<h2>{activeCategory}</h2>
<fieldset>
{filteredWallpapers.map(({ title, theme, fluent_id }) => {
return (
<>
<input
onChange={this.handleChange}
type="radio"
name={`wallpaper-${title}`}
id={title}
value={title}
checked={title === activeWallpaper}
aria-checked={title === activeWallpaper}
className={`wallpaper-input theme-${theme} ${title}`}
/>
<label
htmlFor={title}
className="sr-only"
data-l10n-id={fluent_id}
>
{fluent_id}
</label>
</>
);
})}
</fieldset>
</section>
</CSSTransition>
</div>
);
}
}
export const WallpaperCategories = connect(state => {
return {
Wallpapers: state.Wallpapers,
Prefs: state.Prefs,
};
})(_WallpaperCategories);

View file

@ -1,3 +1,59 @@
.category-list {
border: none;
display: grid;
gap: 16px;
grid-auto-rows: 86px;
grid-template-columns: 1fr 1fr 1fr;
button {
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
border-radius: 8px;
border: none;
box-shadow: 0 1px 2px 0 #3A394433;
cursor: pointer;
height: 86px;
width: 116px;
}
}
.wallpaper-input {
appearance: none;
margin: 0;
padding: 0;
height: 86px;
width: 100%;
box-shadow: $shadow-secondary;
border-radius: 8px;
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
outline: 2px solid transparent;
$wallpapers: dark-landscape, dark-color, dark-mountain, dark-panda, dark-sky, dark-beach, light-beach, light-color, light-landscape, light-mountain, light-panda, light-sky;
@each $wallpaper in $wallpapers {
&.#{$wallpaper} {
background-image: url('chrome://activity-stream/content/data/content/assets/wallpapers/#{$wallpaper}.avif')
}
}
&:checked {
outline-color: var(--color-accent-primary-active);
}
&:focus-visible {
outline-color: var(--newtab-primary-action-background);
}
&:hover {
filter: brightness(55%);
outline-color: transparent;
}
}
.wallpaper-list {
display: grid;
gap: 16px;
@ -7,6 +63,49 @@
padding: 0;
border: none;
&.category {
background-color: var(--newtab-background-color-secondary);
color: var(--newtab-text-primary-color);
display: unset;
gap: unset;
grid-auto-rows: unset;
grid-template-columns: unset;
height: 100%;
position: absolute;
top: 0;
visibility: none;
width: 370px; // TODO: check this
z-index: 2;
fieldset {
border: none;
display: grid;
gap: 16px;
grid-auto-rows: 86px;
grid-template-columns: 1fr 1fr 1fr;
}
@media (prefers-reduced-motion: no-preference) {
&.wallpaper-list-enter {
transform: translateX(100%);
}
&.wallpaper-list-enter-active {
transform: translateX(0);
transition: transform 300ms;
}
&.wallpaper-list-exit {
transform: translateX(0);
}
&.wallpaper-list-exit-active {
transform: translateX(100%);
transition: transform 300ms;
}
}
}
&:not(.ignore-color-mode) .wallpaper-input,
&:not(.ignore-color-mode) .sr-only {
&.theme-light {
@ -26,42 +125,6 @@
}
}
.wallpaper-input {
appearance: none;
margin: 0;
padding: 0;
height: 86px;
width: 100%;
box-shadow: $shadow-secondary;
border-radius: 8px;
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
outline: 2px solid transparent;
$wallpapers: dark-landscape, dark-color, dark-mountain, dark-panda, dark-sky, dark-beach, light-beach, light-color, light-landscape, light-mountain, light-panda, light-sky;
@each $wallpaper in $wallpapers {
&.#{$wallpaper} {
background-image: url('chrome://activity-stream/content/data/content/assets/wallpapers/#{$wallpaper}.avif')
}
}
&:checked {
outline-color: var(--color-accent-primary-active);
}
&:focus-visible {
outline-color: var(--newtab-primary-action-background);
}
&:hover {
filter: brightness(55%);
outline-color: transparent;
}
}
// visually hide label, but still read by screen readers
.sr-only {
opacity: 0;
@ -85,3 +148,4 @@
text-decoration: none;
}
}

View file

@ -1949,28 +1949,26 @@ main section {
box-shadow: 0 0 0 2px var(--newtab-primary-action-background-dimmed);
}
.wallpaper-list {
.category-list {
border: none;
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
grid-template-columns: 1fr 1fr 1fr;
}
.category-list button {
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
border-radius: 8px;
border: none;
box-shadow: 0 1px 2px 0 #3A394433;
cursor: pointer;
height: 86px;
width: 116px;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .wallpaper-input {
.wallpaper-input {
appearance: none;
margin: 0;
padding: 0;
@ -1984,52 +1982,111 @@ main section {
cursor: pointer;
outline: 2px solid transparent;
}
.wallpaper-list .wallpaper-input.dark-landscape {
.wallpaper-input.dark-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-landscape.avif");
}
.wallpaper-list .wallpaper-input.dark-color {
.wallpaper-input.dark-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-color.avif");
}
.wallpaper-list .wallpaper-input.dark-mountain {
.wallpaper-input.dark-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-mountain.avif");
}
.wallpaper-list .wallpaper-input.dark-panda {
.wallpaper-input.dark-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-panda.avif");
}
.wallpaper-list .wallpaper-input.dark-sky {
.wallpaper-input.dark-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-sky.avif");
}
.wallpaper-list .wallpaper-input.dark-beach {
.wallpaper-input.dark-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-beach.avif");
}
.wallpaper-list .wallpaper-input.light-beach {
.wallpaper-input.light-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-beach.avif");
}
.wallpaper-list .wallpaper-input.light-color {
.wallpaper-input.light-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-color.avif");
}
.wallpaper-list .wallpaper-input.light-landscape {
.wallpaper-input.light-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-landscape.avif");
}
.wallpaper-list .wallpaper-input.light-mountain {
.wallpaper-input.light-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-mountain.avif");
}
.wallpaper-list .wallpaper-input.light-panda {
.wallpaper-input.light-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-panda.avif");
}
.wallpaper-list .wallpaper-input.light-sky {
.wallpaper-input.light-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-sky.avif");
}
.wallpaper-list .wallpaper-input:checked {
.wallpaper-input:checked {
outline-color: var(--color-accent-primary-active);
}
.wallpaper-list .wallpaper-input:focus-visible {
.wallpaper-input:focus-visible {
outline-color: var(--newtab-primary-action-background);
}
.wallpaper-list .wallpaper-input:hover {
.wallpaper-input:hover {
filter: brightness(55%);
outline-color: transparent;
}
.wallpaper-list {
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
border: none;
}
.wallpaper-list.category {
background-color: var(--newtab-background-color-secondary);
color: var(--newtab-text-primary-color);
display: unset;
gap: unset;
grid-auto-rows: unset;
grid-template-columns: unset;
height: 100%;
position: absolute;
top: 0;
visibility: none;
width: 370px;
z-index: 2;
}
.wallpaper-list.category fieldset {
border: none;
display: grid;
gap: 16px;
grid-auto-rows: 86px;
grid-template-columns: 1fr 1fr 1fr;
}
@media (prefers-reduced-motion: no-preference) {
.wallpaper-list.category.wallpaper-list-enter {
transform: translateX(100%);
}
.wallpaper-list.category.wallpaper-list-enter-active {
transform: translateX(0);
transition: transform 300ms;
}
.wallpaper-list.category.wallpaper-list-exit {
transform: translateX(0);
}
.wallpaper-list.category.wallpaper-list-exit-active {
transform: translateX(100%);
transition: transform 300ms;
}
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .sr-only {
opacity: 0;
overflow: hidden;

View file

@ -1953,28 +1953,26 @@ main section {
box-shadow: 0 0 0 2px var(--newtab-primary-action-background-dimmed);
}
.wallpaper-list {
.category-list {
border: none;
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
grid-template-columns: 1fr 1fr 1fr;
}
.category-list button {
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
border-radius: 8px;
border: none;
box-shadow: 0 1px 2px 0 #3A394433;
cursor: pointer;
height: 86px;
width: 116px;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .wallpaper-input {
.wallpaper-input {
appearance: none;
margin: 0;
padding: 0;
@ -1988,52 +1986,111 @@ main section {
cursor: pointer;
outline: 2px solid transparent;
}
.wallpaper-list .wallpaper-input.dark-landscape {
.wallpaper-input.dark-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-landscape.avif");
}
.wallpaper-list .wallpaper-input.dark-color {
.wallpaper-input.dark-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-color.avif");
}
.wallpaper-list .wallpaper-input.dark-mountain {
.wallpaper-input.dark-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-mountain.avif");
}
.wallpaper-list .wallpaper-input.dark-panda {
.wallpaper-input.dark-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-panda.avif");
}
.wallpaper-list .wallpaper-input.dark-sky {
.wallpaper-input.dark-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-sky.avif");
}
.wallpaper-list .wallpaper-input.dark-beach {
.wallpaper-input.dark-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-beach.avif");
}
.wallpaper-list .wallpaper-input.light-beach {
.wallpaper-input.light-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-beach.avif");
}
.wallpaper-list .wallpaper-input.light-color {
.wallpaper-input.light-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-color.avif");
}
.wallpaper-list .wallpaper-input.light-landscape {
.wallpaper-input.light-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-landscape.avif");
}
.wallpaper-list .wallpaper-input.light-mountain {
.wallpaper-input.light-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-mountain.avif");
}
.wallpaper-list .wallpaper-input.light-panda {
.wallpaper-input.light-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-panda.avif");
}
.wallpaper-list .wallpaper-input.light-sky {
.wallpaper-input.light-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-sky.avif");
}
.wallpaper-list .wallpaper-input:checked {
.wallpaper-input:checked {
outline-color: var(--color-accent-primary-active);
}
.wallpaper-list .wallpaper-input:focus-visible {
.wallpaper-input:focus-visible {
outline-color: var(--newtab-primary-action-background);
}
.wallpaper-list .wallpaper-input:hover {
.wallpaper-input:hover {
filter: brightness(55%);
outline-color: transparent;
}
.wallpaper-list {
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
border: none;
}
.wallpaper-list.category {
background-color: var(--newtab-background-color-secondary);
color: var(--newtab-text-primary-color);
display: unset;
gap: unset;
grid-auto-rows: unset;
grid-template-columns: unset;
height: 100%;
position: absolute;
top: 0;
visibility: none;
width: 370px;
z-index: 2;
}
.wallpaper-list.category fieldset {
border: none;
display: grid;
gap: 16px;
grid-auto-rows: 86px;
grid-template-columns: 1fr 1fr 1fr;
}
@media (prefers-reduced-motion: no-preference) {
.wallpaper-list.category.wallpaper-list-enter {
transform: translateX(100%);
}
.wallpaper-list.category.wallpaper-list-enter-active {
transform: translateX(0);
transition: transform 300ms;
}
.wallpaper-list.category.wallpaper-list-exit {
transform: translateX(0);
}
.wallpaper-list.category.wallpaper-list-exit-active {
transform: translateX(100%);
transition: transform 300ms;
}
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .sr-only {
opacity: 0;
overflow: hidden;

View file

@ -1949,28 +1949,26 @@ main section {
box-shadow: 0 0 0 2px var(--newtab-primary-action-background-dimmed);
}
.wallpaper-list {
.category-list {
border: none;
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
grid-template-columns: 1fr 1fr 1fr;
}
.category-list button {
background-clip: content-box;
background-repeat: no-repeat;
background-size: cover;
border-radius: 8px;
border: none;
box-shadow: 0 1px 2px 0 #3A394433;
cursor: pointer;
height: 86px;
width: 116px;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .wallpaper-input {
.wallpaper-input {
appearance: none;
margin: 0;
padding: 0;
@ -1984,52 +1982,111 @@ main section {
cursor: pointer;
outline: 2px solid transparent;
}
.wallpaper-list .wallpaper-input.dark-landscape {
.wallpaper-input.dark-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-landscape.avif");
}
.wallpaper-list .wallpaper-input.dark-color {
.wallpaper-input.dark-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-color.avif");
}
.wallpaper-list .wallpaper-input.dark-mountain {
.wallpaper-input.dark-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-mountain.avif");
}
.wallpaper-list .wallpaper-input.dark-panda {
.wallpaper-input.dark-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-panda.avif");
}
.wallpaper-list .wallpaper-input.dark-sky {
.wallpaper-input.dark-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-sky.avif");
}
.wallpaper-list .wallpaper-input.dark-beach {
.wallpaper-input.dark-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/dark-beach.avif");
}
.wallpaper-list .wallpaper-input.light-beach {
.wallpaper-input.light-beach {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-beach.avif");
}
.wallpaper-list .wallpaper-input.light-color {
.wallpaper-input.light-color {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-color.avif");
}
.wallpaper-list .wallpaper-input.light-landscape {
.wallpaper-input.light-landscape {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-landscape.avif");
}
.wallpaper-list .wallpaper-input.light-mountain {
.wallpaper-input.light-mountain {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-mountain.avif");
}
.wallpaper-list .wallpaper-input.light-panda {
.wallpaper-input.light-panda {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-panda.avif");
}
.wallpaper-list .wallpaper-input.light-sky {
.wallpaper-input.light-sky {
background-image: url("chrome://activity-stream/content/data/content/assets/wallpapers/light-sky.avif");
}
.wallpaper-list .wallpaper-input:checked {
.wallpaper-input:checked {
outline-color: var(--color-accent-primary-active);
}
.wallpaper-list .wallpaper-input:focus-visible {
.wallpaper-input:focus-visible {
outline-color: var(--newtab-primary-action-background);
}
.wallpaper-list .wallpaper-input:hover {
.wallpaper-input:hover {
filter: brightness(55%);
outline-color: transparent;
}
.wallpaper-list {
display: grid;
gap: 16px;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-rows: 86px;
margin: 16px 0;
padding: 0;
border: none;
}
.wallpaper-list.category {
background-color: var(--newtab-background-color-secondary);
color: var(--newtab-text-primary-color);
display: unset;
gap: unset;
grid-auto-rows: unset;
grid-template-columns: unset;
height: 100%;
position: absolute;
top: 0;
visibility: none;
width: 370px;
z-index: 2;
}
.wallpaper-list.category fieldset {
border: none;
display: grid;
gap: 16px;
grid-auto-rows: 86px;
grid-template-columns: 1fr 1fr 1fr;
}
@media (prefers-reduced-motion: no-preference) {
.wallpaper-list.category.wallpaper-list-enter {
transform: translateX(100%);
}
.wallpaper-list.category.wallpaper-list-enter-active {
transform: translateX(0);
transition: transform 300ms;
}
.wallpaper-list.category.wallpaper-list-exit {
transform: translateX(0);
}
.wallpaper-list.category.wallpaper-list-exit-active {
transform: translateX(100%);
transition: transform 300ms;
}
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: inline-block;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-light, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-light {
display: none;
}
.wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: none;
}
[lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .wallpaper-input.theme-dark, [lwt-newtab-brighttext] .wallpaper-list:not(.ignore-color-mode) .sr-only.theme-dark {
display: inline-block;
}
.wallpaper-list .sr-only {
opacity: 0;
overflow: hidden;

View file

@ -233,6 +233,7 @@ for (const type of [
"UPDATE_PINNED_SEARCH_SHORTCUTS",
"UPDATE_SEARCH_SHORTCUTS",
"UPDATE_SECTION_PREFS",
"WALLPAPERS_CATEGORY_SET",
"WALLPAPERS_FEATURE_HIGHLIGHT_COUNTER_INCREMENT",
"WALLPAPERS_FEATURE_HIGHLIGHT_SEEN",
"WALLPAPERS_SET",
@ -5650,6 +5651,7 @@ const INITIAL_STATE = {
Wallpapers: {
wallpaperList: [],
highlightSeenCounter: 0,
categories: [],
},
Weather: {
initialized: false,
@ -6418,6 +6420,8 @@ function Wallpapers(prevState = INITIAL_STATE.Wallpapers, action) {
...prevState,
highlightSeenCounter: action.data,
};
case actionTypes.WALLPAPERS_CATEGORY_SET:
return { ...prevState, categories: action.data };
default:
return prevState;
}
@ -9123,6 +9127,142 @@ const WallpapersSection = (0,external_ReactRedux_namespaceObject.connect)(state
Prefs: state.Prefs
};
})(_WallpapersSection);
;// CONCATENATED MODULE: ./content-src/components/WallpapersSection/WallpaperCategories.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 _WallpaperCategories extends (external_React_default()).PureComponent {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleReset = this.handleReset.bind(this);
this.handleCategory = this.handleCategory.bind(this);
this.handleBack = this.handleBack.bind(this);
this.prefersHighContrastQuery = null;
this.prefersDarkQuery = null;
this.state = {
activeCategory: null
};
}
componentDidMount() {
this.prefersDarkQuery = globalThis.matchMedia("(prefers-color-scheme: dark)");
}
handleChange(event) {
const {
id
} = event.target;
const prefs = this.props.Prefs.values;
const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
this.props.setPref(`newtabWallpapers.wallpaper-${colorMode}`, id);
this.handleUserEvent({
selected_wallpaper: id,
hadPreviousWallpaper: !!this.props.activeWallpaper
});
// bug 1892095
if (prefs["newtabWallpapers.wallpaper-dark"] === "" && colorMode === "light") {
this.props.setPref("newtabWallpapers.wallpaper-dark", id.replace("light", "dark"));
}
if (prefs["newtabWallpapers.wallpaper-light"] === "" && colorMode === "dark") {
this.props.setPref(`newtabWallpapers.wallpaper-light`, id.replace("dark", "light"));
}
}
handleReset() {
const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
this.props.setPref(`newtabWallpapers.wallpaper-${colorMode}`, "");
this.handleUserEvent({
selected_wallpaper: "none",
hadPreviousWallpaper: !!this.props.activeWallpaper
});
}
handleCategory = event => {
this.setState({
activeCategory: event.target.id
});
};
handleBack() {
this.setState({
activeCategory: null
});
}
// Record user interaction when changing wallpaper and reseting wallpaper to default
handleUserEvent(data) {
this.props.dispatch(actionCreators.OnlyToMain({
type: actionTypes.WALLPAPER_CLICK,
data
}));
}
render() {
const {
wallpaperList,
categories
} = this.props.Wallpapers;
const {
activeWallpaper
} = this.props;
const {
activeCategory
} = this.state;
const filteredWallpapers = wallpaperList.filter(wallpaper => wallpaper.category === activeCategory);
return /*#__PURE__*/external_React_default().createElement("div", null, /*#__PURE__*/external_React_default().createElement("h2", {
"data-l10n-id": "newtab-wallpaper-title"
}, "Wallpapers"), /*#__PURE__*/external_React_default().createElement("button", {
className: "wallpapers-reset",
onClick: this.handleReset,
"data-l10n-id": "newtab-wallpaper-reset"
}), /*#__PURE__*/external_React_default().createElement("fieldset", {
className: "category-list"
}, categories.map(category => {
const firstWallpaper = wallpaperList.find(wallpaper => wallpaper.category === category);
const title = firstWallpaper ? firstWallpaper.title : "";
return /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null, /*#__PURE__*/external_React_default().createElement("input", {
key: category,
id: category,
onClick: this.handleCategory,
className: `wallpaper-input ${title}`
}), /*#__PURE__*/external_React_default().createElement("label", null, category));
})), /*#__PURE__*/external_React_default().createElement(external_ReactTransitionGroup_namespaceObject.CSSTransition, {
in: !!activeCategory,
timeout: 300,
classNames: "wallpaper-list",
unmountOnExit: true
}, /*#__PURE__*/external_React_default().createElement("section", {
className: "category wallpaper-list"
}, /*#__PURE__*/external_React_default().createElement("button", {
onClick: this.handleBack
}, "back arrow"), /*#__PURE__*/external_React_default().createElement("h2", null, activeCategory), /*#__PURE__*/external_React_default().createElement("fieldset", null, filteredWallpapers.map(({
title,
theme,
fluent_id
}) => {
return /*#__PURE__*/external_React_default().createElement((external_React_default()).Fragment, null, /*#__PURE__*/external_React_default().createElement("input", {
onChange: this.handleChange,
type: "radio",
name: `wallpaper-${title}`,
id: title,
value: title,
checked: title === activeWallpaper,
"aria-checked": title === activeWallpaper,
className: `wallpaper-input theme-${theme} ${title}`
}), /*#__PURE__*/external_React_default().createElement("label", {
htmlFor: title,
className: "sr-only",
"data-l10n-id": fluent_id
}, fluent_id));
})))));
}
}
const WallpaperCategories = (0,external_ReactRedux_namespaceObject.connect)(state => {
return {
Wallpapers: state.Wallpapers,
Prefs: state.Prefs
};
})(_WallpaperCategories);
;// CONCATENATED MODULE: ./content-src/components/CustomizeMenu/ContentSection/ContentSection.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,
@ -9132,6 +9272,7 @@ const WallpapersSection = (0,external_ReactRedux_namespaceObject.connect)(state
class ContentSection extends (external_React_default()).PureComponent {
constructor(props) {
super(props);
@ -9213,6 +9354,7 @@ class ContentSection extends (external_React_default()).PureComponent {
openPreferences,
spocMessageVariant,
wallpapersEnabled,
wallpapersV2Enabled,
activeWallpaper,
setPref
} = this.props;
@ -9230,9 +9372,12 @@ class ContentSection extends (external_React_default()).PureComponent {
className: "home-section"
}, wallpapersEnabled && /*#__PURE__*/external_React_default().createElement("div", {
className: "wallpapers-section"
}, /*#__PURE__*/external_React_default().createElement("h2", {
"data-l10n-id": "newtab-wallpaper-title"
}), /*#__PURE__*/external_React_default().createElement(WallpapersSection, {
}, /*#__PURE__*/external_React_default().createElement(WallpapersSection, {
setPref: setPref,
activeWallpaper: activeWallpaper
})), wallpapersV2Enabled && /*#__PURE__*/external_React_default().createElement("div", {
className: "wallpapers-section"
}, /*#__PURE__*/external_React_default().createElement(WallpaperCategories, {
setPref: setPref,
activeWallpaper: activeWallpaper
})), /*#__PURE__*/external_React_default().createElement("div", {
@ -9446,6 +9591,7 @@ class _CustomizeMenu extends (external_React_default()).PureComponent {
setPref: this.props.setPref,
enabledSections: this.props.enabledSections,
wallpapersEnabled: this.props.wallpapersEnabled,
wallpapersV2Enabled: this.props.wallpapersV2Enabled,
activeWallpaper: this.props.activeWallpaper,
pocketRegion: this.props.pocketRegion,
mayHaveSponsoredTopSites: this.props.mayHaveSponsoredTopSites,
@ -10445,6 +10591,7 @@ class BaseContent extends (external_React_default()).PureComponent {
const prefs = props.Prefs.values;
const activeWallpaper = prefs[`newtabWallpapers.wallpaper-${this.state.colorMode}`];
const wallpapersEnabled = prefs["newtabWallpapers.enabled"];
const wallpapersV2Enabled = prefs["newtabWallpapers.v2.enabled"];
const weatherEnabled = prefs.showWeather;
const {
pocketConfig
@ -10475,7 +10622,7 @@ class BaseContent extends (external_React_default()).PureComponent {
mayHaveSponsoredTopSites
} = prefs;
const outerClassName = ["outer-wrapper", isDiscoveryStream && pocketEnabled && "ds-outer-wrapper-search-alignment", isDiscoveryStream && "ds-outer-wrapper-breakpoint-override", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && noSectionsEnabled && "only-search", prefs["logowordmark.alwaysVisible"] && "visible-logo"].filter(v => v).join(" ");
if (wallpapersEnabled) {
if (wallpapersEnabled || wallpapersV2Enabled) {
this.updateWallpaper();
}
return /*#__PURE__*/external_React_default().createElement("div", null, /*#__PURE__*/external_React_default().createElement("menu", {
@ -10487,6 +10634,7 @@ class BaseContent extends (external_React_default()).PureComponent {
setPref: this.setPref,
enabledSections: enabledSections,
wallpapersEnabled: wallpapersEnabled,
wallpapersV2Enabled: wallpapersV2Enabled,
activeWallpaper: activeWallpaper,
pocketRegion: pocketRegion,
mayHaveSponsoredTopSites: mayHaveSponsoredTopSites,

View file

@ -19,6 +19,9 @@ const PREF_WALLPAPERS_ENABLED =
const PREF_WALLPAPERS_HIGHLIGHT_SEEN_COUNTER =
"browser.newtabpage.activity-stream.newtabWallpapers.highlightSeenCounter";
const PREF_WALLPAPERS_V2_ENABLED =
"browser.newtabpage.activity-stream.newtabWallpapers.v2.enabled";
export class WallpaperFeed {
constructor() {
this.loaded = false;
@ -48,8 +51,13 @@ export class WallpaperFeed {
PREF_WALLPAPERS_ENABLED
);
if (wallpapersEnabled) {
const wallpapersV2Enabled = Services.prefs.getBoolPref(
PREF_WALLPAPERS_V2_ENABLED
);
if (wallpapersEnabled || wallpapersV2Enabled) {
if (!this.wallpaperClient) {
// getting collection
this.wallpaperClient = this.RemoteSettings("newtab-wallpapers");
}
@ -73,6 +81,7 @@ export class WallpaperFeed {
}
async updateWallpapers(isStartup = false) {
// retrieving all records in collection
const records = await this.wallpaperClient.get();
if (!records?.length) {
return;
@ -85,9 +94,14 @@ export class WallpaperFeed {
return {
...record,
wallpaperUrl: `${this.baseAttachmentURL}${record.attachment.location}`,
category: record.category || "other",
};
});
const categories = [
...new Set(wallpapers.map(wallpaper => wallpaper.category)),
];
this.store.dispatch(
ac.BroadcastToContent({
type: at.WALLPAPERS_SET,
@ -97,6 +111,16 @@ export class WallpaperFeed {
},
})
);
this.store.dispatch(
ac.BroadcastToContent({
type: at.WALLPAPERS_CATEGORY_SET,
data: categories,
meta: {
isStartup,
},
})
);
}
initHighlightCounter() {

View file

@ -73,7 +73,7 @@ add_task(async function test_onAction_INIT() {
type: at.INIT,
});
Assert.ok(feed.store.dispatch.calledTwice);
Assert.ok(feed.store.dispatch.calledThrice);
Assert.ok(
feed.store.dispatch.firstCall.calledWith(
ac.BroadcastToContent({

View file

@ -867,6 +867,13 @@ pocketNewtab:
pref: browser.newtabpage.activity-stream.newtabWallpapers.enabled
description: >-
Turns on and off wallpaper support.
wallpapersV2:
type: boolean
setPref:
branch: user
pref: browser.newtabpage.activity-stream.newtabWallpapers.v2.enabled
description: >-
Turns on and off updated wallpaper experience.
weatherLocationSearch:
type: boolean
fallbackPref: >-