summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/content-src/components/Base/Base.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/content-src/components/Base/Base.jsx')
-rw-r--r--browser/components/newtab/content-src/components/Base/Base.jsx150
1 files changed, 144 insertions, 6 deletions
diff --git a/browser/components/newtab/content-src/components/Base/Base.jsx b/browser/components/newtab/content-src/components/Base/Base.jsx
index 20402b09f5..1738f8f51a 100644
--- a/browser/components/newtab/content-src/components/Base/Base.jsx
+++ b/browser/components/newtab/content-src/components/Base/Base.jsx
@@ -2,10 +2,7 @@
* 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 {
- actionCreators as ac,
- actionTypes as at,
-} from "common/Actions.sys.mjs";
+import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs";
import { DiscoveryStreamAdmin } from "content-src/components/DiscoveryStreamAdmin/DiscoveryStreamAdmin";
import { ConfirmDialog } from "content-src/components/ConfirmDialog/ConfirmDialog";
import { connect } from "react-redux";
@@ -16,6 +13,9 @@ import React from "react";
import { Search } from "content-src/components/Search/Search";
import { Sections } from "content-src/components/Sections/Sections";
+const VISIBLE = "visible";
+const VISIBILITY_CHANGE_EVENT = "visibilitychange";
+
export const PrefsButton = ({ onClick, icon }) => (
<div className="prefs-button">
<button
@@ -76,7 +76,7 @@ export class _Base extends React.PureComponent {
]
.filter(v => v)
.join(" ");
- global.document.body.className = bodyClassName;
+ globalThis.document.body.className = bodyClassName;
}
render() {
@@ -110,17 +110,75 @@ 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 };
+ this.updateWallpaper = this.updateWallpaper.bind(this);
+ this.prefersDarkQuery = null;
+ this.handleColorModeChange = this.handleColorModeChange.bind(this);
+ this.state = {
+ fixedSearch: false,
+ firstVisibleTimestamp: null,
+ colorMode: "",
+ };
+ }
+
+ setFirstVisibleTimestamp() {
+ if (!this.state.firstVisibleTimestamp) {
+ this.setState({
+ firstVisibleTimestamp: Date.now(),
+ });
+ }
}
componentDidMount() {
global.addEventListener("scroll", this.onWindowScroll);
global.addEventListener("keydown", this.handleOnKeyDown);
+ if (this.props.document.visibilityState === VISIBLE) {
+ this.setFirstVisibleTimestamp();
+ } else {
+ this._onVisibilityChange = () => {
+ if (this.props.document.visibilityState === VISIBLE) {
+ this.setFirstVisibleTimestamp();
+ this.props.document.removeEventListener(
+ VISIBILITY_CHANGE_EVENT,
+ this._onVisibilityChange
+ );
+ this._onVisibilityChange = null;
+ }
+ };
+ this.props.document.addEventListener(
+ VISIBILITY_CHANGE_EVENT,
+ this._onVisibilityChange
+ );
+ }
+ // track change event to dark/light mode
+ this.prefersDarkQuery = globalThis.matchMedia(
+ "(prefers-color-scheme: dark)"
+ );
+
+ this.prefersDarkQuery.addEventListener(
+ "change",
+ this.handleColorModeChange
+ );
+ this.handleColorModeChange();
+ }
+
+ handleColorModeChange() {
+ const colorMode = this.prefersDarkQuery?.matches ? "dark" : "light";
+ this.setState({ colorMode });
}
componentWillUnmount() {
+ this.prefersDarkQuery?.removeEventListener(
+ "change",
+ this.handleColorModeChange
+ );
global.removeEventListener("scroll", this.onWindowScroll);
global.removeEventListener("keydown", this.handleOnKeyDown);
+ if (this._onVisibilityChange) {
+ this.props.document.removeEventListener(
+ VISIBILITY_CHANGE_EVENT,
+ this._onVisibilityChange
+ );
+ }
}
onWindowScroll() {
@@ -160,11 +218,79 @@ export class BaseContent extends React.PureComponent {
this.props.dispatch(ac.SetPref(pref, value));
}
+ renderWallpaperAttribution() {
+ const { wallpaperList } = this.props.Wallpapers;
+ const activeWallpaper =
+ this.props.Prefs.values[
+ `newtabWallpapers.wallpaper-${this.state.colorMode}`
+ ];
+ const selected = wallpaperList.find(wp => wp.title === activeWallpaper);
+ // make sure a wallpaper is selected and that the attribution also exists
+ if (!selected?.attribution) {
+ return null;
+ }
+
+ const { name, webpage } = selected.attribution;
+ if (activeWallpaper && wallpaperList && name.url) {
+ return (
+ <p
+ className={`wallpaper-attribution`}
+ key={name}
+ data-l10n-id="newtab-wallpaper-attribution"
+ data-l10n-args={JSON.stringify({
+ author_string: name.string,
+ author_url: name.url,
+ webpage_string: webpage.string,
+ webpage_url: webpage.url,
+ })}
+ >
+ <a data-l10n-name="name-link" href={name.url}>
+ {name.string}
+ </a>
+ <a data-l10n-name="webpage-link" href={webpage.url}>
+ {webpage.string}
+ </a>
+ </p>
+ );
+ }
+ return null;
+ }
+
+ async updateWallpaper() {
+ const prefs = this.props.Prefs.values;
+ const { wallpaperList } = this.props.Wallpapers;
+
+ if (wallpaperList) {
+ const lightWallpaper =
+ wallpaperList.find(
+ wp => wp.title === prefs["newtabWallpapers.wallpaper-light"]
+ ) || "";
+ const darkWallpaper =
+ wallpaperList.find(
+ wp => wp.title === prefs["newtabWallpapers.wallpaper-dark"]
+ ) || "";
+ global.document?.body.style.setProperty(
+ `--newtab-wallpaper-light`,
+ `url(${lightWallpaper?.wallpaperUrl || ""})`
+ );
+
+ global.document?.body.style.setProperty(
+ `--newtab-wallpaper-dark`,
+ `url(${darkWallpaper?.wallpaperUrl || ""})`
+ );
+ }
+ }
+
render() {
const { props } = this;
const { App } = props;
const { initialized, customizeMenuVisible } = App;
const prefs = props.Prefs.values;
+
+ const activeWallpaper =
+ prefs[`newtabWallpapers.wallpaper-${this.state.colorMode}`];
+ const wallpapersEnabled = prefs["newtabWallpapers.enabled"];
+
const { pocketConfig } = prefs;
const isDiscoveryStream =
@@ -215,6 +341,9 @@ export class BaseContent extends React.PureComponent {
]
.filter(v => v)
.join(" ");
+ if (wallpapersEnabled) {
+ this.updateWallpaper();
+ }
return (
<div>
@@ -224,6 +353,8 @@ export class BaseContent extends React.PureComponent {
openPreferences={this.openPreferences}
setPref={this.setPref}
enabledSections={enabledSections}
+ wallpapersEnabled={wallpapersEnabled}
+ activeWallpaper={activeWallpaper}
pocketRegion={pocketRegion}
mayHaveSponsoredTopSites={mayHaveSponsoredTopSites}
mayHaveSponsoredStories={mayHaveSponsoredStories}
@@ -252,6 +383,7 @@ export class BaseContent extends React.PureComponent {
<DiscoveryStreamBase
locale={props.App.locale}
mayHaveSponsoredStories={mayHaveSponsoredStories}
+ firstVisibleTimestamp={this.state.firstVisibleTimestamp}
/>
</ErrorBoundary>
) : (
@@ -259,6 +391,7 @@ export class BaseContent extends React.PureComponent {
)}
</div>
<ConfirmDialog />
+ {wallpapersEnabled && this.renderWallpaperAttribution()}
</main>
</div>
</div>
@@ -266,10 +399,15 @@ export class BaseContent extends React.PureComponent {
}
}
+BaseContent.defaultProps = {
+ document: global.document,
+};
+
export const Base = connect(state => ({
App: state.App,
Prefs: state.Prefs,
Sections: state.Sections,
DiscoveryStream: state.DiscoveryStream,
Search: state.Search,
+ Wallpapers: state.Wallpapers,
}))(_Base);