set up basic AssetDisplay functionality and removed unnecessary handlebars/js

This commit is contained in:
bill bittner 2018-01-31 21:08:28 -08:00
parent bfa623ec17
commit 97a6254370
21 changed files with 238 additions and 651 deletions

View file

@ -1,139 +0,0 @@
const Asset = function () {
this.data = {};
this.addPlayPauseToVideo = function () {
const that = this;
const video = document.getElementById('video-asset');
if (video) {
// add event listener for click
video.addEventListener('click', ()=> {
that.playOrPause(video);
});
// add event listener for space bar
document.body.onkeyup = (event) => {
if (event.keyCode == 32) {
that.playOrPause(video);
}
};
}
};
this.playOrPause = function(video){
if (video.paused == true) {
video.play();
}
else{
video.pause();
}
};
this.showAsset = function () {
this.hideAssetStatus();
this.showAssetHolder();
if (!this.data.src) {
return console.log('error: src is not set')
}
if (!this.data.contentType) {
return console.log('error: contentType is not set')
}
if (this.data.contentType === 'video/mp4') {
this.showVideo();
} else {
this.showImage();
}
};
this.showVideo = function () {
console.log('showing video', this.data.src);
const video = document.getElementById('video-asset');
const source = document.createElement('source');
source.setAttribute('src', this.data.src);
video.appendChild(source);
video.play();
};
this.showImage = function () {
console.log('showing image', this.data.src);
const asset = document.getElementById('image-asset');
asset.setAttribute('src', this.data.src);
};
this.hideAssetStatus = function () {
const assetStatus = document.getElementById('asset-status');
assetStatus.hidden = true;
};
this.showAssetHolder =function () {
const assetHolder = document.getElementById('asset-holder');
assetHolder.hidden = false;
};
this.showSearchMessage = function () {
const searchMessage = document.getElementById('searching-message');
searchMessage.hidden = false;
};
this.showFailureMessage = function (msg) {
console.log(msg);
const searchMessage = document.getElementById('searching-message');
const failureMessage = document.getElementById('failure-message');
const errorMessage = document.getElementById('error-message');
searchMessage.hidden = true;
failureMessage.hidden = false;
errorMessage.innerText = msg;
};
this.checkFileAndRenderAsset = function () {
const that = this;
this.isFileAvailable()
.then(isAvailable => {
if (!isAvailable) {
console.log('file is not yet available');
that.showSearchMessage();
return that.getAssetOnSpeech();
}
})
.then(() => {
that.showAsset();
})
.catch(error => {
that.showFailureMessage(error);
})
};
this.isFileAvailable = function () {
console.log(`checking if file is available for ${this.data.claimName}#${this.data.claimId}`)
const uri = `/api/file-is-available/${this.data.claimName}/${this.data.claimId}`;
const xhr = new XMLHttpRequest();
return new Promise((resolve, reject) => {
xhr.open("GET", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
const response = JSON.parse(xhr.response);
if (xhr.status == 200) {
console.log('isFileAvailable succeeded:', response);
if (response.message === true) {
resolve(true);
} else {
resolve(false);
}
} else {
console.log('isFileAvailable failed:', response);
reject('Well this sucks, but we can\'t seem to phone home');
}
}
};
xhr.send();
})
};
this.getAssetOnSpeech = function() {
console.log(`getting claim for ${this.data.claimName}#${this.data.claimId}`)
const uri = `/api/claim-get/${this.data.claimName}/${this.data.claimId}`;
const xhr = new XMLHttpRequest();
return new Promise((resolve, reject) => {
xhr.open("GET", uri, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
const response = JSON.parse(xhr.response);
if (xhr.status == 200) {
console.log('getAssetOnSpeech succeeded:', response)
resolve(true);
} else {
console.log('getAssetOnSpeech failed:', response);
reject(response.message);
}
}
};
xhr.send();
})
};
};

View file

