feat: add support for search filters
This commit is contained in:
parent
541f6fc34a
commit
ff0478ade3
20 changed files with 316 additions and 177 deletions
|
@ -34,6 +34,7 @@
|
||||||
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@lbry/components": "^2.2.0",
|
||||||
"@types/three": "^0.93.1",
|
"@types/three": "^0.93.1",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"breakdance": "^3.0.1",
|
"breakdance": "^3.0.1",
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
"hast-util-sanitize": "^1.1.2",
|
"hast-util-sanitize": "^1.1.2",
|
||||||
"keytar": "^4.2.1",
|
"keytar": "^4.2.1",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#42c185e922a7c6091b0e1580bacbfd8e02f45a91",
|
"lbry-redux": "lbryio/lbry-redux#3ab065b11a52d3e2e6a50a25459f9ff0aac03b13",
|
||||||
"lbryinc": "lbryio/lbryinc#60d80401891743f991c040bafa8e51da7e939777",
|
"lbryinc": "lbryio/lbryinc#60d80401891743f991c040bafa8e51da7e939777",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
"mammoth": "^1.4.6",
|
"mammoth": "^1.4.6",
|
||||||
|
@ -62,8 +63,8 @@
|
||||||
"node-fetch": "^2.3.0",
|
"node-fetch": "^2.3.0",
|
||||||
"qrcode.react": "^0.8.0",
|
"qrcode.react": "^0.8.0",
|
||||||
"rc-progress": "^2.0.6",
|
"rc-progress": "^2.0.6",
|
||||||
"react": "^16.6.0",
|
"react": "^16.8.2",
|
||||||
"react-dom": "^16.6.0",
|
"react-dom": "^16.8.2",
|
||||||
"react-feather": "^1.0.8",
|
"react-feather": "^1.0.8",
|
||||||
"react-modal": "^3.1.7",
|
"react-modal": "^3.1.7",
|
||||||
"react-paginate": "^5.2.1",
|
"react-paginate": "^5.2.1",
|
||||||
|
@ -89,7 +90,6 @@
|
||||||
"y18n": "^4.0.0"
|
"y18n": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lbry/components": "^2.2.0",
|
|
||||||
"babel-eslint": "^8.2.2",
|
"babel-eslint": "^8.2.2",
|
||||||
"babel-plugin-module-resolver": "^3.1.1",
|
"babel-plugin-module-resolver": "^3.1.1",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
|
|
|
@ -29,14 +29,16 @@ type Props = {
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
},
|
},
|
||||||
inputButton: ?React.Node,
|
inputButton: ?React.Node,
|
||||||
|
blockWrap: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormField extends React.PureComponent<Props> {
|
export class FormField extends React.PureComponent<Props> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
labelOnLeft: false,
|
labelOnLeft: false,
|
||||||
|
blockWrap: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.input = React.createRef();
|
this.input = React.createRef();
|
||||||
}
|
}
|
||||||
|
@ -66,31 +68,39 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
autoFocus,
|
autoFocus,
|
||||||
inputButton,
|
inputButton,
|
||||||
labelOnLeft,
|
labelOnLeft,
|
||||||
|
blockWrap,
|
||||||
...inputProps
|
...inputProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const errorMessage = typeof error === 'object' ? error.message : error;
|
const errorMessage = typeof error === 'object' ? error.message : error;
|
||||||
|
|
||||||
|
const Wrapper = blockWrap
|
||||||
|
? ({ children: innerChildren }) => <fieldset-section>{innerChildren}</fieldset-section>
|
||||||
|
: ({ children: innerChildren }) => <React.Fragment>{innerChildren}</React.Fragment>;
|
||||||
|
|
||||||
let input;
|
let input;
|
||||||
if (type) {
|
if (type) {
|
||||||
if (type === 'radio') {
|
if (type === 'radio') {
|
||||||
input = (
|
input = (
|
||||||
<fieldset-section>
|
<Wrapper>
|
||||||
<radio-element>
|
<radio-element>
|
||||||
<input id={name} type="radio" {...inputProps} />
|
<input id={name} type="radio" {...inputProps} />
|
||||||
<label htmlFor={name}>{label}</label>
|
<label htmlFor={name}>{label}</label>
|
||||||
<radio-toggle onClick={inputProps.onChange} />
|
<radio-toggle onClick={inputProps.onChange} />
|
||||||
</radio-element>
|
</radio-element>
|
||||||
</fieldset-section>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
} else if (type === 'checkbox') {
|
} else if (type === 'checkbox') {
|
||||||
|
// web components treat props weird
|
||||||
|
// we need to fully remove it for proper component:attribute css styling
|
||||||
|
const elementProps = inputProps.disabled ? { disabled: true } : {};
|
||||||
input = (
|
input = (
|
||||||
<fieldset-section>
|
<Wrapper>
|
||||||
<checkbox-element>
|
<checkbox-element {...elementProps}>
|
||||||
<input id={name} type="checkbox" {...inputProps} />
|
<input id={name} type="checkbox" {...inputProps} />
|
||||||
<label htmlFor={name}>{label}</label>
|
<label htmlFor={name}>{label}</label>
|
||||||
<checkbox-toggle onClick={inputProps.onChange} />
|
<checkbox-toggle onClick={inputProps.onChange} />
|
||||||
</checkbox-element>
|
</checkbox-element>
|
||||||
</fieldset-section>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
} else if (type === 'setting') {
|
} else if (type === 'setting') {
|
||||||
// 'setting' should only be used for settings. Forms should use "checkbox"
|
// 'setting' should only be used for settings. Forms should use "checkbox"
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectSearchUris, selectIsSearching, selectSearchDownloadUris } from 'lbry-redux';
|
import {
|
||||||
|
makeSelectSearchUris,
|
||||||
|
selectIsSearching,
|
||||||
|
selectSearchDownloadUris,
|
||||||
|
makeSelectQueryWithOptions,
|
||||||
|
} from 'lbry-redux';
|
||||||
import FileListSearch from './view';
|
import FileListSearch from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
uris: makeSelectSearchUris(props.query)(state),
|
uris: makeSelectSearchUris(makeSelectQueryWithOptions()(state))(state),
|
||||||
downloadUris: selectSearchDownloadUris(props.query)(state),
|
downloadUris: selectSearchDownloadUris(props.query)(state),
|
||||||
isSearching: selectIsSearching(state),
|
isSearching: selectIsSearching(state),
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,26 +11,11 @@ type Props = {
|
||||||
query: string,
|
query: string,
|
||||||
isSearching: boolean,
|
isSearching: boolean,
|
||||||
uris: ?Array<string>,
|
uris: ?Array<string>,
|
||||||
downloadUris: ?Array<string>,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileListSearch extends React.PureComponent<Props> {
|
class FileListSearch extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { uris, query, downloadUris, isSearching } = this.props;
|
const { uris, query, isSearching } = this.props;
|
||||||
|
|
||||||
const fileResults = [];
|
|
||||||
const channelResults = [];
|
|
||||||
if (uris && uris.length) {
|
|
||||||
uris.forEach(uri => {
|
|
||||||
const isChannel = parseURI(uri).claimName[0] === '@';
|
|
||||||
if (isChannel) {
|
|
||||||
channelResults.push(uri);
|
|
||||||
} else {
|
|
||||||
fileResults.push(uri);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
query && (
|
query && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -38,26 +23,15 @@ class FileListSearch extends React.PureComponent<Props> {
|
||||||
<section className="search__results-section">
|
<section className="search__results-section">
|
||||||
<div className="search__results-title">{__('Search Results')}</div>
|
<div className="search__results-title">{__('Search Results')}</div>
|
||||||
<HiddenNsfwClaims uris={uris} />
|
<HiddenNsfwClaims uris={uris} />
|
||||||
{!isSearching && fileResults.length ? (
|
{!isSearching && uris && uris.length ? (
|
||||||
fileResults.map(uri => <FileTile key={uri} uri={uri} />)
|
uris.map(
|
||||||
) : (
|
uri =>
|
||||||
<NoResults />
|
parseURI(uri).claimName[0] === '@' ? (
|
||||||
)}
|
<ChannelTile key={uri} uri={uri} />
|
||||||
</section>
|
) : (
|
||||||
|
<FileTile key={uri} uri={uri} />
|
||||||
<section className="search__results-section">
|
)
|
||||||
<div className="search__results-title">{__('Channels')}</div>
|
)
|
||||||
{!isSearching && channelResults.length ? (
|
|
||||||
channelResults.map(uri => <ChannelTile key={uri} uri={uri} />)
|
|
||||||
) : (
|
|
||||||
<NoResults />
|
|
||||||
)}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="search__results-section">
|
|
||||||
<div className="search__results-title">{__('Your downloads')}</div>
|
|
||||||
{downloadUris && downloadUris.length ? (
|
|
||||||
downloadUris.map(uri => <FileTile hideNoResult key={uri} uri={uri} />)
|
|
||||||
) : (
|
) : (
|
||||||
<NoResults />
|
<NoResults />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -156,10 +156,12 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="media__title">
|
<div className="media__title">
|
||||||
{(title || name) && (
|
{(title || name) && (
|
||||||
<TruncatedText text={title || name} lines={size === 'small' ? 2 : 3} />
|
<TruncatedText text={title || name} lines={size !== 'small' ? 1 : 2} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{size === 'small' && this.renderFileProperties()}
|
||||||
|
|
||||||
{size !== 'small' ? (
|
{size !== 'small' ? (
|
||||||
<div className="media__subtext">
|
<div className="media__subtext">
|
||||||
{__('Published to')} <UriIndicator uri={uri} link />{' '}
|
{__('Published to')} <UriIndicator uri={uri} link />{' '}
|
||||||
|
@ -169,9 +171,9 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="media__subtext">
|
<div className="media__subtext">
|
||||||
<UriIndicator uri={uri} link />
|
<UriIndicator uri={uri} link />
|
||||||
</div>
|
<div>
|
||||||
<div className="media__subtext">
|
<DateTime timeAgo block={height} />
|
||||||
<DateTime timeAgo block={height} />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
@ -184,7 +186,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{this.renderFileProperties()}
|
{size !== 'small' && this.renderFileProperties()}
|
||||||
|
|
||||||
{!name && (
|
{!name && (
|
||||||
<Yrbl
|
<Yrbl
|
||||||
|
|
16
src/renderer/component/searchOptions/index.js
Normal file
16
src/renderer/component/searchOptions/index.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectSearchOptions, doUpdateSearchOptions } from 'lbry-redux';
|
||||||
|
import SearchOptions from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
options: selectSearchOptions(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
setSearchOption: (option, value) => dispatch(doUpdateSearchOptions({ [option]: value })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(SearchOptions);
|
123
src/renderer/component/searchOptions/view.jsx
Normal file
123
src/renderer/component/searchOptions/view.jsx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// @flow
|
||||||
|
import * as ICONS from 'constants/icons';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { SEARCH_OPTIONS } from 'lbry-redux';
|
||||||
|
import { Form, FormField } from 'component/common/form';
|
||||||
|
import posed from 'react-pose';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
|
const ExpandableOptions = posed.div({
|
||||||
|
hide: { height: 0, opacity: 0 },
|
||||||
|
show: { height: 280, opacity: 1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
setSearchOption: (string, boolean | string | number) => void,
|
||||||
|
options: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const SearchOptions = (props: Props) => {
|
||||||
|
const { options, setSearchOption } = props;
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
const resultCount = options[SEARCH_OPTIONS.RESULT_COUNT];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="card card--section search__options-wrapper">
|
||||||
|
<div className="card--space-between">
|
||||||
|
<Button
|
||||||
|
label={__('SEARCH OPTIONS')}
|
||||||
|
icon={ICONS.OPTIONS}
|
||||||
|
onClick={() => setExpanded(!expanded)}
|
||||||
|
/>
|
||||||
|
{/*
|
||||||
|
Will be added back when api is ready
|
||||||
|
<div className="media__action-group">
|
||||||
|
<span>{__('Find what you were looking for?')}</span>
|
||||||
|
<Button description={__('Yes')} icon={ICONS.YES} />
|
||||||
|
<Button description={__('No')} icon={ICONS.NO} />
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
<ExpandableOptions pose={expanded ? 'show' : 'hide'}>
|
||||||
|
{expanded && (
|
||||||
|
<Form className="card__content search__options">
|
||||||
|
<fieldset>
|
||||||
|
<legend className="search__legend--1">{__('Search For')}</legend>
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.INCLUDE_FILES,
|
||||||
|
label: __('Files'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.INCLUDE_CHANNELS,
|
||||||
|
label: __('Channels'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.INCLUDE_FILES_AND_CHANNELS,
|
||||||
|
label: __('Everything'),
|
||||||
|
},
|
||||||
|
].map(({ option, label }) => (
|
||||||
|
<FormField
|
||||||
|
key={option}
|
||||||
|
type="radio"
|
||||||
|
blockWrap={false}
|
||||||
|
label={label}
|
||||||
|
checked={options[SEARCH_OPTIONS.CLAIM_TYPE] === option}
|
||||||
|
onChange={() => setSearchOption(SEARCH_OPTIONS.CLAIM_TYPE, option)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend className="search__legend--2">{__('File Types')}</legend>
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.MEDIA_VIDEO,
|
||||||
|
label: __('Videos'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.MEDIA_AUDIO,
|
||||||
|
label: __('Sounds'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.MEDIA_IMAGE,
|
||||||
|
label: __('Images'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.MEDIA_TEXT,
|
||||||
|
label: __('Text'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: SEARCH_OPTIONS.MEDIA_APPLICATION,
|
||||||
|
label: __('Other Files'),
|
||||||
|
},
|
||||||
|
].map(({ option, label }) => (
|
||||||
|
<FormField
|
||||||
|
key={option}
|
||||||
|
type="checkbox"
|
||||||
|
blockWrap={false}
|
||||||
|
disabled={options[SEARCH_OPTIONS.CLAIM_TYPE] === SEARCH_OPTIONS.INCLUDE_CHANNELS}
|
||||||
|
label={label}
|
||||||
|
checked={options[option]}
|
||||||
|
onChange={() => setSearchOption(option, !options[option])}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend className="search__legend--3">{__('Other Options')}</legend>
|
||||||
|
<FormField
|
||||||
|
type="number"
|
||||||
|
value={resultCount}
|
||||||
|
onChange={e => setSearchOption(SEARCH_OPTIONS.RESULT_COUNT, e.target.value)}
|
||||||
|
blockWrap={false}
|
||||||
|
label={__('Returned Results')}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</ExpandableOptions>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchOptions;
|
|
@ -10,8 +10,6 @@ import {
|
||||||
doToast,
|
doToast,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import analytics from 'analytics';
|
import analytics from 'analytics';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
|
||||||
import * as settings from 'constants/settings';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import Wunderbar from './view';
|
import Wunderbar from './view';
|
||||||
|
|
||||||
|
@ -27,13 +25,12 @@ const select = state => {
|
||||||
...searchState,
|
...searchState,
|
||||||
wunderbarValue,
|
wunderbarValue,
|
||||||
suggestions: selectSearchSuggestions(state),
|
suggestions: selectSearchSuggestions(state),
|
||||||
resultCount: makeSelectClientSetting(settings.RESULT_COUNT)(state),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
onSearch: (query, size) => {
|
onSearch: query => {
|
||||||
dispatch(doSearch(query, size));
|
dispatch(doSearch(query));
|
||||||
dispatch(doNavigate(`/search`, { query }));
|
dispatch(doNavigate(`/search`, { query }));
|
||||||
analytics.apiLogSearch();
|
analytics.apiLogSearch();
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,13 +12,12 @@ const ESC_KEY_CODE = 27;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
updateSearchQuery: string => void,
|
updateSearchQuery: string => void,
|
||||||
onSearch: (string, ?number) => void,
|
onSearch: string => void,
|
||||||
onSubmit: (string, {}) => void,
|
onSubmit: (string, {}) => void,
|
||||||
wunderbarValue: ?string,
|
wunderbarValue: ?string,
|
||||||
suggestions: Array<string>,
|
suggestions: Array<string>,
|
||||||
doFocus: () => void,
|
doFocus: () => void,
|
||||||
doBlur: () => void,
|
doBlur: () => void,
|
||||||
resultCount: number,
|
|
||||||
focused: boolean,
|
focused: boolean,
|
||||||
doShowSnackBar: ({}) => void,
|
doShowSnackBar: ({}) => void,
|
||||||
};
|
};
|
||||||
|
@ -82,7 +81,7 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(value: string, suggestion?: { value: string, type: string }) {
|
handleSubmit(value: string, suggestion?: { value: string, type: string }) {
|
||||||
const { onSubmit, onSearch, resultCount } = this.props;
|
const { onSubmit, onSearch } = this.props;
|
||||||
const query = value.trim();
|
const query = value.trim();
|
||||||
const getParams = () => {
|
const getParams = () => {
|
||||||
const parts = query.split('?');
|
const parts = query.split('?');
|
||||||
|
@ -98,7 +97,7 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
// User selected a suggestion
|
// User selected a suggestion
|
||||||
if (suggestion) {
|
if (suggestion) {
|
||||||
if (suggestion.type === 'search') {
|
if (suggestion.type === 'search') {
|
||||||
onSearch(query, resultCount);
|
onSearch(query);
|
||||||
} else if (isURIValid(query)) {
|
} else if (isURIValid(query)) {
|
||||||
const params = getParams();
|
const params = getParams();
|
||||||
const uri = normalizeURI(query);
|
const uri = normalizeURI(query);
|
||||||
|
@ -125,7 +124,7 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
onSearch(query, resultCount);
|
onSearch(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,3 +41,6 @@ export const WALLET = 'CreditCard';
|
||||||
export const SETTINGS = 'Settings';
|
export const SETTINGS = 'Settings';
|
||||||
export const INVITE = 'Users';
|
export const INVITE = 'Users';
|
||||||
export const FILE = 'File';
|
export const FILE = 'File';
|
||||||
|
export const OPTIONS = 'Sliders';
|
||||||
|
export const YES = 'ThumbsUp';
|
||||||
|
export const NO = 'ThumbsDown';
|
||||||
|
|
|
@ -1,22 +1,16 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as settings from 'constants/settings';
|
|
||||||
import { selectIsSearching, makeSelectCurrentParam, doUpdateSearchQuery } from 'lbry-redux';
|
import { selectIsSearching, makeSelectCurrentParam, doUpdateSearchQuery } from 'lbry-redux';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
|
||||||
import SearchPage from './view';
|
import SearchPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
isSearching: selectIsSearching(state),
|
isSearching: selectIsSearching(state),
|
||||||
query: makeSelectCurrentParam('query')(state),
|
query: makeSelectCurrentParam('query')(state),
|
||||||
showUnavailable: makeSelectClientSetting(settings.SHOW_UNAVAILABLE)(state),
|
|
||||||
resultCount: makeSelectClientSetting(settings.RESULT_COUNT)(state),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as SETTINGS from 'constants/settings';
|
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { isURIValid, normalizeURI, parseURI } from 'lbry-redux';
|
import { isURIValid, normalizeURI, parseURI } from 'lbry-redux';
|
||||||
|
@ -9,32 +8,15 @@ import FileListSearch from 'component/fileListSearch';
|
||||||
import Page from 'component/page';
|
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';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
query: ?string,
|
query: ?string,
|
||||||
resultCount: number,
|
|
||||||
setClientSetting: (string, number | boolean) => void,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchPage extends React.PureComponent<Props> {
|
class SearchPage extends React.PureComponent<Props> {
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
(this: any).onShowUnavailableChange = this.onShowUnavailableChange.bind(this);
|
|
||||||
(this: any).onSearchResultCountChange = this.onSearchResultCountChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSearchResultCountChange(event: SyntheticInputEvent<*>) {
|
|
||||||
const count = Number(event.target.value);
|
|
||||||
this.props.setClientSetting(SETTINGS.RESULT_COUNT, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
onShowUnavailableChange(event: SyntheticInputEvent<*>) {
|
|
||||||
this.props.setClientSetting(SETTINGS.SHOW_UNAVAILABLE, event.target.checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { query, resultCount } = this.props;
|
const { query } = this.props;
|
||||||
|
|
||||||
const isValid = isURIValid(query);
|
const isValid = isURIValid(query);
|
||||||
|
|
||||||
let uri;
|
let uri;
|
||||||
|
@ -69,14 +51,9 @@ class SearchPage extends React.PureComponent<Props> {
|
||||||
</header>
|
</header>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/*
|
|
||||||
Commented out until I figure out what to do with it in my next PR
|
|
||||||
<div>
|
|
||||||
<FormField type="text" value={resultCount} label={__("Returned results")} /
|
|
||||||
</div>
|
|
||||||
*/}
|
|
||||||
|
|
||||||
<div className="search__results-wrapper">
|
<div className="search__results-wrapper">
|
||||||
|
<SearchOptions />
|
||||||
|
|
||||||
<FileListSearch query={query} />
|
<FileListSearch query={query} />
|
||||||
<div className="help">{__('These search results are provided by LBRY, Inc.')}</div>
|
<div className="help">{__('These search results are provided by LBRY, Inc.')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -97,7 +97,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--uri-indicator {
|
.button--uri-indicator {
|
||||||
color: rgba($lbry-white, 0.9);
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: left;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
// lbry/components overrides and minor styles
|
// lbry/components overrides and minor styles
|
||||||
|
|
||||||
|
input[type='number'] {
|
||||||
|
padding: var(--spacing-s);
|
||||||
|
width: 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox-element {
|
||||||
|
&[disabled='true'] {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkbox-element,
|
checkbox-element,
|
||||||
radio-element,
|
radio-element,
|
||||||
fieldset:last-child,
|
fieldset:last-child,
|
||||||
|
@ -9,6 +20,21 @@ fieldset-section:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkbox-element,
|
||||||
|
radio-element {
|
||||||
|
input[type='checkbox']:checked + label {
|
||||||
|
color: $lbry-black;
|
||||||
|
|
||||||
|
[data-mode='dark'] & {
|
||||||
|
color: $lbry-white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $lbry-teal-4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fieldset-group.fieldset-group--smushed {
|
fieldset-group.fieldset-group--smushed {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
@ -41,6 +67,10 @@ form {
|
||||||
background-color: $lbry-teal-5;
|
background-color: $lbry-teal-5;
|
||||||
border-color: $lbry-teal-5;
|
border-color: $lbry-teal-5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
background-color: $lbry-cyan-5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
.media-tile {
|
.media-tile {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&:not(:last-of-type) {
|
&:not(:last-of-type) {
|
||||||
margin-bottom: var(--spacing-vertical-large);
|
margin-bottom: var(--spacing-vertical-large);
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
.media__info {
|
.media__info {
|
||||||
margin-left: var(--spacing-vertical-medium);
|
margin-left: var(--spacing-vertical-medium);
|
||||||
width: calc(80% - 20rem);
|
width: calc(80% - 20rem);
|
||||||
|
min-width: 40rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@
|
||||||
|
|
||||||
.media__info {
|
.media__info {
|
||||||
margin-left: var(--spacing-vertical-large);
|
margin-left: var(--spacing-vertical-large);
|
||||||
width: calc(80% - 30rem);
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__subtext {
|
.media__subtext {
|
||||||
|
@ -54,21 +56,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__thumb {
|
.media__thumb {
|
||||||
width: 10em;
|
width: 11em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__info {
|
.media__info {
|
||||||
// padding-left: var(--spacing-vertical-medium);
|
|
||||||
width: calc(100% - 10em);
|
width: calc(100% - 10em);
|
||||||
|
min-width: auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__title {
|
.media__title {
|
||||||
margin-bottom: var(--spacing-vertical-small);
|
margin-bottom: var(--spacing-vertical-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media__subtext:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.media__properties {
|
.media__properties {
|
||||||
bottom: -1.5rem;
|
bottom: 0.5rem;
|
||||||
left: calc(-100% - 1.5rem);
|
left: calc(-100% - -2rem);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 0 var(--spacing-vertical-small);
|
padding: 0 var(--spacing-vertical-small);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -143,7 +150,7 @@
|
||||||
|
|
||||||
.media__action-group {
|
.media__action-group {
|
||||||
> *:not(:last-child) {
|
> *:not(:last-child) {
|
||||||
margin-right: var(--spacing-vertical-large);
|
margin-right: var(--spacing-vertical-medium);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +200,11 @@
|
||||||
|
|
||||||
.media__subtitle {
|
.media__subtitle {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
|
color: rgba($lbry-black, 0.8);
|
||||||
|
|
||||||
|
[data-mode='dark'] & {
|
||||||
|
color: rgba($lbry-white, 0.8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__subtitle--large {
|
.media__subtitle--large {
|
||||||
|
@ -412,7 +424,7 @@
|
||||||
color: $lbry-white;
|
color: $lbry-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__subtext {
|
.media__subtitle {
|
||||||
color: mix($lbry-cyan-5, $lbry-white, 20%);
|
color: mix($lbry-cyan-5, $lbry-white, 20%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
color: rgba($lbry-white, 0.6);
|
color: rgba($lbry-white, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media__subtitle {
|
||||||
|
color: rgba($lbry-white, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
html[data-mode='dark'] & {
|
html[data-mode='dark'] & {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-bottom: 1px solid rgba($lbry-white, 0.1);
|
border-bottom: 1px solid rgba($lbry-white, 0.1);
|
||||||
|
@ -46,3 +50,43 @@
|
||||||
@extend .media-group__header-title;
|
@extend .media-group__header-title;
|
||||||
margin-bottom: var(--spacing-vertical-large);
|
margin-bottom: var(--spacing-vertical-large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search__options-wrapper {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search__options {
|
||||||
|
margin-top: var(--spacing-vertical-large);
|
||||||
|
|
||||||
|
legend {
|
||||||
|
&.search__legend--1 {
|
||||||
|
background-color: $lbry-teal-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search__legend--2 {
|
||||||
|
background-color: $lbry-cyan-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search__legend--3 {
|
||||||
|
background-color: $lbry-pink-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-mode='dark'] & {
|
||||||
|
&.search__legend--1 {
|
||||||
|
background-color: $lbry-teal-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search__legend--2 {
|
||||||
|
background-color: $lbry-cyan-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search__legend--3 {
|
||||||
|
background-color: $lbry-pink-5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset:not(:first-child) {
|
||||||
|
margin-top: var(--spacing-vertical-large);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -86,7 +86,9 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
.truncated-text {
|
.truncated-text {
|
||||||
@include truncate;
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
.busy-indicator__loader {
|
.busy-indicator__loader {
|
||||||
|
|
|
@ -1,30 +1,3 @@
|
||||||
@mixin between {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin ellipsis {
|
|
||||||
// to take over for truncate on LBRY Web
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin font-mono {
|
|
||||||
font-family: Inconsolata, 'Fira Mono', 'Droid Sans Mono', 'Source Code Pro', Consolas,
|
|
||||||
'Lucida Console', 'Courier New', Courier, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin font-sans {
|
|
||||||
font-family: 'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
|
|
||||||
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin font-serif {
|
|
||||||
font-family: 'Apple Garamond', Baskerville, Georgia, 'Times New Roman', 'Droid Serif', Times,
|
|
||||||
'Source Serif Pro', serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin placeholder {
|
@mixin placeholder {
|
||||||
animation: pulse 2s infinite ease-in-out;
|
animation: pulse 2s infinite ease-in-out;
|
||||||
background-color: $lbry-gray-2;
|
background-color: $lbry-gray-2;
|
||||||
|
@ -33,26 +6,3 @@
|
||||||
background-color: rgba($lbry-white, 0.1);
|
background-color: rgba($lbry-white, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin thumbnail {
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
float: left;
|
|
||||||
padding-top: var(--video-aspect-ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
clear: both;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin truncate {
|
|
||||||
display: -webkit-box;
|
|
||||||
overflow: hidden;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
}
|
|
||||||
|
|
|
@ -102,12 +102,13 @@ const fileInfoFilter = createFilter('fileInfo', [
|
||||||
const appFilter = createFilter('app', ['hasClickedComment']);
|
const appFilter = createFilter('app', ['hasClickedComment']);
|
||||||
// We only need to persist the receiveAddress for the wallet
|
// We only need to persist the receiveAddress for the wallet
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
|
const searchFilter = createFilter('search', ['options']);
|
||||||
|
|
||||||
const persistOptions = {
|
const persistOptions = {
|
||||||
whitelist: ['subscriptions', 'publish', 'wallet', 'content', 'fileInfo', 'app'],
|
whitelist: ['subscriptions', 'publish', 'wallet', 'content', 'fileInfo', 'app', 'search'],
|
||||||
// Order is important. Needs to be compressed last or other transforms can't
|
// Order is important. Needs to be compressed last or other transforms can't
|
||||||
// read the data
|
// read the data
|
||||||
transforms: [walletFilter, contentFilter, fileInfoFilter, appFilter, compressor],
|
transforms: [walletFilter, contentFilter, fileInfoFilter, appFilter, searchFilter, compressor],
|
||||||
debounce: 10000,
|
debounce: 10000,
|
||||||
storage: localForage,
|
storage: localForage,
|
||||||
};
|
};
|
||||||
|
|
36
yarn.lock
36
yarn.lock
|
@ -5660,9 +5660,9 @@ lazy-val@^1.0.3:
|
||||||
tar-stream "^1.6.2"
|
tar-stream "^1.6.2"
|
||||||
zstd-codec "^0.1.1"
|
zstd-codec "^0.1.1"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#42c185e922a7c6091b0e1580bacbfd8e02f45a91:
|
lbry-redux@lbryio/lbry-redux#2b725cb31729234ba73117e2a74688b8bba26e7c:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/42c185e922a7c6091b0e1580bacbfd8e02f45a91"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/2b725cb31729234ba73117e2a74688b8bba26e7c"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
@ -7868,14 +7868,15 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.2.7:
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-json-comments "~2.0.1"
|
strip-json-comments "~2.0.1"
|
||||||
|
|
||||||
react-dom@^16.6.0:
|
react-dom@^16.8.2:
|
||||||
version "16.7.0"
|
version "16.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.7.0.tgz#a17b2a7ca89ee7390bc1ed5eb81783c7461748b8"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.2.tgz#7c8a69545dd554d45d66442230ba04a6a0a3c3d3"
|
||||||
|
integrity sha512-cPGfgFfwi+VCZjk73buu14pYkYBR1b/SRMSYqkLDdhSEHnSwcuYTPu6/Bh6ZphJFIk80XLvbSe2azfcRzNF+Xg==
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.12.0"
|
scheduler "^0.13.2"
|
||||||
|
|
||||||
react-feather@^1.0.8:
|
react-feather@^1.0.8:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
|
@ -7952,14 +7953,15 @@ react@^0.14.5:
|
||||||
envify "^3.0.0"
|
envify "^3.0.0"
|
||||||
fbjs "^0.6.1"
|
fbjs "^0.6.1"
|
||||||
|
|
||||||
react@^16.6.0:
|
react@^16.8.2:
|
||||||
version "16.7.0"
|
version "16.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-16.7.0.tgz#b674ec396b0a5715873b350446f7ea0802ab6381"
|
resolved "https://registry.yarnpkg.com/react/-/react-16.8.2.tgz#83064596feaa98d9c2857c4deae1848b542c9c0c"
|
||||||
|
integrity sha512-aB2ctx9uQ9vo09HVknqv3DGRpI7OIGJhCx3Bt0QqoRluEjHSaObJl+nG12GDdYH6sTgE7YiPJ6ZUyMx9kICdXw==
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.12.0"
|
scheduler "^0.13.2"
|
||||||
|
|
||||||
read-config-file@3.1.0, read-config-file@^3.0.0:
|
read-config-file@3.1.0, read-config-file@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
|
@ -8532,13 +8534,6 @@ sass-loader@^6.0.7:
|
||||||
neo-async "^2.5.0"
|
neo-async "^2.5.0"
|
||||||
pify "^3.0.0"
|
pify "^3.0.0"
|
||||||
|
|
||||||
sass@^1.17.0:
|
|
||||||
version "1.17.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.17.0.tgz#e370b9302af121c9eadad5639619127772094ae6"
|
|
||||||
integrity sha512-aFi9RQqrCYkHB2DaLKBBbdUhos1N5o3l1ke9N5JqWzgSPmYwZsdmA+ViPVatUy/RPA21uejgYVUXM7GCh8lcdw==
|
|
||||||
dependencies:
|
|
||||||
chokidar "^2.0.0"
|
|
||||||
|
|
||||||
sax@1.2.1:
|
sax@1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
|
||||||
|
@ -8551,9 +8546,10 @@ sax@~1.1.1:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.6.tgz#5d616be8a5e607d54e114afae55b7eaf2fcc3240"
|
||||||
|
|
||||||
scheduler@^0.12.0:
|
scheduler@^0.13.2:
|
||||||
version "0.12.0"
|
version "0.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b"
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.2.tgz#969eaee2764a51d2e97b20a60963b2546beff8fa"
|
||||||
|
integrity sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w==
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
Loading…
Reference in a new issue