List Page: use swipe layout for mobile (#1069)

* Add swipe layout support for Collection Tiles

* Lists: use swipe layout for mobile

Ticket: 950 "playlists page - right now we show watch later on top, and if you have stuff here, you have to scroll down to other playlists. Show a selector on top? Whatever other improvements we can make here to improve UX."
This commit is contained in:
infinite-persistence 2022-03-11 03:53:49 -08:00 committed by GitHub
parent a3ef81cded
commit 5b2c901496
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 31 deletions

View file

@ -2122,6 +2122,7 @@
"Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8": "Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8",
"Choose %asset%": "Choose %asset%",
"Showing %filtered% results of %total%": "Showing %filtered% results of %total%",
"filtered": "filtered",
"Failed to synchronize settings. Wait a while before retrying.": "Failed to synchronize settings. Wait a while before retrying.",
"You are offline. Check your internet connection.": "You are offline. Check your internet connection.",
"A new version of Odysee is available.": "A new version of Odysee is available.",

View file

@ -152,7 +152,11 @@ function ClaimPreviewTile(props: Props) {
if (placeholder || (!claim && isResolvingUri)) {
return (
<li className={classnames('placeholder claim-preview--tile', {})}>
<li
className={classnames('placeholder claim-preview--tile', {
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
})}
>
<div className="media__thumb">
<img src={PlaceholderTx} alt="Placeholder" />
</div>

View file

@ -33,8 +33,8 @@ function CollectionPreviewOverlay(props: Props) {
collectionItemUrls.map((item, index) => {
if (index < 2) {
return (
<div className="collection-preview__overlay-grid-items">
<FileThumbnail uri={item} key={item} />
<div className="collection-preview__overlay-grid-items" key={item}>
<FileThumbnail uri={item} />
</div>
);
}

View file

@ -25,18 +25,12 @@ type Props = {
thumbnail?: string,
title?: string,
placeholder: boolean,
blackListedOutpoints: Array<{
txid: string,
nout: number,
}>,
filteredOutpoints: Array<{
txid: string,
nout: number,
}>,
swipeLayout?: boolean,
blackListedOutpoints: Array<{ txid: string, nout: number }>,
filteredOutpoints: Array<{ txid: string, nout: number }>,
blockedChannelUris: Array<string>,
isMature?: boolean,
showMature: boolean,
collectionId: string,
deleteCollection: (string) => void,
resolveCollectionItems: (any) => void,
isResolvingCollectionClaims: boolean,
@ -53,6 +47,7 @@ function CollectionPreviewTile(props: Props) {
collectionItemUrls,
claim,
resolveCollectionItems,
swipeLayout = false,
} = props;
const { push } = useHistory();
@ -120,7 +115,11 @@ function CollectionPreviewTile(props: Props) {
if (isResolvingUri || isResolvingCollectionClaims) {
return (
<li className={classnames('claim-preview--tile', {})}>
<li
className={classnames('claim-preview--tile', {
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
})}
>
<div className="placeholder media__thumb" />
<div className="placeholder__wrapper">
<div className="placeholder claim-tile__title" />
@ -129,12 +128,19 @@ function CollectionPreviewTile(props: Props) {
</li>
);
}
if (uri) {
return <ClaimPreviewTile uri={uri} />;
return <ClaimPreviewTile swipeLayout={swipeLayout} uri={uri} />;
}
return (
<li role="link" onClick={handleClick} className={'card claim-preview--tile'}>
<li
role="link"
onClick={handleClick}
className={classnames('card claim-preview--tile', {
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
})}
>
<NavLink {...navLinkProps}>
<FileThumbnail uri={collectionItemUrls && collectionItemUrls.length && collectionItemUrls[0]}>
<React.Fragment>

View file

@ -8,10 +8,10 @@ import Icon from 'component/common/icon';
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import * as KEYCODES from 'constants/keycodes';
import Yrbl from 'component/yrbl';
import classnames from 'classnames';
import { FormField, Form } from 'component/common/form';
import { useIsMobile } from 'effects/use-screensize';
type Props = {
builtinCollections: CollectionGroup,
@ -21,10 +21,8 @@ type Props = {
fetchingCollections: boolean,
};
const ALL = 'All';
const PRIVATE = 'Private';
const PUBLIC = 'Public';
const COLLECTION_FILTERS = [ALL, PRIVATE, PUBLIC];
const LIST_TYPE = Object.freeze({ ALL: 'All', PRIVATE: 'Private', PUBLIC: 'Public' });
const COLLECTION_FILTERS = [LIST_TYPE.ALL, LIST_TYPE.PRIVATE, LIST_TYPE.PUBLIC];
const COLLECTION_SHOW_COUNT = 12;
export default function CollectionsListMine(props: Props) {
@ -40,16 +38,17 @@ export default function CollectionsListMine(props: Props) {
const unpublishedCollectionsList = (Object.keys(unpublishedCollections || {}): any);
const publishedList = (Object.keys(publishedCollections || {}): any);
const hasCollections = unpublishedCollectionsList.length || publishedList.length;
const [filterType, setFilterType] = React.useState(ALL);
const [filterType, setFilterType] = React.useState(LIST_TYPE.ALL);
const [searchText, setSearchText] = React.useState('');
const isMobileScreen = useIsMobile();
const playlistPageUrl = `/$/${PAGES.PLAYLISTS}?type=${filterType}`;
let collectionsToShow = [];
if (filterType === ALL) {
if (filterType === LIST_TYPE.ALL) {
collectionsToShow = unpublishedCollectionsList.concat(publishedList);
} else if (filterType === PRIVATE) {
} else if (filterType === LIST_TYPE.PRIVATE) {
collectionsToShow = unpublishedCollectionsList;
} else if (filterType === PUBLIC) {
} else if (filterType === LIST_TYPE.PUBLIC) {
collectionsToShow = publishedList;
}
@ -92,6 +91,7 @@ export default function CollectionsListMine(props: Props) {
}
return (
<>
{/* Built-in lists */}
{builtin.map((list: Collection) => {
const { items: itemUrls } = list;
return (
@ -122,7 +122,13 @@ export default function CollectionsListMine(props: Props) {
}
/>
</h1>
<ClaimList tileLayout key={list.name} uris={itemUrls.slice(0, 6)} collectionId={list.id} />
<ClaimList
swipeLayout={isMobileScreen}
tileLayout
key={list.name}
uris={itemUrls.slice(0, 6)}
collectionId={list.id}
/>
</>
)}
{!(itemUrls && itemUrls.length) && (
@ -135,6 +141,8 @@ export default function CollectionsListMine(props: Props) {
</div>
);
})}
{/* Playlists: header */}
<div className="claim-grid__wrapper">
<div className="claim-grid__header section">
<h1 className="claim-grid__title">
@ -159,6 +167,8 @@ export default function CollectionsListMine(props: Props) {
)}
</h1>
</div>
{/* Playlists: search */}
<div className="section__header-action-stack">
<div className="section__header--actions">
<div className="claim-search__wrapper">
@ -179,6 +189,7 @@ export default function CollectionsListMine(props: Props) {
<Form onSubmit={() => {}} className="wunderbar--inline">
<Icon icon={ICONS.SEARCH} />
<FormField
name="collection_search"
onFocus={onTextareaFocus}
onBlur={onTextareaBlur}
className="wunderbar__input--inline"
@ -192,10 +203,7 @@ export default function CollectionsListMine(props: Props) {
<p className="collection-grid__results-summary">
{isTruncated && (
<>
{__(`Showing %filtered% results of %total%`, {
filtered: filteredLength,
total: totalLength,
})}
{__('Showing %filtered% results of %total%', { filtered: filteredLength, total: totalLength })}
{`${searchText ? ' (' + __('filtered') + ') ' : ' '}`}
</>
)}
@ -206,12 +214,20 @@ export default function CollectionsListMine(props: Props) {
/>
</p>
</div>
{/* Playlists: tiles */}
{Boolean(hasCollections) && (
<div>
<div className="claim-grid">
<div
className={classnames('claim-grid', {
'swipe-list': isMobileScreen,
})}
>
{filteredCollections &&
filteredCollections.length > 0 &&
filteredCollections.map((key) => <CollectionPreviewTile tileLayout collectionId={key} key={key} />)}
filteredCollections.map((key) => (
<CollectionPreviewTile swipeLayout={isMobileScreen} tileLayout collectionId={key} key={key} />
))}
{!filteredCollections.length && <div className="empty main--empty">{__('No matching playlists')}</div>}
</div>
</div>