@ -1,65 +0,0 @@
// display the content that shows channel creation has started
function showChannelCreateInProgressDisplay () {
const publishChannelForm = document.getElementById('publish-channel-form');
const inProgress = document.getElementById('channel-publish-in-progress');
publishChannelForm.hidden = true;
inProgress.hidden = false;
}
// display the content that shows channel creation is done
function showChannelCreateDoneDisplay() {
const inProgress = document.getElementById('channel-publish-in-progress');
inProgress.hidden=true;
const done = document.getElementById('channel-publish-done');
done.hidden = false;
}
function showChannelCreationError(msg) {
const inProgress = document.getElementById('channel-publish-in-progress');
inProgress.innerText = msg;
}
function publishNewChannel (event) {
const username = document.getElementById('new-channel-name').value;
const password = document.getElementById('new-channel-password').value;
// prevent default so this script can handle submission
event.preventDefault();
// validate submission
validationFunctions.validateNewChannelSubmission(username, password)
.then(() => {
showChannelCreateInProgressDisplay();
// return sendAuthRequest(userName, password, '/signup') // post the request
return fetch('/signup', {
method: 'POST',
body: JSON.stringify({username, password}),
headers: new Headers({
'Content-Type': 'application/json'
}),
credentials: 'include',
})
.then(function(response) {
if (response.ok){
return response.json();
} else {
throw response;
}
})
.catch(function(error) {
throw error;
})
})
.then(signupResult => {
console.log('signup success:', signupResult);
showChannelCreateDoneDisplay();
window.location = '/';
})
.catch(error => {
if (error.name === 'ChannelNameError' || error.name === 'ChannelPasswordError'){
const channelNameErrorDisplayElement = document.getElementById('input-error-channel-name');
validationFunctions.showError(channelNameErrorDisplayElement, error.message);
} else {
console.log('signup failure:', error);
showChannelCreationError('Unfortunately, we encountered an error while creating your channel. Please let us know in slack!', error);
}
})
}

View file

@ -1,44 +0,0 @@
function loginToChannel (event) {
const username = document.getElementById('channel-login-name-input').value;
const password = document.getElementById('channel-login-password-input').value;
// prevent default
event.preventDefault()
validationFunctions.validateNewChannelLogin(username, password)
.then(() => {
return fetch('/login', {
method: 'POST',
body: JSON.stringify({username, password}),
headers: new Headers({
'Content-Type': 'application/json'
}),
credentials: 'include',
})
.then(function(response) {
console.log(response);
if (response.ok){
return response.json();
} else {
throw response;
}
})
.catch(function(error) {
throw error;
})
})
.then(function({success, message}) {
if (success) {
window.location = '/';
} else {
throw new Error(message);
}
})
.catch(error => {
const loginErrorDisplayElement = document.getElementById('login-error-display-element');
if (error.message){
validationFunctions.showError(loginErrorDisplayElement, error.message);
} else {
validationFunctions.showError(loginErrorDisplayElement, 'There was an error logging into your channel');
}
})
}

View file

@ -1,45 +0,0 @@
const ProgressBar = function() {
this.data = {
x: 0,
adder: 1,
bars: [],
};
this.barHolder = document.getElementById('bar-holder');
this.createProgressBar = function (size) {
this.data['size'] = size;
for (var i = 0; i < size; i++) {
const bar = document.createElement('span');
bar.innerText = '| ';
bar.setAttribute('class', 'progress-bar progress-bar--inactive');
this.barHolder.appendChild(bar);
this.data.bars.push(bar);
}
};
this.startProgressBar = function () {
this.updateInterval = setInterval(this.updateProgressBar.bind(this), 300);
};
this.updateProgressBar = function () {
const x = this.data.x;
const adder = this.data.adder;
const size = this.data.size;
// update the appropriate bar
if (x > -1 && x < size){
if (adder === 1){
this.data.bars[x].setAttribute('class', 'progress-bar progress-bar--active');
} else {
this.data.bars[x].setAttribute('class', 'progress-bar progress-bar--inactive');
}
}
// update adder
if (x === size){
this.data['adder'] = -1;
} else if ( x === -1){
this.data['adder'] = 1;
}
// update x
this.data['x'] = x + adder;
};
this.stopProgressBar = function () {
clearInterval(this.updateInterval);
};
};

View file

