Add bare-bones gall app
This commit is contained in:
parent
0736a5870d
commit
05c4d61926
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
gall-app/node_modules
|
6
gall-app/.urbitrc
Normal file
6
gall-app/.urbitrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
URBIT_PIERS: [
|
||||||
|
"../../zod/home",
|
||||||
|
],
|
||||||
|
URL: 'http://localhost:80'
|
||||||
|
};
|
150
gall-app/install.js
Normal file
150
gall-app/install.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
const prompt = require('prompt')
|
||||||
|
const replace = require('replace-in-file')
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
var Promise = require('promise');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
// Making the text input a bit legible.
|
||||||
|
|
||||||
|
prompt.colors = false
|
||||||
|
prompt.message = ""
|
||||||
|
|
||||||
|
// The text input takes a "result" object and passes it to one of two functions to do the logistics.
|
||||||
|
|
||||||
|
prompt.get([{
|
||||||
|
name: 'appName',
|
||||||
|
required: true,
|
||||||
|
description: "What's the name of your application? Lowercase and no spaces, please.",
|
||||||
|
message: "Lowercase and no spaces, please.",
|
||||||
|
conform: function(value) {
|
||||||
|
return /^[a-z0-9]+((\-[a-z0-9]+){1,})?$/g.test(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pier',
|
||||||
|
required: true,
|
||||||
|
description: "Where is your Urbit pier's desk located? For example, /Users/dev/zod/home"
|
||||||
|
}], function (err, result) {
|
||||||
|
setupFull(result)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Migrate application to root directory.
|
||||||
|
|
||||||
|
const deleteFolderRecursive = function (path) {
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
fs.readdirSync(path).forEach(function (file, index) {
|
||||||
|
var curPath = path + "/" + file;
|
||||||
|
if (fs.lstatSync(curPath).isDirectory()) {
|
||||||
|
deleteFolderRecursive(curPath);
|
||||||
|
} else {
|
||||||
|
fs.unlinkSync(curPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fs.rmdirSync(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var promiseAllWait = function (promises) {
|
||||||
|
// this is the same as Promise.all(), except that it will wait for all promises to fulfill before rejecting
|
||||||
|
var all_promises = [];
|
||||||
|
for (var i_promise = 0; i_promise < promises.length; i_promise++) {
|
||||||
|
all_promises.push(
|
||||||
|
promises[i_promise]
|
||||||
|
.then(function (res) {
|
||||||
|
return { res: res };
|
||||||
|
}).catch(function (err) {
|
||||||
|
return { err: err };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(all_promises)
|
||||||
|
.then(function (results) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var is_failure = false;
|
||||||
|
var i_result;
|
||||||
|
for (i_result = 0; i_result < results.length; i_result++) {
|
||||||
|
if (results[i_result].err) {
|
||||||
|
is_failure = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
results[i_result] = results[i_result].res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_failure) {
|
||||||
|
reject(results[i_result].err);
|
||||||
|
} else {
|
||||||
|
resolve(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var movePromiser = function (from, to, records) {
|
||||||
|
return fs.move(from, to)
|
||||||
|
.then(function () {
|
||||||
|
records.push({ from: from, to: to });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var moveDir = function (from_dir, to_dir, callback) {
|
||||||
|
return fs.readdir(from_dir)
|
||||||
|
.then(function (children) {
|
||||||
|
return fs.ensureDir(to_dir)
|
||||||
|
.then(function () {
|
||||||
|
var move_promises = [];
|
||||||
|
var moved_records = [];
|
||||||
|
var child;
|
||||||
|
for (var i_child = 0; i_child < children.length; i_child++) {
|
||||||
|
child = children[i_child];
|
||||||
|
move_promises.push(movePromiser(
|
||||||
|
path.join(from_dir, child),
|
||||||
|
path.join(to_dir, child),
|
||||||
|
moved_records
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return promiseAllWait(move_promises)
|
||||||
|
.catch(function (err) {
|
||||||
|
var undo_move_promises = [];
|
||||||
|
for (var i_moved_record = 0; i_moved_record < moved_records.length; i_moved_record++) {
|
||||||
|
undo_move_promises.push(fs.move(moved_records[i_moved_record].to, moved_records[i_moved_record].from));
|
||||||
|
}
|
||||||
|
|
||||||
|
return promiseAllWait(undo_move_promises)
|
||||||
|
.then(function () {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
return fs.rmdir(from_dir);
|
||||||
|
});
|
||||||
|
}).then(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setupFull = function (result) {
|
||||||
|
fs.access('.DS_Store', (err) => { if (!err) fs.unlinkSync('.DS_Store') })
|
||||||
|
let deHyphenatedName = result.appName.replace(/-/g, '')
|
||||||
|
moveDir('full', './', function() {
|
||||||
|
fs.renameSync('urbit/app/smol.hoon', 'urbit/app/' + deHyphenatedName + '.hoon')
|
||||||
|
fs.renameSync('urbit/app/smol/', 'urbit/app/' + deHyphenatedName)
|
||||||
|
let urbitPierOptions = {
|
||||||
|
files: '.urbitrc',
|
||||||
|
from: "%URBITPIER%",
|
||||||
|
to: result.pier
|
||||||
|
}
|
||||||
|
replace(urbitPierOptions).then(changedFiles => console.log(changedFiles)).catch(err => console.error(err))
|
||||||
|
let appNameOptions = {
|
||||||
|
files: ['webpack.dev.js', 'webpack.prod.js', 'urbit/app/' + deHyphenatedName + '.hoon',
|
||||||
|
'src/js/api.js', 'src/js/subscription.js', 'src/js/components/root.js',
|
||||||
|
'urbit/app/' + deHyphenatedName + '/index.html'
|
||||||
|
],
|
||||||
|
from: /%APPNAME%/g,
|
||||||
|
to: deHyphenatedName
|
||||||
|
}
|
||||||
|
replace(appNameOptions).then(changedFiles => console.log(changedFiles)).catch(err => console.error(err))
|
||||||
|
})
|
||||||
|
console.log("All done! Happy hacking.")
|
||||||
|
}
|
9484
gall-app/package-lock.json
generated
Normal file
9484
gall-app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
66
gall-app/package.json
Normal file
66
gall-app/package.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "create-landscape-app",
|
||||||
|
"version": "4.0.3",
|
||||||
|
"description": "Get started with a Landscape application.",
|
||||||
|
"main": "node install.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node install.js",
|
||||||
|
"serve": "cross-env NODE_ENV=development webpack-dev-server --config webpack.dev.js",
|
||||||
|
"build": "cross-env NODE_ENV=production webpack --config webpack.prod.js"
|
||||||
|
},
|
||||||
|
"author": "Tlon Corp",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "https://github.com/urbit/create-landscape-app",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.9.0",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.9.5",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.10.5",
|
||||||
|
"@babel/preset-env": "^7.9.5",
|
||||||
|
"@babel/preset-react": "^7.9.4",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"babel-plugin-root-import": "^6.5.0",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
|
"file-loader": "^6.0.0",
|
||||||
|
"html-webpack-plugin": "^4.2.0",
|
||||||
|
"react-hot-loader": "^4.12.21",
|
||||||
|
"sass": "^1.26.5",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"webpack": "^4.43.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-dev-server": "^3.10.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.10.5",
|
||||||
|
"@reach/disclosure": "^0.10.5",
|
||||||
|
"@reach/menu-button": "^0.10.5",
|
||||||
|
"@reach/tabs": "^0.10.5",
|
||||||
|
"@tlon/indigo-light": "^1.0.5",
|
||||||
|
"@tlon/indigo-react": "^1.2.8",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"css-loader": "^3.5.3",
|
||||||
|
"formik": "^2.2.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"markdown-to-jsx": "^7.0.1",
|
||||||
|
"moment": "^2.20.1",
|
||||||
|
"mousetrap": "^1.6.3",
|
||||||
|
"mv": "^2.1.1",
|
||||||
|
"promise": "^8.0.3",
|
||||||
|
"prompt": "^1.0.0",
|
||||||
|
"react": "^16.13.1",
|
||||||
|
"react-dom": "^16.13.1",
|
||||||
|
"react-router-dom": "^5.0.0",
|
||||||
|
"replace-in-file": "^4.1.1",
|
||||||
|
"style-loader": "^1.2.1",
|
||||||
|
"styled-components": "^5.2.0",
|
||||||
|
"styled-system": "^5.1.5",
|
||||||
|
"urbit-ob": "^5.0.0",
|
||||||
|
"urbit-sigil-js": "^1.3.13"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"natives": "1.1.3"
|
||||||
|
}
|
||||||
|
}
|
158
gall-app/src/css/custom.css
Normal file
158
gall-app/src/css/custom.css
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
|
||||||
|
margin-block-end: unset;
|
||||||
|
margin-block-start: unset;
|
||||||
|
-webkit-margin-before: unset;
|
||||||
|
-webkit-margin-after: unset;
|
||||||
|
font-family: Inter, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea, select, input, button {
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border: none;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-regular {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-large {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-regular {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-small-mono {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-family: "Source Code Pro", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-regular-400 {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plus-font {
|
||||||
|
font-size: 48px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-font {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.mono {
|
||||||
|
font-family: "Source Code Pro", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inter {
|
||||||
|
font-family: Inter, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mix-blend-diff {
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dark */
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
.bg-black-d {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
.white-d {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.gray1-d {
|
||||||
|
color: #4d4d4d;
|
||||||
|
}
|
||||||
|
.gray2-d {
|
||||||
|
color: #7f7f7f;
|
||||||
|
}
|
||||||
|
.gray3-d {
|
||||||
|
color: #b1b2b3;
|
||||||
|
}
|
||||||
|
.gray4-d {
|
||||||
|
color: #e6e6e6;
|
||||||
|
}
|
||||||
|
.bg-gray0-d {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
.bg-gray1-d {
|
||||||
|
background-color: #4d4d4d;
|
||||||
|
}
|
||||||
|
.b--gray0-d {
|
||||||
|
border-color: #333;
|
||||||
|
}
|
||||||
|
.b--gray1-d {
|
||||||
|
border-color: #4d4d4d;
|
||||||
|
}
|
||||||
|
.b--gray2-d {
|
||||||
|
border-color: #7f7f7f;
|
||||||
|
}
|
||||||
|
.b--white-d {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
.bb-d {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
.invert-d {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
.o-80-d {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
.focus-b--white-d:focus {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.hover-bg-gray1-d:hover {
|
||||||
|
color: #4d4d4d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* responsive */
|
||||||
|
|
||||||
|
@media all and (max-width: 34.375em) {
|
||||||
|
.h-100-minus-40-s {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 34.375em) and (max-width: 46.875em) {
|
||||||
|
.h-100-minus-40-m {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 46.875em) and (max-width: 60em) {
|
||||||
|
.h-100-minus-40-l {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width: 60em) {
|
||||||
|
.h-100-minus-40-xl {
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
}
|
63
gall-app/src/css/fonts.css
Normal file
63
gall-app/src/css/fonts.css
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("https://media.urbit.org/fonts/Inter-Regular.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("https://media.urbit.org/fonts/Inter-Italic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url("https://media.urbit.org/fonts/Inter-Bold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url("https://media.urbit.org/fonts/Inter-BoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-extralight.woff");
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-light.woff");
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff");
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-medium.woff");
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-semibold.woff");
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Source Code Pro";
|
||||||
|
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-bold.woff");
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
1
gall-app/src/css/indigo-static.css
Normal file
1
gall-app/src/css/indigo-static.css
Normal file
File diff suppressed because one or more lines are too long
21
gall-app/src/index.js
Normal file
21
gall-app/src/index.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { Root } from './js/components/root.js';
|
||||||
|
import { api } from './js/api.js';
|
||||||
|
import { subscription } from "./js/subscription.js";
|
||||||
|
|
||||||
|
import './css/indigo-static.css';
|
||||||
|
import './css/fonts.css';
|
||||||
|
import './css/custom.css';
|
||||||
|
|
||||||
|
api.setAuthTokens({
|
||||||
|
ship: window.ship
|
||||||
|
});
|
||||||
|
|
||||||
|
window.urb = new window.channel();
|
||||||
|
|
||||||
|
subscription.start();
|
||||||
|
|
||||||
|
ReactDOM.render((
|
||||||
|
<Root />
|
||||||
|
), document.querySelectorAll("#root")[0]);
|
47
gall-app/src/js/api.js
Normal file
47
gall-app/src/js/api.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
class UrbitApi {
|
||||||
|
setAuthTokens(authTokens) {
|
||||||
|
this.authTokens = authTokens;
|
||||||
|
this.bindPaths = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
bind(path, method, ship = this.authTokens.ship, appl = "browsermanager", success, fail) {
|
||||||
|
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||||
|
|
||||||
|
window.subscriptionId = window.urb.subscribe(ship, appl, path,
|
||||||
|
(err) => {
|
||||||
|
fail(err);
|
||||||
|
},
|
||||||
|
(event) => {
|
||||||
|
success({
|
||||||
|
data: event,
|
||||||
|
from: {
|
||||||
|
ship,
|
||||||
|
path
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
fail(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
browsermanager(data) {
|
||||||
|
this.action("browsermanager", "json", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
action(appl, mark, data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
window.urb.poke(ship, appl, mark, data,
|
||||||
|
(json) => {
|
||||||
|
resolve(json);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export let api = new UrbitApi();
|
||||||
|
window.api = api;
|
37
gall-app/src/js/components/lib/header-bar.js
Normal file
37
gall-app/src/js/components/lib/header-bar.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { Row, Box, Text, Icon } from '@tlon/indigo-react';
|
||||||
|
import { StatusBarItem } from './icons/StatusBarItem';
|
||||||
|
import { Sigil } from './icons/sigil';
|
||||||
|
|
||||||
|
|
||||||
|
const HeaderBar = (props) => {
|
||||||
|
|
||||||
|
const display = (!window.location.href.includes('popout/'))
|
||||||
|
? 'grid' : 'none';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
display={display}
|
||||||
|
width="100%"
|
||||||
|
gridTemplateRows="30px"
|
||||||
|
gridTemplateColumns="3fr 1fr"
|
||||||
|
py={2}
|
||||||
|
>
|
||||||
|
<Row collapse>
|
||||||
|
<StatusBarItem mr={2} onClick={() => window.location.href = '/'}>
|
||||||
|
<Icon icon='Home' color='black' />
|
||||||
|
</StatusBarItem>
|
||||||
|
</Row>
|
||||||
|
<Row justifyContent="flex-end" collapse>
|
||||||
|
<StatusBarItem onClick={() => window.location.href = '/~profile'}>
|
||||||
|
<Sigil ship={window.ship} size={24} color={"#000000"} classes="dib mix-blend-diff" />
|
||||||
|
<Text ml={2} display={["none", "inline"]} fontFamily="mono">~{window.ship}</Text>
|
||||||
|
</StatusBarItem>
|
||||||
|
</Row>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HeaderBar;
|
41
gall-app/src/js/components/lib/icons/StatusBarItem.js
Normal file
41
gall-app/src/js/components/lib/icons/StatusBarItem.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import { Row as _Row, Icon } from "@tlon/indigo-react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const Row = styled(_Row)`
|
||||||
|
cursor: pointer;
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export function StatusBarItem({
|
||||||
|
badge,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Row
|
||||||
|
position="relative"
|
||||||
|
collapse
|
||||||
|
border={1}
|
||||||
|
borderRadius={2}
|
||||||
|
color="washedGray"
|
||||||
|
bg="white"
|
||||||
|
alignItems="center"
|
||||||
|
py={1}
|
||||||
|
px={2}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{badge && (
|
||||||
|
<Icon
|
||||||
|
size="22px"
|
||||||
|
icon="Bullet"
|
||||||
|
fill="blue"
|
||||||
|
position="absolute"
|
||||||
|
top={"-10px"}
|
||||||
|
right={"-12px"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
9
gall-app/src/js/components/lib/icons/icon-spinner.js
Normal file
9
gall-app/src/js/components/lib/icons/icon-spinner.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
export class IconSpinner extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="spinner-pending"></div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
32
gall-app/src/js/components/lib/icons/sigil.js
Normal file
32
gall-app/src/js/components/lib/icons/sigil.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { sigil, reactRenderer } from 'urbit-sigil-js';
|
||||||
|
|
||||||
|
|
||||||
|
export class Sigil extends Component {
|
||||||
|
render() {
|
||||||
|
const { props } = this;
|
||||||
|
|
||||||
|
let classes = props.classes || "";
|
||||||
|
|
||||||
|
if (props.ship.length > 14) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={"bg-black dib " + classes}
|
||||||
|
style={{ width: props.size, height: props.size }}>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className={"dib " + classes} style={{ flexBasis: 32, backgroundColor: props.color }}>
|
||||||
|
{sigil({
|
||||||
|
patp: props.ship,
|
||||||
|
renderer: reactRenderer,
|
||||||
|
size: props.size,
|
||||||
|
colors: [props.color, "white"]
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
gall-app/src/js/components/root.js
Normal file
56
gall-app/src/js/components/root.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { BrowserRouter, Route } from "react-router-dom";
|
||||||
|
import _ from 'lodash';
|
||||||
|
import HeaderBar from "./lib/header-bar.js"
|
||||||
|
|
||||||
|
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
||||||
|
|
||||||
|
import light from './themes/light';
|
||||||
|
import dark from './themes/dark';
|
||||||
|
|
||||||
|
import { Text, Box } from '@tlon/indigo-react';
|
||||||
|
|
||||||
|
|
||||||
|
export class Root extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
dark: false
|
||||||
|
}
|
||||||
|
this.updateTheme = this.updateTheme.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTheme(updateTheme) {
|
||||||
|
this.setState({ dark: updateTheme });
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.themeWatcher = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
this.setState({ dark: this.themeWatcher.matches });
|
||||||
|
this.themeWatcher.addListener(this.updateTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BrowserRouter>
|
||||||
|
<ThemeProvider theme={this.state.dark ? dark : light}>
|
||||||
|
<Box display='flex' flexDirection='column' position='absolute' backgroundColor='white' height='100%' width='100%' px={[0,4]} pb={[0,4]}>
|
||||||
|
<HeaderBar/>
|
||||||
|
<Route exact path="/~browsermanager" render={ () => {
|
||||||
|
return (
|
||||||
|
<Box height='100%' p='4' display='flex' flexDirection='column' borderWidth={['none', '1px']} borderStyle="solid" borderColor="washedGray">
|
||||||
|
<Text fontSize='1'>browsermanager</Text>
|
||||||
|
<Text pt='3'>Welcome to your Landscape application.</Text>
|
||||||
|
<Text pt='3'>To get started, edit <code>src/index.js</code> or <code>urbit/app/browsermanager.hoon</code> and <code>|commit %home</code> on your Urbit ship to see your changes.</Text>
|
||||||
|
<a className="db f8 pt3" href="https://urbit.org/docs">-> Read the docs</a>
|
||||||
|
</Box>
|
||||||
|
)}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</ThemeProvider>
|
||||||
|
</BrowserRouter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
183
gall-app/src/js/components/themes/dark.js
Normal file
183
gall-app/src/js/components/themes/dark.js
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
import baseStyled from "styled-components";
|
||||||
|
|
||||||
|
const base = {
|
||||||
|
white: "rgba(255,255,255,1)",
|
||||||
|
black: "rgba(0,0,0,1)",
|
||||||
|
red: "rgba(255,65,54,1)",
|
||||||
|
yellow: "rgba(255,199,0,1)",
|
||||||
|
green: "rgba(0,159,101,1)",
|
||||||
|
blue: "rgba(0,142,255,1)",
|
||||||
|
};
|
||||||
|
|
||||||
|
const scales = {
|
||||||
|
white05: "rgba(255,255,255,0.05)",
|
||||||
|
white10: "rgba(255,255,255,0.1)",
|
||||||
|
white20: "rgba(255,255,255,0.2)",
|
||||||
|
white30: "rgba(255,255,255,0.3)",
|
||||||
|
white40: "rgba(255,255,255,0.4)",
|
||||||
|
white50: "rgba(255,255,255,0.5)",
|
||||||
|
white60: "rgba(255,255,255,0.6)",
|
||||||
|
white70: "rgba(255,255,255,0.7)",
|
||||||
|
white80: "rgba(255,255,255,0.8)",
|
||||||
|
white90: "rgba(255,255,255,0.9)",
|
||||||
|
white100: "rgba(255,255,255,1)",
|
||||||
|
black05: "rgba(0,0,0,0.05)",
|
||||||
|
black10: "rgba(0,0,0,0.1)",
|
||||||
|
black20: "rgba(0,0,0,0.2)",
|
||||||
|
black30: "rgba(0,0,0,0.3)",
|
||||||
|
black40: "rgba(0,0,0,0.4)",
|
||||||
|
black50: "rgba(0,0,0,0.5)",
|
||||||
|
black60: "rgba(0,0,0,0.6)",
|
||||||
|
black70: "rgba(0,0,0,0.7)",
|
||||||
|
black80: "rgba(0,0,0,0.8)",
|
||||||
|
black90: "rgba(0,0,0,0.9)",
|
||||||
|
black100: "rgba(0,0,0,1)",
|
||||||
|
red05: "rgba(255,65,54,0.05)",
|
||||||
|
red10: "rgba(255,65,54,0.1)",
|
||||||
|
red20: "rgba(255,65,54,0.2)",
|
||||||
|
red30: "rgba(255,65,54,0.3)",
|
||||||
|
red40: "rgba(255,65,54,0.4)",
|
||||||
|
red50: "rgba(255,65,54,0.5)",
|
||||||
|
red60: "rgba(255,65,54,0.6)",
|
||||||
|
red70: "rgba(255,65,54,0.7)",
|
||||||
|
red80: "rgba(255,65,54,0.8)",
|
||||||
|
red90: "rgba(255,65,54,0.9)",
|
||||||
|
red100: "rgba(255,65,54,1)",
|
||||||
|
yellow05: "rgba(255,199,0,0.05)",
|
||||||
|
yellow10: "rgba(255,199,0,0.1)",
|
||||||
|
yellow20: "rgba(255,199,0,0.2)",
|
||||||
|
yellow30: "rgba(255,199,0,0.3)",
|
||||||
|
yellow40: "rgba(255,199,0,0.4)",
|
||||||
|
yellow50: "rgba(255,199,0,0.5)",
|
||||||
|
yellow60: "rgba(255,199,0,0.6)",
|
||||||
|
yellow70: "rgba(255,199,0,0.7)",
|
||||||
|
yellow80: "rgba(255,199,0,0.8)",
|
||||||
|
yellow90: "rgba(255,199,0,0.9)",
|
||||||
|
yellow100: "rgba(255,199,0,1)",
|
||||||
|
green05: "rgba(0,159,101,0.05)",
|
||||||
|
green10: "rgba(0,159,101,0.1)",
|
||||||
|
green20: "rgba(0,159,101,0.2)",
|
||||||
|
green30: "rgba(0,159,101,0.3)",
|
||||||
|
green40: "rgba(0,159,101,0.4)",
|
||||||
|
green50: "rgba(0,159,101,0.5)",
|
||||||
|
green60: "rgba(0,159,101,0.6)",
|
||||||
|
green70: "rgba(0,159,101,0.7)",
|
||||||
|
green80: "rgba(0,159,101,0.8)",
|
||||||
|
green90: "rgba(0,159,101,0.9)",
|
||||||
|
green100: "rgba(0,159,101,1)",
|
||||||
|
blue05: "rgba(0,142,255,0.05)",
|
||||||
|
blue10: "rgba(0,142,255,0.1)",
|
||||||
|
blue20: "rgba(0,142,255,0.2)",
|
||||||
|
blue30: "rgba(0,142,255,0.3)",
|
||||||
|
blue40: "rgba(0,142,255,0.4)",
|
||||||
|
blue50: "rgba(0,142,255,0.5)",
|
||||||
|
blue60: "rgba(0,142,255,0.6)",
|
||||||
|
blue70: "rgba(0,142,255,0.7)",
|
||||||
|
blue80: "rgba(0,142,255,0.8)",
|
||||||
|
blue90: "rgba(0,142,255,0.9)",
|
||||||
|
blue100: "rgba(0,142,255,1)",
|
||||||
|
};
|
||||||
|
|
||||||
|
const util = {
|
||||||
|
cyan: "#00FFFF",
|
||||||
|
magenta: "#FF00FF",
|
||||||
|
yellow: "#FFFF00",
|
||||||
|
black: "#000000",
|
||||||
|
gray0: "#333333"
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = {
|
||||||
|
colors: {
|
||||||
|
white: util.gray0,
|
||||||
|
black: base.white,
|
||||||
|
|
||||||
|
gray: scales.white60,
|
||||||
|
lightGray: scales.white30,
|
||||||
|
washedGray: scales.white05,
|
||||||
|
|
||||||
|
red: base.red,
|
||||||
|
lightRed: scales.red30,
|
||||||
|
washedRed: scales.red05,
|
||||||
|
|
||||||
|
yellow: base.yellow,
|
||||||
|
lightYellow: scales.yellow30,
|
||||||
|
washedYellow: scales.yellow10,
|
||||||
|
|
||||||
|
green: base.green,
|
||||||
|
lightGreen: scales.green30,
|
||||||
|
washedGreen: scales.green10,
|
||||||
|
|
||||||
|
blue: base.blue,
|
||||||
|
lightBlue: scales.blue30,
|
||||||
|
washedBlue: scales.blue10,
|
||||||
|
|
||||||
|
none: "rgba(0,0,0,0)",
|
||||||
|
|
||||||
|
scales: scales,
|
||||||
|
util: util,
|
||||||
|
},
|
||||||
|
fonts: {
|
||||||
|
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||||
|
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||||
|
},
|
||||||
|
// font-size
|
||||||
|
fontSizes: [
|
||||||
|
12, // 0
|
||||||
|
16, // 1
|
||||||
|
24, // 2
|
||||||
|
32, // 3
|
||||||
|
48, // 4
|
||||||
|
64, // 5
|
||||||
|
],
|
||||||
|
// font-weight
|
||||||
|
fontWeights: {
|
||||||
|
thin: 300,
|
||||||
|
regular: 400,
|
||||||
|
bold: 600,
|
||||||
|
},
|
||||||
|
// line-height
|
||||||
|
lineHeights: {
|
||||||
|
min: 1.2,
|
||||||
|
short: 1.333333,
|
||||||
|
regular: 1.5,
|
||||||
|
tall: 1.666666,
|
||||||
|
},
|
||||||
|
// border, border-top, border-right, border-bottom, border-left
|
||||||
|
borders: ["none", "1px solid"],
|
||||||
|
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||||
|
space: [
|
||||||
|
0, // 0
|
||||||
|
4, // 1
|
||||||
|
8, // 2
|
||||||
|
16, // 3
|
||||||
|
24, // 4
|
||||||
|
32, // 5
|
||||||
|
48, // 6
|
||||||
|
64, // 7
|
||||||
|
96, // 8
|
||||||
|
],
|
||||||
|
// border-radius
|
||||||
|
radii: [
|
||||||
|
0, // 0
|
||||||
|
2, // 1
|
||||||
|
4, // 2
|
||||||
|
8, // 3
|
||||||
|
],
|
||||||
|
// width, height, min-width, max-width, min-height, max-height
|
||||||
|
sizes: [
|
||||||
|
0, // 0
|
||||||
|
4, // 1
|
||||||
|
8, // 2
|
||||||
|
16, // 3
|
||||||
|
24, // 4
|
||||||
|
32, // 5
|
||||||
|
48, // 6
|
||||||
|
64, // 7
|
||||||
|
96, // 8
|
||||||
|
],
|
||||||
|
// z-index
|
||||||
|
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||||
|
breakpoints: ["550px", "750px", "960px"],
|
||||||
|
};
|
||||||
|
export const styled = baseStyled;
|
||||||
|
export default theme;
|
168
gall-app/src/js/components/themes/light.js
Normal file
168
gall-app/src/js/components/themes/light.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
import baseStyled from "styled-components";
|
||||||
|
|
||||||
|
const base = {
|
||||||
|
white: "rgba(255,255,255,1)",
|
||||||
|
black: "rgba(0,0,0,1)",
|
||||||
|
red: "rgba(255,65,54,1)",
|
||||||
|
yellow: "rgba(255,199,0,1)",
|
||||||
|
green: "rgba(0,159,101,1)",
|
||||||
|
blue: "rgba(0,142,255,1)",
|
||||||
|
};
|
||||||
|
|
||||||
|
const scales = {
|
||||||
|
white10: "rgba(255,255,255,0.1)",
|
||||||
|
white20: "rgba(255,255,255,0.2)",
|
||||||
|
white30: "rgba(255,255,255,0.3)",
|
||||||
|
white40: "rgba(255,255,255,0.4)",
|
||||||
|
white50: "rgba(255,255,255,0.5)",
|
||||||
|
white60: "rgba(255,255,255,0.6)",
|
||||||
|
white70: "rgba(255,255,255,0.7)",
|
||||||
|
white80: "rgba(255,255,255,0.8)",
|
||||||
|
white90: "rgba(255,255,255,0.9)",
|
||||||
|
white100: "rgba(255,255,255,1)",
|
||||||
|
black10: "rgba(0,0,0,0.1)",
|
||||||
|
black20: "rgba(0,0,0,0.2)",
|
||||||
|
black30: "rgba(0,0,0,0.3)",
|
||||||
|
black40: "rgba(0,0,0,0.4)",
|
||||||
|
black50: "rgba(0,0,0,0.5)",
|
||||||
|
black60: "rgba(0,0,0,0.6)",
|
||||||
|
black70: "rgba(0,0,0,0.7)",
|
||||||
|
black80: "rgba(0,0,0,0.8)",
|
||||||
|
black90: "rgba(0,0,0,0.9)",
|
||||||
|
black100: "rgba(0,0,0,1)",
|
||||||
|
red10: "rgba(255,65,54,0.1)",
|
||||||
|
red20: "rgba(255,65,54,0.2)",
|
||||||
|
red30: "rgba(255,65,54,0.3)",
|
||||||
|
red40: "rgba(255,65,54,0.4)",
|
||||||
|
red50: "rgba(255,65,54,0.5)",
|
||||||
|
red60: "rgba(255,65,54,0.6)",
|
||||||
|
red70: "rgba(255,65,54,0.7)",
|
||||||
|
red80: "rgba(255,65,54,0.8)",
|
||||||
|
red90: "rgba(255,65,54,0.9)",
|
||||||
|
red100: "rgba(255,65,54,1)",
|
||||||
|
yellow10: "rgba(255,199,0,0.1)",
|
||||||
|
yellow20: "rgba(255,199,0,0.2)",
|
||||||
|
yellow30: "rgba(255,199,0,0.3)",
|
||||||
|
yellow40: "rgba(255,199,0,0.4)",
|
||||||
|
yellow50: "rgba(255,199,0,0.5)",
|
||||||
|
yellow60: "rgba(255,199,0,0.6)",
|
||||||
|
yellow70: "rgba(255,199,0,0.7)",
|
||||||
|
yellow80: "rgba(255,199,0,0.8)",
|
||||||
|
yellow90: "rgba(255,199,0,0.9)",
|
||||||
|
yellow100: "rgba(255,199,0,1)",
|
||||||
|
green10: "rgba(0,159,101,0.1)",
|
||||||
|
green20: "rgba(0,159,101,0.2)",
|
||||||
|
green30: "rgba(0,159,101,0.3)",
|
||||||
|
green40: "rgba(0,159,101,0.4)",
|
||||||
|
green50: "rgba(0,159,101,0.5)",
|
||||||
|
green60: "rgba(0,159,101,0.6)",
|
||||||
|
green70: "rgba(0,159,101,0.7)",
|
||||||
|
green80: "rgba(0,159,101,0.8)",
|
||||||
|
green90: "rgba(0,159,101,0.9)",
|
||||||
|
green100: "rgba(0,159,101,1)",
|
||||||
|
blue10: "rgba(0,142,255,0.1)",
|
||||||
|
blue20: "rgba(0,142,255,0.2)",
|
||||||
|
blue30: "rgba(0,142,255,0.3)",
|
||||||
|
blue40: "rgba(0,142,255,0.4)",
|
||||||
|
blue50: "rgba(0,142,255,0.5)",
|
||||||
|
blue60: "rgba(0,142,255,0.6)",
|
||||||
|
blue70: "rgba(0,142,255,0.7)",
|
||||||
|
blue80: "rgba(0,142,255,0.8)",
|
||||||
|
blue90: "rgba(0,142,255,0.9)",
|
||||||
|
blue100: "rgba(0,142,255,1)",
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = {
|
||||||
|
colors: {
|
||||||
|
white: base.white,
|
||||||
|
black: base.black,
|
||||||
|
|
||||||
|
gray: scales.black60,
|
||||||
|
lightGray: scales.black30,
|
||||||
|
washedGray: scales.black10,
|
||||||
|
|
||||||
|
red: base.red,
|
||||||
|
lightRed: scales.red30,
|
||||||
|
washedRed: scales.red10,
|
||||||
|
|
||||||
|
yellow: base.yellow,
|
||||||
|
lightYellow: scales.yellow30,
|
||||||
|
washedYellow: scales.yellow10,
|
||||||
|
|
||||||
|
green: base.green,
|
||||||
|
lightGreen: scales.green30,
|
||||||
|
washedGreen: scales.green10,
|
||||||
|
|
||||||
|
blue: base.blue,
|
||||||
|
lightBlue: scales.blue30,
|
||||||
|
washedBlue: scales.blue10,
|
||||||
|
|
||||||
|
none: "rgba(0,0,0,0)",
|
||||||
|
scales: scales,
|
||||||
|
},
|
||||||
|
fonts: {
|
||||||
|
sans: `"Inter", "Inter UI", -apple-system, BlinkMacSystemFont, 'San Francisco', 'Helvetica Neue', Arial, sans-serif`,
|
||||||
|
mono: `"Source Code Pro", "Roboto mono", "Courier New", monospace`,
|
||||||
|
},
|
||||||
|
// font-size
|
||||||
|
fontSizes: [
|
||||||
|
12, // 0
|
||||||
|
16, // 1
|
||||||
|
24, // 2
|
||||||
|
32, // 3
|
||||||
|
48, // 4
|
||||||
|
64, // 5
|
||||||
|
],
|
||||||
|
// font-weight
|
||||||
|
fontWeights: {
|
||||||
|
thin: 300,
|
||||||
|
regular: 400,
|
||||||
|
bold: 600,
|
||||||
|
},
|
||||||
|
// line-height
|
||||||
|
lineHeights: {
|
||||||
|
min: 1.2,
|
||||||
|
short: 1.333333,
|
||||||
|
regular: 1.5,
|
||||||
|
tall: 1.666666,
|
||||||
|
},
|
||||||
|
// border, border-top, border-right, border-bottom, border-left
|
||||||
|
borders: ["none", "1px solid"],
|
||||||
|
// margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap
|
||||||
|
space: [
|
||||||
|
0, // 0
|
||||||
|
4, // 1
|
||||||
|
8, // 2
|
||||||
|
16, // 3
|
||||||
|
24, // 4
|
||||||
|
32, // 5
|
||||||
|
48, // 6
|
||||||
|
64, // 7
|
||||||
|
96, // 8
|
||||||
|
],
|
||||||
|
// border-radius
|
||||||
|
radii: [
|
||||||
|
0, // 0
|
||||||
|
2, // 1
|
||||||
|
4, // 2
|
||||||
|
8, // 3
|
||||||
|
16, // 4
|
||||||
|
],
|
||||||
|
// width, height, min-width, max-width, min-height, max-height
|
||||||
|
sizes: [
|
||||||
|
0, // 0
|
||||||
|
4, // 1
|
||||||
|
8, // 2
|
||||||
|
16, // 3
|
||||||
|
24, // 4
|
||||||
|
32, // 5
|
||||||
|
48, // 6
|
||||||
|
64, // 7
|
||||||
|
96, // 8
|
||||||
|
],
|
||||||
|
// z-index
|
||||||
|
zIndices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||||
|
breakpoints: ["550px", "750px", "960px"],
|
||||||
|
};
|
||||||
|
export const styled = baseStyled;
|
||||||
|
export default theme;
|
82
gall-app/src/js/lib/util.js
Normal file
82
gall-app/src/js/lib/util.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
|
||||||
|
export function uuid() {
|
||||||
|
let str = "0v"
|
||||||
|
str += Math.ceil(Math.random()*8)+"."
|
||||||
|
for (var i = 0; i < 5; i++) {
|
||||||
|
let _str = Math.ceil(Math.random()*10000000).toString(32);
|
||||||
|
_str = ("00000"+_str).substr(-5,5);
|
||||||
|
str += _str+".";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.slice(0,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPatTa(str) {
|
||||||
|
const r = /^[a-z,0-9,\-,\.,_,~]+$/.exec(str)
|
||||||
|
return !!r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Goes from:
|
||||||
|
~2018.7.17..23.15.09..5be5 // urbit @da
|
||||||
|
To:
|
||||||
|
(javascript Date object)
|
||||||
|
*/
|
||||||
|
export function daToDate(st) {
|
||||||
|
var dub = function(n) {
|
||||||
|
return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString();
|
||||||
|
};
|
||||||
|
var da = st.split('..');
|
||||||
|
var bigEnd = da[0].split('.');
|
||||||
|
var lilEnd = da[1].split('.');
|
||||||
|
var ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub(lilEnd[0])}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`;
|
||||||
|
return new Date(ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Goes from:
|
||||||
|
(javascript Date object)
|
||||||
|
To:
|
||||||
|
~2018.7.17..23.15.09..5be5 // urbit @da
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function dateToDa(d, mil) {
|
||||||
|
var fil = function(n) {
|
||||||
|
return n >= 10 ? n : "0" + n;
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
`~${d.getUTCFullYear()}.` +
|
||||||
|
`${(d.getUTCMonth() + 1)}.` +
|
||||||
|
`${fil(d.getUTCDate())}..` +
|
||||||
|
`${fil(d.getUTCHours())}.` +
|
||||||
|
`${fil(d.getUTCMinutes())}.` +
|
||||||
|
`${fil(d.getUTCSeconds())}` +
|
||||||
|
`${mil ? "..0000" : ""}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deSig(ship) {
|
||||||
|
return ship.replace('~', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim patps to match dojo, chat-cli
|
||||||
|
export function cite(ship) {
|
||||||
|
let patp = ship, shortened = "";
|
||||||
|
if (patp.startsWith("~")) {
|
||||||
|
patp = patp.substr(1);
|
||||||
|
}
|
||||||
|
// comet
|
||||||
|
if (patp.length === 56) {
|
||||||
|
shortened = "~" + patp.slice(0, 6) + "_" + patp.slice(50, 56);
|
||||||
|
return shortened;
|
||||||
|
}
|
||||||
|
// moon
|
||||||
|
if (patp.length === 27) {
|
||||||
|
shortened = "~" + patp.slice(14, 20) + "^" + patp.slice(21, 27);
|
||||||
|
return shortened;
|
||||||
|
}
|
||||||
|
return `~${patp}`;
|
||||||
|
}
|
18
gall-app/src/js/reducers/initial.js
Normal file
18
gall-app/src/js/reducers/initial.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
|
export class InitialReducer {
|
||||||
|
/* if we get a diff from the app that looks like this:
|
||||||
|
|
||||||
|
{ initial: {}}
|
||||||
|
|
||||||
|
it will set the state to look like the contents of "initial"
|
||||||
|
|
||||||
|
*/
|
||||||
|
reduce(json, state) {
|
||||||
|
let data = _.get(json, 'initial', false);
|
||||||
|
if (data) {
|
||||||
|
state = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
gall-app/src/js/reducers/update.js
Normal file
26
gall-app/src/js/reducers/update.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
|
export class UpdateReducer {
|
||||||
|
|
||||||
|
/* If we get an incoming object like this:
|
||||||
|
|
||||||
|
{ update: {new: {}}}
|
||||||
|
|
||||||
|
It will replace the entire contents of the state with the incoming state enclosed in "new".
|
||||||
|
|
||||||
|
Feel free to amend the behaviour as necessary.
|
||||||
|
*/
|
||||||
|
reduce(json, state) {
|
||||||
|
let data = _.get(json, 'update', false);
|
||||||
|
if (data) {
|
||||||
|
this.reduceState(_.get(data, 'new', false), state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reduceState(incoming, state) {
|
||||||
|
if (incoming) {
|
||||||
|
state = incoming;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
gall-app/src/js/store.js
Normal file
37
gall-app/src/js/store.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { InitialReducer } from './reducers/initial';
|
||||||
|
import { UpdateReducer } from './reducers/update';
|
||||||
|
|
||||||
|
class Store {
|
||||||
|
|
||||||
|
/*
|
||||||
|
The store holds all state for the front-end. We initialise a subscription to the back-end through
|
||||||
|
subscription.js and then let the store class handle all incoming diffs, including the initial one
|
||||||
|
we get from subscribing to the back-end.
|
||||||
|
|
||||||
|
It's important that state be mutated and set in one place, so pipe changes through the handleEvent method.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.state = {};
|
||||||
|
|
||||||
|
this.initialReducer = new InitialReducer();
|
||||||
|
this.updateReducer = new UpdateReducer();
|
||||||
|
this.setState = () => { };
|
||||||
|
}
|
||||||
|
|
||||||
|
setStateHandler(setState) {
|
||||||
|
this.setState = setState;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent(data) {
|
||||||
|
let json = data.data;
|
||||||
|
|
||||||
|
console.log(json);
|
||||||
|
this.initialReducer.reduce(json, this.state);
|
||||||
|
this.updateReducer.reduce(json, this.state);
|
||||||
|
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export let store = new Store();
|
||||||
|
window.store = store;
|
36
gall-app/src/js/subscription.js
Normal file
36
gall-app/src/js/subscription.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { api } from './api';
|
||||||
|
import { store } from './store';
|
||||||
|
|
||||||
|
export class Subscription {
|
||||||
|
|
||||||
|
// uncomment the following code to start up a subscription on the '/' path
|
||||||
|
//
|
||||||
|
// see on-watch in your app's hoon file for behaviour
|
||||||
|
//
|
||||||
|
start() {
|
||||||
|
if (api.authTokens) {
|
||||||
|
// this.initializebrowsermanager();
|
||||||
|
} else {
|
||||||
|
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializebrowsermanager() {
|
||||||
|
// api.bind('/', 'PUT', api.authTokens.ship, 'browsermanager',
|
||||||
|
// this.handleEvent.bind(this),
|
||||||
|
// this.handleError.bind(this));
|
||||||
|
// }
|
||||||
|
|
||||||
|
handleEvent(diff) {
|
||||||
|
store.handleEvent(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(err) {
|
||||||
|
console.error(err);
|
||||||
|
api.bind('/', 'PUT', api.authTokens.ship, 'browsermanager',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export let subscription = new Subscription();
|
46
gall-app/urbit/app/browsermanager.hoon
Normal file
46
gall-app/urbit/app/browsermanager.hoon
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/+ *server, default-agent
|
||||||
|
::
|
||||||
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
|
--
|
||||||
|
^- agent:gall
|
||||||
|
|_ bol=bowl:gall
|
||||||
|
+* this .
|
||||||
|
browsermanager-core +>
|
||||||
|
cc ~(. browsermanager-core bol)
|
||||||
|
def ~(. (default-agent this %|) bol)
|
||||||
|
::
|
||||||
|
++ on-init
|
||||||
|
^- (quip card _this)
|
||||||
|
=/ launcha [%launch-action !>([%add %browsermanager [[%basic 'browsermanager' '/~browsermanager/img/tile.png' '/~browsermanager'] %.y]])]
|
||||||
|
=/ filea [%file-server-action !>([%serve-dir /'~browsermanager' /app/browsermanager %.n %.n])]
|
||||||
|
:_ this
|
||||||
|
:~ [%pass /srv %agent [our.bol %file-server] %poke filea]
|
||||||
|
[%pass /browsermanager %agent [our.bol %launch] %poke launcha]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ on-watch
|
||||||
|
|= =path
|
||||||
|
^- (quip card _this)
|
||||||
|
?: ?=([%http-response *] path)
|
||||||
|
`this
|
||||||
|
?. =(/ path)
|
||||||
|
(on-watch:def path)
|
||||||
|
[[%give %fact ~ %json !>(*json)]~ this]
|
||||||
|
::
|
||||||
|
++ on-agent on-agent:def
|
||||||
|
::
|
||||||
|
++ on-arvo
|
||||||
|
|= [=wire =sign-arvo]
|
||||||
|
^- (quip card _this)
|
||||||
|
?. ?=(%bound +<.sign-arvo)
|
||||||
|
(on-arvo:def wire sign-arvo)
|
||||||
|
[~ this]
|
||||||
|
::
|
||||||
|
++ on-poke on-poke:def
|
||||||
|
++ on-save on-save:def
|
||||||
|
++ on-load on-load:def
|
||||||
|
++ on-leave on-leave:def
|
||||||
|
++ on-peek on-peek:def
|
||||||
|
++ on-fail on-fail:def
|
||||||
|
--
|
BIN
gall-app/urbit/app/browsermanager/img/home.png
Normal file
BIN
gall-app/urbit/app/browsermanager/img/home.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 679 B |
BIN
gall-app/urbit/app/browsermanager/img/tile.png
Normal file
BIN
gall-app/urbit/app/browsermanager/img/tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
15
gall-app/urbit/app/browsermanager/index.html
Normal file
15
gall-app/urbit/app/browsermanager/index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>browsermanager</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" />
|
||||||
|
<script src="/~landscape/js/channel.js"></script>
|
||||||
|
<script src="/~landscape/js/session.js"></script>
|
||||||
|
<script src="/~browsermanager/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
81333
gall-app/urbit/app/browsermanager/js/index.js
Normal file
81333
gall-app/urbit/app/browsermanager/js/index.js
Normal file
File diff suppressed because one or more lines are too long
118
gall-app/webpack.dev.js
Normal file
118
gall-app/webpack.dev.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
const path = require('path');
|
||||||
|
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
const urbitrc = require('./.urbitrc');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
|
function copy(src,dest) {
|
||||||
|
return new Promise((res,rej) =>
|
||||||
|
fs.copy(src,dest, err => err ? rej(err) : res()));
|
||||||
|
}
|
||||||
|
|
||||||
|
class UrbitShipPlugin {
|
||||||
|
constructor(urbitrc) {
|
||||||
|
this.piers = urbitrc.URBIT_PIERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.afterEmit.tapPromise(
|
||||||
|
'UrbitShipPlugin',
|
||||||
|
async (compilation) => {
|
||||||
|
const src = './urbit/app'
|
||||||
|
|
||||||
|
return Promise.all(this.piers.map(pier => {
|
||||||
|
const dst = path.resolve(pier, 'app');
|
||||||
|
copy(src, dst).then(() => {
|
||||||
|
pier = pier.split('/');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let devServer = {
|
||||||
|
contentBase: path.resolve('./urbit/app/browsermanager/js'),
|
||||||
|
hot: true,
|
||||||
|
port: 9000,
|
||||||
|
historyApiFallback: true,
|
||||||
|
writeToDisk: (filePath) => {
|
||||||
|
return /index.js$/.test(filePath);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(urbitrc.URL) {
|
||||||
|
devServer = {
|
||||||
|
...devServer,
|
||||||
|
index: '',
|
||||||
|
proxy: {
|
||||||
|
'/~browsermanager/js/index.js': {
|
||||||
|
target: 'http://localhost:9000',
|
||||||
|
pathRewrite: (req, path) => '/index.js'
|
||||||
|
},
|
||||||
|
'**': {
|
||||||
|
target: urbitrc.URL,
|
||||||
|
// ensure proxy doesn't timeout channels
|
||||||
|
proxyTimeout: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'development',
|
||||||
|
entry: {
|
||||||
|
app: './src/index.js'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||||
|
plugins: [
|
||||||
|
'@babel/transform-runtime',
|
||||||
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
'react-hot-loader/babel'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [
|
||||||
|
// Creates `style` nodes from JS strings
|
||||||
|
'style-loader',
|
||||||
|
// Translates CSS into CommonJS
|
||||||
|
'css-loader',
|
||||||
|
// Compiles Sass to CSS
|
||||||
|
'sass-loader'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js']
|
||||||
|
},
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
devServer: devServer,
|
||||||
|
plugins: [
|
||||||
|
new UrbitShipPlugin(urbitrc)
|
||||||
|
],
|
||||||
|
watch: true,
|
||||||
|
output: {
|
||||||
|
filename: 'index.js',
|
||||||
|
chunkFilename: 'index.js',
|
||||||
|
path: path.resolve('./urbit/app/browsermanager/js'),
|
||||||
|
publicPath: '/'
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: false,
|
||||||
|
usedExports: true
|
||||||
|
}
|
||||||
|
};
|
57
gall-app/webpack.prod.js
Normal file
57
gall-app/webpack.prod.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
const urbitrc = require('./.urbitrc');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: {
|
||||||
|
app: './src/index.js'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||||
|
plugins: [
|
||||||
|
'@babel/transform-runtime',
|
||||||
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
|
'@babel/plugin-proposal-class-properties'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [
|
||||||
|
// Creates `style` nodes from JS strings
|
||||||
|
'style-loader',
|
||||||
|
// Translates CSS into CommonJS
|
||||||
|
'css-loader',
|
||||||
|
// Compiles Sass to CSS
|
||||||
|
'sass-loader'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js']
|
||||||
|
},
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin()
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
filename: 'index.js',
|
||||||
|
path: path.resolve(__dirname, `${urbitrc.URBIT_PIERS[0]}/app/browsermanager/js`),
|
||||||
|
publicPath: '/',
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: true,
|
||||||
|
usedExports: true
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user