improve file page ux
This commit is contained in:
parent
6be2388620
commit
da96f28794
8 changed files with 182 additions and 147 deletions
|
@ -5,10 +5,10 @@ import classnames from 'classnames';
|
|||
type Props = {
|
||||
body: string,
|
||||
label?: string,
|
||||
children: ?React.Node,
|
||||
icon: ?boolean,
|
||||
children?: React.Node,
|
||||
icon?: boolean,
|
||||
direction: string,
|
||||
onFormField?: boolean,
|
||||
onComponent?: boolean, // extra padding to account for button/form field size
|
||||
};
|
||||
|
||||
class ToolTip extends React.PureComponent<Props> {
|
||||
|
@ -17,9 +17,11 @@ class ToolTip extends React.PureComponent<Props> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { children, label, body, icon, direction, onFormField } = this.props;
|
||||
const { children, label, body, icon, direction, onComponent } = this.props;
|
||||
|
||||
const tooltipContent = children || label;
|
||||
const bodyLength = body.length;
|
||||
const isShortDescription = bodyLength < 30;
|
||||
|
||||
return (
|
||||
<span
|
||||
|
@ -30,11 +32,17 @@ class ToolTip extends React.PureComponent<Props> {
|
|||
'tooltip--right': direction === 'right',
|
||||
'tooltip--bottom': direction === 'bottom',
|
||||
'tooltip--left': direction === 'left',
|
||||
'tooltip--on-formfield': onFormField,
|
||||
'tooltip--on-component': onComponent,
|
||||
})}
|
||||
>
|
||||
{tooltipContent}
|
||||
<span className="tooltip__body">{body}</span>
|
||||
<span
|
||||
className={classnames('tooltip__body', {
|
||||
'tooltip__body--short': isShortDescription,
|
||||
})}
|
||||
>
|
||||
{body}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import { MODALS } from 'lbry-redux';
|
||||
import classnames from 'classnames';
|
||||
import * as icons from 'constants/icons';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
|
||||
type FileInfo = {
|
||||
claim_id: string,
|
||||
|
@ -15,34 +15,35 @@ type Props = {
|
|||
openModal: ({ id: string }, { uri: string }) => void,
|
||||
claimIsMine: boolean,
|
||||
fileInfo: FileInfo,
|
||||
vertical?: boolean, // should the buttons be stacked vertically?
|
||||
};
|
||||
|
||||
class FileActions extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { fileInfo, uri, openModal, claimIsMine, vertical, claimId } = this.props;
|
||||
const { fileInfo, uri, openModal, claimIsMine, claimId } = this.props;
|
||||
const showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
||||
|
||||
return (
|
||||
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
||||
<React.Fragment>
|
||||
{showDelete && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.TRASH}
|
||||
iconColor="red"
|
||||
label={__('Delete')}
|
||||
onClick={() => openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
|
||||
/>
|
||||
<Tooltip onComponent body={__('Delete this file')}>
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.TRASH}
|
||||
description={__('Delete')}
|
||||
onClick={() => openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.REPORT}
|
||||
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
||||
label={__('Report content')}
|
||||
/>
|
||||
<Tooltip onComponent body={__('Report content')}>
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.REPORT}
|
||||
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</section>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
import ToolTip from 'component/common/tooltip';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -59,7 +60,7 @@ class FileDownloadLink extends React.PureComponent<Props> {
|
|||
if (loading || downloading) {
|
||||
const progress =
|
||||
fileInfo && fileInfo.written_bytes
|
||||
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
||||
? (fileInfo.written_bytes / fileInfo.total_bytes) * 100
|
||||
: 0;
|
||||
const label = fileInfo
|
||||
? __('Downloading: ') + progress.toFixed(0) + __('% complete')
|
||||
|
@ -72,25 +73,22 @@ class FileDownloadLink extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
button="alt"
|
||||
label={__('Download')}
|
||||
icon={icons.DOWNLOAD}
|
||||
iconColor="purple"
|
||||
onClick={() => {
|
||||
purchaseUri(uri);
|
||||
}}
|
||||
/>
|
||||
<ToolTip onComponent body={__('Download')}>
|
||||
<Button
|
||||
button="alt"
|
||||
icon={icons.DOWNLOAD}
|
||||
iconColor="purple"
|
||||
onClick={() => {
|
||||
purchaseUri(uri);
|
||||
}}
|
||||
/>
|
||||
</ToolTip>
|
||||
);
|
||||
} else if (fileInfo && fileInfo.download_path) {
|
||||
return (
|
||||
<Button
|
||||
button="alt"
|
||||
iconColor="purple"
|
||||
label={__('Open File')}
|
||||
icon={icons.OPEN}
|
||||
onClick={() => openFile()}
|
||||
/>
|
||||
<ToolTip onComponent body={__('Open file')}>
|
||||
<Button button="alt" iconColor="purple" icon={icons.LOCAL} onClick={() => openFile()} />
|
||||
</ToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import {
|
|||
selectSearchState as selectSearch,
|
||||
selectWunderBarAddress,
|
||||
doUpdateSearchQuery,
|
||||
doNotify,
|
||||
MODALS,
|
||||
doFocusSearchInput,
|
||||
doBlurSearchInput,
|
||||
doSearch,
|
||||
|
@ -37,4 +35,7 @@ const perform = dispatch => ({
|
|||
doBlur: () => dispatch(doBlurSearchInput()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(Wunderbar);
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(Wunderbar);
|
||||
|
|
|
@ -167,10 +167,10 @@ class FilePage extends React.Component<Props> {
|
|||
<div className="card__title-identity--file">
|
||||
<h1 className="card__title card__title--file">{title}</h1>
|
||||
<div className="card__title-identity-icons">
|
||||
<FilePrice uri={normalizeURI(uri)} />
|
||||
{isRewardContent && (
|
||||
<Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />
|
||||
)}
|
||||
<FilePrice uri={normalizeURI(uri)} />
|
||||
</div>
|
||||
</div>
|
||||
<span className="card__subtitle card__subtitle--file">
|
||||
|
@ -180,60 +180,55 @@ class FilePage extends React.Component<Props> {
|
|||
{metadata.nsfw && <div>NSFW</div>}
|
||||
<div className="card__channel-info">
|
||||
<UriIndicator uri={uri} link />
|
||||
<div className="card__actions card__actions--no-margin">
|
||||
{claimIsMine ? (
|
||||
<Button
|
||||
button="primary"
|
||||
icon={icons.EDIT}
|
||||
label={__('Edit')}
|
||||
onClick={() => {
|
||||
prepareEdit(claim, editUri);
|
||||
navigate('/publish');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
||||
)}
|
||||
</div>
|
||||
<div className="card__actions card__actions--between">
|
||||
{(claimIsMine || subscriptionUri || speechSharable) && (
|
||||
<div className="card__actions">
|
||||
{claimIsMine ? (
|
||||
<Button
|
||||
button="primary"
|
||||
icon={icons.EDIT}
|
||||
label={__('Edit')}
|
||||
onClick={() => {
|
||||
prepareEdit(claim, editUri);
|
||||
navigate('/publish');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
||||
)}
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon="Send"
|
||||
label={__('Enjoy this? Send a tip')}
|
||||
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
|
||||
/>
|
||||
)}
|
||||
{speechSharable && (
|
||||
<ViewOnWebButton claimId={claim.claim_id} claimName={claim.name} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="card__actions">
|
||||
<FileDownloadLink uri={uri} />
|
||||
<FileActions uri={uri} claimId={claim.claim_id} />
|
||||
</div>
|
||||
</div>
|
||||
{(!claimIsMine || speechSharable) && (
|
||||
<div className="card__actions card__actions--end">
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
button="alt"
|
||||
icon="Send"
|
||||
label={__('Enjoy this? Send a tip')}
|
||||
onClick={() => openModal({ id: MODALS.SEND_TIP }, { uri })}
|
||||
/>
|
||||
)}
|
||||
{speechSharable && (
|
||||
<ViewOnWebButton claimId={claim.claim_id} claimName={claim.name} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<FormRow alignRight padded>
|
||||
<FormField
|
||||
useToggle
|
||||
name="autoplay"
|
||||
type="checkbox"
|
||||
checked={autoplay}
|
||||
onChange={this.onAutoplayChange}
|
||||
postfix={
|
||||
<ToolTip
|
||||
onFormField
|
||||
label={__('Autoplay')}
|
||||
body={__('Automatically download and play free content.')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<FormRow padded>
|
||||
<ToolTip onComponent body={__('Automatically download and play free content.')}>
|
||||
<FormField
|
||||
useToggle
|
||||
name="autoplay"
|
||||
type="checkbox"
|
||||
postfix={__('Autoplay')}
|
||||
checked={autoplay}
|
||||
onChange={this.onAutoplayChange}
|
||||
/>
|
||||
</ToolTip>
|
||||
</FormRow>
|
||||
</div>
|
||||
|
||||
<div className="card__content">
|
||||
<FileDownloadLink uri={uri} />
|
||||
<FileActions uri={uri} claimId={claim.claim_id} />
|
||||
</div>
|
||||
|
||||
<div className="card__content--extra-padding">
|
||||
<FileDetails uri={uri} />
|
||||
</div>
|
||||
|
|
|
@ -93,9 +93,9 @@
|
|||
.card__title-identity--file {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.credit-amount,
|
||||
|
||||
.icon {
|
||||
margin: $spacing-vertical * 1/3;
|
||||
margin: 0 $spacing-vertical * 1/3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@
|
|||
|
||||
.card__subtext-title {
|
||||
color: var(--text-color);
|
||||
font-size: calc(var(--font-size-subtext-multiple) * 1.5em);
|
||||
font-size: calc(var(--font-size-subtext-multiple) * 1.2em);
|
||||
|
||||
&:not(:first-of-type) {
|
||||
margin-top: $spacing-vertical * 3/2;
|
||||
|
@ -220,8 +220,12 @@
|
|||
margin-top: $spacing-vertical * 2/3;
|
||||
display: flex;
|
||||
|
||||
&:not(.card__actions--vertical) .btn:nth-child(n + 2) {
|
||||
margin-left: $spacing-vertical / 3;
|
||||
&:not(.card__actions--vertical) {
|
||||
.btn:nth-child(n + 2),
|
||||
// For buttons wrapped in a tooltip
|
||||
.tooltip:nth-child(n + 2) {
|
||||
margin-left: $spacing-vertical / 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,6 +262,11 @@
|
|||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.card__actions--between {
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/*
|
||||
.card-row is used on the discover page
|
||||
It is a list of cards that extend past the right edge of the screen
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
.file-download {
|
||||
font-size: 0.8em;
|
||||
align-self: center;
|
||||
}
|
||||
|
|
|
@ -13,43 +13,57 @@
|
|||
}
|
||||
}
|
||||
|
||||
.tooltip--on-formfield {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tooltip--icon {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Tooltip text */
|
||||
.tooltip .tooltip__body {
|
||||
background-color: var(--tooltip-bg);
|
||||
font-family: 'metropolis-medium';
|
||||
font-size: 12px;
|
||||
color: var(--tooltip-color);
|
||||
border-radius: 8px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
white-space: pre-wrap;
|
||||
padding: $spacing-vertical * 1/3;
|
||||
visibility: hidden;
|
||||
.tooltip {
|
||||
.tooltip__body {
|
||||
background-color: var(--tooltip-bg);
|
||||
font-family: 'metropolis-medium';
|
||||
font-size: 12px;
|
||||
color: var(--tooltip-color);
|
||||
border-radius: 8px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
white-space: pre-wrap;
|
||||
padding: $spacing-vertical * 1/3;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tooltip__body--short {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.tooltip__body::after {
|
||||
content: ' ';
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
&.tooltip--on-component {
|
||||
.tooltip__body {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip .tooltip__body::after {
|
||||
content: ' ';
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
}
|
||||
.tooltip--top {
|
||||
.tooltip__body {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
|
||||
.tooltip--top .tooltip__body {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
&.tooltip__body--short {
|
||||
margin-left: -65px;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 100%;
|
||||
|
@ -59,28 +73,36 @@
|
|||
}
|
||||
}
|
||||
|
||||
.tooltip--right .tooltip__body {
|
||||
margin-top: -5px;
|
||||
margin-left: 10px;
|
||||
|
||||
&::after {
|
||||
top: 17px;
|
||||
right: 100%; /* To the left of the tooltip */
|
||||
.tooltip--right {
|
||||
.tooltip__body {
|
||||
margin-top: -5px;
|
||||
border-color: transparent var(--tooltip-bg) transparent transparent;
|
||||
margin-left: 10px;
|
||||
|
||||
&::after {
|
||||
top: 17px;
|
||||
right: 100%; /* To the left of the tooltip */
|
||||
margin-top: -5px;
|
||||
border-color: transparent var(--tooltip-bg) transparent transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip--bottom .tooltip__body {
|
||||
top: 90%;
|
||||
left: 50%;
|
||||
margin-left: -100px;
|
||||
|
||||
&::after {
|
||||
bottom: 100%;
|
||||
.tooltip--bottom {
|
||||
.tooltip__body {
|
||||
top: 90%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-color: transparent transparent var(--tooltip-bg) transparent;
|
||||
margin-left: -100px;
|
||||
|
||||
&.tooltip__body--short {
|
||||
margin-left: -65px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-color: transparent transparent var(--tooltip-bg) transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue