Add tags to publish page, infinite scroll, navigation improvements #2593

Merged
neb-b merged 21 commits from infinite into master 2019-07-02 04:54:36 +02:00
20 changed files with 101 additions and 83 deletions
Showing only changes of commit c6412eebef - Show all commits

View file

@ -63,7 +63,7 @@
"@exponent/electron-cookies": "^2.0.0",
"@hot-loader/react-dom": "16.8",
"@lbry/color": "^1.0.2",
"@lbry/components": "^2.7.2",
"@lbry/components": "^2.7.4",
"@reach/rect": "^0.2.1",
"@reach/tabs": "^0.1.5",
"@reach/tooltip": "^0.2.1",

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { makeSelectFileInfoForUri, makeSelectClaimIsMine, makeSelectClaimForUri } from 'lbry-redux';
import { makeSelectFileInfoForUri, makeSelectClaimIsMine } from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
import FileProperties from './view';
@ -10,7 +10,6 @@ const select = (state, props) => ({
isSubscribed: makeSelectIsSubscribed(props.uri)(state),
isNew: makeSelectIsNew(props.uri)(state),
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
claim: makeSelectClaimForUri(props.uri)(state),
});
export default connect(

View file

@ -4,10 +4,10 @@ import * as React from 'react';
import { parseURI } from 'lbry-redux';
import Icon from 'component/common/icon';
import FilePrice from 'component/filePrice';
import VideoDuration from 'component/videoDuration';
type Props = {
uri: string,
claim: ?StreamClaim,
downloaded: boolean,
claimIsMine: boolean,
isSubscribed: boolean,
@ -16,32 +16,17 @@ type Props = {
};
export default function FileProperties(props: Props) {
const { claim, uri, downloaded, claimIsMine, rewardedContentClaimIds, isSubscribed } = props;
const { uri, downloaded, claimIsMine, rewardedContentClaimIds, isSubscribed } = props;
const { claimId } = parseURI(uri);
const isRewardContent = rewardedContentClaimIds.includes(claimId);
const video = claim && claim.value && claim.value.video;
let duration;
if (video && video.duration) {
// $FlowFixMe
let date = new Date(null);
date.setSeconds(video.duration);
let timeString = date.toISOString().substr(11, 8);
if (timeString.startsWith('00:')) {
timeString = timeString.substr(3);
}
duration = timeString;
}
return (
<div className="file-properties">
{isSubscribed && <Icon tooltip icon={icons.SUBSCRIPTION} />}
{!claimIsMine && downloaded && <Icon tooltip icon={icons.DOWNLOAD} />}
{isRewardContent && <Icon tooltip icon={icons.FEATURED} />}
<FilePrice hideFree uri={uri} />
{duration && <span className="media__subtitle">{duration}</span>}
<VideoDuration className="media__subtitle" uri={uri} />
</div>
);
}

View file

@ -15,6 +15,7 @@ const select = state => ({
channel: makeSelectPublishFormValue('channel')(state),
bid: makeSelectPublishFormValue('bid')(state),
uri: makeSelectPublishFormValue('uri')(state),
bid: makeSelectPublishFormValue('bid')(state),
isStillEditing: selectIsStillEditing(state),
isResolvingUri: selectIsResolvingPublishUris(state),
amountNeededForTakeover: selectTakeOverAmount(state),

View file

@ -10,7 +10,7 @@ type Props = {
name: string,
channel: string,
uri: string,
bid: string,
bid: number,
balance: number,
isStillEditing: boolean,
myClaimForUri: ?StreamClaim,
@ -27,7 +27,7 @@ function PublishText(props: Props) {
uri,
isStillEditing,
myClaimForUri,
bid: bidString,
bid,
isResolvingUri,
amountNeededForTakeover,
prepareEdit,
@ -37,7 +37,6 @@ function PublishText(props: Props) {
const [nameError, setNameError] = useState(undefined);
const [bidError, setBidError] = useState(undefined);
const previousBidAmount = myClaimForUri && Number(myClaimForUri.amount);
const bid = Number(bidString);
function editExistingClaim() {
if (myClaimForUri) {

View file

@ -1,4 +1,5 @@
import { connect } from 'react-redux';
import { doUpdatePublishForm } from 'redux/actions/publish';
import { makeSelectPublishFormValue } from 'redux/selectors/publish';
import PublishPage from './view';
@ -7,7 +8,11 @@ const select = state => ({
fee: makeSelectPublishFormValue('fee')(state),
});
const perform = dispatch => ({
updatePublishForm: values => dispatch(doUpdatePublishForm(values)),
});
export default connect(
select,
null
perform
)(PublishPage);

View file

@ -10,7 +10,7 @@ type Props = {
function RewardTotal(props: Props) {
const { rewards } = props;
const rewardTotal = rewards.reduce((acc, val) => acc + val.reward_amount, 0);
const total = useTween(rewardTotal * 25);
const total = useTween(rewardTotal * 40);
const integer = Math.round(total * rewardTotal);
return (

View file

@ -20,6 +20,7 @@ export default function Tag(props: Props) {
<Button
{...clickProps}
disabled={disabled}
title={type === 'add' ? __('Add tag') : __('Remove tag')}
className={classnames('tag', {
'tag--add': type === 'add',
'tag--remove': type === 'remove',

View file

@ -19,7 +19,7 @@ type Props = {
};
export default function TagSelect(props: Props) {
const { unfollowedTags, followedTags, doToggleTagFollow, doAddTag, onSelect } = props;
const { unfollowedTags = [], followedTags = [], doToggleTagFollow, doAddTag, onSelect } = props;
const [newTag, setNewTag] = useState('');
let tags = unfollowedTags.slice();
@ -27,9 +27,14 @@ export default function TagSelect(props: Props) {
tags.unshift({ name: newTag });
}
const doesTagMatch = ({ name }) => (newTag ? name.toLowerCase().includes(newTag.toLowerCase()) : true);
const suggestedTags = tags.filter(doesTagMatch).slice(0, 5);
const suggestedTransitions = useTransition(suggestedTags, tag => tag.name, unfollowedTagsAnimation);
const doesTagMatch = name => (newTag ? name.toLowerCase().includes(newTag.toLowerCase()) : true);
// Make sure there are no duplicates, then trim
const suggestedTagsSet = new Set(tags.map(tag => tag.name));
const suggestedTags = Array.from(suggestedTagsSet)
.filter(doesTagMatch)
.slice(0, 5);
const suggestedTransitions = useTransition(suggestedTags, tag => tag, unfollowedTagsAnimation);
function onChange(e) {
setNewTag(e.target.value);
@ -42,11 +47,11 @@ export default function TagSelect(props: Props) {
if (onSelect) {
onSelect({ name: newTag });
} else {
if (!unfollowedTags.includes(newTag)) {
if (!unfollowedTags.map(({ name }) => name).includes(newTag)) {
doAddTag(newTag);
}
if (!followedTags.includes(newTag)) {
if (!followedTags.map(({ name }) => name).includes(newTag)) {
doToggleTagFollow(newTag);
}
}
@ -54,9 +59,9 @@ export default function TagSelect(props: Props) {
function handleTagClick(tag) {
if (onSelect) {
onSelect(tag);
onSelect({ name: tag });
} else {
doToggleTagFollow(tag.name);
doToggleTagFollow(tag);
}
}
@ -74,7 +79,7 @@ export default function TagSelect(props: Props) {
<ul className="tags">
{suggestedTransitions.map(({ item, key, props }) => (
<animated.li key={key} style={props}>
<Tag name={item.name} type="add" onClick={() => handleTagClick(item)} />
<Tag name={item} type="add" onClick={() => handleTagClick(item)} />
</animated.li>
))}
{!suggestedTransitions.length && <p className="empty tags__empty-message">No suggested tags</p>}

View file

@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import { makeSelectClaimForUri } from 'lbry-redux';
import VideoDuration from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
});
export default connect(
select,
null
)(VideoDuration);

View file

@ -0,0 +1,30 @@
// @flow
import React from 'react';
type Props = {
claim: ?StreamClaim,
className?: string,
};
function VideoDuration(props: Props) {
const { claim, className } = props;
const video = claim && claim.value && claim.value.video;
let duration;
if (video && video.duration) {
// $FlowFixMe
let date = new Date(null);
date.setSeconds(video.duration);
let timeString = date.toISOString().substr(11, 8);
if (timeString.startsWith('00:')) {
timeString = timeString.substr(3);
}
duration = timeString;
}
return duration ? <span className={className}>{duration}</span> : null;
}
export default VideoDuration;

View file

@ -9,9 +9,7 @@ import InvitePage from 'page/invite';
const WalletPage = () => (
<Page>
<UserEmail />
{IS_WEB && <UnsupportedOnWeb />}
<UnsupportedOnWeb />
<div className={classnames({ 'card--disabled': IS_WEB })}>
<div className="columns">
<UserEmail />

View file

@ -22,6 +22,7 @@ import RecommendedContent from 'component/recommendedContent';
import ClaimTags from 'component/claimTags';
import CommentsList from 'component/commentsList';
import CommentCreate from 'component/commentCreate';
import VideoDuration from 'component/videoDuration';
type Props = {
claim: StreamClaim,
@ -184,21 +185,6 @@ class FilePage extends React.Component<Props> {
const insufficientCredits = !claimIsMine && costInfo && costInfo.cost > balance;
const video = claim && claim.value && claim.value.video;
let duration;
if (video && video.duration) {
// $FlowFixMe
let date = new Date(null);
date.setSeconds(video.duration);
let timeString = date.toISOString().substr(11, 8);
if (timeString.startsWith('00:')) {
timeString = timeString.substr(3);
}
duration = timeString;
}
return (
<Page className="main--file-page">
<div className="grid-area--content card">
@ -295,7 +281,7 @@ class FilePage extends React.Component<Props> {
</div>
<div className="media__subtext media__subtext--large">
{video && <p className="media__info-text">{duration}</p>}
<VideoDuration uri={uri} />
{claimIsMine && (
<p>

View file

@ -18,9 +18,16 @@
}
}
// Fix this in lbry/components
.button--primary:not(:hover) {
background-color: $lbry-teal-4;
.button--primary {
&:not(:hover) {
// fix this in components repo
background-color: $lbry-teal-4;
}
&:hover {
background-color: $lbry-teal-3;
}
svg {
color: white;
}

View file

@ -96,8 +96,8 @@
}
.claim-preview--injected,
.claim-preview {
border-top: 1px solid rgba($lbry-teal-5, 0.1);
.claim-preview + .claim-preview {
border-bottom: 1px solid rgba($lbry-teal-5, 0.1);
}
.claim-preview--large {
@ -147,6 +147,7 @@
.claim-preview-properties {
align-items: flex-end;
flex: 1;
}
.claim-preview-title {

View file

@ -1,25 +1,5 @@
@import '~@lbry/components/sass/form/_index.scss';
// replace this
form {
// setting the font size here sizes everything within
&:not(:last-child) {
margin-bottom: var(--spacing-s);
}
}
input,
select {
height: var(--spacing-l);
border: 1px solid;
}
checkbox-element,
radio-element,
select {
cursor: pointer;
}
textarea {
&::placeholder {
opacity: 0.4;

View file

@ -145,6 +145,7 @@
// S U B T I T L E
.media__subtitle {
align-self: flex-start;
font-size: 0.8em;
color: rgba($lbry-black, 0.6);

View file

@ -57,6 +57,10 @@ $main: $lbry-teal-5;
&:active {
background-color: $main;
}
&:focus {
@include focus;
}
}
.tag--remove {

View file

@ -15,3 +15,7 @@
}
}
}
@mixin focus {
box-shadow: 0 0 0 2px $lbry-blue-1;
}

View file

@ -862,10 +862,10 @@
resolved "https://registry.yarnpkg.com/@lbry/color/-/color-1.1.1.tgz#b80ec25fb515d436129332b20c767c5a7014ac09"
integrity sha512-BdxqWmm84WYOd1ZsPruJiGr7WBEophVfJKg7oywFOAMb0h6ERe4Idx1ceweMSvCOyPlR5GAhil9Gvk70SBFdxQ==
"@lbry/components@^2.7.2":
version "2.7.2"
resolved "https://registry.yarnpkg.com/@lbry/components/-/components-2.7.2.tgz#a941ced2adf78ab52026f5533e5f6b3454f862a9"
integrity sha512-TSBmxc4i2E3v7qGC7LgdcrUUcpiUYBA1KMVSW5vrpDJroNy3fnr3/niGJTudVQ4LQzlOXpt7bsRATFh8vRmXnQ==
"@lbry/components@^2.7.4":
version "2.7.4"
resolved "https://registry.yarnpkg.com/@lbry/components/-/components-2.7.4.tgz#3a633725137ffcb1f081f71dbf5397d66bf444cd"
integrity sha512-X0QBpdlsPntmuC/COolx/rOmUxa5XeHDjdcpl79Db3Y3upkEYwwtvl+S/OkkPbdxouoJfZTB4QqQuGkNi1xGdw==
"@mapbox/hast-util-table-cell-style@^0.1.3":
version "0.1.3"