Publish api fix #191

Merged
bones7242 merged 4 commits from publish-api-fix into redesign-1 2017-10-07 02:47:59 +02:00
49 changed files with 1168 additions and 1049 deletions
Showing only changes of commit 8e2e05ea4a - Show all commits

View file

@ -43,5 +43,7 @@ module.exports = {
} else { } else {
return error; return error;
} }
useObjectPropertiesIfNoKeys (err) {
return useObjectPropertiesIfNoKeys(err);
}, },
}; };

View file

@ -11,6 +11,7 @@ module.exports = new PassportLocalStrategy(
}, },
(req, username, password, done) => { (req, username, password, done) => {
logger.debug(`verifying loggin attempt ${username} ${password}`); logger.debug(`verifying loggin attempt ${username} ${password}`);
let userInfo = {};
return db.User return db.User
.findOne({where: {userName: username}}) .findOne({where: {userName: username}})
.then(user => { .then(user => {
@ -23,9 +24,18 @@ module.exports = new PassportLocalStrategy(
return done(null, false, {message: 'Incorrect username or password.'}); return done(null, false, {message: 'Incorrect username or password.'});
} }
logger.debug('user found:', user.dataValues); logger.debug('user found:', user.dataValues);
return user.getChannel().then(channel => { userInfo['id'] = user.id;
return done(null, user); userInfo['userName'] = user.userName;
}); return user.getChannel();
})
.then(channel => {
userInfo['channelName'] = channel.channelName;
userInfo['channelClaimId'] = channel.channelClaimId;
return db.getShortChannelIdFromLongChannelId(channel.channelClaimId, channel.channelName);
})
.then(shortChannelId => {
userInfo['shortChannelId'] = shortChannelId;
return done(null, userInfo);
}) })
.catch(error => { .catch(error => {
return done(error); return done(error);

View file

@ -11,7 +11,7 @@ module.exports = new PassportLocalStrategy(
passReqToCallback: true, // we want to be able to read the post body message parameters in the callback passReqToCallback: true, // we want to be able to read the post body message parameters in the callback
}, },
(req, username, password, done) => { (req, username, password, done) => {
logger.debug(`new channel signup request: ${username} ${password}`); logger.debug(`new channel signup request. user: ${username} pass: ${password} .`);
let user; let user;
// server-side validaton of inputs (username, password) // server-side validaton of inputs (username, password)

View file

@ -1,276 +0,0 @@
/* GENERAL */
/* TEXT */
body, button, input, textarea, label, select, option {
font-family: serif;
}
p {
padding-left: 0.3em;
}
.center-text {
text-align: center;
}
.url-text {
margin:0px;
padding:0px;
}
/* HEADERS */
h1 {
font-size: x-large;
}
h2 {
font-size: medium;
margin-top: 1em;
border-top: 1px #999 solid;
background-color: lightgray;
padding: 6px;
}
h3 {
color: black;;
}
.h3--secondary {
color: lightgray;
}
h4 {
padding: 3px;
}
/* CONTAINERS */
.wrapper {
margin-left: 20%;
width:60%;
}
.full {
clear: both;
}
.main {
float: left;
width: 65%;
}
.panel {
overflow: auto;
word-wrap: break-word;
}
.sidebar {
float: right;
width: 33%;
}
footer {
display: inline-block;
width: 100%;
margin-bottom: 2px;
padding-bottom: 2px;
border-bottom: 1px lightgrey solid;
margin-top: 2px;
padding-top: 2px;
border-top: 1px lightgrey solid;
text-align: center;
color: grey;
}
/* COLUMNS AND ROWS */
.col-left, .col-right {
overflow: auto;
margin: 0px;
width: 48%;
}
.col-left {
padding: 5px 10px 5px 0px;
float: left;
}
.col-right {
padding: 5px 0px 5px 10px;
float: right;
}
.row {
padding: 1em 2% 1em 2%;
margin: 0px;
}
.row--wide {
padding-right: 0px;
padding-left: 0px;
}
.row--thin {
padding-top: 0.5em;
padding-bottom: 0.5em;
}
.top-bar {
margin: 2em 0px 2px 0px;
padding: 0px 0px 2px 0px;
border-bottom: 1px lightgrey solid;
overflow: auto;
text-align: right;
vertical-align: text-bottom;
}
.column {
display: inline-block;
padding: 0px;
margin: 0px;
}
.column--1 {
width: 8%;
}
.column--2 {
width: 16%;
}
.column--3 {
width: 24%;
}
.column--4 {
width: 32%;
}
.column--5 {
width: 40%;
}
.column--6 {
width: 48%;
}
.column--7 {
width: 56%;
}
.column--8 {
width: 64%;
}
.column--9 {
width: 72%;
}
.column--10 {
width: 80%;
}
.column--11 {
width: 88%;
}
.column--12 {
width: 96%;
}
/* LINKS */
a, a:visited {
color: blue;
text-decoration: none;
}
/* ERROR MESSAGES */
.info-message {
font-weight: bold;
}
.info-message--success {
color: green;
}
.info-message--failure {
color: red;
}
/* INPUT FIELDS */
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px white inset;
}
.label, .input-text, .select, .textarea {
font-size: medium;
padding: 0.3em;
outline: none;
border: 0px;
background-color: white;
}
.input-text--primary, .select--primary, .textarea--primary {
border-bottom: 1px solid blue;
}
.input-text--primary:focus, .select--primary:focus, .textarea--primary:focus {
border-bottom: 1px solid grey;
}
.input-checkbox, .input-textarea {
border: 1px solid grey;
}
/* BUTTONS */
button {
border: 1px solid black;
padding: 0.5em;
margin: 0.5em 0.3em 0.5em 0.3em;
color: black;
background-color: white;
}
button:hover {
border: 1px solid blue;
color: white;
background-color: blue;
}
button:active{
border: 1px solid blue;
color: white;
background-color: white;
}
/* TABLES */
table {
width: 100%;
text-align: left;
}
/* other */
.stop-float {
clear: both;
}
.toggle-link {
float: right;
}
.wrap-words {
word-wrap: break-word;
}

View file

@ -1,185 +0,0 @@
/* top bar */
#logo, #title {
float: left;
}
#logo {
height: 1.5em;
}
#title {
margin: 2px 5px 2px 5px;
}
.top-bar-left {
float: left;
}
.top-bar-tagline {
font-style: italic;
color: grey;
}
.top-bar-right {
margin-left: 0.5em;
}
/* publish */
#drop-zone {
border: 1px dashed lightgrey;
padding: 1em;
height: 13em;
background: #F5F0EF;
}
#asset-preview-holder {
width: 100%;
margin-bottom: 1em;
}
/* show routes */
.show-asset {
width: 100%;
margin-bottom: 1em;
margin-top: 1em;
}
.show-asset-lite {
margin: 0px;
}
.panel.links {
font-size: small;
}
input.link {
width: 80%;
}
button.copy-button {
padding: 4px;
float: right;
}
.share-option {
margin-bottom: 1em;
}
.metadata-table {
font-size: small;
border-collapse: collapse;
margin-bottom: 1em;
}
.metadata-row {
border-bottom: 1px solid lightgrey;
margin: 2px;
}
.left-column {
width: 30%;
font-weight: bold;
vertical-align: top;
}
/* trending claims */
.grid-item {
width: 23%;
margin: 0px 1% 20px 1%;
}
/* learn more */
.learn-more {
text-align: center;
border-top: 1px solid lightgrey;
}
/* examples */
.example {
clear: both;
width: 100%;
margin-bottom: 15px;
overflow: auto;
}
.example-image, .example-code {
float: left;
margin: 2%;
}
.example-image {
width: 21%;
}
.example-code {
float: right;
padding: 4%;
width: 62%;
background-color: lightgrey;
font-family: monospace;
color: #666;
word-wrap: break-word;
}
/* contribute */
#github-logo {
float: right;
height: 1em;
}
/* content lists */
.content-list-card {
margin-top: 2px;
padding-top: 2px;
border-top: 1px lightgrey solid;
overflow: auto;
position: relative;
}
.content-list-card-link {
position:absolute;
width:100%;
height:100%;
top:0;
left: 0;
z-index: 1;
}
.content-list-asset {
width: 20%;
float: left;
margin: 5px 30px 5px 0px;
}
.content-list-title {
color: black;
font-weight: bold;
}
.content-list-details {
word-wrap: break-word;
}
.content-list-details > ul {
position: relative;
z-index: 2;
list-style: none;
list-style-type: none;
}
.content-list-card:hover {
background-color: #F5F0EF;
}
/* statistics */
.totals-row {
border-top: 1px solid grey;
border-bottom: 1px solid grey;
font-weight: bold;
}
.stats-table-url {
word-wrap: break-word;
}

View file

