Merge pull request #2395 from lbryio/dev

New routing setup
This commit is contained in:
Sean Yesmunt 2019-03-30 00:25:18 -04:00 committed by GitHub
commit 19043fc7f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 855 additions and 1083 deletions

View file

@ -59,6 +59,7 @@
"@hot-loader/react-dom": "16.8", "@hot-loader/react-dom": "16.8",
"@lbry/color": "^1.0.2", "@lbry/color": "^1.0.2",
"@lbry/components": "^2.3.3", "@lbry/components": "^2.3.3",
"@reach/router": "^1.2.1",
"@types/three": "^0.93.1", "@types/three": "^0.93.1",
"async-exit-hook": "^2.0.1", "async-exit-hook": "^2.0.1",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
@ -106,8 +107,8 @@
"husky": "^0.14.3", "husky": "^0.14.3",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#2a7e05940f892f104428eeb37bd1f178da811a09", "lbry-redux": "lbryio/lbry-redux#86f1340f834d0f5cd5365492a8ff15d4b213a050",
"lbryinc": "lbryio/lbryinc#437260f3dad2321e892388b68749ee6af01aff2b", "lbryinc": "lbryio/lbryinc#d9f9035113c8b9ab3b0ee7ffbd38f910086a665e",
"lint-staged": "^7.0.2", "lint-staged": "^7.0.2",
"localforage": "^1.7.1", "localforage": "^1.7.1",
"make-runnable": "^1.3.6", "make-runnable": "^1.3.6",

View file

@ -35,9 +35,7 @@ export default appState => {
}, },
}; };
const rendererURL = isDev // ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}` const rendererURL = isDev ? `http://localhost:8080` : `file://${__dirname}/index.html`;
? `http://localhost:8080/index.dev.html`
: `file://${__dirname}/index.html`;
let window = new BrowserWindow(windowConfiguration); let window = new BrowserWindow(windowConfiguration);

View file

