use react-router

This commit is contained in:
Sean Yesmunt 2019-04-04 17:05:23 -04:00
parent 87314d7eb8
commit ee7854c429
39 changed files with 352 additions and 350 deletions

View file

@ -59,7 +59,6 @@
"@hot-loader/react-dom": "16.8", "@hot-loader/react-dom": "16.8",
"@lbry/color": "^1.0.2", "@lbry/color": "^1.0.2",
"@lbry/components": "^2.3.3", "@lbry/components": "^2.3.3",
"@reach/router": "^1.2.1",
"@types/three": "^0.93.1", "@types/three": "^0.93.1",
"async-exit-hook": "^2.0.1", "async-exit-hook": "^2.0.1",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
@ -70,6 +69,7 @@
"chalk": "^2.4.2", "chalk": "^2.4.2",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"codemirror": "^5.39.2", "codemirror": "^5.39.2",
"connected-react-router": "^6.3.2",
"copy-webpack-plugin": "^4.6.0", "copy-webpack-plugin": "^4.6.0",
"country-data": "^0.0.31", "country-data": "^0.0.31",
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
@ -104,6 +104,7 @@
"flow-typed": "^2.3.0", "flow-typed": "^2.3.0",
"formik": "^0.10.4", "formik": "^0.10.4",
"hast-util-sanitize": "^1.1.2", "hast-util-sanitize": "^1.1.2",
"history": "^4.9.0",
"husky": "^0.14.3", "husky": "^0.14.3",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git", "lbry-format": "https://github.com/lbryio/lbry-format.git",
@ -134,7 +135,8 @@
"react-modal": "^3.1.7", "react-modal": "^3.1.7",
"react-paginate": "^5.2.1", "react-paginate": "^5.2.1",
"react-pose": "^4.0.5", "react-pose": "^4.0.5",
"react-redux": "^5.0.3", "react-redux": "^6.0.1",
"react-router-dom": "^5.0.0",
"react-simplemde-editor": "^4.0.0", "react-simplemde-editor": "^4.0.0",
"react-toggle": "^4.0.2", "react-toggle": "^4.0.2",
"react-virtualized": "^9.21.0", "react-virtualized": "^9.21.0",

View file