@ -0,0 +1,516 @@
html, body {
margin: 0;
padding: 0;
height: 100%;
}
/* TEXT */
body, button, input, textarea, label, select, option {
font-family: monospace;
font-size: large;
word-wrap: break-word;
}
p {
padding-left: 0.3em;
}
.center-text {
text-align: center;
}
.url-text {
margin:0px;
padding:0px;
}
.url-text--primary {
color: black;
}
.url-text--secondary {
color: lightgrey;
}
.pull-quote {
font-size: 3rem;
}
/* TOOL TIPS */
/* Tooltip container */
.tooltip {
position: relative;
}
/* Tooltip text */
.tooltip > .tooltip-text {
visibility: hidden;
width: 15em;
background-color: dodgerblue;
color: #fff;
text-align: center;
padding: 0.5em;
/* Position the tooltip text */
position: absolute;
z-index: 1;
bottom: 110%;
left: 50%;
margin-left: -8em; /* Use half of the width (120/2 = 60), to center the tooltip */
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover > .tooltip-text {
visibility: visible;
}
/* arrow at bottom of tooltip text */
.tooltip > .tooltip-text::after {
content: " ";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: dodgerblue transparent transparent transparent;
}
/* LINKS */
a, a:visited {
text-decoration: none;
}
/* HEADERS */
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.5rem;
}
.h2--secondary {
font-weight: normal;
color: lightgrey;
}
.h2--top {
margin-top: 0px;
}
h3 {
font-size: 1rem;
font-weight: normal;
}
/* COLUMNS AND ROWS */
.row {
clear: both;
padding: 2rem 2rem 2rem 2rem;
margin: 0px;
}
.row--wide {
padding-right: 0px;
padding-left: 0px;
}
.row--short {
padding-top: 0px;
padding-bottom: 0px;
}
.row--full-height {
height: calc(100% - 9rem);
}
.column {
display: inline-block;
padding: 0px;
margin: 0px;
}
.column--1 {
width: 10%;
}
.column--2 {
width: 20%;
}
.column--3 {
width: 30%;
}
.column--4 {
width: 40%;
}
.column--5 {
width: 50%;
}
.column--6 {
width: 60%;
}
.column--7 {
width: 70%;
}
.column--8 {
width: 80%;
}
.column--9 {
width: 90%;
}
.column--10 {
width: 100%;
}
/* ALIGNMENT */
.align-content-left {
text-align: left;
}
.align-content-center {
text-align: center;
}
.align-content-right {
text-align: right;
}
.align-content-top {
vertical-align: top;
}
.align-content-right {
vertical-align: bottom;
}
/* ERROR MESSAGES */
.info-message {
font-weight: bold;
}
.info-message--success {
color: green;
}
.info-message--failure {
color: red;
}
/* INPUT FIELDS */
/* blocks */
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px white inset;
}
.label, .input-text, .select, .textarea {
margin: 0px;
padding: 0.3em;
outline: none;
border: 0px;
background-color: white;
}
.input-disabled {
border: 1px solid black;
padding: 0.5em;
margin: 0px;
color: black;
background-color: white;
}
option {
font-family: monospace;
}
.input-checkbox {
border: 1px solid grey;
background: white;
}
.input-file {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.input-file-label {
color: dodgerblue;
text-decoration: underline;
cursor: pointer;
}
.select--no-arrow {
-moz-appearance:none;
-webkit-appearance: none;
cursor: pointer;
}
.select--arrow {
-moz-appearance:none;
-webkit-appearance: none;
background: url('../img/down_triangle.png') no-repeat right;
padding-right: 1em;
}
/* modifiers */
.input-text--primary, .select--primary, .textarea--primary {
border-bottom: 1px solid dodgerblue;
}
.input-text--primary:focus, .select--primary:focus, .textarea--primary:focus {
border-bottom: 1px solid dodgerblue;
}
.input-text--large, .select--large, .textarea--large {
font-size: 1.5rem;
border-left: 1px solid dodgerblue;
}
.input-text--large:focus, .select--large:focus, .textarea--large:focus {
border-left: 1px solid dodgerblue;
}
.input-text--full-width, .textarea--full-width {
width: calc(100% - 0.6em);
}
.input-disabled--full-width {
width: calc(100% - 1em - 2px);
}
/* BUTTONS */
button {
cursor: pointer;
}
.button--primary {
border: 1px solid black;
padding: 0.5em;
margin: 0.5em 0.3em 0.5em 0.3em;
color: black;
background-color: white;
}
.button--primary:hover {
border: 1px solid dodgerblue;
color: white;
background-color: dodgerblue;
}
.button--primary:active{
border: 1px solid dodgerblue;
color: white;
background-color: white;
}
.button--large{
margin: 0px;
width: calc(100% - 2px);
padding: 2rem;
font-size: x-large;
}
.button--cancel{
border: 0px;
background-color: white;
color: grey;
}
/* TABLES */
table {
width: 100%;
text-align: left;
}
/* NAV BAR */
.nav-bar {
height: 5rem;
}
.nav-bar-title-section, .nav-bar-link-section {
padding: 0px 1em 0px 1em;
}
.nav-bar-title-section {
overflow: hidden;
border-bottom: 2px solid #eaeaea;
position: relative;
}
.nav-bar-link-section {
position: absolute;
bottom: 0px;
right: 0px;
z-index: 1;
}
.nav-bar-logo, .nav-bar-title, .nav-bar-link {
padding: 2rem 0.5rem 1.5rem 0.5rem;
display: inline-block;
color: black;
}
.nav-bar-title--superscript {
font-size: small;
vertical-align: top;
}
.nav-bar-link {
border-bottom: 2px solid white;
}
.nav-bar-link--active {
color: #1e90ff;
border-bottom: 2px solid #1e90ff;
}
/* PUBLISH FORM */
.dropzone {
border: 2px dashed lightgrey;
text-align: center;
}
.dropzone:hover {
border: 2px dashed #1e90ff;
}
#primary-dropzone-wrapper, #publish-form-wrapper {
height: 100%;
}
#primary-dropzone {
height: calc(100% - 4px);
position: relative;
}
#asset-preview-holder {
position: relative;
}
#primary-dropzone-instructions, #preview-dropzone-instructions {
position: absolute;
top: 40%;
left: 50%;
transform: translateX(-50%) translateY(-40%);
}
#asset-preview {
display: block;
padding: 0.5rem;
width: calc(100% - 1rem);
}
/* Show page */
.asset-display {
display: block;
width: 100%;
}
/* item lists */
.content-list-item {
}
.content-list-item-asset {
width: 90%;
}
.content-list-item-link {
}
/* other */
.toggle-link {
float: right;
}
.wrap-words {
word-wrap: break-word;
}
/* Social Sharing Icons */
.button {
margin-right: 10px;
max-width: 100px;
display: inline;
padding: 8px;
}
a.reddit-share.button img {
width: 38px;
height: 38px;}
.row--short img {
width: 40px;
height: 40px;
}
.row--short img:hover {
-webkit-animation: animation 20000ms linear both;
animation: animation 20000ms linear both;
}
@-webkit-keyframes animation {
0% { -webkit-transform: matrix3d(-0.5, -0.866, 0, 0, 0.866, -0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.5, -0.866, 0, 0, 0.866, -0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.16% { -webkit-transform: matrix3d(-0.493, -0.875, 0, 0, 0.769, -0.646, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.493, -0.875, 0, 0, 0.769, -0.646, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.32% { -webkit-transform: matrix3d(-0.546, -0.846, 0, 0, 0.699, -0.724, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.546, -0.846, 0, 0, 0.699, -0.724, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.64% { -webkit-transform: matrix3d(-0.703, -0.715, 0, 0, 0.603, -0.801, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.703, -0.715, 0, 0, 0.603, -0.801, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.95% { -webkit-transform: matrix3d(-0.836, -0.55, 0, 0, 0.509, -0.861, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.836, -0.55, 0, 0, 0.509, -0.861, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
1.26% { -webkit-transform: matrix3d(-0.924, -0.383, 0, 0, 0.384, -0.923, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.924, -0.383, 0, 0, 0.384, -0.923, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
1.57% { -webkit-transform: matrix3d(-0.974, -0.225, 0, 0, 0.236, -0.972, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.974, -0.225, 0, 0, 0.236, -0.972, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
2.82% { -webkit-transform: matrix3d(-0.919, 0.394, 0, 0, -0.394, -0.919, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.919, 0.394, 0, 0, -0.394, -0.919, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.07% { -webkit-transform: matrix3d(-0.538, 0.843, 0, 0, -0.843, -0.538, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.538, 0.843, 0, 0, -0.843, -0.538, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.3% { -webkit-transform: matrix3d(-0.447, 0.894, 0, 0, -0.894, -0.447, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.447, 0.894, 0, 0, -0.894, -0.447, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
5% { -webkit-transform: matrix3d(-0.161, 0.987, 0, 0, -0.987, -0.161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.161, 0.987, 0, 0, -0.987, -0.161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
8.61% { -webkit-transform: matrix3d(0.873, 0.487, 0, 0, -0.487, 0.873, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.873, 0.487, 0, 0, -0.487, 0.873, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
12.91% { -webkit-transform: matrix3d(0.976, -0.217, 0, 0, 0.217, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.976, -0.217, 0, 0, 0.217, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
17.22% { -webkit-transform: matrix3d(0.925, -0.381, 0, 0, 0.381, 0.925, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.925, -0.381, 0, 0, 0.381, 0.925, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
28.33% { -webkit-transform: matrix3d(0.996, -0.086, 0, 0, 0.086, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.996, -0.086, 0, 0, 0.086, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
39.44% { -webkit-transform: matrix3d(1, 0.026, 0, 0, -0.026, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0.026, 0, 0, -0.026, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
61.66% { -webkit-transform: matrix3d(1, -0.002, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, -0.002, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
83.98% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
}
@keyframes animation {
0% { -webkit-transform: matrix3d(-0.5, -0.866, 0, 0, 0.866, -0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.5, -0.866, 0, 0, 0.866, -0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.16% { -webkit-transform: matrix3d(-0.493, -0.875, 0, 0, 0.769, -0.646, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.493, -0.875, 0, 0, 0.769, -0.646, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.32% { -webkit-transform: matrix3d(-0.546, -0.846, 0, 0, 0.699, -0.724, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.546, -0.846, 0, 0, 0.699, -0.724, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.64% { -webkit-transform: matrix3d(-0.703, -0.715, 0, 0, 0.603, -0.801, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.703, -0.715, 0, 0, 0.603, -0.801, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
0.95% { -webkit-transform: matrix3d(-0.836, -0.55, 0, 0, 0.509, -0.861, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.836, -0.55, 0, 0, 0.509, -0.861, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
1.26% { -webkit-transform: matrix3d(-0.924, -0.383, 0, 0, 0.384, -0.923, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.924, -0.383, 0, 0, 0.384, -0.923, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
1.57% { -webkit-transform: matrix3d(-0.974, -0.225, 0, 0, 0.236, -0.972, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.974, -0.225, 0, 0, 0.236, -0.972, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
2.82% { -webkit-transform: matrix3d(-0.919, 0.394, 0, 0, -0.394, -0.919, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.919, 0.394, 0, 0, -0.394, -0.919, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.07% { -webkit-transform: matrix3d(-0.538, 0.843, 0, 0, -0.843, -0.538, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.538, 0.843, 0, 0, -0.843, -0.538, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
4.3% { -webkit-transform: matrix3d(-0.447, 0.894, 0, 0, -0.894, -0.447, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.447, 0.894, 0, 0, -0.894, -0.447, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
5% { -webkit-transform: matrix3d(-0.161, 0.987, 0, 0, -0.987, -0.161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(-0.161, 0.987, 0, 0, -0.987, -0.161, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
8.61% { -webkit-transform: matrix3d(0.873, 0.487, 0, 0, -0.487, 0.873, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.873, 0.487, 0, 0, -0.487, 0.873, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
12.91% { -webkit-transform: matrix3d(0.976, -0.217, 0, 0, 0.217, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.976, -0.217, 0, 0, 0.217, 0.976, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
17.22% { -webkit-transform: matrix3d(0.925, -0.381, 0, 0, 0.381, 0.925, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.925, -0.381, 0, 0, 0.381, 0.925, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
28.33% { -webkit-transform: matrix3d(0.996, -0.086, 0, 0, 0.086, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(0.996, -0.086, 0, 0, 0.086, 0.996, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
39.44% { -webkit-transform: matrix3d(1, 0.026, 0, 0, -0.026, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0.026, 0, 0, -0.026, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
61.66% { -webkit-transform: matrix3d(1, -0.002, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, -0.002, 0, 0, 0.002, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
83.98% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
100% { -webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
}

View file

@ -1,15 +1,5 @@
@media (max-width: 1250px) {
.wrapper {
margin-left: 10%;
width:80%;
}
}
@media (max-width: 1000px) { @media (max-width: 1000px) {
.wrapper {
margin-left: 10%;
width:80%;
}
.main { .main {
float: none; float: none;
@ -28,32 +18,50 @@
} }
@media (max-width: 750px ) { @media (max-width: 750px ) {
.col-left, .col-right {
float: none; .column--med-10 {
margin: 0px;
padding: 0px;
width: 100%; width: 100%;
} }
.col-right { .h2--top {
padding-top: 20px; margin-top: 1em;
}
.all-claims-asset {
width:30%;
}
.all-claims-details {
font-size: small;
}
.show-asset-lite {
width: 100%;
}
.top-bar-tagline {
clear: both;
text-align: left;
width: 100%;
} }
} }
@media (max-width: 475px) {
.nav-bar {
height: 8rem;
}
.nav-bar-title {
padding-bottom: 0px;
}
.nav-bar-link-section {
position: relative;
padding-left: 0px;
}
.row--full-height {
height: calc(100% - 11rem);
}
.column--sml-10 {
width: 100%;
}
#publish-active-area > .row, #details-detail > .row, #channel-login-form > .row, #publish-channel-form > .row {
padding: 1em 0px 1em 0px;
}
}
@media (max-width: 350px) {
body, button, input, textarea, label, select, option {
font-size: medium;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 B

After

Width:  |  Height:  |  Size: 195 B

View file

@ -6,10 +6,10 @@ function getRequest (url) {
xhttp.responseType = 'json'; xhttp.responseType = 'json';
xhttp.onreadystatechange = () => { xhttp.onreadystatechange = () => {
if (xhttp.readyState == 4 ) { if (xhttp.readyState == 4 ) {
console.log(xhttp);
if ( xhttp.status == 200) { if ( xhttp.status == 200) {
console.log('response:', xhttp.response);
resolve(xhttp.response); resolve(xhttp.response);
} else if (xhttp.status == 401) {
reject('wrong username or password');
} else { } else {
reject('request failed with status:' + xhttp.status); reject('request failed with status:' + xhttp.status);
}; };
@ -28,10 +28,10 @@ function postRequest (url, params) {
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.onreadystatechange = () => { xhttp.onreadystatechange = () => {
if (xhttp.readyState == 4 ) { if (xhttp.readyState == 4 ) {
console.log(xhttp);
if ( xhttp.status == 200) { if ( xhttp.status == 200) {
console.log('response:', xhttp.response);
resolve(xhttp.response); resolve(xhttp.response);
} else if (xhttp.status == 401) {
reject('wrong username or password');
} else { } else {
reject('request failed with status:' + xhttp.status); reject('request failed with status:' + xhttp.status);
}; };
@ -80,6 +80,31 @@ function createProgressBar(element, size){
setInterval(addOne, 300); setInterval(addOne, 300);
} }
function getCookie(cname) {
const name = cname + "=";
const decodedCookie = decodeURIComponent(document.cookie);
const ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function checkCookie() {
const channelName = getCookie("channel_name");
if (channelName != "") {
console.log(`cookie found for ${channelName}`);
} else {
console.log('no channel_name cookie found');
}
}
// Create new error objects, that prototypically inherit from the Error constructor // Create new error objects, that prototypically inherit from the Error constructor
function FileError(message) { function FileError(message) {
this.name = 'FileError'; this.name = 'FileError';

View file

@ -1,62 +1,43 @@
/* drop zone functions */
function drop_handler(ev) {
ev.preventDefault();
// if dropped items aren't files, reject them
var dt = ev.dataTransfer;
if (dt.items) {
if (dt.items[0].kind == 'file') {
var droppedFile = dt.items[0].getAsFile();
previewAndStageFile(droppedFile);
}
}
}
function dragover_handler(ev) {
ev.preventDefault();
}
function dragend_handler(ev) {
var dt = ev.dataTransfer;
if (dt.items) {
for (var i = 0; i < dt.items.length; i++) {
dt.items.remove(i);
}
} else {
ev.dataTransfer.clearData();
}
}
/* publish functions */ /* publish functions */
// update the publish status function cancelPublish () {
function updatePublishStatus(msg){ window.location.href = '/';
document.getElementById('publish-status').innerHTML = msg;
} }
// When a file is selected for publish, validate that file and // When a file is selected for publish, validate that file and
// stage it so it will be ready when the publish button is clicked. // stage it so it will be ready when the publish button is clicked.
function previewAndStageFile(selectedFile){ function previewAndStageFile(selectedFile){
var previewHolder = document.getElementById('asset-preview-holder'); const publishForm = document.getElementById('publish-form-wrapper');
var dropzone = document.getElementById('drop-zone'); const assetPreview = document.getElementById('asset-preview-target');
var previewReader = new FileReader(); const primaryDropzone = document.getElementById('primary-dropzone-wrapper');
var nameInput = document.getElementById('claim-name-input'); const previewReader = new FileReader();
const nameInput = document.getElementById('claim-name-input');
const fileSelectionError = document.getElementById('input-error-file-selection');
// validate the file's name, type, and size // validate the file's name, type, and size
try { try {
console.log('validating file');
validateFile(selectedFile); validateFile(selectedFile);
} catch (error) { } catch (error) {
showError('input-error-file-selection', error.message); console.log('file validation failed with error:', error);
showError(fileSelectionError, error.message);
return; return;
} }
// set the image preview, if an image was provided // set the image preview, if an image was provided
console.log('file type:', selectedFile.type)
if (selectedFile.type !== 'video/mp4') { if (selectedFile.type !== 'video/mp4') {
if (selectedFile.type === 'image/gif') {
assetPreview.innerHTML = `<h2>loading preview...</h2>`
}
previewReader.readAsDataURL(selectedFile); previewReader.readAsDataURL(selectedFile);
previewReader.onloadend = function () { previewReader.onloadend = function () {
dropzone.style.display = 'none'; assetPreview.innerHTML = '<img id="asset-preview" src="' + previewReader.result + '" alt="image preview"/>';
previewHolder.style.display = 'block';
previewHolder.innerHTML = '<img width="100%" src="' + previewReader.result + '" alt="image preview"/>';
}; };
} else {
assetPreview.innerHTML = `<img id="asset-preview" src="/assets/img/black_video_play.jpg"/>`
} }
// hide the drop zone
primaryDropzone.hidden = true;
publishForm.hidden = false;
// set the name input value to the image name if none is set yet // set the name input value to the image name if none is set yet
if (nameInput.value === "") { if (nameInput.value === "") {
var filename = selectedFile.name.substring(0, selectedFile.name.indexOf('.')) var filename = selectedFile.name.substring(0, selectedFile.name.indexOf('.'))
@ -68,11 +49,29 @@ function previewAndStageFile(selectedFile){
} }
// Validate the publish submission and then trigger publishing. // Validate the publish submission and then trigger publishing.
function publishSelectedImage(event) { function publishStagedFile(event) {
var claimName = document.getElementById('claim-name-input').value;
var channelName = document.getElementById('channel-name-select').value;
// prevent default so this script can handle submission // prevent default so this script can handle submission
event.preventDefault(); event.preventDefault();
// declare variables
const claimName = document.getElementById('claim-name-input').value;
let channelName = document.getElementById('channel-name-select').value;
const fileSelectionError = document.getElementById('input-error-file-selection');
const claimNameError = document.getElementById('input-error-claim-name');
const channelSelectError = document.getElementById('input-error-channel-select');
const publishSubmitError = document.getElementById('input-error-publish-submit');
let anonymousOrInChannel;
// replace channelName with 'anonymous' if needed
const radios = document.getElementsByName('anonymous-or-channel');
for (let i = 0; i < radios.length; i++) {
if (radios[i].checked) {
// do whatever you want with the checked radio
anonymousOrInChannel = radios[i].value;
// only one radio can be logically checked, don't check the rest
break;
}
}
if (anonymousOrInChannel === 'anonymous') {channelName = 'anonymous'};
console.log('channel name:', channelName);
// validate, submit, and handle response // validate, submit, and handle response
validateFilePublishSubmission(stagedFiles, claimName, channelName) validateFilePublishSubmission(stagedFiles, claimName, channelName)
.then(() => { .then(() => {
@ -80,14 +79,14 @@ function publishSelectedImage(event) {
}) })
.catch(error => { .catch(error => {
if (error.name === 'FileError') { if (error.name === 'FileError') {
showError(document.getElementById('input-error-file-selection'), error.message); showError(fileSelectionError, error.message);
} else if (error.name === 'NameError') { } else if (error.name === 'NameError') {
showError(document.getElementById('input-error-claim-name'), error.message); showError(claimNameError, error.message);
} else if (error.name === 'ChannelNameError'){ } else if (error.name === 'ChannelNameError'){
console.log(error); console.log(error);
showError(document.getElementById('input-error-channel-select'), error.message); showError(channelSelectError, error.message);
} else { } else {
showError(document.getElementById('input-error-publish-submit'), error.message); showError(publishSubmitError, error.message);
} }
return; return;
}) })

View file

@ -1,5 +1,3 @@
// validation function which checks the proposed file's type, size, and name // validation function which checks the proposed file's type, size, and name
function validateFile(file) { function validateFile(file) {
if (!file) { if (!file) {

View file

@ -9,7 +9,13 @@ module.exports = (app) => {
}); });
// route for log in // route for log in
app.post('/login', passport.authenticate('local-login'), (req, res) => { app.post('/login', passport.authenticate('local-login'), (req, res) => {
logger.debug(req.user);
logger.debug('successful login'); logger.debug('successful login');
res.status(200).json(true); res.status(200).json({
success : true,
channelName : req.user.channelName,
channelClaimId: req.user.channelClaimId,
shortChannelId: req.user.shortChannelId,
});
}); });
}; };

View file

@ -31,7 +31,7 @@ module.exports = (app) => {
getTrendingClaims(dateTime) getTrendingClaims(dateTime)
.then(result => { .then(result => {
// logger.debug(result); // logger.debug(result);
res.status(200).render('trending', { res.status(200).render('popular', {
trendingAssets: result, trendingAssets: result,
}); });
}) })

View file

@ -48,17 +48,17 @@ module.exports = (app, siofu, hostedContentPath) => {
// publish the file // publish the file
publish(publishParams, file.name, file.meta.type) publish(publishParams, file.name, file.meta.type)
.then(result => { .then(result => {
postToStats('PUBLISH', '/', null, null, null, 'success');
socket.emit('publish-complete', { name: publishParams.name, result }); socket.emit('publish-complete', { name: publishParams.name, result });
postToStats('PUBLISH', '/', null, null, null, 'success');
}) })
.catch(error => { .catch(error => {
error = errorHandlers.handlePublishError(error);
postToStats('PUBLISH', '/', null, null, null, error);
socket.emit('publish-failure', error); socket.emit('publish-failure', error);
logger.error('Publish Error:', useObjectPropertiesIfNoKeys(error));
postToStats('PUBLISH', '/', null, null, null, error);
}); });
} else { } else {
logger.error(`An error occurred in uploading the client's file`);
socket.emit('publish-failure', 'File uploaded, but with errors'); socket.emit('publish-failure', 'File uploaded, but with errors');
logger.error(`An error occurred in uploading the client's file`);
postToStats('PUBLISH', '/', null, null, null, 'File uploaded, but with errors'); postToStats('PUBLISH', '/', null, null, null, 'File uploaded, but with errors');
// to-do: remove the file, if not done automatically // to-do: remove the file, if not done automatically
} }

View file

@ -61,7 +61,7 @@ passport.deserializeUser((id, done) => { // this populates req.user
.then(shortChannelId => { .then(shortChannelId => {
userInfo['shortChannelId'] = shortChannelId; userInfo['shortChannelId'] = shortChannelId;
done(null, userInfo); done(null, userInfo);
return null; return null; // note: why return null and not the done?
}) })
.catch(error => { .catch(error => {
logger.error('sequelize error', error); logger.error('sequelize error', error);
@ -85,7 +85,7 @@ app.set('view engine', 'handlebars');
// middleware to pass user info back to client (for handlebars access), if user is logged in // middleware to pass user info back to client (for handlebars access), if user is logged in
app.use((req, res, next) => { app.use((req, res, next) => {
if (req.user) { if (req.user) {
logger.verbose(req.user); // logger.verbose(req.user);
res.locals.user = { res.locals.user = {
id : req.user.id, id : req.user.id,
userName : req.user.userName, userName : req.user.userName,

View file

@ -1,17 +1,31 @@
<div class="wrapper">
{{> topBar}} {{> topBar}}
<div class="main"> <div class="row row--full-height">
<h2>About Spee.ch</h2> <div class="column column--5 column--med-10 align-content-top">
<p>Spee.ch is a single-serving site that reads and publishes images to and from the <a class="white-text" href="https://lbry.io">LBRY</a> blockchain.</p> <div class="row row--short">
<p>Spee.ch is an image hosting service, but with the added benefit that it stores your images on a decentralized network of computers -- the LBRY network. This means that your images are stored in multiple locations without a single point of failure.</p> <span class="pull-quote">Open-source, decentralized image and video hosting</span>
{{> examples}}
{{> documentation}}
{{> bugs}}
</div> </div>
<div class="sidebar"> <div class="row">
{{> contribute}} <p>
<a href="#">GITHUB</a>
</p>
<p>
<a href="#">SLACK CHANNEL</a>
</p>
<p>
<a href="#">DOCUMENTATION</a>
</p>
</div> </div>
{{> footer}} </div><div class="column column--5 column--med-10 align-content-top">
</div> <div class="row row--short">
<p>Spee.ch is a media-hosting site that reads and publishes content from the <a class="white-text" href="https://lbry.io">LBRY</a> blockchain.</p>
<p>Spee.ch is a hosting service, but with the added benefit that it stores your content on a decentralized network of computers -- the LBRY network. This means that your images are stored in multiple locations without a single point of failure.</p>
<h3>[Contribute]</h3>
<p>Spee.ch is an open source project. Please contribute to the existing site, or fork it and make your own!</p>
<p>If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a href="https://github.com/lbryio/spee.ch">github repo</a> and go to town!</p>
<p>If you want to improve spee.ch, join our <a href="https://lbry.slack.com">slack channel</a> or solve one of our <a href="https://github.com/lbryio/spee.ch/issues">github issues</a>.</p>
</div>
</div>
</div>
<script src="/assets/js/generalFunctions.js"></script> <script src="/assets/js/generalFunctions.js"></script>

View file

@ -1,11 +1,8 @@
<div class="wrapper"> {{> topBar}}
{{> topBar}} <div class="row row--full-height">
<div> <h2>{{this.channelName}}<span class="h2--secondary">:{{this.longChannelId}}</span></h2>
<h3>{{this.channelName}}<span class="h3--secondary">:{{this.longChannelId}}</span></h3>
<p>Below is all the free content in this channel.</p> <p>Below is all the free content in this channel.</p>
{{#each this.claims}} {{#each this.claims}}
{{> contentListItem}} {{> contentListItem}}
{{/each}} {{/each}}
</div>
{{> footer}}
</div> </div>

View file

@ -1,7 +1,6 @@
<div class="wrapper">
{{> topBar}} {{> topBar}}
<div> <div>
<h3>404: Not Found</h3> <h3>404: Not Found</h3>
<p>That page does not exist. Return <a href="/">home</a>.</p> <p>That page does not exist. Return <a href="/">home</a>.</p>
</div> </div>
</div>

View file

@ -1,25 +1,111 @@
<script src="/assets/js/generalFunctions.js"></script> <script src="/assets/js/generalFunctions.js"></script>
<div class="row"> {{> topBar}}
<div class="column column--2"></div> <div class="row row--full-height">
<div class="column column--8"> <div id="primary-dropzone-wrapper">
{{> topBar}} <div id="primary-dropzone" class="dropzone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)">
{{> publishForm}} <div id="primary-dropzone-instructions">
{{> learnMore}} <div class="row">
{{> footer}} <p>Drag & drop image or video here</p>
<p>OR</p>
<form>
<label class="input-file-label" for="siofu_input">CHOOSE FILE</label>
<input class=" input-file" type="file" id="siofu_input" name="siofu_input" accept="video/*,image/*" onchange="previewAndStageFile(event.target.files[0])" enctype="multipart/form-data"/>
</form>
</div>
<div class="info-message info-message--failure" id="input-error-file-selection" hidden="true"></div>
</div>
</div>
</div>
<div id="publish-form-wrapper" hidden="true">
<div class="column column--10">
<!-- title input -->
<input type="text" id="publish-title" class="input-text input-text--large input-text--full-width" placeholder="Title (optional)">
</div>
<div class="column column--5 column--med-10 align-content-top" >
<!-- preview -->
<div class="row">
<div id="asset-preview-holder" class="dropzone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)" onmouseenter="showInstructions()" onmouseleave="hideInstructions()">
<div id="asset-preview-target"></div>
<div id="preview-dropzone-instructions" hidden="true">
<div class="row">
<p>Drag & drop image or video here</p>
<p>OR</p>
<form>
<label class="input-file-label" for="siofu_input">CHOOSE FILE</label>
<input class=" input-file" type="file" id="siofu_input" name="siofu_input" accept="video/*,image/*" onchange="previewAndStageFile(event.target.files[0])" enctype="multipart/form-data"/>
</form>
</div>
</div>
</div>
</div>
<!-- description input -->
<textarea rows="2" id="publish-description" class="textarea textarea--large textarea--full-width" placeholder="Description (optional)"></textarea>
</div><div class="column column--5 column--med-10 align-content-top">
<div id="publish-status" class="row" hidden="true"></div>
<div id="publish-progress-bar" class="row" hidden="true"></div>
<div id="publish-active-area">
{{> publishForm-Channel}}
{{> publishForm-Url}}
{{> publishForm-Details}}
{{> publishForm-Submit}}
</div>
</div> </div>
</div> </div>
<script src="/socket.io/socket.io.js"></script> <script src="/socket.io/socket.io.js"></script>
<script src="/siofu/client.js"></script> <script src="/siofu/client.js"></script>
<script src="/assets/js/validationFunctions.js"></script> <script src="/assets/js/validationFunctions.js"></script>
<script src="/assets/js/publishFileFunctions.js"></script> <script src="/assets/js/publishFileFunctions.js"></script>
<script typ="text/javascript"> <script typ="text/javascript">
// define variables
checkCookie();
var socket = io(); var socket = io();
var uploader = new SocketIOFileUpload(socket); var uploader = new SocketIOFileUpload(socket);
var stagedFiles = null; var stagedFiles = null;
/* drop zone functions */
function showInstructions () {
document.getElementById('preview-dropzone-instructions').hidden = false;
document.getElementById('asset-preview').style.opacity = 0.3;
}
function hideInstructions () {
document.getElementById('preview-dropzone-instructions').hidden = true;
document.getElementById('asset-preview').style.opacity = 1;
}
function drop_handler(event) {
event.preventDefault();
// if dropped items aren't files, reject them
var dt = event.dataTransfer;
if (dt.items) {
if (dt.items[0].kind == 'file') {
var droppedFile = dt.items[0].getAsFile();
previewAndStageFile(droppedFile);
}
}
}
function dragover_handler(event) {
event.preventDefault();
}
function dragend_handler(event) {
var dt = event.dataTransfer;
if (dt.items) {
for (var i = 0; i < dt.items.length; i++) {
dt.items.remove(i);
}
} else {
event.dataTransfer.clearData();
}
}
/* socketio-file-upload listeners */ /* socketio-file-upload listeners */
function updatePublishStatus(msg){
document.getElementById('publish-status').innerHTML = msg;
}
uploader.addEventListener('start', function(event){ uploader.addEventListener('start', function(event){
var name = document.getElementById('claim-name-input').value; var name = document.getElementById('claim-name-input').value;
var title = document.getElementById('publish-title').value; var title = document.getElementById('publish-title').value;
@ -34,10 +120,12 @@
event.file.meta.nsfw = nsfw; event.file.meta.nsfw = nsfw;
event.file.meta.type = stagedFiles[0].type; event.file.meta.type = stagedFiles[0].type;
event.file.meta.channel = channel; event.file.meta.channel = channel;
// re-set the html in the publish area // hide the submit area
document.getElementById('publish-active-area').innerHTML = '<div id="publish-status"></div><div id="progress-bar"></div>'; document.getElementById('publish-active-area').hidden = true;
// start a progress animation // show the progress status and animation
createProgressBar(document.getElementById('progress-bar'), 12); document.getElementById('publish-status').hidden = false;
document.getElementById('publish-progress-bar').hidden = false;
createProgressBar(document.getElementById('publish-progress-bar'), 12);
// google analytics // google analytics
ga('send', { ga('send', {
hitType: 'event', hitType: 'event',
@ -54,16 +142,15 @@
updatePublishStatus(msg); updatePublishStatus(msg);
}); });
socket.on('publish-failure', function(msg){ socket.on('publish-failure', function(msg){
document.getElementById('publish-active-area').innerHTML = '<p> --(✖╭╮✖)→ </p><p>' + JSON.stringify(msg) + '</p><strong>For help, post the above error text in the #speech channel on the <a href="https://lbry.slack.com/" target="_blank">lbry slack</a></strong>'; updatePublishStatus('<p> --(✖╭╮✖)→ </p><p>' + JSON.stringify(msg) + '</p><strong>For help, post the above error text in the #speech channel on the <a href="https://lbry.slack.com/" target="_blank">lbry slack</a></strong>');
document.getElementById('publish-progress-bar').hidden = true;
}); });
socket.on('publish-complete', function(msg){ socket.on('publish-complete', function(msg){
var publishResults;
var showUrl = msg.result.claim_id + "/" + msg.name; var showUrl = msg.result.claim_id + "/" + msg.name;
// build new publish area // update status
publishResults = '<p>Your publish is complete! You are being redirected to it now.</p>'; updatePublishStatus('<p>Your publish is complete! You are being redirected to it now.</p><p><a target="_blank" href="' + showUrl + '">If you do not get redirected, click here.</a></p>');
publishResults += '<p><a target="_blank" href="' + showUrl + '">If you do not get redirected, click here.</a></p>'; document.getElementById('publish-progress-bar').hidden = true;
// update publish area // redirect the user
document.getElementById('publish-active-area').innerHTML = publishResults;
window.location.href = showUrl; window.location.href = showUrl;
}); });
</script> </script>

View file

@ -6,8 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Spee.ch</title> <title>Spee.ch</title>
<link rel="stylesheet" href="/assets/css/reset.css" type="text/css"> <link rel="stylesheet" href="/assets/css/reset.css" type="text/css">
<link rel="stylesheet" href="/assets/css/BEM.css" type="text/css"> <link rel="stylesheet" href="/assets/css/general.css" type="text/css">
<link rel="stylesheet" href="/assets/css/componentStyle.css" type="text/css">
<link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css"> <link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css">
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@lbryio" /> <meta name="twitter:site" content="@lbryio" />

View file

@ -6,8 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Spee.ch</title> <title>Spee.ch</title>
<link rel="stylesheet" href="/assets/css/reset.css" type="text/css"> <link rel="stylesheet" href="/assets/css/reset.css" type="text/css">
<link rel="stylesheet" href="/assets/css/BEM.css" type="text/css"> <link rel="stylesheet" href="/assets/css/general.css" type="text/css">
<link rel="stylesheet" href="/assets/css/componentStyle.css" type="text/css">
<link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css"> <link rel="stylesheet" href="/assets/css/mediaQueries.css" type="text/css">
<meta property="fb:app_id" content="1371961932852223"> <meta property="fb:app_id" content="1371961932852223">
{{#unless fileInfo.nsfw}} {{#unless fileInfo.nsfw}}

View file

@ -1,21 +1,13 @@
<div class="wrapper"> {{> topBar}}
{{> topBar}}
<h2>Log In</h2>
<div class="row row--wide">
<div class="column column--6"> <div class="row row--full-height">
<div class="column column--5 column--med-10 align-content-top">
<p>Log in to an existing channel:</p> <p>Log in to an existing channel:</p>
{{>channelLoginForm}} {{>channelLoginForm}}
</div> </div><div class="column column--5 column--med-10 align-content-top">
</div>
<h2>Create New</h2>
<div class="row row--wide">
<div class="column column--6">
<p>Create a brand new channel:</p> <p>Create a brand new channel:</p>
{{>channelCreationForm}} {{>channelCreationForm}}
</div> </div>
</div>
{{> footer}}
</div> </div>
<script src="/assets/js/generalFunctions.js"></script> <script src="/assets/js/generalFunctions.js"></script>

View file

@ -1,4 +1,4 @@
<div class="wrapper">
{{> topBar}} {{> topBar}}
<div> <div>
<h2>New on Spee.ch</h2> <h2>New on Spee.ch</h2>
@ -22,5 +22,3 @@
</div> </div>
{{/each}} {{/each}}
</div> </div>
{{> footer}}
</div>

View file

@ -1,8 +1,7 @@
<div class="wrapper">
{{> topBar}} {{> topBar}}
<div> <div>
<h3>No Claims</h3> <h3>No Claims</h3>
<p>There are no free assets on this channel.</p> <p>There are no free assets on this channel.</p>
<p><i>If you think this message is an error, contact us in the <a href="https://lbry.slack.com/" target="_blank">LBRY slack!</a></i></p> <p><i>If you think this message is an error, contact us in the <a href="https://lbry.slack.com/" target="_blank">LBRY slack!</a></i></p>
</div> </div>
</div>

View file

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

View file

@ -1,23 +1,19 @@
<div class="row"> <a href="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">
<div id="asset-placeholder"> {{#ifConditional fileInfo.fileType '===' 'video/mp4'}}
<a href="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">
{{#ifConditional fileInfo.fileType '===' 'video/mp4'}}
{{#ifConditional fileInfo.fileExt '===' 'gifv'}} {{#ifConditional fileInfo.fileExt '===' 'gifv'}}
<video class="show-asset" autoplay loop muted> <video class="asset-display" autoplay loop muted>
<source src="/media/{{fileInfo.fileName}}"> <source src="/media/{{fileInfo.fileName}}">
{{!--fallback--}} {{!--fallback--}}
Your browser does not support the <code>video</code> element. Your browser does not support the <code>video</code> element.
</video> </video>
{{else}} {{else}}
<video class="show-asset" autoplay controls> <video class="asset-display" autoplay controls>
<source src="/media/{{fileInfo.fileName}}"> <source src="/media/{{fileInfo.fileName}}">
{{!--fallback--}} {{!--fallback--}}
Your browser does not support the <code>video</code> element. Your browser does not support the <code>video</code> element.
</video> </video>
{{/ifConditional}} {{/ifConditional}}
{{else}} {{else}}
<img class="show-asset" src="/media/{{fileInfo.fileName}}" /> <img class="asset-display" src="/media/{{fileInfo.fileName}}" />
{{/ifConditional}} {{/ifConditional}}
</a> </a>
</div>
</div>

View file

@ -1,55 +1,57 @@
<div class="panel"> <h2 class="h2--top">Title</h2>
<h2>Title</h2> <div class="row row--short">
<p>{{fileInfo.title}}</> {{fileInfo.title}}
</div> </div>
<div class="panel links"> <h2>Share via Social Media</h2>
<h2>Links</h2> <div class="row row--short">
{{!--short direct link to asset--}} <a class="twitter-share button" target="_blank" href="https://twitter.com/intent/tweet?text=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">
<div class="share-option"> <img src="https://i.imgur.com/Vt1XU5f.png" />
<a href="/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">Permanent Short Link</a> (most convenient) </a>
<a class="fb-share button" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fspee.ch%2F{{fileInfo.shortId}}%2F{{fileInfo.name}}.{{fileInfo.fileExt}}&amp;src=sdkpreparse">
<img src="https://i.imgur.com/SpOUrdt.png" />
</a>
<a class="tumblr-share button" target="_blank" href="https://www.tumblr.com/widgets/share/tool?posttype=photo&title=Spee.ch%20%7C%20Share&caption=Shared%20From%20https://spee.ch%20A%20Decentralized%20Image%20Hosting%20Service%20Running%20On%20The%20LBRY%20Protocol%20&content=https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}&tags=lbry%2C%20spee.ch%2C%20lbry.io&canonicalUrl=https%3A%2F%2Fspee.ch%2F{{fileInfo.shortId}}%2F{{fileInfo.name}}.{{fileInfo.fileExt}}&shareSource=tumblr_share_button">
<img src="https://i.imgur.com/0g1xcRd.png" />
</a>
<a class="reddit-share button" target="_blank" href="https://www.reddit.com/submit?url=http%3A%2F%2Fspee.ch%2F{{fileInfo.shortId}}%2F{{fileInfo.name}}.{{fileInfo.fileExt}}&title={{fileInfo.name}}(Decentralized%20Hosting%20Provided%20By%20Spee.ch%20Using%20the%20LBRY%20Protocol)">
<img src="https://i.imgur.com/I57laEJ.png" />
</a>
</div>
<h2>Links</h2>
{{!-- short direct link to asset --}}
<div class="row row--short">
<div class="column column--7">
<p><a href="/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">Short Link</a></p>
<div class="input-error" id="input-error-copy-short-link" hidden="true"></div> <div class="input-error" id="input-error-copy-short-link" hidden="true"></div>
<br/> <br/>
<input type="text" id="short-link" class="link" readonly spellcheck="false" value="https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}" onclick="select()"/> <input type="text" id="short-link" class="input-disabled input-text--full-width" readonly spellcheck="false" value="https://spee.ch/{{fileInfo.shortId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}" onclick="select()"/>
<button class="copy-button" data-elementtocopy="short-link" onclick="copyToClipboard(event)">copy</button> </div><div class="column column--1"></div><div class="column column--2">
<button class="button--primary" data-elementtocopy="short-link" onclick="copyToClipboard(event)">copy</button>
</div> </div>
{{!-- link to show route for asset--}} </div>
<div class="share-option"> {{!-- html text for embedding asset--}}
<a href="/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}">Permanent Long Link</a> (fastest service) <div class="row row--short">
<div class="input-error" id="input-error-copy-long-link" hidden="true"></div> <div class="column column--7">
</br> <p>Embed HTML</p>
<input type="text" id="long-link" class="link" readonly onclick="select()" spellcheck="false" value="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>
<button class="copy-button" data-elementtocopy="long-link" onclick="copyToClipboard(event)">copy</button>
</div>
{{!-- html text for embedding asset--}}
<div class="share-option">
Embed HTML
<div class="input-error" id="input-error-copy-embed-text" hidden="true"></div> <div class="input-error" id="input-error-copy-embed-text" hidden="true"></div>
<br/> <br/>
{{#ifConditional fileInfo.fileType '===' 'video/mp4'}} {{#ifConditional fileInfo.fileType '===' 'video/mp4'}}
<input type="text" id="embed-text" class="link" readonly onclick="select()" spellcheck="false" value='&lt;video width="100%" controls src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>&lt;/video>'/> <input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;video width="100%" controls src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>&lt;/video>'/>
{{else}} {{else}}
<input type="text" id="embed-text" class="link" readonly onclick="select()" spellcheck="false" value='&lt;img src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}" />'/> <input type="text" id="embed-text" class="input-disabled input-text--full-width" readonly onclick="select()" spellcheck="false" value='&lt;img src="https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}}"/>'/>
{{/ifConditional}} {{/ifConditional}}
<button class="copy-button" data-elementtocopy="embed-text" onclick="copyToClipboard(event)">copy</button> </div><div class="column column--1"></div><div class="column column--2">
<button class="button--primary" data-elementtocopy="embed-text" onclick="copyToClipboard(event)">copy</button>
</div> </div>
{{!--markdown text using asset--}}
{{#ifConditional fileInfo.fileType '===' 'video/mp4'}}
{{else}}
<div class="share-option">
Markdown
<div class="input-error" id="input-error-copy-markdown-text" hidden="true"></div>
<br/>
<input type="text" id="markdown-text" class="link" readonly onclick="select()" spellcheck="false" value='![{{fileInfo.name}}](https://spee.ch/{{fileInfo.claimId}}/{{fileInfo.name}}.{{fileInfo.fileExt}})'/>
<button class="copy-button" data-elementtocopy="markdown-text" onclick="copyToClipboard(event)">copy</button>
</div>
{{/ifConditional}}
</div> </div>
<div class="panel">
<h2>Description</h2> <h2>Description</h2>
<p>{{fileInfo.description}}</p> <div class="row row--short">
{{fileInfo.description}}
</div> </div>
<div class="panel">
<h2>Metadata</h2> <h2>Metadata</h2>
<div class="row row--short">
<table class="metadata-table" style="table-layout: fixed"> <table class="metadata-table" style="table-layout: fixed">
<tr class="metadata-row"> <tr class="metadata-row">
<td class="left-column">Name</td> <td class="left-column">Name</td>
@ -57,7 +59,7 @@
</tr> </tr>
<tr class="metadata-row"> <tr class="metadata-row">
<td class="left-column">Claim Id</td> <td class="left-column">Claim Id</td>
<td>{{fileInfo.claimId}}</td> <td class="wrap-words">{{fileInfo.claimId}}</td>
</tr> </tr>
<tr class="metadata-row"> <tr class="metadata-row">
<td class="left-column">File Name</td> <td class="left-column">File Name</td>
@ -74,3 +76,17 @@
</tr> </tr>
</table> </table>
</div> </div>
<script type ="text/javascript">
function copyToClipboard(event){
var elementToCopy = event.target.dataset.elementtocopy;
var element = document.getElementById(elementToCopy);
var errorElement = 'input-error-copy-text' + elementToCopy;
element.select();
try {
document.execCommand('copy');
} catch (err) {
showError(errorElement, 'Oops, unable to copy');
}
}
</script>

View file

@ -1,10 +1,9 @@
<form id="publish-channel-form"> <form id="publish-channel-form">
<div class="row row--wide row--short">
<div class="column column--3"> <div class="column column--3 column--sml-10">
<label class="label" for="new-channel-name">Name:</label> <label class="label" for="new-channel-name">Name:</label>
</div> </div><div class="column column--6 column--sml-10">
<div class="column column--9">
<div id="input-error-channel-name" class="info-message info-message--failure"></div> <div id="input-error-channel-name" class="info-message info-message--failure"></div>
<div class="input-text--primary"> <div class="input-text--primary">
<span>@</span> <span>@</span>
@ -12,17 +11,18 @@
<span id="input-success-channel-name" class="info-message info-message--success"></span> <span id="input-success-channel-name" class="info-message info-message--success"></span>
</div> </div>
</div> </div>
<div class="column column--3">
<label class="label" for="new-channel-password">Password:</label>
</div> </div>
<div class="column column--9"> <div class="row row--wide row--short">
<div class="column column--3 column--sml-10">
<label class="label" for="new-channel-password">Password:</label>
</div><div class="column column--6 column--sml-10">
<div id="input-error-channel-password" class="info-message info-message--failure"></div> <div id="input-error-channel-password" class="info-message info-message--failure"></div>
<input type="password" name="new-channel-password" id="new-channel-password" placeholder="" value="" class="input-text input-text--primary"> <input type="password" name="new-channel-password" id="new-channel-password" placeholder="" value="" class="input-text input-text--primary">
</div> </div>
</div>
<div class="row row--wide"> <div class="row row--wide">
<button onclick="publishNewChannel(event)">Create Channel</button> <button class="button--primary" onclick="publishNewChannel(event)">Create Channel</button>
</div> </div>
</form> </form>
@ -39,7 +39,7 @@
<script type="text/javascript"> <script type="text/javascript">
function publishNewChannel (event) { function publishNewChannel (event) {
const channelName = document.getElementById('new-channel-name').value; const userName = document.getElementById('new-channel-name').value;
const password = document.getElementById('new-channel-password').value; const password = document.getElementById('new-channel-password').value;
const channelNameErrorDisplayElement = document.getElementById('input-error-channel-name'); const channelNameErrorDisplayElement = document.getElementById('input-error-channel-name');
const passwordErrorDisplayElement = document.getElementById('input-error-channel-password'); const passwordErrorDisplayElement = document.getElementById('input-error-channel-password');
@ -50,13 +50,13 @@
// prevent default so this script can handle submission // prevent default so this script can handle submission
event.preventDefault(); event.preventDefault();
// validate submission // validate submission
validateNewChannelSubmission(channelName, password) validateNewChannelSubmission(userName, password)
.then(() => { .then(() => {
console.log('in progress'); console.log('in progress');
chanelCreateForm.hidden = true; chanelCreateForm.hidden = true;
inProgress.hidden = false; inProgress.hidden = false;
createProgressBar(document.getElementById('create-channel-progress-bar'), 12); createProgressBar(document.getElementById('create-channel-progress-bar'), 12);
return sendAuthRequest(channelName, password, '/signup') // post the request return sendAuthRequest(userName, password, '/signup') // post the request
}) })
.then(() => { .then(() => {
console.log('success'); console.log('success');

View file

@ -1,41 +1,65 @@
<form id="channel-login-form"> <form id="channel-login-form">
<div class="row row--wide row--short">
<div class="column column--3"> <div class="column column--3 column--sml-10">
<label class="label" for="login-channel-name">Name:</label> <label class="label" for="login-channel-name">Name:</label>
</div> </div><div class="column column--6 column--sml-10">
<div class="column column--9">
<div id="login-error-display-element" class="info-message info-message--failure"></div> <div id="login-error-display-element" class="info-message info-message--failure"></div>
<div class="input-text--primary"> <div class="input-text--primary">
<span>@</span> <span>@</span>
<input type="text" name="login-channel-name" id="login-channel-name" class="input-text" placeholder="" value=""> <input type="text" name="login-channel-name" id="login-channel-name" class="input-text" placeholder="" value="">
</div> </div>
</div> </div>
<div class="column column--3">
<label class="label" for="login-channel-password" >Password:</label>
</div> </div>
<div class="column column--9"> <div class="row row--wide row--short">
<div class="column column--3 column--sml-10">
<label class="label" for="login-channel-password" >Password:</label>
</div><div class="column column--6 column--sml-10">
<input type="password" name="login-channel-password" id="login-channel-password" class="input-text input-text--primary" placeholder="" value=""> <input type="password" name="login-channel-password" id="login-channel-password" class="input-text input-text--primary" placeholder="" value="">
</div> </div>
</div>
<div class="row row--wide">
<button class="button--primary" onclick="loginToChannel(event)">Authenticate</button>
</div>
</form> </form>
<div class="row row--wide">
<button onclick="loginToChannel(event)">Login</button>
</div>
<script type="text/javascript"> <script type="text/javascript">
function loginToChannel (event) { function loginToChannel (event) {
const channelName = document.getElementById('login-channel-name').value; const userName = document.getElementById('login-channel-name').value;
const password = document.getElementById('login-channel-password').value; const password = document.getElementById('login-channel-password').value;
const loginErrorDisplayElement = document.getElementById('login-error-display-element'); const loginErrorDisplayElement = document.getElementById('login-error-display-element');
// prevent default // prevent default
event.preventDefault() event.preventDefault()
// send request // send request
sendAuthRequest(channelName, password, '/login') sendAuthRequest(userName, password, '/login')
.then(() => { // update session cookie with new channel name and ids
console.log('login success'); .then(result => {
window.location.href = '/'; console.log('login success', result);
// replace the current cookies
document.cookie = `channel_name=${result.channelName}`;
document.cookie = `channel_claim_id=${result.channelClaimId}`;
document.cookie = `short_channel_id=${result.shortChannelId}`;
return result;
})
// update channel selection
.then(result => {
const channelSelect = document.getElementById('channel-name-select');
// remove the old channel option
const oldChannel = document.getElementById('channel-option')
if (oldChannel){
oldChannel.parentNode.removeChild(oldChannel);
}
// add new channel option & select it
const newChannelOption = document.createElement('option');
newChannelOption.setAttribute('value', result.channelName);
newChannelOption.setAttribute('id', 'channel-option');
newChannelOption.setAttribute('selected', '');
newChannelOption.innerText = result.channelName;
channelSelect.insertBefore(newChannelOption, channelSelect.firstChild);
// update selection
toggleSelectedChannel(result.channelName);
}) })
.catch(error => { .catch(error => {
showError(loginErrorDisplayElement, error); showError(loginErrorDisplayElement, error);

View file

@ -1,15 +1,14 @@
<div class='content-list-card'> <div class='row row--wide'>
<div class="column column--3 align-content-top">
<a href="{{this.showUrlLong}}"><span class='content-list-card-link'></span></a> <a href="{{this.showUrlLong}}"><span class='content-list-card-link'></span></a>
{{#ifConditional this.contentType '===' 'video/mp4'}} {{#ifConditional this.contentType '===' 'video/mp4'}}
<img class="content-list-asset" src="{{this.thumbnail}}"/> <img class="content-list-item-asset" src="{{this.thumbnail}}"/>
{{else}} {{else}}
<img class="content-list-asset" src="{{this.directUrlLong}}" /> <img class="content-list-item-asset" src="{{this.directUrlLong}}" />
{{/ifConditional}} {{/ifConditional}}
<div class="content-list-details"> </div><div class="column column--7 align-content-top">
<ul> <p>{{this.title}}</p>
<li class="content-list-title">{{this.title}}</li> <a href="{{this.directUrlShort}}">spee.ch{{this.directUrlShort}}</a>
<li><a href="{{this.directUrlShort}}">spee.ch{{this.directUrlShort}}</a></li>
</ul>
</div> </div>
</div> </div>

View file

@ -1,8 +0,0 @@
<div>
<h2>Contribute
<a href="https://github.com/lbryio/spee.ch" target="_blank"><img id="github-logo" src="/assets/img/GitHub-Mark-32px.png"/></a>
</h2>
<p><strong>Spee.ch is an open source project. Please contribute to the existing site, or fork it and make your own!</strong></p>
<p>If you have an idea for your own spee.ch-like site on top of LBRY, fork our <a href="https://github.com/lbryio/spee.ch">github repo</a> and go to town!</p>
<p>If you want to improve spee.ch, join our <a href="https://lbry.slack.com">slack channel</a> or solve one of our <a href="https://github.com/lbryio/spee.ch/issues">github issues</a>.</p>
</div>

View file

@ -1,36 +0,0 @@
<div class="panel">
<h2>Documentation
<a class="toggle-link" id="documentation-toggle" href="#" onclick="toggleSection(event)" data-open="false" data-openlabel="[ - ]" data-closedlabel="[ + ]" data-slaveelementid="documentation-detail">[ + ]</a>
</h2>
<div id="documentation-detail" hidden="true">
<code>https://spee.ch/</code>
<ul>
<li>Learn about Spee.ch and publish your own media</li>
</ul>
<code>https://spee.ch/:name.ext</code>
<ul>
<li >Serves the winning free, public claim at this name directly</li>
<li >E.g. <a href="/doitlive.png">spee.ch/doitlive.png</a></li>
</ul>
<code>https://spee.ch/:name</code>
<ul>
<li >Serves an HTML page which shows the winning claim at this name with additional details</li>
<li >E.g. <a href="/doitlive">spee.ch/doitlive</a></li>
</ul>
<code>https://spee.ch/:name/:claim_id.ext</code>
<ul>
<li >Serves a specific image or video file directly</li>
<li >E.g. <a href="/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0/doitlive.jpg">spee.ch/doitlive/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0.jpg</a></li>
</ul>
<code>https://spee.ch/:name/:claim_id</code>
<ul>
<li >Serves an HTML page with this specific claim and additional details</li>
<li >E.g. <a href="/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0/doitlive">spee.ch/doitlive/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0</a></li>
</ul>
<code>https://spee.ch/:name/all</code>
<ul>
<li >Displays a list of all files at a claim</li>
<li >E.g. <a href="/doitlive/all">spee.ch/doitlive/all</a></li>
</ul>
</div>
</div>

View file

@ -1,17 +0,0 @@
<div class="panel">
<h2>Examples
<a class="toggle-link" id="examples-toggle" href="#" onclick="toggleSection(event)" data-open="false" data-openlabel="[ - ]" data-closedlabel="[ + ]" data-slaveelementid="examples-detail">[ + ]</a>
</h2>
<div id="examples-detail" hidden="true">
<div class="example">
<h4>Use spee.ch to embed a specific image:</h4>
<a href="/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0/doitlive.jpg"><img class="example-image" src="/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0/doitlive.jpg"/></a>
<div class="example-code">&lt;img src="https://spee.ch/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0/doitlive.jpg"/&gt;</div>
</div>
<div class="example">
<h4>Use spee.ch to serve the top free image at a claim:</h4>
<a href="/doitlive.png"><img class="example-image" src="/doitlive.png"/></a>
<div class="example-code">&lt;img src="https://spee.ch/doitlive.png"/&gt;</div>
</div>
</div>
</div>

View file

@ -1,3 +0,0 @@
<footer class="row">
<p> thanks for visiting spee.ch </p>
</footer>

View file

@ -1,3 +0,0 @@
<div class="row learn-more">
<p><i>Spee.ch is an open-source project. You should <a href="https://github.com/lbryio/spee.ch/issues">contribute</a> on github, or <a href="https://github.com/lbryio/spee.ch">fork it</a> and make your own!</i></p>
</div>

View file

@ -1,66 +1,104 @@
<!-- select whether to publish anonymously or in a channel -->
<div class="row"> <div class="row">
<div class="column column--3"> <div class="column column--10">
<label class="label" for="channel-name-select">Channel:</label> <form>
<input type="radio" name="anonymous-or-channel" id="anonymous-select" class="" value="anonymous" {{#unless user}}checked {{/unless}} onchange="toggleChannel(event.target.value)"/>
<label class="label" for="anonymous-select">Anonymous</label>
<input type="radio" name="anonymous-or-channel" id="in-a-channel-select" class="" value="in a channel" {{#if user}}checked {{/if}} onchange="toggleChannel(event.target.value)"/>
<label class="label" for="in-a-channel-select">In a channel</label>
</form>
</div> </div>
<div class="column column--9"> </div>
<div id="channel-select-options" {{#unless user}}hidden="true"{{/unless}}>
<!-- select whether to create new or log in to existing channel -->
<div class="row">
<div class="column column--3 column--sml-10">
<label class="label" for="channel-name-select">Channel:</label>
</div><div class="column column--7 column--sml-10">
<div id="input-error-channel-select" class="info-message info-message--failure"></div> <div id="input-error-channel-select" class="info-message info-message--failure"></div>
<select type="text" id="channel-name-select" class="select select--primary" value="channel" onchange="toggleChannel(event)"> <select type="text" id="channel-name-select" class="select select--primary select--arrow" onchange="toggleSelectedChannel(event.target.selectedOptions[0].value)">
<optgroup>
{{#if user}} {{#if user}}
<option value="{{user.channelName}}" >@{{user.userName}}</option> <option value="{{user.channelName}}" id="channel-option">{{user.channelName}}</option>
{{/if}} {{/if}}
<option value="none" >None</option> <option value="login">Existing</option>
</optgroup>
<optgroup>
<option value="login">Login</option>
<option value="new" >New</option> <option value="new" >New</option>
</optgroup>
</select> </select>
</div> </div>
</div> </div>
<!-- log into an existing channel -->
<div id="channel-login-details" class="row" hidden="true"> <div id="channel-login-details" class="row row--short" {{#if user}}hidden="true"{{/if}}>
{{> channelLoginForm}} {{> channelLoginForm}}
</div> </div>
<!-- create a channel -->
<div id="channel-create-details" class="row" hidden="true"> <div id="channel-create-details" class="row row--short" hidden="true">
{{> channelCreationForm}} {{> channelCreationForm}}
</div>
</div> </div>
<script src="/assets/js/authFunctions.js"></script> <script src="/assets/js/authFunctions.js"></script>
<script type="text/javascript"> <script type="text/javascript">
function toggleChannel (event) { // show or hide the channel selection tools
function toggleChannel (selectedOption) {
const channelSelectOptions = document.getElementById('channel-select-options');
console.log('toggleChannel event triggered', selectedOption);
// show/hide the login and new channel forms
if (selectedOption === 'anonymous') {
channelSelectOptions.hidden = true;
channelSelectOptions.hidden = true;
// update url
updateUrl(selectedOption);
} else if (selectedOption === 'in a channel') {
channelSelectOptions.hidden = false;
// update url
let selectedChannel = document.getElementById('channel-name-select').selectedOptions[0].value
toggleSelectedChannel(selectedChannel);
} else {
console.log('selected option was not recognized');
}
}
// show or hide the channel create/login tool
function toggleSelectedChannel (selectedChannel) {
const createChannelTool = document.getElementById('channel-create-details'); const createChannelTool = document.getElementById('channel-create-details');
const loginToChannelTool = document.getElementById('channel-login-details'); const loginToChannelTool = document.getElementById('channel-login-details');
const selectedOption = event.target.selectedOptions[0].value; console.log('toggleSelectedChannel event triggered', selectedChannel);
const urlChannel = document.getElementById('url-channel');
console.log('toggle event triggered');
if (selectedOption === 'new') {
// show/hide the login and new channel forms // show/hide the login and new channel forms
if (selectedChannel === 'new') {
createChannelTool.hidden = false; createChannelTool.hidden = false;
loginToChannelTool.hidden = true; loginToChannelTool.hidden = true;
// update URL } else if (selectedChannel === 'login') {
urlChannel.innerText = '';
} else if (selectedOption === 'login') {
// show/hide the login and new channel forms
loginToChannelTool.hidden = false; loginToChannelTool.hidden = false;
createChannelTool.hidden = true; createChannelTool.hidden = true;
// update URL
urlChannel.innerText = '';
} else { } else {
// hide the login and new channel forms // hide the login and new channel forms
loginToChannelTool.hidden = true; loginToChannelTool.hidden = true;
createChannelTool.hidden = true; createChannelTool.hidden = true;
hideError(document.getElementById('input-error-channel-select')); hideError(document.getElementById('input-error-channel-select'));
// update URL
if (selectedOption === 'none'){
console.log('selected option: none');
urlChannel.innerText = '';
} else {
console.log('selected option:', selectedOption);
// retrieve short url from db
urlChannel.innerText = `{{user.channelName}}:{{user.shortChannelId}}/`;
} }
// update url
updateUrl(selectedChannel);
}
function updateUrl (selectedOption) {
const urlChannel = document.getElementById('url-channel');
const urlNoChannelPlaceholder = document.getElementById('url-no-channel-placeholder');
const urlChannelPlaceholder = document.getElementById('url-channel-placeholder');
if (selectedOption === 'new' || selectedOption === 'login' || selectedOption === ''){
urlChannel.hidden = true;
urlNoChannelPlaceholder.hidden = true;
urlChannelPlaceholder.hidden = false;
} else if (selectedOption === 'anonymous'){
urlChannel.hidden = true;
urlNoChannelPlaceholder.hidden = false;
urlChannelPlaceholder.hidden = true;
} else {
urlChannel.hidden = false;
// show channel and short id
const selectedChannel = getCookie('channel_name');
const shortChannelId = getCookie('short_channel_id');
urlChannel.innerText = `${selectedChannel}:${shortChannelId}`;
urlNoChannelPlaceholder.hidden = true;
urlChannelPlaceholder.hidden = true;
} }
} }
</script> </script>

View file

@ -1,28 +1,9 @@
<div id="details-detail" hidden="true"> <div id="details-detail" hidden="true">
<div class="row row--thin"> <div class="row row--short">
<div class="column column--3"> <div class="column column--3 column--sml-10">
<label for="publish-title" class="label">Title: </label> <label for="publish-license" class="label">License:</label>
</div> </div><div class="column column--7 column--sml-10">
<div class="column column--9">
<input type="text" id="publish-title" class="input-text input-text--primary">
</div>
</div>
<div class="row row--thin">
<div class="column column--3">
<label for="publish-description" class="label">Description: </label>
</div>
<div class="column column--9">
<textarea rows="2" id="publish-description" class="input-textarea"></textarea>
</div>
</div>
<div class="row row--thin">
<div class="column column--3">
<label for="publish-license" class="label">License:* </label>
</div>
<div class="column column--9">
<select type="text" id="publish-license" class="select select--primary"> <select type="text" id="publish-license" class="select select--primary">
<option value="Public Domain">Public Domain</option> <option value="Public Domain">Public Domain</option>
<option value="Creative Commons">Creative Commons</option> <option value="Creative Commons">Creative Commons</option>
@ -30,18 +11,17 @@
</div> </div>
</div> </div>
<div class="row row--thin"> <div class="row row--short">
<div class="column column--3"> <div class="column column--3 column--sml-10">
<label for="publish-nsfw" class="label">NSFW*</label> <label for="publish-nsfw" class="label">NSFW:</label>
</div> </div><div class="column column--7 column--sml-10">
<div class="column column--9">
<input class="input-checkbox" type="checkbox" id="publish-nsfw"> <input class="input-checkbox" type="checkbox" id="publish-nsfw">
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="column column--12"> <div class="column column--10">
<a class="label" id="details-toggle" href="#" onclick="toggleSection(event)" data-open="false" data-openlabel="[less]" data-closedlabel="[more]" data-slaveelementid="details-detail">[more]</a> <a class="label" id="details-toggle" href="#" onclick="toggleSection(event)" data-open="false" data-openlabel="[less]" data-closedlabel="[more]" data-slaveelementid="details-detail">[more]</a>
</div> </div>
</div> </div>

View file

@ -0,0 +1,11 @@
<div class="row">
<div class="input-error" id="input-error-publish-submit" hidden="true"></div>
<button id="publish-submit" class="button--primary button--large" onclick="publishStagedFile(event)">Upload</button>
</div>
<div class="row row--short align-content-center">
<button class="button--cancel" onclick="cancelPublish()">Cancel</button>
</div>
<script type="text/javascript" >
</script>

View file

@ -1,13 +1,18 @@
<div class="row"> <div class="row">
<div class="column column--3">
<div class="column column--3 column--sml-10">
<label class="label">URL:</label> <label class="label">URL:</label>
</div> </div><div class="column column--6 column--sml-10">
<div class="column column--9">
<div id="input-error-claim-name" class="info-message info-message--failure" hidden="true"></div> <div id="input-error-claim-name" class="info-message info-message--failure" hidden="true"></div>
<div class="input-text--primary"> <div class="input-text--primary">
<span class="url-text">Spee.ch/</span><span id="url-channel" class="url-text">{{#if user}}{{user.channelName}}:{{user.shortChannelId}}/{{/if}}</span><input type="text" id="claim-name-input" class="input-text" placeholder="your-url-here" oninput="checkClaimName(event.target.value)"> <span class="url-text">Spee.ch /</span>
<span id="url-channel" class="url-text url-text--primary" {{#if user}}{{else}}hidden="true"{{/if}}>{{user.channelName}}:{{user.shortChannelId}}</span>
<span id="url-no-channel-placeholder" class="url-text url-text--secondary tooltip" {{#if user}}hidden="true"{{else}}{{/if}}>xyz<span class="tooltip-text">This will be a random id</span></span>
<span id="url-channel-placeholder" class="url-text url-text--secondary tooltip" hidden="true">@channel<span class="tooltip-text">Select a channel above</span></span>
/
<input type="text" id="claim-name-input" class="input-text" placeholder="your-url-here" oninput="checkClaimName(event.target.value)">
<span id="input-success-claim-name" class="info-message info-message--success"></span> <span id="input-success-claim-name" class="info-message info-message--success"></span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,62 +0,0 @@
<div class="panel">
<h2>Publish</h2>
<div class="row">
<div class="col-left">
<div id="file-selection-area">
<div id="drop-zone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)">
<div class="row">
<p>Drag and drop your file here, or choose your file below.</p>
<div class="info-message info-message--failure" id="input-error-file-selection" hidden="true"></div>
</div>
<div class="row">
<input type="file" id="siofu_input" name="file" accept="video/*,image/*" onchange="previewAndStageFile(event.target.files[0])" enctype="multipart/form-data"/>
</div>
</div>
<div id="asset-preview-holder"></div>
</div>
</div>
<div class="col-right">
<div id="publish-active-area">
{{> publishForm-Channel}}
{{> publishForm-Url}}
{{> publishForm-Details}}
<div class="row">
<div class="input-error" id="input-error-publish-submit" hidden="true"></div>
<button id="publish-submit" onclick="publishSelectedImage(event)">Publish</button>
<button onclick="resetPublishArea()">Reset</button>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" >
function resetPublishArea (){
// reset file selection area
document.getElementById('file-selection-area').innerHTML = `<div id="drop-zone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)">
<p>Drag and drop your file here, or choose your file below.</p>
<div class="info-message info-message--failure" id="input-error-file-selection" hidden="true"></div>
<input type="file" id="siofu_input" name="file" accept="video/*,image/*" onchange="previewAndStageFile(event.target.files[0])" enctype="multipart/form-data"/>
</div>
<div id="asset-preview-holder"></div>`;
// reset inputs
document.getElementById('claim-name-input').value = '';
document.getElementById('publish-title').value = '';
document.getElementById('publish-description').value = '';
document.getElementById('publish-nsfw').checked = false;
// remove staged files
stagedFiles = null;
// clear any errors
document.getElementById('input-error-file-selection').innerHTML = '';
document.getElementById('input-error-claim-name').innerHTML = '';
document.getElementById('input-error-publish-submit').innerHTML = '';
document.getElementById('input-success-claim-name').hidden = true;
}
</script>

View file

@ -1,20 +1,23 @@
<div class="row top-bar"> <div class="row-wide nav-bar">
<a href="https://en.wikipedia.org/wiki/Freedom_of_information" target="_blank"><img id="logo" src="/assets/img/content-freedom-64px.png"/></a> <div class="nav-bar-title-section">
<h1 id="title"><a href="/">Spee.ch</a></h1><span class="top-bar-left">(beta)</span> <a href="/"><span class="nav-bar-title">spee&lt;h</span></a><span class="nav-bar-title nav-bar-title--superscript">(beta)</span>
<a href="/popular" class="top-bar-right">popular</a> <div class="nav-bar-link-section">
<a href="https://github.com/lbryio/spee.ch" target="_blank" class="top-bar-right">source</a> <a class="nav-bar-link" href="/">Upload</a>
<a href="/about" class="top-bar-right">help</a> <a class="nav-bar-link" href="/popular">Popular</a>
<a class="nav-bar-link" href="/about">About</a>
<!--{{#if user}}-->
<!--<select type="text" class="select select--no-arrow nav-bar-link" onchange="toggleLogin(event)">-->
<!--<option value="{{user.channelName}}:{{user.channelClaimId}}">@{{user.userName}}</option>-->
<!--<option value="view">View</option>-->
<!--<option value="logout">Logout</option>-->
<!--</select>-->
<!--{{else}}-->
<!--<a class="nav-bar-link" href="/login">Login</a>-->
<!--{{/if}}-->
</div>
</div>
{{#if user}}
<select type="text" class="select" onchange="toggleLogin(event)">
<option value="none">@{{user.userName}}</option>
<option value="view">view</option>
<option value="logout">logout</option>
</select>
{{else}}
<a href="/login" class="top-bar-right">login</a>
{{/if}}
<div class="top-bar-tagline">Open-source, decentralized image and video hosting.</div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
@ -22,11 +25,24 @@
console.log(event); console.log(event);
const selectedOption = event.target.selectedOptions[0].value; const selectedOption = event.target.selectedOptions[0].value;
if (selectedOption === 'logout') { if (selectedOption === 'logout') {
console.log('login'); console.log('log out');
// remove session cookies
// send logout request to server
window.location.href = '/logout'; window.location.href = '/logout';
} else if (selectedOption === 'view') { } else if (selectedOption === 'view') {
console.log('view channel'); console.log('view channel');
window.location.href = '/{{user.channelName}}:{{user.channelClaimId}}'; window.location.href = '/{{user.channelName}}:{{user.channelClaimId}}';
} }
} }
// highlight the link for the current page
const navBarLinks = document.getElementsByClassName('nav-bar-link');
for (let i = 0; i < navBarLinks.length; i++){
const link = navBarLinks[i];
if (link.href == window.location.href) {
link.setAttribute('class', 'nav-bar-link nav-bar-link--active');
} else if (`/${link.value}` === window.location.pathname) {
link.setAttribute('class', 'select select--no-arrow nav-bar-link nav-bar-link--active');
}
}
</script> </script>

View file

@ -1,5 +0,0 @@
<h2>What Is Spee.ch?</h2>
<h3>Spee.ch is for sharing</h3>
<p>Spee.ch is a platform by which you can publish images to the Lbry blockchain. Just upload an image, title it, and send it off into the lbry blockchain.</p>
<p>Spee.ch is also a platform to serve you those images. It's like have a personal chef that will serve you a meal anywhere in the world. All you have to do is ask for it, by using "spee.ch/" + the name of a claim.</p>
<p>If you want a specific image, just ask for it with the claim_id by using "spee.ch/" + the name of the claim + "/" + the claim id.</p>

7
views/popular.handlebars Normal file
View file

@ -0,0 +1,7 @@
{{> topBar}}
<div class="row">
{{#each trendingAssets}}
{{> contentListItem}}
{{/each}}
</div>

View file

@ -1,24 +1,11 @@
<div class="wrapper">
{{> topBar}} {{> topBar}}
<div class="main"> <div class="row">
<div class="column column--6 column--med-10 align-content-top">
{{> asset}} {{> asset}}
</div> </div><div class="column column--4 column--med-10 align-content-top">
<div class="sidebar"> <div class="row row--short">
{{> assetInfo}} {{> assetInfo}}
</div> </div>
{{> footer}} </div>
</div> </div>
<script type ="text/javascript">
function copyToClipboard(event){
var elementToCopy = event.target.dataset.elementtocopy;
var element = document.getElementById(elementToCopy);
var errorElement = 'input-error-copy-text' + elementToCopy;
element.select();
try {
document.execCommand('copy');
} catch (err) {
showError(errorElement, 'Oops, unable to copy');
}
}
</script>

View file

@ -1,4 +1,4 @@
<div class="wrapper">
<div class="top-bar"> <div class="top-bar">
{{> topBar}} {{> topBar}}
</div> </div>
@ -35,4 +35,3 @@
</table> </table>
</div> </div>
</div>

View file

@ -1,11 +0,0 @@
<div class="wrapper">
{{> topBar}}
<div>
<h3>Popular</h3>
<p>Below are the 25 most popular items on spee.ch</p>
{{#each trendingAssets}}
{{> contentListItem}}
{{/each}}
</div>
{{> footer}}
</div>