@ -5,4 +5,8 @@ const port = 1337;
app.use(express.static(__dirname)); 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}`));

View file

@ -1,13 +1,6 @@
import { hot } from 'react-hot-loader/root'; import { hot } from 'react-hot-loader/root';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import { doUpdateBlockHeight, doError } from 'lbry-redux';
selectPageTitle,
selectHistoryIndex,
selectActiveHistoryEntry,
doUpdateBlockHeight,
doError,
} from 'lbry-redux';
import { doRecordScroll } from 'redux/actions/navigation';
import { doToggleEnhancedLayout } from 'redux/actions/app'; import { doToggleEnhancedLayout } from 'redux/actions/app';
import { selectUser } from 'lbryinc'; import { selectUser } from 'lbryinc';
import { selectThemePath } from 'redux/selectors/settings'; import { selectThemePath } from 'redux/selectors/settings';
@ -15,17 +8,13 @@ import { selectEnhancedLayout } from 'redux/selectors/app';
import App from './view'; import App from './view';
const select = state => ({ const select = state => ({
pageTitle: selectPageTitle(state),
user: selectUser(state), user: selectUser(state),
currentStackIndex: selectHistoryIndex(state),
currentPageAttributes: selectActiveHistoryEntry(state),
theme: selectThemePath(state), theme: selectThemePath(state),
enhancedLayout: selectEnhancedLayout(state), enhancedLayout: selectEnhancedLayout(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
alertError: errorList => dispatch(doError(errorList)), alertError: errorList => dispatch(doError(errorList)),
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
updateBlockHeight: () => dispatch(doUpdateBlockHeight()), updateBlockHeight: () => dispatch(doUpdateBlockHeight()),
toggleEnhancedLayout: () => dispatch(doToggleEnhancedLayout()), toggleEnhancedLayout: () => dispatch(doToggleEnhancedLayout()),
}); });

View file

@ -14,9 +14,6 @@ const TWO_POINT_FIVE_MINUTES = 1000 * 60 * 2.5;
type Props = { type Props = {
alertError: (string | {}) => void, alertError: (string | {}) => void,
recordScroll: number => void,
currentStackIndex: number,
currentPageAttributes: { path: string, scrollY: number },
pageTitle: ?string, pageTitle: ?string,
theme: string, theme: string,
updateBlockHeight: () => void, updateBlockHeight: () => void,
@ -25,12 +22,6 @@ type Props = {
}; };
class App extends React.PureComponent<Props> { class App extends React.PureComponent<Props> {
constructor() {
super();
this.mainContent = undefined;
(this: any).scrollListener = this.scrollListener.bind(this);
}
componentWillMount() { componentWillMount() {
const { alertError, theme } = this.props; const { alertError, theme } = this.props;
@ -47,12 +38,6 @@ class App extends React.PureComponent<Props> {
componentDidMount() { componentDidMount() {
const { updateBlockHeight, toggleEnhancedLayout } = this.props; 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 ReactModal.setAppElement('#window'); // fuck this
this.enhance = new EnhancedLayoutListener(() => toggleEnhancedLayout()); this.enhance = new EnhancedLayoutListener(() => toggleEnhancedLayout());
@ -63,18 +48,9 @@ class App extends React.PureComponent<Props> {
}, TWO_POINT_FIVE_MINUTES); }, TWO_POINT_FIVE_MINUTES);
} }
componentWillReceiveProps(props: Props) {
const { pageTitle } = props;
this.setTitleFromProps(pageTitle);
}
componentDidUpdate(prevProps: Props) { componentDidUpdate(prevProps: Props) {
const { currentStackIndex: prevStackIndex, theme: prevTheme } = prevProps; const { theme: prevTheme } = prevProps;
const { currentStackIndex, currentPageAttributes, theme } = this.props; const { theme } = this.props;
if (this.mainContent && currentStackIndex !== prevStackIndex && currentPageAttributes) {
this.mainContent.scrollTop = currentPageAttributes.scrollY || 0;
}
if (prevTheme !== theme) { if (prevTheme !== theme) {
// $FlowFixMe // $FlowFixMe
@ -83,26 +59,9 @@ class App extends React.PureComponent<Props> {
} }
componentWillUnmount() { componentWillUnmount() {
if (this.mainContent) {
this.mainContent.removeEventListener('scroll', this.scrollListener);
}
this.enhance = null; 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; enhance: ?any;
render() { render() {

View file

@ -1,12 +1,3 @@
import { connect } from 'react-redux';
import { doNavigate } from 'redux/actions/navigation';
import Button from './view'; import Button from './view';
const perform = dispatch => ({ export default Button;
doNavigate: (path, params) => dispatch(doNavigate(path, params)),
});
export default connect(
null,
perform
)(Button);

View file

@ -2,6 +2,8 @@
import * as React from 'react'; import * as React from 'react';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import classnames from 'classnames'; import classnames from 'classnames';
import { Link } from '@reach/router';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
onClick: ?(any) => any, onClick: ?(any) => any,
@ -13,9 +15,6 @@ type Props = {
disabled: ?boolean, disabled: ?boolean,
children: ?React.Node, children: ?React.Node,
navigate: ?string, navigate: ?string,
// TODO: these (nav) should be a reusable type
doNavigate: (string, ?any) => void,
navigateParams: any,
className: ?string, className: ?string,
description: ?string, description: ?string,
type: string, type: string,
@ -24,7 +23,7 @@ type Props = {
iconColor?: string, iconColor?: string,
iconSize?: number, iconSize?: number,
constrict: ?boolean, // to shorten the button and ellipsis, only use for links constrict: ?boolean, // to shorten the button and ellipsis, only use for links
selected: ?boolean, activeClass?: string,
}; };
class Button extends React.PureComponent<Props> { class Button extends React.PureComponent<Props> {
@ -43,8 +42,6 @@ class Button extends React.PureComponent<Props> {
disabled, disabled,
children, children,
navigate, navigate,
navigateParams,
doNavigate,
className, className,
description, description,
button, button,
@ -53,7 +50,7 @@ class Button extends React.PureComponent<Props> {
iconColor, iconColor,
iconSize, iconSize,
constrict, constrict,
selected, activeClass,
...otherProps ...otherProps
} = this.props; } = this.props;
@ -72,20 +69,11 @@ class Button extends React.PureComponent<Props> {
'button--disabled': disabled, 'button--disabled': disabled,
'button--link': button === 'link', 'button--link': button === 'link',
'button--constrict': constrict, 'button--constrict': constrict,
'button--selected': selected,
} }
: 'button--no-style', : 'button--no-style',
className className
); );
const extendedOnClick =
!onClick && navigate
? event => {
event.stopPropagation();
doNavigate(navigate, navigateParams || {});
}
: onClick;
const content = ( const content = (
<span className="button__content"> <span className="button__content">
{icon && <Icon icon={icon} iconColor={iconColor} size={iconSize} />} {icon && <Icon icon={icon} iconColor={iconColor} size={iconSize} />}
@ -95,16 +83,43 @@ class Button extends React.PureComponent<Props> {
</span> </span>
); );
return href ? ( if (href) {
<a className={combinedClassName} href={href} title={title}> return (
<a href={href} className={combinedClassName}>
{content} {content}
</a> </a>
);
}
// 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 ? (
<Link
to={path}
title={title}
onClick={e => e.stopPropagation()}
getProps={({ isCurrent }) => ({
className:
isCurrent && activeClass ? `${combinedClassName} ${activeClass}` : combinedClassName,
})}
>
{content}
</Link>
) : ( ) : (
<button <button
title={title} title={title}
aria-label={description || label || title} aria-label={description || label || title}
className={combinedClassName} className={combinedClassName}
onClick={extendedOnClick} onClick={onClick}
disabled={disabled} disabled={disabled}
type={type} type={type}
{...otherProps} {...otherProps}

View file

@ -1,11 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doFetchClaimsByChannel } from 'redux/actions/content'; import { doFetchClaimsByChannel } from 'redux/actions/content';
import { makeSelectCategoryListUris } from 'redux/selectors/content'; import { makeSelectCategoryListUris } from 'redux/selectors/content';
import { import { makeSelectFetchingChannelClaims, doResolveUris } from 'lbry-redux';
makeSelectFetchingChannelClaims,
doResolveUris,
selectActiveHistoryEntry,
} from 'lbry-redux';
import { selectShowNsfw } from 'redux/selectors/settings'; import { selectShowNsfw } from 'redux/selectors/settings';
import CategoryList from './view'; import CategoryList from './view';
@ -13,7 +9,6 @@ const select = (state, props) => ({
urisInList: makeSelectCategoryListUris(props.uris, props.categoryLink)(state), urisInList: makeSelectCategoryListUris(props.uris, props.categoryLink)(state),
fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state), fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
obscureNsfw: !selectShowNsfw(state), obscureNsfw: !selectShowNsfw(state),
currentPageAttributes: selectActiveHistoryEntry(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({

View file

@ -1,12 +1,13 @@
// @flow // @flow
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React, { PureComponent, createRef } from 'react'; import React, { PureComponent, createRef } from 'react';
import { normalizeURI } from 'lbry-redux'; import { normalizeURI, parseURI } from 'lbry-redux';
import ToolTip from 'component/common/tooltip'; import ToolTip from 'component/common/tooltip';
import FileCard from 'component/fileCard'; import FileCard from 'component/fileCard';
import Button from 'component/button'; import Button from 'component/button';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';
import throttle from 'util/throttle'; import throttle from 'util/throttle';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
category: string, category: string,
@ -44,7 +45,7 @@ class CategoryList extends PureComponent<Props, State> {
(this: any).handleScrollNext = this.handleScrollNext.bind(this); (this: any).handleScrollNext = this.handleScrollNext.bind(this);
(this: any).handleScrollPrevious = this.handleScrollPrevious.bind(this); (this: any).handleScrollPrevious = this.handleScrollPrevious.bind(this);
(this: any).handleArrowButtonsOnScroll = this.handleArrowButtonsOnScroll.bind(this); (this: any).handleArrowButtonsOnScroll = this.handleArrowButtonsOnScroll.bind(this);
(this: any).handleResolveOnScroll = this.handleResolveOnScroll.bind(this); // (this: any).handleResolveOnScroll = this.handleResolveOnScroll.bind(this);
this.scrollWrapper = createRef(); this.scrollWrapper = createRef();
} }
@ -75,32 +76,34 @@ class CategoryList extends PureComponent<Props, State> {
} }
} }
componentDidUpdate(prevProps: Props) { // The old lazy loading for home page relied on the navigation reducers copy of the scroll height
const { scrollY: previousScrollY } = prevProps.currentPageAttributes; // Keeping it commented out for now to try and find a better way for better TTI on the homepage
const { scrollY } = this.props.currentPageAttributes; // componentDidUpdate(prevProps: Props) {
// const {scrollY: previousScrollY} = prevProps.currentPageAttributes;
// const {scrollY} = this.props.currentPageAttributes;
if (scrollY > previousScrollY) { // if(scrollY > previousScrollY) {
this.handleResolveOnScroll(); // this.handleResolveOnScroll();
} // }
} // }
handleResolveOnScroll() { // handleResolveOnScroll() {
const { // const {
urisInList, // urisInList,
resolveUris, // resolveUris,
currentPageAttributes: { scrollY }, // currentPageAttributes: {scrollY},
} = this.props; // } = this.props;
const scrollWrapper = this.scrollWrapper.current; // const scrollWrapper = this.scrollWrapper.current;
if (!scrollWrapper) { // if(!scrollWrapper) {
return; // return;
} // }
const shouldResolve = window.innerHeight > scrollWrapper.offsetTop - scrollY; // const shouldResolve = window.innerHeight > scrollWrapper.offsetTop - scrollY;
if (shouldResolve && urisInList) { // if(shouldResolve && urisInList) {
resolveUris(urisInList); // resolveUris(urisInList);
} // }
} // }
handleArrowButtonsOnScroll() { handleArrowButtonsOnScroll() {
// Determine if the arrow buttons should be disabled // Determine if the arrow buttons should be disabled
@ -261,6 +264,11 @@ class CategoryList extends PureComponent<Props, State> {
const isCommunityTopBids = category.match(/^community/i); const isCommunityTopBids = category.match(/^community/i);
const showScrollButtons = isCommunityTopBids ? !obscureNsfw : true; const showScrollButtons = isCommunityTopBids ? !obscureNsfw : true;
let channelLink;
if (categoryLink) {
channelLink = formatLbryUriForWeb(categoryLink);
}
return ( return (
<section className="media-group--row"> <section className="media-group--row">
<header className="media-group__header"> <header className="media-group__header">
@ -268,11 +276,7 @@ class CategoryList extends PureComponent<Props, State> {
{categoryLink ? ( {categoryLink ? (
<div className="channel-info__actions"> <div className="channel-info__actions">
<div className="channel-info__actions__group"> <div className="channel-info__actions__group">
<Button <Button label={category} navigate={channelLink} />
label={category}
navigate="/show"
navigateParams={{ uri: categoryLink, page: 1 }}
/>
<SubscribeButton <SubscribeButton
button="alt" button="alt"
showSnackBarOnSubscribe showSnackBarOnSubscribe
@ -313,7 +317,7 @@ class CategoryList extends PureComponent<Props, State> {
{__( {__(
'The community top bids section is only visible if you allow mature content in the app. You can change your content viewing preferences' 'The community top bids section is only visible if you allow mature content in the app. You can change your content viewing preferences'
)}{' '} )}{' '}
<Button button="link" navigate="/settings" label={__('here')} />. <Button button="link" navigate="/$/settings" label={__('here')} />.
</p> </p>
) : ( ) : (
<ul className="media-scrollhouse" ref={this.scrollWrapper}> <ul className="media-scrollhouse" ref={this.scrollWrapper}>

View file

@ -5,7 +5,6 @@ import {
makeSelectIsUriResolving, makeSelectIsUriResolving,
makeSelectTotalItemsForChannel, makeSelectTotalItemsForChannel,
} from 'lbry-redux'; } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import ChannelTile from './view'; import ChannelTile from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -15,7 +14,6 @@ const select = (state, props) => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
}); });

View file

@ -5,6 +5,8 @@ import TruncatedText from 'component/common/truncated-text';
import classnames from 'classnames'; import classnames from 'classnames';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';
import type { Claim } from 'types/claim'; import type { Claim } from 'types/claim';
import { navigate } from '@reach/router';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
uri: string, uri: string,
@ -13,7 +15,6 @@ type Props = {
size: string, size: string,
claim: ?Claim, claim: ?Claim,
resolveUri: string => void, resolveUri: string => void,
navigate: (string, ?{}) => void,
}; };
class ChannelTile extends React.PureComponent<Props> { class ChannelTile extends React.PureComponent<Props> {
@ -36,7 +37,7 @@ class ChannelTile extends React.PureComponent<Props> {
} }
render() { render() {
const { claim, navigate, isResolvingUri, totalItems, uri, size } = this.props; const { claim, isResolvingUri, totalItems, uri, size } = this.props;
let channelName; let channelName;
let subscriptionUri; let subscriptionUri;
@ -45,7 +46,7 @@ class ChannelTile extends React.PureComponent<Props> {
subscriptionUri = `lbry://${claim.permanent_url}`; subscriptionUri = `lbry://${claim.permanent_url}`;
} }
const onClick = () => navigate('/show', { uri, page: 1 }); const onClick = () => navigate(formatLbryUriForWeb(uri));
return ( return (
<section <section

View file

@ -26,7 +26,7 @@ class FileExporter extends React.PureComponent<Props> {
constructor() { constructor() {
super(); super();
this.handleButtonClick = this.handleButtonClick.bind(this); (this: any).handleButtonClick = this.handleButtonClick.bind(this);
} }
handleFileCreation(filename: string, data: any) { handleFileCreation(filename: string, data: any) {

View file

@ -1,6 +1,6 @@
// @flow // @flow
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React, { Fragment } from 'react';
type IconProps = { type IconProps = {
size: number, size: number,
@ -16,7 +16,7 @@ const buildIcon = iconStrokes => (props: IconProps) => {
viewBox="0 0 24 24" viewBox="0 0 24 24"
width={size} width={size}
height={size} height={size}
fill="none" fill="solid"
stroke={color} stroke={color}
strokeWidth="2" strokeWidth="2"
strokeLinecap="round" strokeLinecap="round"
@ -114,4 +114,16 @@ export const customIcons = {
[ICONS.UNSUBSCRIBE]: buildIcon( [ICONS.UNSUBSCRIBE]: buildIcon(
<path d="M 12,5.67 10.94,4.61 C 5.7533356,-0.57666427 -2.0266644,7.2033357 3.16,12.39 l 1.06,1.06 7.78,7.78 7.78,-7.78 1.06,-1.06 c 2.149101,-2.148092 2.149101,-5.6319078 0,-7.78 -2.148092,-2.1491008 -5.631908,-2.1491008 -7.78,0 L 9.4481298,8.2303201 15.320603,9.2419066 11.772427,13.723825" /> <path d="M 12,5.67 10.94,4.61 C 5.7533356,-0.57666427 -2.0266644,7.2033357 3.16,12.39 l 1.06,1.06 7.78,7.78 7.78,-7.78 1.06,-1.06 c 2.149101,-2.148092 2.149101,-5.6319078 0,-7.78 -2.148092,-2.1491008 -5.631908,-2.1491008 -7.78,0 L 9.4481298,8.2303201 15.320603,9.2419066 11.772427,13.723825" />
), ),
[ICONS.LBRY]: buildIcon(
<Fragment>
<path
transform="scale(0.15)"
d="M296.05, 85.9l0, 14.1l-138.8, 85.3l-104.6, -51.3l0.2, -7.9l104, 51.2l132.2, -81.2l0, -5.8l-124.8, -60.2l-139.2, 86.1l0, 38.5l131.8, 65.2l137.6, -84.4l3.9, 6l-141.1, 86.4l-139.2, -68.8l0, -46.8l145.8, -90.2l132.2, 63.8Z"
/>
<path
transform="scale(0.15)"
d="M294.25, 150.9l2, -12.6l-12.2, -2.1l0.8, -4.9l17.1, 2.9l-2.8, 17.5l-4.9, -0.8Z"
/>
</Fragment>
),
}; };

View file

@ -46,7 +46,8 @@ class IconComponent extends React.PureComponent<Props> {
render() { render() {
const { icon, tooltip, iconColor, size } = this.props; const { icon, tooltip, iconColor, size } = this.props;
const Icon = customIcons[this.props.icon] || FeatherIcons[this.props.icon]; const Icon = customIcons[this.props.icon] || FeatherIcons[this.props.icon];
console.log('icon', icon);
console.log('Icon', Icon);
if (!Icon) { if (!Icon) {
return null; return null;
} }

View file

@ -45,7 +45,7 @@ export default class ErrorBoundary extends React.Component<Props, State> {
button="link" button="link"
className="load-screen__button" className="load-screen__button"
label={__('refreshing the app')} label={__('refreshing the app')}
onClick={() => window.location.reload()} onClick={() => (window.location.href = '/')}
/>{' '} />{' '}
{__('to fix it')}. {__('to fix it')}.
</p> </p>

View file

@ -1,11 +1,9 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { doNavigate } from 'redux/actions/navigation';
import ExternalLink from './view'; import ExternalLink from './view';
const select = () => ({}); const select = () => ({});
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
}); });

View file

@ -4,6 +4,7 @@ import * as ICONS from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import { isURIValid } from 'lbry-redux'; import { isURIValid } from 'lbry-redux';
import Button from 'component/button'; import Button from 'component/button';
import { navigate } from '@reach/router';
type Props = { type Props = {
href: string, href: string,
@ -45,14 +46,7 @@ class ExternalLink extends React.PureComponent<Props> {
// Return local link if protocol is lbry uri // Return local link if protocol is lbry uri
if (protocol && protocol[0] === 'lbry:' && isURIValid(href)) { if (protocol && protocol[0] === 'lbry:' && isURIValid(href)) {
element = ( element = <Button button="link" title={title || href} label={children} navigate={href} />;
<Button
button="link"
title={title || href}
label={children}
onClick={() => navigate('/show', { uri: href })}
/>
);
} }
return element; return element;

View file

@ -9,7 +9,6 @@ import {
makeSelectClaimIsPending, makeSelectClaimIsPending,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc'; import { selectRewardContentClaimIds } from 'lbryinc';
import { doNavigate } from 'redux/actions/navigation';
import { makeSelectContentPositionForUri } from 'redux/selectors/content'; import { makeSelectContentPositionForUri } from 'redux/selectors/content';
import { selectShowNsfw } from 'redux/selectors/settings'; import { selectShowNsfw } from 'redux/selectors/settings';
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions'; import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
@ -31,7 +30,6 @@ const select = (state, props) => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)), clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
}); });

View file

@ -11,13 +11,14 @@ import classnames from 'classnames';
import FilePrice from 'component/filePrice'; import FilePrice from 'component/filePrice';
import { openCopyLinkMenu } from 'util/context-menu'; import { openCopyLinkMenu } from 'util/context-menu';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import { navigate } from '@reach/router';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
uri: string, uri: string,
claim: ?Claim, claim: ?Claim,
fileInfo: ?{}, fileInfo: ?{},
metadata: ?Metadata, metadata: ?Metadata,
navigate: (string, ?{}) => void,
rewardedContentClaimIds: Array<string>, rewardedContentClaimIds: Array<string>,
obscureNsfw: boolean, obscureNsfw: boolean,
claimIsMine: boolean, claimIsMine: boolean,
@ -61,7 +62,6 @@ class FileCard extends React.PureComponent<Props> {
claim, claim,
fileInfo, fileInfo,
metadata, metadata,
navigate,
rewardedContentClaimIds, rewardedContentClaimIds,
obscureNsfw, obscureNsfw,
claimIsMine, claimIsMine,
@ -108,11 +108,16 @@ class FileCard extends React.PureComponent<Props> {
} }
}; };
const onClick = e => {
e.stopPropagation();
navigate(formatLbryUriForWeb(uri));
};
return ( return (
<li <li
tabIndex="0" tabIndex="0"
role="button" role="button"
onClick={!pending ? () => navigate('/show', { uri }) : () => {}} onClick={!pending && claim ? onClick : () => {}}
className={classnames('media-card', { className={classnames('media-card', {
'card--link': !pending, 'card--link': !pending,
'media--pending': pending, 'media--pending': pending,

View file

@ -21,7 +21,6 @@ class FileListSearch extends React.PureComponent<Props> {
<React.Fragment> <React.Fragment>
<div className="search__results"> <div className="search__results">
<section className="search__results-section"> <section className="search__results-section">
<div className="search__results-title">{__('Search Results')}</div>
<HiddenNsfwClaims uris={uris} /> <HiddenNsfwClaims uris={uris} />
{!isSearching && uris && uris.length ? ( {!isSearching && uris && uris.length ? (
uris.map(uri => uris.map(uri =>

View file

@ -9,7 +9,6 @@ import {
} from 'lbry-redux'; } from 'lbry-redux';
import { selectRewardContentClaimIds } from 'lbryinc'; import { selectRewardContentClaimIds } from 'lbryinc';
import { selectShowNsfw } from 'redux/selectors/settings'; import { selectShowNsfw } from 'redux/selectors/settings';
import { doNavigate } from 'redux/actions/navigation';
import { doClearPublish, doUpdatePublishForm } from 'redux/actions/publish'; import { doClearPublish, doUpdatePublishForm } from 'redux/actions/publish';
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions'; import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
import FileTile from './view'; import FileTile from './view';
@ -28,7 +27,6 @@ const select = (state, props) => ({
const perform = dispatch => ({ const perform = dispatch => ({
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
navigate: (path, params) => dispatch(doNavigate(path, params)),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
updatePublishForm: value => dispatch(doUpdatePublishForm(value)), updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
}); });

View file

@ -12,6 +12,8 @@ import FilePrice from 'component/filePrice';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import { navigate } from '@reach/router';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
obscureNsfw: boolean, obscureNsfw: boolean,
@ -23,7 +25,6 @@ type Props = {
claim: ?Claim, claim: ?Claim,
metadata: ?Metadata, metadata: ?Metadata,
resolveUri: string => void, resolveUri: string => void,
navigate: (string, ?{}) => void,
clearPublish: () => void, clearPublish: () => void,
updatePublishForm: ({}) => void, updatePublishForm: ({}) => void,
hideNoResult: boolean, // don't show the tile if there is no claim at this uri hideNoResult: boolean, // don't show the tile if there is no claim at this uri
@ -83,7 +84,6 @@ class FileTile extends React.PureComponent<Props> {
claim, claim,
metadata, metadata,
isResolvingUri, isResolvingUri,
navigate,
obscureNsfw, obscureNsfw,
claimIsMine, claimIsMine,
clearPublish, clearPublish,
@ -115,7 +115,7 @@ class FileTile extends React.PureComponent<Props> {
return displayHiddenMessage ? ( return displayHiddenMessage ? (
<span className="help"> <span className="help">
{__('This file is hidden because it is marked NSFW. Update your')}{' '} {__('This file is hidden because it is marked NSFW. Update your')}{' '}
<Button button="link" navigate="/settings" label={__('content viewing preferences')} />{' '} <Button button="link" navigate="/$/settings" label={__('content viewing preferences')} />{' '}
{__('to see it')}. {__('to see it')}.
</span> </span>
) : null; ) : null;
@ -136,7 +136,7 @@ class FileTile extends React.PureComponent<Props> {
const wrapperProps = name const wrapperProps = name
? { ? {
onClick: () => navigate('/show', { uri }), onClick: () => navigate(formatLbryUriForWeb(uri)),
role: 'button', role: 'button',
} }
: {}; : {};

View file

@ -3,7 +3,6 @@ import * as settings from 'constants/settings';
import { doChangeVolume } from 'redux/actions/app'; import { doChangeVolume } from 'redux/actions/app';
import { selectVolume } from 'redux/selectors/app'; import { selectVolume } from 'redux/selectors/app';
import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content'; import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content';
import { doNavigate } from 'redux/actions/navigation';
import { doClaimEligiblePurchaseRewards, makeSelectCostInfoForUri } from 'lbryinc'; import { doClaimEligiblePurchaseRewards, makeSelectCostInfoForUri } from 'lbryinc';
import { import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
@ -45,7 +44,6 @@ const perform = dispatch => ({
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()), claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
savePosition: (claimId, outpoint, position) => savePosition: (claimId, outpoint, position) =>
dispatch(savePosition(claimId, outpoint, position)), dispatch(savePosition(claimId, outpoint, position)),
navigate: (path, params) => dispatch(doNavigate(path, params)),
}); });
export default connect( export default connect(

View file

@ -1,7 +1,6 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance, selectIsBackDisabled, selectIsForwardDisabled } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
import { formatCredits } from 'util/format-credits'; import { formatCredits } from 'util/format-credits';
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app'; import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
import { doDownloadUpgradeRequested } from 'redux/actions/app'; import { doDownloadUpgradeRequested } from 'redux/actions/app';
import Header from './view'; import Header from './view';
@ -11,15 +10,10 @@ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
isUpgradeAvailable: selectIsUpgradeAvailable(state), isUpgradeAvailable: selectIsUpgradeAvailable(state),
roundedBalance: formatCredits(selectBalance(state) || 0, 2), roundedBalance: formatCredits(selectBalance(state) || 0, 2),
isBackDisabled: selectIsBackDisabled(state),
isForwardDisabled: selectIsForwardDisabled(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()), downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()),
navigate: path => dispatch(doNavigate(path)),
back: () => dispatch(doHistoryBack()),
forward: () => dispatch(doHistoryForward()),
}); });
export default connect( export default connect(

View file

@ -15,7 +15,6 @@ type Props = {
back: () => void, back: () => void,
forward: () => void, forward: () => void,
downloadUpgradeRequested: any => void, downloadUpgradeRequested: any => void,
navigate: any => void,
}; };
const Header = (props: Props) => { const Header = (props: Props) => {
@ -24,7 +23,6 @@ const Header = (props: Props) => {
balance, balance,
downloadUpgradeRequested, downloadUpgradeRequested,
isUpgradeAvailable, isUpgradeAvailable,
navigate,
roundedBalance, roundedBalance,
back, back,
isBackDisabled, isBackDisabled,
@ -38,6 +36,7 @@ const Header = (props: Props) => {
return ( return (
<header className="header"> <header className="header">
<div className="header__navigation"> <div className="header__navigation">
{/* @if TARGET='app' */}
<Button <Button
className="header__navigation-item header__navigation-item--wallet" className="header__navigation-item header__navigation-item--wallet"
description={__('Your wallet')} description={__('Your wallet')}
@ -48,25 +47,23 @@ const Header = (props: Props) => {
<LbcSymbol /> <LbcSymbol />
</React.Fragment> </React.Fragment>
} }
onClick={() => navigate('/wallet')} navigate="/$/wallet"
/> />
<Button <Button
className="header__navigation-item header__navigation-item--back" className="header__navigation-item header__navigation-item--back"
description={__('Navigate back')} description={__('Navigate back')}
disabled={isBackDisabled} onClick={() => window.history.back()}
icon={ICONS.ARROW_LEFT} icon={ICONS.ARROW_LEFT}
iconSize={15} iconSize={15}
onClick={back}
/> />
<Button <Button
className="header__navigation-item header__navigation-item--forward" className="header__navigation-item header__navigation-item--forward"
description={__('Navigate forward')} description={__('Navigate forward')}
disabled={isForwardDisabled} onClick={() => window.history.forward()}
icon={ICONS.ARROW_RIGHT} icon={ICONS.ARROW_RIGHT}
iconSize={15} iconSize={15}
onClick={forward}
/> />
<Button <Button
@ -74,8 +71,17 @@ const Header = (props: Props) => {
description={__('Home')} description={__('Home')}
icon={ICONS.HOME} icon={ICONS.HOME}
iconSize={15} iconSize={15}
onClick={() => navigate('/discover')} navigate="/"
/> />
{/* @endif */}
{/* @if TARGET='web' */}
<Button
className="header__navigation-item header__navigation-item--lbry"
label={__('LBRY')}
iconRight={ICONS.LBRY}
navigate="/"
/>
{/* @endif */}
</div> </div>
<WunderBar /> <WunderBar />
@ -94,7 +100,7 @@ const Header = (props: Props) => {
icon={ICONS.UPLOAD} icon={ICONS.UPLOAD}
iconSize={24} iconSize={24}
label={isUpgradeAvailable ? '' : __('Publish')} label={isUpgradeAvailable ? '' : __('Publish')}
onClick={() => navigate('/publish')} navigate="/$/publish"
/> />
{/* @if TARGET='app' */} {/* @if TARGET='app' */}

View file

@ -16,7 +16,7 @@ export default (props: Props) => {
<div className={className || 'help'}> <div className={className || 'help'}>
{numberOfNsfwClaims} {numberOfNsfwClaims > 1 ? __('files') : __('file')}{' '} {numberOfNsfwClaims} {numberOfNsfwClaims > 1 ? __('files') : __('file')}{' '}
{__('hidden due to your')}{' '} {__('hidden due to your')}{' '}
<Button button="link" navigate="/settings" label={__('content viewing preferences')} />. <Button button="link" navigate="/$/settings" label={__('content viewing preferences')} />.
</div> </div>
) )
); );

View file

@ -95,7 +95,7 @@ class InviteNew extends React.PureComponent<Props> {
/> />
<p className="help"> <p className="help">
{__('Earn')} <Button button="link" navigate="/rewards" label={__('rewards')} />{' '} {__('Earn')} <Button button="link" navigate="/$/rewards" label={__('rewards')} />{' '}
{__('for inviting your friends.')} {__('Read our')}{' '} {__('for inviting your friends.')} {__('Read our')}{' '}
<Button button="link" label={__('FAQ')} href="https://lbry.com/faq/referrals" />{' '} <Button button="link" label={__('FAQ')} href="https://lbry.com/faq/referrals" />{' '}
{__('to learn more about referrals')}. {__('to learn more about referrals')}.

View file

@ -1,12 +0,0 @@
import { connect } from 'react-redux';
import { doNavigate } from 'redux/actions/navigation';
import NsfwOverlay from './view';
const perform = dispatch => ({
navigateSettings: () => dispatch(doNavigate('/settings')),
});
export default connect(
null,
perform
)(NsfwOverlay);

View file

@ -1,13 +0,0 @@
import React from 'react';
import Button from 'component/button';
const NsfwOverlay = () => (
<div className="card-overlay">
<p>
{__('This content is Not Safe For Work. To view adult content, please change your')}{' '}
<Button button="link" navigate="/settings" label={__('settings')} />.
</p>
</div>
);
export default NsfwOverlay;

View file

@ -1,33 +1,2 @@
import { connect } from 'react-redux';
import {
selectBalance,
selectPageTitle,
selectIsBackDisabled,
selectIsForwardDisabled,
} from 'lbry-redux';
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
import { doDownloadUpgrade } from 'redux/actions/app';
import { selectIsUpgradeAvailable, selectNavLinks } from 'redux/selectors/app';
import { formatCredits } from 'util/format-credits';
import Page from './view'; import Page from './view';
export default Page;
const select = state => ({
pageTitle: selectPageTitle(state),
navLinks: selectNavLinks(state),
isBackDisabled: selectIsBackDisabled(state),
isForwardDisabled: selectIsForwardDisabled(state),
isUpgradeAvailable: selectIsUpgradeAvailable(state),
balance: formatCredits(selectBalance(state) || 0, 2),
});
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
back: () => dispatch(doHistoryBack()),
forward: () => dispatch(doHistoryForward()),
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
});
export default connect(
select,
perform
)(Page);

View file

@ -91,11 +91,6 @@ class Page extends React.PureComponent<Props, State> {
'main--extra-padding': extraPadding, 'main--extra-padding': extraPadding,
})} })}
> >
{pageTitle && (
<div className="page__header">
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
</div>
)}
{!loading && children} {!loading && children}
{showLoader && ( {showLoader && (
<div className="page__empty"> <div className="page__empty">

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { makeSelectRewardByType, makeSelectIsRewardClaimPending, doClaimRewardType } from 'lbryinc'; import { makeSelectRewardByType, makeSelectIsRewardClaimPending, doClaimRewardType } from 'lbryinc';
import { doNavigate } from 'redux/actions/navigation';
import RewardLink from './view'; import RewardLink from './view';
const select = (state, props) => ({ const select = (state, props) => ({
@ -10,7 +9,6 @@ const select = (state, props) => ({
const perform = dispatch => ({ const perform = dispatch => ({
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, { notifyError: true })), claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, { notifyError: true })),
navigate: path => dispatch(doNavigate(path)),
}); });
export default connect( export default connect(

View file

@ -51,7 +51,7 @@ class RewardSummary extends React.Component<Props> {
<div className="card__actions"> <div className="card__actions">
<Button <Button
button="primary" button="primary"
navigate="/rewards" navigate="/$/rewards"
label={hasRewards ? __('Claim Rewards') : __('View Rewards')} label={hasRewards ? __('Claim Rewards') : __('View Rewards')}
/> />
</div> </div>

View file

@ -36,7 +36,7 @@ const RewardTile = (props: Props) => {
<Button button="primary" onClick={openRewardCodeModal} label={__('Enter Code')} /> <Button button="primary" onClick={openRewardCodeModal} label={__('Enter Code')} />
)} )}
{reward.reward_type === rewards.TYPE_REFERRAL && ( {reward.reward_type === rewards.TYPE_REFERRAL && (
<Button button="primary" navigate="/invite" label={__('Go To Invites')} /> <Button button="primary" navigate="/$/invite" label={__('Go To Invites')} />
)} )}
{reward.reward_type !== rewards.TYPE_REFERRAL && {reward.reward_type !== rewards.TYPE_REFERRAL &&
(claimed ? ( (claimed ? (

View file

@ -1,14 +1,2 @@
import { connect } from 'react-redux';
import { selectCurrentPage, selectCurrentParams, doToast } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import Router from './view'; import Router from './view';
export default Router;
const select = state => ({
params: selectCurrentParams(state),
currentPage: selectCurrentPage(state),
});
export default connect(
select,
{ doOpenModal, doToast }
)(Router);

View file

@ -1,10 +1,10 @@
import * as PAGES from 'constants/pages';
import React from 'react'; import React from 'react';
import { Router } from '@reach/router';
import SettingsPage from 'page/settings'; import SettingsPage from 'page/settings';
import HelpPage from 'page/help'; import HelpPage from 'page/help';
import ReportPage from 'page/report'; import ReportPage from 'page/report';
import WalletPage from 'page/wallet'; import WalletPage from 'page/wallet';
import GetCreditsPage from 'page/getCredits';
import SendReceivePage from 'page/sendCredits';
import ShowPage from 'page/show'; import ShowPage from 'page/show';
import PublishPage from 'page/publish'; import PublishPage from 'page/publish';
import DiscoverPage from 'page/discover'; import DiscoverPage from 'page/discover';
@ -12,7 +12,6 @@ import RewardsPage from 'page/rewards';
import FileListDownloaded from 'page/fileListDownloaded'; import FileListDownloaded from 'page/fileListDownloaded';
import FileListPublished from 'page/fileListPublished'; import FileListPublished from 'page/fileListPublished';
import TransactionHistoryPage from 'page/transactionHistory'; import TransactionHistoryPage from 'page/transactionHistory';
import ChannelPage from 'page/channel';
import AuthPage from 'page/auth'; import AuthPage from 'page/auth';
import InvitePage from 'page/invite'; import InvitePage from 'page/invite';
import BackupPage from 'page/backup'; import BackupPage from 'page/backup';
@ -20,41 +19,28 @@ import SubscriptionsPage from 'page/subscriptions';
import SearchPage from 'page/search'; import SearchPage from 'page/search';
import UserHistoryPage from 'page/userHistory'; import UserHistoryPage from 'page/userHistory';
const route = (props, page, routesMap) => { export default function AppRouter(props) {
const component = routesMap[page]; return (
if (!component) { <Router>
props.doToast({ <DiscoverPage path="/" />
message: __('Invalid page requested'), <ShowPage path="/:claimName/:claimId" />
}); <ShowPage path="/:claimName" />
<AuthPage path={`$/${PAGES.AUTH}`} />
<BackupPage path={`$/${PAGES.BACKUP}`} />
<InvitePage path={`$/${PAGES.INVITE}`} />
<FileListDownloaded path={`$/${PAGES.DOWNLOADED}`} />
<FileListPublished path={`$/${PAGES.PUBLISHED}`} />
<HelpPage path={`$/${PAGES.HELP}`} />
<PublishPage path={`$/${PAGES.PUBLISH}`} />
<ReportPage path={`$/${PAGES.REPORT}`} />
<RewardsPage path={`$/${PAGES.REWARDS}`} />
<SearchPage path={`$/${PAGES.SEARCH}`} />
<SettingsPage path={`$/${PAGES.SETTINGS}`} />
<SubscriptionsPage path={`$/${PAGES.SUBSCRIPTIONS}`} />
<TransactionHistoryPage path={`$/${PAGES.HISTORY}`} />
<UserHistoryPage path={`$/${PAGES.USER_HISTORY}`} />
<WalletPage path={`$/${PAGES.WALLET}`} />
</Router>
);
} }
return component || routesMap.discover;
};
const Router = props => {
const { currentPage, params } = props;
return route(props, currentPage, {
auth: <AuthPage params={params} />,
backup: <BackupPage params={params} />,
channel: <ChannelPage params={params} />,
discover: <DiscoverPage params={params} />,
downloaded: <FileListDownloaded params={params} />,
help: <HelpPage params={params} />,
history: <TransactionHistoryPage params={params} />,
invite: <InvitePage params={params} />,
publish: <PublishPage params={params} />,
published: <FileListPublished params={params} />,
getcredits: <GetCreditsPage params={params} />,
report: <ReportPage params={params} />,
rewards: <RewardsPage params={params} />,
send: <SendReceivePage params={params} />,
settings: <SettingsPage params={params} />,
show: <ShowPage {...params} />,
wallet: <WalletPage params={params} />,
subscriptions: <SubscriptionsPage params={params} />,
search: <SearchPage {...params} />,
user_history: <UserHistoryPage {...params} />,
});
};
export default Router;

View file

@ -8,7 +8,7 @@ import Button from 'component/button';
const ExpandableOptions = posed.div({ const ExpandableOptions = posed.div({
hide: { height: 0, opacity: 0 }, hide: { height: 0, opacity: 0 },
show: { height: 280, opacity: 1 }, show: { height: 300, opacity: 1 },
}); });
type Props = { type Props = {
@ -34,11 +34,11 @@ const SearchOptions = (props: Props) => {
const resultCount = options[SEARCH_OPTIONS.RESULT_COUNT]; const resultCount = options[SEARCH_OPTIONS.RESULT_COUNT];
return ( return (
<div className="card card--section search__options-wrapper"> <div className="search__options-wrapper">
<div className="card--space-between"> <div className="card--space-between">
<Button <Button
button="alt" button="alt"
label={__('ADVANCED SEARCH')} label={__('FILTER')}
iconRight={expanded ? ICONS.UP : ICONS.DOWN} iconRight={expanded ? ICONS.UP : ICONS.DOWN}
onClick={toggleSearchExpanded} onClick={toggleSearchExpanded}
/> />

View file

@ -1,10 +1,8 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectNavLinks } from 'redux/selectors/app';
import { selectUnreadAmount } from 'redux/selectors/subscriptions'; import { selectUnreadAmount } from 'redux/selectors/subscriptions';
import SideBar from './view'; import SideBar from './view';
const select = state => ({ const select = state => ({
navLinks: selectNavLinks(state),
unreadSubscriptionTotal: selectUnreadAmount(state), unreadSubscriptionTotal: selectUnreadAmount(state),
}); });

View file

@ -1,4 +1,6 @@
// @flow // @flow
import * as PAGES from 'constants/pages';
import * as ICONS from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import classnames from 'classnames'; import classnames from 'classnames';
@ -14,86 +16,96 @@ type SideBarLink = {
}; };
type Props = { type Props = {
navLinks: {
primary: Array<SideBarLink>,
secondary: Array<SideBarLink>,
},
unreadSubscriptionTotal: number, unreadSubscriptionTotal: number,
}; };
class SideBar extends React.PureComponent<Props> { class SideBar extends React.PureComponent<Props> {
renderNavLink(navLink: SideBarLink) {
const { label, path, active, subLinks = [], icon, guide } = navLink;
const inner = (
<li
className={classnames('navigation__link', {
'navigation__link--active': active,
'navigation__link--guide': guide,
})}
key={label}
>
<Button icon={icon} label={label} navigate={path} />
{
// The sublinks should be animated on open close
// Removing it because the current implementation with CSSTransitionGroup
// was really slow and looked pretty bad. Possible fix is upgrading to v2
// Not sure if that has better performance
}
{!!subLinks.length && active && (
<ul key="0" className="navigation__link-items">
{subLinks.map(({ active: subLinkActive, label: subLabel, path: subPath }) => (
<li
className={classnames('navigation__link-item', {
'navigation__link-item--active': subLinkActive,
})}
key={subPath}
>
{subPath ? <Button label={subLabel} navigate={subPath} /> : <span>{subLabel}</span>}
</li>
))}
</ul>
)}
</li>
);
return guide ? (
<Tooltip key={guide} alwaysVisible direction="right" body={guide}>
{inner}
</Tooltip>
) : (
inner
);
}
render() { render() {
const { navLinks, unreadSubscriptionTotal } = this.props; const { unreadSubscriptionTotal } = this.props;
const buildLink = (path, label, icon) => ({
navigate: path ? `$/${path}` : '/',
label,
icon,
});
const renderLink = (linkProps, index) => (
<li key={index}>
<Button
{...linkProps}
className="navigation__link"
activeClass="navigation__link--active"
/>
</li>
);
return ( return (
<nav className="navigation"> <nav className="navigation">
<div className="navigation__links"> <ul className="navigation__links">
{navLinks.primary.map(({ label, path, active, icon }) => ( {[
<Button {
icon={icon} ...buildLink(null, __('Home'), ICONS.HOME),
className={classnames('navigation__link', { },
'navigation__link--active': active, {
})} ...buildLink(
key={path} PAGES.SUBSCRIPTIONS,
label={ `${__('Subscriptions')} ${
path === '/subscriptions' && unreadSubscriptionTotal unreadSubscriptionTotal > 0 ? '(' + unreadSubscriptionTotal + ')' : ''
? `${label} (${unreadSubscriptionTotal})` }`,
: label ICONS.SUBSCRIPTION
} ),
navigate={path} },
/> ].map(renderLink)}
))} </ul>
<div className="navigation__link navigation__link--title">My LBRY</div>
<div className="navigation__links">
<ul> <ul>
<li className="navigation__link navigation__link--title">Account</li> {[
{navLinks.secondary.map(this.renderNavLink)} {
...buildLink(PAGES.DOWNLOADED, 'Downloads', ICONS.LOCAL),
},
{
...buildLink(PAGES.PUBLISHED, 'Publishes', ICONS.PUBLISHED),
},
{
...buildLink(PAGES.USER_HISTORY, 'History', ICONS.HISTORY),
},
{
...buildLink(PAGES.INVITE, 'Invite', ICONS.INVITE),
},
{
...buildLink(PAGES.REWARDS, 'Rewards', ICONS.FEATURED),
},
].map(renderLink)}
</ul> </ul>
</div> </div>
<div className="navigation__link navigation__link--title">Wallet</div>
<ul className="navigation__links">
{[
{
...buildLink(PAGES.WALLET, 'Overview', ICONS.WALLET),
},
{
...buildLink(PAGES.HISTORY, 'Transactions', ICONS.TRANSACTIONS),
},
{
...buildLink(PAGES.BACKUP, 'Backup', ICONS.BACKUP),
},
].map(renderLink)}
</ul>
<ul className="navigation__links navigation__links--bottom">
{[
{
...buildLink(PAGES.SETTINGS, 'Settings', ICONS.SETTINGS),
},
{
...buildLink(PAGES.HELP, 'Help', ICONS.HELP),
},
].map(renderLink)}
</ul>
</nav> </nav>
); );
} }

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectClaimedRewardsByTransactionId } from 'lbryinc'; import { selectClaimedRewardsByTransactionId } from 'lbryinc';
import { doNavigate } from 'redux/actions/navigation';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { import {
selectAllMyClaimsByOutpoint, selectAllMyClaimsByOutpoint,
@ -16,7 +15,6 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
setTransactionFilter: filterSetting => dispatch(doSetTransactionListFilter(filterSetting)), setTransactionFilter: filterSetting => dispatch(doSetTransactionListFilter(filterSetting)),
}); });

View file

@ -1,5 +1,6 @@
// @flow // @flow
import type { Transaction } from 'types/transaction'; import type { Transaction } from 'types/transaction';
import * as TXN_TYPES from 'constants/transaction_types';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React from 'react';
import ButtonTransaction from 'component/common/transaction-link'; import ButtonTransaction from 'component/common/transaction-link';
@ -7,7 +8,7 @@ import CreditAmount from 'component/common/credit-amount';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Button from 'component/button'; import Button from 'component/button';
import { buildURI } from 'lbry-redux'; import { buildURI } from 'lbry-redux';
import * as txnTypes from 'constants/transaction_types'; import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
transaction: Transaction, transaction: Transaction,
@ -26,7 +27,7 @@ class TransactionListItem extends React.PureComponent<Props> {
} }
getLink(type: string) { getLink(type: string) {
if (type === txnTypes.TIP) { if (type === TXN_TYPES.TIP) {
return <Button icon={ICONS.UNLOCK} onClick={this.abandonClaim} title={__('Unlock Tip')} />; return <Button icon={ICONS.UNLOCK} onClick={this.abandonClaim} title={__('Unlock Tip')} />;
} }
return <Button icon={ICONS.DELETE} onClick={this.abandonClaim} title={__('Abandon Claim')} />; return <Button icon={ICONS.DELETE} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
@ -68,12 +69,7 @@ class TransactionListItem extends React.PureComponent<Props> {
<td className="table__item--actionable"> <td className="table__item--actionable">
{reward && <span>{reward.reward_title}</span>} {reward && <span>{reward.reward_title}</span>}
{name && claimId && ( {name && claimId && (
<Button <Button constrict button="link" navigate={buildURI({ claimName: name, claimId })}>
constrict
button="link"
navigate="/show"
navigateParams={{ uri: buildURI({ claimName: name, claimId }) }}
>
{name} {name}
</Button> </Button>
)} )}

View file

@ -105,12 +105,10 @@ class TransactionList extends React.PureComponent<Props> {
</div> </div>
)} )}
</header> </header>
{!transactionList.length && ( {!transactionList.length && <p>{emptyMessage || __('No transactions to list.')}</p>}
<p className="card__content">{emptyMessage || __('No transactions to list.')}</p>
)}
{!!transactionList.length && ( {!!transactionList.length && (
<div className="card__content"> <React.Fragment>
<table className="table table--transactions"> <table className="table table--transactions">
<thead> <thead>
<tr> <tr>
@ -133,7 +131,7 @@ class TransactionList extends React.PureComponent<Props> {
))} ))}
</tbody> </tbody>
</table> </table>
</div> </React.Fragment>
)} )}
</React.Fragment> </React.Fragment>
); );

View file

@ -35,7 +35,7 @@ class TransactionListRecent extends React.PureComponent<Props> {
<p className="card__subtitle"> <p className="card__subtitle">
{__('To view all of your transactions, navigate to the')}{' '} {__('To view all of your transactions, navigate to the')}{' '}
<Button button="link" navigate="/history" label={__('transactions page')} />. <Button button="link" navigate="/$/history" label={__('transactions page')} />.
</p> </p>
</header> </header>
@ -53,15 +53,15 @@ class TransactionListRecent extends React.PureComponent<Props> {
transactions={transactions} transactions={transactions}
emptyMessage={__("Looks like you don't have any recent transactions.")} emptyMessage={__("Looks like you don't have any recent transactions.")}
/> />
</div>
<div className="card__actions"> <div className="card__actions">
<Button <Button
button="primary" button="primary"
navigate="/history" navigate="/$/history"
label={__('Full History')} label={__('Full History')}
icon={icons.HISTORY} icon={icons.HISTORY}
/> />
</div> </div>
</div>
</Fragment> </Fragment>
)} )}
</section> </section>

View file

@ -57,12 +57,7 @@ class UriIndicator extends React.PureComponent<Props> {
} }
return ( return (
<Button <Button noPadding className="button--uri-indicator" navigate={channelLink}>
noPadding
className="button--uri-indicator"
navigate="/show"
navigateParams={{ uri: channelLink, page: 1 }}
>
{inner} {inner}
</Button> </Button>
); );

View file

@ -5,7 +5,6 @@ import {
doUserCheckEmailVerified, doUserCheckEmailVerified,
selectUser, selectUser,
} from 'lbryinc'; } from 'lbryinc';
import { doNavigate } from 'redux/actions/navigation';
import UserEmailVerify from './view'; import UserEmailVerify from './view';
const select = state => ({ const select = state => ({
@ -16,7 +15,6 @@ const select = state => ({
const perform = dispatch => ({ const perform = dispatch => ({
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)), resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
checkEmailVerified: () => dispatch(doUserCheckEmailVerified()), checkEmailVerified: () => dispatch(doUserCheckEmailVerified()),
navigate: path => dispatch(doNavigate(path)),
}); });
export default connect( export default connect(

View file

@ -1,22 +1,22 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content'; import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content';
import { doNavigate } from 'redux/actions/navigation';
import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux'; import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux';
import { doClearContentHistoryUri } from 'redux/actions/content'; import { doClearContentHistoryUri } from 'redux/actions/content';
import UserHistory from './view'; import UserHistory from './view';
const select = state => { const select = (state, props) => {
const paramPage = Number(makeSelectCurrentParam('page')(state) || 0); const { search } = props.location;
const urlParams = new URLSearchParams(search);
const page = Number(urlParams.get('page')) || 0;
return { return {
page,
pageCount: selectHistoryPageCount(state), pageCount: selectHistoryPageCount(state),
page: paramPage, history: makeSelectHistoryForPage(page)(state),
params: selectCurrentParams(state),
history: makeSelectHistoryForPage(paramPage)(state),
}; };
}; };
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)), clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
}); });

View file

@ -4,6 +4,7 @@ import Button from 'component/button';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
import ReactPaginate from 'react-paginate'; import ReactPaginate from 'react-paginate';
import UserHistoryItem from 'component/userHistoryItem'; import UserHistoryItem from 'component/userHistoryItem';
import { navigate } from '@reach/router';
type HistoryItem = { type HistoryItem = {
uri: string, uri: string,
@ -14,7 +15,6 @@ type Props = {
history: Array<HistoryItem>, history: Array<HistoryItem>,
page: number, page: number,
pageCount: number, pageCount: number,
navigate: (string, {}) => void,
clearHistoryUri: string => void, clearHistoryUri: string => void,
params: { page: number }, params: { page: number },
}; };
@ -52,9 +52,8 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
} }
changePage(pageNumber: number) { changePage(pageNumber: number) {
const { params } = this.props; console.log('new', pageNumber);
const newParams = { ...params, page: pageNumber }; navigate(`/$/user_history?page=${pageNumber}`);
this.props.navigate('/user_history', newParams);
} }
paginate(e: SyntheticKeyboardEvent<*>) { paginate(e: SyntheticKeyboardEvent<*>) {
@ -94,7 +93,8 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
} }
render() { render() {
const { history, page, pageCount } = this.props; const { history = [], page, pageCount } = this.props;
console.log('this.props', this.props);
const { itemsSelected } = this.state; const { itemsSelected } = this.state;
const allSelected = Object.keys(itemsSelected).length === history.length; const allSelected = Object.keys(itemsSelected).length === history.length;
const selectHandler = allSelected ? this.unselectAll : this.selectAll; const selectHandler = allSelected ? this.unselectAll : this.selectAll;
@ -148,6 +148,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
onPageChange={e => this.changePage(e.selected)} onPageChange={e => this.changePage(e.selected)}
forcePage={page} forcePage={page}
initialPage={page} initialPage={page}
disableInitialCallback
containerClassName="pagination" containerClassName="pagination"
/> />
</fieldset-section> </fieldset-section>
@ -175,7 +176,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
<div className="card__content"> <div className="card__content">
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<Button button="primary" navigate="/discover" label={__('Explore new content')} /> <Button button="primary" navigate="/" label={__('Explore new content')} />
</div> </div>
</div> </div>
</section> </section>

View file

@ -51,8 +51,7 @@ class UserHistoryItem extends React.PureComponent<Props> {
constrict constrict
button="link" button="link"
label={name ? `lbry://${name}` : `lbry://...`} label={name ? `lbry://${name}` : `lbry://...`}
navigate="/show" navigate={uri}
navigateParams={{ uri }}
/> />
</div> </div>
); );

View file

@ -1,7 +1,6 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { doNavigate } from 'redux/actions/navigation';
import { import {
doUserIdentityVerify, doUserIdentityVerify,
rewards, rewards,
@ -22,7 +21,6 @@ const select = state => {
}; };
const perform = dispatch => ({ const perform = dispatch => ({
navigate: uri => dispatch(doNavigate(uri)),
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)), verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
verifyPhone: () => dispatch(doOpenModal(MODALS.PHONE_COLLECTION)), verifyPhone: () => dispatch(doOpenModal(MODALS.PHONE_COLLECTION)),
}); });

View file

@ -8,7 +8,6 @@ import { Lbryio } from 'lbryinc';
type Props = { type Props = {
errorMessage: ?string, errorMessage: ?string,
isPending: boolean, isPending: boolean,
navigate: string => void,
verifyUserIdentity: string => void, verifyUserIdentity: string => void,
verifyPhone: () => void, verifyPhone: () => void,
}; };
@ -25,7 +24,7 @@ class UserVerify extends React.PureComponent<Props> {
} }
render() { render() {
const { errorMessage, isPending, navigate, verifyPhone } = this.props; const { errorMessage, isPending, verifyPhone } = this.props;
return ( return (
<React.Fragment> <React.Fragment>
<section className="card card--section"> <section className="card card--section">
@ -137,11 +136,7 @@ class UserVerify extends React.PureComponent<Props> {
<div className="card__content"> <div className="card__content">
<div className="card__actions"> <div className="card__actions">
<Button <Button navigate="/" button="primary" label={__('Skip Rewards')} />
onClick={() => navigate('/discover')}
button="primary"
label={__('Skip Rewards')}
/>
</div> </div>
</div> </div>
</section> </section>

View file

@ -2,7 +2,9 @@
import * as React from 'react'; import * as React from 'react';
import { stopContextMenu } from 'util/context-menu'; import { stopContextMenu } from 'util/context-menu';
import Button from 'component/button'; import Button from 'component/button';
// @if TARGET='app'
import { shell } from 'electron'; import { shell } from 'electron';
// @endif
type Props = { type Props = {
source: string, source: string,
@ -22,7 +24,12 @@ class PdfViewer extends React.PureComponent<Props> {
openFile() { openFile() {
const { source } = this.props; const { source } = this.props;
const path = `file://${source}`; const path = `file://${source}`;
// @if TARGET='app'
shell.openExternal(path); shell.openExternal(path);
// @endif
// @if TARGET='web'
console.error('provide stub for shell.openExternal');
// @endif
} }
render() { render() {

View file

@ -12,7 +12,7 @@ const WalletBalance = (props: Props) => {
return ( return (
<section <section
className="card card--section card--wallet-balance" className="card card--section card--wallet-balance"
style={{ backgroundImage: `url(${BalanceBackground})` }} style={{ backgroundImage: `url(/${BalanceBackground})` }}
> >
<header className="card__header"> <header className="card__header">
<h2 className="card__title">{__('Balance')}</h2> <h2 className="card__title">{__('Balance')}</h2>

View file

@ -1,44 +1,38 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { import {
selectSearchState as selectSearch,
selectWunderBarAddress,
selectSearchSuggestions,
doUpdateSearchQuery,
doFocusSearchInput, doFocusSearchInput,
doBlurSearchInput, doBlurSearchInput,
doUpdateSearchQuery,
doSearch, doSearch,
doToast, selectSearchValue,
selectSearchSuggestions,
selectSearchBarFocused,
parseURI,
} from 'lbry-redux'; } from 'lbry-redux';
import analytics from 'analytics'; import analytics from 'analytics';
import { doNavigate } from 'redux/actions/navigation';
import Wunderbar from './view'; import Wunderbar from './view';
import { navigate } from '@reach/router';
import { formatLbryUriForWeb } from 'util/uri';
const select = state => { 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), suggestions: selectSearchSuggestions(state),
}; searchQuery: selectSearchValue(state),
}; isFocused: selectSearchBarFocused(state),
});
const perform = dispatch => ({ const perform = dispatch => ({
onSearch: query => { onSearch: query => {
dispatch(doSearch(query)); navigate(`/$/search?q=${query}`);
dispatch(doNavigate(`/search`, { query }));
analytics.apiLogSearch(); 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)), updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
doFocus: () => dispatch(doFocusSearchInput()), doFocus: () => dispatch(doFocusSearchInput()),
doBlur: () => dispatch(doBlurSearchInput()), doBlur: () => dispatch(doBlurSearchInput()),
doShowSnackBar: props => dispatch(doToast(props)),
}); });
export default connect( export default connect(

View file

@ -1,19 +1,22 @@
// @flow // @flow
import * as PAGES from 'constants/pages';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React from 'react';
import classnames from 'classnames'; 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 Icon from 'component/common/icon';
import { parseQueryParams } from 'util/query-params'; import { parseQueryParams } from 'util/query-params';
import Autocomplete from './internal/autocomplete'; import Autocomplete from './internal/autocomplete';
import { Location, navigate } from '@reach/router';
const L_KEY_CODE = 76; const L_KEY_CODE = 76;
const ESC_KEY_CODE = 27; const ESC_KEY_CODE = 27;
type Props = { type Props = {
searchQuery: ?string,
updateSearchQuery: string => void, updateSearchQuery: string => void,
onSearch: string => void, onSearch: string => void,
onSubmit: (string, {}) => void, onSubmit: string => void,
wunderbarValue: ?string, wunderbarValue: ?string,
suggestions: Array<string>, suggestions: Array<string>,
doFocus: () => void, doFocus: () => void,
@ -22,10 +25,18 @@ type Props = {
doShowSnackBar: ({}) => void, doShowSnackBar: ({}) => void,
}; };
class WunderBar extends React.PureComponent<Props> { type State = {
query: ?string,
};
class WunderBar extends React.PureComponent<Props, State> {
constructor() { constructor() {
super(); super();
this.state = {
query: null,
};
(this: any).handleSubmit = this.handleSubmit.bind(this); (this: any).handleSubmit = this.handleSubmit.bind(this);
(this: any).handleChange = this.handleChange.bind(this); (this: any).handleChange = this.handleChange.bind(this);
(this: any).handleKeyDown = this.handleKeyDown.bind(this); (this: any).handleKeyDown = this.handleKeyDown.bind(this);
@ -61,6 +72,7 @@ class WunderBar extends React.PureComponent<Props> {
return; return;
} }
// @if TARGET='app'
const shouldFocus = const shouldFocus =
process.platform === 'darwin' process.platform === 'darwin'
? keyCode === L_KEY_CODE && metaKey ? keyCode === L_KEY_CODE && metaKey
@ -70,30 +82,20 @@ class WunderBar extends React.PureComponent<Props> {
this.input.focus(); this.input.focus();
doFocus(); doFocus();
} }
// @endif
} }
} }
handleChange(e: SyntheticInputEvent<*>) { handleChange(e: SyntheticInputEvent<*>) {
const { updateSearchQuery } = this.props;
const { value } = e.target; const { value } = e.target;
const { updateSearchQuery } = this.props;
updateSearchQuery(value); updateSearchQuery(value);
} }
handleSubmit(value: string, suggestion?: { value: string, type: string }) { handleSubmit(value: string, suggestion?: { value: string, type: string }) {
const { onSubmit, onSearch, doShowSnackBar } = this.props; const { onSubmit, onSearch, doShowSnackBar } = this.props;
const query = value.trim(); const query = value.trim();
const getParams = () => {
const parts = query.split('?');
let extraParams = {};
if (parts.length > 0) {
extraParams = parseQueryParams(parts.join(''));
}
return extraParams;
};
const showSnackError = () => { const showSnackError = () => {
doShowSnackBar({ doShowSnackBar({
message: __('Invalid LBRY URL entered. Only A-Z, a-z, 0-9, and "-" allowed.'), message: __('Invalid LBRY URL entered. Only A-Z, a-z, 0-9, and "-" allowed.'),
@ -105,23 +107,20 @@ class WunderBar extends React.PureComponent<Props> {
if (suggestion.type === 'search') { if (suggestion.type === 'search') {
onSearch(query); onSearch(query);
} else if (isURIValid(query)) { } else if (isURIValid(query)) {
const params = getParams();
const uri = normalizeURI(query); const uri = normalizeURI(query);
onSubmit(uri, params); onSubmit(uri);
} else { } else {
showSnackError(); showSnackError();
} }
return; return;
} }
// Currently no suggestion is highlighted. The user may have started // Currently no suggestion is highlighted. The user may have started
// typing, then lost focus and came back later on the same page // typing, then lost focus and came back later on the same page
try { try {
if (isURIValid(query)) { if (isURIValid(query)) {
const uri = normalizeURI(query); const uri = normalizeURI(query);
const params = getParams(); onSubmit(uri);
onSubmit(uri, params);
} else { } else {
showSnackError(); showSnackError();
} }
@ -133,7 +132,7 @@ class WunderBar extends React.PureComponent<Props> {
input: ?HTMLInputElement; input: ?HTMLInputElement;
render() { render() {
const { wunderbarValue, suggestions, doFocus, doBlur } = this.props; const { suggestions, doFocus, doBlur, searchQuery } = this.props;
return ( return (
<div className="wunderbar"> <div className="wunderbar">
@ -141,7 +140,7 @@ class WunderBar extends React.PureComponent<Props> {
<Autocomplete <Autocomplete
autoHighlight autoHighlight
wrapperStyle={{ flex: 1, position: 'relative' }} wrapperStyle={{ flex: 1, position: 'relative' }}
value={wunderbarValue || ''} value={searchQuery}
items={suggestions} items={suggestions}
getItemValue={item => item.value} getItemValue={item => item.value}
onChange={this.handleChange} onChange={this.handleChange}

View file

@ -28,7 +28,14 @@ export default class extends React.PureComponent<Props> {
return ( return (
<div className="yrbl-wrap"> <div className="yrbl-wrap">
<img alt="Friendly gerbil" className={classnames('yrbl', className)} src={image} /> <img
alt="Friendly gerbil"
className={classnames('yrbl', className)}
src={
// If we don't use a leading `/` @reach/router will try to append the src url to the existing web url
`/${image}`
}
/>
{title && subtitle && ( {title && subtitle && (
<div className="card__content"> <div className="card__content">
<h2 className="card__title">{title}</h2> <h2 className="card__title">{title}</h2>

View file

@ -48,3 +48,6 @@ export const UP = 'ChevronUp';
export const DOWN = 'ChevronDown'; export const DOWN = 'ChevronDown';
export const SECURE = 'Lock'; export const SECURE = 'Lock';
export const MENU = 'Menu'; export const MENU = 'Menu';
export const BACKUP = 'Database';
export const TRANSACTIONS = 'FileText';
export const LBRY = 'Lbry';

View file

@ -1,8 +1,8 @@
import ErrorBoundary from 'component/errorBoundary'; import ErrorBoundary from 'component/errorBoundary';
import App from 'component/app'; import App from 'component/app';
import SnackBar from 'component/snackBar'; import SnackBar from 'component/snackBar';
import SplashScreen from 'component/splash';
// @if TARGET='app' // @if TARGET='app'
import SplashScreen from 'component/splash';
import moment from 'moment'; import moment from 'moment';
import { ipcRenderer, remote, shell } from 'electron'; import { ipcRenderer, remote, shell } from 'electron';
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
@ -19,7 +19,6 @@ import {
doHideModal, doHideModal,
} from 'redux/actions/app'; } from 'redux/actions/app';
import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux'; import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux';
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings'; import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc'; import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc';
import 'scss/all.scss'; import 'scss/all.scss';
@ -46,11 +45,11 @@ if (process.env.SEARCH_API_URL) {
// @if TARGET='app' // @if TARGET='app'
ipcRenderer.on('navigate-backward', () => { ipcRenderer.on('navigate-backward', () => {
app.store.dispatch(doHistoryBack()); // app.store.dispatch(doHistoryBack());
}); });
ipcRenderer.on('navigate-forward', () => { ipcRenderer.on('navigate-forward', () => {
app.store.dispatch(doHistoryForward()); // app.store.dispatch(doHistoryForward());
}); });
// @endif // @endif
@ -132,9 +131,9 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
app.store.dispatch(doConditionalAuthNavigate(newSession)); app.store.dispatch(doConditionalAuthNavigate(newSession));
} else if (uri.startsWith(APPPAGEURL)) { } else if (uri.startsWith(APPPAGEURL)) {
const navpage = uri.replace(APPPAGEURL, '').toLowerCase(); const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
app.store.dispatch(doNavigate(`/${navpage}`)); // app.store.dispatch(doNavigate(`/${navpage}`));
} else if (isURIValid(uri)) { } else if (isURIValid(uri)) {
app.store.dispatch(doNavigate('/show', { uri })); // app.store.dispatch(doNavigate('/show', { uri }));
} else { } else {
app.store.dispatch( app.store.dispatch(
doToast({ doToast({
@ -147,7 +146,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
ipcRenderer.on('open-menu', (event, uri) => { ipcRenderer.on('open-menu', (event, uri) => {
if (uri && uri.startsWith('/help')) { 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()); app.store.dispatch(doBlackListedOutpointsSubscribe());
function onDaemonReady() { 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 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( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<ErrorBoundary> <ErrorBoundary>
@ -245,11 +246,9 @@ const init = () => {
</Provider>, </Provider>,
document.getElementById('app') document.getElementById('app')
); );
// @if TARGET='web'
window.sessionStorage.removeItem('loaded');
// @endif
} }
// @if TARGET='app'
if (window.sessionStorage.getItem('loaded') === 'y') { if (window.sessionStorage.getItem('loaded') === 'y') {
onDaemonReady(); onDaemonReady();
} else { } else {
@ -263,6 +262,10 @@ const init = () => {
document.getElementById('app') document.getElementById('app')
); );
} }
// @endif
// @if TARGET='web'
onDaemonReady();
// @endif
}; };
init(); init();

View file

@ -1,11 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc'; import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc';
import { selectBalance } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import * as settings from 'constants/settings'; import * as settings from 'constants/settings';
import ModalCreditIntro from './view'; import ModalCreditIntro from './view';
import { navigate } from '@reach/router';
const select = state => ({ const select = state => ({
currentBalance: selectBalance(state), currentBalance: selectBalance(state),
@ -15,8 +15,8 @@ const select = state => ({
const perform = dispatch => () => ({ const perform = dispatch => () => ({
addBalance: () => { addBalance: () => {
navigate('/$/getcredits');
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true)); dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
dispatch(doNavigate('/getcredits'));
dispatch(doHideModal()); dispatch(doHideModal());
}, },
closeModal: () => { closeModal: () => {

View file

@ -1,6 +1,7 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { Modal } from 'modal/modal'; import { Modal } from 'modal/modal';
import { formatLbryUriForWeb } from 'util/uri';
// @if TARGET='app' // @if TARGET='app'
import { shell } from 'electron'; import { shell } from 'electron';
// @endif // @endif
@ -13,10 +14,16 @@ type Props = {
class ModalOpenExternalLink extends React.PureComponent<Props> { class ModalOpenExternalLink extends React.PureComponent<Props> {
openExternalLink() { openExternalLink() {
const { uri, closeModal } = this.props; const { uri, closeModal } = this.props;
// @if TARGET='app'
const { openExternal } = shell; const { openExternal } = shell;
if (uri) { if (uri) {
openExternal(uri); openExternal(uri);
} }
// @endif
// @if TARGET='web'
window.open(uri);
// @endif
closeModal(); closeModal();
} }

View file

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { selectPhoneToVerify, selectUser } from 'lbryinc'; import { selectPhoneToVerify, selectUser } from 'lbryinc';
import { doNavigate } from 'redux/actions/navigation'; import { navigate } from '@reach/router';
import ModalPhoneCollection from './view'; import ModalPhoneCollection from './view';
const select = state => ({ const select = state => ({
@ -12,7 +12,7 @@ const select = state => ({
const perform = dispatch => () => ({ const perform = dispatch => () => ({
closeModal: () => { closeModal: () => {
dispatch(doHideModal()); dispatch(doHideModal());
dispatch(doNavigate('/rewards')); navigate('/$/rewards');
}, },
}); });

View file

@ -2,12 +2,10 @@ import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import ModalSendTip from './view'; import ModalSendTip from './view';
import { doClearPublish } from 'redux/actions/publish'; import { doClearPublish } from 'redux/actions/publish';
import { doNavigate } from 'redux/actions/navigation';
const perform = dispatch => ({ const perform = dispatch => ({
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
navigate: (path, params) => dispatch(doNavigate(path, params)),
}); });
export default connect( export default connect(

View file

@ -1,20 +1,15 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as settings from 'constants/settings'; 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 { makeSelectClientSetting } from 'redux/selectors/settings';
import { import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc';
selectUser,
selectUserIsVerificationCandidate,
selectCostForCurrentPageUri,
} from 'lbryinc';
import { selectModal } from 'redux/selectors/app'; import { selectModal } from 'redux/selectors/app';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import ModalRouter from './view'; import ModalRouter from './view';
const select = state => ({ const select = (state, props) => ({
balance: selectBalance(state), balance: selectBalance(state),
showPageCost: selectCostForCurrentPageUri(state), showPageCost: makeSelectCostInfoForUri(props.uri)(state),
page: selectCurrentPage(state),
isVerificationCandidate: selectUserIsVerificationCandidate(state), isVerificationCandidate: selectUserIsVerificationCandidate(state),
isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state), isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state),
isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)( isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)(

View file

@ -113,6 +113,7 @@ class ModalRouter extends React.PureComponent<Props, State> {
isPaidShowPage(props: Props) { isPaidShowPage(props: Props) {
const { page, showPageCost } = props; const { page, showPageCost } = props;
// Fix me
return page === 'show' && showPageCost > 0; return page === 'show' && showPageCost > 0;
} }

View file

@ -1,6 +1,4 @@
import { selectPathAfterAuth } from 'lbry-redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doNavigate } from 'redux/actions/navigation';
import { import {
selectAuthenticationIsPending, selectAuthenticationIsPending,
selectEmailToVerify, selectEmailToVerify,
@ -17,16 +15,11 @@ const select = state => ({
selectUserIsPending(state) || selectUserIsPending(state) ||
selectIdentityVerifyIsPending(state), selectIdentityVerifyIsPending(state),
email: selectEmailToVerify(state), email: selectEmailToVerify(state),
pathAfterAuth: selectPathAfterAuth(state),
user: selectUser(state), user: selectUser(state),
isVerificationCandidate: selectUserIsVerificationCandidate(state), isVerificationCandidate: selectUserIsVerificationCandidate(state),
}); });
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
});
export default connect( export default connect(
select, select,
perform null
)(AuthPage); )(AuthPage);

View file

@ -1,4 +1,5 @@
// @flow // @flow
import type { UrlLocation } from 'types/location';
import React from 'react'; import React from 'react';
import BusyIndicator from 'component/common/busy-indicator'; import BusyIndicator from 'component/common/busy-indicator';
import Button from 'component/button'; import Button from 'component/button';
@ -6,17 +7,18 @@ import UserEmailNew from 'component/userEmailNew';
import UserEmailVerify from 'component/userEmailVerify'; import UserEmailVerify from 'component/userEmailVerify';
import UserVerify from 'component/userVerify'; import UserVerify from 'component/userVerify';
import Page from 'component/page'; import Page from 'component/page';
import { navigate } from '@reach/router';
type Props = { type Props = {
isPending: boolean, isPending: boolean,
email: string, email: string,
pathAfterAuth: string, pathAfterAuth: string,
location: UrlLocation,
user: ?{ user: ?{
has_verified_email: boolean, has_verified_email: boolean,
is_reward_approved: boolean, is_reward_approved: boolean,
is_identity_verified: boolean, is_identity_verified: boolean,
}, },
navigate: (string, ?{}) => void,
}; };
class AuthPage extends React.PureComponent<Props> { class AuthPage extends React.PureComponent<Props> {
@ -29,14 +31,18 @@ class AuthPage extends React.PureComponent<Props> {
} }
navigateIfAuthenticated = (props: Props) => { navigateIfAuthenticated = (props: Props) => {
const { isPending, user, pathAfterAuth, navigate } = props; const { isPending, user, location } = props;
if ( if (
!isPending && !isPending &&
user && user &&
user.has_verified_email && user.has_verified_email &&
(user.is_reward_approved || user.is_identity_verified) (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<Props> {
} }
render() { render() {
const { navigate } = this.props;
const [innerContent, useTemplate] = this.renderMain(); const [innerContent, useTemplate] = this.renderMain();
return ( return (
@ -69,11 +74,7 @@ class AuthPage extends React.PureComponent<Props> {
{`${__( {`${__(
'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.' '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.'
)} `} )} `}
<Button <Button button="link" navigate="/" label={__('Return home.')} />
button="link"
onClick={() => navigate('/discover')}
label={__('Return home.')}
/>
</p> </p>
</section> </section>
) : ( ) : (

View file

@ -3,30 +3,24 @@ import { doFetchClaimsByChannel } from 'redux/actions/content';
import { PAGE_SIZE } from 'constants/claim'; import { PAGE_SIZE } from 'constants/claim';
import { import {
makeSelectClaimForUri, makeSelectClaimForUri,
makeSelectClaimsInChannelForCurrentPage, makeSelectClaimsInChannelForCurrentPageState,
makeSelectFetchingChannelClaims, makeSelectFetchingChannelClaims,
makeSelectCurrentParam,
makeSelectClaimIsMine, makeSelectClaimIsMine,
makeSelectTotalPagesForChannel, makeSelectTotalPagesForChannel,
selectCurrentParams,
} from 'lbry-redux'; } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import ChannelPage from './view'; import ChannelPage from './view';
const select = (state, props) => ({ const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state), claim: makeSelectClaimForUri(props.uri)(state),
claimsInChannel: makeSelectClaimsInChannelForCurrentPage(props.uri)(state), claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state),
fetching: makeSelectFetchingChannelClaims(props.uri)(state), fetching: makeSelectFetchingChannelClaims(props.uri)(state),
page: makeSelectCurrentParam('page')(state),
params: selectCurrentParams(state),
totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state), totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state),
channelIsMine: makeSelectClaimIsMine(props.uri)(state), channelIsMine: makeSelectClaimIsMine(props.uri)(state),
}); });
const perform = dispatch => ({ const perform = dispatch => ({
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)), fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
navigate: (path, params) => dispatch(doNavigate(path, params)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
}); });

View file

@ -1,8 +1,9 @@
// @flow // @flow
import type { Claim } from 'types/claim'; import type { Claim } from 'types/claim';
import type { UrlLocation } from 'types/location';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import React from 'react'; import React, { useEffect } from 'react';
import BusyIndicator from 'component/common/busy-indicator'; import BusyIndicator from 'component/common/busy-indicator';
import { FormField, Form } from 'component/common/form'; import { FormField, Form } from 'component/common/form';
import ReactPaginate from 'react-paginate'; import ReactPaginate from 'react-paginate';
@ -11,10 +12,10 @@ import Page from 'component/page';
import FileList from 'component/fileList'; import FileList from 'component/fileList';
import HiddenNsfwClaims from 'component/hiddenNsfwClaims'; import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
import Button from 'component/button'; import Button from 'component/button';
import { navigate } from '@reach/router';
type Props = { type Props = {
uri: string, uri: string,
page: number,
totalPages: number, totalPages: number,
fetching: boolean, fetching: boolean,
params: { page: number }, params: { page: number },
@ -24,32 +25,42 @@ type Props = {
fetchClaims: (string, number) => void, fetchClaims: (string, number) => void,
navigate: (string, {}) => void, navigate: (string, {}) => void,
openModal: (id: string, { uri: string }) => void, openModal: (id: string, { uri: string }) => void,
location: UrlLocation,
}; };
class ChannelPage extends React.PureComponent<Props> { function ChannelPage(props: Props) {
componentDidMount() { const {
const { uri, page, fetchClaims } = this.props; uri,
fetchClaims(uri, page || 1); fetching,
} claimsInChannel,
claim,
totalPages,
channelIsMine,
openModal,
fetchClaims,
location,
} = props;
componentDidUpdate(prevProps: Props) { const { name, permanent_url: permanentUrl } = claim;
const { page, fetchClaims, uri } = this.props; const { search } = location;
const urlParams = new URLSearchParams(search);
const page = Number(urlParams.get('page')) || 1;
if (prevProps.page && prevProps.page && page !== prevProps.page) { useEffect(() => {
// Fetch new claims if the channel or page number changes
fetchClaims(uri, page); fetchClaims(uri, page);
} }, [uri, page]);
const changePage = (pageNumber: number) => {
if (!page && pageNumber === 1) {
return;
} }
changePage(pageNumber: number) { navigate(`?page=${pageNumber}`);
const { params } = this.props; };
const newParams = Object.assign({}, params, { page: pageNumber });
this.props.navigate('/show', newParams); const paginate = (e: SyntheticKeyboardEvent<*>) => {
} // Change page if enter was pressed, and the given page is between the first and the last page
paginate(e: SyntheticKeyboardEvent<*>, totalPages: number) {
// Change page if enter was pressed, and the given page is between
// the first and the last.
const pageFromInput = Number(e.currentTarget.value); const pageFromInput = Number(e.currentTarget.value);
if ( if (
@ -59,29 +70,9 @@ class ChannelPage extends React.PureComponent<Props> {
pageFromInput > 0 && pageFromInput > 0 &&
pageFromInput <= totalPages 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 ? (
<FileList sortByHeight hideFilter fileInfos={claimsInChannel} />
) : (
!fetching && <span className="empty">{__('No content found.')}</span>
);
return ( return (
<Page notContained> <Page notContained>
@ -90,6 +81,7 @@ class ChannelPage extends React.PureComponent<Props> {
{name} {name}
{fetching && <BusyIndicator />} {fetching && <BusyIndicator />}
</h1> </h1>
<span>{`lbry://${permanentUrl}`}</span>
<div className="channel-info__actions__group"> <div className="channel-info__actions__group">
<SubscribeButton uri={`lbry://${permanentUrl}`} channelName={name} /> <SubscribeButton uri={`lbry://${permanentUrl}`} channelName={name} />
@ -104,7 +96,13 @@ class ChannelPage extends React.PureComponent<Props> {
</div> </div>
</header> </header>
<section className="media-group--list">{contentList}</section> <section className="media-group--list">
{claimsInChannel && claimsInChannel.length ? (
<FileList sortByHeight hideFilter fileInfos={claimsInChannel} />
) : (
!fetching && <span className="empty">{__('No content found.')}</span>
)}
</section>
{(!fetching || (claimsInChannel && claimsInChannel.length)) && totalPages > 1 && ( {(!fetching || (claimsInChannel && claimsInChannel.length)) && totalPages > 1 && (
<Form> <Form>
@ -121,16 +119,17 @@ class ChannelPage extends React.PureComponent<Props> {
nextClassName="pagination__item pagination__item--next" nextClassName="pagination__item pagination__item--next"
breakClassName="pagination__item pagination__item--break" breakClassName="pagination__item pagination__item--break"
marginPagesDisplayed={2} marginPagesDisplayed={2}
onPageChange={e => this.changePage(e.selected + 1)} onPageChange={e => changePage(e.selected + 1)}
forcePage={currentPage} forcePage={page - 1}
initialPage={currentPage} initialPage={page - 1}
disableInitialCallback
containerClassName="pagination" containerClassName="pagination"
/> />
</fieldset-section> </fieldset-section>
<FormField <FormField
className="paginate-channel" className="paginate-channel"
onKeyUp={e => this.paginate(e, totalPages)} onKeyUp={e => paginate(e)}
label={__('Go to page:')} label={__('Go to page:')}
type="text" type="text"
name="paginate-file" name="paginate-file"
@ -143,6 +142,5 @@ class ChannelPage extends React.PureComponent<Props> {
</Page> </Page>
); );
} }
}
export default ChannelPage; export default ChannelPage;

View file

@ -14,7 +14,7 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
fetchFeaturedUris: () => dispatch(doFetchFeaturedUris(true)), fetchFeaturedUris: () => dispatch(doFetchFeaturedUris()),
fetchRewardedContent: () => dispatch(doFetchRewardedContent()), fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
fetchRewards: () => dispatch(doRewardList()), fetchRewards: () => dispatch(doRewardList()),
}); });

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as settings from 'constants/settings'; import * as settings from 'constants/settings';
import { doNavigate } from 'redux/actions/navigation';
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content'; import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
import { doRemoveUnreadSubscription } from 'redux/actions/subscriptions'; import { doRemoveUnreadSubscription } from 'redux/actions/subscriptions';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetClientSetting } from 'redux/actions/settings';
@ -15,10 +14,10 @@ import {
makeSelectChannelForClaimUri, makeSelectChannelForClaimUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { import {
makeSelectCostInfoForUri,
doFetchCostInfoForUri,
doFetchViewCount, doFetchViewCount,
makeSelectViewCountForUri, makeSelectViewCountForUri,
makeSelectCostInfoForUri,
doFetchCostInfoForUri,
} from 'lbryinc'; } from 'lbryinc';
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings'; import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
@ -43,7 +42,6 @@ const select = (state, props) => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: (path, params) => dispatch(doNavigate(path, params)),
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)), fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)), fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
openModal: (modal, props) => dispatch(doOpenModal(modal, props)), openModal: (modal, props) => dispatch(doOpenModal(modal, props)),

View file

@ -39,7 +39,6 @@ type Props = {
channelUri: string, channelUri: string,
viewCount: number, viewCount: number,
prepareEdit: ({}, string) => void, prepareEdit: ({}, string) => void,
navigate: (string, ?{}) => void,
openModal: (id: string, { uri: string }) => void, openModal: (id: string, { uri: string }) => void,
markSubscriptionRead: (string, string) => void, markSubscriptionRead: (string, string) => void,
fetchViewCount: string => void, fetchViewCount: string => void,
@ -132,7 +131,6 @@ class FilePage extends React.Component<Props> {
openModal, openModal,
claimIsMine, claimIsMine,
prepareEdit, prepareEdit,
navigate,
costInfo, costInfo,
fileInfo, fileInfo,
channelUri, channelUri,
@ -173,6 +171,7 @@ class FilePage extends React.Component<Props> {
return ( return (
<Page notContained className="main--file-page"> <Page notContained className="main--file-page">
<div className="grid-area--content"> <div className="grid-area--content">
<h1 className="media__uri">{uri}</h1>
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />} {showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
{!showFile && {!showFile &&
(thumbnail ? ( (thumbnail ? (
@ -231,9 +230,9 @@ class FilePage extends React.Component<Props> {
button="primary" button="primary"
icon={icons.EDIT} icon={icons.EDIT}
label={__('Edit')} label={__('Edit')}
navigate="/$/publish"
onClick={() => { onClick={() => {
prepareEdit(claim, editUri); prepareEdit(claim, editUri);
navigate('/publish');
}} }}
/> />
)} )}

View file

@ -5,7 +5,6 @@ import {
selectIsFetchingFileList, selectIsFetchingFileList,
selectFileListDownloadedSort, selectFileListDownloadedSort,
} from 'lbry-redux'; } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import FileListDownloaded from './view'; import FileListDownloaded from './view';
const select = state => ({ const select = state => ({
@ -15,11 +14,7 @@ const select = state => ({
sortBy: selectFileListDownloadedSort(state), sortBy: selectFileListDownloadedSort(state),
}); });
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
});
export default connect( export default connect(
select, select,
perform null
)(FileListDownloaded); )(FileListDownloaded);

View file

@ -8,13 +8,12 @@ import { PAGES } from 'lbry-redux';
type Props = { type Props = {
fetching: boolean, fetching: boolean,
fileInfos: {}, fileInfos: {},
navigate: (string, ?{}) => void,
sortBy: string, sortBy: string,
}; };
class FileListDownloaded extends React.PureComponent<Props> { class FileListDownloaded extends React.PureComponent<Props> {
render() { render() {
const { fetching, fileInfos, navigate, sortBy } = this.props; const { fetching, fileInfos, sortBy } = this.props;
const hasDownloads = fileInfos && Object.values(fileInfos).length > 0; const hasDownloads = fileInfos && Object.values(fileInfos).length > 0;
return ( return (
@ -32,11 +31,7 @@ class FileListDownloaded extends React.PureComponent<Props> {
<div className="card__content"> <div className="card__content">
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<Button <Button button="primary" navigate="/" label={__('Explore new content')} />
button="primary"
onClick={() => navigate('/discover')}
label={__('Explore new content')}
/>
</div> </div>
</div> </div>
</section> </section>

View file

@ -4,7 +4,6 @@ import {
selectFileListPublishedSort, selectFileListPublishedSort,
selectMyClaimsWithoutChannels, selectMyClaimsWithoutChannels,
} from 'lbry-redux'; } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doCheckPendingPublishes } from 'redux/actions/publish'; import { doCheckPendingPublishes } from 'redux/actions/publish';
import FileListPublished from './view'; import FileListPublished from './view';
@ -15,7 +14,6 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
checkPendingPublishes: () => dispatch(doCheckPendingPublishes()), checkPendingPublishes: () => dispatch(doCheckPendingPublishes()),
}); });

View file

@ -9,7 +9,6 @@ import { PAGES } from 'lbry-redux';
type Props = { type Props = {
claims: Array<Claim>, claims: Array<Claim>,
checkPendingPublishes: () => void, checkPendingPublishes: () => void,
navigate: (string, ?{}) => void,
fetching: boolean, fetching: boolean,
sortBy: string, sortBy: string,
}; };
@ -21,7 +20,7 @@ class FileListPublished extends React.PureComponent<Props> {
} }
render() { render() {
const { fetching, claims, navigate, sortBy } = this.props; const { fetching, claims, sortBy } = this.props;
return ( return (
<Page notContained loading={fetching}> <Page notContained loading={fetching}>
{claims && claims.length ? ( {claims && claims.length ? (
@ -45,7 +44,7 @@ class FileListPublished extends React.PureComponent<Props> {
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<Button <Button
button="primary" button="primary"
onClick={() => navigate('/publish')} navigate="/$/publish"
label={__('Publish something new')} label={__('Publish something new')}
/> />
</div> </div>

View file

@ -200,7 +200,7 @@ class HelpPage extends React.PureComponent<Props, State> {
<div className="card__content"> <div className="card__content">
<div className="card__actions"> <div className="card__actions">
<Button <Button
navigate="/report" navigate="/$/report"
label={__('Submit a Bug Report/Feature Request')} label={__('Submit a Bug Report/Feature Request')}
icon={icons.REPORT} icon={icons.REPORT}
button="primary" button="primary"

View file

@ -1,6 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doResolveUri, selectBalance } from 'lbry-redux'; import { doResolveUri, selectBalance } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { import {
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
@ -35,7 +34,6 @@ const perform = dispatch => ({
clearPublish: () => dispatch(doClearPublish()), clearPublish: () => dispatch(doClearPublish()),
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),
publish: params => dispatch(doPublish(params)), publish: params => dispatch(doPublish(params)),
navigate: path => dispatch(doNavigate(path)),
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)), prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()), resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
}); });

View file

@ -6,7 +6,7 @@ import {
selectUser, selectUser,
doRewardList, doRewardList,
} from 'lbryinc'; } from 'lbryinc';
import { doAuthNavigate, doNavigate } from 'redux/actions/navigation'; import { navigate } from '@reach/router';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings } from 'redux/selectors/settings';
import RewardsPage from './view'; import RewardsPage from './view';
@ -20,9 +20,8 @@ const select = state => ({
const perform = dispatch => ({ const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()), fetchRewards: () => dispatch(doRewardList()),
navigate: path => dispatch(doNavigate(path)),
doAuth: () => { doAuth: () => {
dispatch(doAuthNavigate('/rewards')); navigate('/$/auth?redirect=rewards');
}, },
}); });

View file

@ -11,7 +11,6 @@ import { rewards as REWARD_TYPES } from 'lbryinc';
type Props = { type Props = {
doAuth: () => void, doAuth: () => void,
navigate: string => void,
fetching: boolean, fetching: boolean,
rewards: Array<Reward>, rewards: Array<Reward>,
claimed: Array<Reward>, claimed: Array<Reward>,
@ -28,7 +27,7 @@ type Props = {
class RewardsPage extends PureComponent<Props> { class RewardsPage extends PureComponent<Props> {
renderPageHeader() { renderPageHeader() {
const { doAuth, navigate, user, daemonSettings } = this.props; const { doAuth, user, daemonSettings } = this.props;
if (user && !user.is_reward_approved && daemonSettings && daemonSettings.share_usage_data) { if (user && !user.is_reward_approved && daemonSettings && daemonSettings.share_usage_data) {
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) { if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
@ -68,7 +67,7 @@ class RewardsPage extends PureComponent<Props> {
)}`} )}`}
</p> </p>
<p> <p>
<Button onClick={() => navigate('/discover')} button="primary" label="Return Home" /> <Button navigate="/" button="primary" label="Return Home" />
</p> </p>
</section> </section>
); );
@ -93,7 +92,7 @@ class RewardsPage extends PureComponent<Props> {
} }
renderUnclaimedRewards() { renderUnclaimedRewards() {
const { fetching, rewards, user, daemonSettings, navigate, claimed } = this.props; const { fetching, rewards, user, daemonSettings, claimed } = this.props;
if (daemonSettings && !daemonSettings.share_usage_data) { if (daemonSettings && !daemonSettings.share_usage_data) {
return ( return (
@ -104,7 +103,7 @@ class RewardsPage extends PureComponent<Props> {
{__( {__(
'Rewards are currently disabled for your account. Turn on diagnostic data sharing, in' 'Rewards are currently disabled for your account. Turn on diagnostic data sharing, in'
)}{' '} )}{' '}
<Button button="link" onClick={() => navigate('/settings')} label="Settings" /> <Button button="link" navigate="/$/settings" label="Settings" />
{__(', in order to re-enable them.')} {__(', in order to re-enable them.')}
</p> </p>
</header> </header>

View file

@ -1,17 +1,14 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectIsSearching, makeSelectCurrentParam, doUpdateSearchQuery } from 'lbry-redux'; import { doSearch, selectIsSearching } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import SearchPage from './view'; import SearchPage from './view';
const select = state => ({ const select = state => ({
isSearching: selectIsSearching(state), isSearching: selectIsSearching(state),
query: makeSelectCurrentParam('query')(state),
}); });
const perform = dispatch => ({ const perform = {
navigate: path => dispatch(doNavigate(path)), doSearch,
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)), };
});
export default connect( export default connect(
select, select,

View file

@ -1,6 +1,7 @@
// @flow // @flow
import type { UrlLocation } from 'types/location';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import * as React from 'react'; import React, { useEffect, Fragment } from 'react';
import { isURIValid, normalizeURI, parseURI } from 'lbry-redux'; import { isURIValid, normalizeURI, parseURI } from 'lbry-redux';
import FileTile from 'component/fileTile'; import FileTile from 'component/fileTile';
import ChannelTile from 'component/channelTile'; import ChannelTile from 'component/channelTile';
@ -9,55 +10,88 @@ import Page from 'component/page';
import ToolTip from 'component/common/tooltip'; import ToolTip from 'component/common/tooltip';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import SearchOptions from 'component/searchOptions'; import SearchOptions from 'component/searchOptions';
import { Location } from '@reach/router';
type Props = { type Props = { doSearch: string => void, location: UrlLocation };
query: ?string,
};
class SearchPage extends React.PureComponent<Props> { export default function SearchPage(props: Props) {
render() { const {
const { query } = this.props; doSearch,
location: { search },
} = props;
const urlParams = new URLSearchParams(location.search);
const urlQuery = urlParams.get('q');
useEffect(() => {
if (urlQuery) {
doSearch(urlQuery);
}
}, [urlQuery]);
return (
<Page noPadding>
<Location>
{(locationProps: {
location: {
search: string,
},
}) => {
const { location } = locationProps;
const urlParams = new URLSearchParams(location.search);
const query = urlParams.get('q');
const isValid = isURIValid(query); const isValid = isURIValid(query);
let uri; let uri;
let isChannel; let isChannel;
let label;
if (isValid) { if (isValid) {
uri = normalizeURI(query); uri = normalizeURI(query);
({ isChannel } = parseURI(uri)); ({ isChannel } = parseURI(uri));
// label = (
// <Fragment>
// {`lbry://${query}`}
// <ToolTip
// icon
// body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
// >
// <Icon icon={ICONS.HELP} />
// </ToolTip>
// </Fragment>
// );
} }
return ( return (
<Page noPadding>
<section className="search"> <section className="search">
{query && isValid && ( {query && (
<Fragment>
<header className="search__header"> <header className="search__header">
<h1 className="search__title"> {isValid && (
{`lbry://${query}`} <Fragment>
<ToolTip <SearchOptions />
icon
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')} <h1 className="media__uri">{uri}</h1>
>
<Icon icon={ICONS.HELP} />
</ToolTip>
</h1>
{isChannel ? ( {isChannel ? (
<ChannelTile size="large" isSearchResult uri={uri} /> <ChannelTile size="large" isSearchResult uri={uri} />
) : ( ) : (
<FileTile size="large" isSearchResult displayHiddenMessage uri={uri} /> <FileTile size="large" isSearchResult displayHiddenMessage uri={uri} />
)} )}
</header> </Fragment>
)} )}
</header>
<div className="search__results-wrapper"> <div className="search__results-wrapper">
<SearchOptions />
<FileListSearch query={query} /> <FileListSearch query={query} />
<div className="help">{__('These search results are provided by LBRY, Inc.')}</div> <div className="card__content help">
{__('These search results are provided by LBRY, Inc.')}
</div> </div>
</div>
</Fragment>
)}
</section> </section>
);
}}
</Location>
</Page> </Page>
); );
} }
}
export default SearchPage;

View file

@ -5,16 +5,22 @@ import {
makeSelectClaimForUri, makeSelectClaimForUri,
makeSelectIsUriResolving, makeSelectIsUriResolving,
makeSelectTotalPagesForChannel, makeSelectTotalPagesForChannel,
buildURI,
} from 'lbry-redux'; } from 'lbry-redux';
import { selectBlackListedOutpoints } from 'lbryinc'; import { selectBlackListedOutpoints } from 'lbryinc';
import ShowPage from './view'; import ShowPage from './view';
const select = (state, props) => ({ const select = (state, props) => {
claim: makeSelectClaimForUri(props.uri)(state), // claimName and claimId come from the url `lbry.tv/{claimName}/{claimId}"
isResolvingUri: makeSelectIsUriResolving(props.uri)(state), const uri = buildURI({ contentName: props.claimName, claimId: props.claimId });
return {
claim: makeSelectClaimForUri(uri)(state),
isResolvingUri: makeSelectIsUriResolving(uri)(state),
blackListedOutpoints: selectBlackListedOutpoints(state), blackListedOutpoints: selectBlackListedOutpoints(state),
totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state), totalPages: makeSelectTotalPagesForChannel(uri, PAGE_SIZE)(state),
}); uri: uri,
};
};
const perform = dispatch => ({ const perform = dispatch => ({
resolveUri: uri => dispatch(doResolveUri(uri)), resolveUri: uri => dispatch(doResolveUri(uri)),

View file

@ -1,4 +1,5 @@
// @flow // @flow
import type { UrlLocation } from 'types/location';
import React from 'react'; import React from 'react';
import BusyIndicator from 'component/common/busy-indicator'; import BusyIndicator from 'component/common/busy-indicator';
import ChannelPage from 'page/channel'; import ChannelPage from 'page/channel';
@ -13,6 +14,7 @@ type Props = {
uri: string, uri: string,
claim: Claim, claim: Claim,
totalPages: number, totalPages: number,
location: UrlLocation,
blackListedOutpoints: Array<{ blackListedOutpoints: Array<{
txid: string, txid: string,
nout: number, nout: number,
@ -38,8 +40,7 @@ class ShowPage extends React.PureComponent<Props> {
} }
render() { render() {
const { claim, isResolvingUri, uri, blackListedOutpoints } = this.props; const { claim, isResolvingUri, uri, blackListedOutpoints, location } = this.props;
let innerContent = ''; let innerContent = '';
if (!claim || (claim && !claim.name)) { if (!claim || (claim && !claim.name)) {
@ -58,7 +59,7 @@ class ShowPage extends React.PureComponent<Props> {
</Page> </Page>
); );
} else if (claim.name.length && claim.name[0] === '@') { } else if (claim.name.length && claim.name[0] === '@') {
innerContent = <ChannelPage uri={uri} />; innerContent = <ChannelPage uri={uri} location={location} />;
} else if (claim && blackListedOutpoints) { } else if (claim && blackListedOutpoints) {
let isClaimBlackListed = false; let isClaimBlackListed = false;
@ -89,7 +90,7 @@ class ShowPage extends React.PureComponent<Props> {
</Page> </Page>
); );
} else { } else {
innerContent = <FilePage uri={uri} />; innerContent = <FilePage uri={uri} location={location} />;
} }
} }

View file

@ -13,6 +13,7 @@ import SuggestedSubscriptions from 'component/subscribeSuggested';
import MarkAsRead from 'component/subscribeMarkAsRead'; import MarkAsRead from 'component/subscribeMarkAsRead';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
viewMode: ViewMode, viewMode: ViewMode,
@ -109,12 +110,7 @@ export default (props: Props) => {
return ( return (
<span> <span>
<h2 className="card__title card__title--flex"> <h2 className="card__title card__title--flex">
<Button <Button button="link" navigate={channel} label={claimName} />
button="link"
navigate="/show"
navigateParams={{ uri: channel, page: 1 }}
label={claimName}
/>
<MarkAsRead channel={channel} /> <MarkAsRead channel={channel} />
</h2> </h2>

View file

@ -9,7 +9,7 @@ class UserHistoryPage extends React.PureComponent<Props> {
render() { render() {
return ( return (
<Page> <Page>
<UserHistory /> <UserHistory {...this.props} />
</Page> </Page>
); );
} }

View file

@ -6,6 +6,7 @@ import TransactionListRecent from 'component/transactionListRecent';
import WalletAddress from 'component/walletAddress'; import WalletAddress from 'component/walletAddress';
import Page from 'component/page'; import Page from 'component/page';
import UnsupportedOnWeb from 'component/common/unsupported-on-web'; import UnsupportedOnWeb from 'component/common/unsupported-on-web';
import WalletSend from 'component/walletSend';
const WalletPage = () => ( const WalletPage = () => (
<Page> <Page>
@ -15,6 +16,7 @@ const WalletPage = () => (
<WalletBalance /> <WalletBalance />
<RewardSummary /> <RewardSummary />
</div> </div>
<WalletSend />
<WalletAddress /> <WalletAddress />
<TransactionListRecent /> <TransactionListRecent />
</div> </div>

View file

@ -317,6 +317,7 @@ export function doDaemonReady() {
dispatch({ type: ACTIONS.DAEMON_READY }); dispatch({ type: ACTIONS.DAEMON_READY });
dispatch(doFetchDaemonSettings()); dispatch(doFetchDaemonSettings());
dispatch(doBalanceSubscribe()); dispatch(doBalanceSubscribe());
// @if TARGET='app' // @if TARGET='app'
dispatch(doFetchFileInfosAndPublishedClaims()); dispatch(doFetchFileInfosAndPublishedClaims());
if (!selectIsUpgradeSkipped(state)) { if (!selectIsUpgradeSkipped(state)) {

View file

@ -7,7 +7,7 @@ import * as MODALS from 'constants/modal_types';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
// @endif // @endif
import { doOpenModal } from 'redux/actions/app'; 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 { setSubscriptionLatest, doUpdateUnreadSubscriptions } from 'redux/actions/subscriptions';
import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions'; import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions';
import { import {
@ -24,10 +24,11 @@ import {
parseURI, parseURI,
creditsToString, creditsToString,
doError, doError,
makeSelectCostInfoForUri,
} from 'lbry-redux'; } from 'lbry-redux';
import { makeSelectCostInfoForUri } from 'lbryinc';
import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings'; import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings';
import analytics from 'analytics'; import analytics from 'analytics';
import { formatLbryUriForWeb } from 'util/uri';
const DOWNLOAD_POLL_INTERVAL = 250; const DOWNLOAD_POLL_INTERVAL = 250;
@ -82,11 +83,7 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) {
silent: false, silent: false,
}); });
notif.onclick = () => { notif.onclick = () => {
dispatch( navigate(formatLbryUriForWeb(uri));
doNavigate('/show', {
uri,
})
);
}; };
} }

View file

@ -10,7 +10,6 @@ import {
selectFileInfosByOutpoint, selectFileInfosByOutpoint,
} from 'lbry-redux'; } from 'lbry-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { doHistoryBack } from 'redux/actions/navigation';
export function doOpenFileInFolder(path) { export function doOpenFileInFolder(path) {
return () => { return () => {
@ -63,7 +62,6 @@ export function doDeleteFileAndGoBack(fileInfo, deleteFromComputer, abandonClaim
return dispatch => { return dispatch => {
const actions = []; const actions = [];
actions.push(doHideModal()); actions.push(doHideModal());
actions.push(doHistoryBack());
actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim)); actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
dispatch(batchActions(...actions)); dispatch(batchActions(...actions));
}; };

View file

@ -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 },
});
};
}

View file

@ -21,8 +21,9 @@ import {
} from 'lbry-redux'; } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { selectosNotificationsEnabled } from 'redux/selectors/settings'; import { selectosNotificationsEnabled } from 'redux/selectors/settings';
import { doNavigate } from 'redux/actions/navigation'; import { navigate } from '@reach/router';
import analytics from 'analytics'; import analytics from 'analytics';
import { formatLbryUriForWeb } from 'util/uri';
// @if TARGET='app' // @if TARGET='app'
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
@ -327,11 +328,7 @@ export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetS
silent: false, silent: false,
}); });
notif.onclick = () => { notif.onclick = () => {
dispatch( navigate(formatLbryUriForWeb(claim.permanent_url));
doNavigate('/show', {
uri: claim.permanent_url,
})
);
}; };
} }
} }

View file

@ -100,21 +100,6 @@ export const selectDaemonVersionMatched = createSelector(
state => state.daemonVersionMatched 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( export const selectCurrentLanguage = createSelector(
selectState, selectState,
() => i18n.getLocale() || 'en' () => i18n.getLocale() || 'en'
@ -130,147 +115,6 @@ export const selectUpgradeTimer = createSelector(
state => state.checkUpgradeTimer 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( export const selectModal = createSelector(
selectState, selectState,
state => { state => {

View file

@ -3,7 +3,7 @@ import { createSelector } from 'reselect';
import { import {
makeSelectClaimForUri, makeSelectClaimForUri,
selectClaimsByUri, selectClaimsByUri,
makeSelectClaimsInChannelForCurrentPage, makeSelectClaimsInChannelForCurrentPageState,
} from 'lbry-redux'; } from 'lbry-redux';
import { HISTORY_ITEMS_PER_PAGE } from 'constants/content'; import { HISTORY_ITEMS_PER_PAGE } from 'constants/content';
@ -68,7 +68,7 @@ export const makeSelectHistoryForUri = (uri: string) =>
export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) => export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
createSelector( createSelector(
makeSelectClaimsInChannelForCurrentPage(channel), makeSelectClaimsInChannelForCurrentPageState(channel),
channelClaims => { channelClaims => {
if (uris) return uris; if (uris) return uris;

View file

@ -2,6 +2,7 @@
.button { .button {
border-radius: 0; border-radius: 0;
font-size: 1em;
svg { svg {
stroke-width: 1.9; stroke-width: 1.9;

View file

@ -27,7 +27,12 @@
// at smaller screen widths // at smaller screen widths
@media (min-width: 601px) { @media (min-width: 601px) {
/* @if TARGET='app' */
width: 250px; width: 250px;
/* @endif */
/* @if TARGET='web' */
width: 170px;
/* @endif */
} }
@media (max-width: 600px) { @media (max-width: 600px) {
@ -38,9 +43,9 @@
.header__navigation-item { .header__navigation-item {
height: var(--header-height); height: var(--header-height);
background-position: center; display: flex;
background-repeat: no-repeat; justify-content: center;
background-size: 50%; align-items: center;
&:not(:disabled):hover { &:not(:disabled):hover {
background-color: $lbry-gray-1; background-color: $lbry-gray-1;
@ -53,68 +58,49 @@
&:disabled { &:disabled {
opacity: 0.3; opacity: 0.3;
} }
}
.header__navigation-item--back { .button__content {
html[data-mode='dark'] & { line-height: var(--header-height);
svg { overflow: hidden;
stroke: $lbry-white; 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--back,
.header__navigation-item--forward, .header__navigation-item--forward,
.header__navigation-item--home, .header__navigation-item--home,
.header__navigation-item--menu { .header__navigation-item--menu {
width: var(--header-height); width: var(--header-height);
svg {
&:only-child {
// Header icons are a little different because they are larger
top: 0.25rem;
} }
// Currently not used html[data-mode='dark'] & {
// .header__navigation-item--publish, stroke: $lbry-white;
// .header__navigation-item--wallet { }
// // Publish and Wallet links are collapsed }
// // into a menu at smaller screen widths }
//
// @media (max-width: 600px) { .header__navigation-item--lbry {
// display: none; 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 // Publish button
.header__navigation-item--right-action { .header__navigation-item--right-action {
display: flex;
justify-content: center;
position: relative; position: relative;
.button__content { .button__content {
@ -149,12 +135,24 @@
html[data-mode='dark'] & { html[data-mode='dark'] & {
border-color: $lbry-gray-5; border-color: $lbry-gray-5;
} }
}
.button__content { .header__navigation-item--menu {
line-height: var(--header-height); @media (min-width: 601px) {
overflow: hidden; display: none;
text-align: center; }
text-overflow: ellipsis; }
width: 100%;
// 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;
} }
} }

View file

@ -139,6 +139,12 @@
margin-right: var(--spacing-vertical-small); margin-right: var(--spacing-vertical-small);
} }
.media__uri {
font-size: 1.1rem;
padding-bottom: 5px;
opacity: 0.6;
}
// M E D I A // M E D I A
// A C T I O N S // A C T I O N S
@ -508,12 +514,9 @@
font-size: 2rem; font-size: 2rem;
} }
@media (max-width: 600px) {
font-size: 1.75rem;
}
.channel-info__actions__group { .channel-info__actions__group {
button:first-of-type { .button {
&:first-child {
font-size: 2rem; font-size: 2rem;
.button__label { .button__label {
@ -521,11 +524,12 @@
} }
} }
button:last-of-type { &:last-child {
font-weight: normal; font-weight: normal;
} }
} }
} }
}
// M E D I A // M E D I A
// S C R O L L H O U S E // S C R O L L H O U S E

View file

@ -52,6 +52,11 @@
position: relative; position: relative;
} }
.navigation__links--bottom {
position: absolute;
bottom: var(--spacing-vertical-large);
}
.navigation__link { .navigation__link {
display: block; display: block;
line-height: 1.75; line-height: 1.75;
@ -102,7 +107,7 @@
.navigation__link--title { .navigation__link--title {
margin-bottom: var(--spacing-vertical-small); margin-bottom: var(--spacing-vertical-small);
padding-top: var(--spacing-vertical-medium); padding-top: var(--spacing-vertical-large);
color: $lbry-gray-5; color: $lbry-gray-5;
cursor: default; cursor: default;

View file

@ -53,6 +53,7 @@
.search__options-wrapper { .search__options-wrapper {
font-size: 1.25em; font-size: 1.25em;
padding-bottom: var(--spacing-vertical-large);
} }
.search__options { .search__options {

View file

@ -8,7 +8,7 @@
} }
.yrbl { .yrbl {
height: 300px; height: 20rem;
margin-right: var(--spacing-vertical-large); margin-right: var(--spacing-vertical-large);
} }

View file

@ -127,7 +127,7 @@ code {
} }
.help { .help {
font-size: 0.9em; font-size: 1rem;
background-color: rgba($lbry-blue-1, 0.1); background-color: rgba($lbry-blue-1, 0.1);
color: $lbry-gray-5; color: $lbry-gray-5;
display: block; display: block;

View file

@ -39,7 +39,7 @@ $large-breakpoint: 1921px;
--button-height: 36px; --button-height: 36px;
// Header // Header
--header-height: 3.25rem; // 60px; --header-height: 3.5rem;
// Header -> search // Header -> search
--search-modal-input-height: 70px; --search-modal-input-height: 70px;

Some files were not shown because too many files have changed in this diff Show more