Merge branch 'master' into 348-multiple-wallet-addresses
This commit is contained in:
commit
6297faac79
33 changed files with 244 additions and 276 deletions
19
README.md
19
README.md
|
@ -1,7 +1,7 @@
|
|||
# Spee.ch
|
||||
Spee.ch is a web app that reads and publishes images and videos to and from the [LBRY](https://lbry.io/) blockchain.
|
||||
|
||||
## how to run this repository locally
|
||||
## How to run this repository locally
|
||||
* start mysql
|
||||
* install mysql
|
||||
* create a database called `lbry`
|
||||
|
@ -9,8 +9,6 @@ Spee.ch is a web app that reads and publishes images and videos to and from the
|
|||
* start lbrynet daemon
|
||||
* install the [`lbry`](https://github.com/lbryio/lbry) daemon
|
||||
* start the `lbry` daemon
|
||||
* start spee.ch-sync
|
||||
* install and run this [`speech-sync`](https://github.com/billbitt/spee.ch-sync) tool
|
||||
* start spee.ch
|
||||
* clone this repo
|
||||
* run `npm install`
|
||||
|
@ -20,6 +18,9 @@ Spee.ch is a web app that reads and publishes images and videos to and from the
|
|||
* build the app by running `npm run build-prod`
|
||||
* to start the server, run `npm run start`
|
||||
* visit [localhost:3000](http://localhost:3000)
|
||||
* start spee.ch-sync (optional, recommended)
|
||||
* Note: this tool will decode blocks from the `lbry` blockchain and update the Claim and Certificate tables in mysql with all the claims from the blockchain. This is not necessary if you only want to host and resolve content published through your version of spee.ch, but it is required if you want to retrieve and host other content from the lbry network.
|
||||
* install and run this [`speech-sync`](https://github.com/billbitt/spee.ch-sync) tool
|
||||
|
||||
## Tests
|
||||
* Spee.ch uses `mocha` with `chai` for testing.
|
||||
|
@ -33,16 +34,16 @@ Spee.ch is a web app that reads and publishes images and videos to and from the
|
|||
* example: `curl https://spee.ch/api/claim/resolve/doitlive/xyz`
|
||||
* /api/claim/list/:name
|
||||
* example: `curl https://spee.ch/api/claim/list/doitlive`
|
||||
* /api/claim/availability/:name (
|
||||
* returns `true`/`false` for whether a name is available through spee.ch
|
||||
* /api/claim/availability/:name
|
||||
* returns the name if it is available
|
||||
* example: `curl https://spee.ch/api/claim/availability/doitlive`
|
||||
* /api/channel/availability/:name (
|
||||
* returns `true`/`false` for whether a channel is available through spee.ch
|
||||
* /api/channel/availability/:name
|
||||
* returns the name if it is available
|
||||
* example: `curl https://spee.ch/api/channel/availability/@CoolChannel`
|
||||
|
||||
#### POST
|
||||
* /api/claim/publish
|
||||
* example: `curl -X POST -F 'name=MyPictureName' -F 'file=@/path/to/myPicture.jpeg' https://spee.ch/api/claim/publish`
|
||||
* example: `curl -F 'name=MyPictureName' -F 'file=@/path/to/myPicture.jpeg' https://spee.ch/api/claim/publish`
|
||||
* Parameters:
|
||||
* `name`
|
||||
* `file` (must be type .mp4, .jpeg, .jpg, .gif, or .png)
|
||||
|
@ -54,5 +55,5 @@ Spee.ch is a web app that reads and publishes images and videos to and from the
|
|||
* `channelName`(optional)
|
||||
* `channelPassword` (optional,; required if `channelName` is provided)
|
||||
|
||||
## bugs
|
||||
## Bugs
|
||||
If you find a bug or experience a problem, please report your issue here on github and find us in the lbry discord!
|
||||
|
|
|
@ -23,14 +23,14 @@ module.exports = {
|
|||
title : 'Spee.ch',
|
||||
name : 'Spee.ch',
|
||||
host : 'https://spee.ch',
|
||||
description: 'Open-source, decentralized image and video sharing.'
|
||||
description: 'Open-source, decentralized image and video sharing.',
|
||||
},
|
||||
publish: {
|
||||
primaryClaimAddress : null, // choose any address from your lbry wallet
|
||||
additionalClaimAddresses: [], // // optional: add previously used claim addresses
|
||||
thumbnailChannel : '@channelName', // create a channel to use for thumbnail images
|
||||
thumbnailChannelId : 'xyz123...', // the channel_id (claim id) for the channel above
|
||||
}
|
||||
},
|
||||
claim: {
|
||||
defaultTitle : 'Spee.ch',
|
||||
defaultThumbnail : 'https://spee.ch/assets/img/video_thumb_default.png',
|
||||
|
|
|
@ -158,6 +158,13 @@ a, a:visited {
|
|||
color: #4156C5;
|
||||
}
|
||||
|
||||
.link--secondary, .link--secondary:visited {
|
||||
font-size: medium;
|
||||
margin: 0px;
|
||||
padding: 0.3em;
|
||||
color: #9b9b9b;
|
||||
}
|
||||
|
||||
.link--nav {
|
||||
color: black;
|
||||
border-bottom: 2px solid white;
|
||||
|
@ -461,6 +468,10 @@ button {
|
|||
color: #9b9b9b;
|
||||
}
|
||||
|
||||
.button--wide {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* TABLES */
|
||||
|
||||
table {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
const ActiveStatusBar = () => {
|
||||
return <span className="progress-bar progress-bar--active">| </span>;
|
||||
}
|
||||
return <span className='progress-bar progress-bar--active'>| </span>;
|
||||
};
|
||||
|
||||
export default ActiveStatusBar;
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
class AssetInfo extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
showDetails: false,
|
||||
};
|
||||
this.toggleDetails = this.toggleDetails.bind(this);
|
||||
this.copyToClipboard = this.copyToClipboard.bind(this);
|
||||
}
|
||||
toggleDetails () {
|
||||
if (this.state.showDetails) {
|
||||
return this.setState({showDetails: false});
|
||||
}
|
||||
this.setState({showDetails: true});
|
||||
}
|
||||
copyToClipboard (event) {
|
||||
var elementToCopy = event.target.dataset.elementtocopy;
|
||||
var element = document.getElementById(elementToCopy);
|
||||
element.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (err) {
|
||||
this.setState({error: 'Oops, unable to copy'});
|
||||
}
|
||||
}
|
||||
render () {
|
||||
const { asset: { shortId, claimData : { channelName, certificateId, description, name, claimId, fileExt, contentType, thumbnail, host } } } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{channelName &&
|
||||
<div className="row row--padded row--wide row--no-top">
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">Channel:</span>
|
||||
</div>
|
||||
<div className="column column--8 column--med-10">
|
||||
<span className="text"><Link to={`/${channelName}:${certificateId}`}>{channelName}</Link></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{description &&
|
||||
<div className="row row--padded row--wide row--no-top">
|
||||
<span className="text">{description}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className="row row--padded row--wide row--no-top">
|
||||
<div id="show-short-link">
|
||||
<div className="column column--2 column--med-10">
|
||||
<Link className="link--primary" to={`/${shortId}/${name}.${fileExt}`}><span
|
||||
className="text">Link:</span></Link>
|
||||
</div>
|
||||
<div className="column column--8 column--med-10">
|
||||
<div className="row row--short row--wide">
|
||||
<div className="column column--7">
|
||||
<div className="input-error" id="input-error-copy-short-link" hidden="true">error here</div>
|
||||
<input type="text" id="short-link" className="input-disabled input-text--full-width" readOnly
|
||||
spellCheck="false"
|
||||
value={`${host}/${shortId}/${name}.${fileExt}`}
|
||||
onClick={this.select}/>
|
||||
</div>
|
||||
<div className="column column--1"> </div>
|
||||
<div className="column column--2">
|
||||
<button className="button--primary" data-elementtocopy="short-link"
|
||||
onClick={this.copyToClipboard}>copy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="show-embed-code">
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">Embed:</span>
|
||||
</div>
|
||||
<div className="column column--8 column--med-10">
|
||||
<div className="row row--short row--wide">
|
||||
<div className="column column--7">
|
||||
<div className="input-error" id="input-error-copy-embed-text" hidden="true">error here</div>
|
||||
{(contentType === 'video/mp4') ? (
|
||||
<input type="text" id="embed-text" className="input-disabled input-text--full-width" readOnly
|
||||
onClick={this.select} spellCheck="false"
|
||||
value={`<video width="100%" controls poster="${thumbnail}" src="${host}/${claimId}/${name}.${fileExt}"/></video>`}/>
|
||||
) : (
|
||||
<input type="text" id="embed-text" className="input-disabled input-text--full-width" readOnly
|
||||
onClick={this.select} spellCheck="false"
|
||||
value={`<img src="${host}/${claimId}/${name}.${fileExt}"/>`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="column column--1"> </div>
|
||||
<div className="column column--2">
|
||||
<button className="button--primary" data-elementtocopy="embed-text"
|
||||
onClick={this.copyToClipboard}>copy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="show-share-buttons">
|
||||
<div className="row row--padded row--wide row--no-top">
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">Share:</span>
|
||||
</div>
|
||||
<div className="column column--7 column--med-10">
|
||||
<div
|
||||
className="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap">
|
||||
<a className="link--primary" target="_blank"
|
||||
href={`https://twitter.com/intent/tweet?text=${host}/${shortId}/${name}`}>twitter</a>
|
||||
<a className="link--primary" target="_blank"
|
||||
href={`https://www.facebook.com/sharer/sharer.php?u=${host}/${shortId}/${name}`}>facebook</a>
|
||||
<a className="link--primary" target="_blank"
|
||||
href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${host}/${shortId}/${name}`}>tumblr</a>
|
||||
<a className="link--primary" target="_blank"
|
||||
href={`https://www.reddit.com/submit?url=${host}/${shortId}/${name}&title=${name}`}>reddit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ this.state.showDetails &&
|
||||
<div>
|
||||
<div className="row--padded row--wide row--no-top">
|
||||
<div>
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">Claim Name:</span>
|
||||
</div><div className="column column--8 column--med-10">
|
||||
{name}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">Claim Id:</span>
|
||||
</div><div className="column column--8 column--med-10">
|
||||
{claimId}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="column column--2 column--med-10">
|
||||
<span className="text">File Type:</span>
|
||||
</div><div className="column column--8 column--med-10">
|
||||
{contentType ? `${contentType}` : 'unknown'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row--padded row--wide row--no-top">
|
||||
<div className="column column--10">
|
||||
<a target="_blank" href="https://lbry.io/dmca">Report</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className="row row--wide">
|
||||
<button className="button--secondary" onClick={this.toggleDetails}>{this.state.showDetails ? 'less' : 'more'}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AssetInfo;
|
|
@ -2,31 +2,32 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
class ExpandingTextarea extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this._handleChange = this._handleChange.bind(this);
|
||||
}
|
||||
componentDidMount () {
|
||||
this.adjustTextarea({});
|
||||
}
|
||||
|
||||
render () {
|
||||
const { onChange, ...rest } = this.props;
|
||||
return (
|
||||
<textarea
|
||||
{ ...rest }
|
||||
ref={x => this.el = x}
|
||||
onChange={ this._handleChange.bind(this) }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleChange (event) {
|
||||
const { onChange } = this.props;
|
||||
if (onChange) onChange(event);
|
||||
this.adjustTextarea(event);
|
||||
}
|
||||
|
||||
adjustTextarea ({ target = this.el }) {
|
||||
target.style.height = 0;
|
||||
target.style.height = `${target.scrollHeight}px`;
|
||||
}
|
||||
render () {
|
||||
const { ...rest } = this.props;
|
||||
return (
|
||||
<textarea
|
||||
{...rest}
|
||||
ref={x => this.el = x}
|
||||
onChange={this._handleChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExpandingTextarea.propTypes = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
const InactiveStatusBar = () => {
|
||||
return <span className="progress-bar progress-bar--inactive">| </span>;
|
||||
}
|
||||
return <span className='progress-bar progress-bar--inactive'>| </span>;
|
||||
};
|
||||
|
||||
export default InactiveStatusBar;
|
||||
|
|
|
@ -3,20 +3,20 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
function Logo () {
|
||||
return (
|
||||
<svg version="1.1" id="Layer_1" x="0px" y="0px" height="24px" viewBox="0 0 80 31" enableBackground="new 0 0 80 31" className="nav-bar-logo">
|
||||
<Link to="/">
|
||||
<svg version='1.1' id='Layer_1' x='0px' y='0px' height='24px' viewBox='0 0 80 31' enableBackground='new 0 0 80 31' className='nav-bar-logo'>
|
||||
<Link to='/'>
|
||||
<title>Logo</title>
|
||||
<desc>Spee.ch logo</desc>
|
||||
<g id="About">
|
||||
<g id="Publish-Form-V2-_x28_filled_x29_" transform="translate(-42.000000, -23.000000)">
|
||||
<g id="Group-17" transform="translate(42.000000, 22.000000)">
|
||||
<text transform="matrix(1 0 0 1 0 20)" fontSize="25" fontFamily="Roboto">Spee<h</text>
|
||||
<g id="Group-16" transform="translate(0.000000, 30.000000)">
|
||||
<path id="Line-8" fill="none" stroke="#09F911" strokeWidth="1" strokeLinecap="square" d="M0.5,1.5h15"/>
|
||||
<path id="Line-8-Copy" fill="none" stroke="#029D74" strokeWidth="1" strokeLinecap="square" d="M16.5,1.5h15"/>
|
||||
<path id="Line-8-Copy-2" fill="none" stroke="#E35BD8" strokeWidth="1" strokeLinecap="square" d="M32.5,1.5h15"/>
|
||||
<path id="Line-8-Copy-3" fill="none" stroke="#4156C5" strokeWidth="1" strokeLinecap="square" d="M48.5,1.5h15"/>
|
||||
<path id="Line-8-Copy-4" fill="none" stroke="#635688" strokeWidth="1" strokeLinecap="square" d="M64.5,1.5h15"/>
|
||||
<g id='About'>
|
||||
<g id='Publish-Form-V2-_x28_filled_x29_' transform='translate(-42.000000, -23.000000)'>
|
||||
<g id='Group-17' transform='translate(42.000000, 22.000000)'>
|
||||
<text transform='matrix(1 0 0 1 0 20)' fontSize='25' fontFamily='Roboto'>Spee<h</text>
|
||||
<g id='Group-16' transform='translate(0.000000, 30.000000)'>
|
||||
<path id='Line-8' fill='none' stroke='#09F911' strokeWidth='1' strokeLinecap='square' d='M0.5,1.5h15' />
|
||||
<path id='Line-8-Copy' fill='none' stroke='#029D74' strokeWidth='1' strokeLinecap='square' d='M16.5,1.5h15' />
|
||||
<path id='Line-8-Copy-2' fill='none' stroke='#E35BD8' strokeWidth='1' strokeLinecap='square' d='M32.5,1.5h15' />
|
||||
<path id='Line-8-Copy-3' fill='none' stroke='#4156C5' strokeWidth='1' strokeLinecap='square' d='M48.5,1.5h15' />
|
||||
<path id='Line-8-Copy-4' fill='none' stroke='#635688' strokeWidth='1' strokeLinecap='square' d='M64.5,1.5h15' />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
|||
|
||||
function NavBarChannelDropdown ({ channelName, handleSelection, defaultSelection, VIEW, LOGOUT }) {
|
||||
return (
|
||||
<select type="text" id="nav-bar-channel-select" className="select select--arrow link--nav" onChange={handleSelection} value={defaultSelection}>
|
||||
<option id="nav-bar-channel-select-channel-option">{channelName}</option>
|
||||
<select type='text' id='nav-bar-channel-select' className='select select--arrow link--nav' onChange={handleSelection} value={defaultSelection}>
|
||||
<option id='nav-bar-channel-select-channel-option'>{channelName}</option>
|
||||
<option value={VIEW}>View</option>
|
||||
<option value={LOGOUT}>Logout</option>
|
||||
</select>
|
||||
|
|
|
@ -4,13 +4,13 @@ import PropTypes from 'prop-types';
|
|||
function UrlMiddle ({publishInChannel, selectedChannel, loggedInChannelName, loggedInChannelShortId}) {
|
||||
if (publishInChannel) {
|
||||
if (selectedChannel === loggedInChannelName) {
|
||||
return <span id="url-channel" className="url-text--secondary">{loggedInChannelName}:{loggedInChannelShortId} /</span>;
|
||||
return <span id='url-channel' className='url-text--secondary'>{loggedInChannelName}:{loggedInChannelShortId} /</span>;
|
||||
}
|
||||
return <span id="url-channel-placeholder" className="url-text--secondary tooltip">@channel<span
|
||||
className="tooltip-text">Select a channel below</span> /</span>;
|
||||
return <span id='url-channel-placeholder' className='url-text--secondary tooltip'>@channel<span
|
||||
className='tooltip-text'>Select a channel below</span> /</span>;
|
||||
}
|
||||
return (
|
||||
<span id="url-no-channel-placeholder" className="url-text--secondary tooltip">xyz<span className="tooltip-text">This will be a random id</span> /</span>
|
||||
<span id='url-no-channel-placeholder' className='url-text--secondary tooltip'>xyz<span className='tooltip-text'>This will be a random id</span> /</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
123
react/containers/AssetInfo/view.jsx
Normal file
123
react/containers/AssetInfo/view.jsx
Normal file
|
@ -0,0 +1,123 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
class AssetInfo extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.copyToClipboard = this.copyToClipboard.bind(this);
|
||||
}
|
||||
copyToClipboard (event) {
|
||||
var elementToCopy = event.target.dataset.elementtocopy;
|
||||
var element = document.getElementById(elementToCopy);
|
||||
element.select();
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
} catch (err) {
|
||||
this.setState({error: 'Oops, unable to copy'});
|
||||
}
|
||||
}
|
||||
render () {
|
||||
const { asset: { shortId, claimData : { channelName, certificateId, description, name, claimId, fileExt, contentType, thumbnail, host } } } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{channelName &&
|
||||
<div className='row row--padded row--wide row--no-top'>
|
||||
<div className='column column--2 column--med-10'>
|
||||
<span className='text'>Channel:</span>
|
||||
</div>
|
||||
<div className='column column--8 column--med-10'>
|
||||
<span className='text'><Link to={`/${channelName}:${certificateId}`}>{channelName}</Link></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{description &&
|
||||
<div className='row row--padded row--wide row--no-top'>
|
||||
<span className='text'>{description}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div id='show-share-buttons'>
|
||||
<div className='row row--padded row--wide row--no-top'>
|
||||
<div className='column column--2 column--med-10'>
|
||||
<span className='text'>Share:</span>
|
||||
</div>
|
||||
<div className='column column--8 column--med-10'>
|
||||
<div
|
||||
className='row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap'>
|
||||
<a className='link--primary' target='_blank' href={`https://twitter.com/intent/tweet?text=${host}/${shortId}/${name}`}>twitter</a>
|
||||
<a className='link--primary' target='_blank' href={`https://www.facebook.com/sharer/sharer.php?u=${host}/${shortId}/${name}`}>facebook</a>
|
||||
<a className='link--primary' target='_blank' href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${host}/${shortId}/${name}`}>tumblr</a>
|
||||
<a className='link--primary' target='_blank' href={`https://www.reddit.com/submit?url=${host}/${shortId}/${name}&title=${name}`}>reddit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='row row--padded row--wide row--no-top'>
|
||||
<div id='show-short-link'>
|
||||
<div className='column column--2 column--med-10'>
|
||||
<span className='text'>Link:</span>
|
||||
</div>
|
||||
<div className='column column--8 column--med-10'>
|
||||
<div className='row row--short row--wide'>
|
||||
<div className='column column--7'>
|
||||
<div className='input-error' id='input-error-copy-short-link' hidden='true'>error here</div>
|
||||
<input type='text' id='short-link' className='input-disabled input-text--full-width' readOnly
|
||||
spellCheck='false'
|
||||
value={`${host}/${shortId}/${name}.${fileExt}`}
|
||||
onClick={this.select} />
|
||||
</div>
|
||||
<div className='column column--1' />
|
||||
<div className='column column--2'>
|
||||
<button className='button--primary button--wide' data-elementtocopy='short-link'
|
||||
onClick={this.copyToClipboard}>copy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id='show-embed-code'>
|
||||
<div className='column column--2 column--med-10'>
|
||||
<span className='text'>Embed:</span>
|
||||
</div>
|
||||
<div className='column column--8 column--med-10'>
|
||||
<div className='row row--short row--wide'>
|
||||
<div className='column column--7'>
|
||||
<div className='input-error' id='input-error-copy-embed-text' hidden='true'>error here</div>
|
||||
{(contentType === 'video/mp4') ? (
|
||||
<input type='text' id='embed-text' className='input-disabled input-text--full-width' readOnly
|
||||
onClick={this.select} spellCheck='false'
|
||||
value={`<video width="100%" controls poster="${thumbnail}" src="${host}/${claimId}/${name}.${fileExt}"/></video>`} />
|
||||
) : (
|
||||
<input type='text' id='embed-text' className='input-disabled input-text--full-width' readOnly
|
||||
onClick={this.select} spellCheck='false'
|
||||
value={`<img src="${host}/${claimId}/${name}.${fileExt}"/>`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className='column column--1' />
|
||||
<div className='column column--2'>
|
||||
<button className='button--primary button--wide' data-elementtocopy='embed-text'
|
||||
onClick={this.copyToClipboard}>copy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex-container--row flex-container--space-between-bottom'>
|
||||
<Link className='link--primary' to={`/${shortId}/${name}.${fileExt}`}><span
|
||||
className='text'>Direct Link</span></Link>
|
||||
<a className='link--primary' href={`${host}/${claimId}/${name}.${fileExt}`} download={name}>Download</a>
|
||||
<a className='link--primary' target='_blank' href='https://lbry.io/dmca'>Report</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AssetInfo;
|
|
@ -3,9 +3,7 @@ import View from './view';
|
|||
import { selectAsset } from 'selectors/show';
|
||||
|
||||
const mapStateToProps = ({ show }) => {
|
||||
// select title
|
||||
const { claimData: { title } } = selectAsset(show);
|
||||
// return props
|
||||
return {
|
||||
title,
|
||||
};
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
const AssetTitle = ({ title }) => {
|
||||
return (
|
||||
<div>
|
||||
<span className="text--large">{title}</span>
|
||||
<span className='text--large'>{title}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -24,7 +24,7 @@ class ChannelClaimsDisplay extends React.Component {
|
|||
render () {
|
||||
const { channel: { claimsData: { claims, currentPage, totalPages } } } = this.props;
|
||||
return (
|
||||
<div className="row row--tall">
|
||||
<div className='row row--tall'>
|
||||
{(claims.length > 0) ? (
|
||||
<div>
|
||||
{claims.map((claim, index) => <AssetPreview
|
||||
|
|
|
@ -54,15 +54,15 @@ class NavBar extends React.Component {
|
|||
}
|
||||
render () {
|
||||
return (
|
||||
<div className="row row--wide nav-bar">
|
||||
<div className="row row--padded row--short flex-container--row flex-container--space-between-center">
|
||||
<div className='row row--wide nav-bar'>
|
||||
<div className='row row--padded row--short flex-container--row flex-container--space-between-center'>
|
||||
<Logo />
|
||||
<div className="nav-bar--center">
|
||||
<span className="nav-bar-tagline">Open-source, decentralized image and video sharing.</span>
|
||||
<div className='nav-bar--center'>
|
||||
<span className='nav-bar-tagline'>Open-source, decentralized image and video sharing.</span>
|
||||
</div>
|
||||
<div className="nav-bar--right">
|
||||
<NavLink className="nav-bar-link link--nav" activeClassName="link--nav-active" to="/" exact={true}>Publish</NavLink>
|
||||
<NavLink className="nav-bar-link link--nav" activeClassName="link--nav-active" to="/about">About</NavLink>
|
||||
<div className='nav-bar--right'>
|
||||
<NavLink className='nav-bar-link link--nav' activeClassName='link--nav-active' to='/' exact>Publish</NavLink>
|
||||
<NavLink className='nav-bar-link link--nav' activeClassName='link--nav-active' to='/about'>About</NavLink>
|
||||
{ this.props.channelName ? (
|
||||
<NavBarChannelDropdown
|
||||
channelName={this.props.channelName}
|
||||
|
@ -72,7 +72,7 @@ class NavBar extends React.Component {
|
|||
LOGOUT={LOGOUT}
|
||||
/>
|
||||
) : (
|
||||
<NavLink id="nav-bar-login-link" className="nav-bar-link link--nav" activeClassName="link--nav-active" to="/login">Channel</NavLink>
|
||||
<NavLink id='nav-bar-login-link' className='nav-bar-link link--nav' activeClassName='link--nav-active' to='/login'>Channel</NavLink>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -24,48 +24,48 @@ class PublishMetadataInputs extends React.Component {
|
|||
}
|
||||
render () {
|
||||
return (
|
||||
<div id="publish-details" className="row row--padded row--no-top row--wide">
|
||||
<div id='publish-details' className='row row--padded row--no-top row--wide'>
|
||||
{this.props.showMetadataInputs && (
|
||||
<div>
|
||||
<div className="row row--no-top">
|
||||
<div className="column column--3 column--med-10 align-content-top">
|
||||
<label htmlFor="publish-license" className="label">Description:</label>
|
||||
</div><div className="column column--7 column--sml-10">
|
||||
<div className='row row--no-top'>
|
||||
<div className='column column--3 column--med-10 align-content-top'>
|
||||
<label htmlFor='publish-license' className='label'>Description:</label>
|
||||
</div><div className='column column--7 column--sml-10'>
|
||||
<ExpandingTextArea
|
||||
id="publish-description"
|
||||
className="textarea textarea--primary textarea--full-width"
|
||||
id='publish-description'
|
||||
className='textarea textarea--primary textarea--full-width'
|
||||
rows={1}
|
||||
maxLength={2000}
|
||||
style={{ maxHeight: 200 }}
|
||||
name="description"
|
||||
placeholder="Optional description"
|
||||
name='description'
|
||||
placeholder='Optional description'
|
||||
value={this.props.description}
|
||||
onChange={this.handleInput} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row row--no-top">
|
||||
<div className="column column--3 column--med-10">
|
||||
<label htmlFor="publish-license" className="label">License:</label>
|
||||
</div><div className="column column--7 column--sml-10">
|
||||
<select type="text" name="license" id="publish-license" className="select select--primary" onChange={this.handleSelect}>
|
||||
<option value=" ">Unspecified</option>
|
||||
<option value="Public Domain">Public Domain</option>
|
||||
<option value="Creative Commons">Creative Commons</option>
|
||||
<div className='row row--no-top'>
|
||||
<div className='column column--3 column--med-10'>
|
||||
<label htmlFor='publish-license' className='label'>License:</label>
|
||||
</div><div className='column column--7 column--sml-10'>
|
||||
<select type='text' name='license' id='publish-license' className='select select--primary' onChange={this.handleSelect}>
|
||||
<option value=' '>Unspecified</option>
|
||||
<option value='Public Domain'>Public Domain</option>
|
||||
<option value='Creative Commons'>Creative Commons</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row row--no-top">
|
||||
<div className="column column--3">
|
||||
<label htmlFor="publish-nsfw" className="label">Mature:</label>
|
||||
</div><div className="column column--7">
|
||||
<input className="input-checkbox" type="checkbox" id="publish-nsfw" name="nsfw" value={this.props.nsfw} onChange={this.handleInput} />
|
||||
<div className='row row--no-top'>
|
||||
<div className='column column--3'>
|
||||
<label htmlFor='publish-nsfw' className='label'>Mature:</label>
|
||||
</div><div className='column column--7'>
|
||||
<input className='input-checkbox' type='checkbox' id='publish-nsfw' name='nsfw' value={this.props.nsfw} onChange={this.handleInput} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<button className="button--secondary" onClick={this.toggleShowInputs}>{this.props.showMetadataInputs ? 'less' : 'more'}</button>
|
||||
<button className='button--secondary' onClick={this.toggleShowInputs}>{this.props.showMetadataInputs ? 'less' : 'more'}</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ class PublishTitleInput extends React.Component {
|
|||
}
|
||||
render () {
|
||||
return (
|
||||
<input type="text" id="publish-title" className="input-text text--large input-text--full-width" name="title" placeholder="Give your post a title..." onChange={this.handleInput} value={this.props.title}/>
|
||||
<input type='text' id='publish-title' className='input-text text--large input-text--full-width' name='title' placeholder='Give your post a title...' onChange={this.handleInput} value={this.props.title} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ import React from 'react';
|
|||
import SEO from 'components/SEO';
|
||||
import NavBar from 'containers/NavBar';
|
||||
import ErrorPage from 'components/ErrorPage';
|
||||
import AssetTitle from 'components/AssetTitle';
|
||||
import AssetDisplay from 'components/AssetDisplay';
|
||||
import AssetInfo from 'components/AssetInfo';
|
||||
import AssetTitle from 'containers/AssetTitle';
|
||||
import AssetDisplay from 'containers/AssetDisplay';
|
||||
import AssetInfo from 'containers/AssetInfo';
|
||||
|
||||
class ShowAssetDetails extends React.Component {
|
||||
render () {
|
||||
const { asset } = this.props;
|
||||
if (asset) {
|
||||
const { name } = asset.claimData;
|
||||
const { claimData: { name } } = asset;
|
||||
return (
|
||||
<div>
|
||||
<SEO pageTitle={`${name} - details`} asset={asset} />
|
||||
|
@ -29,7 +29,6 @@ class ShowAssetDetails extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import SEO from 'components/SEO';
|
||||
import { Link } from 'react-router-dom';
|
||||
import AssetDisplay from 'components/AssetDisplay';
|
||||
import AssetDisplay from 'containers/AssetDisplay';
|
||||
|
||||
class ShowLite extends React.Component {
|
||||
render () {
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import ErrorPage from 'components/ErrorPage';
|
||||
import ShowAssetLite from 'components/ShowAssetLite';
|
||||
import ShowAssetDetails from 'components/ShowAssetDetails';
|
||||
import ShowChannel from 'components/ShowChannel';
|
||||
import ShowAssetLite from 'containers/ShowAssetLite';
|
||||
import ShowAssetDetails from 'containers/ShowAssetDetails';
|
||||
import ShowChannel from 'containers/ShowChannel';
|
||||
|
||||
import { CHANNEL, ASSET_LITE, ASSET_DETAILS } from 'constants/show_request_types';
|
||||
|
||||
|
|
Loading…
Reference in a new issue