@ -1,132 +0,0 @@
// validation function which checks the proposed file's type, size, and name
const validationFunctions = {
validateChannelName: function (name) {
name = name.substring(name.indexOf('@') + 1);
// ensure a name was entered
if (name.length < 1) {
throw new ChannelNameError("You must enter a name for your channel");
}
// validate the characters in the 'name' field
const invalidCharacters = /[^A-Za-z0-9,-,@]/g.exec(name);
if (invalidCharacters) {
throw new ChannelNameError('"' + invalidCharacters + '" characters are not allowed');
}
},
validatePassword: function (password) {
if (password.length < 1) {
throw new ChannelPasswordError("You must enter a password for you channel");
}
},
// validation functions to check claim & channel name eligibility as the inputs change
isChannelNameAvailable: function (name) {
return this.isNameAvailable(name, '/api/channel-is-available/');
},
isNameAvailable: function (name, apiUrl) {
console.log('isNameAvailable?', name);
const url = apiUrl + name;
return fetch(url)
.then(function (response) {
return response.json();
})
.catch(error => {
console.log('isNameAvailable error', error);
throw error;
})
},
showError: function (errorDisplay, errorMsg) {
errorDisplay.hidden = false;
errorDisplay.innerText = errorMsg;
},
hideError: function (errorDisplay) {
errorDisplay.hidden = true;
errorDisplay.innerText = '';
},
showSuccess: function (successElement) {
successElement.hidden = false;
successElement.innerHTML = "&#x2714";
},
hideSuccess: function (successElement) {
successElement.hidden = true;
successElement.innerHTML = "";
},
checkChannelName: function (name) {
var successDisplayElement = document.getElementById('input-success-channel-name');
var errorDisplayElement = document.getElementById('input-error-channel-name');
var channelName = `@${name}`;
var that = this;
try {
// check to make sure the characters are valid
that.validateChannelName(channelName);
// check to make sure it is available
that.isChannelNameAvailable(channelName)
.then(function(isAvailable){
console.log('isChannelNameAvailable:', isAvailable);
if (isAvailable) {
that.hideError(errorDisplayElement);
that.showSuccess(successDisplayElement)
} else {
that.hideSuccess(successDisplayElement);
that.showError(errorDisplayElement, 'Sorry, that name is already taken');
}
})
.catch(error => {
that.hideSuccess(successDisplayElement);
that.showError(errorDisplayElement, error.message);
});
} catch (error) {
that.hideSuccess(successDisplayElement);
that.showError(errorDisplayElement, error.message);
}
},
// validation function which checks all aspects of a new channel submission
validateNewChannelSubmission: function (userName, password) {
const channelName = `@${userName}`;
var that = this;
return new Promise(function (resolve, reject) {
// 1. validate name
try {
that.validateChannelName(channelName);
} catch (error) {
return reject(error);
}
// 2. validate password
try {
that.validatePassword(password);
} catch (error) {
return reject(error);
}
// 3. if all validation passes, check availability of the name
that.isChannelNameAvailable(channelName)
.then(function(isAvailable) {
if (isAvailable) {
resolve();
} else {
reject(new ChannelNameError('Sorry, that name is already taken'));
}
})
.catch(function(error) {
reject(error);
});
});
},
// validation function which checks all aspects of a new channel login
validateNewChannelLogin: function (userName, password) {
const channelName = `@${userName}`;
var that = this;
return new Promise(function (resolve, reject) {
// 1. validate name
try {
that.validateChannelName(channelName);
} catch (error) {
return reject(error);
}
// 2. validate password
try {
that.validatePassword(password);
} catch (error) {
return reject(error);
}
resolve();
});
}
};

View file

