new build setup for web/electron
This commit is contained in:
parent
7ea2a1dade
commit
de3639f29c
440 changed files with 5859 additions and 3991 deletions
9
.babelrc
Normal file
9
.babelrc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"presets": ["@babel/react", "@babel/flow"],
|
||||||
|
"plugins": [
|
||||||
|
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
|
||||||
|
"@babel/plugin-transform-flow-strip-types",
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
"babel-plugin-add-module-exports"
|
||||||
|
]
|
||||||
|
}
|
|
@ -6,13 +6,6 @@
|
||||||
"plugin:flowtype/recommended",
|
"plugin:flowtype/recommended",
|
||||||
"plugin:prettier/recommended"
|
"plugin:prettier/recommended"
|
||||||
],
|
],
|
||||||
"settings": {
|
|
||||||
"import/resolver": {
|
|
||||||
"webpack": {
|
|
||||||
"config": "webpack.renderer.additions.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
|
@ -20,7 +13,7 @@
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"__static": true,
|
"__static": true,
|
||||||
"staticResourcesPath": true,
|
"i18n": true,
|
||||||
"__": true,
|
"__": true,
|
||||||
"__n": true,
|
"__n": true,
|
||||||
"app": true
|
"app": true
|
||||||
|
@ -59,6 +52,7 @@
|
||||||
"no-empty": 0,
|
"no-empty": 0,
|
||||||
"react/prefer-stateless-function": 0,
|
"react/prefer-stateless-function": 0,
|
||||||
"react/sort-comp": 0,
|
"react/sort-comp": 0,
|
||||||
"jsx-a11y/media-has-caption": 0
|
"jsx-a11y/media-has-caption": 0,
|
||||||
|
"no-underscore-dangle": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,7 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/node_modules
|
/node_modules
|
||||||
/dist
|
/dist
|
||||||
/static/daemon/lbrynet*
|
/static/lbrynet
|
||||||
/static/locales
|
/static/locales
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
|
@ -89,8 +89,4 @@ const downloadDaemon = targetPlatform =>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = downloadDaemon;
|
downloadDaemon();
|
||||||
|
|
||||||
require('make-runnable/custom')({
|
|
||||||
printOutputFrame: false,
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
const extract = require("i18n-extract");
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
const outputDir = `${__dirname}/../static/locales`;
|
|
||||||
const outputPath = `${outputDir}/en.json`;
|
|
||||||
|
|
||||||
if (!fs.existsSync(outputDir)) {
|
|
||||||
fs.mkdirSync(outputDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFile(outputPath, "{}", "utf8", err => {
|
|
||||||
if (err) {
|
|
||||||
return console.log(err);
|
|
||||||
}
|
|
||||||
const enLocale = require(outputPath);
|
|
||||||
|
|
||||||
const keys = extract.extractFromFiles("src/**/*.{js,jsx}", {
|
|
||||||
marker: "__",
|
|
||||||
});
|
|
||||||
|
|
||||||
let reports = [];
|
|
||||||
reports = reports.concat(extract.findMissing(enLocale, keys));
|
|
||||||
|
|
||||||
if (reports.length > 0) {
|
|
||||||
fs.readFile(outputPath, "utf8", (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
} else {
|
|
||||||
localeObj = JSON.parse(data);
|
|
||||||
|
|
||||||
for (let i = 0; i < reports.length; i++) {
|
|
||||||
// no need to care for other types than MISSING because starting file will always be empty
|
|
||||||
if (reports[i].type === "MISSING") {
|
|
||||||
localeObj[reports[i].key] = reports[i].key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = JSON.stringify(localeObj, null, "\t"); // convert it back to json-string
|
|
||||||
fs.writeFile(outputPath, json, "utf8", err => {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
console.log("Extracted all strings!");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,6 +1,9 @@
|
||||||
{
|
{
|
||||||
"appId": "io.lbry.LBRY",
|
"appId": "io.lbry.LBRY",
|
||||||
"productName": "LBRY",
|
"productName": "LBRY",
|
||||||
|
"directories": {
|
||||||
|
"output": "dist/electron"
|
||||||
|
},
|
||||||
"publish": [
|
"publish": [
|
||||||
{
|
{
|
||||||
"provider": "s3",
|
"provider": "s3",
|
||||||
|
@ -44,6 +47,7 @@
|
||||||
],
|
],
|
||||||
"linux": {
|
"linux": {
|
||||||
"target": "deb",
|
"target": "deb",
|
||||||
|
"executableName": "LBRY",
|
||||||
"category": "AudioVideo;Video",
|
"category": "AudioVideo;Video",
|
||||||
"desktop": {
|
"desktop": {
|
||||||
"MimeType": "x-scheme-handler/lbry",
|
"MimeType": "x-scheme-handler/lbry",
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"renderer": {
|
|
||||||
"webpackConfig": "webpack.renderer.additions.js"
|
|
||||||
}
|
|
||||||
}
|
|
63
package.json
63
package.json
|
@ -18,16 +18,15 @@
|
||||||
"name": "LBRY Inc.",
|
"name": "LBRY Inc.",
|
||||||
"email": "hello@lbry.io"
|
"email": "hello@lbry.io"
|
||||||
},
|
},
|
||||||
"main": "src/main/index.js",
|
"main": "./dist/main/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"extract-langs": "node build/extractLocals.js",
|
"compile:electron": "webpack --progress --config webpack.electron.config.js",
|
||||||
"compile": "electron-webpack && yarn extract-langs",
|
"compile:web": "webpack --progress --config webpack.web.config.js",
|
||||||
|
"compile": "yarn compile:electron && yarn compile:web",
|
||||||
"build": "yarn compile && electron-builder build",
|
"build": "yarn compile && electron-builder build",
|
||||||
"build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null",
|
"build:dir": "yarn build -- --dir -c.compression=store -c.mac.identity=null",
|
||||||
"build:web": "webpack",
|
"dev:electron": "yarn compile:electron && electron ./dist/electron/main/bundle.js",
|
||||||
"dev": "electron-webpack dev",
|
"dev:internal-apis": "LBRY_API_URL='http://localhost:8080' yarn dev:electron",
|
||||||
"dev:internal-apis": "LBRY_API_URL='http://localhost:8080' yarn dev",
|
|
||||||
"dev:web": "webpack --watch",
|
|
||||||
"lint": "eslint 'src/**/*.{js,jsx}' --fix && flow",
|
"lint": "eslint 'src/**/*.{js,jsx}' --fix && flow",
|
||||||
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write",
|
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write",
|
||||||
"flow-defs": "flow-typed install",
|
"flow-defs": "flow-typed install",
|
||||||
|
@ -36,10 +35,9 @@
|
||||||
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lbry/components": "^2.2.4",
|
"@babel/polyfill": "^7.2.5",
|
||||||
"@types/three": "^0.93.1",
|
"@types/three": "^0.93.1",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"breakdance": "^3.0.1",
|
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"codemirror": "^5.39.2",
|
"codemirror": "^5.39.2",
|
||||||
"country-data": "^0.0.31",
|
"country-data": "^0.0.31",
|
||||||
|
@ -48,12 +46,12 @@
|
||||||
"electron-dl": "^1.11.0",
|
"electron-dl": "^1.11.0",
|
||||||
"electron-is-dev": "^0.3.0",
|
"electron-is-dev": "^0.3.0",
|
||||||
"electron-log": "^2.2.12",
|
"electron-log": "^2.2.12",
|
||||||
"electron-updater": "^2.23.3",
|
"electron-updater": "^4.0.0",
|
||||||
"electron-window-state": "^4.1.1",
|
"electron-window-state": "^4.1.1",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"formik": "^0.10.4",
|
"formik": "^0.10.4",
|
||||||
"hast-util-sanitize": "^1.1.2",
|
"hast-util-sanitize": "^1.1.2",
|
||||||
"keytar": "^4.2.1",
|
"keytar": "^4.3.0",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#406e1970b9d5594faf0407100c9bbed45d904cdf",
|
"lbry-redux": "lbryio/lbry-redux#406e1970b9d5594faf0407100c9bbed45d904cdf",
|
||||||
"lbryinc": "lbryio/lbryinc#2334ad53e82c22d6291899785d5292347008f2a9",
|
"lbryinc": "lbryio/lbryinc#2334ad53e82c22d6291899785d5292347008f2a9",
|
||||||
|
@ -62,8 +60,10 @@
|
||||||
"mime": "^2.3.1",
|
"mime": "^2.3.1",
|
||||||
"mixpanel-browser": "^2.17.1",
|
"mixpanel-browser": "^2.17.1",
|
||||||
"moment": "^2.22.0",
|
"moment": "^2.22.0",
|
||||||
|
"node-abi": "^2.5.1",
|
||||||
"node-fetch": "^2.3.0",
|
"node-fetch": "^2.3.0",
|
||||||
"preprocess-loader": "^0.3.0",
|
"preprocess-loader": "^0.3.0",
|
||||||
|
"prop-types": "^15.6.2",
|
||||||
"qrcode.react": "^0.8.0",
|
"qrcode.react": "^0.8.0",
|
||||||
"rc-progress": "^2.0.6",
|
"rc-progress": "^2.0.6",
|
||||||
"react": "^16.8.2",
|
"react": "^16.8.2",
|
||||||
|
@ -86,28 +86,37 @@
|
||||||
"render-media": "^3.1.0",
|
"render-media": "^3.1.0",
|
||||||
"reselect": "^3.0.0",
|
"reselect": "^3.0.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"source-map-support": "^0.5.4",
|
"source-map-support": "^0.5.10",
|
||||||
|
"stream-to-blob-url": "^2.1.1",
|
||||||
"three": "^0.93.0",
|
"three": "^0.93.0",
|
||||||
|
"three-full": "^11.3.2",
|
||||||
"tree-kill": "^1.1.0",
|
"tree-kill": "^1.1.0",
|
||||||
"video.js": "^7.2.2",
|
"video.js": "^7.2.2",
|
||||||
"y18n": "^4.0.0"
|
"y18n": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^8.2.2",
|
"@babel/core": "^7.0.0",
|
||||||
"babel-plugin-module-resolver": "^3.1.1",
|
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||||
"babel-polyfill": "^6.26.0",
|
"@babel/plugin-proposal-decorators": "^7.3.0",
|
||||||
"babel-preset-env": "^1.6.1",
|
"@babel/plugin-transform-flow-strip-types": "^7.2.3",
|
||||||
"babel-preset-react": "^6.24.1",
|
"@babel/preset-flow": "^7.0.0",
|
||||||
"babel-preset-stage-2": "^6.18.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
|
"@lbry/color": "^1.0.2",
|
||||||
|
"@lbry/components": "^2.2.4",
|
||||||
|
"async-exit-hook": "^2.0.1",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"babel-loader": "^8.0.5",
|
||||||
|
"babel-plugin-add-module-exports": "^1.0.0",
|
||||||
"copy-webpack-plugin": "^4.6.0",
|
"copy-webpack-plugin": "^4.6.0",
|
||||||
|
"css-loader": "^2.1.0",
|
||||||
"decompress": "^4.2.0",
|
"decompress": "^4.2.0",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"electron": "^2.0.14",
|
"electron": "^4.0.4",
|
||||||
"electron-builder": "^20.22.0",
|
"electron-builder": "^20.38.4",
|
||||||
"electron-devtools-installer": "^2.2.3",
|
"electron-devtools-installer": "^2.2.3",
|
||||||
"electron-publisher-s3": "^20.8.1",
|
"electron-publisher-s3": "^20.8.1",
|
||||||
"electron-webpack": "^1.13.0",
|
"electron-webpack": "^2.6.2",
|
||||||
"eslint": "^4.19.0",
|
"eslint": "^4.19.0",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-config-prettier": "^2.9.0",
|
"eslint-config-prettier": "^2.9.0",
|
||||||
|
@ -121,17 +130,21 @@
|
||||||
"flow-bin": "^0.89.0",
|
"flow-bin": "^0.89.0",
|
||||||
"flow-typed": "^2.3.0",
|
"flow-typed": "^2.3.0",
|
||||||
"husky": "^0.14.3",
|
"husky": "^0.14.3",
|
||||||
"i18n-extract": "^0.5.1",
|
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"make-runnable": "^1.3.6",
|
"make-runnable": "^1.3.6",
|
||||||
"node-libs-browser": "^2.1.0",
|
"node-libs-browser": "^2.1.0",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.11.0",
|
||||||
|
"preprocess-loader": "^0.3.0",
|
||||||
"prettier": "^1.11.1",
|
"prettier": "^1.11.1",
|
||||||
"sass-loader": "^6.0.7",
|
"sass-loader": "^7.1.0",
|
||||||
"webpack": "^3.10.0",
|
"style-loader": "^0.23.1",
|
||||||
|
"webpack": "^4.28.4",
|
||||||
"webpack-build-notifier": "^0.1.23",
|
"webpack-build-notifier": "^0.1.23",
|
||||||
|
"webpack-dev-server": "^3.1.14",
|
||||||
|
"webpack-merge": "^4.2.1",
|
||||||
|
"webpack-node-externals": "^1.7.2",
|
||||||
"yarnhook": "^0.2.0"
|
"yarnhook": "^0.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -141,7 +154,7 @@
|
||||||
"lbrySettings": {
|
"lbrySettings": {
|
||||||
"lbrynetDaemonVersion": "0.32.4",
|
"lbrynetDaemonVersion": "0.32.4",
|
||||||
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
|
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
|
||||||
"lbrynetDaemonDir": "static/daemon",
|
"lbrynetDaemonDir": "static",
|
||||||
"lbrynetDaemonFileName": "lbrynet"
|
"lbrynetDaemonFileName": "lbrynet"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
import express from 'express';
|
|
||||||
import unpackByOutpoint from './unpackByOutpoint';
|
|
||||||
|
|
||||||
// Polyfills and `lbry-redux`
|
|
||||||
global.fetch = require('node-fetch');
|
|
||||||
|
|
||||||
global.window = global;
|
|
||||||
// eslint-disable-next-line import/no-commonjs,global-require
|
|
||||||
const { Lbry } = require('lbry-redux');
|
|
||||||
|
|
||||||
delete global.window;
|
|
||||||
|
|
||||||
export default async function startSandbox() {
|
|
||||||
const sandbox = express();
|
|
||||||
const port = 5278;
|
|
||||||
|
|
||||||
sandbox.get('/set/:outpoint', async (req, res) => {
|
|
||||||
const { outpoint } = req.params;
|
|
||||||
const resolvedPath = await unpackByOutpoint(Lbry, outpoint);
|
|
||||||
|
|
||||||
sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath));
|
|
||||||
|
|
||||||
res.send(`/sandbox/${outpoint}/`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
sandbox.listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`));
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import { spawn, execSync } from 'child_process';
|
||||||
import { Lbry } from 'lbry-redux';
|
import { Lbry } from 'lbry-redux';
|
||||||
|
|
||||||
export default class Daemon {
|
export default class Daemon {
|
||||||
static path = process.env.LBRY_DAEMON || path.join(__static, 'daemon/lbrynet');
|
static path = process.env.LBRY_DAEMON || path.join(__static, 'lbrynet');
|
||||||
subprocess;
|
subprocess;
|
||||||
handlers;
|
handlers;
|
||||||
|
|
|
@ -5,15 +5,15 @@ export default window => {
|
||||||
let iconPath;
|
let iconPath;
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'darwin': {
|
case 'darwin': {
|
||||||
iconPath = path.join(__static, '/img/tray/mac/trayTemplate.png');
|
iconPath = 'static/img/tray/mac/trayTemplate.png';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'win32': {
|
case 'win32': {
|
||||||
iconPath = path.join(__static, '/img/tray/windows/tray.ico');
|
iconPath = 'static/img/tray/windows/tray.ico';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
iconPath = path.join(__static, '/img/tray/default/tray.png');
|
iconPath = 'static/img/tray/default/tray.png';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import path from 'path';
|
||||||
import { app, BrowserWindow, dialog, shell, screen } from 'electron';
|
import { app, BrowserWindow, dialog, shell, screen } from 'electron';
|
||||||
import isDev from 'electron-is-dev';
|
import isDev from 'electron-is-dev';
|
||||||
import windowStateKeeper from 'electron-window-state';
|
import windowStateKeeper from 'electron-window-state';
|
||||||
|
@ -34,8 +35,8 @@ export default appState => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const rendererURL = isDev
|
const rendererURL = isDev // ? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
||||||
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
? `file://${path.resolve(__dirname, '../index.html')}`
|
||||||
: `file://${__dirname}/index.html`;
|
: `file://${__dirname}/index.html`;
|
||||||
|
|
||||||
let window = new BrowserWindow(windowConfiguration);
|
let window = new BrowserWindow(windowConfiguration);
|
||||||
|
@ -45,6 +46,8 @@ export default appState => {
|
||||||
// and restore the maximized or full screen state.
|
// and restore the maximized or full screen state.
|
||||||
windowState.manage(window);
|
windowState.manage(window);
|
||||||
|
|
||||||
|
console.log('url', rendererURL);
|
||||||
|
console.log('window', window);
|
||||||
window.loadURL(rendererURL);
|
window.loadURL(rendererURL);
|
||||||
|
|
||||||
let deepLinkingURI;
|
let deepLinkingURI;
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
// Module imports
|
// Module imports
|
||||||
// @if TARGET='app'
|
import '@babel/polyfill';
|
||||||
import keytar from 'keytar';
|
import keytar from 'keytar';
|
||||||
import SemVer from 'semver';
|
import SemVer from 'semver';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
|
@ -12,8 +12,8 @@ import { Lbry } from 'lbry-redux';
|
||||||
import Daemon from './Daemon';
|
import Daemon from './Daemon';
|
||||||
import createTray from './createTray';
|
import createTray from './createTray';
|
||||||
import createWindow from './createWindow';
|
import createWindow from './createWindow';
|
||||||
import pjson from '../../package.json';
|
import pjson from '../../../package.json';
|
||||||
import startSandbox from './startSandbox';
|
// import startSandbox from './startSandbox';
|
||||||
|
|
||||||
autoUpdater.autoDownload = true;
|
autoUpdater.autoDownload = true;
|
||||||
|
|
||||||
|
@ -29,26 +29,20 @@ let showingAutoUpdateCloseAlert = false;
|
||||||
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
||||||
// object is garbage collected.
|
// object is garbage collected.
|
||||||
let rendererWindow;
|
let rendererWindow;
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
let tray;
|
let tray;
|
||||||
let daemon;
|
let daemon;
|
||||||
|
|
||||||
const appState = {};
|
const appState = {};
|
||||||
|
|
||||||
const installExtensions = async () => {
|
const installExtensions = async () => {
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
// // eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
||||||
const installer = require('electron-devtools-installer');
|
// const installer = require('electron-devtools-installer');
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
// // eslint-disable-next-line import/no-extraneous-dependencies,global-require
|
||||||
const devtronExtension = require('devtron');
|
// const devtronExtension = require('devtron');
|
||||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
// const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
|
||||||
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
|
// await devtronExtension.install();
|
||||||
|
// return Promise.all(extensions.map(name => installer.default(installer[name]))).catch(console.log);
|
||||||
return Promise.all(
|
|
||||||
extensions.map(
|
|
||||||
name => installer.default(installer[name], forceDownload),
|
|
||||||
devtronExtension.install()
|
|
||||||
)
|
|
||||||
).catch(console.log);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
app.setAsDefaultProtocolClient('lbry');
|
app.setAsDefaultProtocolClient('lbry');
|
||||||
|
@ -95,7 +89,7 @@ app.on('ready', async () => {
|
||||||
daemon.launch();
|
daemon.launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
startSandbox();
|
// startSandbox();
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
await installExtensions();
|
await installExtensions();
|
||||||
|
@ -295,7 +289,8 @@ process.on('uncaughtException', error => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Force single instance application
|
// Force single instance application
|
||||||
const isSecondInstance = app.makeSingleInstance(argv => {
|
app.requestSingleInstanceLock();
|
||||||
|
app.on('second-instance', (event, argv) => {
|
||||||
if (rendererWindow) {
|
if (rendererWindow) {
|
||||||
if (
|
if (
|
||||||
(process.platform === 'win32' || process.platform === 'linux') &&
|
(process.platform === 'win32' || process.platform === 'linux') &&
|
||||||
|
@ -323,8 +318,3 @@ const isSecondInstance = app.makeSingleInstance(argv => {
|
||||||
rendererWindow.show();
|
rendererWindow.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isSecondInstance) {
|
|
||||||
app.exit();
|
|
||||||
}
|
|
||||||
// @endif
|
|
28
src/platforms/electron/startSandbox.js
Normal file
28
src/platforms/electron/startSandbox.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// import express from 'express';
|
||||||
|
// import unpackByOutpoint from './unpackByOutpoint';
|
||||||
|
|
||||||
|
// // Polyfills and `lbry-redux`
|
||||||
|
// global.fetch = require('node-fetch');
|
||||||
|
|
||||||
|
// global.window = global;
|
||||||
|
// // eslint-disable-next-line import/no-commonjs,global-require
|
||||||
|
// const { Lbry } = require('lbry-redux');
|
||||||
|
|
||||||
|
// delete global.window;
|
||||||
|
|
||||||
|
// export default async function startSandbox() {
|
||||||
|
// const sandbox = express();
|
||||||
|
// const port = 5278;
|
||||||
|
|
||||||
|
// sandbox.get('/set/:outpoint', async (req, res) => {
|
||||||
|
// const { outpoint } = req.params;
|
||||||
|
// const resolvedPath = await unpackByOutpoint(Lbry, outpoint);
|
||||||
|
|
||||||
|
// sandbox.use(`/sandbox/${outpoint}/`, express.static(resolvedPath));
|
||||||
|
|
||||||
|
// res.send(`/sandbox/${outpoint}/`);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // eslint-disable-next-line no-console
|
||||||
|
// sandbox.listen(port, 'localhost', () => console.log(`Sandbox listening on port ${port}.`));
|
||||||
|
// }
|
11
src/platforms/web/electron.js
Normal file
11
src/platforms/web/electron.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export const clipboard = () => {
|
||||||
|
throw 'Fix me!';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ipcRenderer = () => {
|
||||||
|
throw 'Fix me!';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const remote = () => {
|
||||||
|
throw 'Fix me!';
|
||||||
|
};
|
23
src/platforms/web/stubs.js
Normal file
23
src/platforms/web/stubs.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const callable = () => {
|
||||||
|
throw Error('Need to fix this stub');
|
||||||
|
};
|
||||||
|
const returningCallable = value => () => value;
|
||||||
|
|
||||||
|
export const remote = {
|
||||||
|
dialog: {
|
||||||
|
showOpenDialog: callable,
|
||||||
|
},
|
||||||
|
getCurrentWindow: callable,
|
||||||
|
app: {
|
||||||
|
getAppPath: callable,
|
||||||
|
},
|
||||||
|
BrowserWindow: {
|
||||||
|
getFocusedWindow: callable,
|
||||||
|
},
|
||||||
|
Menu: {
|
||||||
|
getApplicationMenu: callable,
|
||||||
|
},
|
||||||
|
require: callable,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isDev = false;
|
|
@ -1,33 +0,0 @@
|
||||||
import { LoadingManager, STLLoader, OBJLoader2 } from './three';
|
|
||||||
|
|
||||||
const Manager = ({ onLoad, onStart, onError }) => {
|
|
||||||
const manager = new LoadingManager();
|
|
||||||
manager.onLoad = onLoad;
|
|
||||||
manager.onStart = onStart;
|
|
||||||
manager.onError = onError;
|
|
||||||
|
|
||||||
return manager;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Loader = (fileType, manager) => {
|
|
||||||
const fileTypes = {
|
|
||||||
stl: () => new STLLoader(manager),
|
|
||||||
obj: () => new OBJLoader2(manager),
|
|
||||||
};
|
|
||||||
return fileTypes[fileType] ? fileTypes[fileType]() : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ThreeLoader = ({ fileType = null, downloadPath = null }, renderModel, managerEvents) => {
|
|
||||||
if (fileType) {
|
|
||||||
const manager = Manager(managerEvents);
|
|
||||||
const loader = Loader(fileType, manager);
|
|
||||||
|
|
||||||
if (loader) {
|
|
||||||
loader.load(`file://${downloadPath}`, data => {
|
|
||||||
renderModel(fileType, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ThreeLoader;
|
|
|
@ -1,11 +0,0 @@
|
||||||
import * as THREE from 'three';
|
|
||||||
|
|
||||||
// Currently it's not possible to import the files within the "examples/js" directory.
|
|
||||||
// Fix: https://github.com/mrdoob/three.js/issues/9562#issuecomment-383390251
|
|
||||||
global.THREE = THREE;
|
|
||||||
require('three/examples/js/controls/OrbitControls');
|
|
||||||
require('three/examples/js/loaders/LoaderSupport');
|
|
||||||
require('three/examples/js/loaders/OBJLoader2');
|
|
||||||
require('three/examples/js/loaders/STLLoader');
|
|
||||||
|
|
||||||
module.exports = global.THREE;
|
|
|
@ -1,74 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import {
|
|
||||||
makeSelectClaimForUri,
|
|
||||||
selectClaimsByUri,
|
|
||||||
makeSelectClaimsInChannelForCurrentPage,
|
|
||||||
} from 'lbry-redux';
|
|
||||||
import { HISTORY_ITEMS_PER_PAGE } from 'constants/content';
|
|
||||||
|
|
||||||
export const selectState = (state: any) => state.content || {};
|
|
||||||
|
|
||||||
export const selectPlayingUri = createSelector(selectState, state => state.playingUri);
|
|
||||||
|
|
||||||
export const selectChannelClaimCounts = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.channelClaimCounts || {}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectTotalItemsForChannel = (uri: string) =>
|
|
||||||
createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri]);
|
|
||||||
|
|
||||||
export const selectRewardContentClaimIds = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.rewardedContentClaimIds
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectContentPositionForUri = (uri: string) =>
|
|
||||||
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
|
|
||||||
if (!claim) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
|
||||||
const id = claim.claim_id;
|
|
||||||
return state.positions[id] ? state.positions[id][outpoint] : null;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectHistoryPageCount = createSelector(selectState, state =>
|
|
||||||
Math.ceil(state.history.length / HISTORY_ITEMS_PER_PAGE)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectHistoryForPage = (page: number) =>
|
|
||||||
createSelector(selectState, selectClaimsByUri, (state, claimsByUri) => {
|
|
||||||
const left = page * HISTORY_ITEMS_PER_PAGE;
|
|
||||||
const historyItems = state.history.slice(left, left + HISTORY_ITEMS_PER_PAGE);
|
|
||||||
|
|
||||||
// See if we have the claim info for the uris in your history
|
|
||||||
// If not, it will need to be fetched in the component
|
|
||||||
return historyItems.map(historyItem => {
|
|
||||||
const { uri, lastViewed } = historyItem;
|
|
||||||
const claimAtUri = claimsByUri[uri];
|
|
||||||
|
|
||||||
if (claimAtUri) {
|
|
||||||
return { lastViewed, uri, ...claimAtUri };
|
|
||||||
}
|
|
||||||
return historyItem;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const makeSelectHistoryForUri = (uri: string) =>
|
|
||||||
createSelector(selectState, state => state.history.find(i => i.uri === uri));
|
|
||||||
|
|
||||||
export const makeSelectCategoryListUris = (uris: ?Array<string>, channel: string) =>
|
|
||||||
createSelector(makeSelectClaimsInChannelForCurrentPage(channel), channelClaims => {
|
|
||||||
if (uris) return uris;
|
|
||||||
|
|
||||||
if (channelClaims) {
|
|
||||||
const CATEGORY_LIST_SIZE = 10;
|
|
||||||
return channelClaims
|
|
||||||
.slice(0, CATEGORY_LIST_SIZE)
|
|
||||||
.map(({ name, claim_id: claimId }) => `${name}#${claimId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
|
@ -1,199 +0,0 @@
|
||||||
import {
|
|
||||||
selectClaimsByUri,
|
|
||||||
selectIsFetchingClaimListMine,
|
|
||||||
selectMyClaims,
|
|
||||||
selectClaimsById,
|
|
||||||
buildURI,
|
|
||||||
} from 'lbry-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
|
|
||||||
export const selectState = state => state.fileInfo || {};
|
|
||||||
|
|
||||||
export const selectFileInfosByOutpoint = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.byOutpoint || {}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectIsFetchingFileList = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.isFetchingFileList
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectIsFetchingFileListDownloadedOrPublished = createSelector(
|
|
||||||
selectIsFetchingFileList,
|
|
||||||
selectIsFetchingClaimListMine,
|
|
||||||
(isFetchingFileList, isFetchingClaimListMine) => isFetchingFileList || isFetchingClaimListMine
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectFileInfoForUri = uri =>
|
|
||||||
createSelector(selectClaimsByUri, selectFileInfosByOutpoint, (claims, byOutpoint) => {
|
|
||||||
const claim = claims[uri];
|
|
||||||
const outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
|
||||||
return outpoint ? byOutpoint[outpoint] : undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectDownloadingByOutpoint = createSelector(
|
|
||||||
selectState,
|
|
||||||
state => state.downloadingByOutpoint || {}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const makeSelectDownloadingForUri = uri =>
|
|
||||||
createSelector(
|
|
||||||
selectDownloadingByOutpoint,
|
|
||||||
makeSelectFileInfoForUri(uri),
|
|
||||||
(byOutpoint, fileInfo) => {
|
|
||||||
if (!fileInfo) return false;
|
|
||||||
return byOutpoint[fileInfo.outpoint];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectUrisLoading = createSelector(selectState, state => state.urisLoading || {});
|
|
||||||
|
|
||||||
export const makeSelectLoadingForUri = uri =>
|
|
||||||
createSelector(selectUrisLoading, byUri => byUri && byUri[uri]);
|
|
||||||
|
|
||||||
export const selectFileInfosDownloaded = createSelector(
|
|
||||||
selectFileInfosByOutpoint,
|
|
||||||
selectMyClaims,
|
|
||||||
(byOutpoint, myClaims) =>
|
|
||||||
Object.values(byOutpoint).filter(fileInfo => {
|
|
||||||
const myClaimIds = myClaims.map(claim => claim.claim_id);
|
|
||||||
|
|
||||||
return (
|
|
||||||
fileInfo &&
|
|
||||||
myClaimIds.indexOf(fileInfo.claim_id) === -1 &&
|
|
||||||
(fileInfo.completed || fileInfo.written_bytes)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// export const selectFileInfoForUri = (state, props) => {
|
|
||||||
// const claims = selectClaimsByUri(state),
|
|
||||||
// claim = claims[props.uri],
|
|
||||||
// fileInfos = selectAllFileInfos(state),
|
|
||||||
// outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
|
|
||||||
|
|
||||||
// return outpoint && fileInfos ? fileInfos[outpoint] : undefined;
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const selectDownloadingFileInfos = createSelector(
|
|
||||||
selectDownloadingByOutpoint,
|
|
||||||
selectFileInfosByOutpoint,
|
|
||||||
(downloadingByOutpoint, fileInfosByOutpoint) => {
|
|
||||||
const outpoints = Object.keys(downloadingByOutpoint);
|
|
||||||
const fileInfos = [];
|
|
||||||
|
|
||||||
outpoints.forEach(outpoint => {
|
|
||||||
const fileInfo = fileInfosByOutpoint[outpoint];
|
|
||||||
|
|
||||||
if (fileInfo) fileInfos.push(fileInfo);
|
|
||||||
});
|
|
||||||
|
|
||||||
return fileInfos;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectTotalDownloadProgress = createSelector(selectDownloadingFileInfos, fileInfos => {
|
|
||||||
const progress = [];
|
|
||||||
|
|
||||||
fileInfos.forEach(fileInfo => {
|
|
||||||
progress.push((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
|
||||||
});
|
|
||||||
|
|
||||||
const totalProgress = progress.reduce((a, b) => a + b, 0);
|
|
||||||
|
|
||||||
if (fileInfos.length > 0) return totalProgress / fileInfos.length / 100.0;
|
|
||||||
return -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectSearchDownloadUris = query =>
|
|
||||||
createSelector(selectFileInfosDownloaded, selectClaimsById, (fileInfos, claimsById) => {
|
|
||||||
if (!query || !fileInfos.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryParts = query.toLowerCase().split(' ');
|
|
||||||
const searchQueryDictionary = {};
|
|
||||||
queryParts.forEach(subQuery => {
|
|
||||||
searchQueryDictionary[subQuery] = subQuery;
|
|
||||||
});
|
|
||||||
|
|
||||||
const arrayContainsQueryPart = array => {
|
|
||||||
for (let i = 0; i < array.length; i += 1) {
|
|
||||||
const subQuery = array[i];
|
|
||||||
if (searchQueryDictionary[subQuery]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadResultsFromQuery = [];
|
|
||||||
fileInfos.forEach(fileInfo => {
|
|
||||||
const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo;
|
|
||||||
const { author, description, title } = metadata;
|
|
||||||
|
|
||||||
if (channelName) {
|
|
||||||
const lowerCaseChannel = channelName.toLowerCase();
|
|
||||||
const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @
|
|
||||||
if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameParts = claimName.toLowerCase().split('-');
|
|
||||||
if (arrayContainsQueryPart(nameParts)) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const titleParts = title.toLowerCase().split(' ');
|
|
||||||
if (arrayContainsQueryPart(titleParts)) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (author) {
|
|
||||||
const authorParts = author.toLowerCase().split(' ');
|
|
||||||
if (arrayContainsQueryPart(authorParts)) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description) {
|
|
||||||
const descriptionParts = description.toLowerCase().split(' ');
|
|
||||||
if (arrayContainsQueryPart(descriptionParts)) {
|
|
||||||
downloadResultsFromQuery.push(fileInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return downloadResultsFromQuery.length
|
|
||||||
? downloadResultsFromQuery.map(fileInfo => {
|
|
||||||
const { channel_name: channelName, claim_id: claimId, claim_name: claimName } = fileInfo;
|
|
||||||
|
|
||||||
const uriParams = {};
|
|
||||||
|
|
||||||
if (channelName) {
|
|
||||||
const claim = claimsById[claimId];
|
|
||||||
if (claim && claim.value) {
|
|
||||||
uriParams.claimId = claim.value.publisherSignature.certificateId;
|
|
||||||
} else {
|
|
||||||
uriParams.claimId = claimId;
|
|
||||||
}
|
|
||||||
uriParams.channelName = channelName;
|
|
||||||
uriParams.contentName = claimName;
|
|
||||||
} else {
|
|
||||||
uriParams.claimId = claimId;
|
|
||||||
uriParams.claimName = claimName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uri = buildURI(uriParams);
|
|
||||||
return uri;
|
|
||||||
})
|
|
||||||
: null;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const selectFileInfoErrors = createSelector(selectState, state => state.errors || {});
|
|
20
src/ui/app.js
Normal file
20
src/ui/app.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import store from 'store';
|
||||||
|
|
||||||
|
const env = process.env.NODE_ENV || 'production';
|
||||||
|
|
||||||
|
const logs = [];
|
||||||
|
const app = {
|
||||||
|
env,
|
||||||
|
store,
|
||||||
|
logs,
|
||||||
|
log(message) {
|
||||||
|
logs.push(message);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
global.app = app;
|
||||||
|
|
||||||
|
// Lbryinc needs access to the redux store for dispatching auth-releated actions
|
||||||
|
global.store = app.store;
|
||||||
|
|
||||||
|
export default app;
|
|
@ -8,7 +8,7 @@ import SideBar from 'component/sideBar';
|
||||||
import Header from 'component/header';
|
import Header from 'component/header';
|
||||||
import { openContextMenu } from 'util/context-menu';
|
import { openContextMenu } from 'util/context-menu';
|
||||||
import EnhancedLayoutListener from 'util/enhanced-layout';
|
import EnhancedLayoutListener from 'util/enhanced-layout';
|
||||||
import Native from 'native';
|
import Yrbl from 'component/yrbl';
|
||||||
|
|
||||||
const TWO_POINT_FIVE_MINUTES = 1000 * 60 * 2.5;
|
const TWO_POINT_FIVE_MINUTES = 1000 * 60 * 2.5;
|
||||||
|
|
||||||
|
@ -112,13 +112,7 @@ class App extends React.PureComponent<Props> {
|
||||||
<div id="window" onContextMenu={e => openContextMenu(e)}>
|
<div id="window" onContextMenu={e => openContextMenu(e)}>
|
||||||
<Header />
|
<Header />
|
||||||
<main className="page">
|
<main className="page">
|
||||||
{enhancedLayout && (
|
{enhancedLayout && <Yrbl className="yrbl--enhanced" />}
|
||||||
<img
|
|
||||||
alt="Friendly gerbil"
|
|
||||||
className="yrbl--enhanced"
|
|
||||||
src={Native.imagePath('gerbil-happy.png')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{/* @if TARGET='app' */}
|
{/* @if TARGET='app' */}
|
||||||
<SideBar />
|
<SideBar />
|
||||||
{/* @endif */}
|
{/* @endif */}
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Native from 'native';
|
import Placeholder from './placeholder.png';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
thumbnail: ?string, // externally sourced image
|
thumbnail: ?string, // externally sourced image
|
||||||
|
@ -15,7 +15,7 @@ class CardMedia extends React.PureComponent<Props> {
|
||||||
style={
|
style={
|
||||||
thumbnail
|
thumbnail
|
||||||
? { backgroundImage: `url('${thumbnail}')` }
|
? { backgroundImage: `url('${thumbnail}')` }
|
||||||
: { backgroundImage: `url('${Native.imagePath('placeholder.png')}')` }
|
: { backgroundImage: `url(${Placeholder})` }
|
||||||
}
|
}
|
||||||
className="media__thumb"
|
className="media__thumb"
|
||||||
/>
|
/>
|
|
@ -163,7 +163,7 @@ class CardVerify extends React.Component<Props, State> {
|
||||||
<Button
|
<Button
|
||||||
button="primary"
|
button="primary"
|
||||||
label={this.props.label}
|
label={this.props.label}
|
||||||
icon={ICONS.LOCK}
|
icon={ICONS.SECURE}
|
||||||
disabled={this.props.disabled || this.state.open || this.hasPendingClick}
|
disabled={this.props.disabled || this.state.open || this.hasPendingClick}
|
||||||
onClick={this.onClick.bind(this)}
|
onClick={this.onClick.bind(this)}
|
||||||
/>
|
/>
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import parseData from 'util/parse-data';
|
import parseData from 'util/parse-data';
|
||||||
|
@ -39,6 +38,7 @@ class FileExporter extends React.PureComponent<Props> {
|
||||||
|
|
||||||
handleFileCreation(filename: string, data: any) {
|
handleFileCreation(filename: string, data: any) {
|
||||||
const { onFileCreated } = this.props;
|
const { onFileCreated } = this.props;
|
||||||
|
// @if TARGET='app'
|
||||||
fs.writeFile(filename, data, err => {
|
fs.writeFile(filename, data, err => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
// Do something after creation
|
// Do something after creation
|
||||||
|
@ -47,6 +47,7 @@ class FileExporter extends React.PureComponent<Props> {
|
||||||
onFileCreated(filename);
|
onFileCreated(filename);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// @endif
|
||||||
}
|
}
|
||||||
|
|
||||||
handleButtonClick() {
|
handleButtonClick() {
|
||||||
|
@ -71,7 +72,9 @@ class FileExporter extends React.PureComponent<Props> {
|
||||||
// User hit cancel so do nothing:
|
// User hit cancel so do nothing:
|
||||||
if (!filename) return;
|
if (!filename) return;
|
||||||
// Get extension and remove initial dot
|
// Get extension and remove initial dot
|
||||||
|
// @if TARGET='app'
|
||||||
const format = path.extname(filename).replace(/\./g, '');
|
const format = path.extname(filename).replace(/\./g, '');
|
||||||
|
// @endif
|
||||||
// Parse data to string with the chosen format
|
// Parse data to string with the chosen format
|
||||||
const parsed = parseData(data, format, filters);
|
const parsed = parseData(data, format, filters);
|
||||||
// Write file
|
// Write file
|
|
@ -58,6 +58,7 @@ class FileSelector extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = paths[0];
|
const filePath = paths[0];
|
||||||
|
|
||||||
const extension = path.extname(filePath);
|
const extension = path.extname(filePath);
|
||||||
const fileName = path.basename(filePath, extension);
|
const fileName = path.basename(filePath, extension);
|
||||||
|
|
38
src/ui/component/common/form-components/form-row.jsx
Normal file
38
src/ui/component/common/form-components/form-row.jsx
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// @flow
|
||||||
|
// Used as a wrapper for FormField to produce inline form elements
|
||||||
|
import * as React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: React.Node,
|
||||||
|
padded?: boolean,
|
||||||
|
verticallyCentered?: boolean,
|
||||||
|
stretch?: boolean,
|
||||||
|
alignRight?: boolean,
|
||||||
|
centered?: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class FormRow extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
padded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, padded, verticallyCentered, stretch, alignRight, centered } = this.props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames('form-row', {
|
||||||
|
'form-row--padded': padded,
|
||||||
|
'form-row--vertically-centered': verticallyCentered,
|
||||||
|
'form-row--stretch': stretch,
|
||||||
|
'form-row--right': alignRight,
|
||||||
|
'form-row--centered': centered,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormRow;
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
date?: number,
|
date?: number | {},
|
||||||
timeAgo?: boolean,
|
timeAgo?: boolean,
|
||||||
formatOptions: {},
|
formatOptions: {},
|
||||||
show?: string,
|
show?: string,
|
||||||
|
@ -43,7 +43,7 @@ class DateTime extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { date, formatOptions, timeAgo } = this.props;
|
const { date, formatOptions, timeAgo } = this.props;
|
||||||
const show = this.props.show || DateTime.SHOW_BOTH;
|
const show = this.props.show || DateTime.SHOW_BOTH;
|
||||||
const locale = app.i18n.getLocale();
|
const locale = i18n.getLocale();
|
||||||
|
|
||||||
if (timeAgo) {
|
if (timeAgo) {
|
||||||
return date ? <span>{moment(date).from(moment())}</span> : <span />;
|
return date ? <span>{moment(date).from(moment())}</span> : <span />;
|
|
@ -6,8 +6,8 @@ import React, { Fragment, PureComponent } from 'react';
|
||||||
import { Lbryio } from 'lbryinc';
|
import { Lbryio } from 'lbryinc';
|
||||||
import MarkdownPreview from 'component/common/markdown-preview';
|
import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import path from 'path';
|
|
||||||
import Expandable from 'component/expandable';
|
import Expandable from 'component/expandable';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: Claim,
|
claim: Claim,
|
|
@ -24,8 +24,7 @@ class FileListSearch extends React.PureComponent<Props> {
|
||||||
<div className="search__results-title">{__('Search Results')}</div>
|
<div className="search__results-title">{__('Search Results')}</div>
|
||||||
<HiddenNsfwClaims uris={uris} />
|
<HiddenNsfwClaims uris={uris} />
|
||||||
{!isSearching && uris && uris.length ? (
|
{!isSearching && uris && uris.length ? (
|
||||||
uris.map(
|
uris.map(uri =>
|
||||||
uri =>
|
|
||||||
parseURI(uri).claimName[0] === '@' ? (
|
parseURI(uri).claimName[0] === '@' ? (
|
||||||
<ChannelTile key={uri} uri={uri} />
|
<ChannelTile key={uri} uri={uri} />
|
||||||
) : (
|
) : (
|
|
@ -1,9 +1,11 @@
|
||||||
// @flow
|
/* eslint-disable */
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
// @if TARGET='app'
|
||||||
import { remote } from 'electron';
|
import { remote } from 'electron';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
// @endif
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
import FileRender from 'component/fileRender';
|
import FileRender from 'component/fileRender';
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
|
@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
|
||||||
import posed from 'react-pose';
|
import posed from 'react-pose';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import EmailCollection from 'component/emailCollection';
|
import EmailCollection from 'component/emailCollection';
|
||||||
import Native from 'native';
|
import Yrbl from 'component/yrbl';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Animation for items inside banner
|
// Animation for items inside banner
|
||||||
|
@ -59,11 +59,7 @@ export default class FirstRun extends PureComponent<Props> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="banner banner--first-run">
|
<div className="banner banner--first-run">
|
||||||
<img
|
<Yrbl className="yrbl--first-run" />
|
||||||
alt="Friendly gerbil"
|
|
||||||
className="yrbl--first-run banner__item"
|
|
||||||
src={Native.imagePath('gerbil-happy.png')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="banner__item">
|
<div className="banner__item">
|
||||||
<div className="banner__item--static-for-animation">
|
<div className="banner__item--static-for-animation">
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue