From a26305d75a70bc9915ab8024601b7ae3c79592df Mon Sep 17 00:00:00 2001 From: Dan Peterson Date: Thu, 6 Jan 2022 15:13:26 -0600 Subject: [PATCH] Add horizontal layout (#636) * Test out a horizontal scroll for upcoming (tile only for now) * - add support for list layout - add following label on home page - clan up css and naming conventions * Update header type + show only if scheduled streams are showing --- ui/component/claimList/view.jsx | 68 +++++++++++------- ui/component/claimListDiscover/view.jsx | 38 +++++++++- ui/component/claimPreview/view.jsx | 14 ++-- ui/component/claimPreviewTile/view.jsx | 3 + ui/component/router/view.jsx | 5 +- ui/page/home/view.jsx | 39 +++++++---- ui/scss/all.scss | 2 + ui/scss/component/_claim-list.scss | 8 ++- ui/scss/component/_swipe-list.scss | 13 ++++ ui/scss/component/_utils.scss | 92 +++++++++++++++++++++++++ ui/util/buildHomepage.js | 4 +- ui/util/claim.js | 23 +++++++ 12 files changed, 260 insertions(+), 49 deletions(-) create mode 100644 ui/scss/component/_swipe-list.scss create mode 100644 ui/scss/component/_utils.scss diff --git a/ui/component/claimList/view.jsx b/ui/component/claimList/view.jsx index aeac02b0a..5f3a2f8c1 100644 --- a/ui/component/claimList/view.jsx +++ b/ui/component/claimList/view.jsx @@ -44,7 +44,10 @@ type Props = { collectionId?: string, showNoSourceClaims?: boolean, onClick?: (e: any, claim?: ?Claim, index?: number) => void, - noEmpty: boolean, + maxClaimRender?: number, + excludeUris?: Array, + loadedCallback?: (number) => void, + swipeLayout: boolean, }; export default function ClaimList(props: Props) { @@ -75,7 +78,10 @@ export default function ClaimList(props: Props) { collectionId, showNoSourceClaims, onClick, - noEmpty, + maxClaimRender, + excludeUris = [], + loadedCallback, + swipeLayout = false, } = props; const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW); @@ -85,8 +91,18 @@ export default function ClaimList(props: Props) { const timedOut = uris === null; const urisLength = (uris && uris.length) || 0; - const tileUris = (prefixUris || []).concat(uris); - const sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? tileUris : tileUris.slice().reverse())) || []; + let tileUris = (prefixUris || []).concat(uris || []); + tileUris = tileUris.filter((uri) => !excludeUris.includes(uri)); + + const totalLength = tileUris.length; + + if (maxClaimRender) tileUris = tileUris.slice(0, maxClaimRender); + + let sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? tileUris : tileUris.slice().reverse())) || []; + + React.useEffect(() => { + if (typeof loadedCallback === 'function') loadedCallback(totalLength); + }, [totalLength]); // eslint-disable-line react-hooks/exhaustive-deps const noResultMsg = searchInLanguage ? __('No results. Contents may be hidden by the Language filter.') @@ -96,11 +112,21 @@ export default function ClaimList(props: Props) { setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW); } - function handleClaimClicked(e, claim, index) { - if (onClick) { - onClick(e, claim, index); - } - } + const handleClaimClicked = React.useCallback( + (e, claim, index) => { + if (onClick) { + onClick(e, claim, index); + } + }, + [onClick] + ); + + const customShouldHide = React.useCallback((claim: StreamClaim) => { + // Hack to hide spee.ch thumbnail publishes + // If it meets these requirements, it was probably uploaded here: + // https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79 + return claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch'; + }, []); useEffect(() => { const handleScroll = debounce((e) => { @@ -124,7 +150,7 @@ export default function ClaimList(props: Props) { }, [loading, onScrollBottom, urisLength, pageSize, page]); return tileLayout && !header ? ( -
+
{urisLength > 0 && tileUris.map((uri) => ( ))} - {!timedOut && urisLength === 0 && !loading && !noEmpty && ( -
{empty || noResultMsg}
- )} + {!timedOut && urisLength === 0 && !loading &&
{empty || noResultMsg}
} {timedOut && timedOutMessage &&
{timedOutMessage}
}
) : ( @@ -178,8 +203,9 @@ export default function ClaimList(props: Props) { {urisLength > 0 && (
    {sortedUris.map((uri, index) => ( @@ -199,22 +225,16 @@ export default function ClaimList(props: Props) { showHiddenByUser={showHiddenByUser} collectionId={collectionId} showNoSourceClaims={showNoSourceClaims} - customShouldHide={(claim: StreamClaim) => { - // Hack to hide spee.ch thumbnail publishes - // If it meets these requirements, it was probably uploaded here: - // https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79 - return claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch'; - }} - onClick={(e, claim, index) => handleClaimClicked(e, claim, index)} + customShouldHide={customShouldHide} + onClick={handleClaimClicked} + swipeLayout={swipeLayout} /> ))}
)} - {!timedOut && urisLength === 0 && !loading && !noEmpty && ( -
{empty || noResultMsg}
- )} + {!timedOut && urisLength === 0 && !loading &&
{empty || noResultMsg}
} {!loading && timedOut && timedOutMessage &&
{timedOutMessage}
}
); diff --git a/ui/component/claimListDiscover/view.jsx b/ui/component/claimListDiscover/view.jsx index 7f3e03065..c457b55a5 100644 --- a/ui/component/claimListDiscover/view.jsx +++ b/ui/component/claimListDiscover/view.jsx @@ -94,6 +94,13 @@ type Props = { doClaimSearch: ({}) => void, doToggleTagFollowDesktop: (string) => void, doFetchViewCount: (claimIdCsv: string) => void, + + loadedCallback?: (number) => void, + maxClaimRender?: number, + useSkeletonScreen?: boolean, + excludeUris?: Array, + + swipeLayout: boolean, }; function ClaimListDiscover(props: Props) { @@ -157,6 +164,11 @@ function ClaimListDiscover(props: Props) { empty, claimsByUri, doFetchViewCount, + loadedCallback, + maxClaimRender, + useSkeletonScreen = true, + excludeUris = [], + swipeLayout = false, } = props; const didNavigateForward = history.action === 'PUSH'; const { search } = location; @@ -493,6 +505,21 @@ function ClaimListDiscover(props: Props) { } function resolveOrderByOption(orderBy: string | Array, sortBy: string | Array) { + // let order_by; // peterson 038692cafc793616cceaf10b88909fecde07ad0b + // + // switch (orderBy) { + // case CS.ORDER_BY_TRENDING: + // order_by = CS.ORDER_BY_TRENDING_VALUE; + // break; + // case CS.ORDER_BY_NEW: + // order_by = CS.ORDER_BY_NEW_VALUE; + // break; + // case CS.ORDER_BY_NEW_ASC: + // order_by = CS.ORDER_BY_NEW_ASC_VALUE; + // break; + // default: + // order_by = CS.ORDER_BY_TOP_VALUE; + // } const order_by = orderBy === CS.ORDER_BY_TRENDING ? CS.ORDER_BY_TRENDING_VALUE @@ -569,8 +596,12 @@ function ClaimListDiscover(props: Props) { searchOptions={options} showNoSourceClaims={showNoSourceClaims} empty={empty} + maxClaimRender={maxClaimRender} + excludeUris={excludeUris} + loadedCallback={loadedCallback} + swipeLayout={swipeLayout} /> - {loading && ( + {loading && useSkeletonScreen && (
{new Array(dynamicPageSize).fill(1).map((x, i) => ( @@ -602,8 +633,13 @@ function ClaimListDiscover(props: Props) { searchOptions={options} showNoSourceClaims={hasNoSource || showNoSourceClaims} empty={empty} + maxClaimRender={maxClaimRender} + excludeUris={excludeUris} + loadedCallback={loadedCallback} + swipeLayout={swipeLayout} /> {loading && + useSkeletonScreen && new Array(dynamicPageSize) .fill(1) .map((x, i) => ( diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index 25e0277a4..6cd237d8a 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -6,6 +6,7 @@ import { isEmpty } from 'util/object'; import classnames from 'classnames'; import { isURIValid } from 'util/lbryURI'; import * as COLLECTIONS_CONSTS from 'constants/collections'; +import { isChannelClaim } from 'util/claim'; import { formatLbryUrlForWeb } from 'util/url'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; import FileThumbnail from 'component/fileThumbnail'; @@ -49,7 +50,7 @@ type Props = { type: string, banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean }, hasVisitedUri: boolean, - channelIsBlocked: boolean, + blockedUris: Array, actions: boolean | Node | string | number, properties: boolean | Node | string | number | ((Claim) => Node), empty?: Node, @@ -77,6 +78,7 @@ type Props = { date?: any, indexInContainer?: number, // The index order of this component within 'containerId'. channelSubCount?: number, + swipeLayout: boolean, }; const ClaimPreview = forwardRef((props: Props, ref: any) => { @@ -97,7 +99,6 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { streamingUrl, mediaDuration, // user properties - channelIsBlocked, hasVisitedUri, // component history, @@ -136,10 +137,11 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { disableNavigation, indexInContainer, channelSubCount, + swipeLayout = false, } = props; const isCollection = claim && claim.value_type === 'collection'; const collectionClaimId = isCollection && claim && claim.claim_id; - const listId = collectionId || collectionClaimId || null; + const listId = collectionId || collectionClaimId; const WrapperElement = wrapperElement || 'li'; const shouldFetch = claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending); @@ -170,7 +172,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { claim.value.stream_type && // $FlowFixMe (claim.value.stream_type === 'audio' || claim.value.stream_type === 'video'); - const isChannelUri = claim ? claim.value_type === 'channel' : false; + const isChannelUri = isChannelClaim(claim, uri); const signingChannel = claim && claim.signing_channel; const repostedChannelUri = claim && claim.repost_channel_url && claim.value_type === 'channel' @@ -321,6 +323,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { 'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri, 'claim-preview--pending': pending, 'claim-preview--collection-mine': isMyCollection && listId && type === 'listview', + 'swipe-list__item': swipeLayout, })} > {isMyCollection && listId && type === 'listview' && ( @@ -391,8 +394,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => {
)} - - {isChannelUri && !channelIsBlocked && !claimIsMine && ( + {isChannelUri && !banState.muted && !claimIsMine && ( diff --git a/ui/component/claimPreviewTile/view.jsx b/ui/component/claimPreviewTile/view.jsx index 908ec5f1b..3b431e29c 100644 --- a/ui/component/claimPreviewTile/view.jsx +++ b/ui/component/claimPreviewTile/view.jsx @@ -42,6 +42,7 @@ type Props = { properties?: (Claim) => void, collectionId?: string, viewCount: string, + swipeLayout: boolean, }; // preview image cards used in related video functionality, channel overview page and homepage @@ -66,6 +67,7 @@ function ClaimPreviewTile(props: Props) { collectionId, mediaDuration, viewCount, + swipeLayout = false, } = props; const isRepost = claim && claim.repost_channel_url; const isCollection = claim && claim.value_type === 'collection'; @@ -168,6 +170,7 @@ function ClaimPreviewTile(props: Props) { onClick={handleClick} className={classnames('card claim-preview--tile', { 'claim-preview__wrapper--channel': isChannel, + 'swipe-list__item claim-preview--horizontal-tile': swipeLayout, })} > diff --git a/ui/component/router/view.jsx b/ui/component/router/view.jsx index 095a84cdb..510e7bf3d 100644 --- a/ui/component/router/view.jsx +++ b/ui/component/router/view.jsx @@ -8,6 +8,7 @@ import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment'; import { parseURI, isURIValid } from 'util/lbryURI'; import { WELCOME_VERSION } from 'config'; import { GetLinksData } from 'util/buildHomepage'; +import { useIsLargeScreen } from 'effects/use-screensize'; import HomePage from 'page/home'; import BackupPage from 'page/backup'; @@ -125,8 +126,8 @@ function AppRouter(props: Props) { const urlParams = new URLSearchParams(search); const resetScroll = urlParams.get('reset_scroll'); const hasLinkedCommentInUrl = urlParams.get(LINKED_COMMENT_QUERY_PARAM); - - const dynamicRoutes = GetLinksData(homepageData).filter( + const isLargeScreen = useIsLargeScreen(); + const dynamicRoutes = GetLinksData(homepageData, isLargeScreen).filter( (potentialRoute: any) => potentialRoute && potentialRoute.route ); diff --git a/ui/page/home/view.jsx b/ui/page/home/view.jsx index 93646341e..6f8c815df 100644 --- a/ui/page/home/view.jsx +++ b/ui/page/home/view.jsx @@ -1,7 +1,7 @@ // @flow import * as ICONS from 'constants/icons'; import * as PAGES from 'constants/pages'; -import { SITE_NAME, ENABLE_NO_SOURCE_CLAIMS } from 'config'; +import { SITE_NAME } from 'config'; import React from 'react'; import Page from 'component/page'; import Button from 'component/button'; @@ -9,6 +9,7 @@ import ClaimTilesDiscover from 'component/claimTilesDiscover'; import ClaimPreviewTile from 'component/claimPreviewTile'; import Icon from 'component/common/icon'; import WaitUntilOnPage from 'component/common/wait-until-on-page'; +import { useIsLargeScreen } from 'effects/use-screensize'; // have this? import { GetLinksData } from 'util/buildHomepage'; type Props = { @@ -24,9 +25,11 @@ function HomePage(props: Props) { const showPersonalizedChannels = subscribedChannels && subscribedChannels.length > 0; const showPersonalizedTags = followedTags && followedTags.length > 0; const showIndividualTags = showPersonalizedTags && followedTags.length < 5; + const isLargeScreen = useIsLargeScreen(); const rowData: Array = GetLinksData( homepageData, + isLargeScreen, true, authenticated, showPersonalizedChannels, @@ -37,29 +40,40 @@ function HomePage(props: Props) { showNsfw ); + type SectionHeaderProps = { + title: string, + navigate?: string, + icon?: string, + help?: string, + }; + const SectionHeader = ({ title, navigate = '/', icon = '', help }: SectionHeaderProps) => { + return ( +

+ +

+ ); + }; + function getRowElements(title, route, link, icon, help, options, index, pinUrls) { const tilePlaceholder = (
    {new Array(options.pageSize || 8).fill(1).map((x, i) => ( - + ))}
); - const claimTiles = ( - - ); + const claimTiles = ; return (
+ {/* category header */} {index !== 0 && title && typeof title === 'string' && ( -

- -

+ )} {index === 0 && <>{claimTiles}} @@ -69,6 +83,7 @@ function HomePage(props: Props) { )} + {/* view more button */} {(route || link) && (