@ -1,11 +1,153 @@
import React from 'react'; import React from 'react';
import ProgressBar from 'components/ProgressBar';
import Request from 'utils/request';
const AssetDisplay = ({ name, claimId }) => { const LOCAL_CHECK = 'LOCAL_CHECK';
return ( const SEARCHING = 'SEARCHING';
<div> const UNAVAILABLE = 'UNAVAILABLE';
<p>display {name}#{claimId} here</p> const AVAILABLE = 'AVAILABLE';
</div>
); class AssetDisplay extends React.Component {
constructor (props) {
super(props);
this.state = {
error : null,
status : LOCAL_CHECK,
thumbnail : this.props.thumbnail,
src : `/${this.props.claimId}}/${this.props.name}.${this.props.fileExt}`,
name : this.props.name,
claimId : this.props.claimId,
fileExt : this.props.fileExt,
contentType: this.props.contentType,
};
this.checkIfLocalFileAvailable = this.checkIfLocalFileAvailable.bind(this);
this.triggerGetAssetOnSpeech = this.triggerGetAssetOnSpeech.bind(this);
}
componentDidMount () {
const that = this;
this.checkIfLocalFileAvailable()
.then(isAvailable => {
if (!isAvailable) {
console.log('file is not yet available');
that.setState({status: SEARCHING});
return that.triggerGetAssetOnSpeech();
}
})
.then(() => {
that.setState({status: AVAILABLE});
that.addPlayPauseToVideoToBody();
})
.catch(error => {
that.setState({
status: UNAVAILABLE,
error : error.message,
});
});
}
checkIfLocalFileAvailable () {
console.log(`checking if file is available for ${this.props.name}#${this.props.claimId}`);
const url = `/api/file-is-available/${this.props.name}/${this.props.claimId}`;
return new Promise((resolve, reject) => {
Request(url)
.then(isAvailable => {
console.log('/api/file-is-available response:', isAvailable);
resolve(isAvailable);
})
.catch(error => {
reject(error);
});
});
}
triggerGetAssetOnSpeech () {
console.log(`getting claim for ${this.props.name}#${this.props.claimId}`)
const url = `/api/claim-get/${this.props.name}/${this.props.claimId}`;
return new Promise((resolve, reject) => {
Request(url)
.then(response => {
console.log('/api/claim-get response:', response);
resolve(true);
})
.catch(error => {
reject(error);
});
});
}
addPlayPauseToVideoToBody () {
const that = this;
const video = document.getElementById('video');
if (video) {
// add event listener for click
video.addEventListener('click', () => {
that.playOrPause(video);
});
// add event listener for space bar
document.body.onkeyup = (event) => {
if (event.keyCode === 32) {
that.playOrPause(video);
}
};
}
}
playOrPause (video) {
if (video.paused === true) {
video.play();
} else {
video.pause();
}
}
render () {
return (
<div id="asset-display-component">
{(this.state.status === SEARCHING) &&
<div>
<p>Sit tight, we're searching the LBRY blockchain for your asset!</p>
<ProgressBar size={12}/>
<p>Curious what magic is happening here? <a className="link--primary" target="blank" href="https://lbry.io/faq/what-is-lbry">Learn more.</a></p>
</div>
}
{(this.state.status === UNAVAILABLE) &&
<div>
<p>Unfortunately, we couldn't download your asset from LBRY. You can help us out by sharing the below error message in the <a className="link--primary" href="https://discord.gg/YjYbwhS" target="_blank">LBRY discord</a>.</p>
<i><p id="error-message">{this.state.error}</p></i>
</div>
}
{(this.state.status === AVAILABLE) &&
(() => {
switch (this.state.contentType) {
case 'image/jpeg':
case 'image/jpg':
case 'image/png':
return (
<img className="asset" src={this.state.src} alt={this.state.name}/>
);
case 'image/gif':
return (
<img className="asset" src={this.state.src} alt={this.state.name}/>
);
case 'video/mp4':
return (
<video id="video" className="asset" controls poster={this.state.thumbnail}>
<source src={this.state.src}/>
<p>Your browser does not support the <code>video</code> element.</p>
</video>
);
default:
return (
<p>unsupported file type</p>
);
}
})()
}
</div>
);
}
}; };
// required props
// name
// claimId
// thumbnail
// contentType
// file extension
export default AssetDisplay; export default AssetDisplay;

View file

