Second step of tour almost done
This commit is contained in:
parent
41dff8505a
commit
91c1954949
7 changed files with 154 additions and 73 deletions
|
@ -20,7 +20,7 @@
|
|||
"decamelize": "^2.0.0",
|
||||
"dedent": "^0.7.0",
|
||||
"dotenv": "^6.0.0",
|
||||
"fastify": "^1.8.0",
|
||||
"fastify": "^1.9.0",
|
||||
"fastify-compress": "^0.6.0",
|
||||
"fastify-helmet": "^1.0.3",
|
||||
"fastify-plugin": "^1.2.0",
|
||||
|
@ -41,8 +41,8 @@
|
|||
"slack-node": "^0.1.8",
|
||||
"socket.io": "^2.1.1",
|
||||
"stringify-object": "^3.2.2",
|
||||
"turbocolor": "^2.3.3",
|
||||
"ws": "^5.2.2"
|
||||
"turbocolor": "^2.4.1",
|
||||
"ws": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-env": "^1.7.0",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"sass": "^1.10.0",
|
||||
"snazzy": "^7.1.1",
|
||||
"standardx": "^2.1.0",
|
||||
"updates": "^4.0.0"
|
||||
"updates": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"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
|
@ -37,6 +37,8 @@
|
|||
}
|
||||
|
||||
.hook__navigation__step {
|
||||
background-color: transparent;
|
||||
|
||||
@media (min-width: 501px) {
|
||||
display: inline-block;
|
||||
|
||||
|
@ -69,6 +71,8 @@
|
|||
}
|
||||
|
||||
&:not(.active) {
|
||||
color: $white;
|
||||
|
||||
span {
|
||||
border-color: rgba($white, 0.1);
|
||||
}
|
||||
|
|
32
server.js
32
server.js
|
@ -77,7 +77,7 @@ fastify.ready(err => {
|
|||
if (err) throw err;
|
||||
|
||||
fastify.ws.on("connection", socket => {
|
||||
socket.send(JSON.stringify({
|
||||
socket.send(JSON.stringify({ // TODO: Remove this
|
||||
"message": "notification",
|
||||
"details": "Welcome"
|
||||
}));
|
||||
|
@ -89,8 +89,8 @@ fastify.ready(err => {
|
|||
case "landed on homepage":
|
||||
generateGitHubFeed(result => {
|
||||
socket.send(JSON.stringify({
|
||||
"message": "updated html",
|
||||
"html": result,
|
||||
"message": "updated html",
|
||||
"selector": "#github-feed"
|
||||
}));
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ fastify.ready(err => {
|
|||
break;
|
||||
|
||||
case "fetch metadata":
|
||||
fetchMetadata(data.claim, data.method, socket);
|
||||
fetchMetadata(data, socket);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -175,8 +175,16 @@ function generateGitHubFeed(displayGitHubFeed) {
|
|||
|
||||
|
||||
|
||||
function fetchMetadata(claimAddress, resolveMethod, socket) {
|
||||
if (!claimAddress || !resolveMethod) return;
|
||||
function uploadImage(imageSource, callback) {
|
||||
// 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 = [
|
||||
"fortnite-top-stream-moments-nickatnyte",
|
||||
|
@ -192,15 +200,15 @@ function fetchMetadata(claimAddress, resolveMethod, socket) {
|
|||
];
|
||||
|
||||
if (!allowedMethods.includes(resolveMethod)) return socket.send(JSON.stringify({
|
||||
"details": "Unallowed resolve method for tutorial",
|
||||
"message": "notification",
|
||||
"type": "error",
|
||||
"details": "Unallowed resolve method for tutorial"
|
||||
"type": "error"
|
||||
}));
|
||||
|
||||
if (!allowedClaims.includes(claimAddress)) return socket.send(JSON.stringify({
|
||||
"details": "Invalid claim ID for tutorial",
|
||||
"message": "notification",
|
||||
"type": "error",
|
||||
"details": "Invalid claim ID for tutorial"
|
||||
"type": "error"
|
||||
}));
|
||||
|
||||
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.method = resolveMethod;
|
||||
body.access_token = process.env.LBRY_DAEMON_ACCESS_TOKEN;
|
||||
body.method = resolveMethod;
|
||||
body.uri = claimAddress;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -236,13 +244,13 @@ function fetchMetadata(claimAddress, resolveMethod, socket) {
|
|||
}
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
"message": "updated html",
|
||||
"html": html`
|
||||
<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>
|
||||
<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>
|
||||
`,
|
||||
"message": "updated html",
|
||||
"selector": "#step1-result"
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -16,20 +16,20 @@ module.exports = exports = () => async () => html`
|
|||
<div class="hook" id="hook">
|
||||
<nav class="hook__navigation" id="hook-navigation">
|
||||
<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>
|
||||
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>
|
||||
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>
|
||||
Support with LBC
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
@ -70,8 +70,8 @@ function step1() {
|
|||
<p>Let's start by getting the associated metadata for a claim.</p>
|
||||
|
||||
<div class="hook__page__hero__claim">
|
||||
<span>lbry://</span><input id="fetch-claim-uri" type="text" placeholder=" Claim URI goes here"/>
|
||||
<button data-action="fetch metadata" class="button" title="Execute claim" type="button">Execute</button>
|
||||
<span>lbry://</span><input id="fetch-claim-uri" placeholder=" Claim URI goes here" type="text"/>
|
||||
<button class="button" data-action="execute claim" type="button">Execute</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -82,7 +82,7 @@ function step1() {
|
|||
<p style="text-align: center;">…or select a live example from below</p>
|
||||
|
||||
<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">
|
||||
<h4>It's a Disaster</h4>
|
||||
|
@ -91,7 +91,7 @@ function step1() {
|
|||
</div>
|
||||
|
||||
<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">
|
||||
<h4>Unbubbled with Jamie King, Ep1.1 — Bitcoin, Boom or Bust</h4>
|
||||
|
@ -100,7 +100,7 @@ function step1() {
|
|||
</div>
|
||||
|
||||
<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">
|
||||
<h4>FORTNITE TOP STREAM MOMENTS — Nickatnyte & GamingwithMolt</h4>
|
||||
|
@ -109,7 +109,7 @@ function step1() {
|
|||
</div>
|
||||
|
||||
<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">
|
||||
<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>
|
||||
<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:
|
||||
- isLoading appears
|
||||
- exampleCode and jsonData replace `#step2-placeholder` contents
|
||||
|
@ -154,16 +173,16 @@ function step2() {
|
|||
|
||||
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 = [];
|
||||
|
||||
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`
|
||||
<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">
|
||||
<div class="inner-wrap">
|
||||
<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>
|
||||
</header>
|
||||
|
||||
<div class="hook__page__content inner-wrap">
|
||||
<div class="hook__page__content__meme left">
|
||||
<img id="base-image" style="height: 0; visibility: hidden;" alt="Base image for LBRY meme creator"/>
|
||||
<canvas id="meme-canvas" width="400" height="300">Unfortunately, it looks like canvas is <strong>not supported</strong> in your browser</canvas>
|
||||
<img alt="Base image for LBRY meme creator" id="base-image" style="height: 0; visibility: hidden;"/>
|
||||
<canvas id="meme-canvas" height="300" width="400">Unfortunately, it looks like canvas is <strong>not supported</strong> in your browser</canvas>
|
||||
|
||||
${renderedImages}
|
||||
</div>
|
||||
|
||||
<form class="hook__page__content__meme right"> <!--/ v-on:submit.prevent="submit" /-->
|
||||
<form class="hook__page__content__meme right">
|
||||
<h2>Image Text</h2>
|
||||
|
||||
<fieldset>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<h2 class="__metadata">Metadata</h2>
|
||||
|
||||
<fieldset>
|
||||
<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>
|
||||
<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>
|
||||
<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="zh">Chinese (Mandarin)</option>
|
||||
<option value="en">English</option>
|
||||
|
@ -252,7 +271,7 @@ function step2() {
|
|||
|
||||
<fieldset>
|
||||
<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="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>
|
||||
|
@ -265,11 +284,11 @@ function step2() {
|
|||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<label><input type="checkbox" name="nsfw"/>NSFW</label>
|
||||
<label><input id="meme-nsfw-flag" name="nsfw" type="checkbox"/>NSFW</label>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<input type="submit" class="__button-black" value="Submit"/>
|
||||
<button data-action="upload image" class="__button-black" type="button">Submit</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -14,16 +14,16 @@ $("body").on("click", "[data-action]", event => {
|
|||
const data = event.currentTarget.dataset;
|
||||
|
||||
switch(data.action) {
|
||||
case "fetch metadata":
|
||||
if (!$("#fetch-claim-uri").val()) return;
|
||||
fetchMetadata($("#fetch-claim-uri").val());
|
||||
break;
|
||||
|
||||
case "choose claim":
|
||||
fetchMetadata(data.claimId);
|
||||
fetchMetadata(1, data.claimId);
|
||||
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:nth-child(1)").addClass("active");
|
||||
|
||||
|
@ -32,17 +32,17 @@ $("body").on("click", "[data-action]", event => {
|
|||
$("#step3-page").hide();
|
||||
break;
|
||||
|
||||
case "tour, step two":
|
||||
case "tour, step 2":
|
||||
$(".hook__navigation__step").removeClass("active");
|
||||
$(".hook__navigation__step:nth-child(2)").addClass("active");
|
||||
|
||||
$("#step1-page").hide();
|
||||
$("#step2-page").show();
|
||||
$(".hook__page__content__meme__thumbnail").click();
|
||||
$(".hook__page__content__meme__thumbnail").click(); // preload canvas
|
||||
$("#step3-page").hide();
|
||||
break;
|
||||
|
||||
case "tour, step three":
|
||||
case "tour, step 3":
|
||||
$(".hook__navigation__step").removeClass("active");
|
||||
$(".hook__navigation__step:nth-child(3)").addClass("active");
|
||||
|
||||
|
@ -51,6 +51,10 @@ $("body").on("click", "[data-action]", event => {
|
|||
$("#step3-page").show();
|
||||
break;
|
||||
|
||||
case "upload image":
|
||||
fetchMetadata(2, getMemeInfo());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -88,34 +92,80 @@ function detectLanguageAndUpdate() {
|
|||
) $("#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:
|
||||
[ ] Style code with highlightjs
|
||||
[✓] Add copy to explain that the lbry app has to be running in order to follow example
|
||||
- Style code with highlightjs
|
||||
*/
|
||||
|
||||
$("#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">
|
||||
# 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>
|
||||
|
||||
<div class="loader" id="temp-loader"></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) {
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
|
|
Loading…
Reference in a new issue