diff --git a/.eslintrc.json b/.eslintrc.json index 7f85a5aea..86ec5da22 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -29,6 +29,7 @@ "indent": 0, "jsx-quotes": ["error", "prefer-double"], "new-cap": 0, + "no-console": 1, "no-multi-spaces": 0, "no-redeclare": 0, "no-return-await": 0, diff --git a/package.json b/package.json index 5f0088c03..30f5c3c85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "LBRY", - "version": "0.34.0-rc.5", + "version": "0.34.0-rc.9", "description": "A browser for the LBRY network, a digital marketplace controlled by its users.", "keywords": [ "lbry" @@ -124,7 +124,7 @@ "jsmediatags": "^3.8.1", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#b07dfa172a526aa5e09af57bb6cf33790c8d0c91", + "lbry-redux": "lbryio/lbry-redux#5080eb3ea1f09ce03c4f50d9224feddf737628d3", "lbryinc": "lbryio/lbryinc#a93596c51c8fb0a226cb84df04c26a6bb60a45fb", "lint-staged": "^7.0.2", "localforage": "^1.7.1", @@ -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", @@ -199,8 +200,8 @@ "yarn": "^1.3" }, "lbrySettings": { - "lbrynetDaemonVersion": "0.38.0", - "lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip", + "lbrynetDaemonVersion": "0.38.1", + "lbrynetDaemonUrlTemplate": "http://build.lbry.io/daemon/build-11443_commit-eae4ed7_branch-master/lbrynet-OSNAME.zip", "lbrynetDaemonDir": "static/daemon", "lbrynetDaemonFileName": "lbrynet" } diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx index fc28aa29c..938099c58 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/channelContent/index.js b/src/ui/component/channelContent/index.js index 89bf3f118..df8fa3d77 100644 --- a/src/ui/component/channelContent/index.js +++ b/src/ui/component/channelContent/index.js @@ -2,25 +2,33 @@ import { connect } from 'react-redux'; import { doFetchClaimsByChannel } from 'redux/actions/content'; import { PAGE_SIZE } from 'constants/claim'; import { - makeSelectClaimsInChannelForCurrentPageState, + makeSelectClaimsInChannelForPage, makeSelectFetchingChannelClaims, makeSelectClaimIsMine, makeSelectTotalPagesForChannel, } from 'lbry-redux'; +import { withRouter } from 'react-router'; import ChannelPage from './view'; -const select = (state, props) => ({ - claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state), - fetching: makeSelectFetchingChannelClaims(props.uri)(state), - totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state), - channelIsMine: makeSelectClaimIsMine(props.uri)(state), -}); +const select = (state, props) => { + const { search } = props.location; + const urlParams = new URLSearchParams(search); + const page = urlParams.get('page') || 0; + return { + claimsInChannel: makeSelectClaimsInChannelForPage(props.uri, page)(state), + fetching: makeSelectFetchingChannelClaims(props.uri)(state), + totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state), + channelIsMine: makeSelectClaimIsMine(props.uri)(state), + }; +}; const perform = dispatch => ({ fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)), }); -export default connect( - select, - perform -)(ChannelPage); +export default withRouter( + connect( + select, + perform + )(ChannelPage) +); 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 ed4dfed6a..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'; @@ -29,78 +31,122 @@ const SEARCH_TIMES = [TIME_DAY, TIME_WEEK, TIME_MONTH, TIME_YEAR, TIME_ALL]; type Props = { uris: Array, subscribedChannels: Array, - doClaimSearch: (number, {}) => void, + doClaimSearch: ({}) => void, 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}`; - } - } - - doClaimSearch(20, 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 = (

@@ -109,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/index.js b/src/ui/component/claimPreview/index.js index 96bcfdc89..7277c96e5 100644 --- a/src/ui/component/claimPreview/index.js +++ b/src/ui/component/claimPreview/index.js @@ -11,6 +11,7 @@ import { } from 'lbry-redux'; import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; import { selectShowNsfw } from 'redux/selectors/settings'; +import { makeSelectHasVisitedUri } from 'redux/selectors/content'; import ClaimPreview from './view'; const select = (state, props) => ({ @@ -24,6 +25,7 @@ const select = (state, props) => ({ nsfw: makeSelectClaimIsNsfw(props.uri)(state), blackListedOutpoints: selectBlackListedOutpoints(state), filteredOutpoints: selectFilteredOutpoints(state), + hasVisitedUri: makeSelectHasVisitedUri(props.uri)(state), }); const perform = dispatch => ({ diff --git a/src/ui/component/claimPreview/view.jsx b/src/ui/component/claimPreview/view.jsx index 8da045d10..f50dd39b9 100644 --- a/src/ui/component/claimPreview/view.jsx +++ b/src/ui/component/claimPreview/view.jsx @@ -29,6 +29,7 @@ type Props = { nsfw: boolean, placeholder: boolean, type: string, + hasVisitedUri: boolean, blackListedOutpoints: Array<{ txid: string, nout: number, @@ -56,16 +57,23 @@ function ClaimPreview(props: Props) { type, blackListedOutpoints, filteredOutpoints, + hasVisitedUri, } = props; const haventFetched = claim === undefined; const abandoned = !isResolvingUri && !claim && !placeholder; - const { isChannel } = parseURI(uri); const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0; + let isValid; + try { + parseURI(uri); + isValid = true; + } catch (e) { + isValid = false; + } + const isChannel = isValid ? parseURI(uri).isChannel : false; let shouldHide = abandoned || (!claimIsMine && obscureNsfw && nsfw); // This will be replaced once blocking is done at the wallet server level - if (claim && !shouldHide && blackListedOutpoints) { shouldHide = blackListedOutpoints.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout); } @@ -89,16 +97,16 @@ function ClaimPreview(props: Props) { } useEffect(() => { - if (!isResolvingUri && haventFetched && uri) { + 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 (
  • @@ -117,7 +125,8 @@ function ClaimPreview(props: Props) { onContextMenu={handleContextMenu} className={classnames('claim-preview', { 'claim-preview--large': type === 'large', - 'claim-list__pending': pending, + 'claim-preview--visited': !isChannel && hasVisitedUri, + 'claim-preview--pending': pending, })} > {isChannel ? : } 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/common/icon-custom.jsx b/src/ui/component/common/icon-custom.jsx index 4057af42e..a96191376 100644 --- a/src/ui/component/common/icon-custom.jsx +++ b/src/ui/component/common/icon-custom.jsx @@ -253,6 +253,12 @@ export const icons = { ), + [ICONS.TAG]: buildIcon( + + + + + ), [ICONS.SUPPORT]: buildIcon( 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..826ff8c46 100644 --- a/src/ui/component/splash/view.jsx +++ b/src/ui/component/splash/view.jsx @@ -221,11 +221,11 @@ export default class SplashScreen extends React.PureComponent { :container { perspective: 30vmin; } - + @place-cell: center; @size: 100%; - - box-shadow: @m2(0 0 50px var(--color)); + + box-shadow: @m2(0 0 50px var(--color)); will-change: transform, opacity; animation: scale-up 12s linear infinite; animation-delay: calc(-12s / @size() * @i()); @@ -235,11 +235,11 @@ export default class SplashScreen extends React.PureComponent { transform: translateZ(0) rotate(0); opacity: 0; } - 10% { - opacity: 1; + 10% { + opacity: 1; } 95% { - transform: + transform: translateZ(35vmin) rotateZ(@var(--deg)); } } diff --git a/src/ui/component/transactionList/internal/transaction-list-item.jsx b/src/ui/component/transactionList/internal/transaction-list-item.jsx index 8984b24d5..681580757 100644 --- a/src/ui/component/transactionList/internal/transaction-list-item.jsx +++ b/src/ui/component/transactionList/internal/transaction-list-item.jsx @@ -44,10 +44,12 @@ class TransactionListItem extends React.PureComponent { const { amount, claim_id: claimId, claim_name: name, date, fee, txid, type } = transaction; // Ensure the claim name exists and is valid + let uri; let claimName = name; - if (claimName) { + try { ({ claimName } = parseURI(name)); - } + uri = buildURI({ claimName: claimName, claimId }); + } catch (e) {} const dateFormat = { month: 'short', @@ -72,9 +74,7 @@ class TransactionListItem extends React.PureComponent { {reward && {reward.reward_title}} - {claimName && claimId && ( -

    diff --git a/src/ui/component/wunderbar/view.jsx b/src/ui/component/wunderbar/view.jsx index b4d40f692..94f8b45e2 100644 --- a/src/ui/component/wunderbar/view.jsx +++ b/src/ui/component/wunderbar/view.jsx @@ -3,10 +3,11 @@ import * as PAGES from 'constants/pages'; import * as ICONS from 'constants/icons'; import React from 'react'; import classnames from 'classnames'; -import { normalizeURI, SEARCH_TYPES, isURIValid, buildURI } from 'lbry-redux'; +import { normalizeURI, SEARCH_TYPES, isURIValid } from 'lbry-redux'; +import { withRouter } from 'react-router'; import Icon from 'component/common/icon'; -import { parseQueryParams } from 'util/query-params'; import Autocomplete from './internal/autocomplete'; +import Tag from 'component/tag'; const L_KEY_CODE = 76; const ESC_KEY_CODE = 27; @@ -22,6 +23,7 @@ type Props = { doBlur: () => void, focused: boolean, doShowSnackBar: string => void, + history: { push: string => void }, }; type State = { @@ -51,10 +53,12 @@ class WunderBar extends React.PureComponent { getSuggestionIcon = (type: string) => { switch (type) { - case 'file': + case SEARCH_TYPES.FILE: return ICONS.FILE; - case 'channel': + case SEARCH_TYPES.CHANNEL: return ICONS.CHANNEL; + case SEARCH_TYPES.TAG: + return ICONS.TAG; default: return ICONS.SEARCH; } @@ -90,7 +94,7 @@ class WunderBar extends React.PureComponent { } handleSubmit(value: string, suggestion?: { value: string, type: string }) { - const { onSubmit, onSearch, doShowSnackBar } = this.props; + const { onSubmit, onSearch, doShowSnackBar, history } = this.props; const query = value.trim(); const showSnackError = () => { @@ -99,8 +103,10 @@ class WunderBar extends React.PureComponent { // User selected a suggestion if (suggestion) { - if (suggestion.type === 'search') { + if (suggestion.type === SEARCH_TYPES.SEARCH) { onSearch(query); + } else if (suggestion.type === SEARCH_TYPES.TAG) { + history.push(`/$/${PAGES.TAGS}?t=${suggestion.value}`); } else if (isURIValid(query)) { const uri = normalizeURI(query); onSubmit(uri); @@ -157,18 +163,22 @@ class WunderBar extends React.PureComponent { )} renderItem={({ value, type }, isHighlighted) => (

    - {value} + + {type === SEARCH_TYPES.TAG ? : value} + {isHighlighted && ( {type === SEARCH_TYPES.SEARCH && __('Search')} {type === SEARCH_TYPES.CHANNEL && __('View channel')} {type === SEARCH_TYPES.FILE && __('View file')} + {type === SEARCH_TYPES.TAG && __('View Tag')} )}
    @@ -179,4 +189,4 @@ class WunderBar extends React.PureComponent { } } -export default WunderBar; +export default withRouter(WunderBar); diff --git a/src/ui/constants/icons.js b/src/ui/constants/icons.js index a5306cdce..502d19de9 100644 --- a/src/ui/constants/icons.js +++ b/src/ui/constants/icons.js @@ -69,4 +69,5 @@ export const MUSIC_EQUALIZER = 'Sliders'; export const LIGHT = 'Sun'; export const DARK = 'Moon'; export const LIBRARY = 'Folder'; +export const TAG = 'Tag'; export const SUPPORT = 'TrendingUp'; 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={