@ -3,23 +3,17 @@ import React from 'react';
class AssetInfo extends React.Component { class AssetInfo extends React.Component {
constructor (props) { constructor (props) {
super(props); super(props);
this.toggleSection = this.toggleSection.bind(this); this.state = {
showDetails: false,
}
this.toggleDetails = this.toggleDetails.bind(this);
this.copyToClipboard = this.copyToClipboard.bind(this); this.copyToClipboard = this.copyToClipboard.bind(this);
} }
toggleSection (event) { toggleDetails () {
var dataSet = event.target.dataset; if (this.state.showDetails) {
var status = dataSet.status; return this.setState({showDetails: false});
var toggle = document.getElementById('show-details-toggle');
var details = document.getElementById('show-details');
if (status === 'closed') {
details.hidden = false;
toggle.innerText = '[less]';
toggle.dataset.status = 'open';
} else {
details.hidden = true;
toggle.innerText = '[more]';
toggle.dataset.status = 'closed';
} }
this.setState({showDetails: true});
} }
copyToClipboard (event) { copyToClipboard (event) {
var elementToCopy = event.target.dataset.elementtocopy; var elementToCopy = event.target.dataset.elementtocopy;
@ -126,41 +120,40 @@ class AssetInfo extends React.Component {
</div> </div>
</div> </div>
<div id="show-details" className="row--padded row--wide row--no-top" hidden="true"> { this.state.showDetails &&
<div id="show-claim-name"> <div>
<div className="column column--2 column--med-10"> <div className="row--padded row--wide row--no-top">
<span className="text">Claim Name:</span> <div>
<div className="column column--2 column--med-10">
<span className="text">Claim Name:</span>
</div><div className="column column--8 column--med-10">
{this.props.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">
{this.props.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">
{this.props.contentType ? `${this.props.contentType}` : 'unknown'}
</div>
</div>
</div> </div>
<div className="column column--8 column--med-10"> <div className="row--padded row--wide row--no-top">
{this.props.name} <div className="column column--10">
<a target="_blank" href="https://lbry.io/dmca">Report</a>
</div>
</div> </div>
</div> </div>
<div id="show-claim-id"> }
<div className="column column--2 column--med-10">
<span className="text">Claim Id:</span>
</div>
<div className="column column--8 column--med-10">
{this.props.claimId}
</div>
</div>
<div id="show-claim-id">
<div className="column column--2 column--med-10">
<span className="text">File Type:</span>
</div>
<div className="column column--8 column--med-10">
{this.props.contentType ? `${this.props.contentType}` : 'unknown'}
</div>
</div>
<div id="show-claim-id">
<div className="column column--10">
<a target="_blank" href="https://lbry.io/dmca">Report</a>
</div>
</div>
</div>
<div className="row row--wide"> <div className="row row--wide">
<a className="text link--primary" id="show-details-toggle" href="#" onClick={this.toggleSection} <a className="text link--primary" id="show-details-toggle" href="#" onClick={this.toggleDetails}>{this.state.showDetails ? '[less]' : '[more]'}</a>
data-status="closed">[more]</a>
</div> </div>
</div> </div>
); );

View file

@ -50,7 +50,6 @@ class ChannelClaimsDisplay extends React.Component {
</div> </div>
) : ( ) : (
<div className="row row--tall"> <div className="row row--tall">
<p># of claims in channel: {this.state.totalResults >= 0 ? this.state.totalResults : 'loading...' }</p>
{this.state.claims && this.state.claims.map((claim, index) => <AssetPreview {this.state.claims && this.state.claims.map((claim, index) => <AssetPreview
name={claim.name} name={claim.name}
claimId={claim.claimId} claimId={claim.claimId}

View file

@ -27,6 +27,9 @@ class ShowDetails extends React.Component {
<AssetDisplay <AssetDisplay
name={this.props.claimData.name} name={this.props.claimData.name}
claimId={this.props.claimData.claimId} claimId={this.props.claimData.claimId}
thumbnail={this.props.claimData.thumbnail}
contentType={this.props.claimData.contentType}
fileExt={this.props.claimData.fileExt}
/> />
</div> </div>
</div><div className="column column--5 column--sml-10 align-content-top"> </div><div className="column column--5 column--sml-10 align-content-top">

View file

@ -6,6 +6,6 @@ module.exports = app => {
// a catch-all route if someone visits a page that does not exist // a catch-all route if someone visits a page that does not exist
app.use('*', ({ originalUrl, ip }, res) => { app.use('*', ({ originalUrl, ip }, res) => {
// send response // send response
res.status(404).render('index'); res.status(404).render('404');
}); });
}; };

View file

@ -1,5 +1,4 @@
{{> navBar}} <div class="row row--tall flex-container--column flex-container--center-center">
<div class="row row--padded">
<h3>404: Not Found</h3> <h3>404: Not Found</h3>
<p>That page does not exist. Return <a class="link--primary" href="/">home</a>.</p> <p>That page does not exist. Return <a class="link--primary" href="/">home</a>.</p>
</div> </div>

View file

@ -1,55 +0,0 @@
{{> navBar}}
<div class="row row--padded">
<div class="row">
{{#ifConditional this.totalPages '===' 0}}
<p>There is no content in {{this.channelName}}:{{this.longChannelClaimId}} yet. Upload some!</p>
{{/ifConditional}}
{{#ifConditional this.totalPages '>=' 1}}
<p>Below are the contents for {{this.channelName}}:{{this.longChannelClaimId}}</p>
<div class="grid">
{{#each this.claims}}
{{> gridItem}}
{{/each}}
</div>
{{/ifConditional}}
{{#ifConditional this.totalPages '>' 1}}
<div class="row">
<div class="column column--3 align-content--left">
<a class="link--primary" href="/{{this.channelName}}:{{this.longChannelClaimId}}?p=1">First [1]</a>
</div><div class="column column--4 align-content-center">
{{#if this.previousPage}}
<a class="link--primary" href="/{{this.channelName}}:{{this.longChannelClaimId}}?p={{this.previousPage}}">Previous</a>
{{else}}
<a disabled>Previous</a>
{{/if}}
|
{{#if this.nextPage}}
<a class="link--primary" href="/{{this.channelName}}:{{this.longChannelClaimId}}?p={{this.nextPage}}">Next</a>
{{else}}
<a disabled>Next</a>
{{/if}}
</div><div class="column column--3 align-content-right">
<a class="link--primary" href="/{{this.channelName}}:{{this.longChannelClaimId}}?p={{this.totalPages}}">Last [{{this.totalPages}}]</a>
</div>
</div>
{{/ifConditional}}
</div>
</div>
<script src="/assets/vendors/masonry/masonry.pkgd.min.js"></script>
<script src="/assets/vendors/imagesloaded/imagesloaded.pkgd.min.js"></script>
<script>
// init masonry with element
var grid = document.querySelector('.grid');
var msnry;
imagesLoaded( grid, function() {
msnry = new Masonry( grid, {
itemSelector: '.grid-item',
columnWidth: 3,
percentPosition: true
});
});
</script>

View file

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
<head>
{{ placeCommonHeaderTags }}
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@spee_ch" />
<meta property="og:title" content="{{this.channelName}} on Spee.ch" />
<meta property="og:site_name" content="Spee.ch" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://spee.ch/assets/img/Speech_Logo_Main@OG-02.jpg" />
<meta property="og:url" content="http://spee.ch/{{this.channelName}}:{{this.longChannelId}}" />
<meta property="og:description" content="View images and videos from {{this.channelName}}" />
<!--google font-->
<link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet">
<!-- google analytics -->
{{ googleAnalytics }}
</head>
<body id="channel-body">
<script src="/assets/js/generalFunctions.js"></script>
{{{ body }}}
</body>
</html>

View file

@ -16,8 +16,6 @@
{{ googleAnalytics }} {{ googleAnalytics }}
</head> </head>
<body id="main-body"> <body id="main-body">
<script src="/assets/js/generalFunctions.js"></script>
<script src="/assets/js/validationFunctions.js"></script>
{{{ body }}} {{{ body }}}
</body> </body>
</html> </html>

View file

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
<head>
{{ placeCommonHeaderTags }}
<meta property="fb:app_id" content="1371961932852223">
{{#unless claimInfo.nsfw}}
{{{addTwitterCard claimInfo }}}
{{{addOpenGraph claimInfo }}}
{{/unless}}
<!--google font-->
<link href="https://fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet">
<!-- google analytics -->
{{ googleAnalytics }}
</head>
<body id="show-body">
<script src="/assets/js/generalFunctions.js"></script>
<script src="/assets/js/assetConstructor.js"></script>
{{{ body }}}
</body>
</html>

View file

@ -1,6 +0,0 @@
{{> navBar}}
<div class="row row--padded">
<h3>No Channel</h3>
<p>There are no published channels matching your url</p>
<p>If you think this message is an error, contact us in the <a class="link--primary" href="https://discord.gg/YjYbwhS" target="_blank">LBRY Discord!</a></p>
</div>

View file

@ -1,6 +0,0 @@
{{> navBar}}
<div class="row row--padded">
<h3>No Claims</h3>
<p>There are no free assets at that claim. You should publish one at <a class="link--primary" href="/">spee.ch</a>.</p>
<p>NOTE: it is possible your claim was published, but it is still being processed by the blockchain</p>
</div>

View file

@ -1,7 +1,52 @@
<p id="bar-holder"></p> <p id="bar-holder"></p>
<script src="/assets/js/progressBarConstructor.js"></script>
<script type="text/javascript"> <script type="text/javascript">
const ProgressBar = function() {
this.data = {
x: 0,
adder: 1,
bars: [],
};
this.barHolder = document.getElementById('bar-holder');
this.createProgressBar = function (size) {
this.data['size'] = size;
for (var i = 0; i < size; i++) {
const bar = document.createElement('span');
bar.innerText = '| ';
bar.setAttribute('class', 'progress-bar progress-bar--inactive');
this.barHolder.appendChild(bar);
this.data.bars.push(bar);
}
};
this.startProgressBar = function () {
this.updateInterval = setInterval(this.updateProgressBar.bind(this), 300);
};
this.updateProgressBar = function () {
const x = this.data.x;
const adder = this.data.adder;
const size = this.data.size;
// update the appropriate bar
if (x > -1 && x < size){
if (adder === 1){
this.data.bars[x].setAttribute('class', 'progress-bar progress-bar--active');
} else {
this.data.bars[x].setAttribute('class', 'progress-bar progress-bar--inactive');
}
}
// update adder
if (x === size){
this.data['adder'] = -1;
} else if ( x === -1){
this.data['adder'] = 1;
}
// update x
this.data['x'] = x + adder;
};
this.stopProgressBar = function () {
clearInterval(this.updateInterval);
};
};
const progressBar = new ProgressBar(); const progressBar = new ProgressBar();
progressBar.createProgressBar(10); progressBar.createProgressBar(10);
progressBar.startProgressBar(); progressBar.startProgressBar();

View file

@ -1,7 +0,0 @@
{{> navBar}}
<div class="row row--padded">
<h3>Error</h3>
<p>Unfortnately, Spee.ch encountered an error. You can help us out, by reporting the below error message in the #speech channel on <a class="link--primary" href="https://discord.gg/YjYbwhS" target="_blank">LBRY Discord</a>!</p>
<p>status: {{status}}</p>
<p>message: {{message}}</p>
</div>

View file

@ -1,18 +0,0 @@
{{> navBar}}
<div class="row row--tall row--padded">
<div class="column column--10">
<!-- title -->
<span class="text--large">{{claimInfo.title}}</span>
</div>
<div class="column column--5 column--sml-10 align-content-top">
<!-- asset -->
<div class="row row--padded">
{{> asset}}
</div>
</div><div class="column column--5 column--sml-10 align-content-top">
<!-- details -->
<div class="row row--padded">
{{> assetInfo}}
</div>
</div>
</div>

View file

@ -1,32 +0,0 @@
<div>
<h3>Site Statistics</h3>
<p>Serve: {{ totals.totalServe }}</p>
<p>Publish: {{ totals.totalPublish }}</p>
<p>Show: {{ totals.totalShow }}</p>
<p>Percent Success: {{ percentSuccess}}%</p>
<table>
<tr>
<th>action</th>
<th >url</th>
<th class="">count</th>
<th class="">success</th>
<th class="">failure</th>
</tr>
{{#each records}}
<tr>
<td>{{ this.action }}</td>
<td class="stats-table-url">{{ this.url }}</td>
<td class="">{{ this.count }}</td>
<td class="">{{ this.success }}</td>
<td class="">{{ this.failure }}</td>
</tr>
{{/each}}
<tr>
<td></td>
<td></td>
<td class="">{{ totals.totalCount }}</td>
<td class="">{{ totals.totalSuccess }}</td>
<td class="">{{ totals.totalFailure }}</td>
</tr>
</table>
</div>