New routing setup #2395
108 changed files with 855 additions and 1083 deletions
|
@ -59,6 +59,7 @@
|
|||
"@hot-loader/react-dom": "16.8",
|
||||
"@lbry/color": "^1.0.2",
|
||||
"@lbry/components": "^2.3.3",
|
||||
"@reach/router": "^1.2.1",
|
||||
"@types/three": "^0.93.1",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"babel-eslint": "^10.0.1",
|
||||
|
@ -106,8 +107,8 @@
|
|||
"husky": "^0.14.3",
|
||||
"json-loader": "^0.5.4",
|
||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||
"lbry-redux": "lbryio/lbry-redux#2a7e05940f892f104428eeb37bd1f178da811a09",
|
||||
"lbryinc": "lbryio/lbryinc#437260f3dad2321e892388b68749ee6af01aff2b",
|
||||
"lbry-redux": "lbryio/lbry-redux#86f1340f834d0f5cd5365492a8ff15d4b213a050",
|
||||
"lbryinc": "lbryio/lbryinc#d9f9035113c8b9ab3b0ee7ffbd38f910086a665e",
|
||||
"lint-staged": "^7.0.2",
|
||||
"localforage": "^1.7.1",
|
||||
"make-runnable": "^1.3.6",
|
||||
|
|
|
@ -35,9 +35,7 @@ export default appState => {
|
|||
},
|
||||
};
|
||||
|
||||
const rendererURL = isDev // ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
||||
? `http://localhost:8080/index.dev.html`
|
||||
: `file://${__dirname}/index.html`;
|
||||
const rendererURL = isDev ? `http://localhost:8080` : `file://${__dirname}/index.html`;
|
||||
|
||||
let window = new BrowserWindow(windowConfiguration);
|
||||
|
||||
|
|
|
@ -5,4 +5,8 @@ const port = 1337;
|
|||
|
||||
app.use(express.static(__dirname));
|
||||
|
||||
app.listen(port, () => console.log(`UI server listening at localhost://${port}`));
|
||||
app.get('*', function(req, res) {
|
||||
res.sendFile(path.join(__dirname, '/index.html'));
|
||||
});
|
||||
|
||||
app.listen(port, () => console.log(`UI server listening at http://localhost:${port}`));
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
import { hot } from 'react-hot-loader/root';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectPageTitle,
|
||||
selectHistoryIndex,
|
||||
selectActiveHistoryEntry,
|
||||
doUpdateBlockHeight,
|
||||
doError,
|
||||
} from 'lbry-redux';
|
||||
import { doRecordScroll } from 'redux/actions/navigation';
|
||||
import { doUpdateBlockHeight, doError } from 'lbry-redux';
|
||||
import { doToggleEnhancedLayout } from 'redux/actions/app';
|
||||
import { selectUser } from 'lbryinc';
|
||||
import { selectThemePath } from 'redux/selectors/settings';
|
||||
|
@ -15,17 +8,13 @@ import { selectEnhancedLayout } from 'redux/selectors/app';
|
|||
import App from './view';
|
||||
|
||||
const select = state => ({
|
||||
pageTitle: selectPageTitle(state),
|
||||
user: selectUser(state),
|
||||
currentStackIndex: selectHistoryIndex(state),
|
||||
currentPageAttributes: selectActiveHistoryEntry(state),
|
||||
theme: selectThemePath(state),
|
||||
enhancedLayout: selectEnhancedLayout(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
alertError: errorList => dispatch(doError(errorList)),
|
||||
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
||||
updateBlockHeight: () => dispatch(doUpdateBlockHeight()),
|
||||
toggleEnhancedLayout: () => dispatch(doToggleEnhancedLayout()),
|
||||
});
|
||||
|
|
|
@ -14,9 +14,6 @@ const TWO_POINT_FIVE_MINUTES = 1000 * 60 * 2.5;
|
|||
|
||||
type Props = {
|
||||
alertError: (string | {}) => void,
|
||||
recordScroll: number => void,
|
||||
currentStackIndex: number,
|
||||
currentPageAttributes: { path: string, scrollY: number },
|
||||
pageTitle: ?string,
|
||||
theme: string,
|
||||
updateBlockHeight: () => void,
|
||||
|
@ -25,12 +22,6 @@ type Props = {
|
|||
};
|
||||
|
||||
class App extends React.PureComponent<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
this.mainContent = undefined;
|
||||
(this: any).scrollListener = this.scrollListener.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const { alertError, theme } = this.props;
|
||||
|
||||
|
@ -47,12 +38,6 @@ class App extends React.PureComponent<Props> {
|
|||
componentDidMount() {
|
||||
const { updateBlockHeight, toggleEnhancedLayout } = this.props;
|
||||
|
||||
const mainContent = document.getElementById('content');
|
||||
this.mainContent = mainContent;
|
||||
if (this.mainContent) {
|
||||
this.mainContent.addEventListener('scroll', throttle(this.scrollListener, 750));
|
||||
}
|
||||
|
||||
ReactModal.setAppElement('#window'); // fuck this
|
||||
|
||||
this.enhance = new EnhancedLayoutListener(() => toggleEnhancedLayout());
|
||||
|
@ -63,18 +48,9 @@ class App extends React.PureComponent<Props> {
|
|||
}, TWO_POINT_FIVE_MINUTES);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props: Props) {
|
||||
const { pageTitle } = props;
|
||||
this.setTitleFromProps(pageTitle);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const { currentStackIndex: prevStackIndex, theme: prevTheme } = prevProps;
|
||||
const { currentStackIndex, currentPageAttributes, theme } = this.props;
|
||||
|
||||
if (this.mainContent && currentStackIndex !== prevStackIndex && currentPageAttributes) {
|
||||
this.mainContent.scrollTop = currentPageAttributes.scrollY || 0;
|
||||
}
|
||||
const { theme: prevTheme } = prevProps;
|
||||
const { theme } = this.props;
|
||||
|
||||
if (prevTheme !== theme) {
|
||||
// $FlowFixMe
|
||||
|
@ -83,26 +59,9 @@ class App extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.mainContent) {
|
||||
this.mainContent.removeEventListener('scroll', this.scrollListener);
|
||||
}
|
||||
|
||||
this.enhance = null;
|
||||
}
|
||||
|
||||
setTitleFromProps = (title: ?string) => {
|
||||
window.document.title = title || 'LBRY';
|
||||
};
|
||||
|
||||
scrollListener() {
|
||||
const { recordScroll } = this.props;
|
||||
|
||||
if (this.mainContent) {
|
||||
recordScroll(this.mainContent.scrollTop);
|
||||
}
|
||||
}
|
||||
|
||||
mainContent: ?HTMLElement;
|
||||
enhance: ?any;
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import Button from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
doNavigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
perform
|
||||
)(Button);
|
||||
export default Button;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import * as React from 'react';
|
||||
import Icon from 'component/common/icon';
|
||||
import classnames from 'classnames';
|
||||
import { Link } from '@reach/router';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
onClick: ?(any) => any,
|
||||
|
@ -13,9 +15,6 @@ type Props = {
|
|||
disabled: ?boolean,
|
||||
children: ?React.Node,
|
||||
navigate: ?string,
|
||||
// TODO: these (nav) should be a reusable type
|
||||
doNavigate: (string, ?any) => void,
|
||||
navigateParams: any,
|
||||
className: ?string,
|
||||
description: ?string,
|
||||
type: string,
|
||||
|
@ -24,7 +23,7 @@ type Props = {
|
|||
iconColor?: string,
|
||||
iconSize?: number,
|
||||
constrict: ?boolean, // to shorten the button and ellipsis, only use for links
|
||||
selected: ?boolean,
|
||||
activeClass?: string,
|
||||
};
|
||||
|
||||
class Button extends React.PureComponent<Props> {
|
||||
|
@ -43,8 +42,6 @@ class Button extends React.PureComponent<Props> {
|
|||
disabled,
|
||||
children,
|
||||
navigate,
|
||||
navigateParams,
|
||||
doNavigate,
|
||||
className,
|
||||
description,
|
||||
button,
|
||||
|
@ -53,7 +50,7 @@ class Button extends React.PureComponent<Props> {
|
|||
iconColor,
|
||||
iconSize,
|
||||
constrict,
|
||||
selected,
|
||||
activeClass,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
|
@ -72,20 +69,11 @@ class Button extends React.PureComponent<Props> {
|
|||
'button--disabled': disabled,
|
||||
'button--link': button === 'link',
|
||||
'button--constrict': constrict,
|
||||
'button--selected': selected,
|
||||
}
|
||||
: 'button--no-style',
|
||||
className
|
||||
);
|
||||
|
||||
const extendedOnClick =
|
||||
!onClick && navigate
|
||||
? event => {
|
||||
event.stopPropagation();
|
||||
doNavigate(navigate, navigateParams || {});
|
||||
}
|
||||
: onClick;
|
||||
|
||||
const content = (
|
||||
<span className="button__content">
|
||||
{icon && <Icon icon={icon} iconColor={iconColor} size={iconSize} />}
|
||||
|
@ -95,16 +83,43 @@ class Button extends React.PureComponent<Props> {
|
|||
</span>
|
||||
);
|
||||
|
||||
return href ? (
|
||||
<a className={combinedClassName} href={href} title={title}>
|
||||
if (href) {
|
||||
return (
|
||||
<a href={href} className={combinedClassName}>
|
||||
{content}
|
||||
</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
|
||||
title={title}
|
||||
aria-label={description || label || title}
|
||||
className={combinedClassName}
|
||||
onClick={extendedOnClick}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
type={type}
|
||||
{...otherProps}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||
import { makeSelectCategoryListUris } from 'redux/selectors/content';
|
||||
import {
|
||||
makeSelectFetchingChannelClaims,
|
||||
doResolveUris,
|
||||
selectActiveHistoryEntry,
|
||||
} from 'lbry-redux';
|
||||
import { makeSelectFetchingChannelClaims, doResolveUris } from 'lbry-redux';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import CategoryList from './view';
|
||||
|
||||
|
@ -13,7 +9,6 @@ const select = (state, props) => ({
|
|||
urisInList: makeSelectCategoryListUris(props.uris, props.categoryLink)(state),
|
||||
fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
|
||||
obscureNsfw: !selectShowNsfw(state),
|
||||
currentPageAttributes: selectActiveHistoryEntry(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React, { PureComponent, createRef } from 'react';
|
||||
import { normalizeURI } from 'lbry-redux';
|
||||
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||
import ToolTip from 'component/common/tooltip';
|
||||
import FileCard from 'component/fileCard';
|
||||
import Button from 'component/button';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
import throttle from 'util/throttle';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
category: string,
|
||||
|
@ -44,7 +45,7 @@ class CategoryList extends PureComponent<Props, State> {
|
|||
(this: any).handleScrollNext = this.handleScrollNext.bind(this);
|
||||
(this: any).handleScrollPrevious = this.handleScrollPrevious.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();
|
||||
}
|
||||
|
@ -75,32 +76,34 @@ class CategoryList extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const { scrollY: previousScrollY } = prevProps.currentPageAttributes;
|
||||
const { scrollY } = this.props.currentPageAttributes;
|
||||
// The old lazy loading for home page relied on the navigation reducers copy of the scroll height
|
||||
// Keeping it commented out for now to try and find a better way for better TTI on the homepage
|
||||
// componentDidUpdate(prevProps: Props) {
|
||||
// const {scrollY: previousScrollY} = prevProps.currentPageAttributes;
|
||||
// const {scrollY} = this.props.currentPageAttributes;
|
||||
|
||||
if (scrollY > previousScrollY) {
|
||||
this.handleResolveOnScroll();
|
||||
}
|
||||
}
|
||||
// if(scrollY > previousScrollY) {
|
||||
// this.handleResolveOnScroll();
|
||||
// }
|
||||
// }
|
||||
|
||||
handleResolveOnScroll() {
|
||||
const {
|
||||
urisInList,
|
||||
resolveUris,
|
||||
currentPageAttributes: { scrollY },
|
||||
} = this.props;
|
||||
// handleResolveOnScroll() {
|
||||
// const {
|
||||
// urisInList,
|
||||
// resolveUris,
|
||||
// currentPageAttributes: {scrollY},
|
||||
// } = this.props;
|
||||
|
||||
const scrollWrapper = this.scrollWrapper.current;
|
||||
if (!scrollWrapper) {
|
||||
return;
|
||||
}
|
||||
// const scrollWrapper = this.scrollWrapper.current;
|
||||
// if(!scrollWrapper) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
const shouldResolve = window.innerHeight > scrollWrapper.offsetTop - scrollY;
|
||||
if (shouldResolve && urisInList) {
|
||||
resolveUris(urisInList);
|
||||
}
|
||||
}
|
||||
// const shouldResolve = window.innerHeight > scrollWrapper.offsetTop - scrollY;
|
||||
// if(shouldResolve && urisInList) {
|
||||
// resolveUris(urisInList);
|
||||
// }
|
||||
// }
|
||||
|
||||
handleArrowButtonsOnScroll() {
|
||||
// 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 showScrollButtons = isCommunityTopBids ? !obscureNsfw : true;
|
||||
|
||||
let channelLink;
|
||||
if (categoryLink) {
|
||||
channelLink = formatLbryUriForWeb(categoryLink);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="media-group--row">
|
||||
<header className="media-group__header">
|
||||
|
@ -268,11 +276,7 @@ class CategoryList extends PureComponent<Props, State> {
|
|||
{categoryLink ? (
|
||||
<div className="channel-info__actions">
|
||||
<div className="channel-info__actions__group">
|
||||
<Button
|
||||
label={category}
|
||||
navigate="/show"
|
||||
navigateParams={{ uri: categoryLink, page: 1 }}
|
||||
/>
|
||||
<Button label={category} navigate={channelLink} />
|
||||
<SubscribeButton
|
||||
button="alt"
|
||||
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'
|
||||
)}{' '}
|
||||
<Button button="link" navigate="/settings" label={__('here')} />.
|
||||
<Button button="link" navigate="/$/settings" label={__('here')} />.
|
||||
</p>
|
||||
) : (
|
||||
<ul className="media-scrollhouse" ref={this.scrollWrapper}>
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
makeSelectIsUriResolving,
|
||||
makeSelectTotalItemsForChannel,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import ChannelTile from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
@ -15,7 +14,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
});
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import TruncatedText from 'component/common/truncated-text';
|
|||
import classnames from 'classnames';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
import type { Claim } from 'types/claim';
|
||||
import { navigate } from '@reach/router';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
|
@ -13,7 +15,6 @@ type Props = {
|
|||
size: string,
|
||||
claim: ?Claim,
|
||||
resolveUri: string => void,
|
||||
navigate: (string, ?{}) => void,
|
||||
};
|
||||
|
||||
class ChannelTile extends React.PureComponent<Props> {
|
||||
|
@ -36,7 +37,7 @@ class ChannelTile extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { claim, navigate, isResolvingUri, totalItems, uri, size } = this.props;
|
||||
const { claim, isResolvingUri, totalItems, uri, size } = this.props;
|
||||
|
||||
let channelName;
|
||||
let subscriptionUri;
|
||||
|
@ -45,7 +46,7 @@ class ChannelTile extends React.PureComponent<Props> {
|
|||
subscriptionUri = `lbry://${claim.permanent_url}`;
|
||||
}
|
||||
|
||||
const onClick = () => navigate('/show', { uri, page: 1 });
|
||||
const onClick = () => navigate(formatLbryUriForWeb(uri));
|
||||
|
||||
return (
|
||||
<section
|
||||
|
|
|
@ -26,7 +26,7 @@ class FileExporter extends React.PureComponent<Props> {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
this.handleButtonClick = this.handleButtonClick.bind(this);
|
||||
(this: any).handleButtonClick = this.handleButtonClick.bind(this);
|
||||
}
|
||||
|
||||
handleFileCreation(filename: string, data: any) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
type IconProps = {
|
||||
size: number,
|
||||
|
@ -16,7 +16,7 @@ const buildIcon = iconStrokes => (props: IconProps) => {
|
|||
viewBox="0 0 24 24"
|
||||
width={size}
|
||||
height={size}
|
||||
fill="none"
|
||||
fill="solid"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
|
@ -114,4 +114,16 @@ export const customIcons = {
|
|||
[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" />
|
||||
),
|
||||
[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>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -46,7 +46,8 @@ class IconComponent extends React.PureComponent<Props> {
|
|||
render() {
|
||||
const { icon, tooltip, iconColor, size } = this.props;
|
||||
const Icon = customIcons[this.props.icon] || FeatherIcons[this.props.icon];
|
||||
|
||||
console.log('icon', icon);
|
||||
console.log('Icon', Icon);
|
||||
if (!Icon) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ export default class ErrorBoundary extends React.Component<Props, State> {
|
|||
button="link"
|
||||
className="load-screen__button"
|
||||
label={__('refreshing the app')}
|
||||
onClick={() => window.location.reload()}
|
||||
onClick={() => (window.location.href = '/')}
|
||||
/>{' '}
|
||||
{__('to fix it')}.
|
||||
</p>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import ExternalLink from './view';
|
||||
|
||||
const select = () => ({});
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
});
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import * as ICONS from 'constants/icons';
|
|||
import * as React from 'react';
|
||||
import { isURIValid } from 'lbry-redux';
|
||||
import Button from 'component/button';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
type Props = {
|
||||
href: string,
|
||||
|
@ -45,14 +46,7 @@ class ExternalLink extends React.PureComponent<Props> {
|
|||
|
||||
// Return local link if protocol is lbry uri
|
||||
if (protocol && protocol[0] === 'lbry:' && isURIValid(href)) {
|
||||
element = (
|
||||
<Button
|
||||
button="link"
|
||||
title={title || href}
|
||||
label={children}
|
||||
onClick={() => navigate('/show', { uri: href })}
|
||||
/>
|
||||
);
|
||||
element = <Button button="link" title={title || href} label={children} navigate={href} />;
|
||||
}
|
||||
|
||||
return element;
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
makeSelectClaimIsPending,
|
||||
} from 'lbry-redux';
|
||||
import { selectRewardContentClaimIds } from 'lbryinc';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { makeSelectContentPositionForUri } from 'redux/selectors/content';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
||||
|
@ -31,7 +30,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||
});
|
||||
|
|
|
@ -11,13 +11,14 @@ import classnames from 'classnames';
|
|||
import FilePrice from 'component/filePrice';
|
||||
import { openCopyLinkMenu } from 'util/context-menu';
|
||||
import DateTime from 'component/dateTime';
|
||||
import { navigate } from '@reach/router';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
claim: ?Claim,
|
||||
fileInfo: ?{},
|
||||
metadata: ?Metadata,
|
||||
navigate: (string, ?{}) => void,
|
||||
rewardedContentClaimIds: Array<string>,
|
||||
obscureNsfw: boolean,
|
||||
claimIsMine: boolean,
|
||||
|
@ -61,7 +62,6 @@ class FileCard extends React.PureComponent<Props> {
|
|||
claim,
|
||||
fileInfo,
|
||||
metadata,
|
||||
navigate,
|
||||
rewardedContentClaimIds,
|
||||
obscureNsfw,
|
||||
claimIsMine,
|
||||
|
@ -108,11 +108,16 @@ class FileCard extends React.PureComponent<Props> {
|
|||
}
|
||||
};
|
||||
|
||||
const onClick = e => {
|
||||
e.stopPropagation();
|
||||
navigate(formatLbryUriForWeb(uri));
|
||||
};
|
||||
|
||||
return (
|
||||
<li
|
||||
tabIndex="0"
|
||||
role="button"
|
||||
onClick={!pending ? () => navigate('/show', { uri }) : () => {}}
|
||||
onClick={!pending && claim ? onClick : () => {}}
|
||||
className={classnames('media-card', {
|
||||
'card--link': !pending,
|
||||
'media--pending': pending,
|
||||
|
|
|
@ -21,7 +21,6 @@ class FileListSearch extends React.PureComponent<Props> {
|
|||
<React.Fragment>
|
||||
<div className="search__results">
|
||||
<section className="search__results-section">
|
||||
<div className="search__results-title">{__('Search Results')}</div>
|
||||
<HiddenNsfwClaims uris={uris} />
|
||||
{!isSearching && uris && uris.length ? (
|
||||
uris.map(uri =>
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from 'lbry-redux';
|
||||
import { selectRewardContentClaimIds } from 'lbryinc';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doClearPublish, doUpdatePublishForm } from 'redux/actions/publish';
|
||||
import { makeSelectIsSubscribed, makeSelectIsNew } from 'redux/selectors/subscriptions';
|
||||
import FileTile from './view';
|
||||
|
@ -28,7 +27,6 @@ const select = (state, props) => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
clearPublish: () => dispatch(doClearPublish()),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
updatePublishForm: value => dispatch(doUpdatePublishForm(value)),
|
||||
});
|
||||
|
|
|
@ -12,6 +12,8 @@ import FilePrice from 'component/filePrice';
|
|||
import UriIndicator from 'component/uriIndicator';
|
||||
import DateTime from 'component/dateTime';
|
||||
import Yrbl from 'component/yrbl';
|
||||
import { navigate } from '@reach/router';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
obscureNsfw: boolean,
|
||||
|
@ -23,7 +25,6 @@ type Props = {
|
|||
claim: ?Claim,
|
||||
metadata: ?Metadata,
|
||||
resolveUri: string => void,
|
||||
navigate: (string, ?{}) => void,
|
||||
clearPublish: () => void,
|
||||
updatePublishForm: ({}) => void,
|
||||
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,
|
||||
metadata,
|
||||
isResolvingUri,
|
||||
navigate,
|
||||
obscureNsfw,
|
||||
claimIsMine,
|
||||
clearPublish,
|
||||
|
@ -115,7 +115,7 @@ class FileTile extends React.PureComponent<Props> {
|
|||
return displayHiddenMessage ? (
|
||||
<span className="help">
|
||||
{__('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')}.
|
||||
</span>
|
||||
) : null;
|
||||
|
@ -136,7 +136,7 @@ class FileTile extends React.PureComponent<Props> {
|
|||
|
||||
const wrapperProps = name
|
||||
? {
|
||||
onClick: () => navigate('/show', { uri }),
|
||||
onClick: () => navigate(formatLbryUriForWeb(uri)),
|
||||
role: 'button',
|
||||
}
|
||||
: {};
|
||||
|
|
|
@ -3,7 +3,6 @@ import * as settings from 'constants/settings';
|
|||
import { doChangeVolume } from 'redux/actions/app';
|
||||
import { selectVolume } from 'redux/selectors/app';
|
||||
import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doClaimEligiblePurchaseRewards, makeSelectCostInfoForUri } from 'lbryinc';
|
||||
import {
|
||||
makeSelectMetadataForUri,
|
||||
|
@ -45,7 +44,6 @@ const perform = dispatch => ({
|
|||
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
||||
savePosition: (claimId, outpoint, position) =>
|
||||
dispatch(savePosition(claimId, outpoint, position)),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectBalance, selectIsBackDisabled, selectIsForwardDisabled } from 'lbry-redux';
|
||||
import { selectBalance } from 'lbry-redux';
|
||||
import { formatCredits } from 'util/format-credits';
|
||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||
import { selectIsUpgradeAvailable, selectAutoUpdateDownloaded } from 'redux/selectors/app';
|
||||
import { doDownloadUpgradeRequested } from 'redux/actions/app';
|
||||
import Header from './view';
|
||||
|
@ -11,15 +10,10 @@ const select = state => ({
|
|||
balance: selectBalance(state),
|
||||
isUpgradeAvailable: selectIsUpgradeAvailable(state),
|
||||
roundedBalance: formatCredits(selectBalance(state) || 0, 2),
|
||||
isBackDisabled: selectIsBackDisabled(state),
|
||||
isForwardDisabled: selectIsForwardDisabled(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
downloadUpgradeRequested: () => dispatch(doDownloadUpgradeRequested()),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
back: () => dispatch(doHistoryBack()),
|
||||
forward: () => dispatch(doHistoryForward()),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -15,7 +15,6 @@ type Props = {
|
|||
back: () => void,
|
||||
forward: () => void,
|
||||
downloadUpgradeRequested: any => void,
|
||||
navigate: any => void,
|
||||
};
|
||||
|
||||
const Header = (props: Props) => {
|
||||
|
@ -24,7 +23,6 @@ const Header = (props: Props) => {
|
|||
balance,
|
||||
downloadUpgradeRequested,
|
||||
isUpgradeAvailable,
|
||||
navigate,
|
||||
roundedBalance,
|
||||
back,
|
||||
isBackDisabled,
|
||||
|
@ -38,6 +36,7 @@ const Header = (props: Props) => {
|
|||
return (
|
||||
<header className="header">
|
||||
<div className="header__navigation">
|
||||
{/* @if TARGET='app' */}
|
||||
<Button
|
||||
className="header__navigation-item header__navigation-item--wallet"
|
||||
description={__('Your wallet')}
|
||||
|
@ -48,25 +47,23 @@ const Header = (props: Props) => {
|
|||
<LbcSymbol />
|
||||
</React.Fragment>
|
||||
}
|
||||
onClick={() => navigate('/wallet')}
|
||||
navigate="/$/wallet"
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="header__navigation-item header__navigation-item--back"
|
||||
description={__('Navigate back')}
|
||||
disabled={isBackDisabled}
|
||||
onClick={() => window.history.back()}
|
||||
icon={ICONS.ARROW_LEFT}
|
||||
iconSize={15}
|
||||
onClick={back}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="header__navigation-item header__navigation-item--forward"
|
||||
description={__('Navigate forward')}
|
||||
disabled={isForwardDisabled}
|
||||
onClick={() => window.history.forward()}
|
||||
icon={ICONS.ARROW_RIGHT}
|
||||
iconSize={15}
|
||||
onClick={forward}
|
||||
/>
|
||||
|
||||
<Button
|
||||
|
@ -74,8 +71,17 @@ const Header = (props: Props) => {
|
|||
description={__('Home')}
|
||||
icon={ICONS.HOME}
|
||||
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>
|
||||
|
||||
<WunderBar />
|
||||
|
@ -94,7 +100,7 @@ const Header = (props: Props) => {
|
|||
icon={ICONS.UPLOAD}
|
||||
iconSize={24}
|
||||
label={isUpgradeAvailable ? '' : __('Publish')}
|
||||
onClick={() => navigate('/publish')}
|
||||
navigate="/$/publish"
|
||||
/>
|
||||
|
||||
{/* @if TARGET='app' */}
|
||||
|
|
|
@ -16,7 +16,7 @@ export default (props: Props) => {
|
|||
<div className={className || 'help'}>
|
||||
{numberOfNsfwClaims} {numberOfNsfwClaims > 1 ? __('files') : __('file')}{' '}
|
||||
{__('hidden due to your')}{' '}
|
||||
<Button button="link" navigate="/settings" label={__('content viewing preferences')} />.
|
||||
<Button button="link" navigate="/$/settings" label={__('content viewing preferences')} />.
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
|
|
@ -95,7 +95,7 @@ class InviteNew extends React.PureComponent<Props> {
|
|||
/>
|
||||
|
||||
<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')}{' '}
|
||||
<Button button="link" label={__('FAQ')} href="https://lbry.com/faq/referrals" />{' '}
|
||||
{__('to learn more about referrals')}.
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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';
|
||||
|
||||
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);
|
||||
export default Page;
|
||||
|
|
|
@ -91,11 +91,6 @@ class Page extends React.PureComponent<Props, State> {
|
|||
'main--extra-padding': extraPadding,
|
||||
})}
|
||||
>
|
||||
{pageTitle && (
|
||||
<div className="page__header">
|
||||
{pageTitle && <h1 className="page__title">{pageTitle}</h1>}
|
||||
</div>
|
||||
)}
|
||||
{!loading && children}
|
||||
{showLoader && (
|
||||
<div className="page__empty">
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectRewardByType, makeSelectIsRewardClaimPending, doClaimRewardType } from 'lbryinc';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import RewardLink from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
@ -10,7 +9,6 @@ const select = (state, props) => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, { notifyError: true })),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -51,7 +51,7 @@ class RewardSummary extends React.Component<Props> {
|
|||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
navigate="/rewards"
|
||||
navigate="/$/rewards"
|
||||
label={hasRewards ? __('Claim Rewards') : __('View Rewards')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,7 @@ const RewardTile = (props: Props) => {
|
|||
<Button button="primary" onClick={openRewardCodeModal} label={__('Enter Code')} />
|
||||
)}
|
||||
{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 &&
|
||||
(claimed ? (
|
||||
|
|
|
@ -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';
|
||||
|
||||
const select = state => ({
|
||||
params: selectCurrentParams(state),
|
||||
currentPage: selectCurrentPage(state),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
{ doOpenModal, doToast }
|
||||
)(Router);
|
||||
export default Router;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import { Router } from '@reach/router';
|
||||
import SettingsPage from 'page/settings';
|
||||
import HelpPage from 'page/help';
|
||||
import ReportPage from 'page/report';
|
||||
import WalletPage from 'page/wallet';
|
||||
import GetCreditsPage from 'page/getCredits';
|
||||
import SendReceivePage from 'page/sendCredits';
|
||||
import ShowPage from 'page/show';
|
||||
import PublishPage from 'page/publish';
|
||||
import DiscoverPage from 'page/discover';
|
||||
|
@ -12,7 +12,6 @@ import RewardsPage from 'page/rewards';
|
|||
import FileListDownloaded from 'page/fileListDownloaded';
|
||||
import FileListPublished from 'page/fileListPublished';
|
||||
import TransactionHistoryPage from 'page/transactionHistory';
|
||||
import ChannelPage from 'page/channel';
|
||||
import AuthPage from 'page/auth';
|
||||
import InvitePage from 'page/invite';
|
||||
import BackupPage from 'page/backup';
|
||||
|
@ -20,41 +19,28 @@ import SubscriptionsPage from 'page/subscriptions';
|
|||
import SearchPage from 'page/search';
|
||||
import UserHistoryPage from 'page/userHistory';
|
||||
|
||||
const route = (props, page, routesMap) => {
|
||||
const component = routesMap[page];
|
||||
if (!component) {
|
||||
props.doToast({
|
||||
message: __('Invalid page requested'),
|
||||
});
|
||||
}
|
||||
return component || routesMap.discover;
|
||||
};
|
||||
export default function AppRouter(props) {
|
||||
return (
|
||||
<Router>
|
||||
<DiscoverPage path="/" />
|
||||
<ShowPage path="/:claimName/:claimId" />
|
||||
<ShowPage path="/:claimName" />
|
||||
|
||||
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;
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import Button from 'component/button';
|
|||
|
||||
const ExpandableOptions = posed.div({
|
||||
hide: { height: 0, opacity: 0 },
|
||||
show: { height: 280, opacity: 1 },
|
||||
show: { height: 300, opacity: 1 },
|
||||
});
|
||||
|
||||
type Props = {
|
||||
|
@ -34,11 +34,11 @@ const SearchOptions = (props: Props) => {
|
|||
const resultCount = options[SEARCH_OPTIONS.RESULT_COUNT];
|
||||
|
||||
return (
|
||||
<div className="card card--section search__options-wrapper">
|
||||
<div className="search__options-wrapper">
|
||||
<div className="card--space-between">
|
||||
<Button
|
||||
button="alt"
|
||||
label={__('ADVANCED SEARCH')}
|
||||
label={__('FILTER')}
|
||||
iconRight={expanded ? ICONS.UP : ICONS.DOWN}
|
||||
onClick={toggleSearchExpanded}
|
||||
/>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectNavLinks } from 'redux/selectors/app';
|
||||
import { selectUnreadAmount } from 'redux/selectors/subscriptions';
|
||||
import SideBar from './view';
|
||||
|
||||
const select = state => ({
|
||||
navLinks: selectNavLinks(state),
|
||||
unreadSubscriptionTotal: selectUnreadAmount(state),
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import Button from 'component/button';
|
||||
import classnames from 'classnames';
|
||||
|
@ -14,86 +16,96 @@ type SideBarLink = {
|
|||
};
|
||||
|
||||
type Props = {
|
||||
navLinks: {
|
||||
primary: Array<SideBarLink>,
|
||||
secondary: Array<SideBarLink>,
|
||||
},
|
||||
unreadSubscriptionTotal: number,
|
||||
};
|
||||
|
||||
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() {
|
||||
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 (
|
||||
<nav className="navigation">
|
||||
<div className="navigation__links">
|
||||
{navLinks.primary.map(({ label, path, active, icon }) => (
|
||||
<Button
|
||||
icon={icon}
|
||||
className={classnames('navigation__link', {
|
||||
'navigation__link--active': active,
|
||||
})}
|
||||
key={path}
|
||||
label={
|
||||
path === '/subscriptions' && unreadSubscriptionTotal
|
||||
? `${label} (${unreadSubscriptionTotal})`
|
||||
: label
|
||||
}
|
||||
navigate={path}
|
||||
/>
|
||||
))}
|
||||
<ul className="navigation__links">
|
||||
{[
|
||||
{
|
||||
...buildLink(null, __('Home'), ICONS.HOME),
|
||||
},
|
||||
{
|
||||
...buildLink(
|
||||
PAGES.SUBSCRIPTIONS,
|
||||
`${__('Subscriptions')} ${
|
||||
unreadSubscriptionTotal > 0 ? '(' + unreadSubscriptionTotal + ')' : ''
|
||||
}`,
|
||||
ICONS.SUBSCRIPTION
|
||||
),
|
||||
},
|
||||
].map(renderLink)}
|
||||
</ul>
|
||||
|
||||
<div className="navigation__link navigation__link--title">My LBRY</div>
|
||||
|
||||
<div className="navigation__links">
|
||||
<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>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectClaimedRewardsByTransactionId } from 'lbryinc';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import {
|
||||
selectAllMyClaimsByOutpoint,
|
||||
|
@ -16,7 +15,6 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
setTransactionFilter: filterSetting => dispatch(doSetTransactionListFilter(filterSetting)),
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
import type { Transaction } from 'types/transaction';
|
||||
import * as TXN_TYPES from 'constants/transaction_types';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import ButtonTransaction from 'component/common/transaction-link';
|
||||
|
@ -7,7 +8,7 @@ import CreditAmount from 'component/common/credit-amount';
|
|||
import DateTime from 'component/dateTime';
|
||||
import Button from 'component/button';
|
||||
import { buildURI } from 'lbry-redux';
|
||||
import * as txnTypes from 'constants/transaction_types';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
transaction: Transaction,
|
||||
|
@ -26,7 +27,7 @@ class TransactionListItem extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
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.DELETE} onClick={this.abandonClaim} title={__('Abandon Claim')} />;
|
||||
|
@ -68,12 +69,7 @@ class TransactionListItem extends React.PureComponent<Props> {
|
|||
<td className="table__item--actionable">
|
||||
{reward && <span>{reward.reward_title}</span>}
|
||||
{name && claimId && (
|
||||
<Button
|
||||
constrict
|
||||
button="link"
|
||||
navigate="/show"
|
||||
navigateParams={{ uri: buildURI({ claimName: name, claimId }) }}
|
||||
>
|
||||
<Button constrict button="link" navigate={buildURI({ claimName: name, claimId })}>
|
||||
{name}
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
@ -105,12 +105,10 @@ class TransactionList extends React.PureComponent<Props> {
|
|||
</div>
|
||||
)}
|
||||
</header>
|
||||
{!transactionList.length && (
|
||||
<p className="card__content">{emptyMessage || __('No transactions to list.')}</p>
|
||||
)}
|
||||
{!transactionList.length && <p>{emptyMessage || __('No transactions to list.')}</p>}
|
||||
|
||||
{!!transactionList.length && (
|
||||
<div className="card__content">
|
||||
<React.Fragment>
|
||||
<table className="table table--transactions">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -133,7 +131,7 @@ class TransactionList extends React.PureComponent<Props> {
|
|||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -35,7 +35,7 @@ class TransactionListRecent extends React.PureComponent<Props> {
|
|||
|
||||
<p className="card__subtitle">
|
||||
{__('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>
|
||||
</header>
|
||||
|
||||
|
@ -53,15 +53,15 @@ class TransactionListRecent extends React.PureComponent<Props> {
|
|||
transactions={transactions}
|
||||
emptyMessage={__("Looks like you don't have any recent transactions.")}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
navigate="/history"
|
||||
navigate="/$/history"
|
||||
label={__('Full History')}
|
||||
icon={icons.HISTORY}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
</section>
|
||||
|
|
|
@ -57,12 +57,7 @@ class UriIndicator extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
noPadding
|
||||
className="button--uri-indicator"
|
||||
navigate="/show"
|
||||
navigateParams={{ uri: channelLink, page: 1 }}
|
||||
>
|
||||
<Button noPadding className="button--uri-indicator" navigate={channelLink}>
|
||||
{inner}
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
doUserCheckEmailVerified,
|
||||
selectUser,
|
||||
} from 'lbryinc';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import UserEmailVerify from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -16,7 +15,6 @@ const select = state => ({
|
|||
const perform = dispatch => ({
|
||||
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
||||
checkEmailVerified: () => dispatch(doUserCheckEmailVerified()),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux';
|
||||
import { doClearContentHistoryUri } from 'redux/actions/content';
|
||||
import UserHistory from './view';
|
||||
|
||||
const select = state => {
|
||||
const paramPage = Number(makeSelectCurrentParam('page')(state) || 0);
|
||||
const select = (state, props) => {
|
||||
const { search } = props.location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const page = Number(urlParams.get('page')) || 0;
|
||||
|
||||
return {
|
||||
page,
|
||||
pageCount: selectHistoryPageCount(state),
|
||||
page: paramPage,
|
||||
params: selectCurrentParams(state),
|
||||
history: makeSelectHistoryForPage(paramPage)(state),
|
||||
history: makeSelectHistoryForPage(page)(state),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||
});
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import Button from 'component/button';
|
|||
import { Form, FormField } from 'component/common/form';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
import UserHistoryItem from 'component/userHistoryItem';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
type HistoryItem = {
|
||||
uri: string,
|
||||
|
@ -14,7 +15,6 @@ type Props = {
|
|||
history: Array<HistoryItem>,
|
||||
page: number,
|
||||
pageCount: number,
|
||||
navigate: (string, {}) => void,
|
||||
clearHistoryUri: string => void,
|
||||
params: { page: number },
|
||||
};
|
||||
|
@ -52,9 +52,8 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
changePage(pageNumber: number) {
|
||||
const { params } = this.props;
|
||||
const newParams = { ...params, page: pageNumber };
|
||||
this.props.navigate('/user_history', newParams);
|
||||
console.log('new', pageNumber);
|
||||
navigate(`/$/user_history?page=${pageNumber}`);
|
||||
}
|
||||
|
||||
paginate(e: SyntheticKeyboardEvent<*>) {
|
||||
|
@ -94,7 +93,8 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { history, page, pageCount } = this.props;
|
||||
const { history = [], page, pageCount } = this.props;
|
||||
console.log('this.props', this.props);
|
||||
const { itemsSelected } = this.state;
|
||||
const allSelected = Object.keys(itemsSelected).length === history.length;
|
||||
const selectHandler = allSelected ? this.unselectAll : this.selectAll;
|
||||
|
@ -148,6 +148,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
|
|||
onPageChange={e => this.changePage(e.selected)}
|
||||
forcePage={page}
|
||||
initialPage={page}
|
||||
disableInitialCallback
|
||||
containerClassName="pagination"
|
||||
/>
|
||||
</fieldset-section>
|
||||
|
@ -175,7 +176,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
|
|||
|
||||
<div className="card__content">
|
||||
<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>
|
||||
</section>
|
||||
|
|
|
@ -51,8 +51,7 @@ class UserHistoryItem extends React.PureComponent<Props> {
|
|||
constrict
|
||||
button="link"
|
||||
label={name ? `lbry://${name}` : `lbry://...`}
|
||||
navigate="/show"
|
||||
navigateParams={{ uri }}
|
||||
navigate={uri}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as MODALS from 'constants/modal_types';
|
||||
import { connect } from 'react-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import {
|
||||
doUserIdentityVerify,
|
||||
rewards,
|
||||
|
@ -22,7 +21,6 @@ const select = state => {
|
|||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: uri => dispatch(doNavigate(uri)),
|
||||
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
|
||||
verifyPhone: () => dispatch(doOpenModal(MODALS.PHONE_COLLECTION)),
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ import { Lbryio } from 'lbryinc';
|
|||
type Props = {
|
||||
errorMessage: ?string,
|
||||
isPending: boolean,
|
||||
navigate: string => void,
|
||||
verifyUserIdentity: string => void,
|
||||
verifyPhone: () => void,
|
||||
};
|
||||
|
@ -25,7 +24,7 @@ class UserVerify extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { errorMessage, isPending, navigate, verifyPhone } = this.props;
|
||||
const { errorMessage, isPending, verifyPhone } = this.props;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<section className="card card--section">
|
||||
|
@ -137,11 +136,7 @@ class UserVerify extends React.PureComponent<Props> {
|
|||
|
||||
<div className="card__content">
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
onClick={() => navigate('/discover')}
|
||||
button="primary"
|
||||
label={__('Skip Rewards')}
|
||||
/>
|
||||
<Button navigate="/" button="primary" label={__('Skip Rewards')} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
import * as React from 'react';
|
||||
import { stopContextMenu } from 'util/context-menu';
|
||||
import Button from 'component/button';
|
||||
// @if TARGET='app'
|
||||
import { shell } from 'electron';
|
||||
// @endif
|
||||
|
||||
type Props = {
|
||||
source: string,
|
||||
|
@ -22,7 +24,12 @@ class PdfViewer extends React.PureComponent<Props> {
|
|||
openFile() {
|
||||
const { source } = this.props;
|
||||
const path = `file://${source}`;
|
||||
// @if TARGET='app'
|
||||
shell.openExternal(path);
|
||||
// @endif
|
||||
// @if TARGET='web'
|
||||
console.error('provide stub for shell.openExternal');
|
||||
// @endif
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -12,7 +12,7 @@ const WalletBalance = (props: Props) => {
|
|||
return (
|
||||
<section
|
||||
className="card card--section card--wallet-balance"
|
||||
style={{ backgroundImage: `url(${BalanceBackground})` }}
|
||||
style={{ backgroundImage: `url(/${BalanceBackground})` }}
|
||||
>
|
||||
<header className="card__header">
|
||||
<h2 className="card__title">{__('Balance')}</h2>
|
||||
|
|
|
@ -1,44 +1,38 @@
|
|||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectSearchState as selectSearch,
|
||||
selectWunderBarAddress,
|
||||
selectSearchSuggestions,
|
||||
doUpdateSearchQuery,
|
||||
doFocusSearchInput,
|
||||
doBlurSearchInput,
|
||||
doUpdateSearchQuery,
|
||||
doSearch,
|
||||
doToast,
|
||||
selectSearchValue,
|
||||
selectSearchSuggestions,
|
||||
selectSearchBarFocused,
|
||||
parseURI,
|
||||
} from 'lbry-redux';
|
||||
import analytics from 'analytics';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import Wunderbar from './view';
|
||||
import { navigate } from '@reach/router';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
const select = state => {
|
||||
const { isActive, searchQuery, ...searchState } = selectSearch(state);
|
||||
const address = selectWunderBarAddress(state);
|
||||
|
||||
// if we are on the file/channel page
|
||||
// use the address in the history stack
|
||||
const wunderbarValue = isActive ? searchQuery : searchQuery || address;
|
||||
|
||||
return {
|
||||
...searchState,
|
||||
wunderbarValue,
|
||||
const select = state => ({
|
||||
suggestions: selectSearchSuggestions(state),
|
||||
};
|
||||
};
|
||||
searchQuery: selectSearchValue(state),
|
||||
isFocused: selectSearchBarFocused(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
onSearch: query => {
|
||||
dispatch(doSearch(query));
|
||||
dispatch(doNavigate(`/search`, { query }));
|
||||
navigate(`/$/search?q=${query}`);
|
||||
analytics.apiLogSearch();
|
||||
},
|
||||
onSubmit: (uri, extraParams) => dispatch(doNavigate('/show', { uri, ...extraParams })),
|
||||
onSubmit: uri => {
|
||||
const path = formatLbryUriForWeb(uri);
|
||||
navigate(path);
|
||||
dispatch(doUpdateSearchQuery(''));
|
||||
},
|
||||
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
||||
doFocus: () => dispatch(doFocusSearchInput()),
|
||||
doBlur: () => dispatch(doBlurSearchInput()),
|
||||
doShowSnackBar: props => dispatch(doToast(props)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { normalizeURI, SEARCH_TYPES, isURIValid } from 'lbry-redux';
|
||||
import { normalizeURI, SEARCH_TYPES, isURIValid, buildURI } from 'lbry-redux';
|
||||
import Icon from 'component/common/icon';
|
||||
import { parseQueryParams } from 'util/query-params';
|
||||
import Autocomplete from './internal/autocomplete';
|
||||
import { Location, navigate } from '@reach/router';
|
||||
|
||||
const L_KEY_CODE = 76;
|
||||
const ESC_KEY_CODE = 27;
|
||||
|
||||
type Props = {
|
||||
searchQuery: ?string,
|
||||
updateSearchQuery: string => void,
|
||||
onSearch: string => void,
|
||||
onSubmit: (string, {}) => void,
|
||||
onSubmit: string => void,
|
||||
wunderbarValue: ?string,
|
||||
suggestions: Array<string>,
|
||||
doFocus: () => void,
|
||||
|
@ -22,10 +25,18 @@ type Props = {
|
|||
doShowSnackBar: ({}) => void,
|
||||
};
|
||||
|
||||
class WunderBar extends React.PureComponent<Props> {
|
||||
type State = {
|
||||
query: ?string,
|
||||
};
|
||||
|
||||
class WunderBar extends React.PureComponent<Props, State> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
query: null,
|
||||
};
|
||||
|
||||
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||
(this: any).handleChange = this.handleChange.bind(this);
|
||||
(this: any).handleKeyDown = this.handleKeyDown.bind(this);
|
||||
|
@ -61,6 +72,7 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
return;
|
||||
}
|
||||
|
||||
// @if TARGET='app'
|
||||
const shouldFocus =
|
||||
process.platform === 'darwin'
|
||||
? keyCode === L_KEY_CODE && metaKey
|
||||
|
@ -70,30 +82,20 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
this.input.focus();
|
||||
doFocus();
|
||||
}
|
||||
// @endif
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(e: SyntheticInputEvent<*>) {
|
||||
const { updateSearchQuery } = this.props;
|
||||
const { value } = e.target;
|
||||
|
||||
const { updateSearchQuery } = this.props;
|
||||
updateSearchQuery(value);
|
||||
}
|
||||
|
||||
handleSubmit(value: string, suggestion?: { value: string, type: string }) {
|
||||
const { onSubmit, onSearch, doShowSnackBar } = this.props;
|
||||
|
||||
const query = value.trim();
|
||||
const getParams = () => {
|
||||
const parts = query.split('?');
|
||||
|
||||
let extraParams = {};
|
||||
if (parts.length > 0) {
|
||||
extraParams = parseQueryParams(parts.join(''));
|
||||
}
|
||||
|
||||
return extraParams;
|
||||
};
|
||||
|
||||
const showSnackError = () => {
|
||||
doShowSnackBar({
|
||||
message: __('Invalid LBRY URL entered. Only A-Z, a-z, 0-9, and "-" allowed.'),
|
||||
|
@ -105,23 +107,20 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
if (suggestion.type === 'search') {
|
||||
onSearch(query);
|
||||
} else if (isURIValid(query)) {
|
||||
const params = getParams();
|
||||
const uri = normalizeURI(query);
|
||||
onSubmit(uri, params);
|
||||
onSubmit(uri);
|
||||
} else {
|
||||
showSnackError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Currently no suggestion is highlighted. The user may have started
|
||||
// typing, then lost focus and came back later on the same page
|
||||
try {
|
||||
if (isURIValid(query)) {
|
||||
const uri = normalizeURI(query);
|
||||
const params = getParams();
|
||||
onSubmit(uri, params);
|
||||
onSubmit(uri);
|
||||
} else {
|
||||
showSnackError();
|
||||
}
|
||||
|
@ -133,7 +132,7 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
input: ?HTMLInputElement;
|
||||
|
||||
render() {
|
||||
const { wunderbarValue, suggestions, doFocus, doBlur } = this.props;
|
||||
const { suggestions, doFocus, doBlur, searchQuery } = this.props;
|
||||
|
||||
return (
|
||||
<div className="wunderbar">
|
||||
|
@ -141,7 +140,7 @@ class WunderBar extends React.PureComponent<Props> {
|
|||
<Autocomplete
|
||||
autoHighlight
|
||||
wrapperStyle={{ flex: 1, position: 'relative' }}
|
||||
value={wunderbarValue || ''}
|
||||
value={searchQuery}
|
||||
items={suggestions}
|
||||
getItemValue={item => item.value}
|
||||
onChange={this.handleChange}
|
||||
|
|
|
@ -28,7 +28,14 @@ export default class extends React.PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<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 && (
|
||||
<div className="card__content">
|
||||
<h2 className="card__title">{title}</h2>
|
||||
|
|
|
@ -48,3 +48,6 @@ export const UP = 'ChevronUp';
|
|||
export const DOWN = 'ChevronDown';
|
||||
export const SECURE = 'Lock';
|
||||
export const MENU = 'Menu';
|
||||
export const BACKUP = 'Database';
|
||||
export const TRANSACTIONS = 'FileText';
|
||||
export const LBRY = 'Lbry';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ErrorBoundary from 'component/errorBoundary';
|
||||
import App from 'component/app';
|
||||
import SnackBar from 'component/snackBar';
|
||||
import SplashScreen from 'component/splash';
|
||||
// @if TARGET='app'
|
||||
import SplashScreen from 'component/splash';
|
||||
import moment from 'moment';
|
||||
import { ipcRenderer, remote, shell } from 'electron';
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
|
@ -19,7 +19,6 @@ import {
|
|||
doHideModal,
|
||||
} from 'redux/actions/app';
|
||||
import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux';
|
||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
||||
import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc';
|
||||
import 'scss/all.scss';
|
||||
|
@ -46,11 +45,11 @@ if (process.env.SEARCH_API_URL) {
|
|||
|
||||
// @if TARGET='app'
|
||||
ipcRenderer.on('navigate-backward', () => {
|
||||
app.store.dispatch(doHistoryBack());
|
||||
// app.store.dispatch(doHistoryBack());
|
||||
});
|
||||
|
||||
ipcRenderer.on('navigate-forward', () => {
|
||||
app.store.dispatch(doHistoryForward());
|
||||
// app.store.dispatch(doHistoryForward());
|
||||
});
|
||||
// @endif
|
||||
|
||||
|
@ -132,9 +131,9 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
|||
app.store.dispatch(doConditionalAuthNavigate(newSession));
|
||||
} else if (uri.startsWith(APPPAGEURL)) {
|
||||
const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
|
||||
app.store.dispatch(doNavigate(`/${navpage}`));
|
||||
// app.store.dispatch(doNavigate(`/${navpage}`));
|
||||
} else if (isURIValid(uri)) {
|
||||
app.store.dispatch(doNavigate('/show', { uri }));
|
||||
// app.store.dispatch(doNavigate('/show', { uri }));
|
||||
} else {
|
||||
app.store.dispatch(
|
||||
doToast({
|
||||
|
@ -147,7 +146,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
|||
|
||||
ipcRenderer.on('open-menu', (event, uri) => {
|
||||
if (uri && uri.startsWith('/help')) {
|
||||
app.store.dispatch(doNavigate('/help'));
|
||||
// app.store.dispatch(doNavigate('/help'));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -233,9 +232,11 @@ const init = () => {
|
|||
app.store.dispatch(doBlackListedOutpointsSubscribe());
|
||||
|
||||
function onDaemonReady() {
|
||||
// @if TARGET='app'
|
||||
window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again
|
||||
app.store.dispatch(doDaemonReady());
|
||||
// @endif
|
||||
|
||||
app.store.dispatch(doDaemonReady());
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<ErrorBoundary>
|
||||
|
@ -245,11 +246,9 @@ const init = () => {
|
|||
</Provider>,
|
||||
document.getElementById('app')
|
||||
);
|
||||
// @if TARGET='web'
|
||||
window.sessionStorage.removeItem('loaded');
|
||||
// @endif
|
||||
}
|
||||
|
||||
// @if TARGET='app'
|
||||
if (window.sessionStorage.getItem('loaded') === 'y') {
|
||||
onDaemonReady();
|
||||
} else {
|
||||
|
@ -263,6 +262,10 @@ const init = () => {
|
|||
document.getElementById('app')
|
||||
);
|
||||
}
|
||||
// @endif
|
||||
// @if TARGET='web'
|
||||
onDaemonReady();
|
||||
// @endif
|
||||
};
|
||||
|
||||
init();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc';
|
||||
import { selectBalance } from 'lbry-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import * as settings from 'constants/settings';
|
||||
import ModalCreditIntro from './view';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
const select = state => ({
|
||||
currentBalance: selectBalance(state),
|
||||
|
@ -15,8 +15,8 @@ const select = state => ({
|
|||
|
||||
const perform = dispatch => () => ({
|
||||
addBalance: () => {
|
||||
navigate('/$/getcredits');
|
||||
dispatch(doSetClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED, true));
|
||||
dispatch(doNavigate('/getcredits'));
|
||||
dispatch(doHideModal());
|
||||
},
|
||||
closeModal: () => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Modal } from 'modal/modal';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
// @if TARGET='app'
|
||||
import { shell } from 'electron';
|
||||
// @endif
|
||||
|
@ -13,10 +14,16 @@ type Props = {
|
|||
class ModalOpenExternalLink extends React.PureComponent<Props> {
|
||||
openExternalLink() {
|
||||
const { uri, closeModal } = this.props;
|
||||
// @if TARGET='app'
|
||||
const { openExternal } = shell;
|
||||
if (uri) {
|
||||
openExternal(uri);
|
||||
}
|
||||
// @endif
|
||||
// @if TARGET='web'
|
||||
window.open(uri);
|
||||
// @endif
|
||||
|
||||
closeModal();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import { selectPhoneToVerify, selectUser } from 'lbryinc';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { navigate } from '@reach/router';
|
||||
import ModalPhoneCollection from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -12,7 +12,7 @@ const select = state => ({
|
|||
const perform = dispatch => () => ({
|
||||
closeModal: () => {
|
||||
dispatch(doHideModal());
|
||||
dispatch(doNavigate('/rewards'));
|
||||
navigate('/$/rewards');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -2,12 +2,10 @@ import { connect } from 'react-redux';
|
|||
import { doHideModal } from 'redux/actions/app';
|
||||
import ModalSendTip from './view';
|
||||
import { doClearPublish } from 'redux/actions/publish';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
|
||||
const perform = dispatch => ({
|
||||
closeModal: () => dispatch(doHideModal()),
|
||||
clearPublish: () => dispatch(doClearPublish()),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
import { connect } from 'react-redux';
|
||||
import * as settings from 'constants/settings';
|
||||
import { selectBalance, selectCurrentPage, selectError, doToast } from 'lbry-redux';
|
||||
import { selectBalance, makeSelectCostInfoForUri, selectError, doToast } from 'lbry-redux';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import {
|
||||
selectUser,
|
||||
selectUserIsVerificationCandidate,
|
||||
selectCostForCurrentPageUri,
|
||||
} from 'lbryinc';
|
||||
import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc';
|
||||
import { selectModal } from 'redux/selectors/app';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import ModalRouter from './view';
|
||||
|
||||
const select = state => ({
|
||||
const select = (state, props) => ({
|
||||
balance: selectBalance(state),
|
||||
showPageCost: selectCostForCurrentPageUri(state),
|
||||
page: selectCurrentPage(state),
|
||||
showPageCost: makeSelectCostInfoForUri(props.uri)(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
isCreditIntroAcknowledged: makeSelectClientSetting(settings.CREDIT_REQUIRED_ACKNOWLEDGED)(state),
|
||||
isEmailCollectionAcknowledged: makeSelectClientSetting(settings.EMAIL_COLLECTION_ACKNOWLEDGED)(
|
||||
|
|
|
@ -113,6 +113,7 @@ class ModalRouter extends React.PureComponent<Props, State> {
|
|||
|
||||
isPaidShowPage(props: Props) {
|
||||
const { page, showPageCost } = props;
|
||||
// Fix me
|
||||
return page === 'show' && showPageCost > 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { selectPathAfterAuth } from 'lbry-redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import {
|
||||
selectAuthenticationIsPending,
|
||||
selectEmailToVerify,
|
||||
|
@ -17,16 +15,11 @@ const select = state => ({
|
|||
selectUserIsPending(state) ||
|
||||
selectIdentityVerifyIsPending(state),
|
||||
email: selectEmailToVerify(state),
|
||||
pathAfterAuth: selectPathAfterAuth(state),
|
||||
user: selectUser(state),
|
||||
isVerificationCandidate: selectUserIsVerificationCandidate(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
null
|
||||
)(AuthPage);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @flow
|
||||
import type { UrlLocation } from 'types/location';
|
||||
import React from 'react';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import Button from 'component/button';
|
||||
|
@ -6,17 +7,18 @@ import UserEmailNew from 'component/userEmailNew';
|
|||
import UserEmailVerify from 'component/userEmailVerify';
|
||||
import UserVerify from 'component/userVerify';
|
||||
import Page from 'component/page';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
type Props = {
|
||||
isPending: boolean,
|
||||
email: string,
|
||||
pathAfterAuth: string,
|
||||
location: UrlLocation,
|
||||
user: ?{
|
||||
has_verified_email: boolean,
|
||||
is_reward_approved: boolean,
|
||||
is_identity_verified: boolean,
|
||||
},
|
||||
navigate: (string, ?{}) => void,
|
||||
};
|
||||
|
||||
class AuthPage extends React.PureComponent<Props> {
|
||||
|
@ -29,14 +31,18 @@ class AuthPage extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
navigateIfAuthenticated = (props: Props) => {
|
||||
const { isPending, user, pathAfterAuth, navigate } = props;
|
||||
const { isPending, user, location } = props;
|
||||
if (
|
||||
!isPending &&
|
||||
user &&
|
||||
user.has_verified_email &&
|
||||
(user.is_reward_approved || user.is_identity_verified)
|
||||
) {
|
||||
navigate(pathAfterAuth);
|
||||
const { search } = location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const redirectTo = urlParams.get('redirect');
|
||||
const path = redirectTo ? `/$/${redirectTo}` : '/';
|
||||
navigate(path);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -56,7 +62,6 @@ class AuthPage extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { navigate } = this.props;
|
||||
const [innerContent, useTemplate] = this.renderMain();
|
||||
|
||||
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.'
|
||||
)} `}
|
||||
<Button
|
||||
button="link"
|
||||
onClick={() => navigate('/discover')}
|
||||
label={__('Return home.')}
|
||||
/>
|
||||
<Button button="link" navigate="/" label={__('Return home.')} />
|
||||
</p>
|
||||
</section>
|
||||
) : (
|
||||
|
|
|
@ -3,30 +3,24 @@ import { doFetchClaimsByChannel } from 'redux/actions/content';
|
|||
import { PAGE_SIZE } from 'constants/claim';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectClaimsInChannelForCurrentPage,
|
||||
makeSelectClaimsInChannelForCurrentPageState,
|
||||
makeSelectFetchingChannelClaims,
|
||||
makeSelectCurrentParam,
|
||||
makeSelectClaimIsMine,
|
||||
makeSelectTotalPagesForChannel,
|
||||
selectCurrentParams,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import ChannelPage from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
claimsInChannel: makeSelectClaimsInChannelForCurrentPage(props.uri)(state),
|
||||
claimsInChannel: makeSelectClaimsInChannelForCurrentPageState(props.uri)(state),
|
||||
fetching: makeSelectFetchingChannelClaims(props.uri)(state),
|
||||
page: makeSelectCurrentParam('page')(state),
|
||||
params: selectCurrentParams(state),
|
||||
totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state),
|
||||
channelIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
// @flow
|
||||
import type { Claim } from 'types/claim';
|
||||
import type { UrlLocation } from 'types/location';
|
||||
import * as icons from 'constants/icons';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import { FormField, Form } from 'component/common/form';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
|
@ -11,10 +12,10 @@ import Page from 'component/page';
|
|||
import FileList from 'component/fileList';
|
||||
import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
|
||||
import Button from 'component/button';
|
||||
import { navigate } from '@reach/router';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
page: number,
|
||||
totalPages: number,
|
||||
fetching: boolean,
|
||||
params: { page: number },
|
||||
|
@ -24,32 +25,42 @@ type Props = {
|
|||
fetchClaims: (string, number) => void,
|
||||
navigate: (string, {}) => void,
|
||||
openModal: (id: string, { uri: string }) => void,
|
||||
location: UrlLocation,
|
||||
};
|
||||
|
||||
class ChannelPage extends React.PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const { uri, page, fetchClaims } = this.props;
|
||||
fetchClaims(uri, page || 1);
|
||||
}
|
||||
function ChannelPage(props: Props) {
|
||||
const {
|
||||
uri,
|
||||
fetching,
|
||||
claimsInChannel,
|
||||
claim,
|
||||
totalPages,
|
||||
channelIsMine,
|
||||
openModal,
|
||||
fetchClaims,
|
||||
location,
|
||||
} = props;
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const { page, fetchClaims, uri } = this.props;
|
||||
const { name, permanent_url: permanentUrl } = claim;
|
||||
const { search } = location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const page = Number(urlParams.get('page')) || 1;
|
||||
|
||||
if (prevProps.page && prevProps.page && page !== prevProps.page) {
|
||||
useEffect(() => {
|
||||
// Fetch new claims if the channel or page number changes
|
||||
fetchClaims(uri, page);
|
||||
}
|
||||
}, [uri, page]);
|
||||
|
||||
const changePage = (pageNumber: number) => {
|
||||
if (!page && pageNumber === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
changePage(pageNumber: number) {
|
||||
const { params } = this.props;
|
||||
const newParams = Object.assign({}, params, { page: pageNumber });
|
||||
navigate(`?page=${pageNumber}`);
|
||||
};
|
||||
|
||||
this.props.navigate('/show', newParams);
|
||||
}
|
||||
|
||||
paginate(e: SyntheticKeyboardEvent<*>, totalPages: number) {
|
||||
// Change page if enter was pressed, and the given page is between
|
||||
// the first and the last.
|
||||
const paginate = (e: SyntheticKeyboardEvent<*>) => {
|
||||
// Change page if enter was pressed, and the given page is between the first and the last page
|
||||
const pageFromInput = Number(e.currentTarget.value);
|
||||
|
||||
if (
|
||||
|
@ -59,29 +70,9 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
pageFromInput > 0 &&
|
||||
pageFromInput <= totalPages
|
||||
) {
|
||||
this.changePage(pageFromInput);
|
||||
changePage(pageFromInput);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
uri,
|
||||
fetching,
|
||||
claimsInChannel,
|
||||
claim,
|
||||
page,
|
||||
totalPages,
|
||||
channelIsMine,
|
||||
openModal,
|
||||
} = this.props;
|
||||
const { name, permanent_url: permanentUrl } = claim;
|
||||
const currentPage = parseInt((page || 1) - 1, 10);
|
||||
const contentList =
|
||||
claimsInChannel && claimsInChannel.length ? (
|
||||
<FileList sortByHeight hideFilter fileInfos={claimsInChannel} />
|
||||
) : (
|
||||
!fetching && <span className="empty">{__('No content found.')}</span>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page notContained>
|
||||
|
@ -90,6 +81,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
{name}
|
||||
{fetching && <BusyIndicator />}
|
||||
</h1>
|
||||
<span>{`lbry://${permanentUrl}`}</span>
|
||||
|
||||
<div className="channel-info__actions__group">
|
||||
<SubscribeButton uri={`lbry://${permanentUrl}`} channelName={name} />
|
||||
|
@ -104,7 +96,13 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
</div>
|
||||
</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 && (
|
||||
<Form>
|
||||
|
@ -121,16 +119,17 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
nextClassName="pagination__item pagination__item--next"
|
||||
breakClassName="pagination__item pagination__item--break"
|
||||
marginPagesDisplayed={2}
|
||||
onPageChange={e => this.changePage(e.selected + 1)}
|
||||
forcePage={currentPage}
|
||||
initialPage={currentPage}
|
||||
onPageChange={e => changePage(e.selected + 1)}
|
||||
forcePage={page - 1}
|
||||
initialPage={page - 1}
|
||||
disableInitialCallback
|
||||
containerClassName="pagination"
|
||||
/>
|
||||
</fieldset-section>
|
||||
|
||||
<FormField
|
||||
className="paginate-channel"
|
||||
onKeyUp={e => this.paginate(e, totalPages)}
|
||||
onKeyUp={e => paginate(e)}
|
||||
label={__('Go to page:')}
|
||||
type="text"
|
||||
name="paginate-file"
|
||||
|
@ -142,7 +141,6 @@ class ChannelPage extends React.PureComponent<Props> {
|
|||
{!channelIsMine && <HiddenNsfwClaims className="card__content help" uri={uri} />}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ChannelPage;
|
||||
|
|
|
@ -14,7 +14,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchFeaturedUris: () => dispatch(doFetchFeaturedUris(true)),
|
||||
fetchFeaturedUris: () => dispatch(doFetchFeaturedUris()),
|
||||
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
||||
fetchRewards: () => dispatch(doRewardList()),
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import * as settings from 'constants/settings';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
|
||||
import { doRemoveUnreadSubscription } from 'redux/actions/subscriptions';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
|
@ -15,10 +14,10 @@ import {
|
|||
makeSelectChannelForClaimUri,
|
||||
} from 'lbry-redux';
|
||||
import {
|
||||
makeSelectCostInfoForUri,
|
||||
doFetchCostInfoForUri,
|
||||
doFetchViewCount,
|
||||
makeSelectViewCountForUri,
|
||||
makeSelectCostInfoForUri,
|
||||
doFetchCostInfoForUri,
|
||||
} from 'lbryinc';
|
||||
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||
|
@ -43,7 +42,6 @@ const select = (state, props) => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
fetchFileInfo: uri => dispatch(doFetchFileInfo(uri)),
|
||||
fetchCostInfo: uri => dispatch(doFetchCostInfoForUri(uri)),
|
||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||
|
|
|
@ -39,7 +39,6 @@ type Props = {
|
|||
channelUri: string,
|
||||
viewCount: number,
|
||||
prepareEdit: ({}, string) => void,
|
||||
navigate: (string, ?{}) => void,
|
||||
openModal: (id: string, { uri: string }) => void,
|
||||
markSubscriptionRead: (string, string) => void,
|
||||
fetchViewCount: string => void,
|
||||
|
@ -132,7 +131,6 @@ class FilePage extends React.Component<Props> {
|
|||
openModal,
|
||||
claimIsMine,
|
||||
prepareEdit,
|
||||
navigate,
|
||||
costInfo,
|
||||
fileInfo,
|
||||
channelUri,
|
||||
|
@ -173,6 +171,7 @@ class FilePage extends React.Component<Props> {
|
|||
return (
|
||||
<Page notContained className="main--file-page">
|
||||
<div className="grid-area--content">
|
||||
<h1 className="media__uri">{uri}</h1>
|
||||
{showFile && <FileViewer className="content__embedded" uri={uri} mediaType={mediaType} />}
|
||||
{!showFile &&
|
||||
(thumbnail ? (
|
||||
|
@ -231,9 +230,9 @@ class FilePage extends React.Component<Props> {
|
|||
button="primary"
|
||||
icon={icons.EDIT}
|
||||
label={__('Edit')}
|
||||
navigate="/$/publish"
|
||||
onClick={() => {
|
||||
prepareEdit(claim, editUri);
|
||||
navigate('/publish');
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
selectIsFetchingFileList,
|
||||
selectFileListDownloadedSort,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import FileListDownloaded from './view';
|
||||
|
||||
const select = state => ({
|
||||
|
@ -15,11 +14,7 @@ const select = state => ({
|
|||
sortBy: selectFileListDownloadedSort(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
null
|
||||
)(FileListDownloaded);
|
||||
|
|
|
@ -8,13 +8,12 @@ import { PAGES } from 'lbry-redux';
|
|||
type Props = {
|
||||
fetching: boolean,
|
||||
fileInfos: {},
|
||||
navigate: (string, ?{}) => void,
|
||||
sortBy: string,
|
||||
};
|
||||
|
||||
class FileListDownloaded extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { fetching, fileInfos, navigate, sortBy } = this.props;
|
||||
const { fetching, fileInfos, sortBy } = this.props;
|
||||
const hasDownloads = fileInfos && Object.values(fileInfos).length > 0;
|
||||
|
||||
return (
|
||||
|
@ -32,11 +31,7 @@ class FileListDownloaded extends React.PureComponent<Props> {
|
|||
|
||||
<div className="card__content">
|
||||
<div className="card__actions card__actions--center">
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={() => navigate('/discover')}
|
||||
label={__('Explore new content')}
|
||||
/>
|
||||
<Button button="primary" navigate="/" label={__('Explore new content')} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
selectFileListPublishedSort,
|
||||
selectMyClaimsWithoutChannels,
|
||||
} from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doCheckPendingPublishes } from 'redux/actions/publish';
|
||||
import FileListPublished from './view';
|
||||
|
||||
|
@ -15,7 +14,6 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
checkPendingPublishes: () => dispatch(doCheckPendingPublishes()),
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import { PAGES } from 'lbry-redux';
|
|||
type Props = {
|
||||
claims: Array<Claim>,
|
||||
checkPendingPublishes: () => void,
|
||||
navigate: (string, ?{}) => void,
|
||||
fetching: boolean,
|
||||
sortBy: string,
|
||||
};
|
||||
|
@ -21,7 +20,7 @@ class FileListPublished extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { fetching, claims, navigate, sortBy } = this.props;
|
||||
const { fetching, claims, sortBy } = this.props;
|
||||
return (
|
||||
<Page notContained loading={fetching}>
|
||||
{claims && claims.length ? (
|
||||
|
@ -45,7 +44,7 @@ class FileListPublished extends React.PureComponent<Props> {
|
|||
<div className="card__actions card__actions--center">
|
||||
<Button
|
||||
button="primary"
|
||||
onClick={() => navigate('/publish')}
|
||||
navigate="/$/publish"
|
||||
label={__('Publish something new')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -200,7 +200,7 @@ class HelpPage extends React.PureComponent<Props, State> {
|
|||
<div className="card__content">
|
||||
<div className="card__actions">
|
||||
<Button
|
||||
navigate="/report"
|
||||
navigate="/$/report"
|
||||
label={__('Submit a Bug Report/Feature Request')}
|
||||
icon={icons.REPORT}
|
||||
button="primary"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { doResolveUri, selectBalance } from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import {
|
||||
selectPublishFormValues,
|
||||
selectIsStillEditing,
|
||||
|
@ -35,7 +34,6 @@ const perform = dispatch => ({
|
|||
clearPublish: () => dispatch(doClearPublish()),
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
publish: params => dispatch(doPublish(params)),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
prepareEdit: (claim, uri) => dispatch(doPrepareEdit(claim, uri)),
|
||||
resetThumbnailStatus: () => dispatch(doResetThumbnailStatus()),
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
selectUser,
|
||||
doRewardList,
|
||||
} from 'lbryinc';
|
||||
import { doAuthNavigate, doNavigate } from 'redux/actions/navigation';
|
||||
import { navigate } from '@reach/router';
|
||||
import { selectDaemonSettings } from 'redux/selectors/settings';
|
||||
import RewardsPage from './view';
|
||||
|
||||
|
@ -20,9 +20,8 @@ const select = state => ({
|
|||
|
||||
const perform = dispatch => ({
|
||||
fetchRewards: () => dispatch(doRewardList()),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
doAuth: () => {
|
||||
dispatch(doAuthNavigate('/rewards'));
|
||||
navigate('/$/auth?redirect=rewards');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import { rewards as REWARD_TYPES } from 'lbryinc';
|
|||
|
||||
type Props = {
|
||||
doAuth: () => void,
|
||||
navigate: string => void,
|
||||
fetching: boolean,
|
||||
rewards: Array<Reward>,
|
||||
claimed: Array<Reward>,
|
||||
|
@ -28,7 +27,7 @@ type Props = {
|
|||
|
||||
class RewardsPage extends PureComponent<Props> {
|
||||
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.primary_email || !user.has_verified_email || !user.is_identity_verified) {
|
||||
|
@ -68,7 +67,7 @@ class RewardsPage extends PureComponent<Props> {
|
|||
)}`}
|
||||
</p>
|
||||
<p>
|
||||
<Button onClick={() => navigate('/discover')} button="primary" label="Return Home" />
|
||||
<Button navigate="/" button="primary" label="Return Home" />
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
|
@ -93,7 +92,7 @@ class RewardsPage extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
renderUnclaimedRewards() {
|
||||
const { fetching, rewards, user, daemonSettings, navigate, claimed } = this.props;
|
||||
const { fetching, rewards, user, daemonSettings, claimed } = this.props;
|
||||
|
||||
if (daemonSettings && !daemonSettings.share_usage_data) {
|
||||
return (
|
||||
|
@ -104,7 +103,7 @@ class RewardsPage extends PureComponent<Props> {
|
|||
{__(
|
||||
'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.')}
|
||||
</p>
|
||||
</header>
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectIsSearching, makeSelectCurrentParam, doUpdateSearchQuery } from 'lbry-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doSearch, selectIsSearching } from 'lbry-redux';
|
||||
import SearchPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
isSearching: selectIsSearching(state),
|
||||
query: makeSelectCurrentParam('query')(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
||||
});
|
||||
const perform = {
|
||||
doSearch,
|
||||
};
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import type { UrlLocation } from 'types/location';
|
||||
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 FileTile from 'component/fileTile';
|
||||
import ChannelTile from 'component/channelTile';
|
||||
|
@ -9,55 +10,88 @@ import Page from 'component/page';
|
|||
import ToolTip from 'component/common/tooltip';
|
||||
import Icon from 'component/common/icon';
|
||||
import SearchOptions from 'component/searchOptions';
|
||||
import { Location } from '@reach/router';
|
||||
|
||||
type Props = {
|
||||
query: ?string,
|
||||
};
|
||||
type Props = { doSearch: string => void, location: UrlLocation };
|
||||
|
||||
class SearchPage extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { query } = this.props;
|
||||
export default function SearchPage(props: Props) {
|
||||
const {
|
||||
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);
|
||||
|
||||
let uri;
|
||||
let isChannel;
|
||||
let label;
|
||||
if (isValid) {
|
||||
uri = normalizeURI(query);
|
||||
({ 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 (
|
||||
<Page noPadding>
|
||||
<section className="search">
|
||||
{query && isValid && (
|
||||
{query && (
|
||||
<Fragment>
|
||||
<header className="search__header">
|
||||
<h1 className="search__title">
|
||||
{`lbry://${query}`}
|
||||
<ToolTip
|
||||
icon
|
||||
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
|
||||
>
|
||||
<Icon icon={ICONS.HELP} />
|
||||
</ToolTip>
|
||||
</h1>
|
||||
{isValid && (
|
||||
<Fragment>
|
||||
<SearchOptions />
|
||||
|
||||
<h1 className="media__uri">{uri}</h1>
|
||||
{isChannel ? (
|
||||
<ChannelTile size="large" isSearchResult uri={uri} />
|
||||
) : (
|
||||
<FileTile size="large" isSearchResult displayHiddenMessage uri={uri} />
|
||||
)}
|
||||
</header>
|
||||
</Fragment>
|
||||
)}
|
||||
</header>
|
||||
|
||||
<div className="search__results-wrapper">
|
||||
<SearchOptions />
|
||||
|
||||
<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>
|
||||
</Fragment>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}}
|
||||
</Location>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchPage;
|
||||
|
|
|
@ -5,16 +5,22 @@ import {
|
|||
makeSelectClaimForUri,
|
||||
makeSelectIsUriResolving,
|
||||
makeSelectTotalPagesForChannel,
|
||||
buildURI,
|
||||
} from 'lbry-redux';
|
||||
import { selectBlackListedOutpoints } from 'lbryinc';
|
||||
import ShowPage from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
||||
const select = (state, props) => {
|
||||
// claimName and claimId come from the url `lbry.tv/{claimName}/{claimId}"
|
||||
const uri = buildURI({ contentName: props.claimName, claimId: props.claimId });
|
||||
return {
|
||||
claim: makeSelectClaimForUri(uri)(state),
|
||||
isResolvingUri: makeSelectIsUriResolving(uri)(state),
|
||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||
totalPages: makeSelectTotalPagesForChannel(props.uri, PAGE_SIZE)(state),
|
||||
});
|
||||
totalPages: makeSelectTotalPagesForChannel(uri, PAGE_SIZE)(state),
|
||||
uri: uri,
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @flow
|
||||
import type { UrlLocation } from 'types/location';
|
||||
import React from 'react';
|
||||
import BusyIndicator from 'component/common/busy-indicator';
|
||||
import ChannelPage from 'page/channel';
|
||||
|
@ -13,6 +14,7 @@ type Props = {
|
|||
uri: string,
|
||||
claim: Claim,
|
||||
totalPages: number,
|
||||
location: UrlLocation,
|
||||
blackListedOutpoints: Array<{
|
||||
txid: string,
|
||||
nout: number,
|
||||
|
@ -38,8 +40,7 @@ class ShowPage extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { claim, isResolvingUri, uri, blackListedOutpoints } = this.props;
|
||||
|
||||
const { claim, isResolvingUri, uri, blackListedOutpoints, location } = this.props;
|
||||
let innerContent = '';
|
||||
|
||||
if (!claim || (claim && !claim.name)) {
|
||||
|
@ -58,7 +59,7 @@ class ShowPage extends React.PureComponent<Props> {
|
|||
</Page>
|
||||
);
|
||||
} else if (claim.name.length && claim.name[0] === '@') {
|
||||
innerContent = <ChannelPage uri={uri} />;
|
||||
innerContent = <ChannelPage uri={uri} location={location} />;
|
||||
} else if (claim && blackListedOutpoints) {
|
||||
let isClaimBlackListed = false;
|
||||
|
||||
|
@ -89,7 +90,7 @@ class ShowPage extends React.PureComponent<Props> {
|
|||
</Page>
|
||||
);
|
||||
} else {
|
||||
innerContent = <FilePage uri={uri} />;
|
||||
innerContent = <FilePage uri={uri} location={location} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import SuggestedSubscriptions from 'component/subscribeSuggested';
|
|||
import MarkAsRead from 'component/subscribeMarkAsRead';
|
||||
import Tooltip from 'component/common/tooltip';
|
||||
import Yrbl from 'component/yrbl';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
type Props = {
|
||||
viewMode: ViewMode,
|
||||
|
@ -109,12 +110,7 @@ export default (props: Props) => {
|
|||
return (
|
||||
<span>
|
||||
<h2 className="card__title card__title--flex">
|
||||
<Button
|
||||
button="link"
|
||||
navigate="/show"
|
||||
navigateParams={{ uri: channel, page: 1 }}
|
||||
label={claimName}
|
||||
/>
|
||||
<Button button="link" navigate={channel} label={claimName} />
|
||||
<MarkAsRead channel={channel} />
|
||||
</h2>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class UserHistoryPage extends React.PureComponent<Props> {
|
|||
render() {
|
||||
return (
|
||||
<Page>
|
||||
<UserHistory />
|
||||
<UserHistory {...this.props} />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import TransactionListRecent from 'component/transactionListRecent';
|
|||
import WalletAddress from 'component/walletAddress';
|
||||
import Page from 'component/page';
|
||||
import UnsupportedOnWeb from 'component/common/unsupported-on-web';
|
||||
import WalletSend from 'component/walletSend';
|
||||
|
||||
const WalletPage = () => (
|
||||
<Page>
|
||||
|
@ -15,6 +16,7 @@ const WalletPage = () => (
|
|||
<WalletBalance />
|
||||
<RewardSummary />
|
||||
</div>
|
||||
<WalletSend />
|
||||
<WalletAddress />
|
||||
<TransactionListRecent />
|
||||
</div>
|
||||
|
|
|
@ -317,6 +317,7 @@ export function doDaemonReady() {
|
|||
dispatch({ type: ACTIONS.DAEMON_READY });
|
||||
dispatch(doFetchDaemonSettings());
|
||||
dispatch(doBalanceSubscribe());
|
||||
|
||||
// @if TARGET='app'
|
||||
dispatch(doFetchFileInfosAndPublishedClaims());
|
||||
if (!selectIsUpgradeSkipped(state)) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as MODALS from 'constants/modal_types';
|
|||
import { ipcRenderer } from 'electron';
|
||||
// @endif
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { navigate } from '@reach/router';
|
||||
import { setSubscriptionLatest, doUpdateUnreadSubscriptions } from 'redux/actions/subscriptions';
|
||||
import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions';
|
||||
import {
|
||||
|
@ -24,10 +24,11 @@ import {
|
|||
parseURI,
|
||||
creditsToString,
|
||||
doError,
|
||||
makeSelectCostInfoForUri,
|
||||
} from 'lbry-redux';
|
||||
import { makeSelectCostInfoForUri } from 'lbryinc';
|
||||
import { makeSelectClientSetting, selectosNotificationsEnabled } from 'redux/selectors/settings';
|
||||
import analytics from 'analytics';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
|
||||
const DOWNLOAD_POLL_INTERVAL = 250;
|
||||
|
||||
|
@ -82,11 +83,7 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) {
|
|||
silent: false,
|
||||
});
|
||||
notif.onclick = () => {
|
||||
dispatch(
|
||||
doNavigate('/show', {
|
||||
uri,
|
||||
})
|
||||
);
|
||||
navigate(formatLbryUriForWeb(uri));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
selectFileInfosByOutpoint,
|
||||
} from 'lbry-redux';
|
||||
import { doHideModal } from 'redux/actions/app';
|
||||
import { doHistoryBack } from 'redux/actions/navigation';
|
||||
|
||||
export function doOpenFileInFolder(path) {
|
||||
return () => {
|
||||
|
@ -63,7 +62,6 @@ export function doDeleteFileAndGoBack(fileInfo, deleteFromComputer, abandonClaim
|
|||
return dispatch => {
|
||||
const actions = [];
|
||||
actions.push(doHideModal());
|
||||
actions.push(doHistoryBack());
|
||||
actions.push(doDeleteFile(fileInfo, deleteFromComputer, abandonClaim));
|
||||
dispatch(batchActions(...actions));
|
||||
};
|
||||
|
|
|
@ -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 },
|
||||
});
|
||||
};
|
||||
}
|
|
@ -21,8 +21,9 @@ import {
|
|||
} from 'lbry-redux';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { selectosNotificationsEnabled } from 'redux/selectors/settings';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { navigate } from '@reach/router';
|
||||
import analytics from 'analytics';
|
||||
import { formatLbryUriForWeb } from 'util/uri';
|
||||
// @if TARGET='app'
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
@ -327,11 +328,7 @@ export const doCheckPendingPublishes = () => (dispatch: Dispatch, getState: GetS
|
|||
silent: false,
|
||||
});
|
||||
notif.onclick = () => {
|
||||
dispatch(
|
||||
doNavigate('/show', {
|
||||
uri: claim.permanent_url,
|
||||
})
|
||||
);
|
||||
navigate(formatLbryUriForWeb(claim.permanent_url));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,21 +100,6 @@ export const selectDaemonVersionMatched = createSelector(
|
|||
state => state.daemonVersionMatched
|
||||
);
|
||||
|
||||
export const selectSnackBar = createSelector(
|
||||
selectState,
|
||||
state => state.snackBar || {}
|
||||
);
|
||||
|
||||
export const selectSnackBarSnacks = createSelector(
|
||||
selectSnackBar,
|
||||
snackBar => snackBar.snacks || []
|
||||
);
|
||||
|
||||
export const selectBadgeNumber = createSelector(
|
||||
selectState,
|
||||
state => state.badgeNumber
|
||||
);
|
||||
|
||||
export const selectCurrentLanguage = createSelector(
|
||||
selectState,
|
||||
() => i18n.getLocale() || 'en'
|
||||
|
@ -130,147 +115,6 @@ export const selectUpgradeTimer = createSelector(
|
|||
state => state.checkUpgradeTimer
|
||||
);
|
||||
|
||||
export const selectNavLinks = createSelector(
|
||||
selectCurrentPage,
|
||||
selectHistoryStack,
|
||||
makeSelectClientSetting(SETTINGS.FIRST_RUN_COMPLETED),
|
||||
makeSelectClientSetting(SETTINGS.INVITE_ACKNOWLEDGED),
|
||||
(currentPage, historyStack, firstRunCompleted, inviteAcknowledged) => {
|
||||
// Determine if any links should show a tooltip for a guided tour
|
||||
// It will only show one at a time, in the order they are set.
|
||||
const guidedTourItem = [
|
||||
// @if TARGET='app'
|
||||
{
|
||||
page: PAGES.INVITE,
|
||||
hasBeenCompleted: inviteAcknowledged,
|
||||
guide: 'Check this out!',
|
||||
},
|
||||
// @endif
|
||||
// Add more items below for tooltip guides that will happen after a user has completed the invite guide
|
||||
].filter(({ hasBeenCompleted }) => !hasBeenCompleted)[0];
|
||||
|
||||
const isWalletPage = page =>
|
||||
page === PAGES.WALLET ||
|
||||
page === PAGES.SEND ||
|
||||
page === PAGES.GET_CREDITS ||
|
||||
page === PAGES.HISTORY ||
|
||||
page === PAGES.BACKUP;
|
||||
|
||||
const isCurrentlyWalletPage = isWalletPage(currentPage);
|
||||
const previousStack = historyStack.slice().reverse();
|
||||
|
||||
const getPreviousSubLinkPath = checkIfValidPage => {
|
||||
for (let i = 0; i < previousStack.length; i += 1) {
|
||||
const currentStackItem = previousStack[i];
|
||||
|
||||
// Trim off the "/" from the path
|
||||
const pageInStack = currentStackItem.path.slice(1);
|
||||
if (checkIfValidPage(pageInStack)) {
|
||||
return currentStackItem.path;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// Gets the last active sublink in a section
|
||||
const getActiveSublink = category => {
|
||||
if (category === PAGES.WALLET) {
|
||||
const previousPath = getPreviousSubLinkPath(isWalletPage);
|
||||
return previousPath || `/${PAGES.WALLET}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// Is this path the first unacknowledged item in the guided tour list
|
||||
const getGuideIfNecessary = page => {
|
||||
if (!firstRunCompleted) {
|
||||
return null;
|
||||
}
|
||||
return guidedTourItem && guidedTourItem.page === page ? guidedTourItem.guide : null;
|
||||
};
|
||||
|
||||
const buildLink = (label, page) => ({
|
||||
label,
|
||||
path: `/${page}`,
|
||||
active: currentPage === page,
|
||||
guide: getGuideIfNecessary(page),
|
||||
});
|
||||
|
||||
const walletSubLinks = [
|
||||
{
|
||||
...buildLink('Overview', PAGES.WALLET),
|
||||
},
|
||||
{
|
||||
...buildLink('Send & Receive', PAGES.SEND),
|
||||
},
|
||||
{
|
||||
...buildLink('Transactions', PAGES.HISTORY),
|
||||
},
|
||||
{
|
||||
...buildLink('Get Credits', PAGES.GET_CREDITS),
|
||||
},
|
||||
{
|
||||
...buildLink('Backup', PAGES.BACKUP),
|
||||
},
|
||||
];
|
||||
|
||||
const navLinks = {
|
||||
primary: [
|
||||
{
|
||||
...buildLink('Explore', PAGES.DISCOVER),
|
||||
icon: ICONS.HOME,
|
||||
},
|
||||
{
|
||||
...buildLink('Subscriptions', PAGES.SUBSCRIPTIONS),
|
||||
icon: ICONS.SUBSCRIPTION,
|
||||
},
|
||||
],
|
||||
secondary: [
|
||||
{
|
||||
label: 'Wallet',
|
||||
icon: ICONS.WALLET,
|
||||
subLinks: walletSubLinks,
|
||||
path: isCurrentlyWalletPage ? `/${PAGES.WALLET}` : getActiveSublink(PAGES.WALLET),
|
||||
active: isWalletPage(currentPage),
|
||||
},
|
||||
{
|
||||
...buildLink('Invite', PAGES.INVITE),
|
||||
icon: ICONS.INVITE,
|
||||
},
|
||||
{
|
||||
...buildLink('Rewards', PAGES.REWARDS),
|
||||
// This probably shouldn't use the "FEATURED" icon, but not sure what else to use
|
||||
icon: ICONS.FEATURED,
|
||||
},
|
||||
{
|
||||
...buildLink('Downloads', PAGES.DOWNLOADED),
|
||||
icon: ICONS.LOCAL,
|
||||
},
|
||||
{
|
||||
...buildLink('Publishes', PAGES.PUBLISHED),
|
||||
icon: ICONS.PUBLISHED,
|
||||
},
|
||||
{
|
||||
...buildLink('History', PAGES.USER_HISTORY),
|
||||
icon: ICONS.HISTORY,
|
||||
},
|
||||
{
|
||||
...buildLink('Settings', PAGES.SETTINGS),
|
||||
icon: ICONS.SETTINGS,
|
||||
},
|
||||
{
|
||||
...buildLink('Help', PAGES.HELP),
|
||||
icon: ICONS.HELP,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return navLinks;
|
||||
}
|
||||
);
|
||||
|
||||
export const selectModal = createSelector(
|
||||
selectState,
|
||||
state => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createSelector } from 'reselect';
|
|||
import {
|
||||
makeSelectClaimForUri,
|
||||
selectClaimsByUri,
|
||||
makeSelectClaimsInChannelForCurrentPage,
|
||||
makeSelectClaimsInChannelForCurrentPageState,
|
||||
} from 'lbry-redux';
|
||||
import { HISTORY_ITEMS_PER_PAGE } from 'constants/content';
|
||||
|
||||
|
@ -68,7 +68,7 @@ export const makeSelectHistoryForUri = (uri: string) =>
|
|||
|
||||
export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
|
||||
createSelector(
|
||||
makeSelectClaimsInChannelForCurrentPage(channel),
|
||||
makeSelectClaimsInChannelForCurrentPageState(channel),
|
||||
channelClaims => {
|
||||
if (uris) return uris;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
.button {
|
||||
border-radius: 0;
|
||||
font-size: 1em;
|
||||
|
||||
svg {
|
||||
stroke-width: 1.9;
|
||||
|
|
|
@ -27,7 +27,12 @@
|
|||
// at smaller screen widths
|
||||
|
||||
@media (min-width: 601px) {
|
||||
/* @if TARGET='app' */
|
||||
width: 250px;
|
||||
/* @endif */
|
||||
/* @if TARGET='web' */
|
||||
width: 170px;
|
||||
/* @endif */
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
@ -38,9 +43,9 @@
|
|||
|
||||
.header__navigation-item {
|
||||
height: var(--header-height);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:not(:disabled):hover {
|
||||
background-color: $lbry-gray-1;
|
||||
|
@ -53,68 +58,49 @@
|
|||
&:disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.header__navigation-item--back {
|
||||
html[data-mode='dark'] & {
|
||||
svg {
|
||||
stroke: $lbry-white;
|
||||
}
|
||||
.button__content {
|
||||
line-height: var(--header-height);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.header__navigation-item--forward {
|
||||
html[data-mode='dark'] & {
|
||||
svg {
|
||||
stroke: $lbry-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header__navigation-item--home {
|
||||
html[data-mode='dark'] & {
|
||||
svg {
|
||||
stroke: $lbry-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header__navigation-item--menu {
|
||||
html[data-mode='dark'] & {
|
||||
svg {
|
||||
stroke: $lbry-white;
|
||||
}
|
||||
}
|
||||
|
||||
// This menu button does not need to be seen
|
||||
// at larger screen widths
|
||||
|
||||
@media (min-width: 601px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.header__navigation-item--back,
|
||||
.header__navigation-item--forward,
|
||||
.header__navigation-item--home,
|
||||
.header__navigation-item--menu {
|
||||
width: var(--header-height);
|
||||
svg {
|
||||
&:only-child {
|
||||
// Header icons are a little different because they are larger
|
||||
top: 0.25rem;
|
||||
}
|
||||
|
||||
html[data-mode='dark'] & {
|
||||
stroke: $lbry-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Currently not used
|
||||
// .header__navigation-item--publish,
|
||||
// .header__navigation-item--wallet {
|
||||
// // Publish and Wallet links are collapsed
|
||||
// // into a menu at smaller screen widths
|
||||
//
|
||||
// @media (max-width: 600px) {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
.header__navigation-item--lbry {
|
||||
flex: 1;
|
||||
font-weight: 800;
|
||||
font-size: 1.2rem;
|
||||
margin-left: -1.25rem; // Needed because the lbry icon overflows it's parent so the centering is off
|
||||
|
||||
svg {
|
||||
overflow: visible;
|
||||
color: $lbry-white;
|
||||
opacity: 1;
|
||||
top: -0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Publish button
|
||||
.header__navigation-item--right-action {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.button__content {
|
||||
|
@ -149,12 +135,24 @@
|
|||
html[data-mode='dark'] & {
|
||||
border-color: $lbry-gray-5;
|
||||
}
|
||||
}
|
||||
|
||||
.button__content {
|
||||
line-height: var(--header-height);
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
.header__navigation-item--menu {
|
||||
@media (min-width: 601px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide links that will live in the menu bar
|
||||
@media (max-width: 601px) {
|
||||
.header__navigation-item--back,
|
||||
.header__navigation-item--forward,
|
||||
.header__navigation-item--home,
|
||||
.header__navigation-item--right-action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header__navigation:first-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,12 @@
|
|||
margin-right: var(--spacing-vertical-small);
|
||||
}
|
||||
|
||||
.media__uri {
|
||||
font-size: 1.1rem;
|
||||
padding-bottom: 5px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
// M E D I A
|
||||
// A C T I O N S
|
||||
|
||||
|
@ -508,12 +514,9 @@
|
|||
font-size: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
.channel-info__actions__group {
|
||||
button:first-of-type {
|
||||
.button {
|
||||
&:first-child {
|
||||
font-size: 2rem;
|
||||
|
||||
.button__label {
|
||||
|
@ -521,10 +524,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
button:last-of-type {
|
||||
&:last-child {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// M E D I A
|
||||
|
|
|
@ -52,6 +52,11 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.navigation__links--bottom {
|
||||
position: absolute;
|
||||
bottom: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
.navigation__link {
|
||||
display: block;
|
||||
line-height: 1.75;
|
||||
|
@ -102,7 +107,7 @@
|
|||
|
||||
.navigation__link--title {
|
||||
margin-bottom: var(--spacing-vertical-small);
|
||||
padding-top: var(--spacing-vertical-medium);
|
||||
padding-top: var(--spacing-vertical-large);
|
||||
|
||||
color: $lbry-gray-5;
|
||||
cursor: default;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
.search__options-wrapper {
|
||||
font-size: 1.25em;
|
||||
padding-bottom: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
.search__options {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
}
|
||||
|
||||
.yrbl {
|
||||
height: 300px;
|
||||
height: 20rem;
|
||||
margin-right: var(--spacing-vertical-large);
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ code {
|
|||
}
|
||||
|
||||
.help {
|
||||
font-size: 0.9em;
|
||||
font-size: 1rem;
|
||||
background-color: rgba($lbry-blue-1, 0.1);
|
||||
color: $lbry-gray-5;
|
||||
display: block;
|
||||
|
|
|
@ -39,7 +39,7 @@ $large-breakpoint: 1921px;
|
|||
--button-height: 36px;
|
||||
|
||||
// Header
|
||||
--header-height: 3.25rem; // 60px;
|
||||
--header-height: 3.5rem;
|
||||
|
||||
// Header -> search
|
||||
--search-modal-input-height: 70px;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue
This is the other big file. No longer bringing in the nav links from redux. Will add the tutorial back in a future PR.