diff --git a/browser/ui/webui/brave_webui_source.cc b/browser/ui/webui/brave_webui_source.cc index f14dc34f743d..aa8c081b2916 100644 --- a/browser/ui/webui/brave_webui_source.cc +++ b/browser/ui/webui/brave_webui_source.cc @@ -242,12 +242,14 @@ void CustomizeWebUIHTMLSource(content::WebUI* web_ui, { "braveNewsAdvertBadge", IDS_BRAVE_NEWS_ADVERT_BADGE}, { "braveNewsHideContentFrom", IDS_BRAVE_NEWS_HIDE_CONTENT_FROM}, { "braveNewsSourcesRecommendation", IDS_BRAVE_NEWS_SOURCES_RECOMMENDATION}, - { "braveNewsNoArticles", IDS_BRAVE_NEWS_NO_ARTICLES}, + { "braveNewsNoArticlesTitle", IDS_BRAVE_NEWS_NO_ARTICLES_TITLE}, + { "braveNewsNoArticlesMessage", IDS_BRAVE_NEWS_NO_ARTICLES_MESSAGE}, { "braveNewsCustomizeFeed", IDS_BRAVE_NEWS_CUSTOMIZE_FEED}, { "braveNewsRefreshFeed", IDS_BRAVE_NEWS_REFRESH_FEED}, { "braveNewsOpenArticlesIn", IDS_BRAVE_NEWS_OPEN_ARTICLES_IN}, { "braveNewsOpenArticlesInNewTab", IDS_BRAVE_NEWS_OPEN_ARTICLES_IN_NEW_TAB}, { "braveNewsOpenArticlesInCurrentTab", IDS_BRAVE_NEWS_OPEN_ARTICLES_IN_CURRENT_TAB}, + { "braveNewsCaughtUp", IDS_BRAVE_NEWS_CAUGHT_UP}, // Brave News Channels { "braveNewsChannel-Brave", IDS_BRAVE_NEWS_CHANNEL_BRAVE}, diff --git a/components/brave_new_tab_ui/components/default/braveNews/customize/Carousel.tsx b/components/brave_new_tab_ui/components/default/braveNews/customize/Carousel.tsx index 22ad31ce5263..118b346b914e 100644 --- a/components/brave_new_tab_ui/components/default/braveNews/customize/Carousel.tsx +++ b/components/brave_new_tab_ui/components/default/braveNews/customize/Carousel.tsx @@ -6,7 +6,7 @@ import * as React from 'react' import styled, { css } from 'styled-components' import Flex from '$web-common/Flex' -import FeedCard from './FeedCard' +import PublisherCard from '../../../../../brave_news/browser/resources/shared/PublisherCard' import { ArrowRight } from '../../../../../brave_news/browser/resources/shared/Icons' const CARD_SIZE = 208 @@ -84,7 +84,7 @@ const ItemsContainer = styled(Flex)` } ` -const FeedCardContainer = styled.div` +const PublisherCardContainer = styled.div` min-width: calc((100cqi - ${CARD_GAP} * 2) / 3); max-width: ${CARD_SIZE_PX}; scroll-snap-align: start; @@ -138,9 +138,9 @@ export default function Carousel(props: Props) { } - {props.publisherIds.map(p => - - )} + {props.publisherIds.map(p => + + )} scroll('left')} hidden={availableDirections === 'right' || availableDirections === 'none'}> {ArrowRight} diff --git a/components/brave_new_tab_ui/components/default/braveNews/customize/Discover.tsx b/components/brave_new_tab_ui/components/default/braveNews/customize/Discover.tsx index 8bfa4593d142..64c07457e9d6 100644 --- a/components/brave_new_tab_ui/components/default/braveNews/customize/Discover.tsx +++ b/components/brave_new_tab_ui/components/default/braveNews/customize/Discover.tsx @@ -13,7 +13,7 @@ import styled from 'styled-components' import { useBraveNews, useChannels } from '../../../../../brave_news/browser/resources/shared/Context' import ChannelCard from './ChannelCard' import DiscoverSection from './DiscoverSection' -import FeedCard, { DirectFeedCard } from './FeedCard' +import PublisherCard, { DirectPublisherCard } from '../../../../../brave_news/browser/resources/shared/PublisherCard' import { PopularCarousel } from './Popular' import { SuggestionsCarousel } from './Suggestions' import useSearch from './useSearch' @@ -89,7 +89,7 @@ function SearchResults (props: SearchResultsProps) { } {search.filteredSources.publisherIds.map(publisherId => - + )} {showFetchPermissionButton &&
@@ -99,7 +99,7 @@ function SearchResults (props: SearchResultsProps) {
} {search.filteredSources.direct.map(r => - )} + )} {!search.canQueryFilterSources && getLocale('braveNewsSearchQueryTooShort') } diff --git a/components/brave_new_tab_ui/components/default/braveNews/customize/Popular.tsx b/components/brave_new_tab_ui/components/default/braveNews/customize/Popular.tsx index fd0e618907d1..df834f6a438e 100644 --- a/components/brave_new_tab_ui/components/default/braveNews/customize/Popular.tsx +++ b/components/brave_new_tab_ui/components/default/braveNews/customize/Popular.tsx @@ -11,7 +11,7 @@ import Carousel from './Carousel' import CustomizeLink from './CustomizeLink' import CustomizePage from './CustomizePage' import DiscoverSection from './DiscoverSection' -import FeedCard from './FeedCard' +import PublisherCard from '../../../../../brave_news/browser/resources/shared/PublisherCard' const usePopularPublisherIds = () => { const { filteredPublisherIds, publishers, locale } = useBraveNews() @@ -49,7 +49,7 @@ export function PopularPage () { const popularPublisherIds = usePopularPublisherIds() return - {popularPublisherIds.map(p => )} + {popularPublisherIds.map(p => )} } diff --git a/components/brave_new_tab_ui/components/default/braveNews/customize/Suggestions.tsx b/components/brave_new_tab_ui/components/default/braveNews/customize/Suggestions.tsx index 286c1f9deb42..8c05d13653c3 100644 --- a/components/brave_new_tab_ui/components/default/braveNews/customize/Suggestions.tsx +++ b/components/brave_new_tab_ui/components/default/braveNews/customize/Suggestions.tsx @@ -11,7 +11,7 @@ import Carousel from './Carousel' import CustomizeLink from './CustomizeLink' import CustomizePage from './CustomizePage' import DiscoverSection from './DiscoverSection' -import FeedCard from './FeedCard' +import PublisherCard from '../../../../../brave_news/browser/resources/shared/PublisherCard' export function SuggestionsCarousel () { const { suggestedPublisherIds, setCustomizePage } = useBraveNews() @@ -31,7 +31,7 @@ export function SuggestionsPage () { const { suggestedPublisherIds } = useBraveNews() return - {suggestedPublisherIds.map(p => )} + {suggestedPublisherIds.map(p => )} } diff --git a/components/brave_new_tab_ui/components/default/page/index.tsx b/components/brave_new_tab_ui/components/default/page/index.tsx index 86999710d322..0ad1dcd24cc9 100644 --- a/components/brave_new_tab_ui/components/default/page/index.tsx +++ b/components/brave_new_tab_ui/components/default/page/index.tsx @@ -88,19 +88,20 @@ const StyledPage = styled('div') ` NTP items remain in the same place, and still allows NTP Page to scroll to the bottom before that starts happening. */ z-index: 3; - /* Blur out the content when Brave News is interacted - with. We need the opacity to fade out our background image. - We need the background image to overcome the bug - where a backdrop-filter element's ancestor which has - a filter must also have a background. When this bug is - fixed then this element won't need the background. - */ - opacity: calc(1 - var(--ntp-extra-content-effect-multiplier)); - filter: blur(var(--blur-amount)); - background: var(--default-bg-color); - ${getPageBackground} } + /* Blur out the content when Brave News is interacted + with. We need the opacity to fade out our background image. + We need the background image to overcome the bug + where a backdrop-filter element's ancestor which has + a filter must also have a background. When this bug is + fixed then this element won't need the background. + */ + opacity: calc(1 - var(--ntp-extra-content-effect-multiplier)); + filter: blur(var(--blur-amount)); + background: var(--default-bg-color); + ${getPageBackground} + @media screen and (max-width: ${breakpointEveryBlock}) { display: flex; flex-direction: column; diff --git a/components/brave_new_tab_ui/tsconfig.json b/components/brave_new_tab_ui/tsconfig.json index 7c5598b439ec..96e7722710e2 100644 --- a/components/brave_new_tab_ui/tsconfig.json +++ b/components/brave_new_tab_ui/tsconfig.json @@ -5,5 +5,4 @@ "**/*.tsx", "**/*.d.ts", "../definitions/*.d.ts" - ] } diff --git a/components/brave_news/browser/resources/Feed.tsx b/components/brave_news/browser/resources/Feed.tsx index 42b82337bd27..95650a8a4ac1 100644 --- a/components/brave_news/browser/resources/Feed.tsx +++ b/components/brave_news/browser/resources/Feed.tsx @@ -14,6 +14,8 @@ import HeroArticle from "./feed/Hero"; import { getHistoryValue, setHistoryState } from "./shared/history"; import NoArticles from "./feed/NoArticles"; import LoadingCard from "./feed/LoadingCard"; +import { spacing } from "@brave/leo/tokens/css"; +import CaughtUp from "./feed/CaughtUp"; // Restoring scroll position is complicated - we have two available strategies: // 1. Scroll to the same position - as long as the window hasn't been resized, @@ -27,11 +29,17 @@ interface NewsScrollData { scrollPos: number, } +const CARD_CLASS = 'feed-card' const FeedContainer = styled.div` width: 540px; display: flex; flex-direction: column; - gap: 12px; + gap: ${spacing.xl}; + + /* Hide Ad elements, if we weren't able to fill them */ + & .${CARD_CLASS}:empty { + display: none; + } ` interface Props { @@ -52,7 +60,6 @@ export const NEWS_FEED_CLASS = "news-feed" // The number of cards to load at a time. Making this too high will result in // jank as all the cards are rendered at once. const PAGE_SIZE = 25; -const CARD_CLASS = 'feed-card' const HISTORY_SCROLL_DATA = 'bn-scroll-data' const HISTORY_CARD_COUNT = 'bn-card-count' @@ -73,7 +80,7 @@ export default function Component({ feed }: Props) { // Store the number of cards we've loaded in history - otherwise when we // navigate back we might not be able to scroll down far enough. React.useEffect(() => { - setHistoryState({ HISTORY_CARD_COUNT: cardCount }) + setHistoryState({ [HISTORY_CARD_COUNT]: cardCount }) }, [cardCount]) // Track the feed scroll position - if we mount this component somewhere with @@ -138,7 +145,11 @@ export default function Component({ feed }: Props) { return {feed - ? !feed.items.length ? : cards + ? !feed.items.length ? + : <> + {cards} + + : } } diff --git a/components/brave_news/browser/resources/feed/Ad.tsx b/components/brave_news/browser/resources/feed/Ad.tsx index d48e560a90cd..296e099b215f 100644 --- a/components/brave_news/browser/resources/feed/Ad.tsx +++ b/components/brave_news/browser/resources/feed/Ad.tsx @@ -121,6 +121,6 @@ export default function Advert(props: Props) { {advert.title} - {advert.ctaText} + {advert.ctaText} } diff --git a/components/brave_news/browser/resources/feed/Article.tsx b/components/brave_news/browser/resources/feed/Article.tsx index 3c5e1b914011..3af97e2c91ab 100644 --- a/components/brave_news/browser/resources/feed/Article.tsx +++ b/components/brave_news/browser/resources/feed/Article.tsx @@ -19,6 +19,7 @@ interface Props { const Container = styled(Card)` display: flex; flex-direction: column; + padding-top: ${spacing.l}; ` export default function Article({ info, hideChannel }: Props) { @@ -27,7 +28,7 @@ export default function Article({ info, hideChannel }: Props) { return - + <BraveNewsLink href={url}>{info.data.title}</BraveNewsLink> diff --git a/components/brave_news/browser/resources/feed/ArticleMetaRow.tsx b/components/brave_news/browser/resources/feed/ArticleMetaRow.tsx index 181c81b1bb47..293c103d2c99 100644 --- a/components/brave_news/browser/resources/feed/ArticleMetaRow.tsx +++ b/components/brave_news/browser/resources/feed/ArticleMetaRow.tsx @@ -16,7 +16,7 @@ import { getLocale } from '$web-common/locale'; import { getTranslatedChannelName } from "../shared/channel"; const MenuButton = styled(Button)` - --leo-button-padding: ${spacing.s}; + --leo-button-padding: 0; flex-grow: 0; ` @@ -34,6 +34,12 @@ export const MetaInfoContainer = styled.h4` gap: ${spacing.s}; ` +const publisherDescription = (article: FeedItemMetadata) => { + if (article.publisherName) return article.publisherName + const url = new URL(article.url.url) + return url.origin +} + export function MetaInfo(props: { article: FeedItemMetadata, hideChannel?: boolean }) { const maybeChannel = !props.hideChannel && <> • {channelIcons[props.article.categoryName] ?? channelIcons.default} {getTranslatedChannelName(props.article.categoryName)} @@ -43,7 +49,7 @@ export function MetaInfo(props: { article: FeedItemMetadata, hideChannel?: boole • {props.article.relativeTimeDescription} return - {props.article.publisherName} {maybeChannel} {maybeTime} + {publisherDescription(props.article)} {maybeChannel} {maybeTime} } @@ -52,15 +58,16 @@ export default function ArticleMetaRow(props: { article: FeedItemMetadata, hideC - + { getBraveNewsController().setPublisherPref(props.article.publisherId, UserEnabled.DISABLED) e.stopPropagation() - }}>{getLocale('braveNewsHideContentFrom', { - '$1': props.article.publisherName - })} + }}> + {getLocale('braveNewsHideContentFrom') + .replace('$1', publisherDescription(props.article))} + } diff --git a/components/brave_news/browser/resources/feed/Card.tsx b/components/brave_news/browser/resources/feed/Card.tsx index 8c6d497cf6d3..248f78525127 100644 --- a/components/brave_news/browser/resources/feed/Card.tsx +++ b/components/brave_news/browser/resources/feed/Card.tsx @@ -3,10 +3,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. +import * as React from 'react'; import { color, effect, font, radius, spacing } from '@brave/leo/tokens/css'; import styled from "styled-components"; import SecureLink, { SecureLinkProps, validateScheme } from '$web-common/SecureLink'; -import * as React from 'react'; import { configurationCache, useBraveNews } from '../shared/Context'; export const Header = styled.h2` @@ -27,14 +27,29 @@ export const Title = styled.h3` margin: 0; text-align: start; - font: ${font.primary.default.regular}; + font: ${font.primary.default.semibold}; color: var(--bn-glass-100); &> a { all: unset; } ` -export const SmallImage = styled.img` +const HidableImage = ({ onError, ...rest }: React.DetailedHTMLProps, HTMLImageElement>) => { + const ref = React.useRef() + + React.useEffect(() => { + ref.current!.style.opacity = '' + }, [rest.src]) + + const handleError = React.useCallback((e) => { + ref.current!.style.opacity = '0' + onError?.(e) + }, [onError]) + + return +} + +export const SmallImage = styled(HidableImage)` &:not([src]) { opacity: 0; } min-width: 96px; @@ -48,7 +63,7 @@ export const SmallImage = styled.img` border-radius: 6px; ` -export const LargeImage = styled.img` +export const LargeImage = styled(HidableImage)` &:not([src]) { opacity: 0; } width: 100%; @@ -65,7 +80,7 @@ export default styled.div` background: var(--bn-glass-container); border-radius: ${radius.xl}; color: var(--bn-glass-100); - padding: ${spacing["2Xl"]}; + padding: ${spacing.xl}; &:has(${Title} a:focus-visible) { box-shadow: ${effect.focusState}; diff --git a/components/brave_news/browser/resources/feed/CaughtUp.tsx b/components/brave_news/browser/resources/feed/CaughtUp.tsx new file mode 100644 index 000000000000..7cf8d977c4e6 --- /dev/null +++ b/components/brave_news/browser/resources/feed/CaughtUp.tsx @@ -0,0 +1,31 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// 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 https://mozilla.org/MPL/2.0/. + +import * as React from 'react'; +import styled from 'styled-components'; +import Flex from '$web-common/Flex'; +import { getLocale } from '../../../../common/locale'; +import Icon from '@brave/leo/react/icon'; +import { spacing } from '@brave/leo/tokens/css'; + +const Container = styled(Flex)` + color: var(--bn-glass-50); + gap: ${spacing.xl}; + + & > hr { + flex: 1; + border-color: var(--bn-glass-10); + } +` + +export default function CaughtUp() { + return +
+ + {getLocale('braveNewsCaughtUp')} + +
+
+} diff --git a/components/brave_news/browser/resources/feed/Cluster.tsx b/components/brave_news/browser/resources/feed/Cluster.tsx index 054fb5b060cf..9532feef0c28 100644 --- a/components/brave_news/browser/resources/feed/Cluster.tsx +++ b/components/brave_news/browser/resources/feed/Cluster.tsx @@ -19,7 +19,8 @@ interface Props { const Container = styled(Card)` display: flex; flex-direction: column; - gap: ${spacing.m}; + gap: ${spacing['2Xl']}; + padding-top: ${spacing['2Xl']}; ` export default function Cluster({ info }: Props) { diff --git a/components/brave_news/browser/resources/feed/Discover.tsx b/components/brave_news/browser/resources/feed/Discover.tsx index 6932ea6a946b..25a0ceec04d9 100644 --- a/components/brave_news/browser/resources/feed/Discover.tsx +++ b/components/brave_news/browser/resources/feed/Discover.tsx @@ -2,53 +2,20 @@ // 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 https://mozilla.org/MPL/2.0/. -import { Discover as Info, Publisher } from 'gen/brave/components/brave_news/common/brave_news.mojom.m'; +import { getLocale } from '$web-common/locale'; +import Icon from '@brave/leo/react/icon'; +import { icon, spacing } from '@brave/leo/tokens/css'; +import { Discover as Info } from 'gen/brave/components/brave_news/common/brave_news.mojom.m'; import * as React from 'react'; import styled from 'styled-components'; -import { publishersCache, useBraveNews } from '../shared/Context'; +import PublisherCard from '../shared/PublisherCard'; import Card, { Title } from './Card'; -import { isPublisherEnabled } from '../shared/api'; -import Button from '@brave/leo/react/button'; -import Icon from '@brave/leo/react/icon'; -import { useLazyUnpaddedImageUrl } from '../shared/useUnpaddedImageUrl'; -import { font, icon, spacing } from '@brave/leo/tokens/css'; -import { getLocale } from '$web-common/locale'; const Row = styled.div` display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 8px; - margin-top: 8px; -` - -const SuggestionCard = styled(Card) <{ backgroundUrl?: string, backgroundColor?: string }>` - position: relative; - display: flex; - align-items: center; - justify-content: center; - - height: 80px; - - background-image: ${p => `url(${p.backgroundUrl})`}, ${p => `linear-gradient(${p.backgroundColor}, ${p.backgroundColor})`}; - background-size: contain; - background-repeat: no-repeat; - background-position: center; -` - -const FollowButton = styled(Button)` - --leo-button-padding: 0; - - position: absolute; - top: 12px; - right: 12px; -` - -const FollowButtonIcon = styled(Icon)` - --leo-icon-size: 24px; -` - -const PublisherTitle = styled.span` - font: ${font.primary.default.regular}; + gap: ${spacing['2Xl']}; + margin-top: ${spacing.m}; ` const TitleIcon = styled(Icon)` @@ -56,31 +23,22 @@ const TitleIcon = styled(Icon)` margin-right: ${spacing.s}; ` +const Container = styled(Card)` + padding: ${spacing['2Xl']} ${spacing.xl}; +` + interface Props { info: Info } -function Suggestion({ publisher }: { publisher: Publisher }) { - const { setElementRef, url: coverUrl } = useLazyUnpaddedImageUrl(publisher.coverUrl?.url, { useCache: true }) - return
- - {!isPublisherEnabled(publisher) && publishersCache.setPublisherFollowed(publisher.publisherId, true)}> - - } - - {publisher?.publisherName} -
-} - export default function Component({ info }: Props) { - const { publishers } = useBraveNews(); - return + return <TitleIcon name="star-outline" /> {getLocale('braveNewsSourcesRecommendation')} - {info.publisherIds.map(p => )} + {info.publisherIds.map(p => )} - +
} diff --git a/components/brave_news/browser/resources/feed/NoArticles.tsx b/components/brave_news/browser/resources/feed/NoArticles.tsx index 21d1237b5a5b..0878a41cccd0 100644 --- a/components/brave_news/browser/resources/feed/NoArticles.tsx +++ b/components/brave_news/browser/resources/feed/NoArticles.tsx @@ -2,18 +2,22 @@ // 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 https://mozilla.org/MPL/2.0/. -import * as React from 'react'; -import Card, { Title } from './Card'; -import Button from '@brave/leo/react/button'; -import { useBraveNews } from '../shared/Context'; import { getLocale } from '$web-common/locale'; -import styled from 'styled-components'; +import Button from '@brave/leo/react/button'; import { spacing } from '@brave/leo/tokens/css'; +import * as React from 'react'; +import styled from 'styled-components'; +import Flex from '../../../../common/Flex'; +import { useBraveNews } from '../shared/Context'; +import { Title } from './Card'; + +const Container = styled(Flex)` + position: sticky; + top: ${spacing.xl}; -const Container = styled(Card)` - display: flex; - align-items: center; + padding: ${spacing.xl}; gap: ${spacing.m}; + color: var(--bn-glass-70); & > leo-button { flex: 0; @@ -22,8 +26,40 @@ const Container = styled(Card)` export default function NoArticles() { const { refreshFeedV2 } = useBraveNews() - return - {getLocale('braveNewsNoArticles')} - + return + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {getLocale('braveNewsNoArticlesTitle')} +
+ {getLocale('braveNewsNoArticlesMessage')} +
+
} diff --git a/components/brave_new_tab_ui/components/default/braveNews/customize/FeedCard.tsx b/components/brave_news/browser/resources/shared/PublisherCard.tsx similarity index 85% rename from components/brave_new_tab_ui/components/default/braveNews/customize/FeedCard.tsx rename to components/brave_news/browser/resources/shared/PublisherCard.tsx index 25b7bc9c65c7..0ba47bfc7824 100644 --- a/components/brave_new_tab_ui/components/default/braveNews/customize/FeedCard.tsx +++ b/components/brave_news/browser/resources/shared/PublisherCard.tsx @@ -7,11 +7,11 @@ import Flex from '$web-common/Flex' import * as React from 'react' import { useState } from 'react' import styled from 'styled-components' -import { usePublisher, usePublisherFollowed } from '../../../../../brave_news/browser/resources/shared/Context' -import getBraveNewsController from '../../../../../brave_news/browser/resources/shared/api' -import { useLazyUnpaddedImageUrl } from '../../../../../brave_news/browser/resources/shared/useUnpaddedImageUrl' -import FollowButton from './FollowButton' -import { getCardColor } from './colors' +import { usePublisher, usePublisherFollowed } from './Context' +import getBraveNewsController from './api' +import { useLazyUnpaddedImageUrl } from './useUnpaddedImageUrl' +import FollowButton from '../../../../brave_new_tab_ui/components/default/braveNews/customize/FollowButton' +import { getCardColor } from '../../../../brave_new_tab_ui/components/default/braveNews/customize/colors' interface CardProps { backgroundColor?: string @@ -63,7 +63,7 @@ const Name = styled.span` font-weight: 600; ` -export default function FeedCard (props: { +export default function PublisherCard (props: { publisherId: string }) { const publisher = usePublisher(props.publisherId) @@ -87,7 +87,7 @@ export default function FeedCard (props: { } -export function DirectFeedCard (props: { +export function DirectPublisherCard (props: { feedUrl: string title: string }) { diff --git a/components/resources/brave_news_strings.grdp b/components/resources/brave_news_strings.grdp index e488e77cd8d3..1c5509843f7f 100644 --- a/components/resources/brave_news_strings.grdp +++ b/components/resources/brave_news_strings.grdp @@ -211,10 +211,13 @@ Hide content from $1The Verge - Sources you'll enjoy + You might also like - - Feed is empty + + This feed is empty + + + There don't seem to be any articles in this feed at this moment. Try coming back later or refreshing the feed. Customize @@ -231,4 +234,7 @@ Current tab + + You're all caught up +