summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState')
-rw-r--r--browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/DSEmptyState.jsx100
-rw-r--r--browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/_DSEmptyState.scss83
2 files changed, 183 insertions, 0 deletions
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/DSEmptyState.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/DSEmptyState.jsx
new file mode 100644
index 0000000000..ff3886b407
--- /dev/null
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/DSEmptyState.jsx
@@ -0,0 +1,100 @@
+/* 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 {
+ actionCreators as ac,
+ actionTypes as at,
+} from "common/Actions.sys.mjs";
+import React from "react";
+
+export class DSEmptyState extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.onReset = this.onReset.bind(this);
+ this.state = {};
+ }
+
+ componentWillUnmount() {
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+ }
+
+ onReset() {
+ if (this.props.dispatch && this.props.feed) {
+ const { feed } = this.props;
+ const { url } = feed;
+ this.props.dispatch({
+ type: at.DISCOVERY_STREAM_FEED_UPDATE,
+ data: {
+ feed: {
+ ...feed,
+ data: {
+ ...feed.data,
+ status: "waiting",
+ },
+ },
+ url,
+ },
+ });
+
+ this.setState({ waiting: true });
+ this.timeout = setTimeout(() => {
+ this.timeout = null;
+ this.setState({
+ waiting: false,
+ });
+ }, 300);
+
+ this.props.dispatch(
+ ac.OnlyToMain({ type: at.DISCOVERY_STREAM_RETRY_FEED, data: { feed } })
+ );
+ }
+ }
+
+ renderButton() {
+ if (this.props.status === "waiting" || this.state.waiting) {
+ return (
+ <button
+ className="try-again-button waiting"
+ data-l10n-id="newtab-discovery-empty-section-topstories-loading"
+ />
+ );
+ }
+
+ return (
+ <button
+ className="try-again-button"
+ onClick={this.onReset}
+ data-l10n-id="newtab-discovery-empty-section-topstories-try-again-button"
+ />
+ );
+ }
+
+ renderState() {
+ if (this.props.status === "waiting" || this.props.status === "failed") {
+ return (
+ <React.Fragment>
+ <h2 data-l10n-id="newtab-discovery-empty-section-topstories-timed-out" />
+ {this.renderButton()}
+ </React.Fragment>
+ );
+ }
+
+ return (
+ <React.Fragment>
+ <h2 data-l10n-id="newtab-discovery-empty-section-topstories-header" />
+ <p data-l10n-id="newtab-discovery-empty-section-topstories-content" />
+ </React.Fragment>
+ );
+ }
+
+ render() {
+ return (
+ <div className="section-empty-state">
+ <div className="empty-state-message">{this.renderState()}</div>
+ </div>
+ );
+ }
+}
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/_DSEmptyState.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/_DSEmptyState.scss
new file mode 100644
index 0000000000..9f9accf71b
--- /dev/null
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSEmptyState/_DSEmptyState.scss
@@ -0,0 +1,83 @@
+.section-empty-state {
+ border: $border-secondary;
+ border-radius: 4px;
+ display: flex;
+ height: $card-height-compact;
+ width: 100%;
+
+ .empty-state-message {
+ color: var(--newtab-text-secondary-color);
+ font-size: 14px;
+ line-height: 20px;
+ text-align: center;
+ margin: auto;
+ max-width: 936px;
+ }
+
+ .try-again-button {
+ margin-top: 12px;
+ padding: 6px 32px;
+ border-radius: 2px;
+ border: 0;
+ background: var(--newtab-button-secondary-color);
+ color: var(--newtab-text-primary-color);
+ cursor: pointer;
+ position: relative;
+ transition: background 0.2s ease, color 0.2s ease;
+
+ &:not(.waiting) {
+ &:focus {
+ @include ds-fade-in;
+
+ @include dark-theme-only {
+ @include ds-fade-in($blue-40-40);
+ }
+ }
+
+ &:hover {
+ @include ds-fade-in(var(--newtab-element-secondary-color));
+ }
+ }
+
+ &::after {
+ content: '';
+ height: 20px;
+ width: 20px;
+ animation: spinner 1s linear infinite;
+ opacity: 0;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin: -10px 0 0 -10px;
+ mask-image: url('chrome://activity-stream/content/data/content/assets/spinner.svg');
+ mask-size: 20px;
+ background: var(--newtab-text-secondary-color);
+ }
+
+ &.waiting {
+ cursor: initial;
+ background: var(--newtab-element-secondary-color);
+ color: transparent;
+ transition: background 0.2s ease;
+
+ &::after {
+ transition: opacity 0.2s ease;
+ opacity: 1;
+ }
+ }
+ }
+
+ h2 {
+ font-size: 15px;
+ font-weight: 600;
+ margin: 0;
+ }
+
+ p {
+ margin: 0;
+ }
+}
+
+@keyframes spinner {
+ to { transform: rotate(360deg); }
+}