Add watch later hover action and Favorites
add watch later hover action replace watch later popup item for favorites lint styling for watch_later overlay Add label Use just claim, add requiresAuth Add list icon Tone down text Turn WL Hover Button into component Change WL hover icons small revert Keep watch later in the menu
This commit is contained in:
parent
16ef013025
commit
aced8fb593
11 changed files with 183 additions and 6 deletions
|
@ -38,6 +38,7 @@ const select = (state, props) => {
|
|||
claim,
|
||||
claimIsMine: makeSelectSigningIsMine(props.uri)(state),
|
||||
hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.WATCH_LATER_ID, permanentUri)(state),
|
||||
hasClaimInCustom: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.FAVORITES_ID, permanentUri)(state),
|
||||
channelIsMuted: makeSelectChannelIsMuted(props.uri)(state),
|
||||
channelIsBlocked: makeSelectChannelIsBlocked(props.uri)(state),
|
||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||
|
|
|
@ -40,6 +40,7 @@ type Props = {
|
|||
isRepost: boolean,
|
||||
doCollectionEdit: (string, any) => void,
|
||||
hasClaimInWatchLater: boolean,
|
||||
hasClaimInCustom: boolean,
|
||||
claimInCollection: boolean,
|
||||
collectionName?: string,
|
||||
collectionId: string,
|
||||
|
@ -75,6 +76,7 @@ function ClaimMenuList(props: Props) {
|
|||
doCommentModUnBlockAsAdmin,
|
||||
doCollectionEdit,
|
||||
hasClaimInWatchLater,
|
||||
hasClaimInCustom,
|
||||
collectionId,
|
||||
collectionName,
|
||||
isMyCollection,
|
||||
|
@ -96,6 +98,7 @@ function ClaimMenuList(props: Props) {
|
|||
const isChannel = !incognitoClaim && signingChannel === claim;
|
||||
const showDelete = claimIsMine || (fileInfo && (fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0));
|
||||
const subscriptionLabel = isSubscribed ? __('Unfollow') : __('Follow');
|
||||
const lastCollectionName = 'Favorites';
|
||||
|
||||
const { push, replace } = useHistory();
|
||||
if (!claim) {
|
||||
|
@ -245,6 +248,29 @@ function ClaimMenuList(props: Props) {
|
|||
</div>
|
||||
</MenuItem>
|
||||
)}
|
||||
{/* CUSTOM LIST */}
|
||||
{isPlayable && !collectionId && (
|
||||
<MenuItem
|
||||
className="comment__menu-option"
|
||||
onSelect={() => {
|
||||
doToast({
|
||||
message: __(`Item %action% ${lastCollectionName}`, {
|
||||
action: hasClaimInCustom ? __('removed from') : __('added to'),
|
||||
}),
|
||||
});
|
||||
doCollectionEdit(COLLECTIONS_CONSTS.FAVORITES_ID, {
|
||||
claims: [contentClaim],
|
||||
remove: hasClaimInCustom,
|
||||
type: 'playlist',
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="menu__link">
|
||||
<Icon aria-hidden icon={hasClaimInCustom ? ICONS.DELETE : ICONS.STAR} />
|
||||
{hasClaimInCustom ? __(`In ${lastCollectionName}`) : __(`${lastCollectionName}`)}
|
||||
</div>
|
||||
</MenuItem>
|
||||
)}
|
||||
{/* COLLECTION OPERATIONS */}
|
||||
{collectionId && collectionName && isCollectionClaim && (
|
||||
<>
|
||||
|
|
|
@ -19,6 +19,7 @@ import ClaimPreviewTitle from 'component/claimPreviewTitle';
|
|||
import ClaimPreviewSubtitle from 'component/claimPreviewSubtitle';
|
||||
import ClaimRepostAuthor from 'component/claimRepostAuthor';
|
||||
import FileDownloadLink from 'component/fileDownloadLink';
|
||||
import FileWatchLaterLink from 'component/fileWatchLaterLink';
|
||||
import PublishPending from 'component/publishPending';
|
||||
import ClaimMenuList from 'component/claimMenuList';
|
||||
import ClaimPreviewLoading from './claim-preview-loading';
|
||||
|
@ -157,6 +158,15 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
|||
isValid = false;
|
||||
}
|
||||
}
|
||||
// $FlowFixMe
|
||||
const isPlayable =
|
||||
claim &&
|
||||
// $FlowFixMe
|
||||
claim.value &&
|
||||
// $FlowFixMe
|
||||
claim.value.stream_type &&
|
||||
// $FlowFixMe
|
||||
(claim.value.stream_type === 'audio' || claim.value.stream_type === 'video');
|
||||
const isCollection = claim && claim.value_type === 'collection';
|
||||
const isChannelUri = isValid ? parseURI(uri).isChannel : false;
|
||||
const signingChannel = claim && claim.signing_channel;
|
||||
|
@ -318,6 +328,11 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
|||
<PreviewOverlayProperties uri={uri} small={type === 'small'} properties={liveProperty} />
|
||||
</div>
|
||||
)}
|
||||
{isPlayable && (
|
||||
<div className="claim-preview__hover-actions">
|
||||
<FileWatchLaterLink uri={uri} />
|
||||
</div>
|
||||
)}
|
||||
</FileThumbnail>
|
||||
</NavLink>
|
||||
) : (
|
||||
|
|
|
@ -13,6 +13,7 @@ import { formatLbryUrlForWeb } from 'util/url';
|
|||
import { parseURI, COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||
import PreviewOverlayProperties from 'component/previewOverlayProperties';
|
||||
import FileDownloadLink from 'component/fileDownloadLink';
|
||||
import FileWatchLaterLink from 'component/fileWatchLaterLink';
|
||||
import ClaimRepostAuthor from 'component/claimRepostAuthor';
|
||||
import ClaimMenuList from 'component/claimMenuList';
|
||||
import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
|
||||
|
@ -75,6 +76,15 @@ function ClaimPreviewTile(props: Props) {
|
|||
const isRepost = claim && claim.repost_channel_url;
|
||||
const isCollection = claim && claim.value_type === 'collection';
|
||||
const isStream = claim && claim.value_type === 'stream';
|
||||
// $FlowFixMe
|
||||
const isPlayable =
|
||||
claim &&
|
||||
// $FlowFixMe
|
||||
claim.value &&
|
||||
// $FlowFixMe
|
||||
claim.value.stream_type &&
|
||||
// $FlowFixMe
|
||||
(claim.value.stream_type === 'audio' || claim.value.stream_type === 'video');
|
||||
const collectionClaimId = isCollection && claim && claim.claim_id;
|
||||
const shouldFetch = claim === undefined;
|
||||
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail;
|
||||
|
@ -195,6 +205,12 @@ function ClaimPreviewTile(props: Props) {
|
|||
)}
|
||||
{/* @endif */}
|
||||
|
||||
{isPlayable && (
|
||||
<div className="claim-preview__hover-actions">
|
||||
<FileWatchLaterLink uri={uri} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="claim-preview__file-property-overlay">
|
||||
<PreviewOverlayProperties uri={uri} properties={liveProperty || properties} />
|
||||
</div>
|
||||
|
|
|
@ -6,6 +6,7 @@ import Button from 'component/button';
|
|||
import * as PAGES from 'constants/pages';
|
||||
import Icon from 'component/common/icon';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import { COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||
|
||||
type Props = {
|
||||
collectionUrls: Array<Claim>,
|
||||
|
@ -26,7 +27,10 @@ export default function CollectionContent(props: Props) {
|
|||
className="file-page__recommended"
|
||||
title={
|
||||
<span>
|
||||
<Icon icon={ICONS.STACK} className="icon--margin-right" />
|
||||
<Icon
|
||||
icon={(id === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
|
||||
(id === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || ICONS.STACK}
|
||||
className="icon--margin-right" />
|
||||
{collectionName}
|
||||
</span>
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ function CollectionSelectItem(props: Props) {
|
|||
let icon;
|
||||
switch (category) {
|
||||
case 'builtin':
|
||||
icon = id === COLLECTIONS_CONSTS.WATCH_LATER_ID ? ICONS.TIME : ICONS.STACK;
|
||||
icon = (id === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) || (id === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || ICONS.STACK;
|
||||
break;
|
||||
case 'published':
|
||||
icon = ICONS.STACK;
|
||||
|
|
|
@ -68,7 +68,9 @@ export default function CollectionsListMine(props: Props) {
|
|||
<span className="claim-grid__title-span">
|
||||
{__(`${list.name}`)}
|
||||
<div className="claim-grid__title--empty">
|
||||
<Icon className="icon--margin-right" icon={ICONS.STACK} />
|
||||
<Icon className="icon--margin-right"
|
||||
icon={(list.id === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
|
||||
(list.id === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || ICONS.STACK} />
|
||||
{itemUrls.length}
|
||||
</div>
|
||||
</span>
|
||||
|
|
26
ui/component/fileWatchLaterLink/index.js
Normal file
26
ui/component/fileWatchLaterLink/index.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
COLLECTIONS_CONSTS,
|
||||
makeSelectCollectionForIdHasClaimUrl,
|
||||
doCollectionEdit,
|
||||
} from 'lbry-redux';
|
||||
import FileWatchLaterLink from './view';
|
||||
import { doToast } from 'redux/actions/notifications';
|
||||
|
||||
const select = (state, props) => {
|
||||
const claim = makeSelectClaimForUri(props.uri)(state);
|
||||
const permanentUri = claim && claim.permanent_url;
|
||||
|
||||
return {
|
||||
claim,
|
||||
hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.WATCH_LATER_ID, permanentUri)(state),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
doToast: (props) => dispatch(doToast(props)),
|
||||
doCollectionEdit: (collection, props) => dispatch(doCollectionEdit(collection, props)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(FileWatchLaterLink);
|
62
ui/component/fileWatchLaterLink/view.jsx
Normal file
62
ui/component/fileWatchLaterLink/view.jsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React, { useRef } from 'react';
|
||||
import Button from 'component/button';
|
||||
import useHover from 'effects/use-hover';
|
||||
import { COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
claim: StreamClaim,
|
||||
hasClaimInWatchLater: boolean,
|
||||
doToast: ({ message: string }) => void,
|
||||
doCollectionEdit: (string, any) => void,
|
||||
};
|
||||
|
||||
function FileWatchLaterLink(props: Props) {
|
||||
const {
|
||||
claim,
|
||||
hasClaimInWatchLater,
|
||||
doToast,
|
||||
doCollectionEdit,
|
||||
} = props;
|
||||
const buttonRef = useRef();
|
||||
let isHovering = useHover(buttonRef);
|
||||
|
||||
if (!claim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleWatchLater(e) {
|
||||
e.preventDefault();
|
||||
doToast({
|
||||
message: __('Item %action% Watch Later', {
|
||||
action: hasClaimInWatchLater ? __('removed from') : __('added to'),
|
||||
}),
|
||||
linkText: !hasClaimInWatchLater && __('See All'),
|
||||
linkTarget: !hasClaimInWatchLater && '/list/watchlater',
|
||||
});
|
||||
doCollectionEdit(COLLECTIONS_CONSTS.WATCH_LATER_ID, {
|
||||
claims: [claim],
|
||||
remove: hasClaimInWatchLater,
|
||||
type: 'playlist',
|
||||
});
|
||||
}
|
||||
|
||||
const title = hasClaimInWatchLater ? __('Remove from Watch Later') : __('Add to Watch Later');
|
||||
const label = !hasClaimInWatchLater ? __('Add') : __('Added');
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={buttonRef}
|
||||
requiresAuth={IS_WEB}
|
||||
title={title}
|
||||
label={label}
|
||||
className="button--file-action"
|
||||
icon={(hasClaimInWatchLater && (isHovering ? ICONS.REMOVE : ICONS.COMPLETED)) || (isHovering ? ICONS.COMPLETED : ICONS.TIME)}
|
||||
onClick={(e) => handleWatchLater(e)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default FileWatchLaterLink;
|
|
@ -111,7 +111,10 @@ export default function CollectionPage(props: Props) {
|
|||
<Card
|
||||
title={
|
||||
<span>
|
||||
<Icon icon={ICONS.STACK} className="icon--margin-right" />
|
||||
<Icon
|
||||
icon={(collectionId === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
|
||||
(collectionId === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || ICONS.STACK}
|
||||
className="icon--margin-right" />
|
||||
{claim ? claim.value.title || claim.name : collection && collection.name}
|
||||
</span>
|
||||
}
|
||||
|
|
|
@ -677,9 +677,31 @@
|
|||
|
||||
& > * {
|
||||
color: var(--color-black);
|
||||
background-color: var(--color-white);
|
||||
padding: var(--spacing-xs);
|
||||
background-color: var(--color-black);
|
||||
border-radius: var(--border-radius);
|
||||
padding: var(--spacing-xxs);
|
||||
margin-right: 0;
|
||||
&:hover {
|
||||
background-color: var(--color-button-alt-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.button--file-action {
|
||||
margin: 0 0;
|
||||
padding: var(--spacing-xxs) var(--spacing-xxs);
|
||||
height: unset;
|
||||
|
||||
.button__label {
|
||||
color: var(--color-text);
|
||||
font-size: var(--font-small);
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.button__label {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue