Second step of tour almost done

This commit is contained in:
ポール ウェッブ 2018-07-24 17:29:25 -05:00
parent 41dff8505a
commit 91c1954949
7 changed files with 154 additions and 73 deletions

View file

@ -20,7 +20,7 @@
"decamelize": "^2.0.0", "decamelize": "^2.0.0",
"dedent": "^0.7.0", "dedent": "^0.7.0",
"dotenv": "^6.0.0", "dotenv": "^6.0.0",
"fastify": "^1.8.0", "fastify": "^1.9.0",
"fastify-compress": "^0.6.0", "fastify-compress": "^0.6.0",
"fastify-helmet": "^1.0.3", "fastify-helmet": "^1.0.3",
"fastify-plugin": "^1.2.0", "fastify-plugin": "^1.2.0",
@ -41,8 +41,8 @@
"slack-node": "^0.1.8", "slack-node": "^0.1.8",
"socket.io": "^2.1.1", "socket.io": "^2.1.1",
"stringify-object": "^3.2.2", "stringify-object": "^3.2.2",
"turbocolor": "^2.3.3", "turbocolor": "^2.4.1",
"ws": "^5.2.2" "ws": "^6.0.0"
}, },
"devDependencies": { "devDependencies": {
"babel-preset-env": "^1.7.0", "babel-preset-env": "^1.7.0",
@ -53,7 +53,7 @@
"sass": "^1.10.0", "sass": "^1.10.0",
"snazzy": "^7.1.1", "snazzy": "^7.1.1",
"standardx": "^2.1.0", "standardx": "^2.1.0",
"updates": "^4.0.0" "updates": "^4.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"request": "^2.87.0" "request": "^2.87.0"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -37,6 +37,8 @@
} }
.hook__navigation__step { .hook__navigation__step {
background-color: transparent;
@media (min-width: 501px) { @media (min-width: 501px) {
display: inline-block; display: inline-block;
@ -69,6 +71,8 @@
} }
&:not(.active) { &:not(.active) {
color: $white;
span { span {
border-color: rgba($white, 0.1); border-color: rgba($white, 0.1);
} }

View file

@ -77,7 +77,7 @@ fastify.ready(err => {
if (err) throw err; if (err) throw err;
fastify.ws.on("connection", socket => { fastify.ws.on("connection", socket => {
socket.send(JSON.stringify({ socket.send(JSON.stringify({ // TODO: Remove this
"message": "notification", "message": "notification",
"details": "Welcome" "details": "Welcome"
})); }));
@ -89,8 +89,8 @@ fastify.ready(err => {
case "landed on homepage": case "landed on homepage":
generateGitHubFeed(result => { generateGitHubFeed(result => {
socket.send(JSON.stringify({ socket.send(JSON.stringify({
"message": "updated html",
"html": result, "html": result,
"message": "updated html",
"selector": "#github-feed" "selector": "#github-feed"
})); }));
}); });
@ -98,7 +98,7 @@ fastify.ready(err => {
break; break;
case "fetch metadata": case "fetch metadata":
fetchMetadata(data.claim, data.method, socket); fetchMetadata(data, socket);
break; break;
default: default:
@ -175,8 +175,16 @@ function generateGitHubFeed(displayGitHubFeed) {
function fetchMetadata(claimAddress, resolveMethod, socket) { function uploadImage(imageSource, callback) {
if (!claimAddress || !resolveMethod) return; // return upload response
}
// TODO: Data parameter should include which step of tour is requesting metadata
function fetchMetadata(data, socket) {
if (data.step === 1 && !data.claim || !data.method) return;
const claimAddress = data.claim;
const resolveMethod = data.method;
const allowedClaims = [ const allowedClaims = [
"fortnite-top-stream-moments-nickatnyte", "fortnite-top-stream-moments-nickatnyte",
@ -192,15 +200,15 @@ function fetchMetadata(claimAddress, resolveMethod, socket) {
]; ];
if (!allowedMethods.includes(resolveMethod)) return socket.send(JSON.stringify({ if (!allowedMethods.includes(resolveMethod)) return socket.send(JSON.stringify({
"details": "Unallowed resolve method for tutorial",
"message": "notification", "message": "notification",
"type": "error", "type": "error"
"details": "Unallowed resolve method for tutorial"
})); }));
if (!allowedClaims.includes(claimAddress)) return socket.send(JSON.stringify({ if (!allowedClaims.includes(claimAddress)) return socket.send(JSON.stringify({
"details": "Invalid claim ID for tutorial",
"message": "notification", "message": "notification",
"type": "error", "type": "error"
"details": "Invalid claim ID for tutorial"
})); }));
const body = {}; const body = {};
@ -212,8 +220,8 @@ function fetchMetadata(claimAddress, resolveMethod, socket) {
// body.file_path = process.env.LBRY_DAEMON_IMAGES_PATH + body.file_path; // TODO: needed for step 2, check for `file_path` // body.file_path = process.env.LBRY_DAEMON_IMAGES_PATH + body.file_path; // TODO: needed for step 2, check for `file_path`
} }
body.method = resolveMethod;
body.access_token = process.env.LBRY_DAEMON_ACCESS_TOKEN; body.access_token = process.env.LBRY_DAEMON_ACCESS_TOKEN;
body.method = resolveMethod;
body.uri = claimAddress; body.uri = claimAddress;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -236,13 +244,13 @@ function fetchMetadata(claimAddress, resolveMethod, socket) {
} }
socket.send(JSON.stringify({ socket.send(JSON.stringify({
"message": "updated html",
"html": html` "html": html`
<p style="text-align: center;">Success! Here is the response for <strong>lbry://${claimAddress}</strong>:</p> <p style="text-align: center;">Success! Here is the response for <strong>lbry://${claimAddress}</strong>:</p>
<pre><code class="json">${stringifyObject(body, { indent: " ", singleQuotes: false })}</code></pre> <pre><code class="json">${stringifyObject(body, { indent: " ", singleQuotes: false })}</code></pre>
<button data-action="tour, step two" class="__button-black" type="button">Go to next step</button> <button class="__button-black" data-action="tour, step 2" type="button">Go to next step</button>
<script>$('#temp-loader').remove();</script> <script>$('#temp-loader').remove();</script>
`, `,
"message": "updated html",
"selector": "#step1-result" "selector": "#step1-result"
})); }));
}); });

View file

@ -16,20 +16,20 @@ module.exports = exports = () => async () => html`
<div class="hook" id="hook"> <div class="hook" id="hook">
<nav class="hook__navigation" id="hook-navigation"> <nav class="hook__navigation" id="hook-navigation">
<div class="inner-wrap"> <!--/ TODO: Save tutorial position to localStorage /--> <div class="inner-wrap"> <!--/ TODO: Save tutorial position to localStorage /-->
<a href="#" class="hook__navigation__step" data-action="tour, step one"> <button class="hook__navigation__step" data-action="tour, step 1" type="button">
<span class="number">1</span> <span class="number">1</span>
Resolve a claim Resolve a claim
</a> </button>
<a href="#" class="hook__navigation__step" data-action="tour, step two"> <button class="hook__navigation__step" data-action="tour, step 2" type="button">
<span class="number">2</span> <span class="number">2</span>
Publish content Publish content
</a> </button>
<a href="#" class="hook__navigation__step" data-action="tour, step three"> <button class="hook__navigation__step" data-action="tour, step 3" type="button">
<span class="number">3</span> <span class="number">3</span>
Support with LBC Support with LBC
</a> </button>
</div> </div>
</nav> </nav>
@ -70,8 +70,8 @@ function step1() {
<p>Let's start by getting the associated metadata for a claim.</p> <p>Let's start by getting the associated metadata for a claim.</p>
<div class="hook__page__hero__claim"> <div class="hook__page__hero__claim">
<span>lbry://</span><input id="fetch-claim-uri" type="text" placeholder="&thinsp;Claim URI goes here"/> <span>lbry://</span><input id="fetch-claim-uri" placeholder="&thinsp;Claim URI goes here" type="text"/>
<button data-action="fetch metadata" class="button" title="Execute claim" type="button">Execute</button> <button class="button" data-action="execute claim" type="button">Execute</button>
</div> </div>
</div> </div>
</header> </header>
@ -82,7 +82,7 @@ function step1() {
<p style="text-align: center;">&hellip;or select a live example from below</p> <p style="text-align: center;">&hellip;or select a live example from below</p>
<div class="hook__page__content__card"> <div class="hook__page__content__card">
<img src="https://spee.ch/0654f2e2322ccfefa02a956d252df9ac7611d8b0/placeholder-itsadisaster.jpeg" data-action="choose claim" data-claim-id="itsadisaster"> <img data-action="choose claim" data-claim-id="itsadisaster" src="https://spee.ch/0654f2e2322ccfefa02a956d252df9ac7611d8b0/placeholder-itsadisaster.jpeg">
<div data-action="choose claim" data-claim-id="itsadisaster"> <div data-action="choose claim" data-claim-id="itsadisaster">
<h4>It's a Disaster</h4> <h4>It's a Disaster</h4>
@ -91,7 +91,7 @@ function step1() {
</div> </div>
<div class="hook__page__content__card"> <div class="hook__page__content__card">
<img src="https://spee.ch/b1bd330e048fc22dc7bf941c33dd8245eef492c1/unbubbled.png" data-action="choose claim" data-claim-id="unbubbled1-1"> <img data-action="choose claim" data-claim-id="unbubbled1-1" src="https://spee.ch/b1bd330e048fc22dc7bf941c33dd8245eef492c1/unbubbled.png">
<div data-action="choose claim" data-claim-id="unbubbled1-1"> <div data-action="choose claim" data-claim-id="unbubbled1-1">
<h4>Unbubbled with Jamie King, Ep1.1 &mdash; Bitcoin, Boom or Bust</h4> <h4>Unbubbled with Jamie King, Ep1.1 &mdash; Bitcoin, Boom or Bust</h4>
@ -100,7 +100,7 @@ function step1() {
</div> </div>
<div class="hook__page__content__card"> <div class="hook__page__content__card">
<img src="https://spee.ch/9880947df41af880bc19724ceddd1cce957a07e2/placeholder-fortninte.jpeg" data-action="choose claim" data-claim-id="fortnite-top-stream-moments-nickatnyte"> <img data-action="choose claim" data-claim-id="fortnite-top-stream-moments-nickatnyte" src="https://spee.ch/9880947df41af880bc19724ceddd1cce957a07e2/placeholder-fortninte.jpeg">
<div data-action="choose claim" data-claim-id="fortnite-top-stream-moments-nickatnyte"> <div data-action="choose claim" data-claim-id="fortnite-top-stream-moments-nickatnyte">
<h4>FORTNITE TOP STREAM MOMENTS &mdash; Nickatnyte &amp; GamingwithMolt</h4> <h4>FORTNITE TOP STREAM MOMENTS &mdash; Nickatnyte &amp; GamingwithMolt</h4>
@ -109,7 +109,7 @@ function step1() {
</div> </div>
<div class="hook__page__content__card"> <div class="hook__page__content__card">
<img src="https://spee.ch/a3b8258478ad88954f42f6ac3427eab380720f60/placeholder-lbrymine.png" data-action="choose claim" data-claim-id="six"> <img data-action="choose claim" data-claim-id="six" src="https://spee.ch/a3b8258478ad88954f42f6ac3427eab380720f60/placeholder-lbrymine.png">
<div data-action="choose claim" data-claim-id="six"> <div data-action="choose claim" data-claim-id="six">
<h4>LBRY Coin (LBC) GPU Miner for AMD and NVIDIA</h4> <h4>LBRY Coin (LBC) GPU Miner for AMD and NVIDIA</h4>
@ -140,6 +140,25 @@ function step2() {
<p style="text-align: center;">Here is the raw response:</p> <p style="text-align: center;">Here is the raw response:</p>
<pre><code class="json"><span v-html="highlight('json', jsonData)"></span></code></pre> <pre><code class="json"><span v-html="highlight('json', jsonData)"></span></code></pre>
Meme submission process:
- `PUT` request to `http://daemon.lbry.tech/images.php`:
- headers: "Content-Type": "text/plain"
- qs: access_token: process.env.LBRY_DAEMON_ACCESS_TOKEN
- body: document.getElementById("meme-canvas").toDataURL("image/jpeg", 0.6)
- response should be parsed as JSON
- //
- socket emit "fetch metadata":
- bid: 0.001, // hard-coded on the back-end
- description: component.description,
- file_path: uploadResponse.body.filename,
- language: component.language,
- license: component.license,
- method: "publish",
- name: component.title,
- nsfw: component.nsfw,
- title: component.title
- socket emit error from back-end if any field is missing
Process after submitting meme: Process after submitting meme:
- isLoading appears - isLoading appears
- exampleCode and jsonData replace `#step2-placeholder` contents - exampleCode and jsonData replace `#step2-placeholder` contents
@ -154,16 +173,16 @@ function step2() {
const images = [ const images = [
{ {
src: "/assets/media/images/carlsagan2.jpg", alt: "Carl Sagan",
alt: "Carl Sagan" src: "/assets/media/images/carlsagan2.jpg"
}, },
{ {
src: "/assets/media/images/doge-meme.jpg", alt: "Doge",
alt: "Doge" src: "/assets/media/images/doge-meme.jpg"
}, },
{ {
src: "/assets/media/images/lbry-green.png", alt: "LBRY Logo With Green Background",
alt: "LBRY Logo With Green Background" src: "/assets/media/images/lbry-green.png"
} }
]; ];
@ -189,54 +208,54 @@ function step2() {
const renderedImages = []; const renderedImages = [];
for (const image of images) { for (const image of images) {
renderedImages.push(`<img src="${image.src}" class="hook__page__content__meme__thumbnail" alt="${image.alt}"/>`); renderedImages.push(`<img alt="${image.alt}" class="hook__page__content__meme__thumbnail" src="${image.src}"/>`);
} }
return html` return html`
<section class="hook__page" id="step2-page" style="display: none;"> <!--/ v-images-loaded="imagesLoaded" /--> <section class="hook__page" id="step2-page" style="display: none;">
<header class="hook__page__hero"> <header class="hook__page__hero">
<div class="inner-wrap"> <div class="inner-wrap">
<h1>Publish your content on the blockchain</h1> <h1>Publish your content on the blockchain</h1>
<p>Upload an image to the blockchain and you are able to view it on the <a href="http://explorer.lbry.io" title="LBRY Blockchain Explorer" target="_blank" rel="noopener noreferrer">LBRY Blockchain Explorer</a>.</p> <p>Upload an image to the blockchain and you are able to view it on the <a href="http://explorer.lbry.io" rel="noopener noreferrer" target="_blank" title="LBRY Blockchain Explorer">LBRY Blockchain Explorer</a>.</p>
</div> </div>
</header> </header>
<div class="hook__page__content inner-wrap"> <div class="hook__page__content inner-wrap">
<div class="hook__page__content__meme left"> <div class="hook__page__content__meme left">
<img id="base-image" style="height: 0; visibility: hidden;" alt="Base image for LBRY meme creator"/> <img alt="Base image for LBRY meme creator" id="base-image" style="height: 0; visibility: hidden;"/>
<canvas id="meme-canvas" width="400" height="300">Unfortunately, it looks like canvas is <strong>not supported</strong> in your browser</canvas> <canvas id="meme-canvas" height="300" width="400">Unfortunately, it looks like canvas is <strong>not supported</strong> in your browser</canvas>
${renderedImages} ${renderedImages}
</div> </div>
<form class="hook__page__content__meme right"> <!--/ v-on:submit.prevent="submit" /--> <form class="hook__page__content__meme right">
<h2>Image Text</h2> <h2>Image Text</h2>
<fieldset> <fieldset>
<label for="meme-top-line">Top line</label> <label for="meme-top-line">Top line</label>
<input name="meme-top-line" id="meme-top-line" type="text" placeholder="${memePlaceholderData.topLine.placeholder}" spellcheck="false" value="${memePlaceholderData.topLine.value}" required/> <input id="meme-top-line" name="meme-top-line" placeholder="${memePlaceholderData.topLine.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.topLine.value}" required/>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label for="meme-bottom-line">Bottom line</label> <label for="meme-bottom-line">Bottom line</label>
<input name="meme-bottom-line" id="meme-bottom-line" type="text" placeholder="${memePlaceholderData.bottomLine.placeholder}" spellcheck="false" value="${memePlaceholderData.bottomLine.value}" required/> <input id="meme-bottom-line" name="meme-bottom-line" placeholder="${memePlaceholderData.bottomLine.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.bottomLine.value}" required/>
</fieldset> </fieldset>
<h2 class="__metadata">Metadata</h2> <h2 class="__metadata">Metadata</h2>
<fieldset> <fieldset>
<label for="meme-title">Title</label> <label for="meme-title">Title</label>
<input name="meme-title" id="meme-title" type="text" placeholder="${memePlaceholderData.title.placeholder}" spellcheck="false" value="${memePlaceholderData.title.value}" required/> <input id="meme-title" name="meme-title" placeholder="${memePlaceholderData.title.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.title.value}" required/>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label for="meme-description">Description</label> <label for="meme-description">Description</label>
<textarea name="meme-description" id="meme-description" type="text" placeholder="${memePlaceholderData.description.placeholder}" spellcheck="false" required>${memePlaceholderData.description.value}</textarea> <textarea id="meme-description" name="meme-description" placeholder="${memePlaceholderData.description.placeholder}" spellcheck="false" type="text" required>${memePlaceholderData.description.value}</textarea>
</fieldset> </fieldset>
<fieldset> <fieldset>
<label for="meme-language">Language</label> <label for="meme-language">Language</label>
<select name="meme-language" id="meme-language"> <select id="meme-language" name="meme-language">
<option value="ar">Arabic</option> <option value="ar">Arabic</option>
<option value="zh">Chinese (Mandarin)</option> <option value="zh">Chinese (Mandarin)</option>
<option value="en">English</option> <option value="en">English</option>
@ -252,7 +271,7 @@ function step2() {
<fieldset> <fieldset>
<label for="meme-license">License</label> <label for="meme-license">License</label>
<select name="meme-license" id="meme-license" required> <select id="meme-license" name="meme-license" required>
<option value="Public Domain">Public Domain</option> <option value="Public Domain">Public Domain</option>
<option value="Creative Commons Attribution 4.0 International">Creative Commons Attribution 4.0 International</option> <option value="Creative Commons Attribution 4.0 International">Creative Commons Attribution 4.0 International</option>
<option value="Creative Commons Attribution-ShareAlike 4.0 International">Creative Commons Attribution-ShareAlike 4.0 International</option> <option value="Creative Commons Attribution-ShareAlike 4.0 International">Creative Commons Attribution-ShareAlike 4.0 International</option>
@ -265,11 +284,11 @@ function step2() {
</fieldset> </fieldset>
<fieldset> <fieldset>
<label><input type="checkbox" name="nsfw"/>NSFW</label> <label><input id="meme-nsfw-flag" name="nsfw" type="checkbox"/>NSFW</label>
</fieldset> </fieldset>
<fieldset> <fieldset>
<input type="submit" class="__button-black" value="Submit"/> <button data-action="upload image" class="__button-black" type="button">Submit</button>
</fieldset> </fieldset>
</form> </form>
</div> </div>

View file

@ -14,16 +14,16 @@ $("body").on("click", "[data-action]", event => {
const data = event.currentTarget.dataset; const data = event.currentTarget.dataset;
switch(data.action) { switch(data.action) {
case "fetch metadata":
if (!$("#fetch-claim-uri").val()) return;
fetchMetadata($("#fetch-claim-uri").val());
break;
case "choose claim": case "choose claim":
fetchMetadata(data.claimId); fetchMetadata(1, data.claimId);
break; break;
case "tour, step one": case "execute claim":
if (!$("#fetch-claim-uri").val()) return;
fetchMetadata(1, $("#fetch-claim-uri").val());
break;
case "tour, step 1":
$(".hook__navigation__step").removeClass("active"); $(".hook__navigation__step").removeClass("active");
$(".hook__navigation__step:nth-child(1)").addClass("active"); $(".hook__navigation__step:nth-child(1)").addClass("active");
@ -32,17 +32,17 @@ $("body").on("click", "[data-action]", event => {
$("#step3-page").hide(); $("#step3-page").hide();
break; break;
case "tour, step two": case "tour, step 2":
$(".hook__navigation__step").removeClass("active"); $(".hook__navigation__step").removeClass("active");
$(".hook__navigation__step:nth-child(2)").addClass("active"); $(".hook__navigation__step:nth-child(2)").addClass("active");
$("#step1-page").hide(); $("#step1-page").hide();
$("#step2-page").show(); $("#step2-page").show();
$(".hook__page__content__meme__thumbnail").click(); $(".hook__page__content__meme__thumbnail").click(); // preload canvas
$("#step3-page").hide(); $("#step3-page").hide();
break; break;
case "tour, step three": case "tour, step 3":
$(".hook__navigation__step").removeClass("active"); $(".hook__navigation__step").removeClass("active");
$(".hook__navigation__step:nth-child(3)").addClass("active"); $(".hook__navigation__step:nth-child(3)").addClass("active");
@ -51,6 +51,10 @@ $("body").on("click", "[data-action]", event => {
$("#step3-page").show(); $("#step3-page").show();
break; break;
case "upload image":
fetchMetadata(2, getMemeInfo());
break;
default: default:
break; break;
} }
@ -88,34 +92,80 @@ function detectLanguageAndUpdate() {
) $("#meme-language").children(`option[value="${compare(memeLocales, userLocales)[0]}"]`).attr("selected", true); ) $("#meme-language").children(`option[value="${compare(memeLocales, userLocales)[0]}"]`).attr("selected", true);
} }
function fetchMetadata(metadataId) {
send(JSON.stringify({
"claim": metadataId,
"message": "fetch metadata",
"method": "resolve"
}));
if (!$("#fetch-claim-uri").val()) $("#fetch-claim-uri").val(metadataId);
function fetchMetadata(stepNumber, data) {
/** /**
TODO: TODO:
[ ] Style code with highlightjs - Style code with highlightjs
[] Add copy to explain that the lbry app has to be running in order to follow example
*/ */
$("#step1-placeholder").html(` console.log(typeof data);
if (!stepNumber) return;
switch(stepNumber) {
case 1:
send(JSON.stringify({
"claim": data,
"message": "fetch metadata",
"method": "resolve",
"step": stepNumber
}));
if (!$("#fetch-claim-uri").val()) $("#fetch-claim-uri").val(data);
$("#step1-placeholder").html(`
<pre><code class="bash"> <pre><code class="bash">
# The LBRY app must be running on your computer for this example to work # The LBRY app must be running on your computer for this example to work
curl "http://localhost:5279" --data "{ 'method': 'resolve', 'params': { 'uri': '${metadataId}' } }" curl "http://localhost:5279" --data "{ 'method': 'resolve', 'params': { 'uri': '${data}' } }"
</code></pre> </code></pre>
<div class="loader" id="temp-loader"></div> <div class="loader" id="temp-loader"></div>
<div id="step1-result"></div> <div id="step1-result"></div>
`); `);
$("#step1-selections").hide(); $("#step1-selections").hide();
break;
case 2:
console.log(stepNumber, data);
break;
default:
break;
}
} }
function getMemeInfo() {
/*
- description: component.description,
- file_path: uploadResponse.body.filename,
- language: component.language,
- license: component.license,
- name: component.title,
- nsfw: component.nsfw,
- title: component.title
// Set on back-end
- bid: 0.001,
- method: "publish"
*/
const info = {};
info.description = $("#meme-description").val();
info.file_path = $("#meme-canvas")[0].toDataURL("image/jpeg", 0.6);
info.language = $("#meme-language").val();
info.license = $("#meme-license").val();
info.name = $("#meme-title").val();
info.nsfw = $("#meme-nsfw-flag").val();
info.title = $("#meme-title").val();
return info;
}
function clearCanvas(canvas) { function clearCanvas(canvas) {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");