From 71771aeb6f224efcaf0d9a28f4f56da954d1db90 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Wed, 26 Apr 2017 23:54:53 -0400 Subject: [PATCH 01/12] it's not the worst thing I've ever done --- ui/js/app.js | 39 ++++--- ui/js/component/header.js | 159 ++++++++++++++++++++--------- ui/js/component/link.js | 2 +- ui/js/lbry.js | 8 +- ui/js/lbryio.js | 5 +- ui/js/page/discover.js | 2 +- ui/js/page/file-list.js | 1 - ui/js/page/publish.js | 3 - ui/js/page/settings.js | 2 +- ui/js/page/show.js | 4 +- ui/js/page/start.js | 3 - ui/js/page/wallet.js | 3 - ui/js/utils.js | 4 +- ui/scss/_canvas.scss | 173 +------------------------------- ui/scss/_global.scss | 4 +- ui/scss/_icons.scss | 6 -- ui/scss/all.scss | 1 + ui/scss/component/_button.scss | 15 ++- ui/scss/component/_card.scss | 4 +- ui/scss/component/_header.scss | 103 +++++++++++++++++++ ui/scss/component/_menu.scss | 2 +- ui/scss/component/_modal.scss | 2 +- ui/scss/component/_tooltip.scss | 2 +- 23 files changed, 272 insertions(+), 275 deletions(-) create mode 100644 ui/scss/component/_header.scss diff --git a/ui/js/app.js b/ui/js/app.js index b7a552e5e..97ad1bfab 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -244,51 +244,50 @@ var App = React.createClass({ return null; } }, - getMainContent: function() + getContentAndAddress: function() { switch(this.state.viewingPage) { case 'settings': - return ; + return ["Settings", "icon-gear", ]; case 'help': - return ; + return ["Help", "icon-question", ]; case 'report': - return ; + return ['Report', 'icon-file', ]; case 'downloaded': - return ; + return ["Downloads & Purchases", "icon-folder", ]; case 'published': - return ; + return ["Publishes", "icon-folder", ]; case 'start': - return ; + return ["Start", "icon-file", ]; case 'rewards': - return ; + return ["Rewards", "icon-bank", ]; case 'wallet': case 'send': case 'receive': - return ; + return [this.state.viewingPage.charAt(0).toUpperCase() + this.state.viewingPage.slice(1), "icon-bank", ] case 'show': - return ; + return [this.state.pageArgs, "icon-file", ]; case 'publish': - return ; + return ["Publish", "icon-upload", ]; case 'developer': - return ; + return ["Developer", "icon-file", ]; case 'discover': default: - return ; + return ["Home", "icon-home", ]; } }, render: function() { - var mainContent = this.getMainContent(), - headerLinks = this.getHeaderLinks(), - searchQuery = this.state.viewingPage == 'discover' && this.state.pageArgs ? this.state.pageArgs : ''; - + let [address, wunderBarIcon, mainContent] = this.getContentAndAddress(), + headerLinks = this.getHeaderLinks(); + return ( this._fullScreenPages.includes(this.state.viewingPage) ? mainContent : -
- +
+
-
{mainContent}
{ - this.setState({ title: mutations[0].target.textContent }); - }).observe( - document.querySelector('title'), - { subtree: true, characterData: true, childList: true } - ); - }, componentDidMount: function() { - document.addEventListener('scroll', this.handleScroll); - }, - componentWillUnmount: function() { - document.removeEventListener('scroll', this.handleScroll); - if (this.userTypingTimer) - { - clearTimeout(this.userTypingTimer); - } - }, - handleScroll: function() { - this.setState({ - isScrolled: document.body.scrollTop > 0 + this._balanceSubscribeId = lbry.balanceSubscribe((balance) => { + this.setState({ balance: balance }); }); }, - onQueryChange: function(event) { - - if (this.userTypingTimer) - { - clearTimeout(this.userTypingTimer); + componentWillUnmount: function() { + if (this._balanceSubscribeId) { + lbry.balanceUnsubscribe(this._balanceSubscribeId) } + }, + render: function() { + return
+ + {this.props.links ? + : + ''} +
+ } +}); + +let WunderBar = React.createClass({ + _userTypingTimer: null, + _input: null, + _stateBeforeSearch: null, + + getInitialState: function() { + return { + address: this.props.address, + icon: this.props.icon + }; + }, + componentWillUnmount: function() { + if (this.userTypingTimer) { + clearTimeout(this._userTypingTimer); + } + }, + onChange: function(event) { + + if (this._userTypingTimer) + { + clearTimeout(this._userTypingTimer); + } + + this.setState({ address: event.target.value }) //@TODO: Switch to React.js timing var searchTerm = event.target.value; - this.userTypingTimer = setTimeout(() => { + + this._userTypingTimer = setTimeout(() => { this.props.onSearch(searchTerm); }, 800); // 800ms delay, tweak for faster/slower }, + componentWillReceiveProps(nextProps) { + if (nextProps.address !== this.state.address || nextProps.icon !== this.state.icon) { + this.setState({ address: nextProps.address, icon: nextProps.icon }); + } + }, + onFocus: function() { + this._stateBeforeSearch = this.state; + let newState = { + icon: "icon-search" + } + // this._input.value = ""; //trigger placeholder + this._focusPending = true; + if (!this.state.address.match(/^lbry:\/\//)) //onFocus, if they are not on an exact URL, clear the bar + { + newState.address = ""; + } + this.setState(newState); + }, + onBlur: function() { + this.setState(this._stateBeforeSearch); + this._input.value = this.state.address; + }, + componentDidUpdate: function() { + this._input.value = this.state.address; + if (this._input && this._focusPending) { + this._input.select(); + this._focusPending = false; + } + }, + onReceiveRef: function(ref) { + this._input = ref; + }, render: function() { - return ( - - ); + return
+ {this.state.icon ? : '' } + +
} -}); +}) var SubHeader = React.createClass({ render: function() { diff --git a/ui/js/component/link.js b/ui/js/component/link.js index 466fcb45c..d46fcda25 100644 --- a/ui/js/component/link.js +++ b/ui/js/component/link.js @@ -41,7 +41,7 @@ export let Link = React.createClass({ content = ( {'icon' in this.props ? : null} - {{this.props.label}} + {this.props.label ? {this.props.label} : null} {'badge' in this.props ? {this.props.badge} : null} ); diff --git a/ui/js/lbry.js b/ui/js/lbry.js index e2807090a..c13635a09 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -627,18 +627,18 @@ lbry.claim_list_mine = function(params={}) { } lbry.resolve = function(params={}) { - const claimCacheKey = 'resolve_claim_cache', - claimCache = getSession(claimCacheKey, {}) + const claimCacheKey = 'resolve_claim_cache3', + claimCache = getLocal(claimCacheKey, {}) return new Promise((resolve, reject) => { if (!params.uri) { throw "Resolve has hacked cache on top of it that requires a URI" } - if (params.uri && claimCache[params.uri]) { + if (params.uri && claimCache[params.uri] !== undefined) { resolve(claimCache[params.uri]); } else { lbry.call('resolve', params, function(data) { claimCache[params.uri] = data; - setSession(claimCacheKey, claimCache) + setLocal(claimCacheKey, claimCache) resolve(data) }, reject) } diff --git a/ui/js/lbryio.js b/ui/js/lbryio.js index bbe6b9ccd..7a1ab58c2 100644 --- a/ui/js/lbryio.js +++ b/ui/js/lbryio.js @@ -7,10 +7,11 @@ const lbryio = { _accessToken: getLocal('accessToken'), _authenticationPromise: null, _user : null, - enabled: true + enabled: false }; -const CONNECTION_STRING = process.env.LBRY_APP_API_URL ? process.env.LBRY_APP_API_URL : 'https://api.lbry.io/'; +// const CONNECTION_STRING = process.env.LBRY_APP_API_URL ? process.env.LBRY_APP_API_URL : 'https://api.lbry.io/'; +const CONNECTION_STRING = 'https://api.lbry.io/'; const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000; lbryio.getExchangeRates = function() { diff --git a/ui/js/page/discover.js b/ui/js/page/discover.js index 42ed3999d..3c807e831 100644 --- a/ui/js/page/discover.js +++ b/ui/js/page/discover.js @@ -164,7 +164,7 @@ var DiscoverPage = React.createClass({ }, componentWillMount: function() { - document.title = "Discover"; + document.title = "Home"; if (this.props.query) { // Rendering with a query already typed diff --git a/ui/js/page/file-list.js b/ui/js/page/file-list.js index 063730e7f..3189d61fd 100644 --- a/ui/js/page/file-list.js +++ b/ui/js/page/file-list.js @@ -19,7 +19,6 @@ export let FileListDownloaded = React.createClass({ }, componentDidMount: function() { this._isMounted = true; - document.title = "Downloaded Files"; lbry.claim_list_mine().then((myClaimInfos) => { if (!this._isMounted) { return; } diff --git a/ui/js/page/publish.js b/ui/js/page/publish.js index 36bcae479..dc34ea500 100644 --- a/ui/js/page/publish.js +++ b/ui/js/page/publish.js @@ -348,9 +348,6 @@ var PublishPage = React.createClass({ componentWillMount: function() { this._updateChannelList(); }, - componentDidMount: function() { - document.title = "Publish"; - }, componentDidUpdate: function() { }, onFileChange: function() { diff --git a/ui/js/page/settings.js b/ui/js/page/settings.js index b0f4ff9d9..6cb062099 100644 --- a/ui/js/page/settings.js +++ b/ui/js/page/settings.js @@ -17,7 +17,7 @@ var SettingsPage = React.createClass({ setClientSetting: function(name, value) { lbry.setClientSetting(name, value) this._onSettingSaveSuccess() - }, + }, onRunOnStartChange: function (event) { this.setDaemonSetting('run_on_startup', event.target.checked); }, diff --git a/ui/js/page/show.js b/ui/js/page/show.js index cc2fb5cfc..f41039868 100644 --- a/ui/js/page/show.js +++ b/ui/js/page/show.js @@ -60,7 +60,6 @@ let ShowPage = React.createClass({ }, componentWillMount: function() { this._uri = lbryuri.normalize(this.props.uri); - document.title = this._uri; lbry.resolve({uri: this._uri}).then(({ claim: {txid, nout, has_signature, signature_is_valid, value: {stream: {metadata, source: {contentType}}}}}) => { const outpoint = txid + ':' + nout; @@ -71,6 +70,8 @@ let ShowPage = React.createClass({ }); }); + document.title = metadata.title ? metadata.title : this._uri; + this.setState({ outpoint: outpoint, metadata: metadata, @@ -91,6 +92,7 @@ let ShowPage = React.createClass({ render: function() { const metadata = this.state.metadata; const title = metadata ? this.state.metadata.title : this._uri; + return (
diff --git a/ui/js/page/start.js b/ui/js/page/start.js index 9f918db27..972df3141 100644 --- a/ui/js/page/start.js +++ b/ui/js/page/start.js @@ -5,9 +5,6 @@ var StartPage = React.createClass({ componentWillMount: function() { lbry.stop(); }, - componentDidMount: function() { - document.title = "LBRY is Closed"; - }, render: function() { return (
diff --git a/ui/js/page/wallet.js b/ui/js/page/wallet.js index 5f9e4e53a..4c3a52d0e 100644 --- a/ui/js/page/wallet.js +++ b/ui/js/page/wallet.js @@ -270,9 +270,6 @@ var WalletPage = React.createClass({ propTypes: { viewingPage: React.PropTypes.string, }, - componentDidMount: function() { - document.title = "My Wallet"; - }, /* Below should be refactored so that balance is shared all of wallet page. Or even broader? What is the proper React pattern for sharing a global state like balance? diff --git a/ui/js/utils.js b/ui/js/utils.js index b24eb25b6..61bf53188 100644 --- a/ui/js/utils.js +++ b/ui/js/utils.js @@ -2,9 +2,9 @@ * Thin wrapper around localStorage.getItem(). Parses JSON and returns undefined if the value * is not set yet. */ -export function getLocal(key) { +export function getLocal(key, fallback=undefined) { const itemRaw = localStorage.getItem(key); - return itemRaw === null ? undefined : JSON.parse(itemRaw); + return itemRaw === null ? fallback : JSON.parse(itemRaw); } /** diff --git a/ui/scss/_canvas.scss b/ui/scss/_canvas.scss index 8aa4227e3..ce8f8e01c 100644 --- a/ui/scss/_canvas.scss +++ b/ui/scss/_canvas.scss @@ -11,44 +11,12 @@ body line-height: $font-line-height; } -$drawer-width: 220px; - -#drawer +#window { - width: $drawer-width; - position: fixed; min-height: 100vh; - left: 0; - top: 0; - background: $color-bg; - z-index: 3; - .drawer-item - { - display: block; - padding: $spacing-vertical / 2; - font-size: 1.2em; - height: $spacing-vertical * 1.5; - .icon - { - margin-right: 6px; - } - .link-label - { - line-height: $spacing-vertical * 1.5; - } - .badge - { - float: right; - margin-top: $spacing-vertical * 0.25 - 2; - background: $color-money; - } - } - .drawer-item-selected - { - background: $color-canvas; - color: $color-primary; - } + background: $color-canvas; } + .badge { background: $color-money; @@ -62,119 +30,9 @@ $drawer-width: 220px; font-weight: bold; color: $color-money; } -#drawer-handle -{ - padding: $spacing-vertical / 2; - max-height: $height-header - $spacing-vertical; - text-align: center; -} - -#window -{ - position: relative; /*window has it's own z-index inside of it*/ - z-index: 1; -} -#window.drawer-closed -{ - #drawer { display: none } -} -#window.drawer-open -{ - #main-content { margin-left: $drawer-width; } - .open-drawer-link { display: none } - #header { padding-left: $drawer-width + $spacing-vertical / 2; } -} - -#header -{ - background: $color-primary; - color: white; - &.header-no-subnav { - height: $height-header; - } - &.header-with-subnav { - height: $height-header * 2; - } - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 2; - box-sizing: border-box; - h1 { font-size: 1.8em; line-height: $height-header - $spacing-vertical; display: inline-block; float: left; } - &.header-scrolled - { - box-shadow: $default-box-shadow; - } -} -.header-top-bar -{ - padding: $spacing-vertical / 2; -} -.header-search -{ - margin-left: 60px; - $padding-adjust: 36px; - text-align: center; - .icon { - position: absolute; - top: $spacing-vertical * 1.5 / 2 + 2px; //hacked - margin-left: -$padding-adjust + 14px; //hacked - } - input[type="search"] { - position: relative; - left: -$padding-adjust; - background: rgba(255, 255, 255, 0.3); - color: white; - width: 400px; - height: $spacing-vertical * 1.5; - line-height: $spacing-vertical * 1.5; - padding-left: $padding-adjust + 3; - padding-right: 3px; - @include border-radius(2px); - @include placeholder-color(#e8e8e8); - &:focus { - box-shadow: $focus-box-shadow; - } - } -} - -nav.sub-header -{ - background: $color-primary; - text-transform: uppercase; - padding: $spacing-vertical / 2; - > a - { - $sub-header-selected-underline-height: 2px; - display: inline-block; - margin: 0 15px; - padding: 0 5px; - line-height: $height-header - $spacing-vertical - $sub-header-selected-underline-height; - color: #e8e8e8; - &:first-child - { - margin-left: 0; - } - &:last-child - { - margin-right: 0; - } - &.sub-header-selected - { - border-bottom: $sub-header-selected-underline-height solid #fff; - color: #fff; - } - &:hover - { - color: #fff; - } - } -} #main-content { - background: $color-canvas; &.no-sub-nav { min-height: calc(100vh - 60px); //should be -$height-header, but I'm dumb I guess? It wouldn't work @@ -182,8 +40,7 @@ nav.sub-header } &.with-sub-nav { - min-height: calc(100vh - 120px); //should be -$height-header, but I'm dumb I guess? It wouldn't work - main { margin-top: $height-header * 2; } + min-height: calc(100vh - 60px); //should be -$height-header, but I'm dumb I guess? It wouldn't work } main { @@ -195,26 +52,4 @@ nav.sub-header margin-right: auto; } } -} - -$header-icon-size: 1.5em; - -.open-drawer-link, .close-drawer-link -{ - display: inline-block; - font-size: $header-icon-size; - padding: 2px 6px 0 6px; - float: left; -} -.close-lbry-link -{ - font-size: $header-icon-size; - float: right; - padding: 0 6px 0 18px; -} - -.full-screen -{ - width: 100%; - height: 100%; } \ No newline at end of file diff --git a/ui/scss/_global.scss b/ui/scss/_global.scss index d829d8245..c2ea35878 100644 --- a/ui/scss/_global.scss +++ b/ui/scss/_global.scss @@ -34,8 +34,8 @@ $height-header: $spacing-vertical * 2.5; $height-button: $spacing-vertical * 1.5; $height-video-embedded: $width-page-constrained * 9 / 16; -$default-box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12); -$focus-box-shadow: 2px 4px 4px 0 rgba(0,0,0,.14),2px 5px 3px -2px rgba(0,0,0,.2),2px 3px 7px 0 rgba(0,0,0,.12); +$box-shadow-layer: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12); +$box-shadow-focus: 2px 4px 4px 0 rgba(0,0,0,.14),2px 5px 3px -2px rgba(0,0,0,.2),2px 3px 7px 0 rgba(0,0,0,.12); $transition-standard: .225s ease; diff --git a/ui/scss/_icons.scss b/ui/scss/_icons.scss index 91b8255bb..441113e39 100644 --- a/ui/scss/_icons.scss +++ b/ui/scss/_icons.scss @@ -25,12 +25,6 @@ transform: translate(0, 0); } -.icon-mega -{ - font-size: 200px; - line-height: 1; -} - /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen readers do not read off random characters that represent icons */ .icon-glass:before { diff --git a/ui/scss/all.scss b/ui/scss/all.scss index b4c6611a6..413a7edaa 100644 --- a/ui/scss/all.scss +++ b/ui/scss/all.scss @@ -10,6 +10,7 @@ @import "component/_file-actions.scss"; @import "component/_file-tile.scss"; @import "component/_form-field.scss"; +@import "component/_header.scss"; @import "component/_menu.scss"; @import "component/_tooltip.scss"; @import "component/_load-screen.scss"; diff --git a/ui/scss/component/_button.scss b/ui/scss/component/_button.scss index e3c5fe8e8..5c6fed22f 100644 --- a/ui/scss/component/_button.scss +++ b/ui/scss/component/_button.scss @@ -34,6 +34,11 @@ $button-focus-shift: 12%; { padding-left: 5px; } + .icon:only-child + { + padding-left: 0; + padding-right: 0; + } } .button-block { @@ -49,17 +54,17 @@ $button-focus-shift: 12%; $color-button-text: white; color: darken($color-button-text, $button-focus-shift * 0.5); background-color: $color-primary; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; &:focus { color: $color-button-text; - //box-shadow: $focus-box-shadow; + //box-shadow: $box-shadow-focus; background-color: mix(black, $color-primary, $button-focus-shift) } } .button-alt { background-color: $color-bg-alt; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; } .button-text @@ -76,3 +81,7 @@ $button-focus-shift: 12%; @include text-link(#aaa); font-size: 0.8em; } +.button--flat +{ + box-shadow: none !important; +} \ No newline at end of file diff --git a/ui/scss/component/_card.scss b/ui/scss/component/_card.scss index e019d7342..e10d02fb3 100644 --- a/ui/scss/component/_card.scss +++ b/ui/scss/component/_card.scss @@ -7,7 +7,7 @@ $padding-card-horizontal: $spacing-vertical * 2/3; margin-right: auto; max-width: $width-page-constrained; background: $color-bg; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; border-radius: 2px; margin-bottom: $spacing-vertical * 2/3; overflow: auto; @@ -86,7 +86,7 @@ $card-link-scaling: 1.1; .card--link:hover { position: relative; z-index: 1; - box-shadow: $focus-box-shadow; + box-shadow: $box-shadow-focus; transform: scale($card-link-scaling); transform-origin: 50% 50%; overflow-x: visible; diff --git a/ui/scss/component/_header.scss b/ui/scss/component/_header.scss new file mode 100644 index 000000000..5a550e771 --- /dev/null +++ b/ui/scss/component/_header.scss @@ -0,0 +1,103 @@ +@import "../global"; + +$color-header: #666; + + +$header-icon-size: 1.5em; + +.open-drawer-link, .close-drawer-link +{ + display: inline-block; + font-size: $header-icon-size; + padding: 2px 6px 0 6px; + float: left; +} + +#header +{ + color: $color-header; + background: #fff; + display: flex; + /* + &.header-no-subnav { + height: $height-header; + } + &.header-with-subnav { + height: $height-header * 2; + }*/ + position: fixed; + box-shadow: $box-shadow-layer; + top: 0; + left: 0; + width: 100%; + z-index: 2; + padding: $spacing-vertical / 2; + box-sizing: border-box; +} +.header__item { + flex: 0 0 content; + padding-left: $spacing-vertical / 4; + padding-right: $spacing-vertical / 4; +} +.header__item--wunderbar { + flex-grow: 1; +} + +.wunderbar +{ + position: relative; + .icon { + position: absolute; + left: 10px; + top: $spacing-vertical / 2 - 4px; //hacked + } +} +.wunderbar__input { + background: rgba(255, 255, 255, 0.7); + width: 100%; + color: $color-header; + height: $spacing-vertical * 1.5; + line-height: $spacing-vertical * 1.5; + padding-left: 38px; + padding-right: 5px; + border: 1px solid $color-text-dark; + @include border-radius(2px); + border: 1px solid #ccc; + &:focus { + box-shadow: $box-shadow-focus; + border-color: $color-header; + } +} + +nav.sub-header +{ + text-transform: uppercase; + padding: $spacing-vertical / 2; + > a + { + $sub-header-selected-underline-height: 2px; + display: inline-block; + margin: 0 15px; + padding: 0 5px; + line-height: $height-header - $spacing-vertical - $sub-header-selected-underline-height; + color: $color-header; + &:first-child + { + margin-left: 0; + } + &:last-child + { + margin-right: 0; + } + $color-selected-subheader: darken($color-header, 20%); + &.sub-header-selected + { + border-bottom: $sub-header-selected-underline-height solid $color-selected-subheader; + color: $color-selected-subheader; + } + &:hover + { + color: $color-selected-subheader; + } + } +} \ No newline at end of file diff --git a/ui/scss/component/_menu.scss b/ui/scss/component/_menu.scss index e3b0566c4..d8e79be28 100644 --- a/ui/scss/component/_menu.scss +++ b/ui/scss/component/_menu.scss @@ -10,7 +10,7 @@ $border-radius-menu: 2px; position: absolute; white-space: nowrap; background-color: white; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; border-radius: $border-radius-menu; padding-top: ($spacing-vertical / 5) 0px; z-index: 1; diff --git a/ui/scss/component/_modal.scss b/ui/scss/component/_modal.scss index 13284c7ff..05d5e8de1 100644 --- a/ui/scss/component/_modal.scss +++ b/ui/scss/component/_modal.scss @@ -29,7 +29,7 @@ overflow: auto; border-radius: 4px; padding: $spacing-vertical; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; max-width: 400px; } diff --git a/ui/scss/component/_tooltip.scss b/ui/scss/component/_tooltip.scss index 9a6ccd7da..0d909d9fb 100644 --- a/ui/scss/component/_tooltip.scss +++ b/ui/scss/component/_tooltip.scss @@ -24,7 +24,7 @@ background-color: $color-bg; font-size: $font-size * 7/8; line-height: $font-line-height; - box-shadow: $default-box-shadow; + box-shadow: $box-shadow-layer; } .tooltip--header .tooltip__link { From 543b912ddb75ad593d7c8eb46482231e39cb19d3 Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Thu, 27 Apr 2017 09:17:18 -0400 Subject: [PATCH 02/12] more cleanup / restoration --- ui/js/app.js | 31 ++---------------- ui/js/component/header.js | 27 +++++++-------- ui/js/page/file-list.js | 60 +++++++++++++++++----------------- ui/js/page/help.js | 4 ++- ui/js/page/rewards.js | 8 +++-- ui/js/page/settings.js | 13 +++++++- ui/js/page/wallet.js | 12 +++++++ ui/scss/_canvas.scss | 23 ++++--------- ui/scss/_gui.scss | 3 +- ui/scss/component/_header.scss | 22 +++++++++---- 10 files changed, 102 insertions(+), 101 deletions(-) diff --git a/ui/js/app.js b/ui/js/app.js index 97ad1bfab..bf0bd4723 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -220,30 +220,6 @@ var App = React.createClass({ errorInfo:
    {errorInfoList}
, }); }, - getHeaderLinks: function() - { - switch(this.state.viewingPage) - { - case 'wallet': - case 'send': - case 'receive': - case 'rewards': - return { - '?wallet': 'Overview', - '?send': 'Send', - '?receive': 'Receive', - '?rewards': 'Rewards', - }; - case 'downloaded': - case 'published': - return { - '?downloaded': 'Downloaded', - '?published': 'Published', - }; - default: - return null; - } - }, getContentAndAddress: function() { switch(this.state.viewingPage) @@ -278,16 +254,15 @@ var App = React.createClass({ } }, render: function() { - let [address, wunderBarIcon, mainContent] = this.getContentAndAddress(), - headerLinks = this.getHeaderLinks(); + let [address, wunderBarIcon, mainContent] = this.getContentAndAddress(); return ( this._fullScreenPages.includes(this.state.viewingPage) ? mainContent :
-
+ onSearch={this.onSearch} viewingPage={this.state.viewingPage} /> +
{mainContent}
{ - this.setState({ balance: balance }); + if (this._isMounted) { + this.setState({balance: balance}); + } }); }, componentWillUnmount: function() { + this._isMounted = false; if (this._balanceSubscribeId) { lbry.balanceUnsubscribe(this._balanceSubscribeId) } }, render: function() { - return
-
- {this.props.links ? - : - ''} -
} }); @@ -93,7 +93,8 @@ let WunderBar = React.createClass({ onFocus: function() { this._stateBeforeSearch = this.state; let newState = { - icon: "icon-search" + icon: "icon-search", + isActive: true } // this._input.value = ""; //trigger placeholder this._focusPending = true; @@ -104,7 +105,7 @@ let WunderBar = React.createClass({ this.setState(newState); }, onBlur: function() { - this.setState(this._stateBeforeSearch); + this.setState(Object.assign({}, this._stateBeforeSearch, { isActive: false })); this._input.value = this.state.address; }, componentDidUpdate: function() { @@ -118,7 +119,7 @@ let WunderBar = React.createClass({ this._input = ref; }, render: function() { - return
+ return
{this.state.icon ? : '' } + ); diff --git a/ui/js/page/file-list.js b/ui/js/page/file-list.js index 3189d61fd..41a2254b5 100644 --- a/ui/js/page/file-list.js +++ b/ui/js/page/file-list.js @@ -3,12 +3,22 @@ import lbry from '../lbry.js'; import lbryuri from '../lbryuri.js'; import {Link} from '../component/link.js'; import {FormField} from '../component/form.js'; +import {SubHeader} from '../component/header.js'; import {FileTileStream} from '../component/file-tile.js'; import rewards from '../rewards.js'; import lbryio from '../lbryio.js'; import {BusyMessage, Thumbnail} from '../component/common.js'; +export let FileListNav = React.createClass({ + render: function() { + return ; + } +}); + export let FileListDownloaded = React.createClass({ _isMounted: false, @@ -37,25 +47,20 @@ export let FileListDownloaded = React.createClass({ this._isMounted = false; }, render: function() { + let content = ""; if (this.state.fileInfos === null) { - return ( -
- -
- ); + content = ; } else if (!this.state.fileInfos.length) { - return ( -
- You haven't downloaded anything from LBRY yet. Go ! -
- ); + content = You haven't downloaded anything from LBRY yet. Go !; } else { - return ( -
- -
- ); + content = ; } + return ( +
+ + {content} +
+ ); } }); @@ -102,27 +107,22 @@ export let FileListPublished = React.createClass({ this._isMounted = false; }, render: function () { + let content = null; if (this.state.fileInfos === null) { - return ( -
- -
- ); + content = ; } else if (!this.state.fileInfos.length) { - return ( -
- You haven't published anything to LBRY yet. Try ! -
- ); + content = You haven't published anything to LBRY yet. Try !; } else { - return ( -
- -
- ); + content = ; } + return ( +
+ + {content} +
+ ); } }); diff --git a/ui/js/page/help.js b/ui/js/page/help.js index 99e6ad0d7..42e65df14 100644 --- a/ui/js/page/help.js +++ b/ui/js/page/help.js @@ -3,6 +3,7 @@ import React from 'react'; import lbry from '../lbry.js'; import {Link} from '../component/link.js'; +import {SettingsNav} from './settings.js'; import {version as uiVersion} from 'json!../../package.json'; var HelpPage = React.createClass({ @@ -49,7 +50,8 @@ var HelpPage = React.createClass({ } return ( -
+
+

Read the FAQ

diff --git a/ui/js/page/rewards.js b/ui/js/page/rewards.js index 18e936aee..c4261804f 100644 --- a/ui/js/page/rewards.js +++ b/ui/js/page/rewards.js @@ -4,6 +4,7 @@ import lbryio from '../lbryio.js'; import {CreditAmount, Icon} from '../component/common.js'; import rewards from '../rewards.js'; import Modal from '../component/modal.js'; +import {WalletNav} from './wallet.js'; import {RewardLink} from '../component/link.js'; const RewardTile = React.createClass({ @@ -56,14 +57,15 @@ var RewardsPage = React.createClass({ }, render: function() { return ( -
-
+
+ +
{!this.state.userRewards ? (this.state.failed ?
Failed to load rewards.
: '') : this.state.userRewards.map(({RewardType, RewardTitle, RewardDescription, TransactionID, RewardAmount}) => { return ; })} - +
); } diff --git a/ui/js/page/settings.js b/ui/js/page/settings.js index 6cb062099..abc65271d 100644 --- a/ui/js/page/settings.js +++ b/ui/js/page/settings.js @@ -1,7 +1,17 @@ import React from 'react'; import {FormField, FormRow} from '../component/form.js'; +import {SubHeader} from '../component/header.js'; import lbry from '../lbry.js'; +export let SettingsNav = React.createClass({ + render: function() { + return ; + } +}); + var SettingsPage = React.createClass({ _onSettingSaveSuccess: function() { // This is bad. @@ -92,7 +102,8 @@ var SettingsPage = React.createClass({
*/ return ( -
+
+

Download Directory

diff --git a/ui/js/page/wallet.js b/ui/js/page/wallet.js index 4c3a52d0e..b3c1b458b 100644 --- a/ui/js/page/wallet.js +++ b/ui/js/page/wallet.js @@ -2,6 +2,7 @@ import React from 'react'; import lbry from '../lbry.js'; import {Link} from '../component/link.js'; import Modal from '../component/modal.js'; +import {SubHeader} from '../component/header.js'; import {FormField, FormRow} from '../component/form.js'; import {Address, BusyMessage, CreditAmount} from '../component/common.js'; @@ -263,6 +264,16 @@ var TransactionList = React.createClass({ } }); +export let WalletNav = React.createClass({ + render: function() { + return ; + } +}); var WalletPage = React.createClass({ _balanceSubscribeId: null, @@ -294,6 +305,7 @@ var WalletPage = React.createClass({ render: function() { return (
+

Balance

diff --git a/ui/scss/_canvas.scss b/ui/scss/_canvas.scss index ce8f8e01c..21237c939 100644 --- a/ui/scss/_canvas.scss +++ b/ui/scss/_canvas.scss @@ -33,23 +33,12 @@ body #main-content { - &.no-sub-nav + padding: $spacing-vertical; + margin-top: $height-header; + main.constrained-page { - min-height: calc(100vh - 60px); //should be -$height-header, but I'm dumb I guess? It wouldn't work - main { margin-top: $height-header; } - } - &.with-sub-nav - { - min-height: calc(100vh - 60px); //should be -$height-header, but I'm dumb I guess? It wouldn't work - } - main - { - padding: $spacing-vertical; - &.constrained-page - { - max-width: $width-page-constrained; - margin-left: auto; - margin-right: auto; - } + max-width: $width-page-constrained; + margin-left: auto; + margin-right: auto; } } \ No newline at end of file diff --git a/ui/scss/_gui.scss b/ui/scss/_gui.scss index f875a6940..c514f0712 100644 --- a/ui/scss/_gui.scss +++ b/ui/scss/_gui.scss @@ -126,10 +126,11 @@ p .sort-section { display: block; - margin-bottom: 5px; + margin-bottom: $spacing-vertical * 2/3; text-align: right; + line-height: 1; font-size: 0.85em; color: $color-help; } diff --git a/ui/scss/component/_header.scss b/ui/scss/component/_header.scss index 5a550e771..15e15d1ee 100644 --- a/ui/scss/component/_header.scss +++ b/ui/scss/component/_header.scss @@ -1,7 +1,7 @@ @import "../global"; $color-header: #666; - +$color-header-active: darken($color-header, 20%); $header-icon-size: 1.5em; @@ -52,6 +52,9 @@ $header-icon-size: 1.5em; top: $spacing-vertical / 2 - 4px; //hacked } } + +.wunderbar--active .icon-search { color: $color-primary; } + .wunderbar__input { background: rgba(255, 255, 255, 0.7); width: 100%; @@ -64,15 +67,21 @@ $header-icon-size: 1.5em; @include border-radius(2px); border: 1px solid #ccc; &:focus { + color: $color-header-active; box-shadow: $box-shadow-focus; - border-color: $color-header; + border-color: $color-primary; } } nav.sub-header { text-transform: uppercase; - padding: $spacing-vertical / 2; + padding: 0 0 $spacing-vertical; + &.sub-header--constrained { + max-width: $width-page-constrained; + margin-left: auto; + margin-right: auto; + } > a { $sub-header-selected-underline-height: 2px; @@ -89,15 +98,14 @@ nav.sub-header { margin-right: 0; } - $color-selected-subheader: darken($color-header, 20%); &.sub-header-selected { - border-bottom: $sub-header-selected-underline-height solid $color-selected-subheader; - color: $color-selected-subheader; + border-bottom: $sub-header-selected-underline-height solid $color-header-active; + color: $color-header-active; } &:hover { - color: $color-selected-subheader; + color: $color-header-active; } } } \ No newline at end of file From e42252507bb2307f8211fb5d4ce993a2da1a277f Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 30 Apr 2017 04:06:50 -0400 Subject: [PATCH 03/12] Minor style fixes --- ui/js/component/header.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ui/js/component/header.js b/ui/js/component/header.js index aadcf7cd2..b05246036 100644 --- a/ui/js/component/header.js +++ b/ui/js/component/header.js @@ -98,9 +98,9 @@ let WunderBar = React.createClass({ } // this._input.value = ""; //trigger placeholder this._focusPending = true; - if (!this.state.address.match(/^lbry:\/\//)) //onFocus, if they are not on an exact URL, clear the bar + if (!this.state.address.startsWith('lbry://')) //onFocus, if they are not on an exact URL, clear the bar { - newState.address = ""; + newState.address = ''; } this.setState(newState); }, @@ -119,16 +119,18 @@ let WunderBar = React.createClass({ this._input = ref; }, render: function() { - return
- {this.state.icon ? : '' } - + return ( +
+ {this.state.icon ? : '' } +
+ ); } }) From a82ee8a2d584a5773ef936e6c9f204eca99ead51 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 30 Apr 2017 04:07:35 -0400 Subject: [PATCH 04/12] Fix refreshing behavior on new input in WunderBar Before, would compare the address inside it to the page address passed in by
to determine if there was a page change. This would cause user input to be replaced with "Home" when typing a search, since during a search the page address is always "Home," not the query. Now it simply checks if the page being viewed has changed. --- ui/js/component/header.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/js/component/header.js b/ui/js/component/header.js index b05246036..464b11f9a 100644 --- a/ui/js/component/header.js +++ b/ui/js/component/header.js @@ -34,7 +34,7 @@ var Header = React.createClass({
- +
@@ -86,7 +86,7 @@ let WunderBar = React.createClass({ }, componentWillReceiveProps(nextProps) { - if (nextProps.address !== this.state.address || nextProps.icon !== this.state.icon) { + if (nextProps.viewingPage !== this.props.viewingPage) { this.setState({ address: nextProps.address, icon: nextProps.icon }); } }, From 0b8d9e3d826f4e02d4201954a6532c1ed7e09f12 Mon Sep 17 00:00:00 2001 From: Alex Liebowitz Date: Sun, 30 Apr 2017 23:33:53 -0400 Subject: [PATCH 05/12] Simplify state management of viewing page Explicitly set the page being viewed to "discover" instead of just rendering the discover page if none is set. Eliminates several real or possible bugs and edge cases. --- ui/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/js/app.js b/ui/js/app.js index bf0bd4723..4a11a858b 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -81,6 +81,7 @@ var App = React.createClass({ drawerOpenRaw = sessionStorage.getItem('drawerOpen'); return Object.assign(this.getViewingPageAndArgs(window.location.search), { + viewingPage: 'discover', drawerOpen: drawerOpenRaw !== null ? JSON.parse(drawerOpenRaw) : true, errorInfo: null, modal: null, @@ -249,7 +250,6 @@ var App = React.createClass({ case 'developer': return ["Developer", "icon-file", ]; case 'discover': - default: return ["Home", "icon-home", ]; } }, From da538a7a239c63cfb5b2237549db2b660902e46b Mon Sep 17 00:00:00 2001 From: Jeremy Kauffman Date: Sun, 30 Apr 2017 20:15:21 -0400 Subject: [PATCH 06/12] many bug fixes, working back button, progress towards working search --- ui/js/app.js | 64 +++++++------ ui/js/component/common.js | 19 +--- ui/js/component/drawer.js | 67 ------------- ui/js/component/header.js | 16 ++-- ui/js/component/load_screen.js | 6 -- ui/js/lbry.js | 19 +++- ui/js/lbryio.js | 14 --- ui/js/page/discover.js | 165 +++----------------------------- ui/js/page/file-list.js | 7 +- ui/js/page/help.js | 5 +- ui/js/page/publish.js | 6 +- ui/js/page/report.js | 5 +- ui/js/page/rewards.js | 2 +- ui/js/page/search.js | 139 +++++++++++++++++++++++++++ ui/js/page/settings.js | 5 +- ui/js/page/show.js | 4 +- ui/js/page/start.js | 2 +- ui/js/page/wallet.js | 2 +- ui/package.json | 1 - ui/scss/_canvas.scss | 13 ++- ui/scss/_gui.scss | 5 +- ui/scss/component/_card.scss | 6 +- ui/scss/component/_header.scss | 17 ---- ui/scss/component/_tooltip.scss | 1 + 24 files changed, 247 insertions(+), 343 deletions(-) delete mode 100644 ui/js/component/drawer.js create mode 100644 ui/js/page/search.js diff --git a/ui/js/app.js b/ui/js/app.js index 4a11a858b..a416a6e80 100644 --- a/ui/js/app.js +++ b/ui/js/app.js @@ -12,10 +12,10 @@ import RewardPage from './page/reward.js'; import WalletPage from './page/wallet.js'; import ShowPage from './page/show.js'; import PublishPage from './page/publish.js'; +import SearchPage from './page/search.js'; import DiscoverPage from './page/discover.js'; import DeveloperPage from './page/developer.js'; import {FileListDownloaded, FileListPublished} from './page/file-list.js'; -import Drawer from './component/drawer.js'; import Header from './component/header.js'; import {Modal, ExpandableModal} from './component/modal.js'; import {Link} from './component/link.js'; @@ -38,6 +38,7 @@ var App = React.createClass({ data: 'Error data', }, _fullScreenPages: ['watch'], + _storeHistoryOfNextRender: false, _upgradeDownloadItem: null, _isMounted: false, @@ -71,18 +72,17 @@ var App = React.createClass({ getViewingPageAndArgs: function(address) { // For now, routes are in format ?page or ?page=args let [isMatch, viewingPage, pageArgs] = address.match(/\??([^=]*)(?:=(.*))?/); + console.log(pageArgs); + console.log(decodeURIComponent(pageArgs)); return { viewingPage: viewingPage, - pageArgs: pageArgs === undefined ? null : pageArgs + pageArgs: pageArgs === undefined ? null : decodeURIComponent(pageArgs) }; }, getInitialState: function() { - var match, param, val, viewingPage, pageArgs, - drawerOpenRaw = sessionStorage.getItem('drawerOpen'); - return Object.assign(this.getViewingPageAndArgs(window.location.search), { viewingPage: 'discover', - drawerOpen: drawerOpenRaw !== null ? JSON.parse(drawerOpenRaw) : true, + appUrl: null, errorInfo: null, modal: null, downloadProgress: null, @@ -90,6 +90,8 @@ var App = React.createClass({ }); }, componentWillMount: function() { + window.addEventListener("popstate", this.onHistoryPop); + document.addEventListener('unhandledError', (event) => { this.alertError(event.detail); }); @@ -106,9 +108,9 @@ var App = React.createClass({ if (target.matches('a[href^="?"]')) { event.preventDefault(); if (this._isMounted) { - history.pushState({}, document.title, target.getAttribute('href')); - this.registerHistoryPop(); - this.setState(this.getViewingPageAndArgs(target.getAttribute('href'))); + let appUrl = target.getAttribute('href'); + this._storeHistoryOfNextRender = true; + this.setState(Object.assign({}, this.getViewingPageAndArgs(appUrl), { appUrl: appUrl })); } } target = target.parentNode; @@ -126,14 +128,6 @@ var App = React.createClass({ }); } }, - openDrawer: function() { - sessionStorage.setItem('drawerOpen', true); - this.setState({ drawerOpen: true }); - }, - closeDrawer: function() { - sessionStorage.setItem('drawerOpen', false); - this.setState({ drawerOpen: false }); - }, closeModal: function() { this.setState({ modal: null, @@ -144,10 +138,17 @@ var App = React.createClass({ }, componentWillUnmount: function() { this._isMounted = false; + window.removeEventListener("popstate", this.onHistoryPop); }, - registerHistoryPop: function() { - window.addEventListener("popstate", () => { - this.setState(this.getViewingPageAndArgs(location.pathname)); + onHistoryPop: function() { + this.setState(this.getViewingPageAndArgs(location.search)); + }, + onSearch: function(term) { + this._storeHistoryOfNextRender = true; + this.setState({ + viewingPage: "search", + appUrl: "?search=" + encodeURIComponent(term), + pageArgs: term }); }, handleUpgradeClicked: function() { @@ -202,12 +203,6 @@ var App = React.createClass({ modal: null, }); }, - onSearch: function(term) { - this.setState({ - viewingPage: 'discover', - pageArgs: term - }); - }, alertError: function(error) { var errorInfoList = []; for (let key of Object.keys(error)) { @@ -225,12 +220,14 @@ var App = React.createClass({ { switch(this.state.viewingPage) { + case 'search': + return [this.state.pageArgs ? this.state.pageArgs : "Search", 'icon-search', ]; case 'settings': return ["Settings", "icon-gear", ]; case 'help': return ["Help", "icon-question", ]; case 'report': - return ['Report', 'icon-file', ]; + return ['Report an Issue', 'icon-file', ]; case 'downloaded': return ["Downloads & Purchases", "icon-folder", ]; case 'published': @@ -250,18 +247,25 @@ var App = React.createClass({ case 'developer': return ["Developer", "icon-file", ]; case 'discover': - return ["Home", "icon-home", ]; + default: + return ["Home", "icon-home", ]; } }, render: function() { let [address, wunderBarIcon, mainContent] = this.getContentAndAddress(); + lbry.setTitle(address); + + if (this._storeHistoryOfNextRender) { + this._storeHistoryOfNextRender = false; + history.pushState({}, document.title, this.state.appUrl); + } + return ( this._fullScreenPages.includes(this.state.viewingPage) ? mainContent :
-
+
{mainContent}
diff --git a/ui/js/component/common.js b/ui/js/component/common.js index 7139e5dfe..8da20ca8e 100644 --- a/ui/js/component/common.js +++ b/ui/js/component/common.js @@ -1,6 +1,5 @@ import React from 'react'; import lbry from '../lbry.js'; -import $clamp from 'clamp-js-main'; //component/icon.js export let Icon = React.createClass({ @@ -19,29 +18,15 @@ export let Icon = React.createClass({ export let TruncatedText = React.createClass({ propTypes: { - lines: React.PropTypes.number, - height: React.PropTypes.string, - auto: React.PropTypes.bool, + lines: React.PropTypes.number }, getDefaultProps: function() { return { lines: null, - height: null, - auto: true, } }, - componentDidMount: function() { - // Manually round up the line height, because clamp.js doesn't like fractional-pixel line heights. - - // Need to work directly on the style object because setting the style prop doesn't update internal styles right away. - this.refs.span.style.lineHeight = Math.ceil(parseFloat(getComputedStyle(this.refs.span).lineHeight)) + 'px'; - - $clamp(this.refs.span, { - clamp: this.props.lines || this.props.height || 'auto', - }); - }, render: function() { - return {this.props.children}; + return {this.props.children}; } }); diff --git a/ui/js/component/drawer.js b/ui/js/component/drawer.js deleted file mode 100644 index b19e901f5..000000000 --- a/ui/js/component/drawer.js +++ /dev/null @@ -1,67 +0,0 @@ -import lbry from '../lbry.js'; -import React from 'react'; -import {Link} from './link.js'; - -var DrawerItem = React.createClass({ - getDefaultProps: function() { - return { - subPages: [], - }; - }, - render: function() { - var isSelected = (this.props.viewingPage == this.props.href.substr(1) || - this.props.subPages.indexOf(this.props.viewingPage) != -1); - return - } -}); - -var drawerImageStyle = { //@TODO: remove this, img should be properly scaled once size is settled - height: '36px' -}; - -var Drawer = React.createClass({ - _balanceSubscribeId: null, - - handleLogoClicked: function(event) { - if ((event.ctrlKey || event.metaKey) && event.shiftKey) { - window.location.href = '?developer' - event.preventDefault(); - } - }, - getInitialState: function() { - return { - balance: 0, - }; - }, - componentDidMount: function() { - this._balanceSubscribeId = lbry.balanceSubscribe((balance) => { - this.setState({ - balance: balance - }); - }); - }, - componentWillUnmount: function() { - if (this._balanceSubscribeId) { - lbry.balanceUnsubscribe(this._balanceSubscribeId) - } - }, - render: function() { - return ( - - ); - } -}); - - -export default Drawer; diff --git a/ui/js/component/header.js b/ui/js/component/header.js index 464b11f9a..308cd633b 100644 --- a/ui/js/component/header.js +++ b/ui/js/component/header.js @@ -28,13 +28,14 @@ var Header = React.createClass({ render: function() { return
); diff --git a/ui/js/lbry.js b/ui/js/lbry.js index c13635a09..356887483 100644 --- a/ui/js/lbry.js +++ b/ui/js/lbry.js @@ -31,7 +31,6 @@ function savePendingPublish({name, channel_name}) { return newPendingPublish; } - /** * If there is a pending publish with the given name or outpoint, remove it. * A channel name may also be provided along with name. @@ -132,6 +131,24 @@ lbry.connect = function() { return lbry._connectPromise; } + +//kill this but still better than document.title =, which this replaced +lbry.setTitle = function(title) { + document.title = title + " - LBRY"; +} + +//kill this with proper routing +lbry.back = function() { + console.log(window.history); + if (window.history.length > 1) { + console.log('history exists, go back'); + window.history.back(); + } else { + console.log('no history, reload'); + window.location.href = "?discover"; + } +} + lbry.isDaemonAcceptingConnections = function (callback) { // Returns true/false whether the daemon is at a point it will start returning status lbry.call('status', {}, () => callback(true), null, () => callback(false)) diff --git a/ui/js/lbryio.js b/ui/js/lbryio.js index 7a1ab58c2..f37cccf62 100644 --- a/ui/js/lbryio.js +++ b/ui/js/lbryio.js @@ -151,20 +151,6 @@ lbryio.authenticate = function() { } else { setCurrentUser() } - // if (!lbryio._ - //(data) => { - // resolve(data) - // localStorage.setItem('accessToken', ID); - // localStorage.setItem('appId', installation_id); - // this.setState({ - // registrationCheckComplete: true, - // justRegistered: true, - // }); - //}); - // lbryio.call('user_install', 'exists', {app_id: installation_id}).then((userExists) => { - // // TODO: deal with case where user exists already with the same app ID, but we have no access token. - // // Possibly merge in to the existing user with the same app ID. - // }) }).catch(reject); }); } diff --git a/ui/js/page/discover.js b/ui/js/page/discover.js index 3c807e831..d522a99f8 100644 --- a/ui/js/page/discover.js +++ b/ui/js/page/discover.js @@ -1,79 +1,18 @@ 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.js'; import {ToolTip} from '../component/tooltip.js'; -import {BusyMessage} from '../component/common.js'; - -var fetchResultsStyle = { - color: '#888', - textAlign: 'center', - fontSize: '1.2em' - }; - -var SearchActive = React.createClass({ - render: function() { - return ( -
- -
- ); - } -}); - -var searchNoResultsStyle = { - textAlign: 'center' -}, searchNoResultsMessageStyle = { - fontStyle: 'italic', - marginRight: '5px' -}; - -var SearchNoResults = React.createClass({ - render: function() { - return ( -
- No one has checked anything in for {this.props.query} yet. - -
- ); - } -}); - -var SearchResults = 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}
- ); - } -}); const communityCategoryToolTipText = ('Community Content is a public space where anyone can share content with the ' + -'rest of the LBRY community. Bid on the names "one," "two," "three," "four" and ' + + 'rest of the LBRY community. Bid on the names "one," "two," "three," "four" and ' + '"five" to put your content here!'); -var FeaturedCategory = React.createClass({ +let FeaturedCategory = React.createClass({ render: function() { return (
{ this.props.category ?

{this.props.category} - { this.props.category == "community" ? + { this.props.category.match(/^community/i) ? : '' }

: '' } @@ -82,7 +21,7 @@ var FeaturedCategory = React.createClass({ } }) -var FeaturedContent = React.createClass({ +let DiscoverPage = React.createClass({ getInitialState: function() { return { featuredUris: {}, @@ -105,101 +44,19 @@ var FeaturedContent = React.createClass({ }); }, render: function() { - return ( + return
{ this.state.failed ?
Failed to load landing content.
:
{ - Object.keys(this.state.featuredUris).map((category) => { - return this.state.featuredUris[category].length ? - : - ''; - }) + Object.keys(this.state.featuredUris).map((category) => { + return this.state.featuredUris[category].length ? + : + ''; + }) }
- ); - } -}); - -var DiscoverPage = React.createClass({ - userTypingTimer: null, - - propTypes: { - showWelcome: React.PropTypes.bool.isRequired, - }, - - componentDidUpdate: function() { - if (this.props.query != this.state.query) - { - this.handleSearchChanged(this.props.query); - } - }, - - getDefaultProps: function() { - return { - showWelcome: false, - } - }, - - componentWillReceiveProps: function(nextProps, nextState) { - if (nextProps.query != nextState.query) - { - this.handleSearchChanged(nextProps.query); - } - }, - - handleSearchChanged: function(query) { - this.setState({ - searching: true, - query: query, - }); - - lighthouse.search(query).then(this.searchCallback); - }, - - handleWelcomeDone: function() { - this.setState({ - welcomeComplete: true, - }); - }, - - componentWillMount: function() { - document.title = "Home"; - - if (this.props.query) { - // Rendering with a query already typed - this.handleSearchChanged(this.props.query); - } - }, - - getInitialState: function() { - return { - welcomeComplete: false, - results: [], - query: this.props.query, - searching: ('query' in this.props) && (this.props.query.length > 0) - }; - }, - - searchCallback: function(results) { - if (this.state.searching) //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 ? : null } - { !this.state.searching && this.props.query && this.state.results.length ? : null } - { !this.state.searching && this.props.query && !this.state.results.length ? : null } - { !this.props.query && !this.state.searching ? : null } -
- ); + }
; } }); diff --git a/ui/js/page/file-list.js b/ui/js/page/file-list.js index 41a2254b5..71f8e2fc2 100644 --- a/ui/js/page/file-list.js +++ b/ui/js/page/file-list.js @@ -56,7 +56,7 @@ export let FileListDownloaded = React.createClass({ content = ; } return ( -
+
{content}
@@ -83,12 +83,11 @@ export let FileListPublished = React.createClass({ else { rewards.claimReward(rewards.TYPE_FIRST_PUBLISH).catch(() => {}) } - }); + }, () => {}); }, componentDidMount: function () { this._isMounted = true; this._requestPublishReward(); - document.title = "Published Files"; lbry.claim_list_mine().then((claimInfos) => { if (!this._isMounted) { return; } @@ -118,7 +117,7 @@ export let FileListPublished = React.createClass({ content = ; } return ( -
+
{content}
diff --git a/ui/js/page/help.js b/ui/js/page/help.js index 42e65df14..d6a28ae99 100644 --- a/ui/js/page/help.js +++ b/ui/js/page/help.js @@ -25,9 +25,6 @@ var HelpPage = React.createClass({ }); }); }, - componentDidMount: function() { - document.title = "Help"; - }, render: function() { let ver, osName, platform, newVerLink; if (this.state.versionInfo) { @@ -50,7 +47,7 @@ var HelpPage = React.createClass({ } return ( -
+
diff --git a/ui/js/page/publish.js b/ui/js/page/publish.js index dc34ea500..03583136b 100644 --- a/ui/js/page/publish.js +++ b/ui/js/page/publish.js @@ -148,7 +148,7 @@ var PublishPage = React.createClass({ }); }, handlePublishStartedConfirmed: function() { - window.location = "?published"; + window.location.href = "?published"; }, handlePublishError: function(error) { this.setState({ @@ -384,7 +384,7 @@ var PublishPage = React.createClass({ const lbcInputHelp = "This LBC remains yours and the deposit can be undone at any time." return ( -
+
@@ -548,7 +548,7 @@ var PublishPage = React.createClass({
- +
diff --git a/ui/js/page/report.js b/ui/js/page/report.js index 47a4d2a7a..e76905d4b 100644 --- a/ui/js/page/report.js +++ b/ui/js/page/report.js @@ -18,9 +18,6 @@ var ReportPage = React.createClass({ this._messageArea.value = ''; } }, - componentDidMount: function() { - document.title = "Report an Issue"; - }, closeModal: function() { this.setState({ modal: null, @@ -34,7 +31,7 @@ var ReportPage = React.createClass({ }, render: function() { return ( -
+

Report an Issue

Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!

diff --git a/ui/js/page/rewards.js b/ui/js/page/rewards.js index c4261804f..3462517c9 100644 --- a/ui/js/page/rewards.js +++ b/ui/js/page/rewards.js @@ -57,7 +57,7 @@ var RewardsPage = React.createClass({ }, render: function() { return ( -
+
{!this.state.userRewards diff --git a/ui/js/page/search.js b/ui/js/page/search.js new file mode 100644 index 000000000..3df3dd07d --- /dev/null +++ b/ui/js/page/search.js @@ -0,0 +1,139 @@ +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.js'; +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, + + 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.state.searching ? + : + (this.state.results.length ? + : + ); + } +}); + +let SearchPage = React.createClass({ + + _isMounted: false, + + propTypes: { + query: React.PropTypes.string.isRequired + }, + + isValidUri: function(query) { + return true; + }, + + 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) ? +
+

lbry://{this.props.query}

+
+
: '' } +

Search

+ +
+ ); + } +}); + +export default SearchPage; diff --git a/ui/js/page/settings.js b/ui/js/page/settings.js index abc65271d..cbc0765a8 100644 --- a/ui/js/page/settings.js +++ b/ui/js/page/settings.js @@ -66,9 +66,6 @@ var SettingsPage = React.createClass({ showUnavailable: lbry.getClientSetting('showUnavailable'), } }, - componentDidMount: function() { - document.title = "Settings"; - }, componentWillMount: function() { lbry.getDaemonSettings((settings) => { this.setState({ @@ -102,7 +99,7 @@ var SettingsPage = React.createClass({
*/ return ( -
+
diff --git a/ui/js/page/show.js b/ui/js/page/show.js index f41039868..8622a814d 100644 --- a/ui/js/page/show.js +++ b/ui/js/page/show.js @@ -70,7 +70,7 @@ let ShowPage = React.createClass({ }); }); - document.title = metadata.title ? metadata.title : this._uri; + lbry.setTitle(metadata.title ? metadata.title : this._uri) this.setState({ outpoint: outpoint, @@ -94,7 +94,7 @@ let ShowPage = React.createClass({ const title = metadata ? this.state.metadata.title : this._uri; return ( -
+
{ this.state.contentType && this.state.contentType.startsWith('video/') ?