releasable?

This commit is contained in:
Jeremy Kauffman 2017-05-01 18:31:13 -04:00
parent 59da42a84b
commit 13e198f20e
12 changed files with 182 additions and 257 deletions

View file

@ -15,6 +15,7 @@ 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 lbryuri from './lbryuri.js';
import {FileListDownloaded, FileListPublished} from './page/file-list.js';
import Header from './component/header.js';
import {Modal, ExpandableModal} from './component/modal.js';
@ -250,7 +251,7 @@ var App = React.createClass({
case 'receive':
return [this.state.viewingPage.charAt(0).toUpperCase() + this.state.viewingPage.slice(1), "icon-bank", <WalletPage viewingPage={this.state.viewingPage} />]
case 'show':
return [this.state.pageArgs, "icon-file", <ShowPage uri={this.state.pageArgs} />];
return [lbryuri.normalize(this.state.pageArgs), "icon-file", <ShowPage uri={this.state.pageArgs} />];
case 'publish':
return ["Publish", "icon-upload", <PublishPage />];
case 'developer':

View file

@ -3,7 +3,7 @@ import lbry from '../lbry.js';
import lbryuri from '../lbryuri.js';
import {Link} from '../component/link.js';
import {FileActions} from '../component/file-actions.js';
import {Thumbnail, TruncatedText, FilePrice} from '../component/common.js';
import {BusyMessage, TruncatedText, FilePrice} from '../component/common.js';
import UriIndicator from '../component/channel-indicator.js';
/*should be merged into FileTile once FileTile is refactored to take a single id*/
@ -77,37 +77,32 @@ export let FileTileStream = React.createClass({
const isConfirmed = !!metadata;
const title = isConfirmed ? metadata.title : uri;
const obscureNsfw = this.props.obscureNsfw && isConfirmed && metadata.nsfw;
const primaryUrl = "?show=" + uri;
return (
<section className={ 'file-tile card ' + (obscureNsfw ? 'card--obscured ' : '') } onMouseEnter={this.handleMouseOver} onMouseLeave={this.handleMouseOut}>
<div className={"row-fluid card__inner file-tile__row"}>
<div className="span3 file-tile__thumbnail-container">
<a href={'?show=' + uri}><Thumbnail className="file-tile__thumbnail" {... metadata && metadata.thumbnail ? {src: metadata.thumbnail} : {}} alt={'Photo for ' + this.props.uri} /></a>
</div>
<div className="span9">
<div className="card__title-primary">
{ !this.props.hidePrice
? <FilePrice uri={this.props.uri} />
: null}
<div className="meta"><a href={'?show=' + this.props.uri}>{uri}</a></div>
<h3>
<a href={'?show=' + uri} title={title}>
<TruncatedText lines={1}>
{title}
</TruncatedText>
</a>
</h3>
<a href={primaryUrl} className="card__link">
<div className={"card__inner file-tile__row"}>
<div className="card__media"
style={{ backgroundImage: "url('" + (metadata && metadata.thumbnail ? metadata.thumbnail : lbry.imagePath('default-thumb.svg')) + "')" }}>
</div>
<div className="card__content">
<p className="file-tile__description">
<TruncatedText lines={2}>
<div className="file-tile__content">
<div className="card__title-primary">
{ !this.props.hidePrice
? <FilePrice uri={this.props.uri} />
: null}
<div className="meta">{uri}</div>
<h3><TruncatedText lines={1}>{title}</TruncatedText></h3>
</div>
<div className="card__content card__subtext">
<TruncatedText lines={3}>
{isConfirmed
? metadata.description
: <span className="empty">This file is pending confirmation.</span>}
</TruncatedText>
</p>
</div>
</div>
</div>
</div>
</a>
{this.state.showNsfwHelp
? <div className='card-overlay'>
<p>
@ -224,6 +219,7 @@ export let FileCardStream = React.createClass({
export let FileTile = React.createClass({
_isMounted: false,
_isResolvePending: false,
propTypes: {
uri: React.PropTypes.string.isRequired,
@ -236,7 +232,9 @@ export let FileTile = React.createClass({
}
},
resolve: function(uri) {
this._isResolvePending = true;
lbry.resolve({uri: uri}).then((resolutionInfo) => {
this._isResolvePending = false;
if (this._isMounted && resolutionInfo && resolutionInfo.claim && resolutionInfo.claim.value &&
resolutionInfo.claim.value.stream && resolutionInfo.claim.value.stream.metadata) {
// In case of a failed lookup, metadata will be null, in which case the component will never display
@ -267,7 +265,9 @@ export let FileTile = React.createClass({
}
if (this.props.showEmpty)
{
return <div className="empty">Empty file tile for {this.props.uri}</div>
return this._isResolvePending ?
<BusyMessage message="Loading magic decentralized data" /> :
<div className="empty">{lbryuri.normalize(this.props.uri)} is unclaimed. <Link label="Put something here" href="?publish" /></div>;
}
return null;
}

View file

@ -59,29 +59,36 @@ var Header = React.createClass({
}
});
let WunderBar = React.createClass({
_userTypingTimer: null,
_input: null,
_stateBeforeSearch: null,
_resetOnNextBlur: true,
propTypes: {
class WunderBar extends React.PureComponent {
static propTypes = {
onSearch: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired
},
}
getInitialState: function() {
return {
constructor(props) {
super(props);
this._userTypingTimer = null;
this._input = null;
this._stateBeforeSearch = null;
this._resetOnNextBlur = true;
this.onChange = this.onChange.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
this.onReceiveRef = this.onReceiveRef.bind(this);
this.state = {
address: this.props.address,
icon: this.props.icon
};
},
componentWillUnmount: function() {
}
componentWillUnmount() {
if (this.userTypingTimer) {
clearTimeout(this._userTypingTimer);
}
},
onChange: function(event) {
}
onChange(event) {
if (this._userTypingTimer)
{
@ -96,19 +103,21 @@ let WunderBar = React.createClass({
this._resetOnNextBlur = false;
this.props.onSearch(searchTerm);
}, 800); // 800ms delay, tweak for faster/slower
},
}
componentWillReceiveProps(nextProps) {
if (nextProps.viewingPage !== this.props.viewingPage || nextProps.address != this.props.address) {
this.setState({ address: nextProps.address, icon: nextProps.icon });
}
},
onFocus: function() {
}
onFocus() {
this._stateBeforeSearch = this.state;
let newState = {
icon: "icon-search",
isActive: true
}
// this._input.value = ""; //trigger placeholder
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
@ -116,8 +125,9 @@ let WunderBar = React.createClass({
newState.address = '';
}
this.setState(newState);
},
onBlur: function() {
}
onBlur() {
let commonState = {isActive: false};
if (this._resetOnNextBlur) {
this.setState(Object.assign({}, this._stateBeforeSearch, commonState));
@ -127,28 +137,43 @@ let WunderBar = React.createClass({
this._stateBeforeSearch = this.state;
this.setState(commonState);
}
},
componentDidUpdate: function() {
}
componentDidUpdate() {
this._input.value = this.state.address;
if (this._input && this._focusPending) {
this._input.select();
this._focusPending = false;
}
},
onKeyPress: function(event) {
}
onKeyPress(event) {
if (event.charCode == 13 && this._input.value) {
let uri = lbryuri.normalize(this._input.value);
clearTimeout(this._userTypingTimer);
this.props.onSubmit(uri);
this.setState({ value: uri })
let uri = null,
method = "onSubmit";
this._resetOnNextBlur = false;
clearTimeout(this._userTypingTimer);
try {
uri = lbryuri.normalize(this._input.value);
this.setState({ value: uri });
} catch (error) { //then it's not a valid URL, so let's search
uri = this._input.value;
method = "onSearch";
}
this.props[method](uri);
this._input.blur();
}
},
onReceiveRef: function(ref) {
}
onReceiveRef(ref) {
this._input = ref;
},
render: function() {
}
render() {
return (
<div className={'wunderbar' + (this.state.isActive ? ' wunderbar--active' : '')}>
{this.state.icon ? <Icon fixed icon={this.state.icon} /> : '' }
@ -163,7 +188,7 @@ let WunderBar = React.createClass({
</div>
);
}
})
}
export let SubHeader = React.createClass({
render: function() {

View file

@ -139,12 +139,9 @@ lbry.setTitle = function(title) {
//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";
}
}

View file

@ -105,7 +105,12 @@ let SearchPage = React.createClass({
},
isValidUri: function(query) {
return true;
try {
lbryuri.parse(query);
return true;
} catch (e) {
return false;
}
},
componentWillMount: function() {
@ -148,7 +153,7 @@ let SearchPage = React.createClass({
<section className="section-spaced">
<h3 className="card-row__header">
Search Results for {this.props.query}
<ToolTip label="?" body="These search results are provided by LBRY, Inc." className="tooltip--header"/>
<ToolTip label="?" body="These search results are provided by LBRY Inc." className="tooltip--header"/>
</h3>
<SearchResults query={this.props.query} />
</section>

View file

@ -266,7 +266,6 @@ let ShowPage = React.createClass({
delete channelUriObj.path;
delete channelUriObj.contentName;
const channelUri = this.state.signatureIsValid && this.state.hasSignature && channelUriObj.isChannel ? lbryuri.build(channelUriObj, false) : null;
console.log(this.state);
innerContent = <FilePage
uri={this._uri}
channelUri={channelUri}

View file

@ -1,49 +0,0 @@
@import "global";
html
{
height: 100%;
font-size: $font-size;
}
body
{
font-family: 'Source Sans Pro', sans-serif;
line-height: $font-line-height;
}
#window
{
min-height: 100vh;
background: $color-canvas;
}
.badge
{
background: $color-money;
display: inline-block;
padding: 2px;
color: white;
border-radius: 2px;
}
.credit-amount--indicator
{
font-weight: bold;
color: $color-money;
}
#main-content
{
padding: $spacing-vertical;
margin-top: $height-header;
display: flex;
flex-direction: column;
main {
margin-left: auto;
margin-right: auto;
max-width: 100%;
}
main.main--single-column
{
width: $width-page-constrained;
}
}

View file

@ -160,4 +160,35 @@ $blur-intensity: 8px;
width:1px;
height:1px;
overflow:hidden;
}
@mixin text-link($color: $color-primary, $hover-opacity: 0.70) {
.icon
{
&:first-child {
padding-right: 5px;
}
&:last-child:not(:only-child) {
padding-left: 5px;
}
}
&:not(.no-underline) {
text-decoration: underline;
.icon {
text-decoration: none;
}
}
&:hover
{
opacity: $hover-opacity;
transition: opacity $transition-standard;
text-decoration: underline;
.icon {
text-decoration: none;
}
}
color: $color;
cursor: pointer;
}

View file

@ -1,87 +0,0 @@
@import "global";
$gutter_fluid: 4;
[class*="span"] {
min-height: 1px;
max-width: 100%;
}
.span12 { width: 100%; }
.span11 { width: 91.666%; }
.span10 { width: 83.333%; }
.span9 { width: 75%; }
.span8 { width: 66.666%; }
.span7 { width: 58.333%; }
.span6 { width: 50%; }
.span5 { width: 41.666%; }
.span4 { width: 33.333%; }
.span3 { width: 25%; }
.span2 { width: 16.666%; }
.span1 { width: 8.333%; }
.row-fluid {
width: 100%;
> [class*="span"] {
float: left;
width: 100%;
margin-left: 1% * $gutter_fluid;
&:first-child
{
margin-left: 0;
}
}
$column_width: (100% - $gutter_fluid * 11) / 12;
> .span12 { width: $column_width * 12 + $gutter_fluid * 11; }
> .span11 { width: $column_width * 11 + $gutter_fluid * 10; }
> .span10 { width: $column_width * 10 + $gutter_fluid * 9; }
> .span9 { width: $column_width * 9 + $gutter_fluid * 8; }
> .span8 { width: $column_width * 8 + $gutter_fluid * 7; }
> .span7 { width: $column_width * 7 + $gutter_fluid * 6; }
> .span6 { width: $column_width * 6 + $gutter_fluid * 5; }
> .span5 { width: $column_width * 5 + $gutter_fluid * 4; }
> .span4 { width: $column_width * 4 + $gutter_fluid * 3; }
> .span3 { width: $column_width * 3 + $gutter_fluid * 2; }
> .span2 { width: $column_width * 2 + $gutter_fluid * 1; }
> .span1 { width: $column_width; }
}
.tile-fluid {
width: 100%;
> [class*="span"] {
float: left;
}
}
.column-fluid {
@include display-flex();
flex-wrap: wrap;
> [class*="span"] {
@include display-flex();
@include flex(1 0 auto);
overflow: hidden;
justify-content: center;
}
}
.row-fluid, .tile-fluid {
@include clearfix();
}
@media (max-width: $mobile-width-threshold) {
.row-fluid, .tile-fluid, .column-fluid {
width: 100%;
}
.pull-left, .pull-right
{
float: none;
}
[class*="span"] {
float: none !important;
width: 100% !important;
margin-left: 0 !important;
display: block !important;
}
}

View file

@ -1,35 +1,51 @@
@import "global";
@mixin text-link($color: $color-primary, $hover-opacity: 0.70) {
html
{
height: 100%;
font-size: $font-size;
}
body
{
font-family: 'Source Sans Pro', sans-serif;
line-height: $font-line-height;
}
.icon
#window
{
min-height: 100vh;
background: $color-canvas;
}
.badge
{
background: $color-money;
display: inline-block;
padding: 2px;
color: white;
border-radius: 2px;
}
.credit-amount--indicator
{
font-weight: bold;
color: $color-money;
}
#main-content
{
padding: $spacing-vertical;
margin-top: $height-header;
display: flex;
flex-direction: column;
main {
margin-left: auto;
margin-right: auto;
max-width: 100%;
}
main.main--single-column
{
&:first-child {
padding-right: 5px;
}
&:last-child:not(:only-child) {
padding-left: 5px;
}
width: $width-page-constrained;
}
&:not(.no-underline) {
text-decoration: underline;
.icon {
text-decoration: none;
}
}
&:hover
{
opacity: $hover-opacity;
transition: opacity $transition-standard;
text-decoration: underline;
.icon {
text-decoration: none;
}
}
color: $color;
cursor: pointer;
}
.icon-fixed-width {

View file

@ -1,8 +1,6 @@
@import "_reset";
@import "_grid";
@import "_icons";
@import "_mediaelement";
@import "_canvas";
@import "_gui";
@import "component/_table";
@import "component/_button.scss";

View file

@ -1,37 +1,26 @@
@import "../global";
$height-file-tile: $spacing-vertical * 8;
$height-file-tile: $spacing-vertical * 6;
.file-tile__row {
overflow: hidden;
height: $height-file-tile;
.credit-amount {
float: right;
}
//Hack! Remove below!
.card__title-primary {
margin-top: $spacing-vertical * 2/3;
//also a hack
.card__media {
height: $height-file-tile;
max-width: $height-file-tile;
width: $height-file-tile;
margin-right: $spacing-vertical / 2;
float: left;
}
//basically everything here is a hack now
.file-tile__content {
padding-top: $spacing-vertical * 1/3;
margin-left: $height-file-tile + $spacing-vertical / 2;
}
.card__title-primary {
margin-top: 0;
}
}
.file-tile__thumbnail {
max-width: 100%;
max-height: $height-file-tile;
vertical-align: middle;
display: block;
margin-left: auto;
margin-right: auto;
}
.file-tile__thumbnail-container
{
height: $height-file-tile;
@include absolute-center();
}
.file-tile__title {
font-weight: bold;
}
.file-tile__description {
color: #444;
margin-top: 12px;
font-size: 0.9em;
}