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