diff --git a/package.json b/package.json index 5f1bbcbf5..9c0a1f78c 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "@hot-loader/react-dom": "16.8", "@lbry/color": "^1.0.2", "@lbry/components": "^2.3.3", + "@reach/router": "^1.2.1", "@types/three": "^0.93.1", "async-exit-hook": "^2.0.1", "babel-eslint": "^10.0.1", @@ -106,8 +107,8 @@ "husky": "^0.14.3", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#2a7e05940f892f104428eeb37bd1f178da811a09", - "lbryinc": "lbryio/lbryinc#437260f3dad2321e892388b68749ee6af01aff2b", + "lbry-redux": "lbryio/lbry-redux#86f1340f834d0f5cd5365492a8ff15d4b213a050", + "lbryinc": "lbryio/lbryinc#d9f9035113c8b9ab3b0ee7ffbd38f910086a665e", "lint-staged": "^7.0.2", "localforage": "^1.7.1", "make-runnable": "^1.3.6", diff --git a/src/platforms/electron/createWindow.js b/src/platforms/electron/createWindow.js index 2c07b5266..3c7ad0563 100644 --- a/src/platforms/electron/createWindow.js +++ b/src/platforms/electron/createWindow.js @@ -35,9 +35,7 @@ export default appState => { }, }; - const rendererURL = isDev // ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}` - ? `http://localhost:8080/index.dev.html` - : `file://${__dirname}/index.html`; + const rendererURL = isDev ? `http://localhost:8080` : `file://${__dirname}/index.html`; let window = new BrowserWindow(windowConfiguration); diff --git a/src/platforms/web/server.js b/src/platforms/web/server.js index 0404ecba5..6a84b17fe 100644 --- a/src/platforms/web/server.js +++ b/src/platforms/web/server.js @@ -5,4 +5,8 @@ const port = 1337; app.use(express.static(__dirname)); -app.listen(port, () => console.log(`UI server listening at localhost://${port}`)); +app.get('*', function(req, res) { + res.sendFile(path.join(__dirname, '/index.html')); +}); + +app.listen(port, () => console.log(`UI server listening at http://localhost:${port}`)); diff --git a/src/ui/component/app/index.js b/src/ui/component/app/index.js index 9a1a19f24..767e4a32d 100644 --- a/src/ui/component/app/index.js +++ b/src/ui/component/app/index.js @@ -1,13 +1,6 @@ import { hot } from 'react-hot-loader/root'; import { connect } from 'react-redux'; -import { - selectPageTitle, - selectHistoryIndex, - selectActiveHistoryEntry, - doUpdateBlockHeight, - doError, -} from 'lbry-redux'; -import { doRecordScroll } from 'redux/actions/navigation'; +import { doUpdateBlockHeight, doError } from 'lbry-redux'; import { doToggleEnhancedLayout } from 'redux/actions/app'; import { selectUser } from 'lbryinc'; import { selectThemePath } from 'redux/selectors/settings'; @@ -15,17 +8,13 @@ import { selectEnhancedLayout } from 'redux/selectors/app'; import App from './view'; const select = state => ({ - pageTitle: selectPageTitle(state), user: selectUser(state), - currentStackIndex: selectHistoryIndex(state), - currentPageAttributes: selectActiveHistoryEntry(state), theme: selectThemePath(state), enhancedLayout: selectEnhancedLayout(state), }); const perform = dispatch => ({ alertError: errorList => dispatch(doError(errorList)), - recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)), updateBlockHeight: () => dispatch(doUpdateBlockHeight()), toggleEnhancedLayout: () => dispatch(doToggleEnhancedLayout()), }); diff --git a/src/ui/component/app/view.jsx b/src/ui/component/app/view.jsx index cee6db32c..8f2ea7f64 100644 --- a/src/ui/component/app/view.jsx +++ b/src/ui/component/app/view.jsx @@ -14,9 +14,6 @@ const TWO_POINT_FIVE_MINUTES = 1000 * 60 * 2.5; type Props = { alertError: (string | {}) => void, - recordScroll: number => void, - currentStackIndex: number, - currentPageAttributes: { path: string, scrollY: number }, pageTitle: ?string, theme: string, updateBlockHeight: () => void, @@ -25,12 +22,6 @@ type Props = { }; class App extends React.PureComponent { - constructor() { - super(); - this.mainContent = undefined; - (this: any).scrollListener = this.scrollListener.bind(this); - } - componentWillMount() { const { alertError, theme } = this.props; @@ -47,12 +38,6 @@ class App extends React.PureComponent { componentDidMount() { const { updateBlockHeight, toggleEnhancedLayout } = this.props; - const mainContent = document.getElementById('content'); - this.mainContent = mainContent; - if (this.mainContent) { - this.mainContent.addEventListener('scroll', throttle(this.scrollListener, 750)); - } - ReactModal.setAppElement('#window'); // fuck this this.enhance = new EnhancedLayoutListener(() => toggleEnhancedLayout()); @@ -63,18 +48,9 @@ class App extends React.PureComponent { }, TWO_POINT_FIVE_MINUTES); } - componentWillReceiveProps(props: Props) { - const { pageTitle } = props; - this.setTitleFromProps(pageTitle); - } - componentDidUpdate(prevProps: Props) { - const { currentStackIndex: prevStackIndex, theme: prevTheme } = prevProps; - const { currentStackIndex, currentPageAttributes, theme } = this.props; - - if (this.mainContent && currentStackIndex !== prevStackIndex && currentPageAttributes) { - this.mainContent.scrollTop = currentPageAttributes.scrollY || 0; - } + const { theme: prevTheme } = prevProps; + const { theme } = this.props; if (prevTheme !== theme) { // $FlowFixMe @@ -83,26 +59,9 @@ class App extends React.PureComponent { } componentWillUnmount() { - if (this.mainContent) { - this.mainContent.removeEventListener('scroll', this.scrollListener); - } - this.enhance = null; } - setTitleFromProps = (title: ?string) => { - window.document.title = title || 'LBRY'; - }; - - scrollListener() { - const { recordScroll } = this.props; - - if (this.mainContent) { - recordScroll(this.mainContent.scrollTop); - } - } - - mainContent: ?HTMLElement; enhance: ?any; render() { diff --git a/src/ui/component/button/index.js b/src/ui/component/button/index.js index c3bb8586d..05ac0e39a 100644 --- a/src/ui/component/button/index.js +++ b/src/ui/component/button/index.js @@ -1,12 +1,3 @@ -import { connect } from 'react-redux'; -import { doNavigate } from 'redux/actions/navigation'; import Button from './view'; -const perform = dispatch => ({ - doNavigate: (path, params) => dispatch(doNavigate(path, params)), -}); - -export default connect( - null, - perform -)(Button); +export default Button; diff --git a/src/ui/component/button/view.jsx b/src/ui/component/button/view.jsx index a87dbbf73..a71c85989 100644 --- a/src/ui/component/button/view.jsx +++ b/src/ui/component/button/view.jsx @@ -2,6 +2,8 @@ import * as React from 'react'; import Icon from 'component/common/icon'; import classnames from 'classnames'; +import { Link } from '@reach/router'; +import { formatLbryUriForWeb } from 'util/uri'; type Props = { onClick: ?(any) => any, @@ -13,9 +15,6 @@ type Props = { disabled: ?boolean, children: ?React.Node, navigate: ?string, - // TODO: these (nav) should be a reusable type - doNavigate: (string, ?any) => void, - navigateParams: any, className: ?string, description: ?string, type: string, @@ -24,7 +23,7 @@ type Props = { iconColor?: string, iconSize?: number, constrict: ?boolean, // to shorten the button and ellipsis, only use for links - selected: ?boolean, + activeClass?: string, }; class Button extends React.PureComponent { @@ -43,8 +42,6 @@ class Button extends React.PureComponent { disabled, children, navigate, - navigateParams, - doNavigate, className, description, button, @@ -53,7 +50,7 @@ class Button extends React.PureComponent { iconColor, iconSize, constrict, - selected, + activeClass, ...otherProps } = this.props; @@ -64,28 +61,19 @@ class Button extends React.PureComponent { }, button ? { - 'button--primary': button === 'primary', - 'button--secondary': button === 'secondary', - 'button--alt': button === 'alt', - 'button--danger': button === 'danger', - 'button--inverse': button === 'inverse', - 'button--disabled': disabled, - 'button--link': button === 'link', - 'button--constrict': constrict, - 'button--selected': selected, - } + 'button--primary': button === 'primary', + 'button--secondary': button === 'secondary', + 'button--alt': button === 'alt', + 'button--danger': button === 'danger', + 'button--inverse': button === 'inverse', + 'button--disabled': disabled, + 'button--link': button === 'link', + 'button--constrict': constrict, + } : 'button--no-style', className ); - const extendedOnClick = - !onClick && navigate - ? event => { - event.stopPropagation(); - doNavigate(navigate, navigateParams || {}); - } - : onClick; - const content = ( {icon && } @@ -95,16 +83,43 @@ class Button extends React.PureComponent { ); - return href ? ( - + if (href) { + return ( + + {content} + + ); + } + + // Handle lbry:// uris passed in, or already formatted web urls + let path = navigate; + if (path) { + if (path.startsWith('lbry://')) { + path = formatLbryUriForWeb(path); + } else if (!path.startsWith('/')) { + // Force a leading slash so new paths aren't appended on to the current path + path = `/${path}`; + } + } + + return path ? ( + e.stopPropagation()} + getProps={({ isCurrent }) => ({ + className: + isCurrent && activeClass ? `${combinedClassName} ${activeClass}` : combinedClassName, + })} + > {content} - + ) : ( )} diff --git a/src/ui/component/transactionList/view.jsx b/src/ui/component/transactionList/view.jsx index fc7c69bc9..37a9d65e0 100644 --- a/src/ui/component/transactionList/view.jsx +++ b/src/ui/component/transactionList/view.jsx @@ -105,12 +105,10 @@ class TransactionList extends React.PureComponent { )} - {!transactionList.length && ( -