@ -1,7 +1,6 @@
// @flow // @flow
import { Lbryio } from 'lbryinc'; import { Lbryio } from 'lbryinc';
import ReactGA from 'react-ga'; import ReactGA from 'react-ga';
import { globalHistory } from '@reach/router';
type Analytics = { type Analytics = {
pageView: string => void, pageView: string => void,
@ -15,7 +14,7 @@ let analyticsEnabled: boolean = true;
const analytics: Analytics = { const analytics: Analytics = {
pageView: path => { pageView: path => {
if (analyticsEnabled) { if (analyticsEnabled) {
ReactGA.pageview(path); // ReactGA.pageview(path);
} }
}, },
setUser: user => { setUser: user => {
@ -72,19 +71,19 @@ const analytics: Analytics = {
// Initialize google analytics // Initialize google analytics
// Set `debug: true` for debug info // Set `debug: true` for debug info
ReactGA.initialize('UA-60403362-12', { // ReactGA.initialize('UA-60403362-12', {
gaOptions: { name: IS_WEB ? 'web' : 'desktop' }, // gaOptions: { name: IS_WEB ? 'web' : 'desktop' },
testMode: process.env.NODE_ENV !== 'production', // testMode: process.env.NODE_ENV !== 'production',
}); // });
// Manually call the first page view // Manually call the first page view
// Reach Router doesn't include this on `history.listen` // Reach Router doesn't include this on `history.listen`
analytics.pageView(window.location.pathname + window.location.search); // analytics.pageView(window.location.pathname + window.location.search);
// Listen for url changes and report // Listen for url changes and report
// This will include search queries/filter options // This will include search queries/filter options
globalHistory.listen(({ location }) => // globalHistory.listen(({ location }) =>
analytics.pageView(window.location.pathname + window.location.search) // analytics.pageView(window.location.pathname + window.location.search)
); // );
export default analytics; export default analytics;

View file

@ -1,4 +1,4 @@
import store from 'store'; import { store } from 'store';
const env = process.env.NODE_ENV || 'production'; const env = process.env.NODE_ENV || 'production';

View file

@ -3,7 +3,6 @@ import React from 'react';
import Router from 'component/router/index'; import Router from 'component/router/index';
import ModalRouter from 'modal/modalRouter'; import ModalRouter from 'modal/modalRouter';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import throttle from 'util/throttle';
import SideBar from 'component/sideBar'; import SideBar from 'component/sideBar';
import Header from 'component/header'; import Header from 'component/header';
import { openContextMenu } from 'util/context-menu'; import { openContextMenu } from 'util/context-menu';

View file

@ -2,7 +2,7 @@
import * as React from 'react'; import * as React from 'react';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import classnames from 'classnames'; import classnames from 'classnames';
import { Link } from '@reach/router'; import { NavLink } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
import { OutboundLink } from 'react-ga'; import { OutboundLink } from 'react-ga';
@ -109,19 +109,16 @@ class Button extends React.PureComponent<Props> {
} }
return path ? ( return path ? (
<Link <NavLink
exact
to={path} to={path}
title={title} title={title}
onClick={e => e.stopPropagation()} onClick={e => e.stopPropagation()}
getProps={({ isCurrent, isPartiallyCurrent }) => ({ className={combinedClassName}
className: activeClassName={activeClass}
(path === '/' ? isCurrent : isPartiallyCurrent) && activeClass
? `${combinedClassName} ${activeClass}`
: combinedClassName,
})}
> >
{content} {content}
</Link> </NavLink>
) : ( ) : (
<button <button
title={title} title={title}

View file

@ -5,7 +5,7 @@ import TruncatedText from 'component/common/truncated-text';
import classnames from 'classnames'; import classnames from 'classnames';
import SubscribeButton from 'component/subscribeButton'; import SubscribeButton from 'component/subscribeButton';
import type { Claim } from 'types/claim'; import type { Claim } from 'types/claim';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
@ -15,6 +15,7 @@ type Props = {
size: string, size: string,
claim: ?Claim, claim: ?Claim,
resolveUri: string => void, resolveUri: string => void,
history: { push: string => void },
}; };
class ChannelTile extends React.PureComponent<Props> { class ChannelTile extends React.PureComponent<Props> {
@ -37,7 +38,7 @@ class ChannelTile extends React.PureComponent<Props> {
} }
render() { render() {
const { claim, isResolvingUri, totalItems, uri, size } = this.props; const { claim, isResolvingUri, totalItems, uri, size, history } = this.props;
let channelName; let channelName;
let subscriptionUri; let subscriptionUri;
@ -46,7 +47,7 @@ class ChannelTile extends React.PureComponent<Props> {
subscriptionUri = `lbry://${claim.permanent_url}`; subscriptionUri = `lbry://${claim.permanent_url}`;
} }
const onClick = () => navigate(formatLbryUriForWeb(uri)); const onClick = () => history.push(formatLbryUriForWeb(uri));
return ( return (
<section <section
@ -86,4 +87,4 @@ class ChannelTile extends React.PureComponent<Props> {
} }
} }
export default ChannelTile; export default withRouter(ChannelTile);

View file

@ -4,13 +4,11 @@ import * as ICONS from 'constants/icons';
import * as React from 'react'; import * as React from 'react';
import { isURIValid } from 'lbry-redux'; import { isURIValid } from 'lbry-redux';
import Button from 'component/button'; import Button from 'component/button';
import { navigate } from '@reach/router';
type Props = { type Props = {
href: string, href: string,
title?: string, title?: string,
children: React.Node, children: React.Node,
navigate: (string, ?{}) => void,
openModal: (id: string, { uri: string }) => void, openModal: (id: string, { uri: string }) => void,
}; };
@ -21,7 +19,7 @@ class ExternalLink extends React.PureComponent<Props> {
}; };
createLink() { createLink() {
const { href, title, children, openModal, navigate } = this.props; const { href, title, children, openModal } = this.props;
// Regex for url protocol // Regex for url protocol
const protocolRegex = new RegExp('^(https?|lbry)+:', 'i'); const protocolRegex = new RegExp('^(https?|lbry)+:', 'i');

View file

@ -11,7 +11,7 @@ import classnames from 'classnames';
import FilePrice from 'component/filePrice'; import FilePrice from 'component/filePrice';
import { openCopyLinkMenu } from 'util/context-menu'; import { openCopyLinkMenu } from 'util/context-menu';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
@ -29,6 +29,7 @@ type Props = {
isNew: boolean, isNew: boolean,
placeholder: boolean, placeholder: boolean,
preventResolve: boolean, preventResolve: boolean,
history: { push: string => void },
}; };
class FileCard extends React.PureComponent<Props> { class FileCard extends React.PureComponent<Props> {
@ -70,6 +71,7 @@ class FileCard extends React.PureComponent<Props> {
isNew, isNew,
isResolvingUri, isResolvingUri,
placeholder, placeholder,
history,
} = this.props; } = this.props;
const abandoned = !isResolvingUri && !claim && !pending && !placeholder; const abandoned = !isResolvingUri && !claim && !pending && !placeholder;
@ -110,7 +112,7 @@ class FileCard extends React.PureComponent<Props> {
const onClick = e => { const onClick = e => {
e.stopPropagation(); e.stopPropagation();
navigate(formatLbryUriForWeb(uri)); history.push(formatLbryUriForWeb(uri));
}; };
return ( return (
@ -147,4 +149,4 @@ class FileCard extends React.PureComponent<Props> {
} }
} }
export default FileCard; export default withRouter(FileCard);

View file

@ -12,7 +12,7 @@ import FilePrice from 'component/filePrice';
import UriIndicator from 'component/uriIndicator'; import UriIndicator from 'component/uriIndicator';
import DateTime from 'component/dateTime'; import DateTime from 'component/dateTime';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
@ -32,6 +32,7 @@ type Props = {
size: string, size: string,
isSubscribed: boolean, isSubscribed: boolean,
isNew: boolean, isNew: boolean,
history: { push: string => void },
}; };
class FileTile extends React.PureComponent<Props> { class FileTile extends React.PureComponent<Props> {
@ -91,6 +92,7 @@ class FileTile extends React.PureComponent<Props> {
hideNoResult, hideNoResult,
displayHiddenMessage, displayHiddenMessage,
size, size,
history,
} = this.props; } = this.props;
if (!claim && isResolvingUri) { if (!claim && isResolvingUri) {
@ -136,7 +138,7 @@ class FileTile extends React.PureComponent<Props> {
const wrapperProps = name const wrapperProps = name
? { ? {
onClick: () => navigate(formatLbryUriForWeb(uri)), onClick: () => history.push(formatLbryUriForWeb(uri)),
role: 'button', role: 'button',
} }
: {}; : {};
@ -209,7 +211,7 @@ class FileTile extends React.PureComponent<Props> {
clearPublish(); // to remove any existing publish data clearPublish(); // to remove any existing publish data
updatePublishForm({ name: claimName }); // to populate the name updatePublishForm({ name: claimName }); // to populate the name
navigate('/publish'); history.push('/publish');
}} }}
/> />
} }
@ -221,4 +223,4 @@ class FileTile extends React.PureComponent<Props> {
} }
} }
export default FileTile; export default withRouter(FileTile);

View file

@ -88,7 +88,7 @@ const Header = (props: Props) => {
{roundedBalance} <LbcSymbol /> {roundedBalance} <LbcSymbol />
</React.Fragment> </React.Fragment>
} }
navigate="/$/wallet" navigate="/$/account"
/> />
<Button <Button

View file

@ -11,7 +11,7 @@ const select = (state, props) => {
return { return {
page, page,
pageCount: selectHistoryPageCount(state), pageCount: selectHistoryPageCount(state),
history: makeSelectHistoryForPage(page)(state), historyItems: makeSelectHistoryForPage(page)(state),
}; };
}; };

View file

@ -4,7 +4,7 @@ import Button from 'component/button';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
import ReactPaginate from 'react-paginate'; import ReactPaginate from 'react-paginate';
import NavigationHistoryItem from 'component/navigationHistoryItem'; import NavigationHistoryItem from 'component/navigationHistoryItem';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
type HistoryItem = { type HistoryItem = {
uri: string, uri: string,
@ -12,11 +12,12 @@ type HistoryItem = {
}; };
type Props = { type Props = {
history: Array<HistoryItem>, historyItems: Array<HistoryItem>,
page: number, page: number,
pageCount: number, pageCount: number,
clearHistoryUri: string => void, clearHistoryUri: string => void,
params: { page: number }, params: { page: number },
history: { push: string => void },
}; };
type State = { type State = {
@ -52,7 +53,8 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
} }
changePage(pageNumber: number) { changePage(pageNumber: number) {
navigate(`?page=${pageNumber}`); const { history } = this.props;
history.push(`?page=${pageNumber}`);
} }
paginate(e: SyntheticKeyboardEvent<*>) { paginate(e: SyntheticKeyboardEvent<*>) {
@ -69,9 +71,9 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
} }
selectAll() { selectAll() {
const { history } = this.props; const { historyItems } = this.props;
const newSelectedState = {}; const newSelectedState = {};
history.forEach(({ uri }) => (newSelectedState[uri] = true)); historyItems.forEach(({ uri }) => (newSelectedState[uri] = true));
this.setState({ itemsSelected: newSelectedState }); this.setState({ itemsSelected: newSelectedState });
} }
@ -92,7 +94,7 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
} }
render() { render() {
const { history = [], page, pageCount } = this.props; const { historyItems = [], page, pageCount } = this.props;
const { itemsSelected } = this.state; const { itemsSelected } = this.state;
const allSelected = Object.keys(itemsSelected).length === history.length; const allSelected = Object.keys(itemsSelected).length === history.length;
const selectHandler = allSelected ? this.unselectAll : this.selectAll; const selectHandler = allSelected ? this.unselectAll : this.selectAll;
@ -113,9 +115,9 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
onClick={selectHandler} onClick={selectHandler}
/> />
</div> </div>
{!!history.length && ( {!!historyItems.length && (
<section className="card__content item-list"> <section className="card__content item-list">
{history.map(item => ( {historyItems.map(item => (
<NavigationHistoryItem <NavigationHistoryItem
key={item.uri} key={item.uri}
uri={item.uri} uri={item.uri}
@ -182,4 +184,4 @@ class UserHistoryPage extends React.PureComponent<Props, State> {
); );
} }
} }
export default UserHistoryPage; export default withRouter(UserHistoryPage);

View file

@ -5,7 +5,7 @@ import moment from 'moment';
import classnames from 'classnames'; import classnames from 'classnames';
import Button from 'component/button'; import Button from 'component/button';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
type Props = { type Props = {
@ -16,6 +16,7 @@ type Props = {
onSelect?: () => void, onSelect?: () => void,
resolveUri: string => void, resolveUri: string => void,
slim: boolean, slim: boolean,
history: { push: string => void },
}; };
class NavigationHistoryItem extends React.PureComponent<Props> { class NavigationHistoryItem extends React.PureComponent<Props> {
@ -32,7 +33,7 @@ class NavigationHistoryItem extends React.PureComponent<Props> {
} }
render() { render() {
const { lastViewed, selected, onSelect, claim, uri, slim } = this.props; const { lastViewed, selected, onSelect, claim, uri, slim, history } = this.props;
let name; let name;
let title; let title;
@ -45,7 +46,7 @@ class NavigationHistoryItem extends React.PureComponent<Props> {
const onClick = const onClick =
onSelect || onSelect ||
function() { function() {
navigate(navigatePath); history.push(navigatePath);
}; };
return ( return (
@ -65,4 +66,4 @@ class NavigationHistoryItem extends React.PureComponent<Props> {
} }
} }
export default NavigationHistoryItem; export default withRouter(NavigationHistoryItem);

View file

@ -4,7 +4,6 @@ import Button from 'component/button';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
import ReactPaginate from 'react-paginate'; import ReactPaginate from 'react-paginate';
import NavigationHistoryItem from 'component/navigationHistoryItem'; import NavigationHistoryItem from 'component/navigationHistoryItem';
import { navigate } from '@reach/router';
type HistoryItem = { type HistoryItem = {
uri: string, uri: string,

View file

@ -1,6 +1,6 @@
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Router } from '@reach/router'; import { Route, Switch } from 'react-router-dom';
import SettingsPage from 'page/settings'; import SettingsPage from 'page/settings';
import HelpPage from 'page/help'; import HelpPage from 'page/help';
import ReportPage from 'page/report'; import ReportPage from 'page/report';
@ -21,49 +21,32 @@ import UserHistoryPage from 'page/userHistory';
import SendCreditsPage from 'page/sendCredits'; import SendCreditsPage from 'page/sendCredits';
import NavigationHistory from 'page/navigationHistory'; import NavigationHistory from 'page/navigationHistory';
const ScrollHandler = props => {
const { key } = props.location;
useEffect(() => {
// This shouldn't scroll to top when you click "back"
// Might take some more work but fixes scroll position being stuck on navigation for now
const main = document.querySelector('main');
if (main) {
main.scrollIntoView();
}
}, [key]);
return props.children;
};
export default function AppRouter() { export default function AppRouter() {
return ( return (
<Router> <Switch>
<ScrollHandler path="/"> <Route path="/" exact component={DiscoverPage} />
<DiscoverPage path="/" /> <Route path={`/$/${PAGES.AUTH}`} exact component={AuthPage} />
<ShowPage path="/:claimName/:claimId" /> <Route path={`/$/${PAGES.BACKUP}`} exact component={BackupPage} />
<ShowPage path="/:claimName" /> <Route path={`/$/${PAGES.INVITE}`} exact component={InvitePage} />
{/* <ShowPage path="/" uri="five" /> */} <Route path={`/$/${PAGES.DOWNLOADED}`} exact component={FileListDownloaded} />
<Route path={`/$/${PAGES.PUBLISHED}`} exact component={FileListPublished} />
<Route path={`/$/${PAGES.HELP}`} exact component={HelpPage} />
<Route path={`/$/${PAGES.PUBLISH}`} exact component={PublishPage} />
<Route path={`/$/${PAGES.REPORT}`} exact component={ReportPage} />
<Route path={`/$/${PAGES.REWARDS}`} exact component={RewardsPage} />
<Route path={`/$/${PAGES.SEARCH}`} exact component={SearchPage} />
<Route path={`/$/${PAGES.SETTINGS}`} exact component={SettingsPage} />
<Route path={`/$/${PAGES.SUBSCRIPTIONS}`} exact component={SubscriptionsPage} />
<Route path={`/$/${PAGES.TRANSACTIONS}`} exact component={TransactionHistoryPage} />
<Route path={`/$/${PAGES.HISTORY}`} exact component={UserHistoryPage} />
<Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} />
<Route path={`/$/${PAGES.SEND}`} exact component={SendCreditsPage} />
<Route path={`/$/${PAGES.HISTORY}`} exact component={UserHistoryPage} />
<Route path={`/$/${PAGES.HISTORY}/all`} exact component={NavigationHistory} />
<AuthPage path={`$/${PAGES.AUTH}`} /> {/* Below need to go at the end to make sure we don't match any of our pages first */}
<BackupPage path={`$/${PAGES.BACKUP}`} /> <Route path="/:claimName/:claimId" component={ShowPage} />
<InvitePage path={`$/${PAGES.INVITE}`} /> <Route path="/:claimName" component={ShowPage} />
<FileListDownloaded path={`$/${PAGES.DOWNLOADED}`} /> </Switch>
<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.TRANSACTIONS}`} />
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
<AccountPage path={`$/${PAGES.ACCOUNT}`} />
<SendCreditsPage path={`$/${PAGES.SEND}`} />
<UserHistoryPage path={`$/${PAGES.HISTORY}`} />
<NavigationHistory path={`$/${PAGES.HISTORY}/all`} />
</ScrollHandler>
</Router>
); );
} }

View file

@ -11,7 +11,7 @@ import {
} from 'lbry-redux'; } from 'lbry-redux';
import analytics from 'analytics'; import analytics from 'analytics';
import Wunderbar from './view'; import Wunderbar from './view';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
import { formatLbryUriForWeb } from 'util/uri'; import { formatLbryUriForWeb } from 'util/uri';
const select = state => ({ const select = state => ({
@ -20,14 +20,14 @@ const select = state => ({
isFocused: selectSearchBarFocused(state), isFocused: selectSearchBarFocused(state),
}); });
const perform = dispatch => ({ const perform = (dispatch, ownProps) => ({
onSearch: query => { onSearch: query => {
navigate(`/$/search?q=${query}`); ownProps.history.push({ pathname: `/$/search`, search: `?q=${query}` });
analytics.apiLogSearch(); analytics.apiLogSearch();
}, },
onSubmit: uri => { onSubmit: uri => {
const path = formatLbryUriForWeb(uri); const path = formatLbryUriForWeb(uri);
navigate(path); ownProps.history.push(path);
dispatch(doUpdateSearchQuery('')); dispatch(doUpdateSearchQuery(''));
}, },
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)), updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
@ -35,7 +35,9 @@ const perform = dispatch => ({
doBlur: () => dispatch(doBlurSearchInput()), doBlur: () => dispatch(doBlurSearchInput()),
}); });
export default connect( export default withRouter(
connect(
select, select,
perform perform
)(Wunderbar); )(Wunderbar)
);

View file

@ -7,7 +7,6 @@ import { normalizeURI, SEARCH_TYPES, isURIValid, buildURI } from 'lbry-redux';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import { parseQueryParams } from 'util/query-params'; import { parseQueryParams } from 'util/query-params';
import Autocomplete from './internal/autocomplete'; import Autocomplete from './internal/autocomplete';
import { Location, navigate } from '@reach/router';
const L_KEY_CODE = 76; const L_KEY_CODE = 76;
const ESC_KEY_CODE = 27; const ESC_KEY_CODE = 27;

View file

@ -22,11 +22,12 @@ import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux';
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings'; import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc'; import { doAuthenticate, Lbryio, rewards, doBlackListedOutpointsSubscribe } from 'lbryinc';
import 'scss/all.scss'; import 'scss/all.scss';
import store from 'store'; import { store, history } from 'store';
import pjson from 'package.json'; import pjson from 'package.json';
import app from './app'; import app from './app';
import analytics from './analytics'; import analytics from './analytics';
import doLogWarningConsoleMessage from './logWarningConsoleMessage'; import doLogWarningConsoleMessage from './logWarningConsoleMessage';
import { ConnectedRouter } from 'connected-react-router';
const APPPAGEURL = 'lbry://?'; const APPPAGEURL = 'lbry://?';
@ -219,10 +220,12 @@ const init = () => {
app.store.dispatch(doDaemonReady()); app.store.dispatch(doDaemonReady());
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<ConnectedRouter history={history}>
<ErrorBoundary> <ErrorBoundary>
<App /> <App />
<SnackBar /> <SnackBar />
</ErrorBoundary> </ErrorBoundary>
</ConnectedRouter>
</Provider>, </Provider>,
document.getElementById('app') document.getElementById('app')
); );

View file

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

View file

@ -4,6 +4,7 @@ import { Modal } from 'modal/modal';
import Button from 'component/button'; import Button from 'component/button';
import UserPhoneNew from 'component/userPhoneNew'; import UserPhoneNew from 'component/userPhoneNew';
import UserPhoneVerify from 'component/userPhoneVerify'; import UserPhoneVerify from 'component/userPhoneVerify';
import { withRouter } from 'react-router-dom';
type Props = { type Props = {
phone: ?number, phone: ?number,
@ -11,6 +12,7 @@ type Props = {
phone_number: ?number, phone_number: ?number,
}, },
closeModal: () => void, closeModal: () => void,
history: { push: string => void },
}; };
class ModalPhoneCollection extends React.PureComponent<Props> { class ModalPhoneCollection extends React.PureComponent<Props> {
@ -24,7 +26,7 @@ class ModalPhoneCollection extends React.PureComponent<Props> {
} }
renderInner() { renderInner() {
const { closeModal, phone, user } = this.props; const { closeModal, phone, user, history } = this.props;
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />; const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
@ -33,6 +35,8 @@ class ModalPhoneCollection extends React.PureComponent<Props> {
} else if (!user.phone_number) { } else if (!user.phone_number) {
return <UserPhoneVerify cancelButton={cancelButton} />; return <UserPhoneVerify cancelButton={cancelButton} />;
} }
history.push('/$/rewards');
return closeModal(); return closeModal();
} }
@ -52,4 +56,4 @@ class ModalPhoneCollection extends React.PureComponent<Props> {
} }
} }
export default ModalPhoneCollection; export default withRouter(ModalPhoneCollection);

View file

@ -1,12 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app'; import { doHideModal } from 'redux/actions/app';
import { doAuthNavigate } from 'redux/actions/navigation';
import ModalRewardApprovalRequired from './view'; import ModalRewardApprovalRequired from './view';
const perform = dispatch => ({ const perform = dispatch => ({
doAuth: () => { doAuth: () => {
dispatch(doHideModal()); dispatch(doHideModal());
dispatch(doAuthNavigate()); // dispatch(doAuthNavigate());
}, },
closeModal: () => dispatch(doHideModal()), closeModal: () => dispatch(doHideModal()),
}); });

View file

@ -7,13 +7,13 @@ import UserEmailNew from 'component/userEmailNew';
import UserEmailVerify from 'component/userEmailVerify'; import UserEmailVerify from 'component/userEmailVerify';
import UserVerify from 'component/userVerify'; import UserVerify from 'component/userVerify';
import Page from 'component/page'; import Page from 'component/page';
import { navigate } from '@reach/router';
type Props = { type Props = {
isPending: boolean, isPending: boolean,
email: string, email: string,
pathAfterAuth: string, pathAfterAuth: string,
location: UrlLocation, location: UrlLocation,
history: { push: string => void },
user: ?{ user: ?{
has_verified_email: boolean, has_verified_email: boolean,
is_reward_approved: boolean, is_reward_approved: boolean,
@ -31,7 +31,7 @@ class AuthPage extends React.PureComponent<Props> {
} }
navigateIfAuthenticated = (props: Props) => { navigateIfAuthenticated = (props: Props) => {
const { isPending, user, location } = props; const { isPending, user, location, history } = props;
if ( if (
!isPending && !isPending &&
user && user &&
@ -42,7 +42,7 @@ class AuthPage extends React.PureComponent<Props> {
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const redirectTo = urlParams.get('redirect'); const redirectTo = urlParams.get('redirect');
const path = redirectTo ? `/$/${redirectTo}` : '/'; const path = redirectTo ? `/$/${redirectTo}` : '/';
navigate(path); history.push(path);
} }
}; };

View file

@ -12,7 +12,7 @@ import Page from 'component/page';
import FileList from 'component/fileList'; import FileList from 'component/fileList';
import HiddenNsfwClaims from 'component/hiddenNsfwClaims'; import HiddenNsfwClaims from 'component/hiddenNsfwClaims';
import Button from 'component/button'; import Button from 'component/button';
import { navigate } from '@reach/router'; import { withRouter } from 'react-router-dom';
type Props = { type Props = {
uri: string, uri: string,
@ -23,7 +23,7 @@ type Props = {
claimsInChannel: Array<Claim>, claimsInChannel: Array<Claim>,
channelIsMine: boolean, channelIsMine: boolean,
fetchClaims: (string, number) => void, fetchClaims: (string, number) => void,
navigate: (string, {}) => void, history: { push: string => void },
openModal: (id: string, { uri: string }) => void, openModal: (id: string, { uri: string }) => void,
location: UrlLocation, location: UrlLocation,
}; };
@ -39,6 +39,7 @@ function ChannelPage(props: Props) {
openModal, openModal,
fetchClaims, fetchClaims,
location, location,
history,
} = props; } = props;
const { name, permanent_url: permanentUrl } = claim; const { name, permanent_url: permanentUrl } = claim;
@ -56,7 +57,7 @@ function ChannelPage(props: Props) {
return; return;
} }
navigate(`?page=${pageNumber}`); history.push(`?page=${pageNumber}`);
}; };
const paginate = (e: SyntheticKeyboardEvent<*>) => { const paginate = (e: SyntheticKeyboardEvent<*>) => {
@ -143,4 +144,4 @@ function ChannelPage(props: Props) {
); );
} }
export default ChannelPage; export default withRouter(ChannelPage);

View file

@ -1,5 +1,4 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doAuthNavigate } from 'redux/actions/navigation';
import { doFetchAccessToken, selectAccessToken, selectUser } from 'lbryinc'; import { doFetchAccessToken, selectAccessToken, selectUser } from 'lbryinc';
import { selectDaemonSettings } from 'redux/selectors/settings'; import { selectDaemonSettings } from 'redux/selectors/settings';
import HelpPage from './view'; import HelpPage from './view';
@ -11,7 +10,7 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
doAuth: () => dispatch(doAuthNavigate('/help')), // doAuth: () => dispatch(doAuthNavigate('/help')),
fetchAccessToken: () => dispatch(doFetchAccessToken()), fetchAccessToken: () => dispatch(doFetchAccessToken()),
}); });

View file

@ -1,3 +1,3 @@
import UserHistoryPage from './view'; import NavigationHistoryPage from './view';
export default UserHistoryPage; export default NavigationHistoryPage;

View file

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

View file

@ -27,7 +27,7 @@ type Props = {
class RewardsPage extends PureComponent<Props> { class RewardsPage extends PureComponent<Props> {
renderPageHeader() { renderPageHeader() {
const { doAuth, user, daemonSettings } = this.props; const { user, daemonSettings } = this.props;
if (user && !user.is_reward_approved && daemonSettings && daemonSettings.share_usage_data) { if (user && !user.is_reward_approved && daemonSettings && daemonSettings.share_usage_data) {
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) { if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
@ -42,7 +42,7 @@ class RewardsPage extends PureComponent<Props> {
</header> </header>
<div className="card__content"> <div className="card__content">
<Button onClick={doAuth} button="primary" label="Prove Humanity" /> <Button navigate="/$/auth?redirect=rewards" button="primary" label="Prove Humanity" />
</div> </div>
</section> </section>
); );

View file

@ -10,7 +10,6 @@ import Page from 'component/page';
import ToolTip from 'component/common/tooltip'; import ToolTip from 'component/common/tooltip';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import SearchOptions from 'component/searchOptions'; import SearchOptions from 'component/searchOptions';
import { Location } from '@reach/router';
type Props = { doSearch: string => void, location: UrlLocation }; type Props = { doSearch: string => void, location: UrlLocation };
@ -19,9 +18,17 @@ export default function SearchPage(props: Props) {
doSearch, doSearch,
location: { search }, location: { search },
} = props; } = props;
const urlParams = new URLSearchParams(search);
const urlParams = new URLSearchParams(location.search);
const urlQuery = urlParams.get('q'); const urlQuery = urlParams.get('q');
const isValid = isURIValid(urlQuery);
let uri;
let isChannel;
let label;
if (isValid) {
uri = normalizeURI(urlQuery);
({ isChannel } = parseURI(uri));
}
useEffect(() => { useEffect(() => {
if (urlQuery) { if (urlQuery) {
@ -31,39 +38,8 @@ export default function SearchPage(props: Props) {
return ( return (
<Page noPadding> <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 (
<section className="search"> <section className="search">
{query && ( {urlQuery && (
<Fragment> <Fragment>
<header className="search__header"> <header className="search__header">
{isValid && ( {isValid && (
@ -81,7 +57,7 @@ export default function SearchPage(props: Props) {
</header> </header>
<div className="search__results-wrapper"> <div className="search__results-wrapper">
<FileListSearch query={query} /> <FileListSearch query={urlQuery} />
<div className="card__content help"> <div className="card__content help">
{__('These search results are provided by LBRY, Inc.')} {__('These search results are provided by LBRY, Inc.')}
</div> </div>
@ -89,9 +65,6 @@ export default function SearchPage(props: Props) {
</Fragment> </Fragment>
)} )}
</section> </section>
);
}}
</Location>
</Page> </Page>
); );
} }

View file

@ -11,8 +11,14 @@ import { selectBlackListedOutpoints } from 'lbryinc';
import ShowPage from './view'; import ShowPage from './view';
const select = (state, props) => { const select = (state, props) => {
const { pathname } = props.location;
const urlParts = pathname.split('/');
const claimName = urlParts[1];
const claimId = urlParts[2];
// claimName and claimId come from the url `lbry.tv/{claimName}/{claimId}" // claimName and claimId come from the url `lbry.tv/{claimName}/{claimId}"
const uri = buildURI({ contentName: props.claimName, claimId: props.claimId }); const uri = buildURI({ contentName: claimName, claimId: claimId });
return { return {
claim: makeSelectClaimForUri(uri)(state), claim: makeSelectClaimForUri(uri)(state),
isResolvingUri: makeSelectIsUriResolving(uri)(state), isResolvingUri: makeSelectIsUriResolving(uri)(state),

45
src/ui/reducers.js Normal file
View file

@ -0,0 +1,45 @@
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import {
claimsReducer,
fileInfoReducer,
searchReducer,
walletReducer,
notificationsReducer,
} from 'lbry-redux';
import {
userReducer,
rewardsReducer,
costInfoReducer,
blacklistReducer,
homepageReducer,
statsReducer,
} from 'lbryinc';
import appReducer from 'redux/reducers/app';
import availabilityReducer from 'redux/reducers/availability';
import contentReducer from 'redux/reducers/content';
import settingsReducer from 'redux/reducers/settings';
import subscriptionsReducer from 'redux/reducers/subscriptions';
import publishReducer from 'redux/reducers/publish';
export default history =>
combineReducers({
router: connectRouter(history),
app: appReducer,
availability: availabilityReducer,
blacklist: blacklistReducer,
claims: claimsReducer,
content: contentReducer,
costInfo: costInfoReducer,
fileInfo: fileInfoReducer,
homepage: homepageReducer,
notifications: notificationsReducer,
publish: publishReducer,
rewards: rewardsReducer,
search: searchReducer,
settings: settingsReducer,
stats: statsReducer,
subscriptions: subscriptionsReducer,
user: userReducer,
wallet: walletReducer,
});

View file

@ -4,13 +4,11 @@ import isDev from 'electron-is-dev';
import { ipcRenderer, remote } from 'electron'; import { ipcRenderer, remote } from 'electron';
// @endif // @endif
import path from 'path'; import path from 'path';
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { Lbry, doBalanceSubscribe, doFetchFileInfosAndPublishedClaims, doError } from 'lbry-redux'; import { Lbry, doBalanceSubscribe, doFetchFileInfosAndPublishedClaims, doError } from 'lbry-redux';
import Native from 'native'; import Native from 'native';
import { doFetchDaemonSettings } from 'redux/actions/settings'; import { doFetchDaemonSettings } from 'redux/actions/settings';
import { doAuthNavigate } from 'redux/actions/navigation';
import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions'; import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions';
import { import {
selectIsUpgradeSkipped, selectIsUpgradeSkipped,
@ -390,7 +388,7 @@ export function doConditionalAuthNavigate(newSession) {
const modal = selectModal(state); const modal = selectModal(state);
if (newSession || (modal && modal.id !== MODALS.EMAIL_COLLECTION)) { if (newSession || (modal && modal.id !== MODALS.EMAIL_COLLECTION)) {
dispatch(doAuthNavigate()); // dispatch(doAuthNavigate());
} }
}; };
} }

View file

@ -7,7 +7,7 @@ import * as MODALS from 'constants/modal_types';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
// @endif // @endif
import { doOpenModal } from 'redux/actions/app'; import { doOpenModal } from 'redux/actions/app';
import { navigate } from '@reach/router'; import { push } from 'connected-react-router';
import { setSubscriptionLatest, doUpdateUnreadSubscriptions } from 'redux/actions/subscriptions'; import { setSubscriptionLatest, doUpdateUnreadSubscriptions } from 'redux/actions/subscriptions';
import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions'; import { makeSelectUnreadByChannel } from 'redux/selectors/subscriptions';
import { import {
@ -83,7 +83,7 @@ export function doUpdateLoadStatus(uri: string, outpoint: string) {
silent: false, silent: false,
}); });
notif.onclick = () => { notif.onclick = () => {
navigate(formatLbryUriForWeb(uri)); dispatch(push(formatLbryUriForWeb(uri)));
}; };
} }

View file

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

View file

@ -1,72 +0,0 @@
import * as ACTIONS from 'constants/action_types';
const getCurrentPath = () => {
const { hash } = document.location;
if (hash !== '') return hash.replace(/^#/, '');
return '/discover';
};
const reducers = {};
const defaultState = {
currentPath: getCurrentPath(),
pathAfterAuth: '/discover',
index: 0,
stack: [],
};
reducers[ACTIONS.DAEMON_READY] = state => {
const { currentPath } = state;
return Object.assign({}, state, {
stack: [{ path: currentPath, scrollY: 0 }],
});
};
reducers[ACTIONS.CHANGE_AFTER_AUTH_PATH] = (state, action) =>
Object.assign({}, state, {
pathAfterAuth: action.data.path,
});
reducers[ACTIONS.HISTORY_NAVIGATE] = (state, action) => {
const { stack, index } = state;
const { url: path, index: newIndex } = action.data;
const newState = {
currentPath: path,
};
if (newIndex >= 0) {
newState.index = newIndex;
} else if (!stack[index] || stack[index].path !== path) {
// ^ Check for duplicated
newState.stack = [...stack.slice(0, index + 1), { path, scrollY: 0 }];
newState.index = newState.stack.length - 1;
}
return Object.assign({}, state, newState);
};
reducers[ACTIONS.WINDOW_SCROLLED] = (state, action) => {
const { index } = state;
const { scrollY } = action.data;
return Object.assign({}, state, {
stack: state.stack.map((stackItem, itemIndex) => {
if (itemIndex !== index) {
return stackItem;
}
return {
...stackItem,
scrollY,
};
}),
});
};
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) {
return handler(state, action);
}
return state;
}

View file

@ -1,31 +1,12 @@
import appReducer from 'redux/reducers/app';
import availabilityReducer from 'redux/reducers/availability';
import contentReducer from 'redux/reducers/content';
import {
claimsReducer,
fileInfoReducer,
searchReducer,
walletReducer,
notificationsReducer,
} from 'lbry-redux';
import {
userReducer,
rewardsReducer,
costInfoReducer,
blacklistReducer,
homepageReducer,
statsReducer,
} from 'lbryinc';
import navigationReducer from 'redux/reducers/navigation';
import settingsReducer from 'redux/reducers/settings';
import subscriptionsReducer from 'redux/reducers/subscriptions';
import publishReducer from 'redux/reducers/publish';
import { persistStore, autoRehydrate } from 'redux-persist'; import { persistStore, autoRehydrate } from 'redux-persist';
import createCompressor from 'redux-persist-transform-compress'; import createCompressor from 'redux-persist-transform-compress';
import createFilter from 'redux-persist-transform-filter'; import createFilter from 'redux-persist-transform-filter';
import localForage from 'localforage'; import localForage from 'localforage';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
import { createHashHistory, createBrowserHistory } from 'history';
import { connectRouter, routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers';
function isFunction(object) { function isFunction(object) {
return typeof object === 'function'; return typeof object === 'function';
@ -55,34 +36,18 @@ function enableBatching(reducer) {
}; };
} }
const reducers = combineReducers({ // @if TARGET='app'
app: appReducer, const history = createHashHistory();
navigation: navigationReducer, // @endif
availability: availabilityReducer, // @if TARGET='web'
claims: claimsReducer, const history = createBrowserHistory();
fileInfo: fileInfoReducer, // @endif
content: contentReducer,
costInfo: costInfoReducer,
rewards: rewardsReducer,
search: searchReducer,
settings: settingsReducer,
wallet: walletReducer,
user: userReducer,
subscriptions: subscriptionsReducer,
publish: publishReducer,
notifications: notificationsReducer,
blacklist: blacklistReducer,
homepage: homepageReducer,
stats: statsReducer,
});
const bulkThunk = createBulkThunkMiddleware(); const bulkThunk = createBulkThunkMiddleware();
const middleware = [thunk, bulkThunk]; const middleware = [routerMiddleware(history), thunk, bulkThunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore( const store = createStore(
enableBatching(reducers), enableBatching(createRootReducer(history)),
{}, // initial state {}, // initial state
composeEnhancers( composeEnhancers(
autoRehydrate({ autoRehydrate({
@ -126,4 +91,4 @@ window.cacheStore = persistStore(store, persistOptions, err => {
}); });
// @endif // @endif
export default store; export { store, history };

View file

@ -7,6 +7,18 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="text/javascript" src="ui.js"></script> <script type="text/javascript">
// Use relative path if we are in electron
let src = 'ui.js';
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf('electron') === -1) {
src = `/${src}`;
}
const script = document.createElement('script');
script.setAttribute('src', src);
document.body.appendChild(script);
</script>
</body> </body>
</html> </html>

View file

@ -53,7 +53,7 @@ let baseConfig = {
use: { use: {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
outputPath: '$/static/img', outputPath: 'static/img',
name: '[name].[ext]', name: '[name].[ext]',
}, },
}, },
@ -63,7 +63,7 @@ let baseConfig = {
use: { use: {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
outputPath: '$/static/font', outputPath: 'static/font',
}, },
}, },
}, },

139
yarn.lock
View file

@ -734,6 +734,13 @@
dependencies: dependencies:
regenerator-runtime "^0.12.0" regenerator-runtime "^0.12.0"
"@babel/runtime@^7.3.1":
version "7.4.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc"
integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2":
version "7.2.2" version "7.2.2"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
@ -850,17 +857,6 @@
resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf" resolved "https://registry.yarnpkg.com/@posthtml/esm/-/esm-1.0.0.tgz#09bcb28a02438dcee22ad1970ca1d85a000ae0cf"
integrity sha512-dEVG+ITnvqKGa4v040tP+n8LOKOqr94qjLva7bE5pnfm2KHJwsKz69J4KMxgWLznbpBJzy8vQfCayEk3vLZnZQ== integrity sha512-dEVG+ITnvqKGa4v040tP+n8LOKOqr94qjLva7bE5pnfm2KHJwsKz69J4KMxgWLznbpBJzy8vQfCayEk3vLZnZQ==
"@reach/router@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.2.1.tgz#34ae3541a5ac44fa7796e5506a5d7274a162be4e"
integrity sha512-kTaX08X4g27tzIFQGRukaHmNbtMYDS3LEWIS8+l6OayGIw6Oyo1HIF/JzeuR2FoF9z6oV+x/wJSVSq4v8tcUGQ==
dependencies:
create-react-context "^0.2.1"
invariant "^2.2.3"
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
warning "^3.0.0"
"@samverschueren/stream-to-observable@^0.3.0": "@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@ -2545,6 +2541,14 @@ connect-history-api-fallback@^1.3.0:
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
connected-react-router@^6.3.2:
version "6.3.2"
resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.3.2.tgz#8c90b77f1d7b783608cd50e4f69bf60e47265425"
integrity sha512-YxrAfMExl/OBsi+ojA4ywZeC7cmQ52MnZ4bhzqLhhjuOiXcQogC4kW0kodouXAXrXDovb2l3yEhDfpH99/wYcw==
dependencies:
immutable "^3.8.1"
seamless-immutable "^7.1.3"
console-browserify@^1.1.0: console-browserify@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
@ -2697,7 +2701,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
create-react-context@^0.2.1: create-react-context@^0.2.2:
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3" resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3"
integrity sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag== integrity sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==
@ -5104,6 +5108,18 @@ highlight.js@^9.3.0:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.6.tgz#72d4d8d779ec066af9a17cb14360c3def0aa57c4" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.6.tgz#72d4d8d779ec066af9a17cb14360c3def0aa57c4"
integrity sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ== integrity sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==
history@^4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca"
integrity sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==
dependencies:
"@babel/runtime" "^7.1.2"
loose-envify "^1.2.0"
resolve-pathname "^2.2.0"
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
value-equal "^0.4.0"
hmac-drbg@^1.0.0: hmac-drbg@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@ -5374,6 +5390,11 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
immutable@^3.8.1:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=
import-fresh@^2.0.0: import-fresh@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
@ -5495,7 +5516,7 @@ interpret@^1.0.0, interpret@^1.1.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@ -6510,7 +6531,7 @@ longest-streak@^2.0.1:
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e"
integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA== integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -7798,6 +7819,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-to-regexp@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=
dependencies:
isarray "0.0.1"
path-type@^1.0.0: path-type@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@ -8385,7 +8413,7 @@ promise@^7.1.1:
dependencies: dependencies:
asap "~2.0.3" asap "~2.0.3"
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -8641,7 +8669,12 @@ react-hot-loader@^4.7.2:
shallowequal "^1.0.2" shallowequal "^1.0.2"
source-map "^0.7.3" source-map "^0.7.3"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: react-is@^16.6.0, react-is@^16.8.2:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
react-is@^16.7.0, react-is@^16.8.1:
version "16.8.3" version "16.8.3"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.3.tgz#4ad8b029c2a718fc0cfc746c8d4e1b7221e5387d" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.3.tgz#4ad8b029c2a718fc0cfc746c8d4e1b7221e5387d"
integrity sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA== integrity sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==
@ -8678,18 +8711,46 @@ react-pose@^4.0.5:
popmotion-pose "^3.4.0" popmotion-pose "^3.4.0"
tslib "^1.9.1" tslib "^1.9.1"
react-redux@^5.0.3: react-redux@^6.0.1:
version "5.1.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.1.tgz#88e368682c7fa80e34e055cd7ac56f5936b0f52f" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.1.tgz#0d423e2c1cb10ada87293d47e7de7c329623ba4d"
integrity sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg== integrity sha512-T52I52Kxhbqy/6TEfBv85rQSDz6+Y28V/pf52vDWs1YRXG19mcFOGfHnY2HsNFHyhP+ST34Aih98fvt6tqwVcQ==
dependencies:
"@babel/runtime" "^7.3.1"
hoist-non-react-statics "^3.3.0"
invariant "^2.2.4"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.8.2"
react-router-dom@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.0.tgz#542a9b86af269a37f0b87218c4c25ea8dcf0c073"
integrity sha512-wSpja5g9kh5dIteZT3tUoggjnsa+TPFHSMrpHXMpFsaHhQkm/JNVGh2jiF9Dkh4+duj4MKCkwO6H08u6inZYgQ==
dependencies: dependencies:
"@babel/runtime" "^7.1.2" "@babel/runtime" "^7.1.2"
history "^4.9.0"
loose-envify "^1.3.1"
prop-types "^15.6.2"
react-router "5.0.0"
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-router@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.0.tgz#349863f769ffc2fa10ee7331a4296e86bc12879d"
integrity sha512-6EQDakGdLG/it2x9EaCt9ZpEEPxnd0OCLBHQ1AcITAAx7nCnyvnzf76jKWG1s2/oJ7SSviUgfWHofdYljFexsA==
dependencies:
"@babel/runtime" "^7.1.2"
create-react-context "^0.2.2"
history "^4.9.0"
hoist-non-react-statics "^3.1.0" hoist-non-react-statics "^3.1.0"
invariant "^2.2.4" loose-envify "^1.3.1"
loose-envify "^1.1.0" path-to-regexp "^1.7.0"
prop-types "^15.6.1" prop-types "^15.6.2"
react-is "^16.6.0" react-is "^16.6.0"
react-lifecycles-compat "^3.0.0" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-simplemde-editor@^4.0.0: react-simplemde-editor@^4.0.0:
version "4.0.0" version "4.0.0"
@ -8926,6 +8987,11 @@ regenerator-runtime@^0.12.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-runtime@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
regenerator-transform@^0.13.4: regenerator-transform@^0.13.4:
version "0.13.4" version "0.13.4"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb"
@ -9209,6 +9275,11 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve-pathname@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
integrity sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==
resolve-url@^0.2.1: resolve-url@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@ -9386,6 +9457,11 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8" js-base64 "^2.1.8"
source-map "^0.4.2" source-map "^0.4.2"
seamless-immutable@^7.1.3:
version "7.1.4"
resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8"
integrity sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==
seek-bzip@^1.0.5: seek-bzip@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc"
@ -10315,6 +10391,16 @@ timers-browserify@^2.0.4:
dependencies: dependencies:
setimmediate "^1.0.4" setimmediate "^1.0.4"
tiny-invariant@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.4.tgz#346b5415fd93cb696b0c4e8a96697ff590f92463"
integrity sha512-lMhRd/djQJ3MoaHEBrw8e2/uM4rs9YMNk0iOr8rHQ0QdbM7D4l0gFl3szKdeixrlyfm9Zqi4dxHCM2qVG8ND5g==
tiny-warning@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.2.tgz#1dfae771ee1a04396bdfde27a3adcebc6b648b28"
integrity sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==
tmp@^0.0.33: tmp@^0.0.33:
version "0.0.33" version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -10887,6 +10973,11 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0" spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0" spdx-expression-parse "^3.0.0"
value-equal@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
integrity sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==
vary@~1.1.2: vary@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"