Playlistorder (#7442)
* 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 * [Playlist] Pull in sorting changes from desktop + Add Drag-n-Drop + Handle unavailable/deleted claims (#641) * Add ordering Icons * Refactor doCollectionEdit - It required claims as parameter, when only uris are used to populate the collection, so that was changed to pass down the uris instead. - There were unused and mostly unnecessary functions inside, for example the parameter claimIds was never used so it would never enter the claimSearch function which again would be used to generate uris, so it's better to just use uris as parameter * Add List Reordering changes * Add toggle button for list editing * Add toggle on content page collection sidebar * Enable drag-n-drop to re-order list items https://www.youtube.com/watch?v=aYZRRyukuIw * Allow removing all unavailable claims from a List * Fix <g> on icons * Fix section buttons positioning * Move preventDefault and stopPropagation to buttons div instead of each button, preventing clicking even if disabled opening the claim * Change dragging cursor * Fix sizing * Fix dragging component * Restrict dragging to vertical axis * Ignore shuffle state for ordering * Fix console errors * Mobile fixes * Fix sidebar spacing * Fix grey on mobile after click * cleanup Co-authored-by: Dan Peterson <dan@dan-peterson.ca> Co-authored-by: saltrafael <76502841+saltrafael@users.noreply.github.com>
This commit is contained in:
parent
618ab5e195
commit
5fdac4898f
40 changed files with 1114 additions and 544 deletions
|
@ -2,7 +2,8 @@
|
||||||
.*\.typeface\.json
|
.*\.typeface\.json
|
||||||
.*/node_modules/findup/.*
|
.*/node_modules/findup/.*
|
||||||
.*/node_modules/react-plastic/.*
|
.*/node_modules/react-plastic/.*
|
||||||
|
.*/node_modules/raf-schd/.*
|
||||||
|
.*/node_modules/react-beautiful-dnd/.*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
|
|
||||||
|
|
3
flow-typed/Collections.js
vendored
3
flow-typed/Collections.js
vendored
|
@ -24,9 +24,8 @@ declare type CollectionGroup = {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare type CollectionEditParams = {
|
declare type CollectionEditParams = {
|
||||||
claims?: Array<Claim>,
|
uris?: Array<string>,
|
||||||
remove?: boolean,
|
remove?: boolean,
|
||||||
claimIds?: Array<string>,
|
|
||||||
replace?: boolean,
|
replace?: boolean,
|
||||||
order?: { from: number, to: number },
|
order?: { from: number, to: number },
|
||||||
type?: string,
|
type?: string,
|
||||||
|
|
|
@ -62,7 +62,8 @@
|
||||||
"parse-duration": "^1.0.0",
|
"parse-duration": "^1.0.0",
|
||||||
"proxy-polyfill": "0.1.6",
|
"proxy-polyfill": "0.1.6",
|
||||||
"re-reselect": "^4.0.0",
|
"re-reselect": "^4.0.0",
|
||||||
"react-datetime-picker": "^3.2.1",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
|
"react-datetime-picker": "^3.4.3",
|
||||||
"remove-markdown": "^0.3.0",
|
"remove-markdown": "^0.3.0",
|
||||||
"rss": "^1.2.2",
|
"rss": "^1.2.2",
|
||||||
"source-map-explorer": "^2.5.2",
|
"source-map-explorer": "^2.5.2",
|
||||||
|
|
|
@ -2249,5 +2249,11 @@
|
||||||
"Amount of $%input_amount% LBC in USB is lower than price of $%price_amount%": "Amount of $%input_amount% LBC in USB is lower than price of $%price_amount%",
|
"Amount of $%input_amount% LBC in USB is lower than price of $%price_amount%": "Amount of $%input_amount% LBC in USB is lower than price of $%price_amount%",
|
||||||
"Hosting for content you have downloaded": "Hosting for content you have downloaded",
|
"Hosting for content you have downloaded": "Hosting for content you have downloaded",
|
||||||
"Hosting content selected by the network": "Hosting content selected by the network",
|
"Hosting content selected by the network": "Hosting content selected by the network",
|
||||||
|
"Remove all unavailable claims": "Remove all unavailable claims",
|
||||||
|
"Drag": "Drag",
|
||||||
|
"Move Top": "Move Top",
|
||||||
|
"Move Bottom": "Move Bottom",
|
||||||
|
"Move Up": "Move Up",
|
||||||
|
"Move Down": "Move Down",
|
||||||
"--end--": "--end--"
|
"--end--": "--end--"
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,15 +79,7 @@ const ClaimCollectionAdd = (props: Props) => {
|
||||||
.filter((list) => (isChannel ? list.type === 'collection' : list.type === 'playlist'))
|
.filter((list) => (isChannel ? list.type === 'collection' : list.type === 'playlist'))
|
||||||
.map((l) => {
|
.map((l) => {
|
||||||
const { id } = l;
|
const { id } = l;
|
||||||
return (
|
return <CollectionSelectItem collectionId={id} uri={permanentUrl} key={id} category={'builtin'} />;
|
||||||
<CollectionSelectItem
|
|
||||||
claim={claim}
|
|
||||||
collectionId={id}
|
|
||||||
uri={permanentUrl}
|
|
||||||
key={id}
|
|
||||||
category={'builtin'}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
{unpublished &&
|
{unpublished &&
|
||||||
(Object.values(unpublished): any)
|
(Object.values(unpublished): any)
|
||||||
|
@ -96,13 +88,7 @@ const ClaimCollectionAdd = (props: Props) => {
|
||||||
.map((l) => {
|
.map((l) => {
|
||||||
const { id } = l;
|
const { id } = l;
|
||||||
return (
|
return (
|
||||||
<CollectionSelectItem
|
<CollectionSelectItem collectionId={id} uri={permanentUrl} key={id} category={'unpublished'} />
|
||||||
claim={claim}
|
|
||||||
collectionId={id}
|
|
||||||
uri={permanentUrl}
|
|
||||||
key={id}
|
|
||||||
category={'unpublished'}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{published &&
|
{published &&
|
||||||
|
@ -110,13 +96,7 @@ const ClaimCollectionAdd = (props: Props) => {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
const { id } = l;
|
const { id } = l;
|
||||||
return (
|
return (
|
||||||
<CollectionSelectItem
|
<CollectionSelectItem collectionId={id} uri={permanentUrl} key={id} category={'published'} />
|
||||||
claim={claim}
|
|
||||||
collectionId={id}
|
|
||||||
uri={permanentUrl}
|
|
||||||
key={id}
|
|
||||||
category={'published'}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
import { MAIN_CLASS } from 'constants/classnames';
|
import { MAIN_CLASS } from 'constants/classnames';
|
||||||
import type { Node } from 'react';
|
import type { Node } from 'react';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
@ -44,7 +47,13 @@ type Props = {
|
||||||
collectionId?: string,
|
collectionId?: string,
|
||||||
showNoSourceClaims?: boolean,
|
showNoSourceClaims?: boolean,
|
||||||
onClick?: (e: any, claim?: ?Claim, index?: number) => void,
|
onClick?: (e: any, claim?: ?Claim, index?: number) => void,
|
||||||
noEmpty: boolean,
|
maxClaimRender?: number,
|
||||||
|
excludeUris?: Array<string>,
|
||||||
|
loadedCallback?: (number) => void,
|
||||||
|
swipeLayout: boolean,
|
||||||
|
showEdit?: boolean,
|
||||||
|
droppableProvided?: any,
|
||||||
|
unavailableUris?: Array<string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ClaimList(props: Props) {
|
export default function ClaimList(props: Props) {
|
||||||
|
@ -75,7 +84,13 @@ export default function ClaimList(props: Props) {
|
||||||
collectionId,
|
collectionId,
|
||||||
showNoSourceClaims,
|
showNoSourceClaims,
|
||||||
onClick,
|
onClick,
|
||||||
noEmpty,
|
maxClaimRender,
|
||||||
|
excludeUris = [],
|
||||||
|
loadedCallback,
|
||||||
|
swipeLayout = false,
|
||||||
|
showEdit,
|
||||||
|
droppableProvided,
|
||||||
|
unavailableUris,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
|
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
|
||||||
|
@ -85,8 +100,18 @@ export default function ClaimList(props: Props) {
|
||||||
const timedOut = uris === null;
|
const timedOut = uris === null;
|
||||||
const urisLength = (uris && uris.length) || 0;
|
const urisLength = (uris && uris.length) || 0;
|
||||||
|
|
||||||
const tileUris = (prefixUris || []).concat(uris);
|
let tileUris = (prefixUris || []).concat(uris || []);
|
||||||
const sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? tileUris : tileUris.slice().reverse())) || [];
|
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
|
const noResultMsg = searchInLanguage
|
||||||
? __('No results. Contents may be hidden by the Language filter.')
|
? __('No results. Contents may be hidden by the Language filter.')
|
||||||
|
@ -96,11 +121,21 @@ export default function ClaimList(props: Props) {
|
||||||
setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW);
|
setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClaimClicked(e, claim, index) {
|
const handleClaimClicked = React.useCallback(
|
||||||
|
(e, claim, index) => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
onClick(e, claim, index);
|
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(() => {
|
useEffect(() => {
|
||||||
const handleScroll = debounce((e) => {
|
const handleScroll = debounce((e) => {
|
||||||
|
@ -123,8 +158,32 @@ export default function ClaimList(props: Props) {
|
||||||
}
|
}
|
||||||
}, [loading, onScrollBottom, urisLength, pageSize, page]);
|
}, [loading, onScrollBottom, urisLength, pageSize, page]);
|
||||||
|
|
||||||
|
const getClaimPreview = (uri: string, index: number, draggableProvided?: any) => (
|
||||||
|
<ClaimPreview
|
||||||
|
uri={uri}
|
||||||
|
indexInContainer={index}
|
||||||
|
type={type}
|
||||||
|
active={activeUri && uri === activeUri}
|
||||||
|
hideMenu={hideMenu}
|
||||||
|
includeSupportAction={includeSupportAction}
|
||||||
|
showUnresolvedClaim={showUnresolvedClaims}
|
||||||
|
properties={renderProperties || (type !== 'small' ? undefined : false)}
|
||||||
|
renderActions={renderActions}
|
||||||
|
showUserBlocked={showHiddenByUser}
|
||||||
|
showHiddenByUser={showHiddenByUser}
|
||||||
|
collectionId={collectionId}
|
||||||
|
showNoSourceClaims={showNoSourceClaims}
|
||||||
|
customShouldHide={customShouldHide}
|
||||||
|
onClick={handleClaimClicked}
|
||||||
|
swipeLayout={swipeLayout}
|
||||||
|
showEdit={showEdit}
|
||||||
|
dragHandleProps={draggableProvided && draggableProvided.dragHandleProps}
|
||||||
|
unavailableUris={unavailableUris}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return tileLayout && !header ? (
|
return tileLayout && !header ? (
|
||||||
<section className="claim-grid">
|
<section className={classnames('claim-grid', { 'swipe-list': swipeLayout })}>
|
||||||
{urisLength > 0 &&
|
{urisLength > 0 &&
|
||||||
tileUris.map((uri) => (
|
tileUris.map((uri) => (
|
||||||
<ClaimPreviewTile
|
<ClaimPreviewTile
|
||||||
|
@ -134,11 +193,10 @@ export default function ClaimList(props: Props) {
|
||||||
properties={renderProperties}
|
properties={renderProperties}
|
||||||
collectionId={collectionId}
|
collectionId={collectionId}
|
||||||
showNoSourceClaims={showNoSourceClaims}
|
showNoSourceClaims={showNoSourceClaims}
|
||||||
|
swipeLayout={swipeLayout}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{!timedOut && urisLength === 0 && !loading && !noEmpty && (
|
{!timedOut && urisLength === 0 && !loading && <div className="empty main--empty">{empty || noResultMsg}</div>}
|
||||||
<div className="empty main--empty">{empty || noResultMsg}</div>
|
|
||||||
)}
|
|
||||||
{timedOut && timedOutMessage && <div className="empty main--empty">{timedOutMessage}</div>}
|
{timedOut && timedOutMessage && <div className="empty main--empty">{timedOutMessage}</div>}
|
||||||
</section>
|
</section>
|
||||||
) : (
|
) : (
|
||||||
|
@ -178,43 +236,52 @@ export default function ClaimList(props: Props) {
|
||||||
{urisLength > 0 && (
|
{urisLength > 0 && (
|
||||||
<ul
|
<ul
|
||||||
className={classnames('ul--no-style', {
|
className={classnames('ul--no-style', {
|
||||||
card: !(tileLayout || type === 'small'),
|
card: !(tileLayout || swipeLayout || type === 'small'),
|
||||||
'claim-list--card-body': tileLayout,
|
'claim-list--card-body': tileLayout,
|
||||||
|
'swipe-list': swipeLayout,
|
||||||
})}
|
})}
|
||||||
|
{...(droppableProvided && droppableProvided.droppableProps)}
|
||||||
|
ref={droppableProvided && droppableProvided.innerRef}
|
||||||
>
|
>
|
||||||
{sortedUris.map((uri, index) => (
|
{injectedItem && sortedUris.some((uri, index) => index === 4) && <li>{injectedItem}</li>}
|
||||||
<React.Fragment key={uri}>
|
|
||||||
{injectedItem && index === 4 && <li>{injectedItem}</li>}
|
{sortedUris.map((uri, index) =>
|
||||||
<ClaimPreview
|
droppableProvided ? (
|
||||||
uri={uri}
|
<Draggable key={uri} draggableId={uri} index={index}>
|
||||||
indexInContainer={index}
|
{(draggableProvided, draggableSnapshot) => {
|
||||||
type={type}
|
// Restrict dragging to vertical axis
|
||||||
active={activeUri && uri === activeUri}
|
// https://github.com/atlassian/react-beautiful-dnd/issues/958#issuecomment-980548919
|
||||||
hideMenu={hideMenu}
|
let transform = draggableProvided.draggableProps.style.transform;
|
||||||
includeSupportAction={includeSupportAction}
|
|
||||||
showUnresolvedClaim={showUnresolvedClaims}
|
if (draggableSnapshot.isDragging && transform) {
|
||||||
properties={renderProperties || (type !== 'small' ? undefined : false)}
|
transform = transform.replace(/\(.+,/, '(0,');
|
||||||
renderActions={renderActions}
|
}
|
||||||
showUserBlocked={showHiddenByUser}
|
|
||||||
showHiddenByUser={showHiddenByUser}
|
const style = {
|
||||||
collectionId={collectionId}
|
...draggableProvided.draggableProps.style,
|
||||||
showNoSourceClaims={showNoSourceClaims}
|
transform,
|
||||||
customShouldHide={(claim: StreamClaim) => {
|
};
|
||||||
// Hack to hide spee.ch thumbnail publishes
|
|
||||||
// If it meets these requirements, it was probably uploaded here:
|
return (
|
||||||
// https://github.com/lbryio/lbry-redux/blob/master/src/redux/actions/publish.js#L74-L79
|
<li ref={draggableProvided.innerRef} {...draggableProvided.draggableProps} style={style}>
|
||||||
return claim.name.length === 24 && !claim.name.includes(' ') && claim.value.author === 'Spee.ch';
|
{/* https://github.com/atlassian/react-beautiful-dnd/issues/1756 */}
|
||||||
|
<div style={{ display: 'none' }} {...draggableProvided.dragHandleProps} />
|
||||||
|
|
||||||
|
{getClaimPreview(uri, index, draggableProvided)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
onClick={(e, claim, index) => handleClaimClicked(e, claim, index)}
|
</Draggable>
|
||||||
/>
|
) : (
|
||||||
</React.Fragment>
|
getClaimPreview(uri, index)
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
|
{droppableProvided && droppableProvided.placeholder}
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!timedOut && urisLength === 0 && !loading && !noEmpty && (
|
{!timedOut && urisLength === 0 && !loading && <div className="empty empty--centered">{empty || noResultMsg}</div>}
|
||||||
<div className="empty empty--centered">{empty || noResultMsg}</div>
|
|
||||||
)}
|
|
||||||
{!loading && timedOut && timedOutMessage && <div className="empty empty--centered">{timedOutMessage}</div>}
|
{!loading && timedOut && timedOutMessage && <div className="empty empty--centered">{timedOutMessage}</div>}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -94,6 +94,13 @@ type Props = {
|
||||||
doClaimSearch: ({}) => void,
|
doClaimSearch: ({}) => void,
|
||||||
doToggleTagFollowDesktop: (string) => void,
|
doToggleTagFollowDesktop: (string) => void,
|
||||||
doFetchViewCount: (claimIdCsv: string) => void,
|
doFetchViewCount: (claimIdCsv: string) => void,
|
||||||
|
|
||||||
|
loadedCallback?: (number) => void,
|
||||||
|
maxClaimRender?: number,
|
||||||
|
useSkeletonScreen?: boolean,
|
||||||
|
excludeUris?: Array<string>,
|
||||||
|
|
||||||
|
swipeLayout: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ClaimListDiscover(props: Props) {
|
function ClaimListDiscover(props: Props) {
|
||||||
|
@ -157,6 +164,11 @@ function ClaimListDiscover(props: Props) {
|
||||||
empty,
|
empty,
|
||||||
claimsByUri,
|
claimsByUri,
|
||||||
doFetchViewCount,
|
doFetchViewCount,
|
||||||
|
loadedCallback,
|
||||||
|
maxClaimRender,
|
||||||
|
useSkeletonScreen = true,
|
||||||
|
excludeUris = [],
|
||||||
|
swipeLayout = false,
|
||||||
} = props;
|
} = props;
|
||||||
const didNavigateForward = history.action === 'PUSH';
|
const didNavigateForward = history.action === 'PUSH';
|
||||||
const { search } = location;
|
const { search } = location;
|
||||||
|
@ -493,6 +505,21 @@ function ClaimListDiscover(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveOrderByOption(orderBy: string | Array<string>, sortBy: string | Array<string>) {
|
function resolveOrderByOption(orderBy: string | Array<string>, sortBy: string | Array<string>) {
|
||||||
|
// 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 =
|
const order_by =
|
||||||
orderBy === CS.ORDER_BY_TRENDING
|
orderBy === CS.ORDER_BY_TRENDING
|
||||||
? CS.ORDER_BY_TRENDING_VALUE
|
? CS.ORDER_BY_TRENDING_VALUE
|
||||||
|
@ -569,8 +596,12 @@ function ClaimListDiscover(props: Props) {
|
||||||
searchOptions={options}
|
searchOptions={options}
|
||||||
showNoSourceClaims={showNoSourceClaims}
|
showNoSourceClaims={showNoSourceClaims}
|
||||||
empty={empty}
|
empty={empty}
|
||||||
|
maxClaimRender={maxClaimRender}
|
||||||
|
excludeUris={excludeUris}
|
||||||
|
loadedCallback={loadedCallback}
|
||||||
|
swipeLayout={swipeLayout}
|
||||||
/>
|
/>
|
||||||
{loading && (
|
{loading && useSkeletonScreen && (
|
||||||
<div className="claim-grid">
|
<div className="claim-grid">
|
||||||
{new Array(dynamicPageSize).fill(1).map((x, i) => (
|
{new Array(dynamicPageSize).fill(1).map((x, i) => (
|
||||||
<ClaimPreviewTile key={i} placeholder="loading" />
|
<ClaimPreviewTile key={i} placeholder="loading" />
|
||||||
|
@ -602,8 +633,13 @@ function ClaimListDiscover(props: Props) {
|
||||||
searchOptions={options}
|
searchOptions={options}
|
||||||
showNoSourceClaims={hasNoSource || showNoSourceClaims}
|
showNoSourceClaims={hasNoSource || showNoSourceClaims}
|
||||||
empty={empty}
|
empty={empty}
|
||||||
|
maxClaimRender={maxClaimRender}
|
||||||
|
excludeUris={excludeUris}
|
||||||
|
loadedCallback={loadedCallback}
|
||||||
|
swipeLayout={swipeLayout}
|
||||||
/>
|
/>
|
||||||
{loading &&
|
{loading &&
|
||||||
|
useSkeletonScreen &&
|
||||||
new Array(dynamicPageSize)
|
new Array(dynamicPageSize)
|
||||||
.fill(1)
|
.fill(1)
|
||||||
.map((x, i) => (
|
.map((x, i) => (
|
||||||
|
|
|
@ -157,11 +157,9 @@ function ClaimMenuList(props: Props) {
|
||||||
doToast({
|
doToast({
|
||||||
message: source ? __('Item removed from %name%', { name }) : __('Item added to %name%', { name }),
|
message: source ? __('Item removed from %name%', { name }) : __('Item added to %name%', { name }),
|
||||||
});
|
});
|
||||||
doCollectionEdit(collectionId, {
|
if (contentClaim) {
|
||||||
claims: [contentClaim],
|
doCollectionEdit(collectionId, { uris: [contentClaim.permanent_url], remove: source, type: 'playlist' });
|
||||||
remove: source,
|
}
|
||||||
type: 'playlist',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFollow() {
|
function handleFollow() {
|
||||||
|
|
|
@ -10,17 +10,12 @@ import {
|
||||||
selectDateForUri,
|
selectDateForUri,
|
||||||
} from 'redux/selectors/claims';
|
} from 'redux/selectors/claims';
|
||||||
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
|
import { makeSelectStreamingUrlForUri } from 'redux/selectors/file_info';
|
||||||
import {
|
import { makeSelectCollectionIsMine } from 'redux/selectors/collections';
|
||||||
makeSelectCollectionIsMine,
|
|
||||||
makeSelectUrlsForCollectionId,
|
|
||||||
makeSelectIndexForUrlInCollection,
|
|
||||||
} from 'redux/selectors/collections';
|
|
||||||
|
|
||||||
import { doResolveUri } from 'redux/actions/claims';
|
import { doResolveUri } from 'redux/actions/claims';
|
||||||
import { doCollectionEdit } from 'redux/actions/collections';
|
|
||||||
import { doFileGet } from 'redux/actions/file';
|
import { doFileGet } from 'redux/actions/file';
|
||||||
import { selectBanStateForUri } from 'lbryinc';
|
import { selectBanStateForUri } from 'lbryinc';
|
||||||
import { selectShowMatureContent } from 'redux/selectors/settings';
|
import { selectLanguage, selectShowMatureContent } from 'redux/selectors/settings';
|
||||||
import { makeSelectHasVisitedUri } from 'redux/selectors/content';
|
import { makeSelectHasVisitedUri } from 'redux/selectors/content';
|
||||||
import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions';
|
import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions';
|
||||||
import { isClaimNsfw } from 'util/claim';
|
import { isClaimNsfw } from 'util/claim';
|
||||||
|
@ -50,15 +45,13 @@ const select = (state, props) => {
|
||||||
streamingUrl: props.uri && makeSelectStreamingUrlForUri(props.uri)(state),
|
streamingUrl: props.uri && makeSelectStreamingUrlForUri(props.uri)(state),
|
||||||
wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state),
|
wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state),
|
||||||
isCollectionMine: makeSelectCollectionIsMine(props.collectionId)(state),
|
isCollectionMine: makeSelectCollectionIsMine(props.collectionId)(state),
|
||||||
collectionUris: makeSelectUrlsForCollectionId(props.collectionId)(state),
|
lang: selectLanguage(state),
|
||||||
collectionIndex: makeSelectIndexForUrlInCollection(props.uri, props.collectionId)(state),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
resolveUri: (uri) => dispatch(doResolveUri(uri)),
|
resolveUri: (uri) => dispatch(doResolveUri(uri)),
|
||||||
getFile: (uri) => dispatch(doFileGet(uri, false)),
|
getFile: (uri) => dispatch(doFileGet(uri, false)),
|
||||||
editCollection: (id, params) => dispatch(doCollectionEdit(id, params)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ClaimPreview);
|
export default connect(select, perform)(ClaimPreview);
|
||||||
|
|
|
@ -6,10 +6,14 @@ import { isEmpty } from 'util/object';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { isURIValid } from 'util/lbryURI';
|
import { isURIValid } from 'util/lbryURI';
|
||||||
import * as COLLECTIONS_CONSTS from 'constants/collections';
|
import * as COLLECTIONS_CONSTS from 'constants/collections';
|
||||||
|
import { isChannelClaim } from 'util/claim';
|
||||||
import { formatLbryUrlForWeb } from 'util/url';
|
import { formatLbryUrlForWeb } from 'util/url';
|
||||||
import { formatClaimPreviewTitle } from 'util/formatAriaLabel';
|
import { formatClaimPreviewTitle } from 'util/formatAriaLabel';
|
||||||
|
import { toCompactNotation } from 'util/string';
|
||||||
|
import Tooltip from 'component/common/tooltip';
|
||||||
import FileThumbnail from 'component/fileThumbnail';
|
import FileThumbnail from 'component/fileThumbnail';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
|
import PreviewOverlayProperties from 'component/previewOverlayProperties';
|
||||||
import ClaimTags from 'component/claimTags';
|
import ClaimTags from 'component/claimTags';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
import ChannelThumbnail from 'component/channelThumbnail';
|
import ChannelThumbnail from 'component/channelThumbnail';
|
||||||
|
@ -25,10 +29,8 @@ import ClaimMenuList from 'component/claimMenuList';
|
||||||
import ClaimPreviewLoading from './claim-preview-loading';
|
import ClaimPreviewLoading from './claim-preview-loading';
|
||||||
import ClaimPreviewHidden from './claim-preview-no-mature';
|
import ClaimPreviewHidden from './claim-preview-no-mature';
|
||||||
import ClaimPreviewNoContent from './claim-preview-no-content';
|
import ClaimPreviewNoContent from './claim-preview-no-content';
|
||||||
import CollectionEditButtons from './collection-buttons';
|
import CollectionEditButtons from 'component/collectionEditButtons';
|
||||||
|
|
||||||
import AbandonedChannelPreview from 'component/abandonedChannelPreview';
|
import AbandonedChannelPreview from 'component/abandonedChannelPreview';
|
||||||
import PreviewOverlayProperties from 'component/previewOverlayProperties';
|
|
||||||
|
|
||||||
// preview images used on the landing page and on the channel page
|
// preview images used on the landing page and on the channel page
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -49,7 +51,7 @@ type Props = {
|
||||||
type: string,
|
type: string,
|
||||||
banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean },
|
banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean },
|
||||||
hasVisitedUri: boolean,
|
hasVisitedUri: boolean,
|
||||||
channelIsBlocked: boolean,
|
blockedUris: Array<string>,
|
||||||
actions: boolean | Node | string | number,
|
actions: boolean | Node | string | number,
|
||||||
properties: boolean | Node | string | number | ((Claim) => Node),
|
properties: boolean | Node | string | number | ((Claim) => Node),
|
||||||
empty?: Node,
|
empty?: Node,
|
||||||
|
@ -68,15 +70,17 @@ type Props = {
|
||||||
repostUrl?: string,
|
repostUrl?: string,
|
||||||
hideMenu?: boolean,
|
hideMenu?: boolean,
|
||||||
collectionId?: string,
|
collectionId?: string,
|
||||||
editCollection: (string, CollectionEditParams) => void,
|
|
||||||
isCollectionMine: boolean,
|
isCollectionMine: boolean,
|
||||||
collectionUris: Array<Collection>,
|
|
||||||
collectionIndex?: number,
|
|
||||||
disableNavigation?: boolean,
|
disableNavigation?: boolean,
|
||||||
mediaDuration?: string,
|
mediaDuration?: string,
|
||||||
date?: any,
|
date?: any,
|
||||||
indexInContainer?: number, // The index order of this component within 'containerId'.
|
indexInContainer?: number, // The index order of this component within 'containerId'.
|
||||||
channelSubCount?: number,
|
channelSubCount?: number,
|
||||||
|
swipeLayout: boolean,
|
||||||
|
lang: string,
|
||||||
|
showEdit?: boolean,
|
||||||
|
dragHandleProps?: any,
|
||||||
|
unavailableUris?: Array<string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
|
@ -97,7 +101,6 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
streamingUrl,
|
streamingUrl,
|
||||||
mediaDuration,
|
mediaDuration,
|
||||||
// user properties
|
// user properties
|
||||||
channelIsBlocked,
|
|
||||||
hasVisitedUri,
|
hasVisitedUri,
|
||||||
// component
|
// component
|
||||||
history,
|
history,
|
||||||
|
@ -129,34 +132,40 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
hideMenu = false,
|
hideMenu = false,
|
||||||
// repostUrl,
|
// repostUrl,
|
||||||
collectionId,
|
collectionId,
|
||||||
collectionIndex,
|
|
||||||
editCollection,
|
|
||||||
isCollectionMine,
|
isCollectionMine,
|
||||||
collectionUris,
|
|
||||||
disableNavigation,
|
disableNavigation,
|
||||||
indexInContainer,
|
indexInContainer,
|
||||||
channelSubCount,
|
channelSubCount,
|
||||||
|
swipeLayout = false,
|
||||||
|
lang,
|
||||||
|
showEdit,
|
||||||
|
dragHandleProps,
|
||||||
|
unavailableUris,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const isCollection = claim && claim.value_type === 'collection';
|
const isCollection = claim && claim.value_type === 'collection';
|
||||||
const collectionClaimId = isCollection && claim && claim.claim_id;
|
const collectionClaimId = isCollection && claim && claim.claim_id;
|
||||||
const listId = collectionId || collectionClaimId || null;
|
const listId = collectionId || collectionClaimId;
|
||||||
const WrapperElement = wrapperElement || 'li';
|
const WrapperElement = wrapperElement || 'li';
|
||||||
const shouldFetch =
|
const shouldFetch =
|
||||||
claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending);
|
claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending);
|
||||||
const abandoned = !isResolvingUri && !claim;
|
const abandoned = !isResolvingUri && !claim;
|
||||||
const isMyCollection = listId && (isCollectionMine || listId.includes('-'));
|
const isMyCollection = listId && (isCollectionMine || listId.includes('-'));
|
||||||
|
if (isMyCollection && claim === null && unavailableUris) unavailableUris.push(uri);
|
||||||
|
|
||||||
const shouldHideActions = hideActions || isMyCollection || type === 'small' || type === 'tooltip';
|
const shouldHideActions = hideActions || isMyCollection || type === 'small' || type === 'tooltip';
|
||||||
const canonicalUrl = claim && claim.canonical_url;
|
const canonicalUrl = claim && claim.canonical_url;
|
||||||
const lastCollectionIndex = collectionUris ? collectionUris.length - 1 : 0;
|
|
||||||
const channelSubscribers = React.useMemo(() => {
|
const channelSubscribers = React.useMemo(() => {
|
||||||
if (channelSubCount === undefined) {
|
if (channelSubCount === undefined) {
|
||||||
return <span />;
|
return <span />;
|
||||||
}
|
}
|
||||||
const formattedSubCount = Number(channelSubCount).toLocaleString();
|
const formattedSubCount = toCompactNotation(channelSubCount, lang, 10000);
|
||||||
return (
|
return (
|
||||||
|
<Tooltip title={channelSubCount} followCursor placement="top">
|
||||||
<span className="claim-preview__channel-sub-count">
|
<span className="claim-preview__channel-sub-count">
|
||||||
{channelSubCount === 1 ? __('1 Follower') : __('%formattedSubCount% Followers', { formattedSubCount })}
|
{channelSubCount === 1 ? __('1 Follower') : __('%formattedSubCount% Followers', { formattedSubCount })}
|
||||||
</span>
|
</span>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}, [channelSubCount]);
|
}, [channelSubCount]);
|
||||||
const isValid = uri && isURIValid(uri);
|
const isValid = uri && isURIValid(uri);
|
||||||
|
@ -170,12 +179,13 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
claim.value.stream_type &&
|
claim.value.stream_type &&
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
(claim.value.stream_type === 'audio' || claim.value.stream_type === 'video');
|
(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 signingChannel = claim && claim.signing_channel;
|
||||||
const repostedChannelUri =
|
const repostedChannelUri =
|
||||||
claim && claim.repost_channel_url && claim.value_type === 'channel'
|
claim && claim.repost_channel_url && claim.value_type === 'channel'
|
||||||
? claim.permanent_url || claim.canonical_url
|
? claim.permanent_url || claim.canonical_url
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url);
|
||||||
|
|
||||||
// Get channel title ( use name as fallback )
|
// Get channel title ( use name as fallback )
|
||||||
let channelTitle = null;
|
let channelTitle = null;
|
||||||
|
@ -225,7 +235,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
((abandoned && !showUnresolvedClaim) || (!claimIsMine && obscureNsfw && nsfw));
|
((abandoned && !showUnresolvedClaim) || (!claimIsMine && obscureNsfw && nsfw));
|
||||||
|
|
||||||
// This will be replaced once blocking is done at the wallet server level
|
// This will be replaced once blocking is done at the wallet server level
|
||||||
if (claim && !claimIsMine && (banState.blacklisted || banState.filtered)) {
|
if (!shouldHide && !claimIsMine && (banState.blacklisted || banState.filtered)) {
|
||||||
shouldHide = true;
|
shouldHide = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,18 +330,14 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
'claim-preview--channel': isChannelUri,
|
'claim-preview--channel': isChannelUri,
|
||||||
'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri,
|
'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri,
|
||||||
'claim-preview--pending': pending,
|
'claim-preview--pending': pending,
|
||||||
'claim-preview--collection-mine': isMyCollection && listId && type === 'listview',
|
'claim-preview--collection-mine': isMyCollection && showEdit,
|
||||||
|
'swipe-list__item': swipeLayout,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{isMyCollection && listId && type === 'listview' && (
|
{isMyCollection && showEdit && (
|
||||||
<CollectionEditButtons
|
<CollectionEditButtons uri={uri} collectionId={listId} dragHandleProps={dragHandleProps} />
|
||||||
collectionIndex={collectionIndex}
|
|
||||||
editCollection={editCollection}
|
|
||||||
listId={listId}
|
|
||||||
lastCollectionIndex={lastCollectionIndex}
|
|
||||||
claim={claim}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isChannelUri && claim ? (
|
{isChannelUri && claim ? (
|
||||||
<UriIndicator focusable={false} uri={uri} link>
|
<UriIndicator focusable={false} uri={uri} link>
|
||||||
<ChannelThumbnail uri={uri} small={type === 'inline'} />
|
<ChannelThumbnail uri={uri} small={type === 'inline'} />
|
||||||
|
@ -342,7 +348,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
<NavLink aria-hidden tabIndex={-1} {...navLinkProps}>
|
<NavLink aria-hidden tabIndex={-1} {...navLinkProps}>
|
||||||
<FileThumbnail thumbnail={thumbnailUrl}>
|
<FileThumbnail thumbnail={thumbnailUrl}>
|
||||||
<div className="claim-preview__hover-actions">
|
<div className="claim-preview__hover-actions">
|
||||||
{isPlayable && <FileWatchLaterLink focusable={false} uri={uri} />}
|
{isPlayable && <FileWatchLaterLink focusable={false} uri={repostedContentUri} />}
|
||||||
</div>
|
</div>
|
||||||
{/* @if TARGET='app' */}
|
{/* @if TARGET='app' */}
|
||||||
<div className="claim-preview__hover-actions">
|
<div className="claim-preview__hover-actions">
|
||||||
|
@ -352,7 +358,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
</div>
|
</div>
|
||||||
{/* @endif */}
|
{/* @endif */}
|
||||||
<div className="claim-preview__file-property-overlay">
|
<div className="claim-preview__file-property-overlay">
|
||||||
<PreviewOverlayProperties uri={uri} properties={properties} />
|
<PreviewOverlayProperties uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
</FileThumbnail>
|
</FileThumbnail>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
@ -391,8 +397,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
<ChannelThumbnail uri={signingChannel.permanent_url} xsmall />
|
<ChannelThumbnail uri={signingChannel.permanent_url} xsmall />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{isChannelUri && !banState.muted && !claimIsMine && (
|
||||||
{isChannelUri && !channelIsBlocked && !claimIsMine && (
|
|
||||||
<SubscribeButton
|
<SubscribeButton
|
||||||
uri={repostedChannelUri || (uri.startsWith('lbry://') ? uri : `lbry://${uri}`)}
|
uri={repostedChannelUri || (uri.startsWith('lbry://') ? uri : `lbry://${uri}`)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -42,6 +42,7 @@ type Props = {
|
||||||
properties?: (Claim) => void,
|
properties?: (Claim) => void,
|
||||||
collectionId?: string,
|
collectionId?: string,
|
||||||
viewCount: string,
|
viewCount: string,
|
||||||
|
swipeLayout: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
// preview image cards used in related video functionality, channel overview page and homepage
|
// preview image cards used in related video functionality, channel overview page and homepage
|
||||||
|
@ -66,6 +67,7 @@ function ClaimPreviewTile(props: Props) {
|
||||||
collectionId,
|
collectionId,
|
||||||
mediaDuration,
|
mediaDuration,
|
||||||
viewCount,
|
viewCount,
|
||||||
|
swipeLayout = false,
|
||||||
} = props;
|
} = props;
|
||||||
const isRepost = claim && claim.repost_channel_url;
|
const isRepost = claim && claim.repost_channel_url;
|
||||||
const isCollection = claim && claim.value_type === 'collection';
|
const isCollection = claim && claim.value_type === 'collection';
|
||||||
|
@ -84,6 +86,7 @@ function ClaimPreviewTile(props: Props) {
|
||||||
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail;
|
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail;
|
||||||
const canonicalUrl = claim && claim.canonical_url;
|
const canonicalUrl = claim && claim.canonical_url;
|
||||||
const permanentUrl = claim && claim.permanent_url;
|
const permanentUrl = claim && claim.permanent_url;
|
||||||
|
const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url);
|
||||||
const listId = collectionId || collectionClaimId;
|
const listId = collectionId || collectionClaimId;
|
||||||
const navigateUrl =
|
const navigateUrl =
|
||||||
formatLbryUrlForWeb(canonicalUrl || uri || '/') + (listId ? generateListSearchUrlParams(listId) : '');
|
formatLbryUrlForWeb(canonicalUrl || uri || '/') + (listId ? generateListSearchUrlParams(listId) : '');
|
||||||
|
@ -168,6 +171,7 @@ function ClaimPreviewTile(props: Props) {
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className={classnames('card claim-preview--tile', {
|
className={classnames('card claim-preview--tile', {
|
||||||
'claim-preview__wrapper--channel': isChannel,
|
'claim-preview__wrapper--channel': isChannel,
|
||||||
|
'swipe-list__item claim-preview--horizontal-tile': swipeLayout,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<NavLink {...navLinkProps} role="none" tabIndex={-1} aria-hidden>
|
<NavLink {...navLinkProps} role="none" tabIndex={-1} aria-hidden>
|
||||||
|
@ -175,7 +179,7 @@ function ClaimPreviewTile(props: Props) {
|
||||||
{!isChannel && (
|
{!isChannel && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="claim-preview__hover-actions">
|
<div className="claim-preview__hover-actions">
|
||||||
{isPlayable && <FileWatchLaterLink focusable={false} uri={uri} />}
|
{isPlayable && <FileWatchLaterLink focusable={false} uri={repostedContentUri} />}
|
||||||
</div>
|
</div>
|
||||||
{/* @if TARGET='app' */}
|
{/* @if TARGET='app' */}
|
||||||
<div className="claim-preview__hover-actions">
|
<div className="claim-preview__hover-actions">
|
||||||
|
|
|
@ -55,20 +55,6 @@ function CollectionActions(props: Props) {
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const webShareable = true; // collections have cost?
|
const webShareable = true; // collections have cost?
|
||||||
|
|
||||||
/*
|
|
||||||
A bit too much dependency with both ordering and shuffling depending on a single list item index selector
|
|
||||||
For now when they click edit, we'll toggle shuffle off for them.
|
|
||||||
*/
|
|
||||||
const handleSetShowEdit = (setting) => {
|
|
||||||
doToggleShuffleList(collectionId, false);
|
|
||||||
setShowEdit(setting);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePublishMode = () => {
|
|
||||||
doToggleShuffleList(collectionId, false);
|
|
||||||
push(`?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const doPlay = React.useCallback(
|
const doPlay = React.useCallback(
|
||||||
(playUri) => {
|
(playUri) => {
|
||||||
const navigateUrl = formatLbryUrlForWeb(playUri);
|
const navigateUrl = formatLbryUrlForWeb(playUri);
|
||||||
|
@ -138,7 +124,7 @@ function CollectionActions(props: Props) {
|
||||||
title={uri ? __('Update') : __('Publish')}
|
title={uri ? __('Update') : __('Publish')}
|
||||||
label={uri ? __('Update') : __('Publish')}
|
label={uri ? __('Update') : __('Publish')}
|
||||||
className={classnames('button--file-action')}
|
className={classnames('button--file-action')}
|
||||||
onClick={() => handlePublishMode()}
|
onClick={() => push(`?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`)}
|
||||||
icon={ICONS.PUBLISH}
|
icon={ICONS.PUBLISH}
|
||||||
iconColor={collectionHasEdits && 'red'}
|
iconColor={collectionHasEdits && 'red'}
|
||||||
iconSize={18}
|
iconSize={18}
|
||||||
|
@ -165,7 +151,9 @@ function CollectionActions(props: Props) {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const infoButton = (
|
const infoButtons = (
|
||||||
|
<div className="section">
|
||||||
|
{uri && (
|
||||||
<Button
|
<Button
|
||||||
title={__('Info')}
|
title={__('Info')}
|
||||||
className={classnames('button-toggle', {
|
className={classnames('button-toggle', {
|
||||||
|
@ -174,17 +162,17 @@ function CollectionActions(props: Props) {
|
||||||
icon={ICONS.MORE}
|
icon={ICONS.MORE}
|
||||||
onClick={() => setShowInfo(!showInfo)}
|
onClick={() => setShowInfo(!showInfo)}
|
||||||
/>
|
/>
|
||||||
);
|
)}
|
||||||
|
|
||||||
const showEditButton = (
|
{isMyCollection && (
|
||||||
<Button
|
<Button
|
||||||
title={__('Edit')}
|
title={__('Edit')}
|
||||||
className={classnames('button-toggle', {
|
className={classnames('button-toggle', { 'button-toggle--active': showEdit })}
|
||||||
'button-toggle--active': showEdit,
|
|
||||||
})}
|
|
||||||
icon={ICONS.EDIT}
|
icon={ICONS.EDIT}
|
||||||
onClick={() => handleSetShowEdit(!showEdit)}
|
onClick={() => setShowEdit(!showEdit)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
|
@ -192,7 +180,7 @@ function CollectionActions(props: Props) {
|
||||||
<div className="media__actions">
|
<div className="media__actions">
|
||||||
{lhsSection}
|
{lhsSection}
|
||||||
{rhsSection}
|
{rhsSection}
|
||||||
{uri && <span>{infoButton}</span>}
|
{infoButtons}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -202,10 +190,8 @@ function CollectionActions(props: Props) {
|
||||||
{lhsSection}
|
{lhsSection}
|
||||||
{rhsSection}
|
{rhsSection}
|
||||||
</div>
|
</div>
|
||||||
<div className="section">
|
|
||||||
{uri && infoButton}
|
{infoButtons}
|
||||||
{showEditButton}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import CollectionContent from './view';
|
import CollectionContent from './view';
|
||||||
import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims';
|
import { selectClaimForUri } from 'redux/selectors/claims';
|
||||||
import {
|
import {
|
||||||
makeSelectUrlsForCollectionId,
|
makeSelectUrlsForCollectionId,
|
||||||
makeSelectNameForCollectionId,
|
makeSelectNameForCollectionId,
|
||||||
makeSelectCollectionForId,
|
makeSelectCollectionForId,
|
||||||
|
makeSelectCollectionIsMine,
|
||||||
} from 'redux/selectors/collections';
|
} from 'redux/selectors/collections';
|
||||||
import { selectPlayingUri, selectListLoop, selectListShuffle } from 'redux/selectors/content';
|
import { selectPlayingUri, selectListLoop, selectListShuffle } from 'redux/selectors/content';
|
||||||
import { doToggleLoopList, doToggleShuffleList } from 'redux/actions/content';
|
import { doToggleLoopList, doToggleShuffleList } from 'redux/actions/content';
|
||||||
|
import { doCollectionEdit } from 'redux/actions/collections';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const playingUri = selectPlayingUri(state);
|
const playingUri = selectPlayingUri(state);
|
||||||
|
@ -24,7 +26,7 @@ const select = (state, props) => {
|
||||||
collection: makeSelectCollectionForId(props.id)(state),
|
collection: makeSelectCollectionForId(props.id)(state),
|
||||||
collectionUrls: makeSelectUrlsForCollectionId(props.id)(state),
|
collectionUrls: makeSelectUrlsForCollectionId(props.id)(state),
|
||||||
collectionName: makeSelectNameForCollectionId(props.id)(state),
|
collectionName: makeSelectNameForCollectionId(props.id)(state),
|
||||||
isMine: selectClaimIsMine(state, claim),
|
isMyCollection: makeSelectCollectionIsMine(props.id)(state),
|
||||||
loop,
|
loop,
|
||||||
shuffle,
|
shuffle,
|
||||||
};
|
};
|
||||||
|
@ -33,4 +35,5 @@ const select = (state, props) => {
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
doToggleLoopList,
|
doToggleLoopList,
|
||||||
doToggleShuffleList,
|
doToggleShuffleList,
|
||||||
|
doCollectionEdit,
|
||||||
})(CollectionContent);
|
})(CollectionContent);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
import ClaimList from 'component/claimList';
|
import ClaimList from 'component/claimList';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
@ -11,7 +16,7 @@ import * as ICONS from 'constants/icons';
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string,
|
id: string,
|
||||||
url: string,
|
url: string,
|
||||||
isMine: boolean,
|
isMyCollection: boolean,
|
||||||
collectionUrls: Array<Claim>,
|
collectionUrls: Array<Claim>,
|
||||||
collectionName: string,
|
collectionName: string,
|
||||||
collection: any,
|
collection: any,
|
||||||
|
@ -20,10 +25,35 @@ type Props = {
|
||||||
doToggleLoopList: (string, boolean) => void,
|
doToggleLoopList: (string, boolean) => void,
|
||||||
doToggleShuffleList: (string, string, boolean) => void,
|
doToggleShuffleList: (string, string, boolean) => void,
|
||||||
createUnpublishedCollection: (string, Array<any>, ?string) => void,
|
createUnpublishedCollection: (string, Array<any>, ?string) => void,
|
||||||
|
doCollectionEdit: (string, CollectionEditParams) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CollectionContent(props: Props) {
|
export default function CollectionContent(props: Props) {
|
||||||
const { collectionUrls, collectionName, id, url, loop, shuffle, doToggleLoopList, doToggleShuffleList } = props;
|
const {
|
||||||
|
isMyCollection,
|
||||||
|
collectionUrls,
|
||||||
|
collectionName,
|
||||||
|
id,
|
||||||
|
url,
|
||||||
|
loop,
|
||||||
|
shuffle,
|
||||||
|
doToggleLoopList,
|
||||||
|
doToggleShuffleList,
|
||||||
|
doCollectionEdit,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const [showEdit, setShowEdit] = React.useState(false);
|
||||||
|
|
||||||
|
function handleOnDragEnd(result) {
|
||||||
|
const { source, destination } = result;
|
||||||
|
|
||||||
|
if (!destination) return;
|
||||||
|
|
||||||
|
const { index: from } = source;
|
||||||
|
const { index: to } = destination;
|
||||||
|
|
||||||
|
doCollectionEdit(id, { order: { from, to } });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
@ -63,12 +93,26 @@ export default function CollectionContent(props: Props) {
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
titleActions={
|
titleActions={
|
||||||
|
<>
|
||||||
<div className="card__title-actions--link">
|
<div className="card__title-actions--link">
|
||||||
{/* TODO: BUTTON TO SAVE COLLECTION - Probably save/copy modal */}
|
{/* TODO: BUTTON TO SAVE COLLECTION - Probably save/copy modal */}
|
||||||
<Button label={__('View List')} button="link" navigate={`/$/${PAGES.LIST}/${id}`} />
|
<Button label={__('View List')} button="link" navigate={`/$/${PAGES.LIST}/${id}`} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isMyCollection && (
|
||||||
|
<Button
|
||||||
|
title={__('Edit')}
|
||||||
|
className={classnames('button-toggle', { 'button-toggle--active': showEdit })}
|
||||||
|
icon={ICONS.EDIT}
|
||||||
|
onClick={() => setShowEdit(!showEdit)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
body={
|
body={
|
||||||
|
<DragDropContext onDragEnd={handleOnDragEnd}>
|
||||||
|
<Droppable droppableId="list__ordering">
|
||||||
|
{(DroppableProvided) => (
|
||||||
<ClaimList
|
<ClaimList
|
||||||
isCardBody
|
isCardBody
|
||||||
type="small"
|
type="small"
|
||||||
|
@ -76,7 +120,12 @@ export default function CollectionContent(props: Props) {
|
||||||
uris={collectionUrls}
|
uris={collectionUrls}
|
||||||
collectionId={id}
|
collectionId={id}
|
||||||
empty={__('List is Empty')}
|
empty={__('List is Empty')}
|
||||||
|
showEdit={showEdit}
|
||||||
|
droppableProvided={DroppableProvided}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
import CollectionForm from './view';
|
import CollectionForm from './view';
|
||||||
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
||||||
import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app';
|
import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app';
|
||||||
|
import { doCollectionEdit } from 'redux/actions/collections';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
@ -44,12 +45,13 @@ const select = (state, props) => ({
|
||||||
collectionClaimIds: makeSelectClaimIdsForCollectionId(props.collectionId)(state),
|
collectionClaimIds: makeSelectClaimIdsForCollectionId(props.collectionId)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch, ownProps) => ({
|
||||||
publishCollectionUpdate: (params) => dispatch(doCollectionPublishUpdate(params)),
|
publishCollectionUpdate: (params) => dispatch(doCollectionPublishUpdate(params)),
|
||||||
publishCollection: (params, collectionId) => dispatch(doCollectionPublish(params, collectionId)),
|
publishCollection: (params, collectionId) => dispatch(doCollectionPublish(params, collectionId)),
|
||||||
clearCollectionErrors: () => dispatch({ type: ACTIONS.CLEAR_COLLECTION_ERRORS }),
|
clearCollectionErrors: () => dispatch({ type: ACTIONS.CLEAR_COLLECTION_ERRORS }),
|
||||||
setActiveChannel: (claimId) => dispatch(doSetActiveChannel(claimId)),
|
setActiveChannel: (claimId) => dispatch(doSetActiveChannel(claimId)),
|
||||||
setIncognito: (incognito) => dispatch(doSetIncognito(incognito)),
|
setIncognito: (incognito) => dispatch(doSetIncognito(incognito)),
|
||||||
|
doCollectionEdit: (params) => dispatch(doCollectionEdit(ownProps.collectionId, params)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(CollectionForm);
|
export default connect(select, perform)(CollectionForm);
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
@ -54,6 +57,7 @@ type Props = {
|
||||||
onDone: (string) => void,
|
onDone: (string) => void,
|
||||||
setActiveChannel: (string) => void,
|
setActiveChannel: (string) => void,
|
||||||
setIncognito: (boolean) => void,
|
setIncognito: (boolean) => void,
|
||||||
|
doCollectionEdit: (CollectionEditParams) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
function CollectionForm(props: Props) {
|
function CollectionForm(props: Props) {
|
||||||
|
@ -87,6 +91,7 @@ function CollectionForm(props: Props) {
|
||||||
setActiveChannel,
|
setActiveChannel,
|
||||||
setIncognito,
|
setIncognito,
|
||||||
onDone,
|
onDone,
|
||||||
|
doCollectionEdit,
|
||||||
} = props;
|
} = props;
|
||||||
const activeChannelName = activeChannelClaim && activeChannelClaim.name;
|
const activeChannelName = activeChannelClaim && activeChannelClaim.name;
|
||||||
let prefix = 'lbry://';
|
let prefix = 'lbry://';
|
||||||
|
@ -196,6 +201,17 @@ function CollectionForm(props: Props) {
|
||||||
return collectionParams;
|
return collectionParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleOnDragEnd(result) {
|
||||||
|
const { source, destination } = result;
|
||||||
|
|
||||||
|
if (!destination) return;
|
||||||
|
|
||||||
|
const { index: from } = source;
|
||||||
|
const { index: to } = destination;
|
||||||
|
|
||||||
|
doCollectionEdit({ order: { from, to } });
|
||||||
|
}
|
||||||
|
|
||||||
function handleLanguageChange(index, code) {
|
function handleLanguageChange(index, code) {
|
||||||
let langs = [...languageParam];
|
let langs = [...languageParam];
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
|
@ -286,7 +302,6 @@ function CollectionForm(props: Props) {
|
||||||
}
|
}
|
||||||
}, [uri, hasClaim]);
|
}, [uri, hasClaim]);
|
||||||
|
|
||||||
console.log('params', params);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classnames('main--contained', { 'card--disabled': disabled })}>
|
<div className={classnames('main--contained', { 'card--disabled': disabled })}>
|
||||||
|
@ -357,12 +372,19 @@ function CollectionForm(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
|
<DragDropContext onDragEnd={handleOnDragEnd}>
|
||||||
|
<Droppable droppableId="list__ordering">
|
||||||
|
{(DroppableProvided) => (
|
||||||
<ClaimList
|
<ClaimList
|
||||||
uris={collectionUrls}
|
uris={collectionUrls}
|
||||||
collectionId={collectionId}
|
collectionId={collectionId}
|
||||||
empty={__('This list has no items.')}
|
empty={__('This list has no items.')}
|
||||||
type={'listview'}
|
showEdit
|
||||||
|
droppableProvided={DroppableProvided}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<Card
|
<Card
|
||||||
|
|
23
ui/component/collectionEditButtons/index.js
Normal file
23
ui/component/collectionEditButtons/index.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doCollectionEdit } from 'redux/actions/collections';
|
||||||
|
import { makeSelectIndexForUrlInCollection, makeSelectUrlsForCollectionId } from 'redux/selectors/collections';
|
||||||
|
import CollectionButtons from './view';
|
||||||
|
|
||||||
|
const select = (state, props) => {
|
||||||
|
const { uri, collectionId } = props;
|
||||||
|
|
||||||
|
return {
|
||||||
|
collectionIndex: makeSelectIndexForUrlInCollection(uri, collectionId, true)(state),
|
||||||
|
collectionUris: makeSelectUrlsForCollectionId(collectionId)(state),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const perform = (dispatch, ownProps) => {
|
||||||
|
const { collectionId } = ownProps;
|
||||||
|
|
||||||
|
return {
|
||||||
|
editCollection: (params) => dispatch(doCollectionEdit(collectionId, params)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(select, perform)(CollectionButtons);
|
92
ui/component/collectionEditButtons/view.jsx
Normal file
92
ui/component/collectionEditButtons/view.jsx
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// @flow
|
||||||
|
import * as ICONS from 'constants/icons';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import Icon from 'component/common/icon';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
collectionIndex?: number,
|
||||||
|
collectionUris: Array<Collection>,
|
||||||
|
dragHandleProps?: any,
|
||||||
|
uri: string,
|
||||||
|
editCollection: (CollectionEditParams) => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CollectionButtons(props: Props) {
|
||||||
|
const { collectionIndex: foundIndex, collectionUris, dragHandleProps, uri, editCollection } = props;
|
||||||
|
|
||||||
|
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
||||||
|
|
||||||
|
const lastCollectionIndex = collectionUris ? collectionUris.length - 1 : 0;
|
||||||
|
const collectionIndex = Number(foundIndex);
|
||||||
|
|
||||||
|
const orderButton = (className: string, title: string, icon: string, disabled: boolean, handleClick?: () => void) => (
|
||||||
|
<Button
|
||||||
|
className={`button-collection-manage ${className}`}
|
||||||
|
icon={icon}
|
||||||
|
title={title}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => handleClick && handleClick()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="collection-preview__edit-buttons"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="collection-preview__edit-group" {...dragHandleProps}>
|
||||||
|
<div className="button-collection-manage button-collection-drag top-left bottom-left">
|
||||||
|
<Icon icon={ICONS.DRAG} title={__('Drag')} size={20} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="collection-preview__edit-group">
|
||||||
|
{orderButton('', __('Move Top'), ICONS.UP_TOP, collectionIndex === 0, () =>
|
||||||
|
editCollection({ order: { from: collectionIndex, to: 0 } })
|
||||||
|
)}
|
||||||
|
|
||||||
|
{orderButton('', __('Move Bottom'), ICONS.DOWN_BOTTOM, collectionIndex === lastCollectionIndex, () =>
|
||||||
|
editCollection({ order: { from: collectionIndex, to: lastCollectionIndex } })
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="collection-preview__edit-group">
|
||||||
|
{orderButton('', __('Move Up'), ICONS.UP, collectionIndex === 0, () =>
|
||||||
|
editCollection({ order: { from: collectionIndex, to: collectionIndex - 1 } })
|
||||||
|
)}
|
||||||
|
|
||||||
|
{orderButton('', __('Move Down'), ICONS.DOWN, collectionIndex === lastCollectionIndex, () =>
|
||||||
|
editCollection({ order: { from: collectionIndex, to: collectionIndex + 1 } })
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!confirmDelete ? (
|
||||||
|
<div className="collection-preview__edit-group collection-preview__delete ">
|
||||||
|
<Button
|
||||||
|
className="button-collection-manage button-collection-delete top-right bottom-right"
|
||||||
|
icon={ICONS.DELETE}
|
||||||
|
title={__('Remove')}
|
||||||
|
onClick={() => setConfirmDelete(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="collection-preview__edit-group collection-preview__delete">
|
||||||
|
<Button
|
||||||
|
className="button-collection-manage button-collection-delete-cancel top-right"
|
||||||
|
icon={ICONS.REMOVE}
|
||||||
|
title={__('Cancel')}
|
||||||
|
onClick={() => setConfirmDelete(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{orderButton('button-collection-delete-confirm bottom-right', __('Remove'), ICONS.DELETE, false, () =>
|
||||||
|
editCollection({ uris: [uri], remove: true })
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -5,10 +5,12 @@ import { doCollectionEdit } from 'redux/actions/collections';
|
||||||
import CollectionSelectItem from './view';
|
import CollectionSelectItem from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
const { collectionId, uri } = props;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
collection: makeSelectCollectionForId(props.collectionId)(state),
|
collection: makeSelectCollectionForId(collectionId)(state),
|
||||||
hasClaim: makeSelectCollectionForIdHasClaimUrl(props.collectionId, props.uri)(state),
|
hasClaim: makeSelectCollectionForIdHasClaimUrl(collectionId, uri)(state),
|
||||||
collectionPending: makeSelectClaimIsPending(props.collectionId)(state),
|
collectionPending: makeSelectClaimIsPending(collectionId)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,15 @@ type Props = {
|
||||||
category: string,
|
category: string,
|
||||||
edited: boolean,
|
edited: boolean,
|
||||||
editCollection: (string, CollectionEditParams) => void,
|
editCollection: (string, CollectionEditParams) => void,
|
||||||
claim: Claim,
|
uri: string,
|
||||||
collectionPending: Collection,
|
collectionPending: Collection,
|
||||||
};
|
};
|
||||||
|
|
||||||
function CollectionSelectItem(props: Props) {
|
function CollectionSelectItem(props: Props) {
|
||||||
const { collection, hasClaim, category, editCollection, claim, collectionPending } = props;
|
const { collection, hasClaim, category, editCollection, uri, collectionPending } = props;
|
||||||
const { name, id } = collection;
|
const { name, id } = collection;
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
editCollection(id, { claims: [claim], remove: hasClaim });
|
editCollection(id, { uris: [uri], remove: hasClaim });
|
||||||
};
|
};
|
||||||
|
|
||||||
let icon;
|
let icon;
|
||||||
|
|
|
@ -382,21 +382,10 @@ export const icons = {
|
||||||
[ICONS.NO]: buildIcon(
|
[ICONS.NO]: buildIcon(
|
||||||
<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" />
|
<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" />
|
||||||
),
|
),
|
||||||
[ICONS.UP]: buildIcon(
|
[ICONS.UP]: buildIcon(<polyline transform="matrix(1,0,0,-1,0,24.707107)" points="6 9 12 15 18 9" />),
|
||||||
<g>
|
[ICONS.UP_TOP]: buildIcon(<path d="m6 16 6-6 6 6M6 8h12" />),
|
||||||
<polyline transform="matrix(1,0,0,-1,0,24.707107)" points="6 9 12 15 18 9" />
|
[ICONS.DOWN_BOTTOM]: buildIcon(<path d="m6 8 6 6 6-6M6 16h12" />),
|
||||||
</g>
|
[ICONS.DRAG]: buildIcon(<path d="m8 18 4 4 4-4M4 14h16M4 10h16M8 6l4-4 4 4" />),
|
||||||
),
|
|
||||||
[ICONS.UP_TOP]: buildIcon(
|
|
||||||
<g>
|
|
||||||
<path d="m6 16 6-6 6 6M6 8h12" />
|
|
||||||
</g>
|
|
||||||
),
|
|
||||||
[ICONS.DOWN_BOTTOM]: buildIcon(
|
|
||||||
<g>
|
|
||||||
<path d="m6 8 6 6 6-6M6 16h12" />
|
|
||||||
</g>
|
|
||||||
),
|
|
||||||
[ICONS.DOWN]: buildIcon(<polyline points="6 9 12 15 18 9" />),
|
[ICONS.DOWN]: buildIcon(<polyline points="6 9 12 15 18 9" />),
|
||||||
[ICONS.FULLSCREEN]: buildIcon(
|
[ICONS.FULLSCREEN]: buildIcon(
|
||||||
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
|
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doCollectionEdit } from 'redux/actions/collections';
|
import { doCollectionEdit } from 'redux/actions/collections';
|
||||||
import { makeSelectCollectionForIdHasClaimUrl } from 'redux/selectors/collections';
|
import { makeSelectCollectionForIdHasClaimUrl } from 'redux/selectors/collections';
|
||||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
|
||||||
import * as COLLECTIONS_CONSTS from 'constants/collections';
|
import * as COLLECTIONS_CONSTS from 'constants/collections';
|
||||||
import FileWatchLaterLink from './view';
|
import FileWatchLaterLink from './view';
|
||||||
import { doToast } from 'redux/actions/notifications';
|
import { doToast } from 'redux/actions/notifications';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
const claim = makeSelectClaimForUri(props.uri)(state);
|
const { uri } = props;
|
||||||
const permanentUri = claim && claim.permanent_url;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
claim,
|
hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.WATCH_LATER_ID, uri)(state),
|
||||||
hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl(COLLECTIONS_CONSTS.WATCH_LATER_ID, permanentUri)(state),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import * as COLLECTIONS_CONSTS from 'constants/collections';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
claim: StreamClaim,
|
|
||||||
focusable: boolean,
|
focusable: boolean,
|
||||||
hasClaimInWatchLater: boolean,
|
hasClaimInWatchLater: boolean,
|
||||||
doToast: ({ message: string }) => void,
|
doToast: ({ message: string }) => void,
|
||||||
|
@ -15,14 +14,10 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function FileWatchLaterLink(props: Props) {
|
function FileWatchLaterLink(props: Props) {
|
||||||
const { claim, hasClaimInWatchLater, doToast, doCollectionEdit, focusable = true } = props;
|
const { uri, hasClaimInWatchLater, doToast, doCollectionEdit, focusable = true } = props;
|
||||||
const buttonRef = useRef();
|
const buttonRef = useRef();
|
||||||
let isHovering = useHover(buttonRef);
|
let isHovering = useHover(buttonRef);
|
||||||
|
|
||||||
if (!claim) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleWatchLater(e) {
|
function handleWatchLater(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
doToast({
|
doToast({
|
||||||
|
@ -31,7 +26,7 @@ function FileWatchLaterLink(props: Props) {
|
||||||
linkTarget: !hasClaimInWatchLater && '/list/watchlater',
|
linkTarget: !hasClaimInWatchLater && '/list/watchlater',
|
||||||
});
|
});
|
||||||
doCollectionEdit(COLLECTIONS_CONSTS.WATCH_LATER_ID, {
|
doCollectionEdit(COLLECTIONS_CONSTS.WATCH_LATER_ID, {
|
||||||
claims: [claim],
|
uris: [uri],
|
||||||
remove: hasClaimInWatchLater,
|
remove: hasClaimInWatchLater,
|
||||||
type: 'playlist',
|
type: 'playlist',
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment';
|
||||||
import { parseURI, isURIValid } from 'util/lbryURI';
|
import { parseURI, isURIValid } from 'util/lbryURI';
|
||||||
import { WELCOME_VERSION } from 'config';
|
import { WELCOME_VERSION } from 'config';
|
||||||
import { GetLinksData } from 'util/buildHomepage';
|
import { GetLinksData } from 'util/buildHomepage';
|
||||||
|
import { useIsLargeScreen } from 'effects/use-screensize';
|
||||||
|
|
||||||
import HomePage from 'page/home';
|
import HomePage from 'page/home';
|
||||||
import BackupPage from 'page/backup';
|
import BackupPage from 'page/backup';
|
||||||
|
@ -125,8 +126,8 @@ function AppRouter(props: Props) {
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const resetScroll = urlParams.get('reset_scroll');
|
const resetScroll = urlParams.get('reset_scroll');
|
||||||
const hasLinkedCommentInUrl = urlParams.get(LINKED_COMMENT_QUERY_PARAM);
|
const hasLinkedCommentInUrl = urlParams.get(LINKED_COMMENT_QUERY_PARAM);
|
||||||
|
const isLargeScreen = useIsLargeScreen();
|
||||||
const dynamicRoutes = GetLinksData(homepageData).filter(
|
const dynamicRoutes = GetLinksData(homepageData, isLargeScreen).filter(
|
||||||
(potentialRoute: any) => potentialRoute && potentialRoute.route
|
(potentialRoute: any) => potentialRoute && potentialRoute.route
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// https://github.com/carmelopullara/react-feather
|
// https://github.com/carmelopullara/react-feather
|
||||||
// Note: Icons should be named for their purpose, rather than the actual icon.
|
// Note: Icons should be named for their purpose, rather than the actual icon.
|
||||||
// The goal being to reduce multiple uses of the same icon for different purposes.
|
// The goal being to reduce multiple uses of the same icon for different purposes.
|
||||||
//
|
|
||||||
export const REWARDS = 'Award';
|
export const REWARDS = 'Award';
|
||||||
export const LOCAL = 'Folder';
|
export const LOCAL = 'Folder';
|
||||||
export const ALERT = 'AlertCircle';
|
export const ALERT = 'AlertCircle';
|
||||||
|
@ -68,6 +68,7 @@ export const UP = 'ChevronUp';
|
||||||
export const UP_TOP = 'ChevronUpTop';
|
export const UP_TOP = 'ChevronUpTop';
|
||||||
export const DOWN = 'ChevronDown';
|
export const DOWN = 'ChevronDown';
|
||||||
export const DOWN_BOTTOM = 'ChevronDownBottom';
|
export const DOWN_BOTTOM = 'ChevronDownBottom';
|
||||||
|
export const DRAG = 'DragAndDrop';
|
||||||
export const SECURE = 'Lock';
|
export const SECURE = 'Lock';
|
||||||
export const MENU = 'Menu';
|
export const MENU = 'Menu';
|
||||||
export const BACKUP = 'Database';
|
export const BACKUP = 'Database';
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ClaimList from 'component/claimList';
|
import ClaimList from 'component/claimList';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
@ -51,6 +55,7 @@ export default function CollectionPage(props: Props) {
|
||||||
collectionHasEdits,
|
collectionHasEdits,
|
||||||
claimIsPending,
|
claimIsPending,
|
||||||
isResolvingCollection,
|
isResolvingCollection,
|
||||||
|
editCollection,
|
||||||
fetchCollectionItems,
|
fetchCollectionItems,
|
||||||
deleteCollection,
|
deleteCollection,
|
||||||
} = props;
|
} = props;
|
||||||
|
@ -63,9 +68,22 @@ export default function CollectionPage(props: Props) {
|
||||||
const [didTryResolve, setDidTryResolve] = React.useState(false);
|
const [didTryResolve, setDidTryResolve] = React.useState(false);
|
||||||
const [showInfo, setShowInfo] = React.useState(false);
|
const [showInfo, setShowInfo] = React.useState(false);
|
||||||
const [showEdit, setShowEdit] = React.useState(false);
|
const [showEdit, setShowEdit] = React.useState(false);
|
||||||
|
const [unavailableUris, setUnavailable] = React.useState([]);
|
||||||
|
|
||||||
const { name, totalItems } = collection || {};
|
const { name, totalItems } = collection || {};
|
||||||
const isBuiltin = COLLECTIONS_CONSTS.BUILTIN_LISTS.includes(collectionId);
|
const isBuiltin = COLLECTIONS_CONSTS.BUILTIN_LISTS.includes(collectionId);
|
||||||
|
|
||||||
|
function handleOnDragEnd(result) {
|
||||||
|
const { source, destination } = result;
|
||||||
|
|
||||||
|
if (!destination) return;
|
||||||
|
|
||||||
|
const { index: from } = source;
|
||||||
|
const { index: to } = destination;
|
||||||
|
|
||||||
|
editCollection(collectionId, { order: { from, to } });
|
||||||
|
}
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(search);
|
const urlParams = new URLSearchParams(search);
|
||||||
const editing = urlParams.get(PAGE_VIEW_QUERY) === EDIT_PAGE;
|
const editing = urlParams.get(PAGE_VIEW_QUERY) === EDIT_PAGE;
|
||||||
|
|
||||||
|
@ -94,6 +112,18 @@ export default function CollectionPage(props: Props) {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const removeUnavailable = (
|
||||||
|
<Button
|
||||||
|
button="close"
|
||||||
|
icon={ICONS.DELETE}
|
||||||
|
label={__('Remove all unavailable claims')}
|
||||||
|
onClick={() => {
|
||||||
|
editCollection(collectionId, { uris: unavailableUris, remove: true });
|
||||||
|
setUnavailable([]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
let titleActions;
|
let titleActions;
|
||||||
if (collectionHasEdits) {
|
if (collectionHasEdits) {
|
||||||
titleActions = unpublished;
|
titleActions = unpublished;
|
||||||
|
@ -124,7 +154,7 @@ export default function CollectionPage(props: Props) {
|
||||||
{claim ? claim.value.title || claim.name : collection && collection.name}
|
{claim ? claim.value.title || claim.name : collection && collection.name}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
titleActions={titleActions}
|
titleActions={unavailableUris.length > 0 ? removeUnavailable : titleActions}
|
||||||
subtitle={subTitle}
|
subtitle={subTitle}
|
||||||
body={
|
body={
|
||||||
<CollectionActions
|
<CollectionActions
|
||||||
|
@ -191,7 +221,20 @@ export default function CollectionPage(props: Props) {
|
||||||
<Page>
|
<Page>
|
||||||
<div className={classnames('section card-stack')}>
|
<div className={classnames('section card-stack')}>
|
||||||
{info}
|
{info}
|
||||||
<ClaimList uris={collectionUrls} collectionId={collectionId} type={showEdit ? 'listview' : undefined} />
|
|
||||||
|
<DragDropContext onDragEnd={handleOnDragEnd}>
|
||||||
|
<Droppable droppableId="list__ordering">
|
||||||
|
{(DroppableProvided) => (
|
||||||
|
<ClaimList
|
||||||
|
uris={collectionUrls}
|
||||||
|
collectionId={collectionId}
|
||||||
|
showEdit={showEdit}
|
||||||
|
droppableProvided={DroppableProvided}
|
||||||
|
unavailableUris={unavailableUris}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
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 React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
@ -9,6 +9,7 @@ import ClaimTilesDiscover from 'component/claimTilesDiscover';
|
||||||
import ClaimPreviewTile from 'component/claimPreviewTile';
|
import ClaimPreviewTile from 'component/claimPreviewTile';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import WaitUntilOnPage from 'component/common/wait-until-on-page';
|
import WaitUntilOnPage from 'component/common/wait-until-on-page';
|
||||||
|
import { useIsLargeScreen } from 'effects/use-screensize'; // have this?
|
||||||
import { GetLinksData } from 'util/buildHomepage';
|
import { GetLinksData } from 'util/buildHomepage';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -24,9 +25,11 @@ function HomePage(props: Props) {
|
||||||
const showPersonalizedChannels = subscribedChannels && subscribedChannels.length > 0;
|
const showPersonalizedChannels = subscribedChannels && subscribedChannels.length > 0;
|
||||||
const showPersonalizedTags = followedTags && followedTags.length > 0;
|
const showPersonalizedTags = followedTags && followedTags.length > 0;
|
||||||
const showIndividualTags = showPersonalizedTags && followedTags.length < 5;
|
const showIndividualTags = showPersonalizedTags && followedTags.length < 5;
|
||||||
|
const isLargeScreen = useIsLargeScreen();
|
||||||
|
|
||||||
const rowData: Array<RowDataItem> = GetLinksData(
|
const rowData: Array<RowDataItem> = GetLinksData(
|
||||||
homepageData,
|
homepageData,
|
||||||
|
isLargeScreen,
|
||||||
true,
|
true,
|
||||||
authenticated,
|
authenticated,
|
||||||
showPersonalizedChannels,
|
showPersonalizedChannels,
|
||||||
|
@ -37,29 +40,40 @@ function HomePage(props: Props) {
|
||||||
showNsfw
|
showNsfw
|
||||||
);
|
);
|
||||||
|
|
||||||
function getRowElements(title, route, link, icon, help, options, index, pinUrls) {
|
type SectionHeaderProps = {
|
||||||
const tilePlaceholder = (
|
title: string,
|
||||||
<ul className="claim-grid">
|
navigate?: string,
|
||||||
{new Array(options.pageSize || 8).fill(1).map((x, i) => (
|
icon?: string,
|
||||||
<ClaimPreviewTile showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS} key={i} placeholder />
|
help?: string,
|
||||||
))}
|
};
|
||||||
</ul>
|
const SectionHeader = ({ title, navigate = '/', icon = '', help }: SectionHeaderProps) => {
|
||||||
);
|
|
||||||
|
|
||||||
const claimTiles = (
|
|
||||||
<ClaimTilesDiscover {...options} showNoSourceClaims={ENABLE_NO_SOURCE_CLAIMS} hasSource pinUrls={pinUrls} />
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={title} className="claim-grid__wrapper">
|
|
||||||
{index !== 0 && title && typeof title === 'string' && (
|
|
||||||
<h1 className="claim-grid__header">
|
<h1 className="claim-grid__header">
|
||||||
<Button navigate={route || link} button="link">
|
<Button navigate={navigate} button="link">
|
||||||
{icon && <Icon className="claim-grid__header-icon" sectionIcon icon={icon} size={20} />}
|
<Icon className="claim-grid__header-icon" sectionIcon icon={icon} size={20} />
|
||||||
<span className="claim-grid__title">{title}</span>
|
<span className="claim-grid__title">{title}</span>
|
||||||
{help}
|
{help}
|
||||||
</Button>
|
</Button>
|
||||||
</h1>
|
</h1>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRowElements(title, route, link, icon, help, options, index, pinUrls) {
|
||||||
|
const tilePlaceholder = (
|
||||||
|
<ul className="claim-grid">
|
||||||
|
{new Array(options.pageSize || 8).fill(1).map((x, i) => (
|
||||||
|
<ClaimPreviewTile key={i} placeholder />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
|
||||||
|
const claimTiles = <ClaimTilesDiscover {...options} hasSource pinUrls={pinUrls} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={title} className="claim-grid__wrapper">
|
||||||
|
{/* category header */}
|
||||||
|
{index !== 0 && title && typeof title === 'string' && (
|
||||||
|
<SectionHeader title={__(title)} navigate={route || link} icon={icon} help={help} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{index === 0 && <>{claimTiles}</>}
|
{index === 0 && <>{claimTiles}</>}
|
||||||
|
@ -69,6 +83,7 @@ function HomePage(props: Props) {
|
||||||
</WaitUntilOnPage>
|
</WaitUntilOnPage>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* view more button */}
|
||||||
{(route || link) && (
|
{(route || link) && (
|
||||||
<Button
|
<Button
|
||||||
className="claim-grid__title--secondary"
|
className="claim-grid__title--secondary"
|
||||||
|
|
|
@ -318,160 +318,49 @@ export const doCollectionEdit = (collectionId: string, params: CollectionEditPar
|
||||||
) => {
|
) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const collection: Collection = makeSelectCollectionForId(collectionId)(state);
|
const collection: Collection = makeSelectCollectionForId(collectionId)(state);
|
||||||
|
|
||||||
|
if (!collection) return dispatch({ type: ACTIONS.COLLECTION_ERROR, data: { message: 'collection does not exist' } });
|
||||||
|
|
||||||
const editedCollection: Collection = makeSelectEditedCollectionForId(collectionId)(state);
|
const editedCollection: Collection = makeSelectEditedCollectionForId(collectionId)(state);
|
||||||
const unpublishedCollection: Collection = makeSelectUnpublishedCollectionForId(collectionId)(state);
|
const unpublishedCollection: Collection = makeSelectUnpublishedCollectionForId(collectionId)(state);
|
||||||
const publishedCollection: Collection = makeSelectPublishedCollectionForId(collectionId)(state); // needs to be published only
|
const publishedCollection: Collection = makeSelectPublishedCollectionForId(collectionId)(state); // needs to be published only
|
||||||
|
|
||||||
const generateCollectionItemsFromSearchResult = (results) => {
|
const { uris, order, remove, type } = params;
|
||||||
return (
|
|
||||||
Object.values(results)
|
|
||||||
// $FlowFixMe
|
|
||||||
.reduce(
|
|
||||||
(
|
|
||||||
acc,
|
|
||||||
cur: {
|
|
||||||
stream: ?StreamClaim,
|
|
||||||
channel: ?ChannelClaim,
|
|
||||||
claimsInChannel: ?number,
|
|
||||||
collection: ?CollectionClaim,
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
let url;
|
|
||||||
if (cur.stream) {
|
|
||||||
url = cur.stream.permanent_url;
|
|
||||||
} else if (cur.channel) {
|
|
||||||
url = cur.channel.permanent_url;
|
|
||||||
} else if (cur.collection) {
|
|
||||||
url = cur.collection.permanent_url;
|
|
||||||
} else {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
acc.push(url);
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!collection) {
|
|
||||||
return dispatch({
|
|
||||||
type: ACTIONS.COLLECTION_ERROR,
|
|
||||||
data: {
|
|
||||||
message: 'collection does not exist',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentItems = collection.items ? collection.items.concat() : [];
|
|
||||||
const { claims: passedClaims, order, claimIds, replace, remove, type } = params;
|
|
||||||
|
|
||||||
const collectionType = type || collection.type;
|
const collectionType = type || collection.type;
|
||||||
let newItems: Array<?string> = currentItems;
|
const currentUrls = collection.items ? collection.items.concat() : [];
|
||||||
|
let newItems = currentUrls;
|
||||||
|
|
||||||
if (passedClaims) {
|
// Passed uris to add/remove:
|
||||||
|
if (uris) {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
const passedUrls = passedClaims.map((claim) => claim.permanent_url);
|
// Filters (removes) the passed uris from the current list items
|
||||||
// $FlowFixMe // need this?
|
newItems = currentUrls.filter((url) => url && !uris.includes(url));
|
||||||
newItems = currentItems.filter((item: string) => !passedUrls.includes(item));
|
|
||||||
} else {
|
} else {
|
||||||
passedClaims.forEach((claim) => newItems.push(claim.permanent_url));
|
// Pushes (adds to the end) the passed uris to the current list items
|
||||||
}
|
uris.forEach((url) => newItems.push(url));
|
||||||
}
|
|
||||||
|
|
||||||
if (claimIds) {
|
|
||||||
const batches = [];
|
|
||||||
if (claimIds.length > 50) {
|
|
||||||
for (let i = 0; i < Math.ceil(claimIds.length / 50); i++) {
|
|
||||||
batches[i] = claimIds.slice(i * 50, (i + 1) * 50);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
batches[0] = claimIds;
|
|
||||||
}
|
|
||||||
const resultArray = await Promise.all(
|
|
||||||
batches.map((batch) => {
|
|
||||||
let options = { claim_ids: batch, page: 1, page_size: 50 };
|
|
||||||
return dispatch(doClaimSearch(options));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const searchResults = Object.assign({}, ...resultArray);
|
|
||||||
|
|
||||||
if (replace) {
|
|
||||||
newItems = generateCollectionItemsFromSearchResult(searchResults);
|
|
||||||
} else {
|
|
||||||
newItems = currentItems.concat(generateCollectionItemsFromSearchResult(searchResults));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Passed an ordering to change: (doesn't need the uris here since
|
||||||
|
// the items are already on the list)
|
||||||
if (order) {
|
if (order) {
|
||||||
const [movedItem] = currentItems.splice(order.from, 1);
|
const [movedItem] = currentUrls.splice(order.from, 1);
|
||||||
currentItems.splice(order.to, 0, movedItem);
|
currentUrls.splice(order.to, 0, movedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('p&e', publishedCollection.items, newItems, publishedCollection.items.join(','), newItems.join(','))
|
// Delete 'edited' if newItems are the same as publishedItems
|
||||||
if (editedCollection) {
|
if (editedCollection && newItems && publishedCollection.items.join(',') === newItems.join(',')) {
|
||||||
// delete edited if newItems are the same as publishedItems
|
dispatch({ type: ACTIONS.COLLECTION_DELETE, data: { id: collectionId, collectionKey: 'edited' } });
|
||||||
if (publishedCollection.items.join(',') === newItems.join(',')) {
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COLLECTION_DELETE,
|
|
||||||
data: {
|
|
||||||
id: collectionId,
|
|
||||||
collectionKey: 'edited',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.COLLECTION_EDIT,
|
type: ACTIONS.COLLECTION_EDIT,
|
||||||
data: {
|
data: {
|
||||||
id: collectionId,
|
id: collectionId,
|
||||||
collectionKey: 'edited',
|
collectionKey:
|
||||||
collection: {
|
((editedCollection || publishedCollection) && 'edited') ||
|
||||||
items: newItems,
|
(COLS.BUILTIN_LISTS.includes(collectionId) && 'builtin') ||
|
||||||
id: collectionId,
|
(unpublishedCollection && 'unpublished'),
|
||||||
name: params.name || collection.name,
|
|
||||||
updatedAt: getTimestamp(),
|
|
||||||
type: collectionType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (publishedCollection) {
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COLLECTION_EDIT,
|
|
||||||
data: {
|
|
||||||
id: collectionId,
|
|
||||||
collectionKey: 'edited',
|
|
||||||
collection: {
|
|
||||||
items: newItems,
|
|
||||||
id: collectionId,
|
|
||||||
name: params.name || collection.name,
|
|
||||||
updatedAt: getTimestamp(),
|
|
||||||
type: collectionType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (COLS.BUILTIN_LISTS.includes(collectionId)) {
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COLLECTION_EDIT,
|
|
||||||
data: {
|
|
||||||
id: collectionId,
|
|
||||||
collectionKey: 'builtin',
|
|
||||||
collection: {
|
|
||||||
items: newItems,
|
|
||||||
id: collectionId,
|
|
||||||
name: params.name || collection.name,
|
|
||||||
updatedAt: getTimestamp(),
|
|
||||||
type: collectionType,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (unpublishedCollection) {
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COLLECTION_EDIT,
|
|
||||||
data: {
|
|
||||||
id: collectionId,
|
|
||||||
collectionKey: 'unpublished',
|
|
||||||
collection: {
|
collection: {
|
||||||
items: newItems,
|
items: newItems,
|
||||||
id: collectionId,
|
id: collectionId,
|
||||||
|
@ -482,5 +371,6 @@ export const doCollectionEdit = (collectionId: string, params: CollectionEditPar
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -156,13 +156,13 @@ export const makeSelectClaimIdsForCollectionId = (id: string) =>
|
||||||
return ids;
|
return ids;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const makeSelectIndexForUrlInCollection = (url: string, id: string) =>
|
export const makeSelectIndexForUrlInCollection = (url: string, id: string, ignoreShuffle?: boolean) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
(state) => state.content.shuffleList,
|
(state) => state.content.shuffleList,
|
||||||
makeSelectUrlsForCollectionId(id),
|
makeSelectUrlsForCollectionId(id),
|
||||||
makeSelectClaimForUri(url),
|
makeSelectClaimForUri(url),
|
||||||
(shuffleState, urls, claim) => {
|
(shuffleState, urls, claim) => {
|
||||||
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
|
const shuffleUrls = !ignoreShuffle && shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
|
||||||
const listUrls = shuffleUrls || urls;
|
const listUrls = shuffleUrls || urls;
|
||||||
|
|
||||||
const index = listUrls && listUrls.findIndex((u) => u === url);
|
const index = listUrls && listUrls.findIndex((u) => u === url);
|
||||||
|
|
|
@ -66,3 +66,5 @@
|
||||||
@import 'component/empty';
|
@import 'component/empty';
|
||||||
@import 'component/stripe-card';
|
@import 'component/stripe-card';
|
||||||
@import 'component/wallet-tip-send';
|
@import 'component/wallet-tip-send';
|
||||||
|
@import 'component/swipe-list';
|
||||||
|
@import 'component/utils';
|
||||||
|
|
|
@ -120,7 +120,7 @@
|
||||||
order: 1;
|
order: 1;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 -2 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E");
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E");
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus:not(:focus-visible) {
|
&:focus:not(:focus-visible) {
|
||||||
|
@ -128,7 +128,7 @@
|
||||||
// see: https://github.com/lbryio/lbry-desktop/pull/5549#discussion_r580406932
|
// see: https://github.com/lbryio/lbry-desktop/pull/5549#discussion_r580406932
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 -2 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E");
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-monitor'%3E%3Crect x='2' y='3' width='20' height='14' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='8' y1='21' x2='16' y2='21'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12' y2='21'%3E%3C/line%3E%3C/svg%3E");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,26 +148,35 @@
|
||||||
|
|
||||||
.vjs-button--play-next.vjs-button {
|
.vjs-button--play-next.vjs-button {
|
||||||
order: 0;
|
order: 0;
|
||||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-forward'%3e%3cpolygon points='5 4 15 12 5 20 5 4'%3e%3c/polygon%3e%3cline x1='19' y1='5' x2='19' y2='19'%3e%3c/line%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-forward'%3e%3cpolygon points='5 4 15 12 5 20 5 4'%3e%3c/polygon%3e%3cline x1='19' y1='5' x2='19' y2='19'%3e%3c/line%3e%3c/svg%3e");
|
||||||
|
|
||||||
&:focus:not(:focus-visible) {
|
&:focus:not(:focus-visible) {
|
||||||
order: 0;
|
order: 0;
|
||||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-forward'%3e%3cpolygon points='5 4 15 12 5 20 5 4'%3e%3c/polygon%3e%3cline x1='19' y1='5' x2='19' y2='19'%3e%3c/line%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-forward'%3e%3cpolygon points='5 4 15 12 5 20 5 4'%3e%3c/polygon%3e%3cline x1='19' y1='5' x2='19' y2='19'%3e%3c/line%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vjs-button--play-previous.vjs-button {
|
.vjs-button--play-previous.vjs-button {
|
||||||
order: 0;
|
order: 0;
|
||||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-back'%3e%3cpolygon points='19 20 9 12 19 4 19 20'%3e%3c/polygon%3e%3cline x1='5' y1='19' x2='5' y2='5'%3e%3c/line%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-back'%3e%3cpolygon points='19 20 9 12 19 4 19 20'%3e%3c/polygon%3e%3cline x1='5' y1='19' x2='5' y2='5'%3e%3c/line%3e%3c/svg%3e");
|
||||||
|
|
||||||
&:focus:not(:focus-visible) {
|
&:focus:not(:focus-visible) {
|
||||||
order: 0;
|
order: 0;
|
||||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='18' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-back'%3e%3cpolygon points='19 20 9 12 19 4 19 20'%3e%3c/polygon%3e%3cline x1='5' y1='19' x2='5' y2='5'%3e%3c/line%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='19' height='19' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-skip-back'%3e%3cpolygon points='19 20 9 12 19 4 19 20'%3e%3c/polygon%3e%3cline x1='5' y1='19' x2='5' y2='5'%3e%3c/line%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vjs-button--autoplay-next.vjs-button {
|
.vjs-button--autoplay-next.vjs-button {
|
||||||
margin: auto;
|
// TODO: the width and height of a vjs-button should probably retain
|
||||||
|
// its default "100%" value, so that each control-bar button have the same
|
||||||
|
// touch area size. Anything inside (like this on/off switch, or icons)
|
||||||
|
// should be a child (e.g. vjs-icon-placeholder), so that inner margins will
|
||||||
|
// also be consistent.
|
||||||
|
//
|
||||||
|
// TEMP: for now, just hardcode the left-right margin so that it looks
|
||||||
|
// equally spaced compared to its siblings.
|
||||||
|
margin: auto 0.5rem auto 0.7rem;
|
||||||
|
|
||||||
order: 1;
|
order: 1;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
@ -616,16 +625,17 @@ svg + .button__label {
|
||||||
background-color: var(--color-button-alt-bg);
|
background-color: var(--color-button-alt-bg);
|
||||||
color: var(--color-button-alt-text);
|
color: var(--color-button-alt-text);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-button-alt-bg-hover);
|
background-color: var(--color-button-alt-bg-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
&:focus {
|
||||||
padding: var(--spacing-s) var(--spacing-s);
|
background-color: var(--color-button-alt-bg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.top-right {
|
&.top-right {
|
||||||
|
@ -648,6 +658,15 @@ svg + .button__label {
|
||||||
&.button-collection-delete-cancel {
|
&.button-collection-delete-cancel {
|
||||||
background-color: red;
|
background-color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.button-collection-drag {
|
||||||
|
cursor: grab;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: var(--spacing-xs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-toggle--expandformobile {
|
.button-toggle--expandformobile {
|
||||||
|
|
|
@ -216,8 +216,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.claim-preview--collection-mine {
|
.claim-preview--collection-mine {
|
||||||
padding-left: 7rem;
|
padding-left: 9rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
padding-left: 6.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.claim-preview--pending {
|
.claim-preview--pending {
|
||||||
|
@ -240,7 +244,6 @@
|
||||||
.claim-preview__actions {
|
.claim-preview__actions {
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
justify-content: flex-end;
|
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +253,6 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.claim-preview__actions {
|
|
||||||
margin-left: var(--spacing-m);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-xsmall) {
|
@media (max-width: $breakpoint-xsmall) {
|
||||||
|
@ -541,6 +540,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.claim-preview--horizontal-tile {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.claim-tile__title {
|
.claim-tile__title {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: var(--spacing-s);
|
padding: var(--spacing-s);
|
||||||
|
@ -551,7 +556,7 @@
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
min-height: 2rem;
|
min-height: 3.2rem;
|
||||||
|
|
||||||
@media (min-width: $breakpoint-small) {
|
@media (min-width: $breakpoint-small) {
|
||||||
min-height: 2.5rem;
|
min-height: 2.5rem;
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
padding-top: var(--spacing-m);
|
padding-top: var(--spacing-m);
|
||||||
padding-bottom: var(--spacing-m);
|
padding-bottom: var(--spacing-m);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,10 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
flex-grow: 4;
|
flex-grow: 4;
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.collection-edit__header {
|
.collection-edit__header {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
min-height: calc(100vh - var(--header-height));
|
min-height: 100vh;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-top: var(--header-height);
|
margin-top: var(--header-height);
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
padding: var(--spacing-xs);
|
padding: var(--spacing-xs);
|
||||||
padding-top: var(--spacing-m);
|
margin-top: var(--header-height-mobile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: $breakpoint-large) {
|
@media (min-width: $breakpoint-large) {
|
||||||
|
@ -42,20 +42,51 @@
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-wrapper__inner--auth {
|
||||||
|
min-height: unset;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar--pusher {
|
||||||
|
animation-timing-function: var(--resizing-animation-function);
|
||||||
|
transition: transform var(--resizing-animation-timing);
|
||||||
|
transform-origin: left;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
transform: translateX(0);
|
||||||
|
width: calc(100% - var(--spacing-m));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $breakpoint-small) {
|
||||||
|
transform: translateX(var(--side-nav-width--micro));
|
||||||
|
width: calc(100% - ((var(--side-nav-width--micro))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar--pusher--filepage {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar--pusher--open {
|
||||||
|
@media (min-width: $breakpoint-medium) {
|
||||||
|
transform: translateX(var(--side-nav-width));
|
||||||
|
width: calc(100% - var(--side-nav-width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100% - var(--side-nav-width) - var(--spacing-l));
|
width: calc(100% - 2 * var(--spacing-l));
|
||||||
max-width: var(--page-max-width);
|
max-width: var(--page-max-width);
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
min-height: calc(100vh - var(--header-height));
|
||||||
|
|
||||||
@media (max-width: $breakpoint-medium) and (min-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
margin: 0 var(--spacing-l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: $breakpoint-medium) {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-height: calc(100vh - var(--header-height-mobile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,13 +158,7 @@
|
||||||
margin-left: var(--spacing-m);
|
margin-left: var(--spacing-m);
|
||||||
|
|
||||||
.card__header--between {
|
.card__header--between {
|
||||||
padding: var(--spacing-s) var(--spacing-s) var(--spacing-s) var(--spacing-s);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.card__title-actions {
|
|
||||||
padding: 0 0 0 0;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@media (max-width: $breakpoint-medium) {
|
@media (max-width: $breakpoint-medium) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -148,7 +173,18 @@
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
.card__header--between {
|
.card__header--between {
|
||||||
padding: var(--spacing-s) var(--spacing-s) var(--spacing-s) var(--spacing-s);
|
align-items: flex-start !important;
|
||||||
|
|
||||||
|
.card__title-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
padding: var(--spacing-s);
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: var(--spacing-xxs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-page__recommended-collection__row {
|
.file-page__recommended-collection__row {
|
||||||
|
@ -162,6 +198,15 @@
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collection-preview__edit-group {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim-preview--collection-mine {
|
||||||
|
padding-left: 6.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: $breakpoint-medium) {
|
@media (max-width: $breakpoint-medium) {
|
||||||
|
@ -221,12 +266,7 @@
|
||||||
|
|
||||||
.main--full-width {
|
.main--full-width {
|
||||||
@extend .main;
|
@extend .main;
|
||||||
|
|
||||||
@media (min-width: $breakpoint-large) {
|
|
||||||
max-width: none;
|
max-width: none;
|
||||||
width: 100%;
|
|
||||||
margin: 0 var(--spacing-l);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main--auth-page {
|
.main--auth-page {
|
||||||
|
@ -250,6 +290,10 @@
|
||||||
margin-top: var(--spacing-m);
|
margin-top: var(--spacing-m);
|
||||||
padding: 0 var(--spacing-m);
|
padding: 0 var(--spacing-m);
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
padding: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
.card__subtitle {
|
.card__subtitle {
|
||||||
margin: 0 0 var(--spacing-s) 0;
|
margin: 0 0 var(--spacing-s) 0;
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
|
@ -393,18 +437,25 @@
|
||||||
.main__sign-up--graphic {
|
.main__sign-up--graphic {
|
||||||
max-width: 47rem;
|
max-width: 47rem;
|
||||||
|
|
||||||
|
.card__first-pane {
|
||||||
|
width: 50%;
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.card__second-pane {
|
.card__second-pane {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
@media (max-width: $breakpoint-small) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: var(--color-login-graphic-background);
|
background: var(--color-login-graphic-background);
|
||||||
|
|
||||||
@media (max-width: $breakpoint-small) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signup-image {
|
.signup-image {
|
||||||
@media (max-width: $breakpoint-small) {
|
@media (max-width: $breakpoint-small) {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
@ -413,7 +464,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__title {
|
.card__title {
|
||||||
font-size: var(--font-heading);
|
font-size: var(--font-title);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
ui/scss/component/_swipe-list.scss
Normal file
13
ui/scss/component/_swipe-list.scss
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.swipe-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
scroll-snap-type: x mandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swipe-list__item {
|
||||||
|
width: 80vw;
|
||||||
|
margin-right: var(--spacing-s);
|
||||||
|
flex-shrink: 0;
|
||||||
|
scroll-snap-align: start;
|
||||||
|
}
|
92
ui/scss/component/_utils.scss
Normal file
92
ui/scss/component/_utils.scss
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.opacity-40 {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-12 {
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-0 {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-s {
|
||||||
|
margin-top: var(--spacing-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-m {
|
||||||
|
margin-top: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-m {
|
||||||
|
margin-bottom: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-xl {
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-s {
|
||||||
|
margin-left: var(--spacing-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-m {
|
||||||
|
margin-left: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-m {
|
||||||
|
margin-right: var(--spacing-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-0 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-s {
|
||||||
|
font-size: var(--font-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $breakpoint-small) {
|
||||||
|
.md\:items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.md\:flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.md\:ml-m {
|
||||||
|
margin-left: var(--spacing-m);
|
||||||
|
}
|
||||||
|
.md\:flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.md\:w-auto {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.md\:mt-0 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.md\:mb-xl {
|
||||||
|
margin-bottom: var(--spacing-xl);
|
||||||
|
}
|
||||||
|
.md\:h-12 {
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import * as CS from 'constants/claim_search';
|
||||||
import { parseURI } from 'util/lbryURI';
|
import { parseURI } from 'util/lbryURI';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { toCapitalCase } from 'util/string';
|
import { toCapitalCase } from 'util/string';
|
||||||
import { useIsLargeScreen } from 'effects/use-screensize';
|
|
||||||
import { CUSTOM_HOMEPAGE } from 'config';
|
import { CUSTOM_HOMEPAGE } from 'config';
|
||||||
|
|
||||||
export type RowDataItem = {
|
export type RowDataItem = {
|
||||||
|
@ -125,6 +124,7 @@ export const getHomepageRowForCat = (cat: HomepageCat) => {
|
||||||
|
|
||||||
export function GetLinksData(
|
export function GetLinksData(
|
||||||
all: any, // HomepageData type?
|
all: any, // HomepageData type?
|
||||||
|
isLargeScreen: boolean,
|
||||||
isHomepage?: boolean = false,
|
isHomepage?: boolean = false,
|
||||||
authenticated?: boolean,
|
authenticated?: boolean,
|
||||||
showPersonalizedChannels?: boolean,
|
showPersonalizedChannels?: boolean,
|
||||||
|
@ -134,8 +134,6 @@ export function GetLinksData(
|
||||||
showIndividualTags?: boolean,
|
showIndividualTags?: boolean,
|
||||||
showNsfw?: boolean
|
showNsfw?: boolean
|
||||||
) {
|
) {
|
||||||
const isLargeScreen = useIsLargeScreen();
|
|
||||||
|
|
||||||
function getPageSize(originalSize) {
|
function getPageSize(originalSize) {
|
||||||
return isLargeScreen ? originalSize * (3 / 2) : originalSize;
|
return isLargeScreen ? originalSize * (3 / 2) : originalSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { MATURE_TAGS } from 'constants/tags';
|
import { MATURE_TAGS } from 'constants/tags';
|
||||||
|
import { parseURI } from 'util/lbryURI';
|
||||||
|
|
||||||
const matureTagMap = MATURE_TAGS.reduce((acc, tag) => ({ ...acc, [tag]: true }), {});
|
const matureTagMap = MATURE_TAGS.reduce((acc, tag) => ({ ...acc, [tag]: true }), {});
|
||||||
|
|
||||||
|
@ -66,6 +67,28 @@ export function filterClaims(claims: Array<Claim>, query: ?string): Array<Claim>
|
||||||
return claims;
|
return claims;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the claim is a channel.
|
||||||
|
*
|
||||||
|
* @param claim
|
||||||
|
* @param uri An abandoned claim will be null, so provide the `uri` as a fallback to parse.
|
||||||
|
*/
|
||||||
|
export function isChannelClaim(claim: ?Claim, uri?: string) {
|
||||||
|
// 1. parseURI can't resolve a repost's channel, so a `claim` will be needed.
|
||||||
|
// 2. parseURI is still needed to cover the case of abandoned claims.
|
||||||
|
if (claim) {
|
||||||
|
return claim.value_type === 'channel';
|
||||||
|
} else if (uri) {
|
||||||
|
try {
|
||||||
|
return Boolean(parseURI(uri).isChannel);
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getChannelIdFromClaim(claim: ?Claim) {
|
export function getChannelIdFromClaim(claim: ?Claim) {
|
||||||
if (claim) {
|
if (claim) {
|
||||||
if (claim.value_type === 'channel') {
|
if (claim.value_type === 'channel') {
|
||||||
|
|
|
@ -4,14 +4,20 @@ export function toCapitalCase(string: string) {
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toCompactNotation(number: string | number, lang: ?string) {
|
export function toCompactNotation(number: string | number, lang: ?string, minThresholdToApply?: string | number) {
|
||||||
|
const locale = lang || 'en';
|
||||||
|
|
||||||
|
if (minThresholdToApply && Number(number) >= Number(minThresholdToApply)) {
|
||||||
try {
|
try {
|
||||||
return Number(number).toLocaleString(lang || 'en', {
|
return Number(number).toLocaleString(locale, {
|
||||||
compactDisplay: 'short',
|
compactDisplay: 'short',
|
||||||
notation: 'compact',
|
notation: 'compact',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Not all browsers support the addition options.
|
// Not all browsers support the additional options.
|
||||||
return Number(number).toLocaleString();
|
return Number(number).toLocaleString(locale);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Number(number).toLocaleString(locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
395
yarn.lock
395
yarn.lock
|
@ -1167,7 +1167,14 @@
|
||||||
core-js-pure "^3.0.0"
|
core-js-pure "^3.0.0"
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4":
|
"@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.5", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4":
|
||||||
|
version "7.10.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
|
||||||
|
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5":
|
||||||
version "7.14.6"
|
version "7.14.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.6.tgz#535203bc0892efc7dec60bdc27b2ecf6e409062d"
|
||||||
integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
|
integrity sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==
|
||||||
|
@ -1181,6 +1188,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.15.4", "@babel/runtime@^7.9.2":
|
||||||
|
version "7.16.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
|
||||||
|
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.10.1", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
|
"@babel/template@^7.10.1", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
|
||||||
version "7.10.1"
|
version "7.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
||||||
|
@ -1287,9 +1301,9 @@
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@datapunt/matomo-tracker-js@^0.1.4":
|
"@datapunt/matomo-tracker-js@^0.1.4":
|
||||||
version "0.1.4"
|
version "0.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@datapunt/matomo-tracker-js/-/matomo-tracker-js-0.1.4.tgz#1226f0964d2c062bf9392e9c2fd89838262b10df"
|
resolved "https://registry.yarnpkg.com/@datapunt/matomo-tracker-js/-/matomo-tracker-js-0.1.5.tgz#650396e2d8d9d905c04c94e637cbc21c07648d02"
|
||||||
integrity sha512-bi8/guszgciSNLJQIFgph27AzkiCF1DmLBxtmJE3CsLxfc0aTgI2vMg3EFoLv13Mu8HLaCs27Z7vbttlD6jp5w==
|
integrity sha512-4L4y5XlVVfJYeyUY1F3iuG55tWBdM5xODtOJSc4LmxTIeTVMKPdI8VbPG3h/2BzO1xxk/p71XakGlemYzn0inw==
|
||||||
|
|
||||||
"@develar/schema-utils@~2.6.5":
|
"@develar/schema-utils@~2.6.5":
|
||||||
version "2.6.5"
|
version "2.6.5"
|
||||||
|
@ -1552,9 +1566,9 @@
|
||||||
fastq "^1.6.0"
|
fastq "^1.6.0"
|
||||||
|
|
||||||
"@npmcli/fs@^1.0.0":
|
"@npmcli/fs@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f"
|
resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.0.tgz#bec1d1b89c170d40e1b73ad6c943b0b75e7d2951"
|
||||||
integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==
|
integrity sha512-VhP1qZLXcrXRIaPoqb4YA55JQxLNF3jNR4T55IdOJa3+IFJKNYHtPvtXx8slmeMavj37vCzCfrqQM1vWLsYKLA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@gar/promisify" "^1.0.1"
|
"@gar/promisify" "^1.0.1"
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
|
@ -1964,6 +1978,14 @@
|
||||||
"@types/minimatch" "*"
|
"@types/minimatch" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/hoist-non-react-statics@^3.3.0":
|
||||||
|
version "3.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||||
|
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
|
||||||
"@types/html-minifier-terser@^5.0.0":
|
"@types/html-minifier-terser@^5.0.0":
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
|
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
|
||||||
|
@ -2000,9 +2022,9 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
|
||||||
|
|
||||||
"@types/node@^14.6.2":
|
"@types/node@^14.6.2":
|
||||||
version "14.18.1"
|
version "14.18.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.1.tgz#459886b51f52aa923dc06b9ea81cb8b1d733e9d3"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.9.tgz#0e5944eefe2b287391279a19b407aa98bd14436d"
|
||||||
integrity sha512-fTFWOFrgAkj737w1o0HLTIgisgYHnsZfeiqhG1Ltrf/iJjudEbUwetQAsfrtVE49JGwvpEzQR+EbMkIqG4227g==
|
integrity sha512-j11XSuRuAlft6vLDEX4RvhqC0KxNxx6QIyMXNb0vHHSNPXTPeiy3algESWmOOIzEtiEL0qiowPU3ewW9hHVa7Q==
|
||||||
|
|
||||||
"@types/normalize-package-data@^2.4.0":
|
"@types/normalize-package-data@^2.4.0":
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
|
@ -2034,6 +2056,16 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-redux@^7.1.20":
|
||||||
|
version "7.1.21"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.21.tgz#f32bbaf7cbc4b93f51e10d340aa54035c084b186"
|
||||||
|
integrity sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w==
|
||||||
|
dependencies:
|
||||||
|
"@types/hoist-non-react-statics" "^3.3.0"
|
||||||
|
"@types/react" "*"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
redux "^4.0.0"
|
||||||
|
|
||||||
"@types/react-transition-group@^4.4.4":
|
"@types/react-transition-group@^4.4.4":
|
||||||
version "4.4.4"
|
version "4.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
||||||
|
@ -2143,20 +2175,52 @@
|
||||||
resolved "https://registry.yarnpkg.com/@ungap/from-entries/-/from-entries-0.2.1.tgz#7e86196b8b2e99d73106a8f25c2a068326346354"
|
resolved "https://registry.yarnpkg.com/@ungap/from-entries/-/from-entries-0.2.1.tgz#7e86196b8b2e99d73106a8f25c2a068326346354"
|
||||||
integrity sha512-CAqefTFAfnUPwYqsWHXpOxHaq1Zo5UQ3m9Zm2p09LggGe57rqHoBn3c++xcoomzXKynAUuiBMDUCQvKMnXjUpA==
|
integrity sha512-CAqefTFAfnUPwYqsWHXpOxHaq1Zo5UQ3m9Zm2p09LggGe57rqHoBn3c++xcoomzXKynAUuiBMDUCQvKMnXjUpA==
|
||||||
|
|
||||||
"@videojs/http-streaming@2.9.2":
|
"@videojs/http-streaming@2.10.2":
|
||||||
version "2.9.2"
|
version "2.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.9.2.tgz#47d33bb02bd9c1287200398b1e85d213dee814d0"
|
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.10.2.tgz#02e6fcfa74f7850b5f9eb40a8e5c85c9d7d33eaf"
|
||||||
integrity sha512-2ZsxJn4/nZZ6k6jIhic2l9ynGmKwprtuI5b3+M6JgqOSLvQQ/ah+heVs/0g2Ze7qJxodqR+aSY948JwJIz1gCw==
|
integrity sha512-JTAlAUHzj0sTsge2WBh4DWKM2I5BDFEZYOvzxmsK/ySILmI0GRyjAHx9uid68ZECQ2qbEAIRmZW5lWp0R5PeNA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.12.5"
|
"@babel/runtime" "^7.12.5"
|
||||||
"@videojs/vhs-utils" "^3.0.2"
|
"@videojs/vhs-utils" "3.0.3"
|
||||||
aes-decrypter "3.1.2"
|
aes-decrypter "3.1.2"
|
||||||
global "^4.4.0"
|
global "^4.4.0"
|
||||||
m3u8-parser "4.7.0"
|
m3u8-parser "4.7.0"
|
||||||
mpd-parser "0.17.0"
|
mpd-parser "0.19.0"
|
||||||
mux.js "5.12.2"
|
mux.js "5.13.0"
|
||||||
video.js "^6 || ^7"
|
video.js "^6 || ^7"
|
||||||
|
|
||||||
|
"@videojs/http-streaming@2.12.0":
|
||||||
|
version "2.12.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.12.0.tgz#850069e063e26cf2fa5ed9bb3addfc92fa899f78"
|
||||||
|
integrity sha512-vdQA0lDYBXGJqV2T02AGqg1w4dcgyRoN+bYG+G8uF4DpCEMhEtUI0BA4tRu4/Njar8w/9D5k0a1KX40pcvM3fA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@videojs/vhs-utils" "3.0.4"
|
||||||
|
aes-decrypter "3.1.2"
|
||||||
|
global "^4.4.0"
|
||||||
|
m3u8-parser "4.7.0"
|
||||||
|
mpd-parser "0.19.2"
|
||||||
|
mux.js "5.14.1"
|
||||||
|
video.js "^6 || ^7"
|
||||||
|
|
||||||
|
"@videojs/vhs-utils@3.0.3":
|
||||||
|
version "3.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.3.tgz#708bc50742e9481712039695299b32da6582ef92"
|
||||||
|
integrity sha512-bU7daxDHhzcTDbmty1cXjzsTYvx2cBGbA8hG5H2Gvpuk4sdfuvkZtMCwtCqL59p6dsleMPspyaNS+7tWXx2Y0A==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
global "^4.4.0"
|
||||||
|
url-toolkit "^2.2.1"
|
||||||
|
|
||||||
|
"@videojs/vhs-utils@3.0.4", "@videojs/vhs-utils@^3.0.3":
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.4.tgz#e253eecd8e9318f767e752010d213587f94bb03a"
|
||||||
|
integrity sha512-hui4zOj2I1kLzDgf8QDVxD3IzrwjS/43KiS8IHQO0OeeSsb4pB/lgNt1NG7Dv0wMQfCccUpMVLGcK618s890Yg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
global "^4.4.0"
|
||||||
|
url-toolkit "^2.2.1"
|
||||||
|
|
||||||
"@videojs/vhs-utils@^3.0.0", "@videojs/vhs-utils@^3.0.2":
|
"@videojs/vhs-utils@^3.0.0", "@videojs/vhs-utils@^3.0.2":
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.2.tgz#0203418ecaaff29bc33c69b6ad707787347b7614"
|
resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.2.tgz#0203418ecaaff29bc33c69b6ad707787347b7614"
|
||||||
|
@ -2166,10 +2230,10 @@
|
||||||
global "^4.4.0"
|
global "^4.4.0"
|
||||||
url-toolkit "^2.2.1"
|
url-toolkit "^2.2.1"
|
||||||
|
|
||||||
"@videojs/xhr@2.5.1":
|
"@videojs/xhr@2.6.0":
|
||||||
version "2.5.1"
|
version "2.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@videojs/xhr/-/xhr-2.5.1.tgz#26bc5a79dbb3b03bfb13742c6ce559f89e90719e"
|
resolved "https://registry.yarnpkg.com/@videojs/xhr/-/xhr-2.6.0.tgz#cd897e0ad54faf497961bcce3fa16dc15a26bb80"
|
||||||
integrity sha512-wV9nGESHseSK+S9ePEru2+OJZ1jq/ZbbzniGQ4weAmTIepuBMSYPx5zrxxQA0E786T5ykpO8ts+LayV+3/oI2w==
|
integrity sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.5.5"
|
"@babel/runtime" "^7.5.5"
|
||||||
global "~4.4.0"
|
global "~4.4.0"
|
||||||
|
@ -2325,6 +2389,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1"
|
resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1"
|
||||||
integrity sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw==
|
integrity sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw==
|
||||||
|
|
||||||
|
"@xmldom/xmldom@^0.7.2":
|
||||||
|
version "0.7.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d"
|
||||||
|
integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==
|
||||||
|
|
||||||
"@xtuc/ieee754@^1.2.0":
|
"@xtuc/ieee754@^1.2.0":
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
||||||
|
@ -3719,14 +3788,10 @@ codemirror-spell-checker@1.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
typo-js "*"
|
typo-js "*"
|
||||||
|
|
||||||
codemirror@^5.39.2:
|
codemirror@^5.39.2, codemirror@^5.58.2:
|
||||||
version "5.52.0"
|
version "5.63.3"
|
||||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.52.0.tgz#4dbd6aef7f0e63db826b9a23922f0c03ac75c0a7"
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.63.3.tgz#97042a242027fe0c87c09b36bc01931d37b76527"
|
||||||
|
integrity sha512-1C+LELr+5grgJYqwZKqxrcbPsHFHapVaVAloBsFBASbpLnQqLw1U8yXJ3gT5D+rhxIiSpo+kTqN+hQ+9ialIXw==
|
||||||
codemirror@^5.58.2:
|
|
||||||
version "5.59.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.59.2.tgz#ee674d3a4a8d241af38d52afc482625ba7393922"
|
|
||||||
integrity sha512-/D5PcsKyzthtSy2NNKCyJi3b+htRkoKv3idswR/tR6UAvMNKA7SrmyZy6fOONJxSRs1JlUWEDAbxqfdArbK8iA==
|
|
||||||
|
|
||||||
collapse-white-space@^1.0.2:
|
collapse-white-space@^1.0.2:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
|
@ -4177,6 +4242,13 @@ crypto-random-string@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||||
|
|
||||||
|
css-box-model@^1.2.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
|
||||||
|
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
|
||||||
|
dependencies:
|
||||||
|
tiny-invariant "^1.0.6"
|
||||||
|
|
||||||
css-color-names@0.0.4, css-color-names@^0.0.4:
|
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
||||||
|
@ -4258,15 +4330,15 @@ css-select@^2.0.0:
|
||||||
nth-check "^1.0.2"
|
nth-check "^1.0.2"
|
||||||
|
|
||||||
css-select@^4.1.3:
|
css-select@^4.1.3:
|
||||||
version "4.2.0"
|
version "4.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.0.tgz#ab28276d3afb00cc05e818bd33eb030f14f57895"
|
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067"
|
||||||
integrity sha512-6YVG6hsH9yIb/si3Th/is8Pex7qnVHO6t7q7U6TIUnkQASGbS8tnUDBftnPynLNnuUl/r2+PTd0ekiiq7R0zJw==
|
integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase "^1.0.0"
|
boolbase "^1.0.0"
|
||||||
css-what "^5.1.0"
|
css-what "^5.0.0"
|
||||||
domhandler "^4.3.0"
|
domhandler "^4.2.0"
|
||||||
domutils "^2.8.0"
|
domutils "^2.6.0"
|
||||||
nth-check "^2.0.1"
|
nth-check "^2.0.0"
|
||||||
|
|
||||||
css-tree@1.0.0-alpha.37:
|
css-tree@1.0.0-alpha.37:
|
||||||
version "1.0.0-alpha.37"
|
version "1.0.0-alpha.37"
|
||||||
|
@ -4283,10 +4355,10 @@ css-what@^3.2.1:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1"
|
||||||
|
|
||||||
css-what@^5.1.0:
|
css-what@^5.0.0:
|
||||||
version "5.1.0"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
|
||||||
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
|
integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
|
||||||
|
|
||||||
cssesc@^3.0.0:
|
cssesc@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -4745,10 +4817,10 @@ domhandler@^3.0.0, domhandler@^3.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "^2.0.1"
|
domelementtype "^2.0.1"
|
||||||
|
|
||||||
domhandler@^4.2.0, domhandler@^4.3.0:
|
domhandler@^4.2.0:
|
||||||
version "4.3.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626"
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
|
||||||
integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==
|
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
|
||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
|
|
||||||
|
@ -4775,10 +4847,10 @@ domutils@^2.0.0:
|
||||||
domelementtype "^2.0.1"
|
domelementtype "^2.0.1"
|
||||||
domhandler "^3.2.0"
|
domhandler "^3.2.0"
|
||||||
|
|
||||||
domutils@^2.8.0:
|
domutils@^2.6.0:
|
||||||
version "2.8.0"
|
version "2.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442"
|
||||||
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
|
integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==
|
||||||
dependencies:
|
dependencies:
|
||||||
dom-serializer "^1.0.1"
|
dom-serializer "^1.0.1"
|
||||||
domelementtype "^2.2.0"
|
domelementtype "^2.2.0"
|
||||||
|
@ -5722,10 +5794,10 @@ fast-diff@^1.1.1:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||||
|
|
||||||
fast-glob@^3.1.1, fast-glob@^3.2.4:
|
fast-glob@^3.2.4, fast-glob@^3.2.9:
|
||||||
version "3.2.7"
|
version "3.2.11"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
|
||||||
integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
|
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nodelib/fs.stat" "^2.0.2"
|
"@nodelib/fs.stat" "^2.0.2"
|
||||||
"@nodelib/fs.walk" "^1.2.3"
|
"@nodelib/fs.walk" "^1.2.3"
|
||||||
|
@ -5998,9 +6070,9 @@ flush-write-stream@^1.0.0:
|
||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
follow-redirects@^1.0.0:
|
follow-redirects@^1.0.0:
|
||||||
version "1.14.7"
|
version "1.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||||
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
|
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||||
|
|
||||||
for-in@^1.0.2:
|
for-in@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
|
@ -6348,15 +6420,15 @@ globalthis@^1.0.1:
|
||||||
define-properties "^1.1.3"
|
define-properties "^1.1.3"
|
||||||
|
|
||||||
globby@^11.0.1:
|
globby@^11.0.1:
|
||||||
version "11.0.4"
|
version "11.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
|
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
||||||
integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
|
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||||
dependencies:
|
dependencies:
|
||||||
array-union "^2.1.0"
|
array-union "^2.1.0"
|
||||||
dir-glob "^3.0.1"
|
dir-glob "^3.0.1"
|
||||||
fast-glob "^3.1.1"
|
fast-glob "^3.2.9"
|
||||||
ignore "^5.1.4"
|
ignore "^5.2.0"
|
||||||
merge2 "^1.3.0"
|
merge2 "^1.4.1"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
globby@^6.1.0:
|
globby@^6.1.0:
|
||||||
|
@ -6912,10 +6984,10 @@ ignore@^5.0.2:
|
||||||
version "5.1.4"
|
version "5.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
|
||||||
|
|
||||||
ignore@^5.1.4:
|
ignore@^5.2.0:
|
||||||
version "5.1.9"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
|
||||||
integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==
|
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
|
||||||
|
|
||||||
imagesloaded@^4.1.4:
|
imagesloaded@^4.1.4:
|
||||||
version "4.1.4"
|
version "4.1.4"
|
||||||
|
@ -8360,12 +8432,17 @@ merge-descriptors@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||||
|
|
||||||
|
merge-refs@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.0.0.tgz#388348bce22e623782c6df9d3c4fc55888276120"
|
||||||
|
integrity sha512-WZ4S5wqD9FCR9hxkLgvcHJCBxzXzy3VVE6p8W2OzxRzB+hLRlcadGE2bW9xp2KSzk10rvp4y+pwwKO6JQVguMg==
|
||||||
|
|
||||||
merge-stream@^2.0.0:
|
merge-stream@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||||
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
|
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
|
||||||
|
|
||||||
merge2@^1.3.0:
|
merge2@^1.3.0, merge2@^1.4.1:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
@ -8631,15 +8708,25 @@ move-concurrently@^1.0.1:
|
||||||
rimraf "^2.5.4"
|
rimraf "^2.5.4"
|
||||||
run-queue "^1.0.3"
|
run-queue "^1.0.3"
|
||||||
|
|
||||||
mpd-parser@0.17.0:
|
mpd-parser@0.19.0:
|
||||||
version "0.17.0"
|
version "0.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.17.0.tgz#d7f3002edcb706f98993ef75846a713d056d3332"
|
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.19.0.tgz#8937044040ca85e20398ecf5d94552655e2c6728"
|
||||||
integrity sha512-oKS5G0jCcHHJ3sHYlcLeM9Xcbuixl08eAx7QW0Th7ChlZiI0YvLtGaHE/L0aKUBJFNvtkeksIr8XgJgSBBsS4g==
|
integrity sha512-FDLIXtZMZs99fv5iXNFg94quNFT26tobo0NUgHu7L3XgZvEq1NBarf5yxDFFJ1zzfbcmtj+NRaml6nYIxoPWvw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.12.5"
|
"@babel/runtime" "^7.12.5"
|
||||||
"@videojs/vhs-utils" "^3.0.2"
|
"@videojs/vhs-utils" "^3.0.2"
|
||||||
|
"@xmldom/xmldom" "^0.7.2"
|
||||||
|
global "^4.4.0"
|
||||||
|
|
||||||
|
mpd-parser@0.19.2:
|
||||||
|
version "0.19.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.19.2.tgz#68611e653cdf2cc1e90688825c4a129b7f9007e0"
|
||||||
|
integrity sha512-M5tAIdtBM2TN+OSTz/37T7V+h9ZLvhyNqq4TNIdtjAQ/Hg8UnMRf5nJQDjffcXag3POXi31yUJQEKOXdcAM/nw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@videojs/vhs-utils" "^3.0.2"
|
||||||
|
"@xmldom/xmldom" "^0.7.2"
|
||||||
global "^4.4.0"
|
global "^4.4.0"
|
||||||
xmldom "^0.5.0"
|
|
||||||
|
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
@ -8669,10 +8756,17 @@ mute-stream@0.0.7:
|
||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||||
|
|
||||||
mux.js@5.12.2:
|
mux.js@5.13.0:
|
||||||
version "5.12.2"
|
version "5.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.12.2.tgz#cd823312f4bb69adb8b9c5f45635b4451066d6e6"
|
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.13.0.tgz#99c3da21f6c0362a1529729d1c5e5b51f34f606d"
|
||||||
integrity sha512-9OY1lrFIo7FxMeIC6aLUftiNv97AztufDfi30N7qDll1Pcy7bCxlHztyHp1Ce0KQwy2XqchGeENPS4v1NJngHQ==
|
integrity sha512-PkmnzHcTQjUBEHp3KRPQAFoNkJtKlpCEvsYtXDfDrC+/WqbMuxHvoYfmAbHVAH7Sa/KliPVU0dT1ureO8wilog==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.11.2"
|
||||||
|
|
||||||
|
mux.js@5.14.1:
|
||||||
|
version "5.14.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.14.1.tgz#209583f454255d9ba2ff1bb61ad5a6867cf61878"
|
||||||
|
integrity sha512-38kA/xjWRDzMbcpHQfhKbJAME8eTZVsb9U2Puk890oGvGqnyu8B/AkKdICKPHkigfqYX9MY20vje88TP14nhog==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.11.2"
|
"@babel/runtime" "^7.11.2"
|
||||||
|
|
||||||
|
@ -8742,9 +8836,9 @@ node-forge@0.9.0:
|
||||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
|
||||||
|
|
||||||
node-html-parser@^5.1.0:
|
node-html-parser@^5.1.0:
|
||||||
version "5.1.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.1.0.tgz#753f5a60cdfe6d027c15857cb817df592c18c998"
|
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.2.0.tgz#6f29fd00d79f65334e7e20200964644207925607"
|
||||||
integrity sha512-l6C1Gf1o7YuxeMGa17PypEez/rj+ii3q4/NZG37nRmWSLDjHyB0WNrlE4h2UW92D0JSfUSfu+lOvxThttVe7Jw==
|
integrity sha512-fmiwLfQu+J2A0zjwSEkztSHexAf5qq/WoiL/Hgo1K7JpfEP+OGWY5maG0kGaM+IFVdixF/1QbyXaQ3h4cGfeLw==
|
||||||
dependencies:
|
dependencies:
|
||||||
css-select "^4.1.3"
|
css-select "^4.1.3"
|
||||||
he "1.2.0"
|
he "1.2.0"
|
||||||
|
@ -8916,10 +9010,10 @@ nth-check@^1.0.2, nth-check@~1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase "~1.0.0"
|
boolbase "~1.0.0"
|
||||||
|
|
||||||
nth-check@^2.0.1:
|
nth-check@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
|
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
|
||||||
integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
|
integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase "^1.0.0"
|
boolbase "^1.0.0"
|
||||||
|
|
||||||
|
@ -9437,9 +9531,9 @@ picomatch@^2.0.4, picomatch@^2.2.1:
|
||||||
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
|
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
|
||||||
|
|
||||||
picomatch@^2.2.3:
|
picomatch@^2.2.3:
|
||||||
version "2.3.0"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||||
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
pify@^2.0.0, pify@^2.3.0:
|
pify@^2.0.0, pify@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
|
@ -10134,6 +10228,11 @@ queue-microtask@^1.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
|
raf-schd@^4.0.2:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
||||||
|
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||||
|
|
||||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
|
@ -10201,6 +10300,19 @@ react-awesome-lightbox@^1.7.3:
|
||||||
resolved "https://registry.yarnpkg.com/react-awesome-lightbox/-/react-awesome-lightbox-1.7.3.tgz#ee1c00fd4197e0e65bf996aa219eac4d8b6db5a0"
|
resolved "https://registry.yarnpkg.com/react-awesome-lightbox/-/react-awesome-lightbox-1.7.3.tgz#ee1c00fd4197e0e65bf996aa219eac4d8b6db5a0"
|
||||||
integrity sha512-mSxdL3KGzuh2eR8I00nv9njiolmMoXITuCvfd71DBXK13JW3e+Z/sCMENS9+dngBJU8/m7dR1Ix0W6afS5cFsA==
|
integrity sha512-mSxdL3KGzuh2eR8I00nv9njiolmMoXITuCvfd71DBXK13JW3e+Z/sCMENS9+dngBJU8/m7dR1Ix0W6afS5cFsA==
|
||||||
|
|
||||||
|
react-beautiful-dnd@^13.1.0:
|
||||||
|
version "13.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz#ec97c81093593526454b0de69852ae433783844d"
|
||||||
|
integrity sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.9.2"
|
||||||
|
css-box-model "^1.2.0"
|
||||||
|
memoize-one "^5.1.1"
|
||||||
|
raf-schd "^4.0.2"
|
||||||
|
react-redux "^7.2.0"
|
||||||
|
redux "^4.0.4"
|
||||||
|
use-memo-one "^1.1.1"
|
||||||
|
|
||||||
react-calendar@^3.3.1:
|
react-calendar@^3.3.1:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.3.1.tgz#da691a5d59c88f178695fd8b33909a71d698021f"
|
resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.3.1.tgz#da691a5d59c88f178695fd8b33909a71d698021f"
|
||||||
|
@ -10236,25 +10348,26 @@ react-confetti@^4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tween-functions "^1.2.0"
|
tween-functions "^1.2.0"
|
||||||
|
|
||||||
react-date-picker@^8.1.0:
|
react-date-picker@^8.3.3:
|
||||||
version "8.1.1"
|
version "8.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.1.1.tgz#1959608cd042c9bfcf2faa6d63a56e9ef6b17e2b"
|
resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.3.6.tgz#446142bee5691aea66a2bac53313357aca561cd4"
|
||||||
integrity sha512-kFhn+uSJML+EuROvR6qLYU5G3wsxrdB2K1ugh1t6HjJCjphE6ot85jb8THWebqWEcQi07pLseU7ZFpzKDD3A6A==
|
integrity sha512-c1rThf0jSKROoSGLpUEPtcC8VE+XoVgqxh+ng9aLYQvjDMGWQBgoat6Qrj8nRVzvCPpdXV4jqiCB3z2vVVuseA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react-calendar" "^3.0.0"
|
"@types/react-calendar" "^3.0.0"
|
||||||
"@wojtekmaj/date-utils" "^1.0.3"
|
"@wojtekmaj/date-utils" "^1.0.3"
|
||||||
get-user-locale "^1.2.0"
|
get-user-locale "^1.2.0"
|
||||||
make-event-props "^1.1.0"
|
make-event-props "^1.1.0"
|
||||||
merge-class-names "^1.1.1"
|
merge-class-names "^1.1.1"
|
||||||
|
merge-refs "^1.0.0"
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
react-calendar "^3.3.1"
|
react-calendar "^3.3.1"
|
||||||
react-fit "^1.0.3"
|
react-fit "^1.0.3"
|
||||||
update-input-width "^1.1.1"
|
update-input-width "^1.2.2"
|
||||||
|
|
||||||
react-datetime-picker@^3.2.1:
|
react-datetime-picker@^3.4.3:
|
||||||
version "3.2.1"
|
version "3.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-datetime-picker/-/react-datetime-picker-3.2.1.tgz#d3a9631bcba17bd0047e6424cff0dfe242d9cf0e"
|
resolved "https://registry.yarnpkg.com/react-datetime-picker/-/react-datetime-picker-3.4.3.tgz#9163471f72b708185482b6b72cd259da03462f79"
|
||||||
integrity sha512-elybaAL7RJG7r0elYZze5/zQo1ds0v+v89tyZkzEShw+6I1EcveXwYPOMj3aq0k7D5kY/K+dC5dWYw0w4d9kmw==
|
integrity sha512-yuFmh3TJwDo3VnyQF6auRJoeYfFTUtyLsR292lWXieigp0ugKkQefUEzVybZQidiiUlCNK9UQgc37/igl7uBYA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@wojtekmaj/date-utils" "^1.0.3"
|
"@wojtekmaj/date-utils" "^1.0.3"
|
||||||
get-user-locale "^1.2.0"
|
get-user-locale "^1.2.0"
|
||||||
|
@ -10263,9 +10376,9 @@ react-datetime-picker@^3.2.1:
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
react-calendar "^3.3.1"
|
react-calendar "^3.3.1"
|
||||||
react-clock "^3.0.0"
|
react-clock "^3.0.0"
|
||||||
react-date-picker "^8.1.0"
|
react-date-picker "^8.3.3"
|
||||||
react-fit "^1.0.3"
|
react-fit "^1.0.3"
|
||||||
react-time-picker "^4.2.0"
|
react-time-picker "^4.4.2"
|
||||||
|
|
||||||
react-dom@^16.8.2:
|
react-dom@^16.8.2:
|
||||||
version "16.13.0"
|
version "16.13.0"
|
||||||
|
@ -10356,6 +10469,18 @@ react-redux@^6.0.1:
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-is "^16.8.2"
|
react-is "^16.8.2"
|
||||||
|
|
||||||
|
react-redux@^7.2.0:
|
||||||
|
version "7.2.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.6.tgz#49633a24fe552b5f9caf58feb8a138936ddfe9aa"
|
||||||
|
integrity sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.15.4"
|
||||||
|
"@types/react-redux" "^7.1.20"
|
||||||
|
hoist-non-react-statics "^3.3.2"
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
react-is "^17.0.2"
|
||||||
|
|
||||||
react-router-dom@^5.1.0:
|
react-router-dom@^5.1.0:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18"
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18"
|
||||||
|
@ -10399,19 +10524,20 @@ react-spring@^8.0.20, react-spring@^8.0.27:
|
||||||
"@babel/runtime" "^7.3.1"
|
"@babel/runtime" "^7.3.1"
|
||||||
prop-types "^15.5.8"
|
prop-types "^15.5.8"
|
||||||
|
|
||||||
react-time-picker@^4.2.0:
|
react-time-picker@^4.4.2:
|
||||||
version "4.2.1"
|
version "4.4.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-time-picker/-/react-time-picker-4.2.1.tgz#b27f0bbc2e58534f20dbf10b14d0b8f3334fcb07"
|
resolved "https://registry.yarnpkg.com/react-time-picker/-/react-time-picker-4.4.4.tgz#a67ca5fd88f51eac0919df802e416d9a25ad726a"
|
||||||
integrity sha512-T0aEabJ3bz54l8LV3pdpB5lOZuO3pRIbry5STcUV58UndlrWLcHpdpvS1IC8JLNXhbLxzGs1MmpASb5k1ddlsg==
|
integrity sha512-WMdrpGnegug0871Do+SU1Fe91uZGmS6JUo1Yw7eLfU3VHMXCFj9sL9FAT6BuXe7lfILBbXq4tQQOqa/rLDASQg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@wojtekmaj/date-utils" "^1.0.0"
|
"@wojtekmaj/date-utils" "^1.0.0"
|
||||||
get-user-locale "^1.2.0"
|
get-user-locale "^1.2.0"
|
||||||
make-event-props "^1.1.0"
|
make-event-props "^1.1.0"
|
||||||
merge-class-names "^1.1.1"
|
merge-class-names "^1.1.1"
|
||||||
|
merge-refs "^1.0.0"
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
react-clock "^3.0.0"
|
react-clock "^3.0.0"
|
||||||
react-fit "^1.0.3"
|
react-fit "^1.0.3"
|
||||||
update-input-width "^1.1.1"
|
update-input-width "^1.2.2"
|
||||||
|
|
||||||
react-transition-group@^4.4.2:
|
react-transition-group@^4.4.2:
|
||||||
version "4.4.2"
|
version "4.4.2"
|
||||||
|
@ -10606,6 +10732,13 @@ redux@^3.6.0:
|
||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
symbol-observable "^1.0.3"
|
symbol-observable "^1.0.3"
|
||||||
|
|
||||||
|
redux@^4.0.0, redux@^4.0.4:
|
||||||
|
version "4.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104"
|
||||||
|
integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.9.2"
|
||||||
|
|
||||||
regenerate-unicode-properties@^8.2.0:
|
regenerate-unicode-properties@^8.2.0:
|
||||||
version "8.2.0"
|
version "8.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
|
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
|
||||||
|
@ -12172,6 +12305,11 @@ tiny-invariant@^1.0.2:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
||||||
|
|
||||||
|
tiny-invariant@^1.0.6:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9"
|
||||||
|
integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==
|
||||||
|
|
||||||
tiny-relative-date@^1.3.0:
|
tiny-relative-date@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
|
resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
|
||||||
|
@ -12646,10 +12784,10 @@ upath@^1.1.1:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
||||||
|
|
||||||
update-input-width@^1.1.1:
|
update-input-width@^1.2.2:
|
||||||
version "1.2.1"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/update-input-width/-/update-input-width-1.2.1.tgz#769d6182413590c3b50b52ffa9c65d79e2c17f95"
|
resolved "https://registry.yarnpkg.com/update-input-width/-/update-input-width-1.2.2.tgz#9a6a35858ae8e66fbfe0304437b23a4934fc7d37"
|
||||||
integrity sha512-zygDshqDb2C2/kgfoD423n5htv/3OBF7aTaz2u2zZy998EJki8njOHOeZjKEd8XSYeDziIX1JXfMsKaIRJeJ/Q==
|
integrity sha512-6QwD9ZVSXb96PxOZ01DU0DJTPwQGY7qBYgdniZKJN02Xzom2m+9J6EPxMbefskqtj4x78qbe5psDSALq9iNEYg==
|
||||||
|
|
||||||
update-notifier@^2.5.0:
|
update-notifier@^2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
|
@ -12741,6 +12879,11 @@ url@^0.11.0:
|
||||||
punycode "1.3.2"
|
punycode "1.3.2"
|
||||||
querystring "0.2.0"
|
querystring "0.2.0"
|
||||||
|
|
||||||
|
use-memo-one@^1.1.1:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.2.tgz#0c8203a329f76e040047a35a1197defe342fab20"
|
||||||
|
integrity sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==
|
||||||
|
|
||||||
use@^3.1.0:
|
use@^3.1.0:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||||
|
@ -12862,21 +13005,40 @@ vfile@^2.0.0:
|
||||||
unist-util-stringify-position "^1.0.0"
|
unist-util-stringify-position "^1.0.0"
|
||||||
vfile-message "^1.0.0"
|
vfile-message "^1.0.0"
|
||||||
|
|
||||||
"video.js@^6 || ^7", video.js@^7.0.0, video.js@^7.14.3:
|
"video.js@^6 || ^7", video.js@^7.0.0:
|
||||||
version "7.14.3"
|
version "7.15.4"
|
||||||
resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.14.3.tgz#0b612c09a0a81ef9bce65c710e73291cb06dc32c"
|
resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.15.4.tgz#0f96ef138035138cb30bf00a989b6174f0d16bac"
|
||||||
integrity sha512-6avCdSIfn5ss5NOgoQfY/xEfPNcz9DXSw+ZN80NwPguCdRd4VL4y40b/d7osYJwyCdF+YkvhqAW7dw4s0vBigg==
|
integrity sha512-hghxkgptLUvfkpktB4wxcIVF3VpY/hVsMkrjHSv0jpj1bW9Jplzdt8IgpTm9YhlB1KYAp07syVQeZcBFUBwhkw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.12.5"
|
"@babel/runtime" "^7.12.5"
|
||||||
"@videojs/http-streaming" "2.9.2"
|
"@videojs/http-streaming" "2.10.2"
|
||||||
"@videojs/vhs-utils" "^3.0.2"
|
"@videojs/vhs-utils" "^3.0.3"
|
||||||
"@videojs/xhr" "2.5.1"
|
"@videojs/xhr" "2.6.0"
|
||||||
aes-decrypter "3.1.2"
|
aes-decrypter "3.1.2"
|
||||||
global "^4.4.0"
|
global "^4.4.0"
|
||||||
keycode "^2.2.0"
|
keycode "^2.2.0"
|
||||||
m3u8-parser "4.7.0"
|
m3u8-parser "4.7.0"
|
||||||
mpd-parser "0.17.0"
|
mpd-parser "0.19.0"
|
||||||
mux.js "5.12.2"
|
mux.js "5.13.0"
|
||||||
|
safe-json-parse "4.0.0"
|
||||||
|
videojs-font "3.2.0"
|
||||||
|
videojs-vtt.js "^0.15.3"
|
||||||
|
|
||||||
|
video.js@^7.14.3:
|
||||||
|
version "7.17.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.17.0.tgz#35918cc03748a5680f5d5f1da410e06eeea7786e"
|
||||||
|
integrity sha512-8RbLu9+Pdpep9OTPncUHIvZXFgn/7hKdPnSTE/lGSnlFSucXtTUBp41R7NDwncscMLQ0WgazUbmFlvr4MNWMbA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.12.5"
|
||||||
|
"@videojs/http-streaming" "2.12.0"
|
||||||
|
"@videojs/vhs-utils" "^3.0.3"
|
||||||
|
"@videojs/xhr" "2.6.0"
|
||||||
|
aes-decrypter "3.1.2"
|
||||||
|
global "^4.4.0"
|
||||||
|
keycode "^2.2.0"
|
||||||
|
m3u8-parser "4.7.0"
|
||||||
|
mpd-parser "0.19.2"
|
||||||
|
mux.js "5.14.1"
|
||||||
safe-json-parse "4.0.0"
|
safe-json-parse "4.0.0"
|
||||||
videojs-font "3.2.0"
|
videojs-font "3.2.0"
|
||||||
videojs-vtt.js "^0.15.3"
|
videojs-vtt.js "^0.15.3"
|
||||||
|
@ -13363,11 +13525,6 @@ xmldom@^0.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
|
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
|
||||||
integrity sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==
|
integrity sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==
|
||||||
|
|
||||||
xmldom@^0.5.0:
|
|
||||||
version "0.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e"
|
|
||||||
integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==
|
|
||||||
|
|
||||||
xpipe@*:
|
xpipe@*:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf"
|
resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf"
|
||||||
|
|
Loading…
Reference in a new issue