{emptyMessage || __('No transactions to list.')}

- )} + {!transactionList.length &&

{emptyMessage || __('No transactions to list.')}

} {!!transactionList.length && ( -
+ @@ -133,7 +131,7 @@ class TransactionList extends React.PureComponent { ))}
-
+ )} ); diff --git a/src/ui/component/transactionListRecent/view.jsx b/src/ui/component/transactionListRecent/view.jsx index f98e75c3f..f00287b63 100644 --- a/src/ui/component/transactionListRecent/view.jsx +++ b/src/ui/component/transactionListRecent/view.jsx @@ -35,7 +35,7 @@ class TransactionListRecent extends React.PureComponent {

{__('To view all of your transactions, navigate to the')}{' '} - ); diff --git a/src/ui/component/userEmailVerify/index.js b/src/ui/component/userEmailVerify/index.js index b7e009438..4c42172f7 100644 --- a/src/ui/component/userEmailVerify/index.js +++ b/src/ui/component/userEmailVerify/index.js @@ -5,7 +5,6 @@ import { doUserCheckEmailVerified, selectUser, } from 'lbryinc'; -import { doNavigate } from 'redux/actions/navigation'; import UserEmailVerify from './view'; const select = state => ({ @@ -16,7 +15,6 @@ const select = state => ({ const perform = dispatch => ({ resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)), checkEmailVerified: () => dispatch(doUserCheckEmailVerified()), - navigate: path => dispatch(doNavigate(path)), }); export default connect( diff --git a/src/ui/component/userHistory/index.js b/src/ui/component/userHistory/index.js index 01618f6be..f839f01ee 100644 --- a/src/ui/component/userHistory/index.js +++ b/src/ui/component/userHistory/index.js @@ -1,22 +1,22 @@ import { connect } from 'react-redux'; import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content'; -import { doNavigate } from 'redux/actions/navigation'; import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux'; import { doClearContentHistoryUri } from 'redux/actions/content'; import UserHistory from './view'; -const select = state => { - const paramPage = Number(makeSelectCurrentParam('page')(state) || 0); +const select = (state, props) => { + const { search } = props.location; + const urlParams = new URLSearchParams(search); + const page = Number(urlParams.get('page')) || 0; + return { + page, pageCount: selectHistoryPageCount(state), - page: paramPage, - params: selectCurrentParams(state), - history: makeSelectHistoryForPage(paramPage)(state), + history: makeSelectHistoryForPage(page)(state), }; }; const perform = dispatch => ({ - navigate: (path, params) => dispatch(doNavigate(path, params)), clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)), }); diff --git a/src/ui/component/userHistory/view.jsx b/src/ui/component/userHistory/view.jsx index 1ea4a80b3..edf5d0e26 100644 --- a/src/ui/component/userHistory/view.jsx +++ b/src/ui/component/userHistory/view.jsx @@ -4,6 +4,7 @@ import Button from 'component/button'; import { Form, FormField } from 'component/common/form'; import ReactPaginate from 'react-paginate'; import UserHistoryItem from 'component/userHistoryItem'; +import { navigate } from '@reach/router'; type HistoryItem = { uri: string, @@ -14,7 +15,6 @@ type Props = { history: Array, page: number, pageCount: number, - navigate: (string, {}) => void, clearHistoryUri: string => void, params: { page: number }, }; @@ -52,9 +52,8 @@ class UserHistoryPage extends React.PureComponent { } changePage(pageNumber: number) { - const { params } = this.props; - const newParams = { ...params, page: pageNumber }; - this.props.navigate('/user_history', newParams); + console.log('new', pageNumber); + navigate(`/$/user_history?page=${pageNumber}`); } paginate(e: SyntheticKeyboardEvent<*>) { @@ -94,7 +93,8 @@ class UserHistoryPage extends React.PureComponent { } render() { - const { history, page, pageCount } = this.props; + const { history = [], page, pageCount } = this.props; + console.log('this.props', this.props); const { itemsSelected } = this.state; const allSelected = Object.keys(itemsSelected).length === history.length; const selectHandler = allSelected ? this.unselectAll : this.selectAll; @@ -148,6 +148,7 @@ class UserHistoryPage extends React.PureComponent { onPageChange={e => this.changePage(e.selected)} forcePage={page} initialPage={page} + disableInitialCallback containerClassName="pagination" /> @@ -175,7 +176,7 @@ class UserHistoryPage extends React.PureComponent {

-
diff --git a/src/ui/component/userHistoryItem/view.jsx b/src/ui/component/userHistoryItem/view.jsx index c782712ee..cd80c4530 100644 --- a/src/ui/component/userHistoryItem/view.jsx +++ b/src/ui/component/userHistoryItem/view.jsx @@ -51,8 +51,7 @@ class UserHistoryItem extends React.PureComponent { constrict button="link" label={name ? `lbry://${name}` : `lbry://...`} - navigate="/show" - navigateParams={{ uri }} + navigate={uri} /> ); diff --git a/src/ui/component/userVerify/index.js b/src/ui/component/userVerify/index.js index 291cf0890..11fa30c32 100644 --- a/src/ui/component/userVerify/index.js +++ b/src/ui/component/userVerify/index.js @@ -1,7 +1,6 @@ import * as MODALS from 'constants/modal_types'; import { connect } from 'react-redux'; import { doOpenModal } from 'redux/actions/app'; -import { doNavigate } from 'redux/actions/navigation'; import { doUserIdentityVerify, rewards, @@ -22,7 +21,6 @@ const select = state => { }; const perform = dispatch => ({ - navigate: uri => dispatch(doNavigate(uri)), verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)), verifyPhone: () => dispatch(doOpenModal(MODALS.PHONE_COLLECTION)), }); diff --git a/src/ui/component/userVerify/view.jsx b/src/ui/component/userVerify/view.jsx index a88751f9c..8c8f0b9ee 100644 --- a/src/ui/component/userVerify/view.jsx +++ b/src/ui/component/userVerify/view.jsx @@ -8,7 +8,6 @@ import { Lbryio } from 'lbryinc'; type Props = { errorMessage: ?string, isPending: boolean, - navigate: string => void, verifyUserIdentity: string => void, verifyPhone: () => void, }; @@ -25,7 +24,7 @@ class UserVerify extends React.PureComponent { } render() { - const { errorMessage, isPending, navigate, verifyPhone } = this.props; + const { errorMessage, isPending, verifyPhone } = this.props; return (
@@ -137,11 +136,7 @@ class UserVerify extends React.PureComponent {
-
diff --git a/src/ui/component/viewers/pdfViewer.jsx b/src/ui/component/viewers/pdfViewer.jsx index 15ce39913..bc4e001b3 100644 --- a/src/ui/component/viewers/pdfViewer.jsx +++ b/src/ui/component/viewers/pdfViewer.jsx @@ -2,7 +2,9 @@ import * as React from 'react'; import { stopContextMenu } from 'util/context-menu'; import Button from 'component/button'; +// @if TARGET='app' import { shell } from 'electron'; +// @endif type Props = { source: string, @@ -22,7 +24,12 @@ class PdfViewer extends React.PureComponent { openFile() { const { source } = this.props; const path = `file://${source}`; + // @if TARGET='app' shell.openExternal(path); + // @endif + // @if TARGET='web' + console.error('provide stub for shell.openExternal'); + // @endif } render() { diff --git a/src/ui/component/walletBalance/view.jsx b/src/ui/component/walletBalance/view.jsx index fabc90fdb..43551213b 100644 --- a/src/ui/component/walletBalance/view.jsx +++ b/src/ui/component/walletBalance/view.jsx @@ -12,7 +12,7 @@ const WalletBalance = (props: Props) => { return (

{__('Balance')}

diff --git a/src/ui/component/wunderbar/index.js b/src/ui/component/wunderbar/index.js index beb65642d..dc565cfbc 100644 --- a/src/ui/component/wunderbar/index.js +++ b/src/ui/component/wunderbar/index.js @@ -1,44 +1,38 @@ import { connect } from 'react-redux'; import { - selectSearchState as selectSearch, - selectWunderBarAddress, - selectSearchSuggestions, - doUpdateSearchQuery, doFocusSearchInput, doBlurSearchInput, + doUpdateSearchQuery, doSearch, - doToast, + selectSearchValue, + selectSearchSuggestions, + selectSearchBarFocused, + parseURI, } from 'lbry-redux'; import analytics from 'analytics'; -import { doNavigate } from 'redux/actions/navigation'; import Wunderbar from './view'; +import { navigate } from '@reach/router'; +import { formatLbryUriForWeb } from 'util/uri'; -const select = state => { - const { isActive, searchQuery, ...searchState } = selectSearch(state); - const address = selectWunderBarAddress(state); - - // if we are on the file/channel page - // use the address in the history stack - const wunderbarValue = isActive ? searchQuery : searchQuery || address; - - return { - ...searchState, - wunderbarValue, - suggestions: selectSearchSuggestions(state), - }; -}; +const select = state => ({ + suggestions: selectSearchSuggestions(state), + searchQuery: selectSearchValue(state), + isFocused: selectSearchBarFocused(state), +}); const perform = dispatch => ({ onSearch: query => { - dispatch(doSearch(query)); - dispatch(doNavigate(`/search`, { query })); + navigate(`/$/search?q=${query}`); analytics.apiLogSearch(); }, - onSubmit: (uri, extraParams) => dispatch(doNavigate('/show', { uri, ...extraParams })), + onSubmit: uri => { + const path = formatLbryUriForWeb(uri); + navigate(path); + dispatch(doUpdateSearchQuery('')); + }, updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)), doFocus: () => dispatch(doFocusSearchInput()), doBlur: () => dispatch(doBlurSearchInput()), - doShowSnackBar: props => dispatch(doToast(props)), }); export default connect( diff --git a/src/ui/component/wunderbar/view.jsx b/src/ui/component/wunderbar/view.jsx index a9babfdf4..96ca138f2 100644 --- a/src/ui/component/wunderbar/view.jsx +++ b/src/ui/component/wunderbar/view.jsx @@ -1,19 +1,22 @@ // @flow +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 } from 'lbry-redux'; +import { normalizeURI, SEARCH_TYPES, isURIValid, buildURI } from 'lbry-redux'; import Icon from 'component/common/icon'; import { parseQueryParams } from 'util/query-params'; import Autocomplete from './internal/autocomplete'; +import { Location, navigate } from '@reach/router'; const L_KEY_CODE = 76; const ESC_KEY_CODE = 27; type Props = { + searchQuery: ?string, updateSearchQuery: string => void, onSearch: string => void, - onSubmit: (string, {}) => void, + onSubmit: string => void, wunderbarValue: ?string, suggestions: Array, doFocus: () => void, @@ -22,10 +25,18 @@ type Props = { doShowSnackBar: ({}) => void, }; -class WunderBar extends React.PureComponent { +type State = { + query: ?string, +}; + +class WunderBar extends React.PureComponent { constructor() { super(); + this.state = { + query: null, + }; + (this: any).handleSubmit = this.handleSubmit.bind(this); (this: any).handleChange = this.handleChange.bind(this); (this: any).handleKeyDown = this.handleKeyDown.bind(this); @@ -61,6 +72,7 @@ class WunderBar extends React.PureComponent { return; } + // @if TARGET='app' const shouldFocus = process.platform === 'darwin' ? keyCode === L_KEY_CODE && metaKey @@ -70,30 +82,20 @@ class WunderBar extends React.PureComponent { this.input.focus(); doFocus(); } + // @endif } } handleChange(e: SyntheticInputEvent<*>) { - const { updateSearchQuery } = this.props; const { value } = e.target; - + const { updateSearchQuery } = this.props; updateSearchQuery(value); } handleSubmit(value: string, suggestion?: { value: string, type: string }) { const { onSubmit, onSearch, doShowSnackBar } = this.props; + const query = value.trim(); - const getParams = () => { - const parts = query.split('?'); - - let extraParams = {}; - if (parts.length > 0) { - extraParams = parseQueryParams(parts.join('')); - } - - return extraParams; - }; - const showSnackError = () => { doShowSnackBar({ message: __('Invalid LBRY URL entered. Only A-Z, a-z, 0-9, and "-" allowed.'), @@ -105,23 +107,20 @@ class WunderBar extends React.PureComponent { if (suggestion.type === 'search') { onSearch(query); } else if (isURIValid(query)) { - const params = getParams(); const uri = normalizeURI(query); - onSubmit(uri, params); + onSubmit(uri); } else { showSnackError(); } return; } - // Currently no suggestion is highlighted. The user may have started // typing, then lost focus and came back later on the same page try { if (isURIValid(query)) { const uri = normalizeURI(query); - const params = getParams(); - onSubmit(uri, params); + onSubmit(uri); } else { showSnackError(); } @@ -133,7 +132,7 @@ class WunderBar extends React.PureComponent { input: ?HTMLInputElement; render() { - const { wunderbarValue, suggestions, doFocus, doBlur } = this.props; + const { suggestions, doFocus, doBlur, searchQuery } = this.props; return (
@@ -141,7 +140,7 @@ class WunderBar extends React.PureComponent { item.value} onChange={this.handleChange} diff --git a/src/ui/component/yrbl/index.jsx b/src/ui/component/yrbl/index.jsx index 7b486783f..4cdd71d6b 100644 --- a/src/ui/component/yrbl/index.jsx +++ b/src/ui/component/yrbl/index.jsx @@ -28,7 +28,14 @@ export default class extends React.PureComponent { return (
- Friendly gerbil + Friendly gerbil {title && subtitle && (

{title}

diff --git a/src/ui/constants/icons.js b/src/ui/constants/icons.js index 96dc2917e..d31b25c46 100644 --- a/src/ui/constants/icons.js +++ b/src/ui/constants/icons.js @@ -48,3 +48,6 @@ export const UP = 'ChevronUp'; export const DOWN = 'ChevronDown'; export const SECURE = 'Lock'; export const MENU = 'Menu'; +export const BACKUP = 'Database'; +export const TRANSACTIONS = 'FileText'; +export const LBRY = 'Lbry'; diff --git a/src/ui/index.jsx b/src/ui/index.jsx index 4a3d9fde6..72e0d8931 100644 --- a/src/ui/index.jsx +++ b/src/ui/index.jsx @@ -1,8 +1,8 @@ import ErrorBoundary from 'component/errorBoundary'; import App from 'component/app'; import SnackBar from 'component/snackBar'; -import SplashScreen from 'component/splash'; // @if TARGET='app' +import SplashScreen from 'component/splash'; import moment from 'moment'; import { ipcRenderer, remote, shell } from 'electron'; import * as ACTIONS from 'constants/action_types'; @@ -19,7 +19,6 @@ import { doHideModal, } from 'redux/actions/app'; import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux'; -import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation'; import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings'; import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc'; import 'scss/all.scss'; @@ -46,11 +45,11 @@ if (process.env.SEARCH_API_URL) { // @if TARGET='app' ipcRenderer.on('navigate-backward', () => { - app.store.dispatch(doHistoryBack()); + // app.store.dispatch(doHistoryBack()); }); ipcRenderer.on('navigate-forward', () => { - app.store.dispatch(doHistoryForward()); + // app.store.dispatch(doHistoryForward()); }); // @endif @@ -132,9 +131,9 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => { app.store.dispatch(doConditionalAuthNavigate(newSession)); } else if (uri.startsWith(APPPAGEURL)) { const navpage = uri.replace(APPPAGEURL, '').toLowerCase(); - app.store.dispatch(doNavigate(`/${navpage}`)); + // app.store.dispatch(doNavigate(`/${navpage}`)); } else if (isURIValid(uri)) { - app.store.dispatch(doNavigate('/show', { uri })); + // app.store.dispatch(doNavigate('/show', { uri })); } else { app.store.dispatch( doToast({ @@ -147,7 +146,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => { ipcRenderer.on('open-menu', (event, uri) => { if (uri && uri.startsWith('/help')) { - app.store.dispatch(doNavigate('/help')); + // app.store.dispatch(doNavigate('/help')); } }); @@ -233,9 +232,11 @@ const init = () => { app.store.dispatch(doBlackListedOutpointsSubscribe()); function onDaemonReady() { + // @if TARGET='app' window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again - app.store.dispatch(doDaemonReady()); + // @endif + app.store.dispatch(doDaemonReady()); ReactDOM.render( @@ -245,11 +246,9 @@ const init = () => { , document.getElementById('app') ); - // @if TARGET='web' - window.sessionStorage.removeItem('loaded'); - // @endif } + // @if TARGET='app' if (window.sessionStorage.getItem('loaded') === 'y') { onDaemonReady(); } else { @@ -263,6 +262,10 @@ const init = () => { document.getElementById('app') ); } + // @endif + // @if TARGET='web' + onDaemonReady(); + // @endif }; init(); diff --git a/src/ui/modal/modalCreditIntro/index.js b/src/ui/modal/modalCreditIntro/index.js index 8dfb7936b..69f8b718a 100644 --- a/src/ui/modal/modalCreditIntro/index.js +++ b/src/ui/modal/modalCreditIntro/index.js @@ -1,11 +1,11 @@ import { connect } from 'react-redux'; -import { doNavigate } from 'redux/actions/navigation'; import { doSetClientSetting } from 'redux/actions/settings'; import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc'; import { selectBalance } from 'lbry-redux'; import { doHideModal } from 'redux/actions/app'; import * as settings from 'constants/settings'; import ModalCreditIntro from './view'; +import { navigate } from '@reach/router'; const select = state => ({ currentBalance: selectBalance(state), @@ -15,8 +15,8 @@ const select = state => ({ const perform = dispatch => () => ({ addBalance: () => { + navigate('/$/getcredits'); dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true)); - dispatch(doNavigate('/getcredits')); dispatch(doHideModal()); }, closeModal: () => { diff --git a/src/ui/modal/modalOpenExternalLink/view.jsx b/src/ui/modal/modalOpenExternalLink/view.jsx index a097efa7d..37ef808f9 100644 --- a/src/ui/modal/modalOpenExternalLink/view.jsx +++ b/src/ui/modal/modalOpenExternalLink/view.jsx @@ -1,6 +1,7 @@ // @flow import React from 'react'; import { Modal } from 'modal/modal'; +import { formatLbryUriForWeb } from 'util/uri'; // @if TARGET='app' import { shell } from 'electron'; // @endif @@ -13,10 +14,16 @@ type Props = { class ModalOpenExternalLink extends React.PureComponent { openExternalLink() { const { uri, closeModal } = this.props; + // @if TARGET='app' const { openExternal } = shell; if (uri) { openExternal(uri); } + // @endif + // @if TARGET='web' + window.open(uri); + // @endif + closeModal(); } diff --git a/src/ui/modal/modalPhoneCollection/index.js b/src/ui/modal/modalPhoneCollection/index.js index abd0855bc..9c2386f3f 100644 --- a/src/ui/modal/modalPhoneCollection/index.js +++ b/src/ui/modal/modalPhoneCollection/index.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { doHideModal } from 'redux/actions/app'; import { selectPhoneToVerify, selectUser } from 'lbryinc'; -import { doNavigate } from 'redux/actions/navigation'; +import { navigate } from '@reach/router'; import ModalPhoneCollection from './view'; const select = state => ({ @@ -12,7 +12,7 @@ const select = state => ({ const perform = dispatch => () => ({ closeModal: () => { dispatch(doHideModal()); - dispatch(doNavigate('/rewards')); + navigate('/$/rewards'); }, }); diff --git a/src/ui/modal/modalPublish/index.js b/src/ui/modal/modalPublish/index.js index e8d1b6bda..9da101c41 100644 --- a/src/ui/modal/modalPublish/index.js +++ b/src/ui/modal/modalPublish/index.js @@ -2,12 +2,10 @@ import { connect } from 'react-redux'; import { doHideModal } from 'redux/actions/app'; import ModalSendTip from './view'; import { doClearPublish } from 'redux/actions/publish'; -import { doNavigate } from 'redux/actions/navigation'; const perform = dispatch => ({ closeModal: () => dispatch(doHideModal()), clearPublish: () => dispatch(doClearPublish()), - navigate: (path, params) => dispatch(doNavigate(path, params)), }); export default connect( diff --git a/src/ui/modal/modalRouter/index.js b/src/ui/modal/modalRouter/index.js index 4865bf898..2ff9387a5 100644 --- a/src/ui/modal/modalRouter/index.js +++ b/src/ui/modal/modalRouter/index.js @@ -1,20 +1,15 @@ import { connect } from 'react-redux'; import * as settings from 'constants/settings'; -import { selectBalance, selectCurrentPage, selectError, doToast } from 'lbry-redux'; +import { selectBalance, makeSelectCostInfoForUri, selectError, doToast } from 'lbry-redux'; import { makeSelectClientSetting } from 'redux/selectors/settings'; -import { - selectUser, - selectUserIsVerificationCandidate, - selectCostForCurrentPageUri, -} from 'lbryinc'; +import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc'; import { selectModal } from 'redux/selectors/app'; import { doOpenModal } from 'redux/actions/app'; import ModalRouter from './view'; -const select = state => ({ +const select = (state, props) => ({ balance: selectBalance(state), - showPageCost: selectCostForCurrentPageUri(state), - page: selectCurrentPage(state), + showPageCost: makeSelectCostInfoForUri(props.uri)(state), isVerificationCandidate: selectUserIsVerificationCandidate(state), isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state), isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)( diff --git a/src/ui/modal/modalRouter/view.jsx b/src/ui/modal/modalRouter/view.jsx index 2292c655f..69d68d0fb 100644 --- a/src/ui/modal/modalRouter/view.jsx +++ b/src/ui/modal/modalRouter/view.jsx @@ -113,6 +113,7 @@ class ModalRouter extends React.PureComponent { isPaidShowPage(props: Props) { const { page, showPageCost } = props; + // Fix me return page === 'show' && showPageCost > 0; } diff --git a/src/ui/page/auth/index.js b/src/ui/page/auth/index.js index 4fbef0886..5d3a3fc47 100644 --- a/src/ui/page/auth/index.js +++ b/src/ui/page/auth/index.js @@ -1,6 +1,4 @@ -import { selectPathAfterAuth } from 'lbry-redux'; import { connect } from 'react-redux'; -import { doNavigate } from 'redux/actions/navigation'; import { selectAuthenticationIsPending, selectEmailToVerify, @@ -17,16 +15,11 @@ const select = state => ({ selectUserIsPending(state) || selectIdentityVerifyIsPending(state), email: selectEmailToVerify(state), - pathAfterAuth: selectPathAfterAuth(state), user: selectUser(state), isVerificationCandidate: selectUserIsVerificationCandidate(state), }); -const perform = dispatch => ({ - navigate: path => dispatch(doNavigate(path)), -}); - export default connect( select, - perform + null )(AuthPage); diff --git a/src/ui/page/auth/view.jsx b/src/ui/page/auth/view.jsx index cbbfa7b6b..b85b93447 100644 --- a/src/ui/page/auth/view.jsx +++ b/src/ui/page/auth/view.jsx @@ -1,4 +1,5 @@ // @flow +import type { UrlLocation } from 'types/location'; import React from 'react'; import BusyIndicator from 'component/common/busy-indicator'; import Button from 'component/button'; @@ -6,17 +7,18 @@ import UserEmailNew from 'component/userEmailNew'; import UserEmailVerify from 'component/userEmailVerify'; import UserVerify from 'component/userVerify'; import Page from 'component/page'; +import { navigate } from '@reach/router'; type Props = { isPending: boolean, email: string, pathAfterAuth: string, + location: UrlLocation, user: ?{ has_verified_email: boolean, is_reward_approved: boolean, is_identity_verified: boolean, }, - navigate: (string, ?{}) => void, }; class AuthPage extends React.PureComponent { @@ -29,14 +31,18 @@ class AuthPage extends React.PureComponent { } navigateIfAuthenticated = (props: Props) => { - const { isPending, user, pathAfterAuth, navigate } = props; + const { isPending, user, location } = props; if ( !isPending && user && user.has_verified_email && (user.is_reward_approved || user.is_identity_verified) ) { - navigate(pathAfterAuth); + const { search } = location; + const urlParams = new URLSearchParams(search); + const redirectTo = urlParams.get('redirect'); + const path = redirectTo ? `/$/${redirectTo}` : '/'; + navigate(path); } }; @@ -56,7 +62,6 @@ class AuthPage extends React.PureComponent { } render() { - const { navigate } = this.props; const [innerContent, useTemplate] = this.renderMain(); return ( @@ -69,11 +74,7 @@ class AuthPage extends React.PureComponent { {`${__( 'This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards and may be used to sync usage data across devices.' )} `} -
) : ( diff --git a/src/ui/page/channel/index.js b/src/ui/page/channel/index.js index 7b4327180..8c798ab0b 100644 --- a/src/ui/page/channel/index.js +++ b/src/ui/page/channel/index.js @@ -3,30 +3,24 @@ import { doFetchClaimsByChannel } from 'redux/actions/content'; import { PAGE_SIZE } from 'constants/claim'; import { makeSelectClaimForUri, - makeSelectClaimsInChannelForCurrentPage, + makeSelectClaimsInChannelForCurrentPageState, makeSelectFetchingChannelClaims, - makeSelectCurrentParam, makeSelectClaimIsMine, makeSelectTotalPagesForChannel, - selectCurrentParams, } from 'lbry-redux'; -import { doNavigate } from 'redux/actions/navigation'; import { doOpenModal } from 'redux/actions/app'; import ChannelPage from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), - claimsInChannel: makeSelectClaimsInChannelForCurrentPage(props.uri)(state), + claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state), fetching: makeSelectFetchingChannelClaims(props.uri)(state), - page: makeSelectCurrentParam('page')(state), - params: selectCurrentParams(state), totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state), channelIsMine: makeSelectClaimIsMine(props.uri)(state), }); const perform = dispatch => ({ fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)), - navigate: (path, params) => dispatch(doNavigate(path, params)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)), }); diff --git a/src/ui/page/channel/view.jsx b/src/ui/page/channel/view.jsx index ab57589ef..456d49aab 100644 --- a/src/ui/page/channel/view.jsx +++ b/src/ui/page/channel/view.jsx @@ -1,8 +1,9 @@ // @flow import type { Claim } from 'types/claim'; +import type { UrlLocation } from 'types/location'; import * as icons from 'constants/icons'; import * as MODALS from 'constants/modal_types'; -import React from 'react'; +import React, { useEffect } from 'react'; import BusyIndicator from 'component/common/busy-indicator'; import { FormField, Form } from 'component/common/form'; import ReactPaginate from 'react-paginate'; @@ -11,10 +12,10 @@ import Page from 'component/page'; import FileList from 'component/fileList'; import HiddenNsfwClaims from 'component/hiddenNsfwClaims'; import Button from 'component/button'; +import { navigate } from '@reach/router'; type Props = { uri: string, - page: number, totalPages: number, fetching: boolean, params: { page: number }, @@ -24,32 +25,42 @@ type Props = { fetchClaims: (string, number) => void, navigate: (string, {}) => void, openModal: (id: string, { uri: string }) => void, + location: UrlLocation, }; -class ChannelPage extends React.PureComponent { - componentDidMount() { - const { uri, page, fetchClaims } = this.props; - fetchClaims(uri, page || 1); - } +function ChannelPage(props: Props) { + const { + uri, + fetching, + claimsInChannel, + claim, + totalPages, + channelIsMine, + openModal, + fetchClaims, + location, + } = props; - componentDidUpdate(prevProps: Props) { - const { page, fetchClaims, uri } = this.props; + const { name, permanent_url: permanentUrl } = claim; + const { search } = location; + const urlParams = new URLSearchParams(search); + const page = Number(urlParams.get('page')) || 1; - if (prevProps.page && prevProps.page && page !== prevProps.page) { - fetchClaims(uri, page); + useEffect(() => { + // Fetch new claims if the channel or page number changes + fetchClaims(uri, page); + }, [uri, page]); + + const changePage = (pageNumber: number) => { + if (!page && pageNumber === 1) { + return; } - } - changePage(pageNumber: number) { - const { params } = this.props; - const newParams = Object.assign({}, params, { page: pageNumber }); + navigate(`?page=${pageNumber}`); + }; - this.props.navigate('/show', newParams); - } - - paginate(e: SyntheticKeyboardEvent<*>, totalPages: number) { - // Change page if enter was pressed, and the given page is between - // the first and the last. + const paginate = (e: SyntheticKeyboardEvent<*>) => { + // Change page if enter was pressed, and the given page is between the first and the last page const pageFromInput = Number(e.currentTarget.value); if ( @@ -59,90 +70,77 @@ class ChannelPage extends React.PureComponent { pageFromInput > 0 && pageFromInput <= totalPages ) { - this.changePage(pageFromInput); + changePage(pageFromInput); } - } + }; - render() { - const { - uri, - fetching, - claimsInChannel, - claim, - page, - totalPages, - channelIsMine, - openModal, - } = this.props; - const { name, permanent_url: permanentUrl } = claim; - const currentPage = parseInt((page || 1) - 1, 10); - const contentList = - claimsInChannel && claimsInChannel.length ? ( - - ) : ( - !fetching && {__('No content found.')} - ); + return ( + +
+

+ {name} + {fetching && } +

+ {`lbry://${permanentUrl}`} - return ( - -
-

- {name} - {fetching && } -

+
+ +
+
-
- -
-
- -
{contentList}
- - {(!fetching || (claimsInChannel && claimsInChannel.length)) && totalPages > 1 && ( -
- - - this.changePage(e.selected + 1)} - forcePage={currentPage} - initialPage={currentPage} - containerClassName="pagination" - /> - - - this.paginate(e, totalPages)} - label={__('Go to page:')} - type="text" - name="paginate-file" - /> - -
+
+ {claimsInChannel && claimsInChannel.length ? ( + + ) : ( + !fetching && {__('No content found.')} )} +
- {!channelIsMine && } -
- ); - } + {(!fetching || (claimsInChannel && claimsInChannel.length)) && totalPages > 1 && ( +
+ + + changePage(e.selected + 1)} + forcePage={page - 1} + initialPage={page - 1} + disableInitialCallback + containerClassName="pagination" + /> + + + paginate(e)} + label={__('Go to page:')} + type="text" + name="paginate-file" + /> + +
+ )} + + {!channelIsMine && } + + ); } export default ChannelPage; diff --git a/src/ui/page/discover/index.js b/src/ui/page/discover/index.js index 99f92641c..3b59c6e4a 100644 --- a/src/ui/page/discover/index.js +++ b/src/ui/page/discover/index.js @@ -14,7 +14,7 @@ const select = state => ({ }); const perform = dispatch => ({ - fetchFeaturedUris: () => dispatch(doFetchFeaturedUris(true)), + fetchFeaturedUris: () => dispatch(doFetchFeaturedUris()), fetchRewardedContent: () => dispatch(doFetchRewardedContent()), fetchRewards: () => dispatch(doRewardList()), }); diff --git a/src/ui/page/file/index.js b/src/ui/page/file/index.js index c610819af..921eba8b0 100644 --- a/src/ui/page/file/index.js +++ b/src/ui/page/file/index.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; import * as settings from 'constants/settings'; -import { doNavigate } from 'redux/actions/navigation'; import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content'; import { doRemoveUnreadSubscription } from 'redux/actions/subscriptions'; import { doSetClientSetting } from 'redux/actions/settings'; @@ -15,10 +14,10 @@ import { makeSelectChannelForClaimUri, } from 'lbry-redux'; import { - makeSelectCostInfoForUri, - doFetchCostInfoForUri, doFetchViewCount, makeSelectViewCountForUri, + makeSelectCostInfoForUri, + doFetchCostInfoForUri, } from 'lbryinc'; import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; @@ -43,7 +42,6 @@ const select = (state, props) => ({ }); const perform = dispatch => ({ - navigate: (path, params) => dispatch(doNavigate(path, params)), fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)), fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/src/ui/page/file/view.jsx b/src/ui/page/file/view.jsx index 749a5ca1a..7c9eae257 100644 --- a/src/ui/page/file/view.jsx +++ b/src/ui/page/file/view.jsx @@ -39,7 +39,6 @@ type Props = { channelUri: string, viewCount: number, prepareEdit: ({}, string) => void, - navigate: (string, ?{}) => void, openModal: (id: string, { uri: string }) => void, markSubscriptionRead: (string, string) => void, fetchViewCount: string => void, @@ -132,7 +131,6 @@ class FilePage extends React.Component { openModal, claimIsMine, prepareEdit, - navigate, costInfo, fileInfo, channelUri, @@ -173,6 +171,7 @@ class FilePage extends React.Component { return (
+

{uri}

{showFile && } {!showFile && (thumbnail ? ( @@ -231,9 +230,9 @@ class FilePage extends React.Component { button="primary" icon={icons.EDIT} label={__('Edit')} + navigate="/$/publish" onClick={() => { prepareEdit(claim, editUri); - navigate('/publish'); }} /> )} diff --git a/src/ui/page/fileListDownloaded/index.js b/src/ui/page/fileListDownloaded/index.js index cfc3e4588..a1396c231 100644 --- a/src/ui/page/fileListDownloaded/index.js +++ b/src/ui/page/fileListDownloaded/index.js @@ -5,7 +5,6 @@ import { selectIsFetchingFileList, selectFileListDownloadedSort, } from 'lbry-redux'; -import { doNavigate } from 'redux/actions/navigation'; import FileListDownloaded from './view'; const select = state => ({ @@ -15,11 +14,7 @@ const select = state => ({ sortBy: selectFileListDownloadedSort(state), }); -const perform = dispatch => ({ - navigate: path => dispatch(doNavigate(path)), -}); - export default connect( select, - perform + null )(FileListDownloaded); diff --git a/src/ui/page/fileListDownloaded/view.jsx b/src/ui/page/fileListDownloaded/view.jsx index 8bc94552b..9cc001860 100644 --- a/src/ui/page/fileListDownloaded/view.jsx +++ b/src/ui/page/fileListDownloaded/view.jsx @@ -8,13 +8,12 @@ import { PAGES } from 'lbry-redux'; type Props = { fetching: boolean, fileInfos: {}, - navigate: (string, ?{}) => void, sortBy: string, }; class FileListDownloaded extends React.PureComponent { render() { - const { fetching, fileInfos, navigate, sortBy } = this.props; + const { fetching, fileInfos, sortBy } = this.props; const hasDownloads = fileInfos && Object.values(fileInfos).length > 0; return ( @@ -32,11 +31,7 @@ class FileListDownloaded extends React.PureComponent {
-
diff --git a/src/ui/page/fileListPublished/index.js b/src/ui/page/fileListPublished/index.js index 1826fb78d..28a92df66 100644 --- a/src/ui/page/fileListPublished/index.js +++ b/src/ui/page/fileListPublished/index.js @@ -4,7 +4,6 @@ import { selectFileListPublishedSort, selectMyClaimsWithoutChannels, } from 'lbry-redux'; -import { doNavigate } from 'redux/actions/navigation'; import { doCheckPendingPublishes } from 'redux/actions/publish'; import FileListPublished from './view'; @@ -15,7 +14,6 @@ const select = state => ({ }); const perform = dispatch => ({ - navigate: path => dispatch(doNavigate(path)), checkPendingPublishes: () => dispatch(doCheckPendingPublishes()), }); diff --git a/src/ui/page/fileListPublished/view.jsx b/src/ui/page/fileListPublished/view.jsx index 4b92854af..0f1e39d17 100644 --- a/src/ui/page/fileListPublished/view.jsx +++ b/src/ui/page/fileListPublished/view.jsx @@ -9,7 +9,6 @@ import { PAGES } from 'lbry-redux'; type Props = { claims: Array, checkPendingPublishes: () => void, - navigate: (string, ?{}) => void, fetching: boolean, sortBy: string, }; @@ -21,7 +20,7 @@ class FileListPublished extends React.PureComponent { } render() { - const { fetching, claims, navigate, sortBy } = this.props; + const { fetching, claims, sortBy } = this.props; return ( {claims && claims.length ? ( @@ -45,7 +44,7 @@ class FileListPublished extends React.PureComponent {
diff --git a/src/ui/page/help/view.jsx b/src/ui/page/help/view.jsx index f6b53490e..e53db93b5 100644 --- a/src/ui/page/help/view.jsx +++ b/src/ui/page/help/view.jsx @@ -200,7 +200,7 @@ class HelpPage extends React.PureComponent {
+
diff --git a/src/ui/redux/actions/app.js b/src/ui/redux/actions/app.js index 4344320af..b94093ff4 100644 --- a/src/ui/redux/actions/app.js +++ b/src/ui/redux/actions/app.js @@ -317,6 +317,7 @@ export function doDaemonReady() { dispatch({ type: ACTIONS.DAEMON_READY }); dispatch(doFetchDaemonSettings()); dispatch(doBalanceSubscribe()); + // @if TARGET='app' dispatch(doFetchFileInfosAndPublishedClaims()); if (!selectIsUpgradeSkipped(state)) { diff --git a/src/ui/redux/actions/content.js b/src/ui/redux/actions/content.js index 370fd679c..dd8b8a05d 100644 --- a/src/ui/redux/actions/content.js +++ b/src/ui/redux/actions/content.js @@ -7,7 +7,7 @@ import * as MODALS from 'constants/modal_types'; import { ipcRenderer } from 'electron'; // @endif import { doOpenModal } from 'redux/actions/app'; -import { doNavigate } from 'redux/actions/navigation'; +import { navigate } from '@reach/router'; import { setSubscriptionLatest, doUpdateUnreadSubscriptions } from 'redux/actions/subscriptions'; import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions'; import { @@ -24,10 +24,11 @@ import { parseURI, creditsToString, doError, + makeSelectCostInfoForUri, } from 'lbry-redux'; -import { makeSelectCostInfoForUri } from 'lbryinc'; import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings'; import analytics from 'analytics'; +import { formatLbryUriForWeb } from 'util/uri'; const DOWNLOAD_POLL_INTERVAL = 250; @@ -82,11 +83,7 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) { silent: false, }); notif.onclick = () => { - dispatch( - doNavigate('/show', { - uri, - }) - ); + navigate(formatLbryUriForWeb(uri)); }; } diff --git a/src/ui/redux/actions/file.js b/src/ui/redux/actions/file.js index dbe8b7781..fee8cb114 100644 --- a/src/ui/redux/actions/file.js +++ b/src/ui/redux/actions/file.js @@ -10,7 +10,6 @@ import { selectFileInfosByOutpoint, } from 'lbry-redux'; import { doHideModal } from 'redux/actions/app'; -import { doHistoryBack } from 'redux/actions/navigation'; export function doOpenFileInFolder(path) { return () => { @@ -63,7 +62,6 @@ export function doDeleteFileAndGoBack(fileInfo, deleteFromComputer, abandonClaim return dispatch => { const actions = []; actions.push(doHideModal()); - actions.push(doHistoryBack()); actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim)); dispatch(batchActions(...actions)); }; diff --git a/src/ui/redux/actions/navigation.js b/src/ui/redux/actions/navigation.js index 1e331c00a..e69de29bb 100644 --- a/src/ui/redux/actions/navigation.js +++ b/src/ui/redux/actions/navigation.js @@ -1,74 +0,0 @@ -import { ACTIONS, selectHistoryIndex, selectHistoryStack } from 'lbry-redux'; -import { toQueryString } from 'util/query-params'; -import analytics from 'analytics'; - -export function doNavigate(path, params = {}, options = {}) { - return dispatch => { - if (!path) { - return; - } - - // ensure uri always has "lbry://" prefix - const navigationParams = params; - if (path === '/show') { - if (navigationParams.uri && !navigationParams.uri.startsWith('lbry://')) { - navigationParams.uri = `lbry://${navigationParams.uri}`; - } - } - - let url = path; - if (params && Object.values(params).length) { - url += `?${toQueryString(params)}`; - } - - analytics.track('NAVIGATION', { destination: url }); - - const { scrollY } = options; - - dispatch({ - type: ACTIONS.HISTORY_NAVIGATE, - data: { url, index: options.index, scrollY }, - }); - }; -} - -export function doAuthNavigate(pathAfterAuth = null, params = {}) { - return dispatch => { - if (pathAfterAuth) { - dispatch({ - type: ACTIONS.CHANGE_AFTER_AUTH_PATH, - data: { - path: `${pathAfterAuth}?${toQueryString(params)}`, - }, - }); - } - dispatch(doNavigate('/auth')); - }; -} - -export function doHistoryTraverse(dispatch, state, modifier) { - const stack = selectHistoryStack(state); - const index = selectHistoryIndex(state) + modifier; - - if (index >= 0 && index < stack.length) { - const historyItem = stack[index]; - dispatch(doNavigate(historyItem.path, {}, { scrollY: historyItem.scrollY, index })); - } -} - -export function doHistoryBack() { - return (dispatch, getState) => doHistoryTraverse(dispatch, getState(), -1); -} - -export function doHistoryForward() { - return (dispatch, getState) => doHistoryTraverse(dispatch, getState(), 1); -} - -export function doRecordScroll(scroll) { - return dispatch => { - dispatch({ - type: ACTIONS.WINDOW_SCROLLED, - data: { scrollY: scroll }, - }); - }; -} diff --git a/src/ui/redux/actions/publish.js b/src/ui/redux/actions/publish.js index 801790803..a4cd9fda6 100644 --- a/src/ui/redux/actions/publish.js +++ b/src/ui/redux/actions/publish.js @@ -21,8 +21,9 @@ import { } from 'lbry-redux'; import { doOpenModal } from 'redux/actions/app'; import { selectosNotificationsEnabled } from 'redux/selectors/settings'; -import { doNavigate } from 'redux/actions/navigation'; +import { navigate } from '@reach/router'; import analytics from 'analytics'; +import { formatLbryUriForWeb } from 'util/uri'; // @if TARGET='app' import fs from 'fs'; import path from 'path'; @@ -127,12 +128,12 @@ export const doUploadThumbnail = (filePath: string, nsfw: boolean) => (dispatch: .then(json => json.success ? dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE, - thumbnail: `${json.data.url}${fileExt}`, - }, - }) + type: ACTIONS.UPDATE_PUBLISH_FORM, + data: { + uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE, + thumbnail: `${json.data.url}${fileExt}`, + }, + }) : uploadError(json.message) ) .catch(err => uploadError(err.message)); @@ -327,11 +328,7 @@ export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetS silent: false, }); notif.onclick = () => { - dispatch( - doNavigate('/show', { - uri: claim.permanent_url, - }) - ); + navigate(formatLbryUriForWeb(claim.permanent_url)); }; } } diff --git a/src/ui/redux/selectors/app.js b/src/ui/redux/selectors/app.js index 27169590f..69c4fdee3 100644 --- a/src/ui/redux/selectors/app.js +++ b/src/ui/redux/selectors/app.js @@ -100,21 +100,6 @@ export const selectDaemonVersionMatched = createSelector( state => state.daemonVersionMatched ); -export const selectSnackBar = createSelector( - selectState, - state => state.snackBar || {} -); - -export const selectSnackBarSnacks = createSelector( - selectSnackBar, - snackBar => snackBar.snacks || [] -); - -export const selectBadgeNumber = createSelector( - selectState, - state => state.badgeNumber -); - export const selectCurrentLanguage = createSelector( selectState, () => i18n.getLocale() || 'en' @@ -130,147 +115,6 @@ export const selectUpgradeTimer = createSelector( state => state.checkUpgradeTimer ); -export const selectNavLinks = createSelector( - selectCurrentPage, - selectHistoryStack, - makeSelectClientSetting(SETTINGS.FIRST_RUN_COMPLETED), - makeSelectClientSetting(SETTINGS.INVITE_ACKNOWLEDGED), - (currentPage, historyStack, firstRunCompleted, inviteAcknowledged) => { - // Determine if any links should show a tooltip for a guided tour - // It will only show one at a time, in the order they are set. - const guidedTourItem = [ - // @if TARGET='app' - { - page: PAGES.INVITE, - hasBeenCompleted: inviteAcknowledged, - guide: 'Check this out!', - }, - // @endif - // Add more items below for tooltip guides that will happen after a user has completed the invite guide - ].filter(({ hasBeenCompleted }) => !hasBeenCompleted)[0]; - - const isWalletPage = page => - page === PAGES.WALLET || - page === PAGES.SEND || - page === PAGES.GET_CREDITS || - page === PAGES.HISTORY || - page === PAGES.BACKUP; - - const isCurrentlyWalletPage = isWalletPage(currentPage); - const previousStack = historyStack.slice().reverse(); - - const getPreviousSubLinkPath = checkIfValidPage => { - for (let i = 0; i < previousStack.length; i += 1) { - const currentStackItem = previousStack[i]; - - // Trim off the "/" from the path - const pageInStack = currentStackItem.path.slice(1); - if (checkIfValidPage(pageInStack)) { - return currentStackItem.path; - } - } - - return undefined; - }; - - // Gets the last active sublink in a section - const getActiveSublink = category => { - if (category === PAGES.WALLET) { - const previousPath = getPreviousSubLinkPath(isWalletPage); - return previousPath || `/${PAGES.WALLET}`; - } - - return undefined; - }; - - // Is this path the first unacknowledged item in the guided tour list - const getGuideIfNecessary = page => { - if (!firstRunCompleted) { - return null; - } - return guidedTourItem && guidedTourItem.page === page ? guidedTourItem.guide : null; - }; - - const buildLink = (label, page) => ({ - label, - path: `/${page}`, - active: currentPage === page, - guide: getGuideIfNecessary(page), - }); - - const walletSubLinks = [ - { - ...buildLink('Overview', PAGES.WALLET), - }, - { - ...buildLink('Send & Receive', PAGES.SEND), - }, - { - ...buildLink('Transactions', PAGES.HISTORY), - }, - { - ...buildLink('Get Credits', PAGES.GET_CREDITS), - }, - { - ...buildLink('Backup', PAGES.BACKUP), - }, - ]; - - const navLinks = { - primary: [ - { - ...buildLink('Explore', PAGES.DISCOVER), - icon: ICONS.HOME, - }, - { - ...buildLink('Subscriptions', PAGES.SUBSCRIPTIONS), - icon: ICONS.SUBSCRIPTION, - }, - ], - secondary: [ - { - label: 'Wallet', - icon: ICONS.WALLET, - subLinks: walletSubLinks, - path: isCurrentlyWalletPage ? `/${PAGES.WALLET}` : getActiveSublink(PAGES.WALLET), - active: isWalletPage(currentPage), - }, - { - ...buildLink('Invite', PAGES.INVITE), - icon: ICONS.INVITE, - }, - { - ...buildLink('Rewards', PAGES.REWARDS), - // This probably shouldn't use the "FEATURED" icon, but not sure what else to use - icon: ICONS.FEATURED, - }, - { - ...buildLink('Downloads', PAGES.DOWNLOADED), - icon: ICONS.LOCAL, - }, - { - ...buildLink('Publishes', PAGES.PUBLISHED), - icon: ICONS.PUBLISHED, - }, - { - ...buildLink('History', PAGES.USER_HISTORY), - icon: ICONS.HISTORY, - }, - { - ...buildLink('Settings', PAGES.SETTINGS), - icon: ICONS.SETTINGS, - }, - { - ...buildLink('Help', PAGES.HELP), - icon: ICONS.HELP, - }, - ], - }; - - return navLinks; - } -); - export const selectModal = createSelector( selectState, state => { diff --git a/src/ui/redux/selectors/content.js b/src/ui/redux/selectors/content.js index 1f1568df4..d228f2f0c 100644 --- a/src/ui/redux/selectors/content.js +++ b/src/ui/redux/selectors/content.js @@ -3,7 +3,7 @@ import { createSelector } from 'reselect'; import { makeSelectClaimForUri, selectClaimsByUri, - makeSelectClaimsInChannelForCurrentPage, + makeSelectClaimsInChannelForCurrentPageState, } from 'lbry-redux'; import { HISTORY_ITEMS_PER_PAGE } from 'constants/content'; @@ -68,7 +68,7 @@ export const makeSelectHistoryForUri = (uri: string) => export const makeSelectCategoryListUris = (uris: ?Array, channel: string) => createSelector( - makeSelectClaimsInChannelForCurrentPage(channel), + makeSelectClaimsInChannelForCurrentPageState(channel), channelClaims => { if (uris) return uris; diff --git a/src/ui/scss/component/_button.scss b/src/ui/scss/component/_button.scss index 5be396596..4943cd565 100644 --- a/src/ui/scss/component/_button.scss +++ b/src/ui/scss/component/_button.scss @@ -2,6 +2,7 @@ .button { border-radius: 0; + font-size: 1em; svg { stroke-width: 1.9; diff --git a/src/ui/scss/component/_header.scss b/src/ui/scss/component/_header.scss index d2d89cee8..eea4f2188 100644 --- a/src/ui/scss/component/_header.scss +++ b/src/ui/scss/component/_header.scss @@ -27,7 +27,12 @@ // at smaller screen widths @media (min-width: 601px) { + /* @if TARGET='app' */ width: 250px; + /* @endif */ + /* @if TARGET='web' */ + width: 170px; + /* @endif */ } @media (max-width: 600px) { @@ -38,9 +43,9 @@ .header__navigation-item { height: var(--header-height); - background-position: center; - background-repeat: no-repeat; - background-size: 50%; + display: flex; + justify-content: center; + align-items: center; &:not(:disabled):hover { background-color: $lbry-gray-1; @@ -53,68 +58,49 @@ &:disabled { opacity: 0.3; } -} -.header__navigation-item--back { - html[data-mode='dark'] & { - svg { - stroke: $lbry-white; - } + .button__content { + line-height: var(--header-height); + overflow: hidden; + text-align: center; + text-overflow: ellipsis; + width: 100%; } } -.header__navigation-item--forward { - html[data-mode='dark'] & { - svg { - stroke: $lbry-white; - } - } -} - -.header__navigation-item--home { - html[data-mode='dark'] & { - svg { - stroke: $lbry-white; - } - } -} - -.header__navigation-item--menu { - html[data-mode='dark'] & { - svg { - stroke: $lbry-white; - } - } - - // This menu button does not need to be seen - // at larger screen widths - - @media (min-width: 601px) { - display: none; - } -} .header__navigation-item--back, .header__navigation-item--forward, .header__navigation-item--home, .header__navigation-item--menu { width: var(--header-height); + svg { + &:only-child { + // Header icons are a little different because they are larger + top: 0.25rem; + } + + html[data-mode='dark'] & { + stroke: $lbry-white; + } + } } -// Currently not used -// .header__navigation-item--publish, -// .header__navigation-item--wallet { -// // Publish and Wallet links are collapsed -// // into a menu at smaller screen widths -// -// @media (max-width: 600px) { -// display: none; -// } -// } +.header__navigation-item--lbry { + flex: 1; + font-weight: 800; + font-size: 1.2rem; + margin-left: -1.25rem; // Needed because the lbry icon overflows it's parent so the centering is off + + svg { + overflow: visible; + color: $lbry-white; + opacity: 1; + top: -0.2rem; + } +} // Publish button .header__navigation-item--right-action { - display: flex; - justify-content: center; position: relative; .button__content { @@ -149,12 +135,24 @@ html[data-mode='dark'] & { border-color: $lbry-gray-5; } +} - .button__content { - line-height: var(--header-height); - overflow: hidden; - text-align: center; - text-overflow: ellipsis; - width: 100%; +.header__navigation-item--menu { + @media (min-width: 601px) { + display: none; + } +} + +// Hide links that will live in the menu bar +@media (max-width: 601px) { + .header__navigation-item--back, + .header__navigation-item--forward, + .header__navigation-item--home, + .header__navigation-item--right-action { + display: none; + } + + .header__navigation:first-child { + display: none; } } diff --git a/src/ui/scss/component/_media.scss b/src/ui/scss/component/_media.scss index ff8a64225..e4c209c86 100644 --- a/src/ui/scss/component/_media.scss +++ b/src/ui/scss/component/_media.scss @@ -139,6 +139,12 @@ margin-right: var(--spacing-vertical-small); } +.media__uri { + font-size: 1.1rem; + padding-bottom: 5px; + opacity: 0.6; +} + // M E D I A // A C T I O N S @@ -508,21 +514,19 @@ font-size: 2rem; } - @media (max-width: 600px) { - font-size: 1.75rem; - } - .channel-info__actions__group { - button:first-of-type { - font-size: 2rem; + .button { + &:first-child { + font-size: 2rem; - .button__label { - margin: 0; + .button__label { + margin: 0; + } } - } - button:last-of-type { - font-weight: normal; + &:last-child { + font-weight: normal; + } } } } diff --git a/src/ui/scss/component/_navigation.scss b/src/ui/scss/component/_navigation.scss index e8ae5dee9..9f5656ea0 100644 --- a/src/ui/scss/component/_navigation.scss +++ b/src/ui/scss/component/_navigation.scss @@ -52,6 +52,11 @@ position: relative; } +.navigation__links--bottom { + position: absolute; + bottom: var(--spacing-vertical-large); +} + .navigation__link { display: block; line-height: 1.75; @@ -102,7 +107,7 @@ .navigation__link--title { margin-bottom: var(--spacing-vertical-small); - padding-top: var(--spacing-vertical-medium); + padding-top: var(--spacing-vertical-large); color: $lbry-gray-5; cursor: default; diff --git a/src/ui/scss/component/_search.scss b/src/ui/scss/component/_search.scss index 5155333c1..1ce718c0b 100644 --- a/src/ui/scss/component/_search.scss +++ b/src/ui/scss/component/_search.scss @@ -53,6 +53,7 @@ .search__options-wrapper { font-size: 1.25em; + padding-bottom: var(--spacing-vertical-large); } .search__options { diff --git a/src/ui/scss/component/_yrbl.scss b/src/ui/scss/component/_yrbl.scss index 3f1d77844..8d6f92a6d 100644 --- a/src/ui/scss/component/_yrbl.scss +++ b/src/ui/scss/component/_yrbl.scss @@ -8,7 +8,7 @@ } .yrbl { - height: 300px; + height: 20rem; margin-right: var(--spacing-vertical-large); } diff --git a/src/ui/scss/init/_gui.scss b/src/ui/scss/init/_gui.scss index 681898f36..c10d86524 100644 --- a/src/ui/scss/init/_gui.scss +++ b/src/ui/scss/init/_gui.scss @@ -127,7 +127,7 @@ code { } .help { - font-size: 0.9em; + font-size: 1rem; background-color: rgba($lbry-blue-1, 0.1); color: $lbry-gray-5; display: block; diff --git a/src/ui/scss/init/_vars.scss b/src/ui/scss/init/_vars.scss index 730791daa..90972d9e5 100644 --- a/src/ui/scss/init/_vars.scss +++ b/src/ui/scss/init/_vars.scss @@ -39,7 +39,7 @@ $large-breakpoint: 1921px; --button-height: 36px; // Header - --header-height: 3.25rem; // 60px; + --header-height: 3.5rem; // Header -> search --search-modal-input-height: 70px; diff --git a/src/ui/types/location.js b/src/ui/types/location.js new file mode 100644 index 000000000..5ec91da94 --- /dev/null +++ b/src/ui/types/location.js @@ -0,0 +1,18 @@ +// @flow + +export type UrlLocation = { + search: string, + hash: string, + host: string, + hostname: string, + href: string, + key: string, + origin: string, + pathname: string, + port: string, + protocol: string, + reload: () => void, + replace: string => void, + search: string, + state: {}, +}; diff --git a/src/ui/util/uri.js b/src/ui/util/uri.js new file mode 100644 index 000000000..6d8818e55 --- /dev/null +++ b/src/ui/util/uri.js @@ -0,0 +1,13 @@ +// @flow +import { parseURI } from 'lbry-redux'; + +export const formatLbryUriForWeb = (uri: string) => { + const { claimName, claimId } = parseURI(uri); + + let webUrl = `/${claimName}`; + if (claimId) { + webUrl += `/${claimId}`; + } + + return webUrl; +}; diff --git a/static/index.dev.html b/static/index.dev.html index 6fd2defc2..a4796bb47 100644 --- a/static/index.dev.html +++ b/static/index.dev.html @@ -2,6 +2,7 @@ + lbry.tv diff --git a/static/index.html b/static/index.html index b31d55a93..468ad045e 100644 --- a/static/index.html +++ b/static/index.html @@ -7,6 +7,6 @@
- + diff --git a/webpack.base.config.js b/webpack.base.config.js index 98506b907..a2cd8c9db 100644 --- a/webpack.base.config.js +++ b/webpack.base.config.js @@ -38,7 +38,7 @@ let baseConfig = { use: { loader: 'file-loader', options: { - outputPath: 'ui/img', + outputPath: '$/static/img', name: '[name].[ext]', }, }, @@ -48,7 +48,7 @@ let baseConfig = { use: { loader: 'file-loader', options: { - outputPath: 'ui/font', + outputPath: '$/static/font', }, }, }, diff --git a/webpack.electron.config.js b/webpack.electron.config.js index 8f1bd6b09..797867e78 100644 --- a/webpack.electron.config.js +++ b/webpack.electron.config.js @@ -4,9 +4,13 @@ const merge = require('webpack-merge'); const baseConfig = require('./webpack.base.config.js'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const { DefinePlugin } = require('webpack'); +const { getIfUtils, removeEmpty } = require('webpack-config-utils'); const STATIC_ROOT = path.resolve(__dirname, 'static/'); const DIST_ROOT = path.resolve(__dirname, 'dist/'); +const NODE_ENV = process.env.NODE_ENV || 'development'; + +const { ifProduction } = getIfUtils(NODE_ENV); let mainConfig = { target: 'electron-main', @@ -20,7 +24,7 @@ let mainConfig = { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(jsx?$|s?css$)/, use: [ { loader: 'preprocess-loader', @@ -40,7 +44,11 @@ let mainConfig = { { from: `${STATIC_ROOT}/`, to: `${DIST_ROOT}/electron/static/`, - ignore: ['font/**/*'], + ignore: ['font/**/*', 'index.dev.html', 'index.html'], + }, + { + from: ifProduction(`${STATIC_ROOT}/index.html`, `${STATIC_ROOT}/index.dev.html`), + to: `${DIST_ROOT}/electron/static/index.html`, }, ]), ], diff --git a/webpack.web.config.js b/webpack.web.config.js index fcb89732a..4591f8f37 100644 --- a/webpack.web.config.js +++ b/webpack.web.config.js @@ -20,7 +20,7 @@ const webConfig = { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(jsx?$|s?css$)/, use: [ { loader: 'preprocess-loader', diff --git a/yarn.lock b/yarn.lock index 2db758eb2..ec57c0417 100644 --- a/yarn.lock +++ b/yarn.lock @@ -850,6 +850,17 @@ resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf" integrity sha512-dEVG+ITnvqKGa4v040tP+n8LOKOqr94qjLva7bE5pnfm2KHJwsKz69J4KMxgWLznbpBJzy8vQfCayEk3vLZnZQ== +"@reach/router@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.2.1.tgz#34ae3541a5ac44fa7796e5506a5d7274a162be4e" + integrity sha512-kTaX08X4g27tzIFQGRukaHmNbtMYDS3LEWIS8+l6OayGIw6Oyo1HIF/JzeuR2FoF9z6oV+x/wJSVSq4v8tcUGQ== + dependencies: + create-react-context "^0.2.1" + invariant "^2.2.3" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + warning "^3.0.0" + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" @@ -1340,6 +1351,11 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -2584,6 +2600,11 @@ copy-webpack-plugin@^4.6.0: p-limit "^1.0.0" serialize-javascript "^1.4.0" +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: version "2.6.5" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" @@ -2651,6 +2672,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-react-context@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3" + integrity sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag== + dependencies: + fbjs "^0.8.0" + gud "^1.0.0" + crocket@^0.9.11: version "0.9.11" resolved "https://registry.yarnpkg.com/crocket/-/crocket-0.9.11.tgz#288fca11ef0d3dd239b62c488265f30c8edfb0c5" @@ -3589,6 +3618,13 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -4239,6 +4275,19 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" +fbjs@^0.8.0: + version "0.8.17" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + fd-slicer@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" @@ -4854,6 +4903,11 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1. resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== + handle-thing@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" @@ -5204,7 +5258,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5386,7 +5440,7 @@ interpret@^1.0.0, interpret@^1.1.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -invariant@^2.2.2, invariant@^2.2.4: +invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -5734,7 +5788,7 @@ is-retry-allowed@^1.0.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -5829,6 +5883,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6066,17 +6128,17 @@ lazy-val@^1.0.3, lazy-val@^1.0.4: tar-stream "^1.6.2" zstd-codec "^0.1.1" -lbry-redux@lbryio/lbry-redux#2a7e05940f892f104428eeb37bd1f178da811a09: +lbry-redux@lbryio/lbry-redux#86f1340f834d0f5cd5365492a8ff15d4b213a050: version "0.0.1" - resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/2a7e05940f892f104428eeb37bd1f178da811a09" + resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/86f1340f834d0f5cd5365492a8ff15d4b213a050" dependencies: proxy-polyfill "0.1.6" reselect "^3.0.0" uuid "^3.3.2" -lbryinc@lbryio/lbryinc#437260f3dad2321e892388b68749ee6af01aff2b: +lbryinc@lbryio/lbryinc#d9f9035113c8b9ab3b0ee7ffbd38f910086a665e: version "0.0.1" - resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/437260f3dad2321e892388b68749ee6af01aff2b" + resolved "https://codeload.github.com/lbryio/lbryinc/tar.gz/d9f9035113c8b9ab3b0ee7ffbd38f910086a665e" dependencies: bluebird "^3.5.1" reselect "^3.0.0" @@ -7006,6 +7068,14 @@ node-emoji@^1.8.1: dependencies: lodash.toarray "^4.4.0" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-fetch@^2.1.1, node-fetch@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" @@ -8253,6 +8323,13 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" @@ -9350,7 +9427,7 @@ set-value@^2.0.0: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4, setimmediate@~1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -10342,6 +10419,11 @@ typo-js@*: resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.0.3.tgz#54d8ebc7949f1a7810908b6002c6841526c99d5a" integrity sha1-VNjrx5SfGngQkItgAsaEFSbJnVo= +ua-parser-js@^0.7.18: + version "0.7.19" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b" + integrity sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ== + uglify-js@3.4.x: version "3.4.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" @@ -10997,6 +11079,11 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== +whatwg-fetch@>=0.10.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" + integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"