Compare commits

...

3 Commits

Author SHA1 Message Date
ronreg-ribdev db9e8acb5b Update README, add license terms for map 2020-05-11 23:33:37 -07:00
ronreg-ribdev b3802eba76 Image assets, basic layout 2020-05-11 23:33:37 -07:00
ronreg-ribdev ceed2be120 Initial bart-app commit 2020-05-11 23:33:37 -07:00
52 changed files with 77152 additions and 391 deletions

View File

@ -1,5 +1,5 @@
module.exports = {
URBIT_PIERS: [
"%URBITPIER%",
"/home/greg/code/zod/home",
]
};

View File

@ -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
View 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]);

View File

@ -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
View 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))
)
)
);
}
}

View 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}}
)
);
}
}

View 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
View 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
View 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}}
)
)
)
)
}
}

View File

@ -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;
}

View File

@ -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
View 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;

View File

@ -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'));
}));

View File

@ -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>
)
}
}

View File

@ -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;

View File

@ -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('tile-js-bundle-prod',
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
View File

@ -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
View 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;

View File

@ -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
View 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
View 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
View 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;
}
}
}

View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

View 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;

View File

@ -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)
==
::
--

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

View File

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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

File diff suppressed because it is too large Load Diff

19193
urbit/app/barttile/js/tile.js Normal file

File diff suppressed because it is too large Load Diff

View 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
--