restore that shit
This commit is contained in:
parent
155716ee1a
commit
1015abbb87
29 changed files with 329 additions and 186 deletions
|
@ -158,6 +158,7 @@
|
|||
"react-router-dom": "^5.0.0",
|
||||
"react-simplemde-editor": "^4.0.0",
|
||||
"react-spring": "^8.0.20",
|
||||
"react-sticky-box": "^0.8.0",
|
||||
"react-toggle": "^4.0.2",
|
||||
"redux": "^3.6.0",
|
||||
"redux-persist": "^4.8.0",
|
||||
|
|
|
@ -51,14 +51,12 @@ function App(props: Props) {
|
|||
}, [userId]);
|
||||
|
||||
return (
|
||||
<div ref={appRef} onContextMenu={e => openContextMenu(e)}>
|
||||
<div className="main-wrapper" ref={appRef} onContextMenu={e => openContextMenu(e)}>
|
||||
<Header />
|
||||
|
||||
<div className={MAIN_WRAPPER_CLASS}>
|
||||
<div className="main-wrapper-inner">
|
||||
<Router />
|
||||
<SideBar />
|
||||
</div>
|
||||
<div className="main-wrapper__inner">
|
||||
<Router />
|
||||
<SideBar />
|
||||
</div>
|
||||
|
||||
<ModalRouter />
|
||||
|
|
|
@ -118,14 +118,14 @@ function ChannelForm(props: Props) {
|
|||
onUpdate={v => handleThumbnailChange(v)}
|
||||
currentValue={params.thumbnail}
|
||||
assetName={'Thumbnail'}
|
||||
recommended={'(400x400)'}
|
||||
recommended={'(300 x 300)'}
|
||||
/>
|
||||
|
||||
<SelectAsset
|
||||
onUpdate={v => handleCoverChange(v)}
|
||||
currentValue={params.cover}
|
||||
assetName={'Cover'}
|
||||
recommended={'(1000x300)'}
|
||||
recommended={'(1000 x 160)'}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
|
|
|
@ -39,18 +39,16 @@ export default function ClaimList(props: Props) {
|
|||
type,
|
||||
header,
|
||||
onScrollBottom,
|
||||
page,
|
||||
pageSize,
|
||||
} = props;
|
||||
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
|
||||
const hasUris = uris && !!uris.length;
|
||||
const sortedUris = (hasUris && (currentSort === SORT_NEW ? uris : uris.slice().reverse())) || [];
|
||||
const urisLength = (uris && uris.length) || 0;
|
||||
const sortedUris = (urisLength > 0 && (currentSort === SORT_NEW ? uris : uris.slice().reverse())) || [];
|
||||
|
||||
function handleSortChange() {
|
||||
setCurrentSort(currentSort === SORT_NEW ? SORT_OLD : SORT_NEW);
|
||||
}
|
||||
|
||||
const urisLength = uris && uris.length;
|
||||
useEffect(() => {
|
||||
function handleScroll(e) {
|
||||
if (pageSize && onScrollBottom) {
|
||||
|
@ -71,7 +69,7 @@ export default function ClaimList(props: Props) {
|
|||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}
|
||||
}, [loading, onScrollBottom, urisLength]);
|
||||
}, [loading, onScrollBottom, urisLength, pageSize]);
|
||||
|
||||
return (
|
||||
<section
|
||||
|
@ -100,17 +98,17 @@ export default function ClaimList(props: Props) {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{hasUris && (
|
||||
{urisLength > 0 && (
|
||||
<ul>
|
||||
{sortedUris.map((uri, index) => (
|
||||
<React.Fragment key={uri}>
|
||||
<ClaimPreview uri={uri} type={type} placeholder={loading && (!page || page === 1)} />
|
||||
<ClaimPreview uri={uri} type={type} />
|
||||
{index === 4 && injectedItem && <li className="claim-preview--injected">{injectedItem}</li>}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{!hasUris && !loading && <h2 className="main--empty empty">{empty || __('No results')}</h2>}
|
||||
{urisLength === 0 && !loading && <h2 className="main--empty empty">{empty || __('No results')}</h2>}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import { connect } from 'react-redux';
|
||||
import { doClaimSearch, selectLastClaimSearchUris, selectFetchingClaimSearch, doToggleTagFollow } from 'lbry-redux';
|
||||
import { doClaimSearch, selectClaimSearchByQuery, selectFetchingClaimSearch, doToggleTagFollow } from 'lbry-redux';
|
||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import ClaimListDiscover from './view';
|
||||
|
||||
const select = state => ({
|
||||
uris: selectLastClaimSearchUris(state),
|
||||
claimSearchByQuery: selectClaimSearchByQuery(state),
|
||||
loading: selectFetchingClaimSearch(state),
|
||||
subscribedChannels: selectSubscriptions(state),
|
||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
// @flow
|
||||
import type { Node } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import moment from 'moment';
|
||||
import usePersistedState from 'util/use-persisted-state';
|
||||
import { MATURE_TAGS } from 'lbry-redux';
|
||||
import React, { useEffect } from 'react';
|
||||
import { withRouter } from 'react-router';
|
||||
import { buildClaimSearchCacheQuery, MATURE_TAGS } from 'lbry-redux';
|
||||
import { FormField } from 'component/common/form';
|
||||
import moment from 'moment';
|
||||
import ClaimList from 'component/claimList';
|
||||
import Tag from 'component/tag';
|
||||
import ClaimPreview from 'component/claimPreview';
|
||||
import { updateQueryParam } from 'util/query-params';
|
||||
import { toCapitalCase } from 'util/string';
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
const TIME_DAY = 'day';
|
||||
|
@ -33,75 +35,118 @@ type Props = {
|
|||
injectedItem: any,
|
||||
tags: Array<string>,
|
||||
loading: boolean,
|
||||
personal: boolean,
|
||||
personalView: boolean,
|
||||
doToggleTagFollow: string => void,
|
||||
meta?: Node,
|
||||
showNsfw: boolean,
|
||||
history: { action: string, push: string => void, replace: string => void },
|
||||
location: { search: string, pathname: string },
|
||||
claimSearchByQuery: {
|
||||
[string]: Array<string>,
|
||||
},
|
||||
};
|
||||
|
||||
function ClaimListDiscover(props: Props) {
|
||||
const { doClaimSearch, uris, tags, loading, personal, injectedItem, meta, subscribedChannels, showNsfw } = props;
|
||||
const [personalSort, setPersonalSort] = usePersistedState('claim-list-discover:personalSort', SEARCH_SORT_YOU);
|
||||
const [typeSort, setTypeSort] = usePersistedState('claim-list-discover:typeSort', TYPE_TRENDING);
|
||||
const [timeSort, setTimeSort] = usePersistedState('claim-list-discover:timeSort', TIME_WEEK);
|
||||
const [page, setPage] = useState(1);
|
||||
const {
|
||||
doClaimSearch,
|
||||
claimSearchByQuery,
|
||||
tags,
|
||||
loading,
|
||||
personalView,
|
||||
injectedItem,
|
||||
meta,
|
||||
subscribedChannels,
|
||||
showNsfw,
|
||||
history,
|
||||
location,
|
||||
} = props;
|
||||
const didNavigateForward = history.action === 'PUSH';
|
||||
const { search, pathname } = location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const personalSort = urlParams.get('sort') || SEARCH_SORT_YOU;
|
||||
const typeSort = urlParams.get('type') || TYPE_TRENDING;
|
||||
const timeSort = urlParams.get('time') || TIME_WEEK;
|
||||
const page = Number(urlParams.get('page')) || 1;
|
||||
const tagsInUrl = urlParams.get('t') || '';
|
||||
const url = `${pathname}${search}`;
|
||||
const options: {
|
||||
page_size: number,
|
||||
page: number,
|
||||
no_totals: boolean,
|
||||
any_tags: Array<string>,
|
||||
channel_ids: Array<string>,
|
||||
not_tags: Array<string>,
|
||||
order_by: Array<string>,
|
||||
release_time?: string,
|
||||
} = {
|
||||
page_size: PAGE_SIZE,
|
||||
page,
|
||||
// no_totals makes it so the sdk doesn't have to calculate total number pages for pagination
|
||||
// it's faster, but we will need to remove it if we start using total_pages
|
||||
no_totals: true,
|
||||
any_tags: (personalView && personalSort === SEARCH_SORT_YOU) || !personalView ? tags : [],
|
||||
channel_ids: personalSort === SEARCH_SORT_CHANNELS ? subscribedChannels.map(sub => sub.uri.split('#')[1]) : [],
|
||||
not_tags: !showNsfw ? MATURE_TAGS : [],
|
||||
order_by:
|
||||
typeSort === TYPE_TRENDING
|
||||
? ['trending_global', 'trending_mixed']
|
||||
: typeSort === TYPE_NEW
|
||||
? ['release_time']
|
||||
: ['effective_amount'], // Sort by top
|
||||
};
|
||||
|
||||
if (typeSort === TYPE_TOP && timeSort !== TIME_ALL) {
|
||||
options.release_time = `>${Math.floor(
|
||||
moment()
|
||||
.subtract(1, timeSort)
|
||||
.unix()
|
||||
)}`;
|
||||
}
|
||||
|
||||
const claimSearchCacheQuery = buildClaimSearchCacheQuery(options);
|
||||
const uris = claimSearchByQuery[claimSearchCacheQuery] || [];
|
||||
const shouldPerformSearch = uris.length === 0 || didNavigateForward || (!loading && uris.length < PAGE_SIZE * page);
|
||||
// Don't use the query from buildClaimSearchCacheQuery for the effect since that doesn't include page & release_time
|
||||
const optionsStringForEffect = JSON.stringify(options);
|
||||
|
||||
function getSearch() {
|
||||
let search = `?`;
|
||||
if (!personalView) {
|
||||
search += `t=${tagsInUrl}&`;
|
||||
}
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
function handleTypeSort(newTypeSort) {
|
||||
let url = `${getSearch()}type=${newTypeSort}&sort=${personalSort}`;
|
||||
if (newTypeSort === TYPE_TOP) {
|
||||
url += `&time=${timeSort}`;
|
||||
}
|
||||
history.push(url);
|
||||
}
|
||||
|
||||
function handlePersonalSort(newPersonalSort) {
|
||||
history.push(`${getSearch()}type=${typeSort}&sort=${newPersonalSort}`);
|
||||
}
|
||||
|
||||
function handleTimeSort(newTimeSort) {
|
||||
history.push(`${getSearch()}type=${typeSort}&sort=${personalSort}&time=${newTimeSort}`);
|
||||
}
|
||||
|
||||
function handleScrollBottom() {
|
||||
if (!loading) {
|
||||
const uri = updateQueryParam(url, 'page', page + 1);
|
||||
history.replace(uri);
|
||||
}
|
||||
}
|
||||
|
||||
const toCapitalCase = string => string.charAt(0).toUpperCase() + string.slice(1);
|
||||
const tagsString = tags.join(',');
|
||||
const channelsIdString = subscribedChannels.map(channel => channel.uri.split('#')[1]).join(',');
|
||||
useEffect(() => {
|
||||
const options: {
|
||||
page_size: number,
|
||||
any_tags?: Array<string>,
|
||||
order_by?: Array<string>,
|
||||
channel_ids?: Array<string>,
|
||||
release_time?: string,
|
||||
not_tags?: Array<string>,
|
||||
} = { page_size: PAGE_SIZE, page, no_totals: true };
|
||||
const newTags = tagsString.split(',');
|
||||
const newChannelIds = channelsIdString.split(',');
|
||||
|
||||
if ((newTags && !personal) || (newTags && personal && personalSort === SEARCH_SORT_YOU)) {
|
||||
options.any_tags = newTags;
|
||||
} else if (personalSort === SEARCH_SORT_CHANNELS) {
|
||||
options.channel_ids = newChannelIds;
|
||||
if (shouldPerformSearch) {
|
||||
const searchOptions = JSON.parse(optionsStringForEffect);
|
||||
doClaimSearch(searchOptions);
|
||||
}
|
||||
|
||||
if (!showNsfw) {
|
||||
options.not_tags = MATURE_TAGS;
|
||||
}
|
||||
|
||||
if (typeSort === TYPE_TRENDING) {
|
||||
options.order_by = ['trending_global', 'trending_mixed'];
|
||||
} else if (typeSort === TYPE_NEW) {
|
||||
options.order_by = ['release_time'];
|
||||
} else if (typeSort === TYPE_TOP) {
|
||||
options.order_by = ['effective_amount'];
|
||||
if (timeSort !== TIME_ALL) {
|
||||
const time = Math.floor(
|
||||
moment()
|
||||
.subtract(1, timeSort)
|
||||
.unix()
|
||||
);
|
||||
options.release_time = `>${time}`;
|
||||
}
|
||||
}
|
||||
|
||||
options.page_size = PAGE_SIZE;
|
||||
doClaimSearch(options);
|
||||
}, [personal, personalSort, typeSort, timeSort, doClaimSearch, page, tagsString, channelsIdString, showNsfw]);
|
||||
|
||||
function getLabel(type) {
|
||||
if (type === SEARCH_SORT_ALL) {
|
||||
return __('Everyone');
|
||||
}
|
||||
|
||||
return type === SEARCH_SORT_YOU ? __('Tags You Follow') : __('Channels You Follow');
|
||||
}
|
||||
|
||||
function resetList() {
|
||||
setPage(1);
|
||||
}
|
||||
}, [doClaimSearch, shouldPerformSearch, optionsStringForEffect]);
|
||||
|
||||
const header = (
|
||||
<h1 className="card__title--flex">
|
||||
|
@ -110,10 +155,7 @@ function ClaimListDiscover(props: Props) {
|
|||
type="select"
|
||||
name="trending_sort"
|
||||
value={typeSort}
|
||||
onChange={e => {
|
||||
resetList();
|
||||
setTypeSort(e.target.value);
|
||||
}}
|
||||
onChange={e => handleTypeSort(e.target.value)}
|
||||
>
|
||||
{SEARCH_TYPES.map(type => (
|
||||
<option key={type} value={type}>
|
||||
|
@ -122,7 +164,7 @@ function ClaimListDiscover(props: Props) {
|
|||
))}
|
||||
</FormField>
|
||||
<span>{__('For')}</span>
|
||||
{!personal && tags && tags.length ? (
|
||||
{!personalView && tags && tags.length ? (
|
||||
tags.map(tag => <Tag key={tag} name={tag} disabled />)
|
||||
) : (
|
||||
<FormField
|
||||
|
@ -131,13 +173,16 @@ function ClaimListDiscover(props: Props) {
|
|||
className="claim-list__dropdown"
|
||||
value={personalSort}
|
||||
onChange={e => {
|
||||
resetList();
|
||||
setPersonalSort(e.target.value);
|
||||
handlePersonalSort(e.target.value);
|
||||
}}
|
||||
>
|
||||
{SEARCH_FILTER_TYPES.map(type => (
|
||||
<option key={type} value={type}>
|
||||
{getLabel(type)}
|
||||
{type === SEARCH_SORT_ALL
|
||||
? __('Everyone')
|
||||
: type === SEARCH_SORT_YOU
|
||||
? __('Tags You Follow')
|
||||
: __('Channels You Follow')}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
|
@ -148,10 +193,7 @@ function ClaimListDiscover(props: Props) {
|
|||
type="select"
|
||||
name="trending_time"
|
||||
value={timeSort}
|
||||
onChange={e => {
|
||||
resetList();
|
||||
setTimeSort(e.target.value);
|
||||
}}
|
||||
onChange={e => handleTimeSort(e.target.value)}
|
||||
>
|
||||
{SEARCH_TIMES.map(time => (
|
||||
<option key={time} value={time}>
|
||||
|
@ -174,14 +216,14 @@ function ClaimListDiscover(props: Props) {
|
|||
injectedItem={personalSort === SEARCH_SORT_YOU && injectedItem}
|
||||
header={header}
|
||||
headerAltControls={meta}
|
||||
onScrollBottom={() => setPage(page + 1)}
|
||||
onScrollBottom={handleScrollBottom}
|
||||
page={page}
|
||||
pageSize={PAGE_SIZE}
|
||||
/>
|
||||
|
||||
{loading && page > 1 && new Array(PAGE_SIZE).fill(1).map((x, i) => <ClaimPreview key={i} placeholder />)}
|
||||
{loading && new Array(PAGE_SIZE).fill(1).map((x, i) => <ClaimPreview key={i} placeholder />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClaimListDiscover;
|
||||
export default withRouter(ClaimListDiscover);
|
||||
|
|
|
@ -100,13 +100,13 @@ function ClaimPreview(props: Props) {
|
|||
if (isValid && !isResolvingUri && haventFetched && uri) {
|
||||
resolveUri(uri);
|
||||
}
|
||||
}, [isResolvingUri, uri, resolveUri, haventFetched]);
|
||||
}, [isValid, isResolvingUri, uri, resolveUri, haventFetched]);
|
||||
|
||||
if (shouldHide) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (placeholder || isResolvingUri) {
|
||||
if (placeholder || (isResolvingUri && !claim)) {
|
||||
return (
|
||||
<li className="claim-preview" disabled>
|
||||
<div className="placeholder media__thumb" />
|
||||
|
|
|
@ -30,6 +30,7 @@ export function CommentCreate(props: Props) {
|
|||
function handleCommentAck(event) {
|
||||
setCommentAck(true);
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
if (channel !== CHANNEL_NEW && commentValue.length) createComment(commentValue, claimId, channel);
|
||||
setCommentValue('');
|
||||
|
|
|
@ -15,7 +15,7 @@ type Props = {
|
|||
isUpgradeAvailable: boolean,
|
||||
roundedBalance: number,
|
||||
downloadUpgradeRequested: any => void,
|
||||
history: { push: string => void },
|
||||
history: { push: string => void, goBack: () => void, goForward: () => void },
|
||||
currentTheme: string,
|
||||
automaticDarkModeEnabled: boolean,
|
||||
setClientSetting: (string, boolean | string) => void,
|
||||
|
@ -51,7 +51,7 @@ const Header = (props: Props) => {
|
|||
<Button
|
||||
className="header__navigation-item header__navigation-item--back"
|
||||
description={__('Navigate back')}
|
||||
onClick={() => window.history.back()}
|
||||
onClick={() => history.goBack()}
|
||||
icon={ICONS.ARROW_LEFT}
|
||||
iconSize={18}
|
||||
/>
|
||||
|
@ -59,7 +59,7 @@ const Header = (props: Props) => {
|
|||
<Button
|
||||
className="header__navigation-item header__navigation-item--forward"
|
||||
description={__('Navigate forward')}
|
||||
onClick={() => window.history.forward()}
|
||||
onClick={() => history.goForward()}
|
||||
icon={ICONS.ARROW_RIGHT}
|
||||
iconSize={18}
|
||||
/>
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import Router from './view';
|
||||
export default Router;
|
||||
|
||||
const select = state => ({
|
||||
scroll: state.app.scrollHistory[state.app.scrollHistory.length - 1],
|
||||
scrollHistory: state.app.scrollHistory,
|
||||
currentScroll: state.app.currentScroll || 0,
|
||||
});
|
||||
|
||||
export default connect(select)(Router);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Route, Redirect, Switch, withRouter } from 'react-router-dom';
|
||||
|
@ -21,49 +22,56 @@ import NavigationHistory from 'page/navigationHistory';
|
|||
import TagsPage from 'page/tags';
|
||||
import FollowingPage from 'page/following';
|
||||
|
||||
const Scroll = withRouter(function ScrollWrapper(props) {
|
||||
const { pathname } = props.location;
|
||||
// Let app handle scroll
|
||||
if ('scrollRestoration' in history) {
|
||||
history.scrollRestoration = 'manual';
|
||||
}
|
||||
|
||||
type Props = {
|
||||
currentScroll: number,
|
||||
location: { pathname: string, search: string },
|
||||
};
|
||||
|
||||
function AppRouter(props: Props) {
|
||||
const { currentScroll, location } = props;
|
||||
const { pathname, search } = location;
|
||||
|
||||
// Don't update the scroll position if only the `page` param changes
|
||||
const url = `${pathname}${search.replace(/&?\??page=\d+/, '')}`;
|
||||
|
||||
useEffect(() => {
|
||||
// Auto scroll to the top of a window for new pages
|
||||
// The browser will handle scrolling if it needs to, but
|
||||
// for new pages, react-router maintains the current y scroll position
|
||||
window.scrollTo(0, 0);
|
||||
}, [pathname]);
|
||||
window.scrollTo(0, currentScroll);
|
||||
}, [currentScroll, url]);
|
||||
|
||||
return props.children;
|
||||
});
|
||||
|
||||
export default function AppRouter() {
|
||||
return (
|
||||
<Scroll>
|
||||
<Switch>
|
||||
<Route path="/" exact component={DiscoverPage} />
|
||||
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
||||
<Route path={`/$/${PAGES.AUTH}`} exact component={AuthPage} />
|
||||
<Route path={`/$/${PAGES.INVITE}`} exact component={InvitePage} />
|
||||
<Route path={`/$/${PAGES.DOWNLOADED}`} exact component={FileListDownloaded} />
|
||||
<Route path={`/$/${PAGES.PUBLISHED}`} exact component={FileListPublished} />
|
||||
<Route path={`/$/${PAGES.HELP}`} exact component={HelpPage} />
|
||||
<Route path={`/$/${PAGES.PUBLISH}`} exact component={PublishPage} />
|
||||
<Route path={`/$/${PAGES.REPORT}`} exact component={ReportPage} />
|
||||
<Route path={`/$/${PAGES.REWARDS}`} exact component={RewardsPage} />
|
||||
<Route path={`/$/${PAGES.SEARCH}`} exact component={SearchPage} />
|
||||
<Route path={`/$/${PAGES.SETTINGS}`} exact component={SettingsPage} />
|
||||
<Route path={`/$/${PAGES.TRANSACTIONS}`} exact component={TransactionHistoryPage} />
|
||||
<Route path={`/$/${PAGES.LIBRARY}`} exact component={LibraryPage} />
|
||||
<Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} />
|
||||
<Route path={`/$/${PAGES.LIBRARY}/all`} exact component={NavigationHistory} />
|
||||
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
|
||||
<Route path={`/$/${PAGES.FOLLOWING}`} exact component={FollowingPage} />
|
||||
<Route path={`/$/${PAGES.WALLET}`} exact component={WalletPage} />
|
||||
{/* Below need to go at the end to make sure we don't match any of our pages first */}
|
||||
<Route path="/:claimName" exact component={ShowPage} />
|
||||
<Route path="/:claimName/:contentName" exact component={ShowPage} />
|
||||
<Switch>
|
||||
<Route path="/" exact component={DiscoverPage} />
|
||||
<Route path={`/$/${PAGES.DISCOVER}`} exact component={DiscoverPage} />
|
||||
<Route path={`/$/${PAGES.AUTH}`} exact component={AuthPage} />
|
||||
<Route path={`/$/${PAGES.INVITE}`} exact component={InvitePage} />
|
||||
<Route path={`/$/${PAGES.DOWNLOADED}`} exact component={FileListDownloaded} />
|
||||
<Route path={`/$/${PAGES.PUBLISHED}`} exact component={FileListPublished} />
|
||||
<Route path={`/$/${PAGES.HELP}`} exact component={HelpPage} />
|
||||
<Route path={`/$/${PAGES.PUBLISH}`} exact component={PublishPage} />
|
||||
<Route path={`/$/${PAGES.REPORT}`} exact component={ReportPage} />
|
||||
<Route path={`/$/${PAGES.REWARDS}`} exact component={RewardsPage} />
|
||||
<Route path={`/$/${PAGES.SEARCH}`} exact component={SearchPage} />
|
||||
<Route path={`/$/${PAGES.SETTINGS}`} exact component={SettingsPage} />
|
||||
<Route path={`/$/${PAGES.TRANSACTIONS}`} exact component={TransactionHistoryPage} />
|
||||
<Route path={`/$/${PAGES.LIBRARY}`} exact component={LibraryPage} />
|
||||
<Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} />
|
||||
<Route path={`/$/${PAGES.LIBRARY}/all`} exact component={NavigationHistory} />
|
||||
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
|
||||
<Route path={`/$/${PAGES.FOLLOWING}`} exact component={FollowingPage} />
|
||||
<Route path={`/$/${PAGES.WALLET}`} exact component={WalletPage} />
|
||||
{/* Below need to go at the end to make sure we don't match any of our pages first */}
|
||||
<Route path="/:claimName" exact component={ShowPage} />
|
||||
<Route path="/:claimName/:contentName" exact component={ShowPage} />
|
||||
|
||||
{/* Route not found. Mostly for people typing crazy urls into the url */}
|
||||
<Route render={() => <Redirect to="/" />} />
|
||||
</Switch>
|
||||
</Scroll>
|
||||
{/* Route not found. Mostly for people typing crazy urls into the url */}
|
||||
<Route render={() => <Redirect to="/" />} />
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(AppRouter);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import Tag from 'component/tag';
|
||||
import StickyBox from 'react-sticky-box/dist/esnext';
|
||||
|
||||
type Props = {
|
||||
subscriptions: Array<Subscription>,
|
||||
|
@ -12,21 +13,18 @@ type Props = {
|
|||
|
||||
function SideBar(props: Props) {
|
||||
const { subscriptions, followedTags } = props;
|
||||
const buildLink = (path, label, icon, guide) => ({
|
||||
navigate: path ? `$/${path}` : '/',
|
||||
label,
|
||||
icon,
|
||||
guide,
|
||||
});
|
||||
|
||||
const renderLink = linkProps => (
|
||||
<li key={linkProps.label}>
|
||||
<Button {...linkProps} className="navigation__link" activeClass="navigation__link--active" />
|
||||
</li>
|
||||
);
|
||||
function buildLink(path, label, icon, guide) {
|
||||
return {
|
||||
navigate: path ? `$/${path}` : '/',
|
||||
label,
|
||||
icon,
|
||||
guide,
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="navigation-wrapper">
|
||||
<StickyBox offsetBottom={40} offsetTop={100}>
|
||||
<nav className="navigation">
|
||||
<ul className="navigation__links">
|
||||
{[
|
||||
|
@ -39,7 +37,14 @@ function SideBar(props: Props) {
|
|||
{
|
||||
...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISH),
|
||||
},
|
||||
].map(renderLink)}
|
||||
{
|
||||
...buildLink(PAGES.FOLLOWING, __('Customize'), ICONS.EDIT),
|
||||
},
|
||||
].map(linkProps => (
|
||||
<li key={linkProps.label}>
|
||||
<Button {...linkProps} className="navigation__link" activeClass="navigation__link--active" />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="navigation__links tags--vertical">
|
||||
{followedTags.map(({ name }, key) => (
|
||||
|
@ -61,7 +66,7 @@ function SideBar(props: Props) {
|
|||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</StickyBox>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ export default class SplashScreen extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.onReadyToLaunch();
|
||||
|
||||
const { checkDaemonVersion } = this.props;
|
||||
this.adjustErrorTimeout();
|
||||
Lbry.connect()
|
||||
|
|
|
@ -63,7 +63,7 @@ class UriIndicator extends React.PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<Button className="button--uri-indicator" navigate={channelLink}>
|
||||
<Tooltip label={<ClaimPreview uri={channelLink} type="small" />}>{inner}</Tooltip>
|
||||
<Tooltip label={'test' || <ClaimPreview uri={channelLink} type="small" />}>{inner}</Tooltip>
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
makeSelectThumbnailForUri,
|
||||
makeSelectCoverForUri,
|
||||
selectCurrentChannelPage,
|
||||
makeSelectClaimForUri,
|
||||
} from 'lbry-redux';
|
||||
import ChannelPage from './view';
|
||||
|
||||
|
@ -14,6 +15,7 @@ const select = (state, props) => ({
|
|||
cover: makeSelectCoverForUri(props.uri)(state),
|
||||
channelIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
page: selectCurrentChannelPage(state),
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -20,6 +20,7 @@ const ABOUT_PAGE = `about`;
|
|||
|
||||
type Props = {
|
||||
uri: string,
|
||||
claim: ChannelClaim,
|
||||
title: ?string,
|
||||
cover: ?string,
|
||||
thumbnail: ?string,
|
||||
|
@ -31,12 +32,12 @@ type Props = {
|
|||
};
|
||||
|
||||
function ChannelPage(props: Props) {
|
||||
const { uri, title, cover, history, location, page, channelIsMine, thumbnail } = props;
|
||||
const { uri, title, cover, history, location, page, channelIsMine, thumbnail, claim } = props;
|
||||
const { channelName } = parseURI(uri);
|
||||
const { search } = location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const currentView = urlParams.get(PAGE_VIEW_QUERY) || undefined;
|
||||
|
||||
const { permanent_url: permanentUrl } = claim;
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [thumbPreview, setThumbPreview] = useState(thumbnail);
|
||||
const [coverPreview, setCoverPreview] = useState(cover);
|
||||
|
@ -90,7 +91,7 @@ function ChannelPage(props: Props) {
|
|||
<Tab>{editing ? __('Editing Your Channel') : __('About')}</Tab>
|
||||
<div className="card__actions">
|
||||
<ShareButton uri={uri} />
|
||||
<SubscribeButton uri={uri} />
|
||||
<SubscribeButton uri={permanentUrl} />
|
||||
</div>
|
||||
</TabList>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ function DiscoverPage(props: Props) {
|
|||
return (
|
||||
<Page>
|
||||
<ClaimListDiscover
|
||||
personal
|
||||
personalView
|
||||
tags={followedTags.map(tag => tag.name)}
|
||||
meta={<Button button="link" label={__('Customize')} navigate={`/$/${PAGES.FOLLOWING}`} />}
|
||||
injectedItem={<TagsSelect showClose title={__('Customize Your Homepage')} />}
|
||||
|
|
|
@ -63,6 +63,29 @@ const defaultState: AppState = {
|
|||
isUpgradeSkipped: undefined,
|
||||
enhancedLayout: false,
|
||||
searchOptionsExpanded: false,
|
||||
currentScroll: 0,
|
||||
scrollHistory: [0],
|
||||
};
|
||||
|
||||
reducers['@@router/LOCATION_CHANGE'] = (state, action) => {
|
||||
const { currentScroll } = state;
|
||||
const scrollHistory = state.scrollHistory.slice();
|
||||
const { action: name } = action.payload;
|
||||
|
||||
let newCurrentScroll = currentScroll;
|
||||
if (name === 'PUSH') {
|
||||
scrollHistory.push(window.scrollY);
|
||||
newCurrentScroll = 0;
|
||||
} else if (name === 'POP') {
|
||||
newCurrentScroll = scrollHistory[scrollHistory.length - 1];
|
||||
scrollHistory.pop();
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
scrollHistory,
|
||||
currentScroll: newCurrentScroll,
|
||||
};
|
||||
};
|
||||
|
||||
reducers[ACTIONS.DAEMON_READY] = state =>
|
||||
|
|
|
@ -189,4 +189,9 @@
|
|||
|
||||
.claim-preview-tags {
|
||||
margin-left: 0;
|
||||
|
||||
// change this
|
||||
.tag {
|
||||
max-width: 10rem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,25 @@
|
|||
.main-wrapper {
|
||||
position: absolute;
|
||||
min-height: 100vh;
|
||||
width: 100vw;
|
||||
padding-top: var(--header-height);
|
||||
padding-left: var(--spacing-large);
|
||||
padding-right: var(--spacing-large);
|
||||
padding-bottom: var(--spacing-large);
|
||||
display: flex;
|
||||
|
||||
[data-mode='dark'] & {
|
||||
background-color: var(--dm-color-08);
|
||||
}
|
||||
}
|
||||
|
||||
.main-wrapper-inner {
|
||||
.main-wrapper__inner {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
min-height: 100vh;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: var(--spacing-large);
|
||||
position: relative;
|
||||
padding-bottom: var(--spacing-main-padding);
|
||||
}
|
||||
|
||||
.main {
|
||||
min-width: 0;
|
||||
width: calc(100% - var(--side-nav-width) - var(--spacing-main-padding));
|
||||
position: relative;
|
||||
margin-top: calc(var(--header-height) + var(--spacing-large));
|
||||
margin-right: var(--spacing-main-padding);
|
||||
|
||||
@media (max-width: 600px) {
|
||||
width: 100%;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
.navigation-wrapper {
|
||||
width: var(--side-nav-width);
|
||||
left: calc(100% - var(--side-nav-width));
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
// width: var(--side-nav-width);
|
||||
// left: calc(100% - var(--side-nav-width));
|
||||
// height: 100%;
|
||||
// position: absolute;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
width: var(--side-nav-width);
|
||||
padding-bottom: var(--spacing-main-padding);
|
||||
font-size: 1.4rem;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
|
|
@ -45,7 +45,6 @@ $main: $lbry-teal-5;
|
|||
white-space: nowrap;
|
||||
text-transform: lowercase;
|
||||
font-size: 0.7em;
|
||||
max-width: 10rem;
|
||||
min-width: 0;
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -6,6 +6,7 @@ html {
|
|||
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
|
||||
&[data-mode='dark'] {
|
||||
|
@ -20,7 +21,6 @@ body {
|
|||
font-weight: 400;
|
||||
height: 100%;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
background-color: mix($lbry-white, $lbry-gray-1, 70%);
|
||||
|
||||
[data-mode='dark'] & {
|
||||
|
|
|
@ -26,3 +26,13 @@ export function toQueryString(params) {
|
|||
|
||||
return parts.join('&');
|
||||
}
|
||||
|
||||
export function updateQueryParam(uri, key, value) {
|
||||
const re = new RegExp('([?&])' + key + '=.*?(&|$)', 'i');
|
||||
const separator = uri.indexOf('?') !== -1 ? '&' : '?';
|
||||
if (uri.match(re)) {
|
||||
return uri.replace(re, '$1' + key + '=' + value + '$2');
|
||||
} else {
|
||||
return uri + separator + key + '=' + value;
|
||||
}
|
||||
}
|
||||
|
|
5
src/ui/util/string.js
Normal file
5
src/ui/util/string.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
export function toCapitalCase(string: string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
|
@ -10,10 +10,10 @@ export default function useHover(ref) {
|
|||
|
||||
const refElement = ref.current;
|
||||
if (refElement) {
|
||||
refElement.addEventListener('mouseover', handleHover);
|
||||
refElement.addEventListener('mouseenter', handleHover);
|
||||
refElement.addEventListener('mouseleave', handleHover);
|
||||
return () => {
|
||||
refElement.removeEventListener('mouseover', handleHover);
|
||||
refElement.removeEventListener('mouseenter', handleHover);
|
||||
refElement.removeEventListener('mouseleave', handleHover);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<!--
|
||||
Primary definition for this is in webpack.web.config.js
|
||||
We can't access it here because webpack isn't running on this file
|
||||
|
|
|
@ -542,6 +542,7 @@
|
|||
"Upgrade is ready to install": "Upgrade is ready to install",
|
||||
"Upgrade is ready": "Upgrade is ready",
|
||||
"Abandon the claim for this URI": "Abandon the claim for this URI",
|
||||
<<<<<<< HEAD
|
||||
"For video content, use MP4s in H264/AAC format for best compatibility.": "For video content, use MP4s in H264/AAC format for best compatibility.",
|
||||
"Read the App Basics FAQ": "Read the App Basics FAQ",
|
||||
"View all LBRY FAQs": "View all LBRY FAQs",
|
||||
|
@ -577,3 +578,23 @@
|
|||
"These credits are permanently yours and can be removed at any time. Removing this support will reduce the claim's discoverability and return the LBC to your spendable balance.": "These credits are permanently yours and can be removed at any time. Removing this support will reduce the claim's discoverability and return the LBC to your spendable balance.",
|
||||
"The better your tags are, the easier it will be for people to discover your channel.": "The better your tags are, the easier it will be for people to discover your channel."
|
||||
}
|
||||
=======
|
||||
"View Tag": "View Tag",
|
||||
"Invalid claim ID %s.": "Invalid claim ID %s.",
|
||||
"Invalid character %s in name: %s.": "Invalid character %s in name: %s.",
|
||||
"LBRY names cannot contain spaces or reserved symbols ($#@;/\"<>%{}|^~[]`)": "LBRY names cannot contain spaces or reserved symbols ($#@;/\"<>%{}|^~[]`)",
|
||||
"No transactions.": "No transactions.",
|
||||
"Today": "Today",
|
||||
"This": "This",
|
||||
"All time": "All time",
|
||||
"Thumbnail (300 x 300)": "Thumbnail (300 x 300)",
|
||||
"Cover (1000 x 160)": "Cover (1000 x 160)",
|
||||
"No path provided after /": "No path provided after /",
|
||||
"Connection Failure": "Connection Failure",
|
||||
"Try closing all LBRY processes and starting again. If this still happens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.": "Try closing all LBRY processes and starting again. If this still happens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.com if you think this is a software bug.",
|
||||
"Unable to Authenticate": "Unable to Authenticate",
|
||||
"Authentication Failure": "Authentication Failure",
|
||||
"Reload": "Reload",
|
||||
"If reloading does not fix this, or you see this at every start up, please email help@lbry.com.": "If reloading does not fix this, or you see this at every start up, please email help@lbry.com."
|
||||
}
|
||||
>>>>>>> restore that shit
|
||||
|
|
25
yarn.lock
25
yarn.lock
|
@ -769,6 +769,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.1.5":
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b"
|
||||
integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.4.3":
|
||||
version "7.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d"
|
||||
|
@ -6646,9 +6653,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#eb3a7afc46ef69678149ad5caff3829473d75b43:
|
||||
lbry-redux@lbryio/lbry-redux#6406f184e8c87d79f4adb2b8792ff3643f4527ea:
|
||||
version "0.0.1"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/eb3a7afc46ef69678149ad5caff3829473d75b43"
|
||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/6406f184e8c87d79f4adb2b8792ff3643f4527ea"
|
||||
dependencies:
|
||||
proxy-polyfill "0.1.6"
|
||||
reselect "^3.0.0"
|
||||
|
@ -9578,6 +9585,15 @@ react-spring@^8.0.20:
|
|||
"@babel/runtime" "^7.3.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-sticky-box@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/react-sticky-box/-/react-sticky-box-0.8.0.tgz#1c191936af8f5420087b703ec6da4ef46060076c"
|
||||
integrity sha512-al7fY+VzTKBgVrn14l21jQfhuG582Z6FD8tVbWVQDDqzcjLmUrFb+ljG2phxHhRRazg64L3yH4nOKjn78PZmag==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.5"
|
||||
prop-types "^15.6.2"
|
||||
resize-observer-polyfill "^1.5.1"
|
||||
|
||||
react-toggle@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-4.0.2.tgz#77f487860efb87fafd197672a2db8c885be1440f"
|
||||
|
@ -10032,6 +10048,11 @@ reselect@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147"
|
||||
integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=
|
||||
|
||||
resize-observer-polyfill@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
|
||||
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
|
||||
|
||||
resolve-cwd@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
|
||||
|
|
Loading…
Reference in a new issue