Show channel thumbnails in side menu

This commit is contained in:
Marios Vladimerou 2021-06-09 20:20:19 +01:00 committed by jessopb
parent 72a4ed107b
commit d8b40931f3
4 changed files with 65 additions and 24 deletions

View file

@ -5,7 +5,14 @@ import { selectGetSyncErrorMessage, selectSyncFatalError } from 'redux/selectors
import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user';
import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
import { doFetchChannelListMine, doFetchCollectionListMine, SETTINGS, selectMyChannelUrls } from 'lbry-redux';
import {
doFetchChannelListMine,
doFetchCollectionListMine,
SETTINGS,
selectMyChannelUrls,
doResolveUris,
} from 'lbry-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
import {
makeSelectClientSetting,
selectLanguage,
@ -47,6 +54,7 @@ const select = (state) => ({
syncFatalError: selectSyncFatalError(state),
activeChannelClaim: selectActiveChannelClaim(state),
myChannelUrls: selectMyChannelUrls(state),
subscriptions: selectSubscriptions(state),
});
const perform = (dispatch) => ({
@ -63,6 +71,7 @@ const perform = (dispatch) => ({
setActiveChannelIfNotSet: () => dispatch(doSetActiveChannel()),
setIncognito: () => dispatch(doSetIncognito()),
fetchModBlockedList: () => dispatch(doFetchModBlockedList()),
resolveUris: (uris) => dispatch(doResolveUris(uris)),
});
export default hot(connect(select, perform)(App));

View file

@ -1,6 +1,6 @@
// @flow
import * as PAGES from 'constants/pages';
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState, useLayoutEffect } from 'react';
import classnames from 'classnames';
import analytics from 'analytics';
import { buildURI, parseURI } from 'lbry-redux';
@ -84,9 +84,11 @@ type Props = {
syncFatalError: boolean,
activeChannelClaim: ?ChannelClaim,
myChannelUrls: ?Array<string>,
subscriptions: Array<Subscription>,
setActiveChannelIfNotSet: () => void,
setIncognito: (boolean) => void,
fetchModBlockedList: () => void,
resolveUris: (Array<string>) => void,
};
function App(props: Props) {
@ -119,6 +121,8 @@ function App(props: Props) {
setActiveChannelIfNotSet,
setIncognito,
fetchModBlockedList,
resolveUris,
subscriptions,
} = props;
const appRef = useRef();
@ -136,6 +140,8 @@ function App(props: Props) {
// @endif
const { pathname, hash, search } = props.location;
const [upgradeNagClosed, setUpgradeNagClosed] = useState(false);
const [resolvedSubscriptions, setResolvedSubscriptions] = useState(false);
const [sidebarOpen] = usePersistedState('sidebar', true);
const showUpgradeButton =
(autoUpdateDownloaded || (process.platform === 'linux' && isUpgradeAvailable)) && !upgradeNagClosed;
// referral claiming
@ -150,6 +156,7 @@ function App(props: Props) {
const hasNoChannels = myChannelUrls && myChannelUrls.length === 0;
const shouldMigrateLanguage = LANGUAGE_MIGRATIONS[language];
const hasActiveChannelClaim = activeChannelClaim !== undefined;
const isPersonalized = !IS_WEB || hasVerifiedEmail;
let uri;
try {
@ -338,6 +345,16 @@ function App(props: Props) {
}
}, [hasVerifiedEmail, signIn, hasSignedIn]);
// batch resolve subscriptions to be used by the sideNavigation component.
// add it here so that it only resolves the first time, despite route changes.
// useLayoutEffect because it has to be executed before the sideNavigation component requests them
useLayoutEffect(() => {
if (sidebarOpen && isPersonalized && subscriptions && !resolvedSubscriptions) {
setResolvedSubscriptions(true);
resolveUris(subscriptions.map((sub) => sub.uri));
}
}, [sidebarOpen, isPersonalized, resolvedSubscriptions, subscriptions, resolveUris, setResolvedSubscriptions]);
// @if TARGET='web'
useDegradedPerformance(setLbryTvApiStatus, user);
// @endif

View file

@ -8,6 +8,7 @@ import classnames from 'classnames';
import Icon from 'component/common/icon';
import NotificationBubble from 'component/notificationBubble';
import I18nMessage from 'component/i18nMessage';
import ChannelThumbnail from 'component/channelThumbnail';
import { PINNED_LABEL_1, PINNED_URI_1, PINNED_URI_2, PINNED_LABEL_2, SIMPLE_SITE, DOMAIN } from 'config';
// @if TARGET='app'
import { IS_MAC } from 'component/app/view';
@ -362,15 +363,8 @@ function SideNavigation(props: Props) {
{sidebarOpen && isPersonalized && subscriptions && subscriptions.length > 0 && (
<ul className="navigation__secondary navigation-links">
{subscriptions.map(({ uri, channelName }, index) => (
<li key={uri} className="navigation-link__wrapper">
<Button
navigate={uri}
label={channelName}
className="navigation-link"
activeClass="navigation-link--active"
/>
</li>
{subscriptions.map((subscription) => (
<SubscriptionListItem key={subscription.uri} subscription={subscription} />
))}
</ul>
)}
@ -445,15 +439,8 @@ function SideNavigation(props: Props) {
</ul>
{sidebarOpen && isPersonalized && subscriptions && subscriptions.length > 0 && (
<ul className="navigation__secondary navigation-links">
{subscriptions.map(({ uri, channelName }, index) => (
<li key={uri} className="navigation-link__wrapper">
<Button
navigate={uri}
label={channelName}
className="navigation-link"
activeClass="navigation-link--active"
/>
</li>
{subscriptions.map((subscription) => (
<SubscriptionListItem key={subscription.uri} subscription={subscription} />
))}
</ul>
)}
@ -484,4 +471,22 @@ function SideNavigation(props: Props) {
);
}
function SubscriptionListItem({ subscription }: { subscription: Subscription }) {
const { uri, channelName } = subscription;
return (
<li className="navigation-link__wrapper">
<Button
navigate={uri}
className="navigation-link navigation-link--with-thumbnail"
activeClass="navigation-link--active"
>
<ChannelThumbnail uri={uri} />
<span dir="auto" className="button__label">
{channelName}
</span>
</Button>
</li>
);
}
export default SideNavigation;

View file

@ -104,6 +104,16 @@
flex-direction: column;
}
&.navigation-link--with-thumbnail .button__content {
flex-direction: row;
.channel-thumbnail {
@include handleChannelGif(1.5rem);
flex-shrink: 0;
margin-right: var(--spacing-s);
}
}
&:hover:not(.navigation-link--active),
&:focus {
@extend .navigation-link--highlighted;
@ -114,8 +124,8 @@
margin-bottom: 0;
.icon {
height: 1rem;
width: 1rem;
height: 1.5rem;
width: 1.5rem;
}
.button__content {
@ -201,8 +211,8 @@
margin-bottom: 0;
.icon {
height: 1rem;
width: 1rem;
height: 1.5rem;
width: 1.5rem;
}
.button__content {