diff --git a/README.md b/README.md
index adb8b94..1d98944 100755
--- a/README.md
+++ b/README.md
@@ -22,6 +22,10 @@
- [lbry/web-daemon](https://github.com/lbryio/web-daemon)
- [Node](https://nodejs.org) (version >= 10)
+## Notes
+- **This repo will not run locally if you do not also have the LBRY app/daemon and the [web-daemon](https://github.com/lbryio/web-daemon) running.**
+- When running locally and completing the tipping example in Playground, the LBC donated to a creator comes from _your_ LBC balance. Otherwise, the example will fail. On production, the donated LBC comes from LBRY.
+
## Installation
`npm i`
diff --git a/app/components/client/tour-scripts.js b/app/components/client/tour-scripts.js
index e066cfd..7eb7fd3 100644
--- a/app/components/client/tour-scripts.js
+++ b/app/components/client/tour-scripts.js
@@ -13,30 +13,52 @@ if (window.location.href.search && window.location.href.split("?url=")[1]) { //
-$("body").on("click", "[data-action]", event => {
- event.preventDefault();
+document.querySelector("body").addEventListener("click", event => {
+ if (event.target.dataset.action) {
+ event.preventDefault();
+ document.querySelector(".tour").classList.add("waiting");
+ handleExamples(event.target);
+ }
- $(".tour").addClass("waiting");
+ if (
+ event.explicitOriginalTarget.classList &&
+ event.explicitOriginalTarget.classList[0] === "tour__content__meme__canvas__thumbnail"
+ ) {
+ for (const thumbnail of document.querySelectorAll(".tour__content__meme__canvas__thumbnail")) {
+ thumbnail.classList.remove("selected");
+ }
- setTimeout(() => {
- handleExamples(event);
- $(".tour").removeClass("waiting");
- }, 2500); // "rate-limit" to allow example divs time to populate
+ event.explicitOriginalTarget.classList.add("selected");
+ updateCanvas(event.explicitOriginalTarget);
+ }
});
-$("body").on("click", ".tour__content__meme__canvas__thumbnail", event => {
- $(".tour__content__meme__canvas__thumbnail").removeClass("selected");
-
- event.currentTarget.className += " selected";
- updateCanvas(event.currentTarget);
-});
-
-$("#fetch-claim-uri").on("keyup", event => {
+document.getElementById("fetch-claim-uri").addEventListener("keyup", event => {
const key = event.keyCode ? event.keyCode : event.which;
- if (key === 13 && $("#fetch-claim-uri").val()) fetchMetadata(1, $("#fetch-claim-uri").val());
+
+ switch(true) {
+ case (document.querySelector("[data-example='1']").classList.contains("active")):
+ if (
+ key === 13 &&
+ document.getElementById("fetch-claim-uri").value.length > 0
+ ) fetchMetadata(1, document.getElementById("fetch-claim-uri").value);
+ break;
+
+ case (document.querySelector("[data-example='3']").classList.contains("active")):
+ if (
+ key === 13 &&
+ document.getElementById("fetch-claim-uri").value.length > 0
+ ) fetchMetadata(3, document.getElementById("fetch-claim-uri").value);
+ break;
+ }
});
-$("body").on("keyup", "#meme-top-line, #meme-bottom-line", () => updateCanvas());
+document.querySelector("body").addEventListener("keyup", event => {
+ if (
+ event.target.id === "meme-top-line" ||
+ event.target.id === "meme-bottom-line"
+ ) updateCanvas();
+});
@@ -94,17 +116,18 @@ function debounce(func, wait, immediate) {
}
function initializeTour() {
- $(".tour").addClass("waiting");
- $("#fetch-claim-uri").val("").focus(); // reset
- $(".tour__sidebar__example:nth-child(1)").addClass("active");
+ document.querySelector(".tour").classList.add("waiting");
+ document.querySelector("#fetch-claim-uri").value = "";
+ document.querySelector("#fetch-claim-uri").focus();
+ document.querySelector(".tour__navigation__example:nth-child(1)").classList.add("active");
send(JSON.stringify({
"message": "landed on tour"
}));
setTimeout(() => {
- $(".tour").removeClass("waiting");
- }, 2500);
+ document.querySelector(".tour__navigation__example:nth-child(1)").click();
+ }, 300);
}
@@ -200,10 +223,10 @@ function getMemeInfo() { // TODO: Error handling
const handleExamples = debounce(event => {
let exampleNumber;
- const data = event.currentTarget.dataset;
+ const data = event.dataset;
- if (!parseInt($(".tour__sidebar__example.active")[0].dataset.example)) return;
- exampleNumber = parseInt($(".tour__sidebar__example.active")[0].dataset.example);
+ if (!parseInt($(".tour__navigation__example.active")[0].dataset.example)) return;
+ exampleNumber = parseInt($(".tour__navigation__example.active")[0].dataset.example);
switch(data.action) {
case "choose claim":
@@ -224,8 +247,8 @@ const handleExamples = debounce(event => {
$("#tour-url button").text("Resolve");
if ($("#tour-url")[0].style.display === "none") $("#tour-url").show();
- $(".tour__sidebar__example").removeClass("active");
- $(".tour__sidebar__example:nth-child(1)").addClass("active");
+ $(".tour__navigation__example").removeClass("active");
+ $(".tour__navigation__example:nth-child(1)").addClass("active");
$("#tour-loader").empty().show();
$("#tour-results").empty().show();
@@ -244,8 +267,8 @@ const handleExamples = debounce(event => {
$("#fetch-claim-uri").val(""); // reset URL bar
$("#tour-url").hide();
- $(".tour__sidebar__example").removeClass("active");
- $(".tour__sidebar__example:nth-child(2)").addClass("active");
+ $(".tour__navigation__example").removeClass("active");
+ $(".tour__navigation__example:nth-child(2)").addClass("active");
$("#tour-loader").empty().show();
$("#tour-results").empty().show();
@@ -266,8 +289,8 @@ const handleExamples = debounce(event => {
// $("#tour-url").after("
In the LBRY app, you can financially support your favorite creators by donating LBRY Coin (LBC). In this example, we are donating LBC in your stead.
");
if ($("#tour-url")[0].style.display === "none") $("#tour-url").show();
- $(".tour__sidebar__example").removeClass("active");
- $(".tour__sidebar__example:nth-child(3)").addClass("active");
+ $(".tour__navigation__example").removeClass("active");
+ $(".tour__navigation__example:nth-child(3)").addClass("active");
$("#tour-loader").empty().show();
$("#tour-results").empty().show();
diff --git a/app/components/head.js b/app/components/head.js
index 97c34d1..9695bb3 100644
--- a/app/components/head.js
+++ b/app/components/head.js
@@ -39,30 +39,29 @@ module.exports = exports = (state, emit) => {
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
-
-
+
-
-
`;
};
diff --git a/app/components/navigation.js b/app/components/navigation.js
index 00b505b..9de7ee9 100644
--- a/app/components/navigation.js
+++ b/app/components/navigation.js
@@ -30,9 +30,9 @@ export default class Navigation extends Nanocomponent {
url: "/overview"
},
{
- name: "Tour",
- title: "Take a Tour",
- url: "/tour"
+ name: "Playground",
+ title: "Experience LBRY",
+ url: "/playground"
},
{
name: "Resources",
diff --git a/app/components/playground.js b/app/components/playground.js
new file mode 100644
index 0000000..a0c5ad1
--- /dev/null
+++ b/app/components/playground.js
@@ -0,0 +1,82 @@
+"use strict";
+
+
+
+// P A C K A G E S
+
+import dedent from "dedent";
+import html from "choo/html";
+import raw from "choo/html/raw";
+
+
+
+// E X P O R T
+
+export default function () {
+ return dedent`
+
+
+ ${raw(navigation())}
+
+
+ ${raw(example1())}
+
+ `;
+}
+
+
+
+// H E L P E R S
+
+function example1() {
+ return html`
+
+ lbry://
+
+
+
+
+
+
+
+ `;
+}
+
+function navigation() { // TODO: Save tutorial position to localStorage
+ return dedent`
+
+
+ Get details of media (aka, "claim" metadata)
+
+
+
+
+ Create a meme and upload it to the LBRY blockchain
+
+
+
+
+ Support creators on LBRY with a tip, on us!
+
+ `;
+}
diff --git a/app/components/tour.js b/app/components/tour.js
deleted file mode 100644
index 5585ebd..0000000
--- a/app/components/tour.js
+++ /dev/null
@@ -1,62 +0,0 @@
-"use strict";
-
-
-
-// P A C K A G E S
-
-import dedent from "dedent";
-import html from "choo/html";
-import raw from "choo/html/raw";
-
-
-
-// E X P O R T
-
-export default function () {
- return dedent`
-
-
- ${raw(sidebar())}
-
- ${raw(example1())}
-
- `;
-}
-
-
-
-// H E L P E R S
-
-function example1() {
- return html`
-
- lbry://
-
-
-
-
-
- `;
-}
-
-function sidebar() { // TODO: Save tutorial position to localStorage
- return dedent`
-
-
- Get details of media (aka, "claim" metadata)
- In this example, you can see what runs under the hood when selecting content to view in the LBRY app.
-
-
-
-
- Create a meme and upload it to the LBRY blockchain
- Sometimes you want to create content, not just consume it. In this example, you can create a meme and upload it to LBRY!
-
-
-
-
- Support creators on LBRY with a tip, on us!
- In the LBRY app, you can financially support your favorite creators by donating LBRY Coin (LBC). In this example, we are donating LBC in your stead.
-
- `;
-}
diff --git a/app/dist/media/images/og-image.png b/app/dist/media/images/og-image.png
new file mode 100644
index 0000000..e9d3247
Binary files /dev/null and b/app/dist/media/images/og-image.png differ
diff --git a/app/dist/scripts/sockets.js b/app/dist/scripts/sockets.js
index adcebe9..f4b0e8d 100644
--- a/app/dist/scripts/sockets.js
+++ b/app/dist/scripts/sockets.js
@@ -1,34 +1,85 @@
-/* global $, log, ws */ "use strict";
+"use strict";
-// const log = console.log; // eslint-disable-line
+document.addEventListener("DOMContentLoaded", () => {
+ initializeWebSocketConnection();
+ setInterval(checkWebSocketConnection, 5000);
+});
-ws.onmessage = socket => {
- const data = JSON.parse(socket.data);
+let ws = null;
- switch (true) {
- case data.message === "updated html":
- $(data.selector).html(data.html);
- $("#emailMessage").val("");
- break;
+function checkWebSocketConnection() {
+ if (!ws || ws.readyState === 3) initializeWebSocketConnection();
+}
- case data.message === "notification": // TODO: Make work with appending so multiple notifications can be sent
- $("#flash-container").html(`
${data.details}
`);
+function initializeWebSocketConnection() {
+ ws = new WebSocket(location.origin.replace(/^http/, "ws"));
- setTimeout(() => {
- $("#flash-container").html("");
- }, 2100);
+ ws.onopen = () => {
+ console.log("WebSocket connection established"); // eslint-disable-line
+ };
- break;
+ ws.onmessage = socket => {
+ const data = JSON.parse(socket.data);
- default:
- log(data);
- break;
- }
-};
+ switch (true) {
+ case data.message === "updated html":
+ document.querySelector(data.selector).innerHTML = data.html;
+ document.getElementById("emailAddress").value = "";
+ document.getElementById("emailMessage").innerHTML = "";
+
+ // `data.example` is added when updating HTML.
+ // This is when the results of an example are sent to the client.
+ if (data.example) {
+ if (!document.querySelector(`[data-example="${data.example}"`).classList.contains("completed")) {
+ document.getElementById("tour-example-description").classList.remove("success");
+ }
+
+ document.querySelector(`[data-example="${data.example}"`).classList.add("completed");
+ document.getElementById("tour-example-description").classList.add("success");
+
+ document.getElementById("tour-example-description").innerHTML =
+ document.querySelector(`[data-example="${data.example}"`).dataset.success;
+ }
+
+ // If `data.example` isn't found, reset the description area.
+ else {
+ document.getElementById("tour-example-description").classList.remove("success");
+
+ document.getElementById("tour-example-description").innerHTML =
+ document.querySelector(".tour__navigation__example.active").dataset.description;
+ }
+
+ if (document.getElementById("temp-loader"))
+ document.getElementById("temp-loader").style.display = "none";
+
+ document.querySelector(".tour").classList.remove("waiting");
+ break;
+
+ case data.message === "notification": // TODO: Make work with appending so multiple notifications can be sent
+ document.getElementById("flash-container").innerHTML =
+ `
-
`),
"message": "updated html",
"selector": `#example${data.example}-result`
diff --git a/app/helpers/github.js b/app/helpers/github.js
index ab9e2dd..da4f721 100644
--- a/app/helpers/github.js
+++ b/app/helpers/github.js
@@ -2,6 +2,46 @@
+// P A C K A G E S
+
+const async = require("async");
+const color = require("colorette");
+const local = require("app-root-path").require;
+const octokit = require("@octokit/rest")();
+const redis = require("redis");
+
+// V A R I A B L E S
+
+const logSlackError = local("app/helpers/slack");
+const relativeDate = local("app/modules/relative-date");
+let client;
+
+// R E D I S
+
+if (typeof process.env.GITHUB_OAUTH_TOKEN !== "undefined") {
+ octokit.authenticate({
+ type: "oauth",
+ token: process.env.GITHUB_OAUTH_TOKEN
+ });
+} else process.stdout.write(`${color.red("[missing]")} GitHub token`);
+
+if (typeof process.env.REDISCLOUD_URL !== "undefined") {
+ client = redis.createClient(process.env.REDISCLOUD_URL);
+
+ client.on("error", redisError => {
+ process.env.NODE_ENV === "development" ?
+ process.stdout.write(`\n${color.yellow("Unable to connect to Redis client.")}\nYou may be missing an .env file or your connection was reset.`) :
+ logSlackError(
+ "\n" +
+ "> *REDIS ERROR:* ```" + JSON.parse(JSON.stringify(redisError)) + "```" + "\n" +
+ "> _Cause: Someone is trying to run LBRY.tech locally without environment variables OR Heroku is busted_\n"
+ )
+ ;
+ });
+} else process.stdout.write(`${color.red("[missing]")} Redis client URL`);
+
+
+
// P R O G R A M
function generateEvent(event) {
@@ -84,6 +124,44 @@ function generateEvent(event) {
}
}
+function generateGitHubFeed(displayGitHubFeed) {
+ if (typeof process.env.REDISCLOUD_URL !== "undefined") {
+ client.zrevrange("events", 0, 9, (err, reply) => {
+ if (err) return; // TODO: Render a div with nice error message
+
+ const events = [];
+ const renderedEvents = [];
+
+ reply.forEach(item => events.push(JSON.parse(item)));
+
+ for (const event of events) {
+ renderedEvents.push(`
+