summaryrefslogtreecommitdiffstats
path: root/browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx')
-rw-r--r--browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx139
1 files changed, 139 insertions, 0 deletions
diff --git a/browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx b/browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx
new file mode 100644
index 0000000000..25679bc638
--- /dev/null
+++ b/browser/components/pocket/content/panels/js/components/ArticleList/ArticleList.jsx
@@ -0,0 +1,139 @@
+/* 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, { useState } from "react";
+import TelemetryLink from "../TelemetryLink/TelemetryLink";
+
+function ArticleUrl(props) {
+ // We turn off the link if we're either a saved article, or if the url doesn't exist.
+ if (props.savedArticle || !props.url) {
+ return (
+ <div className="stp_article_list_saved_article">{props.children}</div>
+ );
+ }
+ return (
+ <TelemetryLink
+ className="stp_article_list_link"
+ href={props.url}
+ source={props.source}
+ position={props.position}
+ model={props.model}
+ >
+ {props.children}
+ </TelemetryLink>
+ );
+}
+
+function Article(props) {
+ function encodeThumbnail(rawSource) {
+ return rawSource
+ ? `https://img-getpocket.cdn.mozilla.net/80x80/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(
+ rawSource
+ )}`
+ : null;
+ }
+
+ const [thumbnailLoaded, setThumbnailLoaded] = useState(false);
+ const [thumbnailLoadFailed, setThumbnailLoadFailed] = useState(false);
+
+ const {
+ article,
+ savedArticle,
+ position,
+ source,
+ model,
+ utmParams,
+ openInPocketReader,
+ } = props;
+
+ if (!article.url && !article.resolved_url && !article.given_url) {
+ return null;
+ }
+ const url = new URL(article.url || article.resolved_url || article.given_url);
+ const urlSearchParams = new URLSearchParams(utmParams);
+
+ if (
+ openInPocketReader &&
+ article.item_id &&
+ !url.href.match(/getpocket\.com\/read/)
+ ) {
+ url.href = `https://getpocket.com/read/${article.item_id}`;
+ }
+
+ for (let [key, val] of urlSearchParams.entries()) {
+ url.searchParams.set(key, val);
+ }
+
+ // Using array notation because there is a key titled `1` (`images` is an object)
+ const thumbnail =
+ article.thumbnail ||
+ encodeThumbnail(article?.top_image_url || article?.images?.["1"]?.src);
+ const alt = article.alt || "thumbnail image";
+ const title = article.title || article.resolved_title || article.given_title;
+ // Sometimes domain_metadata is not there, depending on the source.
+ const publisher =
+ article.publisher ||
+ article.domain_metadata?.name ||
+ article.resolved_domain;
+
+ return (
+ <li className="stp_article_list_item">
+ <ArticleUrl
+ url={url.href}
+ savedArticle={savedArticle}
+ position={position}
+ source={source}
+ model={model}
+ utmParams={utmParams}
+ >
+ <>
+ {thumbnail && !thumbnailLoadFailed ? (
+ <img
+ className="stp_article_list_thumb"
+ src={thumbnail}
+ alt={alt}
+ width="40"
+ height="40"
+ onLoad={() => {
+ setThumbnailLoaded(true);
+ }}
+ onError={() => {
+ setThumbnailLoadFailed(true);
+ }}
+ style={{
+ visibility: thumbnailLoaded ? `visible` : `hidden`,
+ }}
+ />
+ ) : (
+ <div className="stp_article_list_thumb_placeholder" />
+ )}
+ <div className="stp_article_list_meta">
+ <header className="stp_article_list_header">{title}</header>
+ <p className="stp_article_list_publisher">{publisher}</p>
+ </div>
+ </>
+ </ArticleUrl>
+ </li>
+ );
+}
+
+function ArticleList(props) {
+ return (
+ <ul className="stp_article_list">
+ {props.articles?.map((article, position) => (
+ <Article
+ article={article}
+ savedArticle={props.savedArticle}
+ position={position}
+ source={props.source}
+ model={props.model}
+ utmParams={props.utmParams}
+ openInPocketReader={props.openInPocketReader}
+ />
+ ))}
+ </ul>
+ );
+}
+
+export default ArticleList;