c5c67a0de5
Add doResolveUris() Always call resolveUri() in FileTile and FileCard Before, these components would only try and resolve if claim info wasn't provided. Don't require uri param in lbry.resolve() It can now be "uris" instead, plus the error message about caching doesn't really apply anymore. Don't cache/cancel open resolve requests No longer needed because we're not doing resolve requests in bulk Add support for multiple URI resolution in lbry.resolve() Handle multi URL resolves with one action Update CHANGELOG.md
238 lines
7 KiB
JavaScript
238 lines
7 KiB
JavaScript
import React from "react";
|
|
import ReactDOM from "react-dom";
|
|
import lbryuri from "lbryuri";
|
|
import FileCard from "component/fileCard";
|
|
import { Icon, BusyMessage } from "component/common.js";
|
|
import ToolTip from "component/tooltip.js";
|
|
|
|
class FeaturedCategory extends React.PureComponent {
|
|
componentWillMount() {
|
|
this.setState({
|
|
numItems: this.props.names.length,
|
|
canScrollPrevious: false,
|
|
canScrollNext: true,
|
|
});
|
|
}
|
|
|
|
handleScrollPrevious() {
|
|
const cardRow = ReactDOM.findDOMNode(this.refs.rowitems);
|
|
if (cardRow.scrollLeft > 0) {
|
|
// check the visible cards
|
|
const cards = cardRow.getElementsByTagName("section");
|
|
let firstVisibleCard = null;
|
|
let firstVisibleIdx = -1;
|
|
for (var i = 0; i < cards.length; i++) {
|
|
if (this.isCardVisible(cards[i], cardRow, false)) {
|
|
firstVisibleCard = cards[i];
|
|
firstVisibleIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const numDisplayed = this.numDisplayedCards(cardRow);
|
|
const scrollToIdx = firstVisibleIdx - numDisplayed;
|
|
const animationCallback = () => {
|
|
this.setState({
|
|
canScrollPrevious: cardRow.scrollLeft !== 0,
|
|
canScrollNext: true,
|
|
});
|
|
};
|
|
this.scrollCardItemsLeftAnimated(
|
|
cardRow,
|
|
scrollToIdx < 0 ? 0 : cards[scrollToIdx].offsetLeft,
|
|
100,
|
|
animationCallback
|
|
);
|
|
}
|
|
}
|
|
|
|
handleScrollNext() {
|
|
const cardRow = ReactDOM.findDOMNode(this.refs.rowitems);
|
|
|
|
// check the visible cards
|
|
const cards = cardRow.getElementsByTagName("section");
|
|
let lastVisibleCard = null;
|
|
let lastVisibleIdx = -1;
|
|
for (var i = 0; i < cards.length; i++) {
|
|
if (this.isCardVisible(cards[i], cardRow, true)) {
|
|
lastVisibleCard = cards[i];
|
|
lastVisibleIdx = i;
|
|
}
|
|
}
|
|
|
|
if (lastVisibleCard) {
|
|
const numDisplayed = this.numDisplayedCards(cardRow);
|
|
const animationCallback = () => {
|
|
// update last visible index after scroll
|
|
for (var i = 0; i < cards.length; i++) {
|
|
if (this.isCardVisible(cards[i], cardRow, true)) {
|
|
lastVisibleIdx = i;
|
|
}
|
|
}
|
|
|
|
this.setState({ canScrollPrevious: true });
|
|
if (lastVisibleIdx === cards.length - 1) {
|
|
this.setState({ canScrollNext: false });
|
|
}
|
|
};
|
|
|
|
this.scrollCardItemsLeftAnimated(
|
|
cardRow,
|
|
Math.min(
|
|
lastVisibleCard.offsetLeft,
|
|
cardRow.scrollWidth - cardRow.clientWidth
|
|
),
|
|
100,
|
|
animationCallback
|
|
);
|
|
}
|
|
}
|
|
|
|
scrollCardItemsLeftAnimated(cardRow, target, duration, callback) {
|
|
if (!duration || duration <= diff) {
|
|
cardRow.scrollLeft = target;
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
return;
|
|
}
|
|
|
|
const component = this;
|
|
const diff = target - cardRow.scrollLeft;
|
|
const tick = diff / duration * 10;
|
|
setTimeout(() => {
|
|
cardRow.scrollLeft = cardRow.scrollLeft + tick;
|
|
if (cardRow.scrollLeft === target) {
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
return;
|
|
}
|
|
component.scrollCardItemsLeftAnimated(
|
|
cardRow,
|
|
target,
|
|
duration - 10,
|
|
callback
|
|
);
|
|
}, 10);
|
|
}
|
|
|
|
isCardVisible(section, cardRow, partialVisibility) {
|
|
// check if a card is fully or partialy visible in its parent
|
|
const cardRowWidth = cardRow.offsetWidth;
|
|
const cardRowLeft = cardRow.scrollLeft;
|
|
const cardRowEnd = cardRowLeft + cardRow.offsetWidth;
|
|
const sectionLeft = section.offsetLeft - cardRowLeft;
|
|
const sectionEnd = sectionLeft + section.offsetWidth;
|
|
|
|
return (
|
|
(sectionLeft >= 0 && sectionEnd <= cardRowWidth) ||
|
|
(((sectionLeft < 0 && sectionEnd > 0) ||
|
|
(sectionLeft > 0 && sectionLeft <= cardRowWidth)) &&
|
|
partialVisibility)
|
|
);
|
|
}
|
|
|
|
numDisplayedCards(cardRow) {
|
|
const cards = cardRow.getElementsByTagName("section");
|
|
const cardRowWidth = cardRow.offsetWidth;
|
|
// get the width of the first card and then calculate
|
|
const cardWidth = cards.length > 0 ? cards[0].offsetWidth : 0;
|
|
|
|
if (cardWidth > 0) {
|
|
return Math.ceil(cardRowWidth / cardWidth);
|
|
}
|
|
|
|
// return a default value of 1 card displayed if the card width couldn't be determined
|
|
return 1;
|
|
}
|
|
|
|
render() {
|
|
const { category, names } = this.props;
|
|
|
|
return (
|
|
<div className="card-row card-row--small">
|
|
<h3 className="card-row__header">
|
|
{category}
|
|
{category &&
|
|
category.match(/^community/i) &&
|
|
<ToolTip
|
|
label={__("What's this?")}
|
|
body={__(
|
|
'Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!'
|
|
)}
|
|
className="tooltip--header"
|
|
/>}
|
|
</h3>
|
|
<div className="card-row__scrollhouse">
|
|
{this.state.canScrollPrevious &&
|
|
<div className="card-row__nav card-row__nav--left">
|
|
<a
|
|
className="card-row__scroll-button"
|
|
onClick={this.handleScrollPrevious.bind(this)}
|
|
>
|
|
<Icon icon="icon-chevron-left" />
|
|
</a>
|
|
</div>}
|
|
{this.state.canScrollNext &&
|
|
<div className="card-row__nav card-row__nav--right">
|
|
<a
|
|
className="card-row__scroll-button"
|
|
onClick={this.handleScrollNext.bind(this)}
|
|
>
|
|
<Icon icon="icon-chevron-right" />
|
|
</a>
|
|
</div>}
|
|
<div ref="rowitems" className="card-row__items">
|
|
{names &&
|
|
names.map(name =>
|
|
<FileCard
|
|
key={name}
|
|
displayStyle="card"
|
|
uri={lbryuri.normalize(name)}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
class DiscoverPage extends React.PureComponent {
|
|
componentWillMount() {
|
|
this.props.fetchFeaturedUris();
|
|
}
|
|
|
|
render() {
|
|
const { featuredUris, fetchingFeaturedUris } = this.props;
|
|
const hasContent =
|
|
typeof featuredUris === "object" && Object.keys(featuredUris).length,
|
|
failedToLoad = !fetchingFeaturedUris && !hasContent;
|
|
|
|
return (
|
|
<main className={hasContent && fetchingFeaturedUris ? "reloading" : null}>
|
|
{!hasContent &&
|
|
fetchingFeaturedUris &&
|
|
<BusyMessage message={__("Fetching content")} />}
|
|
{hasContent &&
|
|
Object.keys(featuredUris).map(
|
|
category =>
|
|
featuredUris[category].length
|
|
? <FeaturedCategory
|
|
key={category}
|
|
category={category}
|
|
names={featuredUris[category]}
|
|
/>
|
|
: ""
|
|
)}
|
|
{failedToLoad &&
|
|
<div className="empty">
|
|
{__("Failed to load landing content.")}
|
|
</div>}
|
|
</main>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default DiscoverPage;
|