From 1015abbb87706f52fee82b9c2b71a9592be63a23 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Wed, 17 Jul 2019 16:49:06 -0400 Subject: [PATCH] restore that shit --- package.json | 1 + src/ui/component/app/view.jsx | 10 +- src/ui/component/channelEdit/view.jsx | 4 +- src/ui/component/claimList/view.jsx | 14 +- src/ui/component/claimListDiscover/index.js | 4 +- src/ui/component/claimListDiscover/view.jsx | 200 ++++++++++++-------- src/ui/component/claimPreview/view.jsx | 4 +- src/ui/component/commentCreate/view.jsx | 1 + src/ui/component/header/view.jsx | 6 +- src/ui/component/router/index.js | 10 +- src/ui/component/router/view.jsx | 86 +++++---- src/ui/component/sideBar/view.jsx | 35 ++-- src/ui/component/splash/view.jsx | 2 + src/ui/component/uriIndicator/view.jsx | 2 +- src/ui/page/channel/index.js | 2 + src/ui/page/channel/view.jsx | 7 +- src/ui/page/discover/view.jsx | 2 +- src/ui/redux/reducers/app.js | 23 +++ src/ui/scss/component/_claim-list.scss | 5 + src/ui/scss/component/_main.scss | 19 +- src/ui/scss/component/_navigation.scss | 9 +- src/ui/scss/component/_tags.scss | 1 - src/ui/scss/init/_gui.scss | 2 +- src/ui/util/query-params.js | 10 + src/ui/util/string.js | 5 + src/ui/util/use-hover.js | 4 +- static/index.dev.html | 1 + static/locales/en.json | 21 ++ yarn.lock | 25 ++- 29 files changed, 329 insertions(+), 186 deletions(-) create mode 100644 src/ui/util/string.js diff --git a/package.json b/package.json index cd020b1a0..025c4f37c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx index fc28aa29c..e387f8bc8 100644 --- a/src/ui/component/app/view.jsx +++ b/src/ui/component/app/view.jsx @@ -51,14 +51,12 @@ function App(props: Props) { }, [userId]); return ( -
openContextMenu(e)}> +
openContextMenu(e)}>
-
-
- - -
+
+ +
diff --git a/src/ui/component/channelEdit/view.jsx b/src/ui/component/channelEdit/view.jsx index 561c05a77..77c963402 100644 --- a/src/ui/component/channelEdit/view.jsx +++ b/src/ui/component/channelEdit/view.jsx @@ -118,14 +118,14 @@ function ChannelForm(props: Props) { onUpdate={v => handleThumbnailChange(v)} currentValue={params.thumbnail} assetName={'Thumbnail'} - recommended={'(400x400)'} + recommended={'(300 x 300)'} /> handleCoverChange(v)} currentValue={params.cover} assetName={'Cover'} - recommended={'(1000x300)'} + recommended={'(1000 x 160)'} /> 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 (
)} - {hasUris && ( + {urisLength > 0 && (
    {sortedUris.map((uri, index) => ( - + {index === 4 && injectedItem &&
  • {injectedItem}
  • }
    ))}
)} - {!hasUris && !loading &&

{empty || __('No results')}

} + {urisLength === 0 && !loading &&

{empty || __('No results')}

} ); } diff --git a/src/ui/component/claimListDiscover/index.js b/src/ui/component/claimListDiscover/index.js index c8c1b12ca..1007c230b 100644 --- a/src/ui/component/claimListDiscover/index.js +++ b/src/ui/component/claimListDiscover/index.js @@ -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), diff --git a/src/ui/component/claimListDiscover/view.jsx b/src/ui/component/claimListDiscover/view.jsx index 214a753a5..7308a38ad 100644 --- a/src/ui/component/claimListDiscover/view.jsx +++ b/src/ui/component/claimListDiscover/view.jsx @@ -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, 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, + }, }; 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, + channel_ids: Array, + not_tags: Array, + order_by: Array, + 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, - order_by?: Array, - channel_ids?: Array, - release_time?: string, - not_tags?: Array, - } = { 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 = (

@@ -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 => (

); } -export default ClaimListDiscover; +export default withRouter(ClaimListDiscover); diff --git a/src/ui/component/claimPreview/view.jsx b/src/ui/component/claimPreview/view.jsx index 8d178fa28..f50dd39b9 100644 --- a/src/ui/component/claimPreview/view.jsx +++ b/src/ui/component/claimPreview/view.jsx @@ -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 (
  • diff --git a/src/ui/component/commentCreate/view.jsx b/src/ui/component/commentCreate/view.jsx index c1738ecba..dd81e7d05 100644 --- a/src/ui/component/commentCreate/view.jsx +++ b/src/ui/component/commentCreate/view.jsx @@ -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(''); diff --git a/src/ui/component/header/view.jsx b/src/ui/component/header/view.jsx index cff8b627d..d4c560e6e 100644 --- a/src/ui/component/header/view.jsx +++ b/src/ui/component/header/view.jsx @@ -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) => {
  • - ); + function buildLink(path, label, icon, guide) { + return { + navigate: path ? `$/${path}` : '/', + label, + icon, + guide, + }; + } return ( -
    + -
    + ); } diff --git a/src/ui/component/splash/view.jsx b/src/ui/component/splash/view.jsx index 6ff0d45cf..b518a9a09 100644 --- a/src/ui/component/splash/view.jsx +++ b/src/ui/component/splash/view.jsx @@ -52,6 +52,8 @@ export default class SplashScreen extends React.PureComponent { } componentDidMount() { + this.props.onReadyToLaunch(); + const { checkDaemonVersion } = this.props; this.adjustErrorTimeout(); Lbry.connect() diff --git a/src/ui/component/uriIndicator/view.jsx b/src/ui/component/uriIndicator/view.jsx index 4a929ce6a..56d643e13 100644 --- a/src/ui/component/uriIndicator/view.jsx +++ b/src/ui/component/uriIndicator/view.jsx @@ -63,7 +63,7 @@ class UriIndicator extends React.PureComponent { return ( ); } else { diff --git a/src/ui/page/channel/index.js b/src/ui/page/channel/index.js index a4715823e..667546b11 100644 --- a/src/ui/page/channel/index.js +++ b/src/ui/page/channel/index.js @@ -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( diff --git a/src/ui/page/channel/view.jsx b/src/ui/page/channel/view.jsx index 522c98cdc..daf9c766e 100644 --- a/src/ui/page/channel/view.jsx +++ b/src/ui/page/channel/view.jsx @@ -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) { {editing ? __('Editing Your Channel') : __('About')}
    - +
    diff --git a/src/ui/page/discover/view.jsx b/src/ui/page/discover/view.jsx index c51756bf1..885dbb7e5 100644 --- a/src/ui/page/discover/view.jsx +++ b/src/ui/page/discover/view.jsx @@ -16,7 +16,7 @@ function DiscoverPage(props: Props) { return ( tag.name)} meta={