diff --git a/static/app-strings.json b/static/app-strings.json index b36842566..4c6fb6ac3 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2220,5 +2220,6 @@ "filtered": "filtered", "View All Playlists": "View All Playlists", "Your wallet is not currently using a cloud sync service. You are in control of backing up your wallet.": "Your wallet is not currently using a cloud sync service. You are in control of backing up your wallet.", + "%action% %collection%": "%action% %collection%", "--end--": "--end--" } diff --git a/ui/component/claimList/view.jsx b/ui/component/claimList/view.jsx index 456c23e0f..3531e4d59 100644 --- a/ui/component/claimList/view.jsx +++ b/ui/component/claimList/view.jsx @@ -78,8 +78,6 @@ export default function ClaimList(props: Props) { noEmpty, } = props; - console.log('noempty', noEmpty); - const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW); // Exclude prefix uris in these results variables. We don't want to show diff --git a/ui/component/claimPreview/collection-buttons.jsx b/ui/component/claimPreview/collection-buttons.jsx new file mode 100644 index 000000000..c9b2e40e4 --- /dev/null +++ b/ui/component/claimPreview/collection-buttons.jsx @@ -0,0 +1,121 @@ +// @flow +import React from 'react'; +import Button from 'component/button'; +import * as ICONS from 'constants/icons'; +type Props = { + collectionIndex?: number, + editCollection: (string, CollectionEditParams) => void, + listId?: string, + lastCollectionIndex?: number, + claim: ?Claim, +}; + +function CollectionButtons(props: Props) { + const { collectionIndex, editCollection, listId, lastCollectionIndex, claim } = props; + const [confirmDelete, setConfirmDelete] = React.useState(false); + return ( + <div className="collection-preview__edit-buttons"> + <div className="collection-preview__edit-group"> + <Button + className={'button-collection-manage top-left'} + icon={ICONS.UP_TOP} + disabled={collectionIndex === 0} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: 0 }, + }); + } + }} + /> + <Button + className={'button-collection-manage bottom-left'} + icon={ICONS.DOWN_BOTTOM} + disabled={collectionIndex === lastCollectionIndex} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: lastCollectionIndex }, + }); + } + }} + /> + </div> + <div className="collection-preview__edit-group"> + <Button + className={'button-collection-manage'} + disabled={collectionIndex === 0} + icon={ICONS.UP} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: Number(collectionIndex) - 1 }, + }); + } + }} + /> + <Button + className={'button-collection-manage'} + icon={ICONS.DOWN} + disabled={collectionIndex === lastCollectionIndex} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: Number(collectionIndex + 1) }, + }); + } + }} + /> + </div> + {!confirmDelete && ( + <div className="collection-preview__edit-group collection-preview__delete "> + <Button + // button="alt" + className={'button-collection-manage button-collection-delete top-right bottom-right'} + icon={ICONS.DELETE} + onClick={(e) => { + setConfirmDelete(true); + }} + /> + </div> + )} + {confirmDelete && ( + <div className="collection-preview__edit-group collection-preview__delete"> + <Button + // button="alt" + className={'button-collection-manage button-collection-delete-cancel top-right'} + icon={ICONS.REMOVE} + onClick={(e) => { + setConfirmDelete(false); + }} + /> + <Button + // button="alt" + className={'button-collection-manage button-collection-delete-confirm bottom-right'} + icon={ICONS.DELETE} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + // $FlowFixMe + if (editCollection) editCollection(listId, { claims: [claim], remove: true }); + }} + /> + </div> + )} + </div> + ); +} + +export default CollectionButtons; diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index f5735efcd..37cdbf044 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -25,6 +25,7 @@ import ClaimMenuList from 'component/claimMenuList'; import ClaimPreviewLoading from './claim-preview-loading'; import ClaimPreviewHidden from './claim-preview-no-mature'; import ClaimPreviewNoContent from './claim-preview-no-content'; +import CollectionEditButtons from './collection-buttons'; import Button from 'component/button'; import * as ICONS from 'constants/icons'; @@ -151,7 +152,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { } = props; const isCollection = claim && claim.value_type === 'collection'; const collectionClaimId = isCollection && claim && claim.claim_id; - const listId = collectionId || collectionClaimId; + const listId = collectionId || collectionClaimId || null; const WrapperElement = wrapperElement || 'li'; const shouldFetch = claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending); @@ -160,6 +161,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { const shouldHideActions = hideActions || isMyCollection || type === 'small' || type === 'tooltip'; const canonicalUrl = claim && claim.canonical_url; const lastCollectionIndex = collectionUris ? collectionUris.length - 1 : 0; + console.log('type', type); const channelSubscribers = React.useMemo(() => { if (channelSubCount === undefined) { return <span />; @@ -347,8 +349,18 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { 'claim-preview--channel': isChannelUri, 'claim-preview--visited': !isChannelUri && !claimIsMine && hasVisitedUri, 'claim-preview--pending': pending, + 'claim-preview--collection-mine': isMyCollection && listId && type === 'listview', })} > + {isMyCollection && listId && type === 'listview' && ( + <CollectionEditButtons + collectionIndex={collectionIndex} + editCollection={editCollection} + listId={listId} + lastCollectionIndex={lastCollectionIndex} + claim={claim} + /> + )} {isChannelUri && claim ? ( <UriIndicator focusable={false} uri={uri} link> <ChannelThumbnail uri={uri} small={type === 'inline'} /> @@ -396,13 +408,27 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { {!pending && ( <> {renderActions && claim && renderActions(claim)} - {Boolean(isMyCollection && listId) && ( + {false && Boolean(isMyCollection && listId) && ( <> <div className="collection-preview__edit-buttons"> <div className="collection-preview__edit-group"> <Button - button="alt" - className={'button-collection-order'} + className={'button-collection-manage'} + icon={ICONS.UP_TOP} + disabled={collectionIndex === 0} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: 0 }, + }); + } + }} + /> + <Button + className={'button-collection-manage'} disabled={collectionIndex === 0} icon={ICONS.UP} onClick={(e) => { @@ -417,8 +443,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { }} /> <Button - button="alt" - className={'button-collection-order'} + className={'button-collection-manage'} icon={ICONS.DOWN} disabled={collectionIndex === lastCollectionIndex} onClick={(e) => { @@ -432,10 +457,26 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { } }} /> + <Button + className={'button-collection-manage'} + icon={ICONS.DOWN_BOTTOM} + disabled={collectionIndex === lastCollectionIndex} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + if (editCollection) { + // $FlowFixMe + editCollection(listId, { + order: { from: collectionIndex, to: lastCollectionIndex }, + }); + } + }} + /> </div> <div className="collection-preview__edit-group"> <Button - button="alt" + // button="alt" + className={'button-collection-manage'} icon={ICONS.DELETE} onClick={(e) => { e.preventDefault(); diff --git a/ui/component/common/icon-custom.jsx b/ui/component/common/icon-custom.jsx index d37ce3816..75faeeba3 100644 --- a/ui/component/common/icon-custom.jsx +++ b/ui/component/common/icon-custom.jsx @@ -382,7 +382,21 @@ export const icons = { [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" /> ), - [ICONS.UP]: buildIcon(<polyline transform="matrix(1,0,0,-1,0,24.707107)" points="6 9 12 15 18 9" />), + [ICONS.UP]: buildIcon( + <g> + <polyline transform="matrix(1,0,0,-1,0,24.707107)" points="6 9 12 15 18 9" /> + </g> + ), + [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.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" /> diff --git a/ui/component/fileDescription/view.jsx b/ui/component/fileDescription/view.jsx index 4b045822e..9d20526c7 100644 --- a/ui/component/fileDescription/view.jsx +++ b/ui/component/fileDescription/view.jsx @@ -27,7 +27,7 @@ function FileDescription(props: Props) { const { uri, claim, metadata, pendingAmount, doOpenModal, claimIsMine, expandOverride } = props; const [expanded, setExpanded] = React.useState(false); const [showCreditDetails, setShowCreditDetails] = React.useState(false); - const amount = parseFloat(claim.amount) + parseFloat(pendingAmount || claim.meta.support_amount); + const amount = claim ? parseFloat(claim.amount) + parseFloat(pendingAmount || claim.meta.support_amount) : undefined; const formattedAmount = formatCredits(amount, 2, true); const hasSupport = claim && claim.meta && claim.meta.support_amount && Number(claim.meta.support_amount) > 0; diff --git a/ui/constants/icons.js b/ui/constants/icons.js index e707d3adb..c0a4e05d6 100644 --- a/ui/constants/icons.js +++ b/ui/constants/icons.js @@ -65,7 +65,9 @@ export const OPTIONS = 'Sliders'; export const YES = 'ThumbsUp'; export const NO = 'ThumbsDown'; export const UP = 'ChevronUp'; +export const UP_TOP = 'ChevronUpTop'; export const DOWN = 'ChevronDown'; +export const DOWN_BOTTOM = 'ChevronDownBottom'; export const SECURE = 'Lock'; export const MENU = 'Menu'; export const BACKUP = 'Database'; diff --git a/ui/page/collection/view.jsx b/ui/page/collection/view.jsx index eb173f7c4..994620cb6 100644 --- a/ui/page/collection/view.jsx +++ b/ui/page/collection/view.jsx @@ -188,7 +188,7 @@ export default function CollectionPage(props: Props) { <Page> <div className={classnames('section card-stack')}> {info} - <ClaimList uris={collectionUrls} collectionId={collectionId} /> + <ClaimList uris={collectionUrls} collectionId={collectionId} type={'listview'} /> </div> </Page> ); diff --git a/ui/scss/component/_button.scss b/ui/scss/component/_button.scss index 7f32e6929..18e03e756 100644 --- a/ui/scss/component/_button.scss +++ b/ui/scss/component/_button.scss @@ -604,30 +604,55 @@ svg + .button__label { } } -.button-collection-order { - height: 100%; +.button-collection-manage { font-size: var(--font-base); border-left-width: 0; - border-radius: 0; margin: 0; - color: var(--color-text); + width: 100%; button { - padding: var(--spacing-xs); + padding: var(--spacing-xxs); + } + + .button__content { + display: unset; + } + line-height: 1.2; + font-weight: var(--font-weight-bold); + height: 100%; + background-color: var(--color-button-alt-bg); + color: var(--color-button-alt-text); + text-align: center; + &:hover { + background-color: var(--color-button-alt-bg-hover); + } + + @media (max-width: $breakpoint-small) { + font-size: var(--font-small); } @media (max-width: $breakpoint-small) { padding: var(--spacing-s) var(--spacing-s); } - &:first-of-type { - border-left-width: 1px; + &.top-right { + border-top-right-radius: var(--border-radius); + } + &.top-left { border-top-left-radius: var(--border-radius); + } + &.bottom-right { + border-bottom-right-radius: var(--border-radius); + } + &.bottom-left { border-bottom-left-radius: var(--border-radius); } - &:last-of-type { - border-top-right-radius: var(--border-radius); - border-bottom-right-radius: var(--border-radius); + &.button-collection-delete-confirm { + background-color: green; + } + + &.button-collection-delete-cancel { + background-color: red; } } diff --git a/ui/scss/component/_claim-list.scss b/ui/scss/component/_claim-list.scss index 8aed6c484..4d9a27057 100644 --- a/ui/scss/component/_claim-list.scss +++ b/ui/scss/component/_claim-list.scss @@ -215,6 +215,11 @@ } } +.claim-preview--collection-mine { + padding-left: 7rem; + position: relative; +} + .claim-preview--pending { opacity: 0.6; } diff --git a/ui/scss/component/_collection.scss b/ui/scss/component/_collection.scss index eac2afc07..0aa72987d 100644 --- a/ui/scss/component/_collection.scss +++ b/ui/scss/component/_collection.scss @@ -86,22 +86,27 @@ } .collection-preview__edit-buttons { - display: flex; - flex-direction: row; - margin-top: var(--spacing-xs); - margin-bottom: var(--spacing-xs); + position: absolute; + left: 0; + top: calc(-1 * var(--spacing-m)); + bottom: calc(-1 * var(--spacing-m)); + padding-left: 0; + padding-top: var(--spacing-m); + padding-bottom: var(--spacing-m); + display: grid; + grid-template-columns: 1fr 1fr 1fr; + align-items: center; } .collection-preview__edit-group { - &:not(:last-of-type) { - margin-right: var(--spacing-s); - } - margin-right: var(--spacing-s); - button { - @media (max-width: $breakpoint-small) { - padding: var(--spacing-s) var(--spacing-s); - } - } + height: 100%; + display: flex; + flex-direction: column; + width: 2rem; + align-items: center; + justify-content: center; + align-items: stretch; + flex-grow: 4; } .collection-edit__header {