first version of infinite scroll

This commit is contained in:
Sean Yesmunt 2019-06-27 02:18:45 -04:00
parent 68a18556bf
commit 2ca254a573
33 changed files with 236 additions and 110 deletions

View file

@ -1,6 +1,6 @@
{
"name": "LBRY",
"version": "0.33.1",
"version": "0.33.2",
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
"keywords": [
"lbry"
@ -123,7 +123,7 @@
"jsmediatags": "^3.8.1",
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#141593500693a93db74c62ef5a9fe67b43896603",
"lbry-redux": "lbryio/lbry-redux#2930ad82a90ca91f6caf3761597ef9a67da7db66",
"lbryinc": "lbryio/lbryinc#43d382d9b74d396a581a74d87e4c53105e04f845",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",

View file

@ -1,6 +1,6 @@
import { hot } from 'react-hot-loader/root';
import { connect } from 'react-redux';
import { doUpdateBlockHeight, doError } from 'lbry-redux';
import { doUpdateBlockHeight, doError, doFetchTransactions } from 'lbry-redux';
import { selectUser, doRewardList, doFetchRewardedContent } from 'lbryinc';
import { selectThemePath } from 'redux/selectors/settings';
import App from './view';
@ -15,6 +15,7 @@ const perform = dispatch => ({
updateBlockHeight: () => dispatch(doUpdateBlockHeight()),
fetchRewards: () => dispatch(doRewardList()),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
fetchTransactions: () => dispatch(doFetchTransactions()),
});
export default hot(

View file

@ -9,6 +9,8 @@ import { openContextMenu } from 'util/context-menu';
import useKonamiListener from 'util/enhanced-layout';
import Yrbl from 'component/yrbl';
export const MAIN_WRAPPER_CLASS = 'main-wrapper';
type Props = {
alertError: (string | {}) => void,
pageTitle: ?string,
@ -16,18 +18,23 @@ type Props = {
theme: string,
fetchRewards: () => void,
fetchRewardedContent: () => void,
fetchTransactions: () => void,
};
function App(props: Props) {
const { theme, fetchRewards, fetchRewardedContent } = props;
const { theme, fetchRewards, fetchRewardedContent, fetchTransactions } = props;
const appRef = useRef();
const isEnhancedLayout = useKonamiListener();
useEffect(() => {
ReactModal.setAppElement(appRef.current);
fetchRewards();
fetchRewardedContent();
}, [fetchRewards, fetchRewardedContent]);
// @if TARGET='app'
fetchRewards();
fetchTransactions();
// @endif
}, [fetchRewards, fetchRewardedContent, fetchTransactions]);
useEffect(() => {
// $FlowFixMe
@ -38,7 +45,7 @@ function App(props: Props) {
<div ref={appRef} onContextMenu={e => openContextMenu(e)}>
<Header />
<div className="main-wrapper">
<div className={MAIN_WRAPPER_CLASS}>
<div className="main-wrapper-inner">
<Router />
<SideBar />

View file

@ -35,7 +35,7 @@ function ChannelContent(props: Props) {
{!channelIsMine && <HiddenNsfwClaims className="card__content help" uri={uri} />}
{hasContent && <ClaimList header={false} uris={claimsInChannel.map(claim => claim.permanent_url)} />}
{hasContent && <ClaimList header={false} uris={claimsInChannel.map(claim => claim.permanent_url).reverse()} />}
<Paginate
onPageChange={page => fetchClaims(uri, page)}

View file

@ -1,6 +1,7 @@
// @flow
import { MAIN_WRAPPER_CLASS } from 'component/app/view';
import type { Node } from 'react';
import React from 'react';
import React, { useEffect } from 'react';
import classnames from 'classnames';
import ClaimPreview from 'component/claimPreview';
import Spinner from 'component/spinner';
@ -19,14 +20,25 @@ type Props = {
type: string,
empty?: string,
meta?: Node,
onScrollBottom?: any => void,
// If using the default header, this is a unique ID needed to persist the state of the filter setting
persistedStorageKey?: string,
};
export default function ClaimList(props: Props) {
const { uris, headerAltControls, injectedItem, loading, persistedStorageKey, empty, meta, type, header } = props;
const {
uris,
headerAltControls,
injectedItem,
loading,
persistedStorageKey,
empty,
meta,
type,
header,
onScrollBottom,
} = props;
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
const sortedUris = uris && currentSort === SORT_NEW ? uris.slice().reverse() : uris;
const hasUris = uris && !!uris.length;
const sortedUris = (hasUris && (currentSort === SORT_NEW ? uris : uris.slice().reverse())) || [];
@ -34,8 +46,31 @@ export default function ClaimList(props: Props) {
setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW);
}
useEffect(() => {
if (onScrollBottom) {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}
}, [loading, handleScroll]);
function handleScroll(e) {
if (onScrollBottom) {
const x = document.querySelector(`.${MAIN_WRAPPER_CLASS}`);
if (x && window.scrollY + window.innerHeight >= x.offsetHeight) {
// fix this
if (!loading && uris.length > 19) {
onScrollBottom();
}
}
}
}
return (
<section className={classnames('file-list')}>
<section className={classnames('claim-list')}>
{header !== false && (
<div className={classnames('claim-list__header', { 'claim-list__header--small': type === 'small' })}>
{header || (
@ -60,7 +95,7 @@ export default function ClaimList(props: Props) {
{sortedUris.map((uri, index) => (
<React.Fragment key={uri}>
<ClaimPreview uri={uri} type={type} />
{index === 4 && injectedItem && <li className="claim-list__item--injected">{injectedItem}</li>}
{index === 4 && injectedItem && <li className="claim-preview--injected">{injectedItem}</li>}
</React.Fragment>
))}
</ul>

View file

@ -1,12 +1,14 @@
// @flow
import type { Node } from 'react';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import moment from 'moment';
import usePersistedState from 'util/use-persisted-state';
import { FormField } from 'component/common/form';
import ClaimList from 'component/claimList';
import Tag from 'component/tag';
import usePersistedState from 'util/use-persisted-state';
import ClaimPreview from 'component/claimPreview';
const PAGE_SIZE = 20;
const TIME_DAY = 'day';
const TIME_WEEK = 'week';
const TIME_MONTH = 'month';
@ -37,11 +39,17 @@ function ClaimListDiscover(props: Props) {
const [personalSort, setPersonalSort] = usePersistedState('file-list-trending:personalSort', SEARCH_SORT_YOU);
const [typeSort, setTypeSort] = usePersistedState('file-list-trending:typeSort', TYPE_TRENDING);
const [timeSort, setTimeSort] = usePersistedState('file-list-trending:timeSort', TIME_WEEK);
const [page, setPage] = useState(1);
const toCapitalCase = string => string.charAt(0).toUpperCase() + string.slice(1);
const tagsString = tags.join(',');
useEffect(() => {
const options = {};
const options: {
page_size: number,
any_tags?: Array<string>,
order_by?: Array<string>,
release_time?: string,
} = { page_size: PAGE_SIZE, page };
const newTags = tagsString.split(',');
if ((newTags && !personal) || (newTags && personal && personalSort === SEARCH_SORT_YOU)) {
@ -65,7 +73,7 @@ function ClaimListDiscover(props: Props) {
}
doClaimSearch(20, options);
}, [personal, personalSort, typeSort, timeSort, doClaimSearch, tagsString]);
}, [personal, personalSort, typeSort, timeSort, doClaimSearch, page, tagsString]);
const header = (
<h1 className="card__title--flex">
@ -91,7 +99,10 @@ function ClaimListDiscover(props: Props) {
name="trending_overview"
className="claim-list__dropdown"
value={personalSort}
onChange={e => setPersonalSort(e.target.value)}
onChange={e => {
setPage(1);
setPersonalSort(e.target.value);
}}
>
{SEARCH_FILTER_TYPES.map(type => (
<option key={type} value={type}>
@ -132,7 +143,10 @@ function ClaimListDiscover(props: Props) {
injectedItem={personalSort === SEARCH_SORT_YOU && injectedItem}
header={header}
headerAltControls={headerAltControls}
onScrollBottom={() => setPage(page + 1)}
/>
{loading && page > 1 && new Array(PAGE_SIZE).fill(1).map((x, i) => <ClaimPreview key={i} placeholder />)}
</div>
);
}

View file

@ -1,7 +1,7 @@
// @flow
import React, { useEffect } from 'react';
import classnames from 'classnames';
import { convertToShareLink } from 'lbry-redux';
import { parseURI, convertToShareLink } from 'lbry-redux';
import { withRouter } from 'react-router-dom';
import { openCopyLinkMenu } from 'util/context-menu';
import { formatLbryUriForWeb } from 'util/uri';
@ -53,8 +53,8 @@ function ClaimPreview(props: Props) {
blackListedOutpoints,
} = props;
const haventFetched = claim === undefined;
const abandoned = !isResolvingUri && !claim;
const isChannel = claim && claim.value_type === 'channel';
const abandoned = !isResolvingUri && !claim && !placeholder;
const { isChannel } = parseURI(uri);
const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0;
let shouldHide = abandoned || (!claimIsMine && obscureNsfw && nsfw);
@ -94,10 +94,10 @@ function ClaimPreview(props: Props) {
if (placeholder && !claim) {
return (
<li className="claim-list__item" disabled>
<li className="claim-preview" disabled>
<div className="placeholder media__thumb" />
<div className="placeholder__wrapper">
<div className="placeholder claim-list__item-title" />
<div className="placeholder claim-preview-title" />
<div className="placeholder media__subtitle" />
</div>
</li>
@ -109,15 +109,15 @@ function ClaimPreview(props: Props) {
role="link"
onClick={pending ? undefined : onClick}
onContextMenu={handleContextMenu}
className={classnames('claim-list__item', {
'claim-list__item--large': type === 'large',
className={classnames('claim-preview', {
'claim-preview--large': type === 'large',
'claim-list__pending': pending,
})}
>
{isChannel ? <ChannelThumbnail uri={uri} /> : <CardMedia thumbnail={thumbnail} />}
<div className="claim-list__item-metadata">
<div className="claim-list__item-info">
<div className="claim-list__item-title">
<div className="claim-preview-metadata">
<div className="claim-preview-info">
<div className="claim-preview-title">
<TruncatedText text={title || (claim && claim.name)} lines={1} />
</div>
{type !== 'small' && (
@ -128,7 +128,7 @@ function ClaimPreview(props: Props) {
)}
</div>
<div className="claim-list__item-properties">
<div className="claim-preview-properties">
<div className="media__subtitle">
<UriIndicator uri={uri} link />
{pending && <div>Pending...</div>}

View file

@ -40,6 +40,12 @@ export const icons = {
<path d="M294.3,150.9l2-12.6l-12.2-2.1l0.8-4.9l17.1,2.9l-2.8,17.5L294.3,150.9L294.3,150.9z" />
</svg>
),
[ICONS.FEATURED]: buildIcon(
<g fill="none" fillRule="evenodd" strokeLinecap="round">
<circle cx="12" cy="8" r="7" />
<polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88" />
</g>
),
[ICONS.ARROW_LEFT]: buildIcon(
<g fill="none" fillRule="evenodd" strokeLinecap="round">
<path d="M4, 12 L21, 12" />
@ -210,4 +216,12 @@ export const icons = {
[ICONS.CHAT]: buildIcon(
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
),
[ICONS.YES]: buildIcon(
<path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" />
),
[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 points="18 15 12 9 6 15" />),
[ICONS.DOWN]: buildIcon(<polyline points="6 9 12 15 18 9" />),
};

View file

@ -42,7 +42,6 @@ class FileDetails extends PureComponent<Props> {
<Expandable>
{description && (
<Fragment>
<div className="media__info-title">About</div>
<div className="media__info-text">
<MarkdownPreview content={description} promptLinks />
</div>

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { makeSelectFileInfoForUri, makeSelectClaimIsMine } from 'lbry-redux';
import { makeSelectFileInfoForUri, makeSelectClaimIsMine, makeSelectClaimForUri } from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc';
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
import FileProperties from './view';
@ -10,6 +10,7 @@ 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

@ -7,6 +7,7 @@ import FilePrice from 'component/filePrice';
type Props = {
uri: string,
claim: ?StreamClaim,
downloaded: boolean,
claimIsMine: boolean,
isSubscribed: boolean,
@ -15,16 +16,32 @@ type Props = {
};
export default function FileProperties(props: Props) {
const { uri, downloaded, claimIsMine, rewardedContentClaimIds, isSubscribed } = props;
const { claim, 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>}
</div>
);
}

View file

@ -1,12 +1,18 @@
// @flow
import { remote } from 'electron';
import React from 'react';
import React, { Suspense } from 'react';
import LoadingScreen from 'component/common/loading-screen';
import VideoViewer from 'component/viewers/videoViewer';
// Audio player on hold until the current player is dropped
// This component is half working
// const AudioViewer = React.lazy<*>(() =>
// import(
// /* webpackChunkName: "audioViewer" */
// 'component/viewers/audioViewer'
// )
// );
// const AudioViewer = React.lazy<*>(() =>
// import(/* webpackChunkName: "audioViewer" */
// 'component/viewers/audioViewer')
// );

View file

@ -56,7 +56,7 @@ export default function TagSelect(props: Props) {
if (onSelect) {
onSelect(tag);
} else {
doToggleTagFollow(tag);
doToggleTagFollow(tag.name);
}
}

View file

@ -14,8 +14,10 @@ class TransactionListRecent extends React.PureComponent<Props> {
componentDidMount() {
const { fetchMyClaims, fetchTransactions } = this.props;
// @if TARGET='app'
fetchMyClaims();
fetchTransactions();
// @endif
}
render() {

View file

@ -4,6 +4,7 @@ import Button from 'component/button';
import { FormField } from 'component/common/form';
import UserEmailNew from 'component/userEmailNew';
import UserEmailVerify from 'component/userEmailVerify';
import cookie from 'cookie';
type Props = {
cancelButton: React.Node,
@ -22,6 +23,15 @@ function UserEmail(props: Props) {
isVerified = user.has_verified_email;
}
const buttonsProps = IS_WEB
? {
onClick: () => {
document.cookie = cookie.serialize('auth_token', '');
window.location.reload();
},
}
: { href: 'https://lbry.com/faq/how-to-change-email' };
return (
<section className="card card--section">
{!email && <UserEmailNew />}
@ -43,9 +53,7 @@ function UserEmail(props: Props) {
readOnly
label={__('Your Email')}
value={email}
inputButton={
<Button button="inverse" label={__('Change')} href="https://lbry.com/faq/how-to-change-email" />
}
inputButton={<Button button="inverse" label={__('Change')} {...buttonsProps} />}
/>
)}
<p className="help">

View file

@ -15,9 +15,8 @@ export const SEND = 'send';
export const SETTINGS = 'settings';
export const SHOW = 'show';
export const ACCOUNT = 'account';
export const SUBSCRIPTIONS = 'subscriptions';
export const FOLLOWING = 'following';
export const SEARCH = 'search';
export const TRANSACTIONS = 'transactions';
export const TAGS = 'tags';
export const WALLET = 'wallet';
export const FOLLOWING = 'following';

View file

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

View file

@ -15,7 +15,7 @@ function DiscoverPage(props: Props) {
<ClaimListDiscover
personal
tags={followedTags.map(tag => tag.name)}
injectedItem={<TagsSelect showClose title={__('Make This Your Own')} />}
injectedItem={<TagsSelect showClose title={__('Customize Your Homepage')} />}
/>
</Page>
);

View file

@ -184,6 +184,21 @@ 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">
@ -222,22 +237,11 @@ class FilePage extends React.Component<Props> {
<div className="grid-area--info media__content media__content--large">
<h1 className="media__title media__title--large">{title}</h1>
<div className="media__actions media__actions--between">
<div className="media__subtext media__subtext--large">
<div className="media__subtitle__channel">
<UriIndicator uri={uri} link />
</div>
{__('Published on')} <DateTime uri={uri} show={DateTime.SHOW_DATE} />
<div className="media__subtext media__subtext--large">
<div className="media__subtitle__channel">
<UriIndicator uri={uri} link />
</div>
{claimIsMine && (
<p>
{viewCount} {viewCount !== 1 ? __('Views') : __('View')}
</p>
)}
</div>
<div className="media__actions media__actions--between">
<div className="media__action-group--large">
{claimIsMine && (
@ -282,6 +286,25 @@ class FilePage extends React.Component<Props> {
</div>
</div>
<div
className="media__actions media__actions--between"
style={{ marginTop: '1rem', paddingTop: '1rem', borderTop: '1px solid #ddd' }}
>
<div className="media__subtext media__subtext--large">
<DateTime uri={uri} show={DateTime.SHOW_DATE} />
</div>
<div className="media__subtext media__subtext--large">
{video && <p className="media__info-text">{duration}</p>}
{claimIsMine && (
<p>
{viewCount} {viewCount !== 1 ? __('Views') : __('View')}
</p>
)}
</div>
</div>
<div className="media__info--large">
<ClaimTags uri={uri} type="large" />
</div>

View file

@ -5,26 +5,22 @@ import TagsSelect from 'component/tagsSelect';
import ClaimList from 'component/claimList';
type Props = {
subscribedChannels: Array<{ uri: string }>,
subscribedChannels: Array<Subscription>,
};
function DiscoverPage(props: Props) {
function FollowingEditPage(props: Props) {
const { subscribedChannels } = props;
const channelUris = subscribedChannels.map(({ uri }) => uri);
return (
<Page>
<div className="card">
<TagsSelect showClose={false} title={__('Find New Tags To Follow')} />
</div>
<div className="card">
<ClaimList
header={<h1>{__('Channels You Are Following')}</h1>}
empty={__("You aren't following any channels.")}
uris={subscribedChannels.map(({ uri }) => uri)}
/>
<ClaimList uris={channelUris} />
</div>
</Page>
);
}
export default DiscoverPage;
export default FollowingEditPage;

View file

@ -1,6 +1,6 @@
// @flow
import * as PAGES from 'constants/pages';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import Page from 'component/page';
import ClaimList from 'component/claimList';
import Button from 'component/button';
@ -29,7 +29,7 @@ export default function SubscriptionsPage(props: Props) {
doClaimSearch,
uris,
} = props;
const [page, setPage] = useState(1);
const hasSubscriptions = !!subscribedChannels.length;
const { search } = location;
const urlParams = new URLSearchParams(search);
@ -53,27 +53,31 @@ export default function SubscriptionsPage(props: Props) {
useEffect(() => {
const ids = idString.split(',');
const options = {
page,
channel_ids: ids,
order_by: ['release_time'],
};
doClaimSearch(20, options);
}, [idString, doClaimSearch]);
}, [idString, doClaimSearch, page]);
return (
<Page>
<div className="card">
<ClaimList
loading={loading}
header={<h1>{viewingSuggestedSubs ? __('Discover New Channels') : __('Latest From Your Subscriptions')}</h1>}
header={
<h1>{viewingSuggestedSubs ? __('Discover New Channels') : __("Latest From Who You're Following")}</h1>
}
headerAltControls={
<Button
button="link"
label={viewingSuggestedSubs ? hasSubscriptions && __('Following') : __('Find New Channels')}
label={viewingSuggestedSubs ? hasSubscriptions && __('View Your Feed') : __('Find New Channels')}
onClick={() => onClick()}
/>
}
uris={viewingSuggestedSubs ? suggestedSubscriptions.map(sub => sub.uri) : uris}
onScrollBottom={() => console.log('scroll bottom') || setPage(page + 1)}
/>
</div>
</Page>

View file

@ -4,13 +4,17 @@ import WalletSend from 'component/walletSend';
import WalletAddress from 'component/walletAddress';
import TransactionListRecent from 'component/transactionListRecent';
import Page from 'component/page';
import UnsupportedOnWeb from 'component/common/unsupported-on-web';
const WalletPage = () => (
<Page>
<WalletBalance />
<TransactionListRecent />
<WalletSend />
<WalletAddress />
{IS_WEB && <UnsupportedOnWeb />}
<div className={IS_WEB && 'card--disabled'}>
<WalletBalance />
<TransactionListRecent />
<WalletSend />
<WalletAddress />
</div>
</Page>
);

View file

@ -13,13 +13,13 @@
@import 'component/button';
@import 'component/card';
@import 'component/channel';
@import 'component/claim-list';
@import 'component/comments';
@import 'component/content';
@import 'component/credit';
@import 'component/dat-gui';
@import 'component/expandable';
@import 'component/file-download';
@import 'component/file-list';
@import 'component/file-properties';
@import 'component/file-render';
@import 'component/form-field';

View file

@ -16,7 +16,7 @@ $metadata-z-index: 1;
align-self: flex-start;
position: absolute;
object-fit: cover;
filter: brightness(60%);
filter: brightness(50%);
}
.channel-cover,
@ -27,8 +27,8 @@ $metadata-z-index: 1;
.channel-thumbnail {
display: flex;
height: 5.3rem;
width: 5.4rem;
height: 5rem;
width: 6rem;
background-size: cover;
margin-right: var(--spacing-medium);
}
@ -52,7 +52,6 @@ $metadata-z-index: 1;
margin-left: auto;
margin-right: auto;
align-self: flex-end;
// margin-bottom: -1px;
}
.channel-thumbnail,

View file

@ -43,6 +43,7 @@
background-size: 1.2rem;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 96 96' xmlns='http://www.w3.org/2000/svg' fill='%23ffffff'%3E%3Cpath d='M17.172, 31.172c1.562, -1.562 4.095, -1.562 5.656, 0l25.172, 25.171l25.172, -25.171c1.562, -1.562 4.095, -1.562 5.656, 0c1.562, 1.562 1.562, 4.095 0, 5.656l-28, 28c-1.562, 1.562 -4.095, 1.562 -5.656, 0l-28, -28c-0.781, -0.781 -1.172, -1.805 -1.172, -2.828c0, -1.023 0.391, -2.047 1.172, -2.828Z'/%3E%3C/svg%3E%0A");
height: 2.5rem;
font-size: 1.3rem;
padding: 0 var(--spacing-medium);
padding-right: var(--spacing-large);
margin-bottom: 0;
@ -60,16 +61,6 @@
}
}
.claim-list__header-text {
display: flex;
align-items: center;
}
.claim-list__header-text,
.claim-list__dropdown {
font-size: 1.3rem;
}
.claim-list__alt-controls {
display: flex;
align-items: center;
@ -81,7 +72,7 @@
}
}
.claim-list__item {
.claim-preview {
display: flex;
position: relative;
font-size: 1.3rem;
@ -104,12 +95,12 @@
}
}
.claim-list__item--injected,
.claim-list__item + .claim-list__item {
.claim-preview--injected,
.claim-preview {
border-top: 1px solid rgba($lbry-teal-5, 0.1);
}
.claim-list__item--large {
.claim-preview--large {
@include mediaThumbHoverZoom;
font-size: 1.6rem;
border-bottom: 0;
@ -138,32 +129,32 @@
}
}
.claim-list__item-metadata {
.claim-preview-metadata {
display: flex;
flex-direction: column;
width: 100%;
}
.claim-list__item-info {
.claim-preview-info {
align-items: flex-start;
}
.claim-list__item-info,
.claim-list__item-properties {
.claim-preview-info,
.claim-preview-properties {
display: flex;
justify-content: space-between;
}
.claim-list__item-properties {
.claim-preview-properties {
align-items: flex-end;
}
.claim-list__item-title {
.claim-preview-title {
font-weight: 600;
margin-right: auto;
}
.claim-list__item-tags {
.claim-preview-tags {
margin-left: 0;
}

View file

@ -3,6 +3,14 @@
position: relative;
align-items: center;
.icon {
stroke: rgba($lbry-black, 0.5);
html[data-mode='dark'] & {
stroke: rgba($lbry-white, 0.7);
}
}
& > *:not(:last-child) {
margin-right: var(--spacing-small);
}

View file

@ -132,10 +132,6 @@
color: rgba($lbry-black, 0.8);
font-size: 0.9em;
&:not(:last-child) {
margin-bottom: var(--spacing-medium);
}
html[data-mode='dark'] & {
color: rgba($lbry-white, 0.7);
}
@ -150,7 +146,7 @@
.media__subtitle {
font-size: 0.8em;
color: rgba($lbry-black, 0.8);
color: rgba($lbry-black, 0.6);
[data-mode='dark'] & {
color: rgba($lbry-white, 0.8);
@ -167,6 +163,7 @@
.media__subtitle__channel {
font-weight: 600;
margin: var(--spacing-small) 0;
}
// M E D I A
@ -181,7 +178,7 @@
}
.media__info--large {
border-top: 1px solid $lbry-gray-1;
// border-top: 1px solid $lbry-gray-1;
margin-top: var(--spacing-medium);
html[data-mode='dark'] & {

View file

@ -9,7 +9,7 @@
.placeholder {
display: flex;
&.claim-list__item-title {
&.claim-preview-title {
width: 100%;
height: 3rem;
}

View file

@ -90,7 +90,6 @@
.icon {
margin-right: var(--spacing-small);
margin-bottom: 0.2rem;
stroke: $lbry-gray-5;
}

View file

@ -1,6 +1,6 @@
@mixin placeholder {
animation: pulse 2s infinite ease-in-out;
background-color: $lbry-gray-2;
background-color: $lbry-gray-1;
border-radius: var(--card-radius);
}

View file

@ -12,7 +12,7 @@
<meta property="og:description" content="All your favorite LBRY content in your browser." />
<meta property="og:image" content="/og.png" />
<!-- @endif -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1" /> -->
</head>
<body>

View file

@ -6641,9 +6641,9 @@ lazy-val@^1.0.3, lazy-val@^1.0.4:
yargs "^13.2.2"
zstd-codec "^0.1.1"
lbry-redux@lbryio/lbry-redux#b3bf3f6d53410ff1c5415b51ca425341e364959f:
lbry-redux@lbryio/lbry-redux#2930ad82a90ca91f6caf3761597ef9a67da7db66:
version "0.0.1"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/b3bf3f6d53410ff1c5415b51ca425341e364959f"
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/2930ad82a90ca91f6caf3761597ef9a67da7db66"
dependencies:
proxy-polyfill "0.1.6"
reselect "^3.0.0"