Compare commits
3 Commits
master
...
db9e8acb5b
Author | SHA1 | Date | |
---|---|---|---|
|
db9e8acb5b | ||
|
b3802eba76 | ||
|
ceed2be120 |
2
.urbitrc
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
URBIT_PIERS: [
|
||||
"%URBITPIER%",
|
||||
"/home/greg/code/zod/home",
|
||||
]
|
||||
};
|
||||
|
51
README.md
@ -1,50 +1,5 @@
|
||||
Get started building a simple application for Landscape on your [Urbit](http://urbit.org) ship with a few commands.
|
||||
BART runner app for [Urbit](http://urbit.org).
|
||||
|
||||
This tool is experimental and primarily used internally to develop front-end applications. While Tlon does not officially support this tool, you can always get general programming help for Urbit in the `~dopzod/urbit-help` chat.
|
||||
The Bart App Map was created by Trucy Phan (https://github.com/trucy/bart-map) and is used under
|
||||
the terms of the Creative Commons Attribution 3.0 Unported License.
|
||||
|
||||
## Installation
|
||||
|
||||
This repository is available as a template; to immediately generate your application's repository you can click [here](https://github.com/urbit/create-landscape-app/generate). Clone the generated repository, `npm install` and then run `npm start` to get started (you can also directly clone this repository, if you wish!).
|
||||
|
||||
In order to run your application on your ship, you will need Urbit v.0.10.0 or higher. On your Urbit ship, if you haven't already, mount your pier to Unix with `|mount %`.
|
||||
|
||||
## Using
|
||||
|
||||
Once you're up and running, your tile lives in `tile/tile.js`, which uses [React](https://reactjs.org) to render itself -- you'll want a basic foothold with it first. When you make changes, the `urbit` directory will update with the compiled application and, if you're running `npm run serve`, it will automatically copy itself to your Urbit ship when you save your changes (more information on that below).
|
||||
|
||||
### `npm start`
|
||||
|
||||
This runs the wizard. Give it an application name and the location of your Urbit ship's desk and it will customise the files so your new application will run on your ship.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
This builds your application and copies it into your Urbit ship's desk. In your Urbit (v.0.8.0 or higher) `|commit %home` (or `%your-desk-name`) to synchronise your changes.
|
||||
|
||||
If this is the first time you're running your application on your Urbit ship, don't forget to `|start %yourapp`.
|
||||
|
||||
### `npm run serve`
|
||||
|
||||
Builds the application and copies it into your Urbit ship's desk, watching for changes. In your Urbit (v.0.8.0 or higher) `|commit %home` (or `%your-desk-name`) to synchronise your changes.
|
||||
|
||||
## FAQ
|
||||
|
||||
### What is a "tile" vs. "full" app?
|
||||
|
||||
When you run `npm run start`, the wizard will ask you to specify which you want:
|
||||
|
||||
- **tile**: A tile that exists on the Landscape launch screen. A pre-existing example is the "Weather" tile or the "Clock" tile in Landscape.
|
||||
- **full**: A tile that links to a full-screen application: this means that you will work in both `tile.js` (for the tile interface) and `root.js` (and beyond) in the `src` folder.
|
||||
|
||||
No matter which option you specify, the wizard will customise the Hoon boilerplate for you and provide a basic example accordingly.
|
||||
|
||||
### How can I ensure my app fits Landscape design?
|
||||
|
||||
Landscape makes use of the [Indigo](https://urbit.github.io/indigo-react/) CSS framework. The template tile and full application both make use of it as an example for you to get going fast.
|
||||
|
||||
### What if I want to communicate with my ship / provide more functionality besides a front-end?
|
||||
|
||||
By default, your app will provide an example of passing state from ship to front-end with the `peer-[yourappname]tile` arm in the app's .hoon file -- in this case, just sending your ship's name as a data prop. The code is well-commented if you don't want to pass state, or if you want to know how to pass almost anything else from your ship to the Landscape interface.
|
||||
|
||||
In order to do anything substantial, of course, you'll want to know [Hoon](https://urbit.org/docs/tutorials/hoon/). If this is intimidating, don't panic: `create-landscape-app` is a fantastic way to start learning by leveraging your strengths. This repository is intended to be a boilerplate for rapid front-end development; it's also a gradual, incremental introduction to Hoon for web developers by allowing for rapid prototyping and experimentation with the Landscape interface.
|
||||
|
||||
Happy hacking!
|
||||
|
16
dist/index.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/index.js";import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Root } from '/components/root';
|
||||
import { api } from '/api';
|
||||
import { store } from '/store';
|
||||
import { subscription } from "/subscription";
|
||||
|
||||
api.setAuthTokens({
|
||||
ship: window.ship
|
||||
});
|
||||
|
||||
subscription.start();
|
||||
|
||||
ReactDOM.render((
|
||||
React.createElement(Root, {__self: this, __source: {fileName: _jsxFileName, lineNumber: 15}} )
|
||||
), document.querySelectorAll("#root")[0]);
|
6
full/src/js/api.js → dist/js/api.js
vendored
@ -8,7 +8,7 @@ class UrbitApi {
|
||||
this.bindPaths = [];
|
||||
}
|
||||
|
||||
bind(path, method, ship = this.authTokens.ship, appl = "%APPNAME%", success, fail) {
|
||||
bind(path, method, ship = this.authTokens.ship, appl = "barttile", success, fail) {
|
||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||
|
||||
window.subscriptionId = window.urb.subscribe(ship, appl, path,
|
||||
@ -29,8 +29,8 @@ class UrbitApi {
|
||||
});
|
||||
}
|
||||
|
||||
%APPNAME%(data) {
|
||||
this.action("%APPNAME%", "json", data);
|
||||
barttile(data) {
|
||||
this.action("barttile", "json", data);
|
||||
}
|
||||
|
||||
action(appl, mark, data) {
|
48
dist/js/components/lib/header-bar.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/js/components/lib/header-bar.js";import React, { Component } from "react";
|
||||
import { cite } from '../../lib/util';
|
||||
import { IconHome } from "/components/lib/icons/icon-home";
|
||||
import { Sigil } from "/components/lib/icons/sigil";
|
||||
|
||||
export class HeaderBar extends Component {
|
||||
render() {
|
||||
|
||||
let title = document.title === "Home" ? "" : document.title;
|
||||
|
||||
return (
|
||||
React.createElement('div', {
|
||||
className:
|
||||
"bg-white bg-gray0-d w-100 justify-between relative tc pt3 db"
|
||||
,
|
||||
style: { height: 40 }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 12}}
|
||||
, React.createElement('a', {
|
||||
className: "dib gray2 f9 inter absolute left-0" ,
|
||||
href: "/",
|
||||
style: { top: 14 }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 17}}
|
||||
, React.createElement(IconHome, {__self: this, __source: {fileName: _jsxFileName, lineNumber: 21}})
|
||||
, React.createElement('span', {
|
||||
className: "ml2 white-d v-top lh-title" ,
|
||||
style: { paddingTop: 3 }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 22}}, "Home"
|
||||
|
||||
)
|
||||
)
|
||||
, React.createElement('span', {
|
||||
className: "f9 white-d inter dib" ,
|
||||
style: {
|
||||
verticalAlign: "text-top",
|
||||
paddingTop: 3
|
||||
}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 28}}
|
||||
, title
|
||||
)
|
||||
, React.createElement('div', { className: "absolute right-0 lh-copy" , style: { top: 8 }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 36}}
|
||||
, React.createElement(Sigil, {
|
||||
ship: "~" + window.ship,
|
||||
classes: "v-mid mix-blend-diff" ,
|
||||
size: 16,
|
||||
color: "#000000", __self: this, __source: {fileName: _jsxFileName, lineNumber: 37}}
|
||||
)
|
||||
, React.createElement('span', { className: "mono white-d f9 ml2 c-default" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 43}}, cite(window.ship))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
15
dist/js/components/lib/icons/icon-home.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/js/components/lib/icons/icon-home.js";import React, { Component } from "react";
|
||||
|
||||
export class IconHome extends Component {
|
||||
render() {
|
||||
let classes = !!this.props.classes ? this.props.classes : "";
|
||||
return (
|
||||
React.createElement('img', {
|
||||
className: "invert-d " + classes,
|
||||
src: "/~barttile/img/Home.png",
|
||||
width: 16,
|
||||
height: 16, __self: this, __source: {fileName: _jsxFileName, lineNumber: 7}}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
9
dist/js/components/lib/icons/icon-spinner.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/js/components/lib/icons/icon-spinner.js";import React, { Component } from 'react';
|
||||
|
||||
export class IconSpinner extends Component {
|
||||
render() {
|
||||
return (
|
||||
React.createElement('div', { className: "spinner-pending", __self: this, __source: {fileName: _jsxFileName, lineNumber: 6}})
|
||||
);
|
||||
}
|
||||
}
|
32
dist/js/components/lib/icons/sigil.js
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/js/components/lib/icons/sigil.js";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 (
|
||||
React.createElement('div', {
|
||||
className: "bg-black dib " + classes,
|
||||
style: { width: props.size, height: props.size }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 13}}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
React.createElement('div', { className: "dib " + classes, style: { flexBasis: 32, backgroundColor: props.color }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 20}}
|
||||
, sigil({
|
||||
patp: props.ship,
|
||||
renderer: reactRenderer,
|
||||
size: props.size,
|
||||
colors: [props.color, "white"]
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
dist/js/components/root.js
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/src/js/components/root.js";import React, { Component } from 'react';
|
||||
import { BrowserRouter, Route } from "react-router-dom";
|
||||
import _ from 'lodash';
|
||||
import { HeaderBar } from "./lib/header-bar.js"
|
||||
|
||||
|
||||
export class Root extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
React.createElement(BrowserRouter, {__self: this, __source: {fileName: _jsxFileName, lineNumber: 15}}
|
||||
, React.createElement('div', { className: "absolute h-100 w-100 bg-gray0-d ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 16}}
|
||||
, React.createElement(HeaderBar, {__self: this, __source: {fileName: _jsxFileName, lineNumber: 17}})
|
||||
, React.createElement(Route, { exact: true, path: "/~barttile", render: () => {
|
||||
return (
|
||||
React.createElement('div', { className: "cf w-100 flex flex-column pa4 ba-m ba-l ba-xl b--gray2 br1 h-100 h-100-minus-40-s h-100-minus-40-m h-100-minus-40-l h-100-minus-40-xl f9 white-d overflow-x-hidden" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 20}}
|
||||
, React.createElement('h1', { className: "mt0 f8 fw4" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 21}}, "BART Info" )
|
||||
, React.createElement('div', { style: {display: "grid", gridTemplateColumns: "66% 34%", gridGap: "10px" }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 22}}
|
||||
, React.createElement('div', { className: "topinfo", style: {gridColumn: "1 / 2"}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 23}}
|
||||
, React.createElement('p', { className: "lh-copy measure pt3" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 24}}, "Current time is (current time)" )
|
||||
, React.createElement('p', { className: "lh-copy measure pt3" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 25}}, "Today's bart map:" )
|
||||
)
|
||||
, React.createElement('div', { className: "map", style: {gridColumn: "1", gridRow: "2"}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 27}}
|
||||
, React.createElement('img', { src: "/~barttile/img/BART-Map-Weekday-Saturday.png", __self: this, __source: {fileName: _jsxFileName, lineNumber: 28}} )
|
||||
)
|
||||
, React.createElement('div', { className: "searchsidebar", style: {gridColumn: "2", gridRow: "2"}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 30}}, "Search stuff here"
|
||||
|
||||
)
|
||||
)
|
||||
)
|
||||
)}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 18}}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import _ from 'lodash';
|
||||
|
||||
export class ConfigReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, '%APPNAME%', false);
|
||||
let data = _.get(json, 'barttile', false);
|
||||
if (data) {
|
||||
state.inbox = data.inbox;
|
||||
}
|
0
full/src/js/store.js → dist/js/store.js
vendored
@ -7,14 +7,14 @@ import urbitOb from 'urbit-ob';
|
||||
export class Subscription {
|
||||
start() {
|
||||
if (api.authTokens) {
|
||||
// this.initialize%APPNAME%();
|
||||
// this.initializebarttile();
|
||||
} else {
|
||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||
}
|
||||
}
|
||||
|
||||
// initialize%APPNAME%() {
|
||||
// api.bind('/primary', 'PUT', api.authTokens.ship, '%APPNAME%',
|
||||
// initializebarttile() {
|
||||
// api.bind('/primary', 'PUT', api.authTokens.ship, 'barttile',
|
||||
// this.handleEvent.bind(this),
|
||||
// this.handleError.bind(this));
|
||||
// }
|
||||
@ -25,7 +25,7 @@ export class Subscription {
|
||||
|
||||
handleError(err) {
|
||||
console.error(err);
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, '%APPNAME%',
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'barttile',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
20
dist/tile.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
const _jsxFileName = "/home/greg/code/bart-tile/tile/tile.js";import React, { Component } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export default class barttileTile extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
React.createElement('div', { className: "w-100 h-100 relative bg-white bg-gray0-d ba b--black b--gray1-d" , __self: this, __source: {fileName: _jsxFileName, lineNumber: 9}}
|
||||
, React.createElement('a', { className: "w-100 h-100 db pa2 no-underline" , href: "/~barttile", __self: this, __source: {fileName: _jsxFileName, lineNumber: 10}}
|
||||
, React.createElement('p', { className: "black white-d absolute f9" , style: { left: 8, top: 8 }, __self: this, __source: {fileName: _jsxFileName, lineNumber: 11}}, "BART")
|
||||
, React.createElement('img', { className: "absolute", src: "/~barttile/img/Temp-Bart-Icon.png", style: {top: 40, left: 20, width: "50%"}, __self: this, __source: {fileName: _jsxFileName, lineNumber: 12}})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.barttileTile = barttileTile;
|
164
full/gulpfile.js
@ -1,164 +0,0 @@
|
||||
var gulp = require('gulp');
|
||||
var cssimport = require('gulp-cssimport');
|
||||
var rollup = require('gulp-better-rollup');
|
||||
var cssnano = require('cssnano');
|
||||
var postcss = require('gulp-postcss');
|
||||
var sucrase = require('@sucrase/gulp-plugin');
|
||||
var minify = require('gulp-minify');
|
||||
|
||||
var resolve = require('rollup-plugin-node-resolve');
|
||||
var commonjs = require('rollup-plugin-commonjs');
|
||||
var rootImport = require('rollup-plugin-root-import');
|
||||
var globals = require('rollup-plugin-node-globals');
|
||||
|
||||
/***
|
||||
Main config options
|
||||
***/
|
||||
|
||||
var urbitrc = require('./.urbitrc');
|
||||
|
||||
/***
|
||||
End main config options
|
||||
***/
|
||||
|
||||
gulp.task('css-bundle', function() {
|
||||
let plugins = [
|
||||
cssnano()
|
||||
];
|
||||
return gulp
|
||||
.src('src/index.css')
|
||||
.pipe(cssimport())
|
||||
.pipe(postcss(plugins))
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/css'));
|
||||
});
|
||||
|
||||
gulp.task('jsx-transform', function(cb) {
|
||||
return gulp.src('src/**/*.js')
|
||||
.pipe(sucrase({
|
||||
transforms: ['jsx']
|
||||
}))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('tile-jsx-transform', function(cb) {
|
||||
return gulp.src('tile/**/*.js')
|
||||
.pipe(sucrase({
|
||||
transforms: ['jsx']
|
||||
}))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('js-imports', function(cb) {
|
||||
return gulp.src('dist/index.js')
|
||||
.pipe(rollup({
|
||||
plugins: [
|
||||
commonjs({
|
||||
namedExports: {
|
||||
'node_modules/react/index.js': [ 'Component' ],
|
||||
'node_modules/react-is/index.js': [ 'isValidElementType' ],
|
||||
}
|
||||
}),
|
||||
rootImport({
|
||||
root: `${__dirname}/dist/js`,
|
||||
useEntry: 'prepend',
|
||||
extensions: '.js'
|
||||
}),
|
||||
globals(),
|
||||
resolve()
|
||||
]
|
||||
}, 'umd'))
|
||||
.on('error', function(e){
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
gulp.task('tile-js-imports', function(cb) {
|
||||
return gulp.src('dist/tile.js')
|
||||
.pipe(rollup({
|
||||
plugins: [
|
||||
commonjs({
|
||||
namedExports: {
|
||||
'node_modules/react/index.js': [ 'Component' ],
|
||||
}
|
||||
}),
|
||||
rootImport({
|
||||
root: `${__dirname}/dist/js`,
|
||||
useEntry: 'prepend',
|
||||
extensions: '.js'
|
||||
}),
|
||||
globals(),
|
||||
resolve()
|
||||
]
|
||||
}, 'umd'))
|
||||
.on('error', function(e){
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('js-minify', function () {
|
||||
return gulp.src('./urbit/app/%APPNAME%/js/index.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'));
|
||||
});
|
||||
|
||||
gulp.task('tile-js-minify', function () {
|
||||
return gulp.src('./urbit/app/%APPNAME%/js/tile.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'));
|
||||
});
|
||||
|
||||
gulp.task('urbit-copy', function () {
|
||||
let ret = gulp.src('urbit/**/*');
|
||||
|
||||
urbitrc.URBIT_PIERS.forEach(function(pier) {
|
||||
ret = ret.pipe(gulp.dest(pier));
|
||||
});
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports'));
|
||||
gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports'));
|
||||
gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify'))
|
||||
gulp.task('tile-js-bundle-prod',
|
||||
gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify'));
|
||||
|
||||
gulp.task('bundle-dev',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-dev',
|
||||
'tile-js-bundle-dev'
|
||||
),
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('bundle-prod',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-prod',
|
||||
'tile-js-bundle-prod',
|
||||
),
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('default', gulp.series('bundle-dev'));
|
||||
|
||||
gulp.task('watch', gulp.series('default', function() {
|
||||
gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev'));
|
||||
|
||||
gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev'));
|
||||
gulp.watch('src/**/*.css', gulp.parallel('css-bundle'));
|
||||
|
||||
gulp.watch('urbit/**/*', gulp.parallel('urbit-copy'));
|
||||
}));
|
@ -1,33 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { BrowserRouter, Route } from "react-router-dom";
|
||||
import _ from 'lodash';
|
||||
import { HeaderBar } from "./lib/header-bar.js"
|
||||
|
||||
|
||||
export class Root extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className="absolute h-100 w-100 bg-gray0-d ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl">
|
||||
<HeaderBar/>
|
||||
<Route exact path="/~%APPNAME%" render={ () => {
|
||||
return (
|
||||
<div className="cf w-100 flex flex-column pa4 ba-m ba-l ba-xl b--gray2 br1 h-100 h-100-minus-40-s h-100-minus-40-m h-100-minus-40-l h-100-minus-40-xl f9 white-d overflow-x-hidden">
|
||||
<h1 className="mt0 f8 fw4">%APPNAME%</h1>
|
||||
<p className="lh-copy measure pt3">Welcome to your Landscape application.</p>
|
||||
<p className="lh-copy measure pt3">To get started, edit <code>src/index.js</code>, <code>tile/tile.js</code> or <code>urbit/app/%APPNAME%.hoon</code> and <code>|commit %home</code> on your Urbit ship to see your changes.</p>
|
||||
<a className="black no-underline db f8 pt3" href="https://urbit.org/docs">-> Read the docs</a>
|
||||
</div>
|
||||
)}}
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export default class %APPNAME%Tile extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="w-100 h-100 relative bg-white bg-gray0-d ba b--black b--gray1-d">
|
||||
<a className="w-100 h-100 db pa2 no-underline" href="/~%APPNAME%">
|
||||
<p className="black white-d absolute f9" style={{ left: 8, top: 8 }}>%APPNAME%</p>
|
||||
<img className="absolute" src="/~%APPNAME%/img/Tile.png" style={{top: 39, left: 39}}/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.%APPNAME%Tile = %APPNAME%Tile;
|
94
gulpfile.js
@ -1,5 +1,8 @@
|
||||
var gulp = require('gulp');
|
||||
var cssimport = require('gulp-cssimport');
|
||||
var rollup = require('gulp-better-rollup');
|
||||
var cssnano = require('cssnano');
|
||||
var postcss = require('gulp-postcss');
|
||||
var sucrase = require('@sucrase/gulp-plugin');
|
||||
var minify = require('gulp-minify');
|
||||
|
||||
@ -18,6 +21,25 @@ var urbitrc = require('./.urbitrc');
|
||||
End main config options
|
||||
***/
|
||||
|
||||
gulp.task('css-bundle', function() {
|
||||
let plugins = [
|
||||
cssnano()
|
||||
];
|
||||
return gulp
|
||||
.src('src/index.css')
|
||||
.pipe(cssimport())
|
||||
.pipe(postcss(plugins))
|
||||
.pipe(gulp.dest('./urbit/app/barttile/css'));
|
||||
});
|
||||
|
||||
gulp.task('jsx-transform', function(cb) {
|
||||
return gulp.src('src/**/*.js')
|
||||
.pipe(sucrase({
|
||||
transforms: ['jsx']
|
||||
}))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('tile-jsx-transform', function(cb) {
|
||||
return gulp.src('tile/**/*.js')
|
||||
.pipe(sucrase({
|
||||
@ -26,6 +48,32 @@ gulp.task('tile-jsx-transform', function(cb) {
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('js-imports', function(cb) {
|
||||
return gulp.src('dist/index.js')
|
||||
.pipe(rollup({
|
||||
plugins: [
|
||||
commonjs({
|
||||
namedExports: {
|
||||
'node_modules/react/index.js': [ 'Component' ],
|
||||
'node_modules/react-is/index.js': [ 'isValidElementType' ],
|
||||
}
|
||||
}),
|
||||
rootImport({
|
||||
root: `${__dirname}/dist/js`,
|
||||
useEntry: 'prepend',
|
||||
extensions: '.js'
|
||||
}),
|
||||
globals(),
|
||||
resolve()
|
||||
]
|
||||
}, 'umd'))
|
||||
.on('error', function(e){
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('./urbit/app/barttile/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
gulp.task('tile-js-imports', function(cb) {
|
||||
return gulp.src('dist/tile.js')
|
||||
@ -49,14 +97,21 @@ gulp.task('tile-js-imports', function(cb) {
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'))
|
||||
.pipe(gulp.dest('./urbit/app/barttile/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
gulp.task('tile-js-minify', function () {
|
||||
return gulp.src('./urbit/app/%APPNAME%/js/tile.js')
|
||||
|
||||
gulp.task('js-minify', function () {
|
||||
return gulp.src('./urbit/app/barttile/js/index.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('./urbit/app/%APPNAME%/js/'));
|
||||
.pipe(gulp.dest('./urbit/app/barttile/js/'));
|
||||
});
|
||||
|
||||
gulp.task('tile-js-minify', function () {
|
||||
return gulp.src('./urbit/app/barttile/js/tile.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('./urbit/app/barttile/js/'));
|
||||
});
|
||||
|
||||
gulp.task('urbit-copy', function () {
|
||||
@ -69,14 +124,41 @@ gulp.task('urbit-copy', function () {
|
||||
return ret;
|
||||
});
|
||||
|
||||
gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports'));
|
||||
gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports'));
|
||||
gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify'))
|
||||
gulp.task('tile-js-bundle-prod',
|
||||
gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify'));
|
||||
|
||||
gulp.task('bundle-prod', gulp.series('tile-js-bundle-prod', 'urbit-copy'));
|
||||
gulp.task('bundle-dev',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-dev',
|
||||
'tile-js-bundle-dev'
|
||||
),
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('bundle-prod',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-prod',
|
||||
'tile-js-bundle-prod',
|
||||
),
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('default', gulp.series('bundle-dev'));
|
||||
|
||||
gulp.task('default', gulp.series('tile-js-bundle-dev', 'urbit-copy'));
|
||||
gulp.task('watch', gulp.series('default', function() {
|
||||
gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev'));
|
||||
|
||||
gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev'));
|
||||
gulp.watch('src/**/*.css', gulp.parallel('css-bundle'));
|
||||
|
||||
gulp.watch('urbit/**/*', gulp.parallel('urbit-copy'));
|
||||
}));
|
||||
|
52
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-landscape-app",
|
||||
"version": "2.0.0",
|
||||
"version": "3.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -401,7 +401,8 @@
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1480,7 +1481,8 @@
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@ -1643,7 +1645,8 @@
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@ -1664,12 +1667,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@ -1684,17 +1689,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@ -1811,7 +1819,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@ -1823,6 +1832,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@ -1837,6 +1847,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@ -1844,12 +1855,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@ -1868,6 +1881,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@ -1948,7 +1962,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@ -1960,6 +1975,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@ -2045,7 +2061,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@ -2081,6 +2098,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@ -2100,6 +2118,7 @@
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@ -2143,12 +2162,14 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -5185,7 +5206,8 @@
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
49
src/js/api.js
Normal file
@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
|
||||
class UrbitApi {
|
||||
setAuthTokens(authTokens) {
|
||||
this.authTokens = authTokens;
|
||||
this.bindPaths = [];
|
||||
}
|
||||
|
||||
bind(path, method, ship = this.authTokens.ship, appl = "barttile", 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);
|
||||
});
|
||||
}
|
||||
|
||||
barttile(data) {
|
||||
this.action("barttile", "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;
|
@ -6,7 +6,7 @@ export class IconHome extends Component {
|
||||
return (
|
||||
<img
|
||||
className={"invert-d " + classes}
|
||||
src="/~%APPNAME%/img/Home.png"
|
||||
src="/~barttile/img/Home.png"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
42
src/js/components/root.js
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { Component } from 'react';
|
||||
import { BrowserRouter, Route } from "react-router-dom";
|
||||
import _ from 'lodash';
|
||||
import { HeaderBar } from "./lib/header-bar.js"
|
||||
|
||||
|
||||
export class Root extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className="absolute h-100 w-100 bg-gray0-d ph4-m ph4-l ph4-xl pb4-m pb4-l pb4-xl">
|
||||
<HeaderBar/>
|
||||
<Route exact path="/~barttile" render={ () => {
|
||||
return (
|
||||
<div className="cf w-100 flex flex-column pa4 ba-m ba-l ba-xl b--gray2 br1 h-100 h-100-minus-40-s h-100-minus-40-m h-100-minus-40-l h-100-minus-40-xl f9 white-d overflow-x-hidden">
|
||||
<h1 className="mt0 f8 fw4">BART Info</h1>
|
||||
<div style={{display: "grid", gridTemplateColumns: "66% 34%", gridGap: "10px" }}>
|
||||
<div className="topinfo" style={{gridColumn: "1 / 2"}}>
|
||||
<p className="lh-copy measure pt3">Current time is (current time)</p>
|
||||
<p className="lh-copy measure pt3">Today's bart map:</p>
|
||||
</div>
|
||||
<div className="map" style={{gridColumn: "1", gridRow: "2"}}>
|
||||
<img src="/~barttile/img/BART-Map-Weekday-Saturday.png" />
|
||||
</div>
|
||||
<div className="searchsidebar" style={{gridColumn: "2", gridRow: "2"}}>
|
||||
Search stuff here
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}}
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
82
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}`;
|
||||
}
|
11
src/js/reducers/config.js
Normal file
@ -0,0 +1,11 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class ConfigReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'barttile', false);
|
||||
if (data) {
|
||||
state.inbox = data.inbox;
|
||||
}
|
||||
}
|
||||
}
|
11
src/js/reducers/initial.js
Normal file
@ -0,0 +1,11 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class InitialReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'initial', false);
|
||||
if (data) {
|
||||
state.inbox = data.inbox;
|
||||
}
|
||||
}
|
||||
}
|
17
src/js/reducers/update.js
Normal file
@ -0,0 +1,17 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export class UpdateReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, 'update', false);
|
||||
if (data) {
|
||||
this.reduceInbox(_.get(data, 'inbox', false), state);
|
||||
}
|
||||
}
|
||||
|
||||
reduceInbox(inbox, state) {
|
||||
if (inbox) {
|
||||
state.inbox = inbox;
|
||||
}
|
||||
}
|
||||
}
|
35
src/js/store.js
Normal file
@ -0,0 +1,35 @@
|
||||
import { InitialReducer } from '/reducers/initial';
|
||||
import { ConfigReducer } from '/reducers/config';
|
||||
import { UpdateReducer } from '/reducers/update';
|
||||
|
||||
|
||||
class Store {
|
||||
constructor() {
|
||||
this.state = {
|
||||
inbox: {}
|
||||
};
|
||||
|
||||
this.initialReducer = new InitialReducer();
|
||||
this.configReducer = new ConfigReducer();
|
||||
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.configReducer.reduce(json, this.state);
|
||||
this.updateReducer.reduce(json, this.state);
|
||||
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
export let store = new Store();
|
||||
window.store = store;
|
34
src/js/subscription.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { api } from '/api';
|
||||
import { store } from '/store';
|
||||
|
||||
import urbitOb from 'urbit-ob';
|
||||
|
||||
|
||||
export class Subscription {
|
||||
start() {
|
||||
if (api.authTokens) {
|
||||
// this.initializebarttile();
|
||||
} else {
|
||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||
}
|
||||
}
|
||||
|
||||
// initializebarttile() {
|
||||
// api.bind('/primary', 'PUT', api.authTokens.ship, 'barttile',
|
||||
// this.handleEvent.bind(this),
|
||||
// this.handleError.bind(this));
|
||||
// }
|
||||
|
||||
handleEvent(diff) {
|
||||
store.handleEvent(diff);
|
||||
}
|
||||
|
||||
handleError(err) {
|
||||
console.error(err);
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'barttile',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export let subscription = new Subscription();
|
1
src/js/vendor/sigils-1.2.5.js
vendored
Normal file
@ -2,16 +2,19 @@ import React, { Component } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export default class %APPNAME%Tile extends Component {
|
||||
export default class barttileTile extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="w-100 h-100 relative bg-white bg-gray0-d ba b--black b--gray1-d">
|
||||
<p className="black white-d absolute f9" style={{ left: 8, top: 8 }}>%APPNAME%</p>
|
||||
<a className="w-100 h-100 db pa2 no-underline" href="/~barttile">
|
||||
<p className="black white-d absolute f9" style={{ left: 8, top: 8 }}>BART</p>
|
||||
<img className="absolute" src="/~barttile/img/Temp-Bart-Icon.png" style={{top: 40, left: 20, width: "50%"}}/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.%APPNAME%Tile = %APPNAME%Tile;
|
||||
window.barttileTile = barttileTile;
|
||||
|
@ -2,34 +2,34 @@
|
||||
/= index
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/%APPNAME%/index
|
||||
/: /===/app/barttile/index
|
||||
/| /html/
|
||||
/~ ~
|
||||
==
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/%APPNAME%/js/tile
|
||||
/: /===/app/barttile/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= script
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/%APPNAME%/js/index
|
||||
/: /===/app/barttile/js/index
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= style
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/%APPNAME%/css/index
|
||||
/: /===/app/barttile/css/index
|
||||
/| /css/
|
||||
/~ ~
|
||||
==
|
||||
/= %APPNAME%-png
|
||||
/= barttile-png
|
||||
/^ (map knot @)
|
||||
/: /===/app/%APPNAME%/img /_ /png/
|
||||
/: /===/app/barttile/img /_ /png/
|
||||
::
|
||||
|%
|
||||
+$ card card:agent:gall
|
||||
@ -38,16 +38,16 @@
|
||||
=<
|
||||
|_ bol=bowl:gall
|
||||
+* this .
|
||||
%APPNAME%-core +>
|
||||
cc ~(. %APPNAME%-core bol)
|
||||
barttile-core +>
|
||||
cc ~(. barttile-core bol)
|
||||
def ~(. (default-agent this %|) bol)
|
||||
::
|
||||
++ on-init
|
||||
^- (quip card _this)
|
||||
=/ launcha [%launch-action !>([%add %%APPNAME% / '/~%APPNAME%/js/tile.js'])]
|
||||
=/ launcha [%launch-action !>([%add %barttile / '/~barttile/js/tile.js'])]
|
||||
:_ this
|
||||
:~ [%pass / %arvo %e %connect [~ /'~%APPNAME%'] %%APPNAME%]
|
||||
[%pass /%APPNAME% %agent [our.bol %launch] %poke launcha]
|
||||
:~ [%pass / %arvo %e %connect [~ /'~barttile'] %barttile]
|
||||
[%pass /barttile %agent [our.bol %launch] %poke launcha]
|
||||
==
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
@ -96,18 +96,18 @@
|
||||
^- simple-payload:http
|
||||
=+ url=(parse-request-line url.request.inbound-request)
|
||||
?+ site.url not-found:gen
|
||||
[%'~%APPNAME%' %css %index ~] (css-response:gen style)
|
||||
[%'~%APPNAME%' %js %tile ~] (js-response:gen tile-js)
|
||||
[%'~%APPNAME%' %js %index ~] (js-response:gen script)
|
||||
[%'~barttile' %css %index ~] (css-response:gen style)
|
||||
[%'~barttile' %js %tile ~] (js-response:gen tile-js)
|
||||
[%'~barttile' %js %index ~] (js-response:gen script)
|
||||
::
|
||||
[%'~%APPNAME%' %img @t *]
|
||||
[%'~barttile' %img @t *]
|
||||
=/ name=@t i.t.t.site.url
|
||||
=/ img (~(get by %APPNAME%-png) name)
|
||||
=/ img (~(get by barttile-png) name)
|
||||
?~ img
|
||||
not-found:gen
|
||||
(png-response:gen (as-octs:mimes:html u.img))
|
||||
::
|
||||
[%'~%APPNAME%' *] (html-response:gen index)
|
||||
[%'~barttile' *] (html-response:gen index)
|
||||
==
|
||||
::
|
||||
--
|
1
urbit/app/barttile/css/index.css
Normal file
BIN
urbit/app/barttile/img/BART-Map-Sunday.png
Normal file
After Width: | Height: | Size: 4.5 MiB |
BIN
urbit/app/barttile/img/BART-Map-Weekday-Saturday.png
Normal file
After Width: | Height: | Size: 4.5 MiB |
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
BIN
urbit/app/barttile/img/Temp-Bart-Icon.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -1,16 +1,16 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>%APPNAME%</title>
|
||||
<title>barttile</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||
<link rel="stylesheet" href="/~%APPNAME%/css/index.css" />
|
||||
<link rel="stylesheet" href="/~barttile/css/index.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" />
|
||||
<script src="/~/channel/channel.js"></script>
|
||||
<script src="/~modulo/session.js"></script>
|
||||
<script src="/~%APPNAME%/js/index.js"></script>
|
||||
<script src="/~barttile/js/index.js"></script>
|
||||
</body>
|
||||
</html>
|
57329
urbit/app/barttile/js/index.js
Normal file
19193
urbit/app/barttile/js/tile.js
Normal file
@ -1,71 +0,0 @@
|
||||
/+ *server, default-agent, verb
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/%APPNAME%/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
=, format
|
||||
::
|
||||
%+ verb |
|
||||
^- agent:gall
|
||||
|_ =bowl:gall
|
||||
+* this .
|
||||
def ~(. (default-agent this %|) bowl)
|
||||
::
|
||||
++ on-init
|
||||
^- (quip card:agent:gall _this)
|
||||
=/ launcha
|
||||
[%launch-action !>([%add %%APPNAME% /%APPNAME%tile '/~%APPNAME%/js/tile.js'])]
|
||||
:_ this
|
||||
:~ [%pass / %arvo %e %connect [~ /'~%APPNAME%'] %%APPNAME%]
|
||||
[%pass /%APPNAME% %agent [our.bowl %launch] %poke launcha]
|
||||
==
|
||||
++ on-save on-save:def
|
||||
++ on-load on-load:def
|
||||
++ on-poke
|
||||
|= [=mark =vase]
|
||||
^- (quip card:agent:gall _this)
|
||||
?. ?=(%handle-http-request mark)
|
||||
(on-poke:def mark vase)
|
||||
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
|
||||
:_ this
|
||||
%+ give-simple-payload:app eyre-id
|
||||
%+ require-authorization:app inbound-request
|
||||
|= =inbound-request:eyre
|
||||
=/ request-line (parse-request-line url.request.inbound-request)
|
||||
=/ back-path (flop site.request-line)
|
||||
=/ name=@t
|
||||
=/ back-path (flop site.request-line)
|
||||
?~ back-path
|
||||
''
|
||||
i.back-path
|
||||
::
|
||||
?~ back-path
|
||||
not-found:gen
|
||||
?: =(name 'tile')
|
||||
(js-response:gen tile-js)
|
||||
not-found:gen
|
||||
::
|
||||
++ on-watch
|
||||
|= =path
|
||||
^- (quip card:agent:gall _this)
|
||||
?: ?=([%http-response *] path)
|
||||
`this
|
||||
?. =([/%APPNAME%tile *] path)
|
||||
(on-watch:def path)
|
||||
[[%give %fact ~ %json !>(*json)]~ this]
|
||||
::
|
||||
++ on-leave on-leave:def
|
||||
++ on-peek on-peek:def
|
||||
++ on-agent on-agent:def
|
||||
++ on-arvo
|
||||
|= [=wire =sign-arvo]
|
||||
^- (quip card:agent:gall _this)
|
||||
?. ?=(%bound +<.sign-arvo)
|
||||
(on-arvo:def wire sign-arvo)
|
||||
[~ this]
|
||||
::
|
||||
++ on-fail on-fail:def
|
||||
--
|