diff --git a/ui/js/component/router/view.jsx b/ui/js/component/router/view.jsx index 7fc915882..8b3d66102 100644 --- a/ui/js/component/router/view.jsx +++ b/ui/js/component/router/view.jsx @@ -13,6 +13,7 @@ import RewardsPage from 'page/rewards.js'; import FileListDownloaded from 'page/fileListDownloaded' import FileListPublished from 'page/fileListPublished' import ChannelPage from 'page/channel' +import SearchPage from 'page/search' const route = (page, routesMap) => { const component = routesMap[page] @@ -42,6 +43,7 @@ const Router = (props) => { 'developer': , 'discover': , 'rewards': , + 'search': , }) } diff --git a/ui/js/component/wunderbar/index.js b/ui/js/component/wunderbar/index.js index 85551e637..9860df4f1 100644 --- a/ui/js/component/wunderbar/index.js +++ b/ui/js/component/wunderbar/index.js @@ -25,8 +25,8 @@ const perform = (dispatch) => ({ // navigate: (path) => dispatch(doNavigate(path)), onSearch: (query) => dispatch(doSearchContent(query)), onSubmit: (query) => dispatch(doSearchContent(query)), - // activateSearch: () => dispatch(doActivateSearch()), - // deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50), + activateSearch: () => dispatch(doActivateSearch()), + deactivateSearch: () => setTimeout(() => { dispatch(doDeactivateSearch()) }, 50), }) export default connect(select, perform)(Wunderbar) diff --git a/ui/js/component/wunderbar/view.jsx b/ui/js/component/wunderbar/view.jsx index 821e9bfc0..6ff9c6312 100644 --- a/ui/js/component/wunderbar/view.jsx +++ b/ui/js/component/wunderbar/view.jsx @@ -61,6 +61,8 @@ class WunderBar extends React.PureComponent { isActive: true } + this.props.activateSearch() + this._focusPending = true; //below is hacking, improved when we have proper routing if (!this.state.address.startsWith('lbry://') && this.state.icon !== "icon-search") //onFocus, if they are not on an exact URL or a search page, clear the bar @@ -71,6 +73,7 @@ class WunderBar extends React.PureComponent { } onBlur() { + this.props.deactivateSearch() let commonState = {isActive: false}; if (this._resetOnNextBlur) { this.setState(Object.assign({}, this._stateBeforeSearch, commonState)); diff --git a/ui/js/page/search.js b/ui/js/page/search.js deleted file mode 100644 index f51541bcc..000000000 --- a/ui/js/page/search.js +++ /dev/null @@ -1,165 +0,0 @@ -import React from 'react'; -import lbry from '../lbry.js'; -import lbryio from '../lbryio.js'; -import lbryuri from '../lbryuri.js'; -import lighthouse from '../lighthouse.js'; -import {FileTile, FileTileStream} from '../component/file-tile.js'; -import {Link} from '../component/link'; -import {ToolTip} from '../component/tooltip.js'; -import {BusyMessage} from '../component/common.js'; - -var SearchNoResults = React.createClass({ - render: function() { - return
- - No one has checked anything in for {this.props.query} yet. - - -
; - } -}); - -var SearchResultList = React.createClass({ - render: function() { - var rows = [], - seenNames = {}; //fix this when the search API returns claim IDs - - for (let {name, claim, claim_id, channel_name, channel_id, txid, nout} of this.props.results) { - const uri = lbryuri.build({ - channelName: channel_name, - contentName: name, - claimId: channel_id || claim_id, - }); - - rows.push( - - ); - } - return ( -
{rows}
- ); - } -}); - -let SearchResults = React.createClass({ - propTypes: { - query: React.PropTypes.string.isRequired - }, - - _isMounted: false, - - search: function(term) { - lighthouse.search(term).then(this.searchCallback); - if (!this.state.searching) { - this.setState({ searching: true }) - } - }, - - componentWillMount: function () { - this._isMounted = true; - this.search(this.props.query); - }, - - componentWillReceiveProps: function (nextProps) { - if (nextProps.query != this.props.query) { - this.search(nextProps.query); - } - }, - - componentWillUnmount: function () { - this._isMounted = false; - }, - - getInitialState: function () { - return { - results: [], - searching: true - }; - }, - - searchCallback: function (results) { - if (this._isMounted) //could have canceled while results were pending, in which case nothing to do - { - this.setState({ - results: results, - searching: false //multiple searches can be out, we're only done if we receive one we actually care about - }); - } - }, - - render: function () { - return this.state.searching ? - : - (this.state.results && this.state.results.length ? - : - ); - } -}); - -let SearchPage = React.createClass({ - - _isMounted: false, - - propTypes: { - query: React.PropTypes.string.isRequired - }, - - isValidUri: function(query) { - try { - lbryuri.parse(query); - return true; - } catch (e) { - return false; - } - }, - - componentWillMount: function() { - this._isMounted = true; - lighthouse.search(this.props.query).then(this.searchCallback); - }, - - componentWillUnmount: function() { - this._isMounted = false; - }, - - getInitialState: function() { - return { - results: [], - searching: true - }; - }, - - searchCallback: function(results) { - if (this._isMounted) //could have canceled while results were pending, in which case nothing to do - { - this.setState({ - results: results, - searching: false //multiple searches can be out, we're only done if we receive one we actually care about - }); - } - }, - - render: function() { - return ( -
- { this.isValidUri(this.props.query) ? -
-

- Exact URL - -

- -
: '' } -
-

- Search Results for {this.props.query} - -

- -
-
- ); - } -}); - -export default SearchPage; diff --git a/ui/js/page/search/index.js b/ui/js/page/search/index.js new file mode 100644 index 000000000..e307905e1 --- /dev/null +++ b/ui/js/page/search/index.js @@ -0,0 +1,30 @@ +import React from 'react' +import { + connect, +} from 'react-redux' +import { + doSearchContent, +} from 'actions/search' +import { + selectIsSearching, + selectSearchQuery, + selectCurrentSearchResults, + selectSearchActivated, +} from 'selectors/search' +import { + doNavigate, +} from 'actions/app' +import SearchPage from './view' + +const select = (state) => ({ + isSearching: selectIsSearching(state), + query: selectSearchQuery(state), + results: selectCurrentSearchResults(state), + searchActive: selectSearchActivated(state), +}) + +const perform = (dispatch) => ({ + navigate: (path) => dispatch(doNavigate(path)), +}) + +export default connect(select, perform)(SearchPage) diff --git a/ui/js/page/search/view.jsx b/ui/js/page/search/view.jsx new file mode 100644 index 000000000..a74db1d0a --- /dev/null +++ b/ui/js/page/search/view.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import lbry from 'lbry'; +import lbryio from 'lbryio'; +import lbryuri from 'lbryuri'; +import lighthouse from 'lighthouse'; +import FileTile from 'component/fileTile' +import FileTileStream from 'component/fileTileStream' +import Link from 'component/link' +import {ToolTip} from 'component/tooltip.js'; +import {BusyMessage} from 'component/common.js'; + +const SearchNoResults = (props) => { + const { + navigate, + query, + } = props + + return
+ + No one has checked anything in for {query} yet. + navigate('publish')} /> + +
; +} + +const SearchResultList = (props) => { + const { + results, + } = props + + const rows = [], + seenNames = {}; //fix this when the search API returns claim IDs + + for (let {name, claim, claim_id, channel_name, channel_id, txid, nout} of results) { + const uri = lbryuri.build({ + channelName: channel_name, + contentName: name, + claimId: channel_id || claim_id, + }); + + rows.push( + + ); + } + return ( +
{rows}
+ ); +} + +const SearchResults = (props) => { + const { + searching, + results, + query, + } = props + + return ( + searching ? + : + (results && results.length) ? + : + + ) +} + +const SearchPage = (props) => { + const isValidUri = (query) => true + const { + query, + } = props + + return ( +
+ { isValidUri(query) ? +
+

+ Exact URL + +

+ +
: '' } +
+

+ Search Results for {query} + +

+ +
+
+ ) +} +export default SearchPage; diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js index a104ac17d..c72786747 100644 --- a/ui/js/selectors/app.js +++ b/ui/js/selectors/app.js @@ -1,4 +1,8 @@ import {createSelector} from 'reselect' +import { + selectIsSearching, + selectSearchActivated, +} from 'selectors/search' export const _selectState = state => state.app || {} @@ -14,7 +18,12 @@ export const selectCurrentPath = createSelector( export const selectCurrentPage = createSelector( selectCurrentPath, - (path) => path.split('=')[0] + selectSearchActivated, + (path, searchActivated) => { + if (searchActivated) return 'search' + + return path.split('=')[0] + } ) export const selectCurrentUri = createSelector(