spa: clean up extraneous oldApps files

This commit is contained in:
Matilde Park 2020-05-06 18:10:36 -04:00 committed by Logan Allen
parent 0a1860159d
commit a31787f874
42 changed files with 0 additions and 25680 deletions

View File

@ -1,223 +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 rename = require('gulp-rename');
var del = require('del');
var json = require('rollup-plugin-json');
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');
var rollupReplace = require('@rollup/plugin-replace');
/***
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('../../arvo/app/chat/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', 'cloneElement',
'createContext', 'createElement', 'useState', 'useRef',
'useLayoutEffect', 'useMemo', 'useEffect', 'forwardRef', 'useContext', 'Children' ],
'node_modules/react-is/index.js': [ 'isValidElementType', 'isElement', 'ForwardRef' ],
'node_modules/react-dom/index.js': [ 'createPortal' ]
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
json(),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/chat/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'
}),
json(),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/chat/js/'))
.on('end', cb);
});
gulp.task('js-imports-prod', function(cb) {
return gulp.src('dist/index.js')
.pipe(rollup({
plugins: [
rollupReplace({'process.env.NODE_ENV': JSON.stringify('production')}),
commonjs({
namedExports: {
'node_modules/react/index.js': ['Component', 'cloneElement',
'createContext', 'createElement', 'useState', 'useRef',
'useLayoutEffect', 'useMemo', 'useEffect', 'forwardRef', 'useContext', 'Children' ],
'node_modules/react-is/index.js': [ 'isValidElementType', 'isElement', 'ForwardRef' ],
'node_modules/react-dom/index.js': [ 'createPortal' ]
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
globals(),
json(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/chat/js/'))
.on('end', cb);
});
gulp.task('js-minify', function () {
return gulp.src('../../arvo/app/chat/js/index.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/chat/js/'));
});
gulp.task('tile-js-minify', function () {
return gulp.src('../../arvo/app/chat/js/tile.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/chat/js/'));
});
gulp.task('rename-index-min', function() {
return gulp.src('../../arvo/app/chat/js/index-min.js')
.pipe(rename('index.js'))
.pipe(gulp.dest('../../arvo/app/chat/js/'))
});
gulp.task('rename-tile-min', function() {
return gulp.src('../../arvo/app/chat/js/tile-min.js')
.pipe(rename('tile.js'))
.pipe(gulp.dest('../../arvo/app/chat/js/'))});
gulp.task('clean-min', function() {
return del(['../../arvo/app/chat/js/index-min.js', '../../arvo/app/chat/js/tile-min.js'], {force: true})
});
gulp.task('urbit-copy', function () {
let ret = gulp.src('../../arvo/**/*');
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-prod', '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',
),
'rename-index-min',
'rename-tile-min',
'clean-min',
'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('../../arvo/**/*', gulp.parallel('urbit-copy'));
}));

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
{
"name": "urbit-apps",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@rollup/plugin-replace": "^2.3.0",
"@sucrase/gulp-plugin": "^2.0.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-better-rollup": "^4.0.1",
"gulp-cssimport": "^7.0.0",
"gulp-minify": "^3.1.0",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.4.0",
"rollup": "^1.6.0",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-root-import": "^0.2.3",
"sucrase": "^3.8.0"
},
"dependencies": {
"classnames": "^2.2.6",
"codemirror": "^5.51.2",
"del": "^5.1.0",
"lodash": "^4.17.11",
"moment": "^2.20.1",
"mousetrap": "^1.6.3",
"react": "^16.5.2",
"react-codemirror2": "^6.0.0",
"react-dom": "^16.8.6",
"react-markdown": "^4.3.1",
"react-router-dom": "^5.0.0",
"remark-disable-tokenizers": "^1.0.24",
"urbit-ob": "^5.0.0",
"urbit-sigil-js": "^1.3.2"
},
"resolutions": {
"natives": "1.1.3"
}
}

View File

@ -1,478 +0,0 @@
* {
-webkit-font-smoothing: antialiased;
-webkit-touch-callout: none;
}
html, body {
height: 100%;
width: 100%;
}
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;
padding: 0;
}
textarea, input, button {
outline: none;
-webkit-appearance: none;
border: none;
background-color: #fff;
}
a {
color: #000;
font-weight: 400;
text-decoration: none;
}
h2 {
font-weight: 400;
}
.body-large {
font-size: 20px;
line-height: 24px;
}
.body-medium {
font-size: 16px;
line-height: 19px;
}
.body-small {
font-size: 12px;
line-height: 16px;
color: #7f7f7f;
}
.label-regular {
font-size: 14px;
}
.inter {
font-family: Inter, sans-serif;
}
.clamp-3 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.clamp-message {
max-width: calc(100% - 36px - 1.5rem);
}
.clamp-attachment {
overflow: auto;
max-height: 10em;
max-width: 100%;
}
.lh-16 {
line-height: 16px;
}
.mono {
font-family: "Source Code Pro", monospace;
}
.bg-welcome-green {
background-color: #ECF6F2;
}
.list-ship {
line-height: 2.2;
}
.c-default {
cursor: default;
}
.word-break-all {
word-break: break-all;
}
.focus-b--black:focus {
border-color: #000;
}
.mix-blend-diff {
mix-blend-mode: difference;
}
.placeholder-inter::placeholder {
font-family: "Inter", sans-serif;
}
/* spinner */
.spin-active {
animation: spin 2s infinite;
}
@keyframes spin {
0% {transform: rotate(0deg);}
25% {transform: rotate(90deg);}
50% {transform: rotate(180deg);}
75% {transform: rotate(270deg);}
100% {transform: rotate(360deg);}
}
/* embeds */
.embed-container {
position: relative;
height: 0;
overflow: hidden;
padding-bottom: 28.125%;
}
.embed-container iframe, .embed-container object, .embed-container embed {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.mh-16 {
max-height: 16rem;
}
/* toggler checkbox */
.toggle::after {
content: "";
height: 12px;
width: 12px;
background: white;
position: absolute;
top: 2px;
left: 2px;
border-radius: 100%;
}
.toggle.checked::after {
content: "";
height: 12px;
width: 12px;
background: white;
position: absolute;
top: 2px;
left: 14px;
border-radius: 100%;
}
.shadow-6 {
box-shadow: 2px 4px 20px rgba(0, 0, 0, 0.25);
}
.brt2 {
border-radius: 0.25rem 0.25rem 0 0;
}
.green3 {
color: #7ea899;
}
.unread-notice {
top: 48px;
}
/* responsive */
@media all and (max-width: 34.375em) {
.dn-s {
display: none;
}
.flex-basis-full-s {
flex-basis: 100%;
}
.h-100-minus-40-s {
height: calc(100% - 40px);
}
.h-100-minus-96-s {
height: calc(100% - 96px);
}
.embed-container {
padding-bottom: 56.25%;
}
.unread-notice {
top: 96px;
}
}
@media all and (min-width: 34.375em) and (max-width: 46.875em) {
.flex-basis-250-m {
flex-basis: 250px;
}
.h-100-minus-40-m {
height: calc(100% - 40px);
}
.embed-container {
padding-bottom: 56.25%;
}
}
@media all and (min-width: 46.875em) and (max-width: 60em) {
.flex-basis-250-l {
flex-basis: 250px;
}
.h-100-minus-40-l {
height: calc(100% - 40px);
}
.embed-container {
padding-bottom: 37.5%;
}
}
@media all and (min-width: 60em) {
.flex-basis-250-xl {
flex-basis: 250px;
}
.h-100-minus-40-xl {
height: calc(100% - 40px);
}
}
blockquote {
padding-left: 24px;
padding-top: 8px;
padding-bottom: 8px;
margin-left: 0;
margin-right: 0;
margin-top: 8px;
margin-bottom: 8px;
border-left: 1px solid black;
}
:root {
--dark-gray: #555555;
--gray: #7F7F7F;
--medium-gray: #CCCCCC;
--light-gray: rgba(0,0,0,0.08);
}
.react-codemirror2 {
width: 100%;
}
.CodeMirror {
height: 100% !important;
width: 100% !important;
cursor: text;
}
.CodeMirror * {
font-family: 'Inter';
}
.CodeMirror.cm-s-code.cm-s-tlon * {
font-family: 'Source Code Pro';
}
.CodeMirror-selected { background:#BAE3FE !important; color: black; }
pre.CodeMirror-placeholder.CodeMirror-line-like { color: var(--gray); }
.cm-s-tlon span { font-family: "Inter"}
.cm-s-tlon span.cm-meta { color: var(--gray); }
.cm-s-tlon span.cm-number { color: var(--gray); }
.cm-s-tlon span.cm-keyword { line-height: 1em; font-weight: bold; color: var(--gray); }
.cm-s-tlon span.cm-atom { font-weight: bold; color: var(--gray); }
.cm-s-tlon span.cm-def { color: black; }
.cm-s-tlon span.cm-variable { color: black; }
.cm-s-tlon span.cm-variable-2 { color: black; }
.cm-s-tlon span.cm-variable-3, .cm-s-tlon span.cm-type { color: black; }
.cm-s-tlon span.cm-property { color: black; }
.cm-s-tlon span.cm-operator { color: black; }
.cm-s-tlon span.cm-comment { font-family: 'Source Code Pro'; color: black; background-color: var(--light-gray); display: inline-block; border-radius: 2px;}
.cm-s-tlon span.cm-string { color: var(--dark-gray); }
.cm-s-tlon span.cm-string-2 { color: var(--gray); }
.cm-s-tlon span.cm-qualifier { color: #555; }
.cm-s-tlon span.cm-error { color: #FF0000; }
.cm-s-tlon span.cm-attribute { color: var(--gray); }
.cm-s-tlon span.cm-tag { color: var(--gray); }
.cm-s-tlon span.cm-link { color: var(--dark-gray); text-decoration: none;}
.cm-s-tlon .CodeMirror-activeline-background { background: var(--gray); }
.cm-s-tlon .CodeMirror-cursor {
border-left: 2px solid #3687FF;
}
.cm-s-tlon span.cm-builtin { color: var(--gray); }
.cm-s-tlon span.cm-bracket { color: var(--gray); }
/* .cm-s-tlon { font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;} */
.cm-s-tlon .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }
.CodeMirror-hints.tlon {
/* font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; */
color: #616569;
background-color: #ebf3fd !important;
}
.CodeMirror-hints.tlon .CodeMirror-hint-active {
background-color: #a2b8c9 !important;
color: #5c6065 !important;
}
.title-input[placeholder]:empty:before {
content: attr(placeholder);
color: #7F7F7F;
}
/* 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;
}
.b--green2-d {
border-color: #2aa779;
}
.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 {
background-color: #4d4d4d;
}
blockquote {
border-left: 1px solid white;
}
.contrast-10-d {
filter: contrast(0.1);
}
.bg-none-d {
background: none;
}
/* codemirror */
.cm-s-tlon.CodeMirror {
background: #333;
color: #fff;
}
.cm-s-tlon span.cm-def {
color: white;
}
.cm-s-tlon span.cm-variable {
color: white;
}
.cm-s-tlon span.cm-variable-2 {
color: white;
}
.cm-s-tlon span.cm-variable-3,
.cm-s-tlon span.cm-type {
color: white;
}
.cm-s-tlon span.cm-property {
color: white;
}
.cm-s-tlon span.cm-operator {
color: white;
}
.cm-s-tlon span.cm-string {
color: var(--gray);
}
.cm-s-tlon span.cm-string-2 {
color: var(--gray);
}
.cm-s-tlon span.cm-attribute {
color: var(--gray);
}
.cm-s-tlon span.cm-tag {
color: var(--gray);
}
.cm-s-tlon span.cm-link {
color: var(--gray);
}
/* set rules w/ both color & bg-color last to preserve legibility */
.CodeMirror-selected {
background: var(--medium-gray) !important;
color: white;
}
.cm-s-tlon span.cm-comment {
color: black;
display: inline-block;
padding: 0;
background-color: rgba(255,255,255, 0.3);
border-radius: 2px;
}
}
/* CodeMirror styling */

View File

@ -1,63 +0,0 @@
@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;
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +0,0 @@
@import '../node_modules/codemirror/lib/codemirror.css';
@import '../node_modules/codemirror/theme/material.css';
@import "css/indigo-static.css";
@import "css/fonts.css";
@import "css/custom.css";

View File

@ -1,16 +0,0 @@
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((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,263 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import { uuid } from '/lib/util';
import { store } from '/store';
class UrbitApi {
setAuthTokens(authTokens) {
this.authTokens = authTokens;
this.bindPaths = [];
this.groups = {
add: this.groupAdd.bind(this),
remove: this.groupRemove.bind(this)
};
this.chat = {
message: this.chatMessage.bind(this),
read: this.chatRead.bind(this)
};
this.chatView = {
create: this.chatViewCreate.bind(this),
delete: this.chatViewDelete.bind(this),
join: this.chatViewJoin.bind(this),
groupify: this.chatViewGroupify.bind(this)
};
this.chatHook = {
addSynced: this.chatHookAddSynced.bind(this)
};
this.invite = {
accept: this.inviteAccept.bind(this),
decline: this.inviteDecline.bind(this)
};
}
bind(path, method, ship = this.authTokens.ship, app, success, fail, quit) {
this.bindPaths = _.uniq([...this.bindPaths, path]);
window.subscriptionId = window.urb.subscribe(ship, app, path,
(err) => {
fail(err);
},
(event) => {
success({
data: event,
from: {
ship,
path
}
});
},
(qui) => {
quit(qui);
});
}
action(appl, mark, data) {
return new Promise((resolve, reject) => {
window.urb.poke(ship, appl, mark, data,
(json) => {
resolve(json);
},
(err) => {
reject(err);
});
});
}
addPendingMessage(msg) {
if (store.state.pendingMessages.has(msg.path)) {
store.state.pendingMessages.get(msg.path).unshift(msg.envelope);
} else {
store.state.pendingMessages.set(msg.path, [msg.envelope]);
}
store.setState({
pendingMessages: store.state.pendingMessages
});
}
groupsAction(data) {
return this.action("group-store", "group-action", data);
}
groupAdd(members, path) {
return this.groupsAction({
add: {
members, path
}
});
}
groupRemove(members, path) {
this.groupsAction({
remove: {
members, path
}
});
}
chatAction(data) {
this.action("chat-store", "json", data);
}
chatMessage(path, author, when, letter) {
let data = {
message: {
path,
envelope: {
uid: uuid(),
number: 0,
author,
when,
letter
}
}
};
this.action("chat-hook", "json", data).then(() => {
this.chatRead(path);
})
data.message.envelope.author = data.message.envelope.author.substr(1);
this.addPendingMessage(data.message);
}
chatRead(path, read) {
this.chatAction({ read: { path } });
}
chatHookAddSynced(ship, path, askHistory) {
return this.action("chat-hook", "chat-hook-action", {
'add-synced': {
ship,
path,
'ask-history': askHistory
}
});
}
chatViewAction(data) {
return this.action("chat-view", "json", data);
}
chatViewCreate(
title, description, appPath, groupPath,
security, members, allowHistory
) {
return this.chatViewAction({
create: {
title,
description,
'app-path': appPath,
'group-path': groupPath,
security,
members,
'allow-history': allowHistory
}
});
}
chatViewDelete(path) {
this.chatViewAction({ delete: { 'app-path': path } });
}
chatViewJoin(ship, path, askHistory) {
this.chatViewAction({
join: {
ship,
'app-path': path,
'ask-history': askHistory
}
});
}
chatViewGroupify(path, group = null, inclusive = false) {
let action = { groupify: { 'app-path': path, existing: null } };
if (group) {
action.groupify.existing = {
'group-path': group,
inclusive: inclusive
}
}
return this.chatViewAction(action);
}
inviteAction(data) {
this.action("invite-store", "json", data);
}
inviteAccept(uid) {
this.inviteAction({
accept: {
path: '/chat',
uid
}
});
}
inviteDecline(uid) {
this.inviteAction({
decline: {
path: '/chat',
uid
}
});
}
metadataAction(data) {
return this.action("metadata-hook", "metadata-action", data);
}
metadataAdd(appPath, groupPath, title, description, dateCreated, color) {
let creator = `~${window.ship}`
return this.metadataAction({
add: {
"group-path": groupPath,
resource: {
"app-path": appPath,
"app-name": "chat"
},
metadata: {
title,
description,
color,
'date-created': dateCreated,
creator
}
}
})
}
sidebarToggle() {
let sidebarBoolean = true;
if (store.state.sidebarShown === true) {
sidebarBoolean = false;
}
store.handleEvent({
data: {
local: {
'sidebarToggle': sidebarBoolean
}
}
});
}
setSelected(selected) {
store.handleEvent({
data: {
local: {
selected: selected
}
}
})
}
}
export let api = new UrbitApi();
window.api = api;

View File

@ -1,156 +0,0 @@
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('~', '');
}
export function uxToHex(ux) {
if (ux.length > 2 && ux.substr(0,2) === '0x') {
let value = ux.substr(2).replace('.', '').padStart(6, '0');
return value;
}
let value = ux.replace('.', '').padStart(6, '0');
return value;
}
function hexToDec(hex) {
const alphabet = '0123456789ABCDEF'.split('');
return hex.reverse().reduce((acc, digit, idx) => {
const dec = alphabet.findIndex(a => a === digit.toUpperCase());
if(dec < 0) {
console.log(hex);
throw new Error("Incorrect hex formatting");
}
return acc + dec * (16 ** idx);
}, 0);
}
export function hexToRgba(hex, a) {
const [r,g,b] = _.chunk(hex, 2).map(hexToDec);
return `rgba(${r}, ${g}, ${b}, ${a})`;
}
export function writeText(str) {
return new Promise(function (resolve, reject) {
var range = document.createRange();
range.selectNodeContents(document.body);
document.getSelection().addRange(range);
var success = false;
function listener(e) {
e.clipboardData.setData("text/plain", str);
e.preventDefault();
success = true;
}
document.addEventListener("copy", listener);
document.execCommand("copy");
document.removeEventListener("copy", listener);
document.getSelection().removeAllRanges();
success ? resolve() : reject();
}).catch(function (error) {
console.error(error);
});;
};
// 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}`;
}
export function alphabetiseAssociations(associations) {
let result = {};
Object.keys(associations).sort((a, b) => {
let aName = a.substr(1);
let bName = b.substr(1);
if (associations[a].metadata && associations[a].metadata.title) {
aName = associations[a].metadata.title !== ""
? associations[a].metadata.title
: a.substr(1);
}
if (associations[b].metadata && associations[b].metadata.title) {
bName = associations[b].metadata.title !== ""
? associations[b].metadata.title
: b.substr(1);
}
return aName.toLowerCase().localeCompare(bName.toLowerCase());
}).map((each) => {
result[each] = associations[each];
})
return result;
}

View File

@ -1,79 +0,0 @@
import _ from 'lodash';
export class ChatUpdateReducer {
reduce(json, state) {
let data = _.get(json, 'chat-update', false);
if (data) {
this.pending(data, state);
this.message(data, state);
this.messages(data, state);
this.read(data, state);
this.create(data, state);
this.delete(data, state);
}
}
message(json, state) {
let data = _.get(json, 'message', false);
if (data) {
state.inbox[data.path].envelopes.unshift(data.envelope);
state.inbox[data.path].config.length
= state.inbox[data.path].config.length + 1;
}
}
messages(json, state) {
let data = _.get(json, 'messages', false);
if (data) {
state.inbox[data.path].envelopes =
state.inbox[data.path].envelopes.concat(data.envelopes);
}
}
read(json, state) {
let data = _.get(json, 'read', false);
if (data) {
state.inbox[data.path].config.read =
state.inbox[data.path].config.length;
}
}
create(json, state) {
let data = _.get(json, 'create', false);
if (data) {
state.inbox[data.path] = {
envelopes: [],
config: {
read: 0,
length: 0
}
};
}
}
delete(json, state) {
let data = _.get(json, 'delete', false);
if (data) {
delete state.inbox[data.path];
}
}
pending(json, state) {
let msg = _.get(json, 'message', false);
if (!msg || !state.pendingMessages.has(msg.path)) {
return;
}
let mailbox = state.pendingMessages.get(msg.path);
for (let pendingMsg of mailbox) {
if (msg.envelope.uid === pendingMsg.uid) {
let index = mailbox.indexOf(pendingMsg);
state.pendingMessages.get(msg.path).splice(index, 1);
}
}
}
}

View File

@ -1,68 +0,0 @@
import _ from 'lodash';
export class ContactUpdateReducer {
reduce(json, state) {
let data = _.get(json, 'contact-update', false);
if (data) {
this.create(data, state);
this.delete(data, state);
this.add(data, state);
this.remove(data, state);
this.edit(data, state);
}
}
create(json, state) {
let data = _.get(json, 'create', false);
if (data) {
state.contacts[data.path] = {};
}
}
delete(json, state) {
let data = _.get(json, 'delete', false);
if (data) {
delete state.contacts[data.path];
}
}
add(json, state) {
let data = _.get(json, 'add', false);
if (
data &&
(data.path in state.contacts)
) {
state.contacts[data.path][data.ship] = data.contact;
}
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (
data &&
(data.path in state.contacts) &&
(data.ship in state.contacts[data.path])
) {
delete state.contacts[data.path][data.ship];
}
}
edit(json, state) {
let data = _.get(json, 'edit', false);
if (
data &&
(data.path in state.contacts) &&
(data.ship in state.contacts[data.path])
) {
let edit = Object.keys(data['edit-field']);
if (edit.length !== 1) {
return;
}
state.contacts[data.path][data.ship][edit[0]] =
data['edit-field'][edit[0]];
}
}
}

View File

@ -1,38 +0,0 @@
import _ from 'lodash';
export class InitialReducer {
reduce(json, state) {
let data = _.get(json, 'chat-initial', false);
if (data) {
state.inbox = data;
state.chatInitialized = true;
}
data = _.get(json, 'permission-initial', false);
if (data) {
for (let perm in data) {
state.permissions[perm] = {
who: new Set(data[perm].who),
kind: data[perm].kind
}
}
}
data = _.get(json, 'invite-initial', false);
if (data) {
state.invites = data;
}
data = _.get(json, 'contact-initial', false);
if (data) {
state.contacts = data;
}
data = _.get(json, 'chat-hook-update', false);
if (data) {
state.chatSynced = data;
}
}
}

View File

@ -1,53 +0,0 @@
import _ from 'lodash';
export class InviteUpdateReducer {
reduce(json, state) {
let data = _.get(json, 'invite-update', false);
if (data) {
this.create(data, state);
this.delete(data, state);
this.invite(data, state);
this.accepted(data, state);
this.decline(data, state);
}
}
create(json, state) {
let data = _.get(json, 'create', false);
if (data) {
state.invites[data.path] = {};
}
}
delete(json, state) {
let data = _.get(json, 'delete', false);
if (data) {
delete state.invites[data.path];
}
}
invite(json, state) {
let data = _.get(json, 'invite', false);
if (data) {
state.invites[data.path][data.uid] = data.invite;
}
}
accepted(json, state) {
let data = _.get(json, 'accepted', false);
if (data) {
console.log(data);
delete state.invites[data.path][data.uid];
}
}
decline(json, state) {
let data = _.get(json, 'decline', false);
if (data) {
delete state.invites[data.path][data.uid];
}
}
}

View File

@ -1,25 +0,0 @@
import _ from 'lodash';
export class LocalReducer {
reduce(json, state) {
let data = _.get(json, 'local', false);
if (data) {
this.sidebarToggle(data, state);
this.setSelected(data, state);
}
}
sidebarToggle(obj, state) {
let data = _.has(obj, 'sidebarToggle', false);
if (data) {
state.sidebarShown = obj.sidebarToggle;
}
}
setSelected(obj, state) {
let data = _.has(obj, 'selected', false);
if (data) {
state.selectedGroups = obj.selected;
}
}
}

View File

@ -1,65 +0,0 @@
import _ from 'lodash';
export class MetadataReducer {
reduce(json, state) {
let data = _.get(json, 'metadata-update', false);
if (data) {
this.associations(data, state);
this.add(data, state);
this.update(data, state);
this.remove(data, state);
}
}
associations(json, state) {
let data = _.get(json, 'associations', false);
if (data) {
let metadata = state.associations;
Object.keys(data).map((channel) => {
let channelObj = data[channel];
let app = data[channel]["app-name"];
if (!(app in metadata)) {
metadata[app] = {};
}
metadata[app][channelObj["app-path"]] = channelObj;
})
state.associations = metadata;
}
}
add(json, state) {
let data = _.get(json, 'add', false);
if (data) {
let metadata = state.associations;
let app = data["app-name"];
if (!(app in metadata)) {
metadata[app] = {};
}
metadata[app][data["app-path"]] = data;
state.associations = metadata;
}
}
update(json, state) {
let data = _.get(json, 'update-metadata', false);
if (data) {
let metadata = state.associations;
let app = data["app-name"];
metadata[app][data["app-path"]] = data;
state.associations = metadata;
}
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (data) {
let metadata = state.associations;
let app = data["app-name"];
if (!(app in metadata)) {
return false;
}
delete metadata[app][data["app-path"]];
state.associations = metadata;
}
}
}

View File

@ -1,51 +0,0 @@
import _ from 'lodash';
export class PermissionUpdateReducer {
reduce(json, state) {
let data = _.get(json, 'permission-update', false);
if (data) {
this.create(data, state);
this.delete(data, state);
this.add(data, state);
this.remove(data, state);
}
}
create(json, state) {
let data = _.get(json, 'create', false);
if (data) {
state.permissions[data.path] = {
kind: data.kind,
who: new Set(data.who)
};
}
}
delete(json, state) {
let data = _.get(json, 'delete', false);
if (data) {
delete state.permissions[data.path];
}
}
add(json, state) {
let data = _.get(json, 'add', false);
if (data) {
for (let member of data.who) {
state.permissions[data.path].who.add(member);
}
}
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (data) {
for (let member of data.who) {
state.permissions[data.path].who.delete(member);
}
}
}
}

View File

@ -1,72 +0,0 @@
import { InitialReducer } from '/reducers/initial';
import { ContactUpdateReducer } from '/reducers/contact-update';
import { ChatUpdateReducer } from '/reducers/chat-update';
import { InviteUpdateReducer } from '/reducers/invite-update';
import { PermissionUpdateReducer } from '/reducers/permission-update';
import { MetadataReducer } from '/reducers/metadata-update.js';
import { S3Reducer } from '/reducers/s3.js';
import { LocalReducer } from '/reducers/local.js';
class Store {
constructor() {
this.state = this.initialState();
this.initialReducer = new InitialReducer();
this.permissionUpdateReducer = new PermissionUpdateReducer();
this.contactUpdateReducer = new ContactUpdateReducer();
this.chatUpdateReducer = new ChatUpdateReducer();
this.inviteUpdateReducer = new InviteUpdateReducer();
this.metadataReducer = new MetadataReducer();
this.s3Reducer = new S3Reducer();
this.localReducer = new LocalReducer();
this.setState = () => {};
}
initialState() {
return {
inbox: {},
chatSynced: null,
contacts: {},
permissions: {},
invites: {},
associations: {
chat: {},
contacts: {}
},
s3: {},
selectedGroups: [],
sidebarShown: true,
pendingMessages: new Map([]),
chatInitialized: false
};
}
setStateHandler(setState) {
this.setState = setState;
}
handleEvent(data) {
let json = data.data;
if ('clear' in json && json.clear) {
this.setState(this.initialState());
return;
}
console.log(json);
this.initialReducer.reduce(json, this.state);
this.permissionUpdateReducer.reduce(json, this.state);
this.contactUpdateReducer.reduce(json, this.state);
this.chatUpdateReducer.reduce(json, this.state);
this.inviteUpdateReducer.reduce(json, this.state);
this.metadataReducer.reduce(json, this.state);
this.s3Reducer.reduce(json, this.state);
this.localReducer.reduce(json, this.state);
this.setState(this.state);
}
}
export let store = new Store();
window.store = store;

View File

@ -1,81 +0,0 @@
import { api } from '/api';
import { store } from '/store';
import urbitOb from 'urbit-ob';
export class Subscription {
constructor() {
this.firstRoundSubscriptionComplete = false;
}
start() {
if (api.authTokens) {
this.firstRoundSubscription();
window.urb.setOnChannelError(this.onChannelError.bind(this));
} else {
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
}
}
onChannelError(err) {
console.error('event source error: ', err);
console.log('initiating new channel');
this.firstRoundSubscriptionComplete = false;
setTimeout(2000, () => {
store.handleEvent({
data: { clear : true}
});
this.start();
});
}
subscribe(path, app) {
api.bind(path, 'PUT', api.authTokens.ship, app,
this.handleEvent.bind(this),
(err) => {
console.log(err);
this.subscribe(path, app);
},
() => {
this.subscribe(path, app);
});
}
firstRoundSubscription() {
this.subscribe('/primary', 'chat-view');
}
secondRoundSubscriptions() {
this.subscribe('/synced', 'chat-hook');
this.subscribe('/primary', 'invite-view');
this.subscribe('/all', 'permission-store');
this.subscribe('/primary', 'contact-view');
this.subscribe('/app-name/chat', 'metadata-store');
this.subscribe('/app-name/contacts', 'metadata-store');
this.subscribe('/all', 's3-store');
}
handleEvent(diff) {
if (!this.firstRoundSubscriptionComplete) {
this.firstRoundSubscriptionComplete = true;
this.secondRoundSubscriptions();
}
store.handleEvent(diff);
}
fetchMessages(start, end, path) {
console.log(start, end, path);
fetch(`/~chat/paginate/${start}/${end}${path}`)
.then((response) => response.json())
.then((json) => {
store.handleEvent({
data: json
});
});
}
}
export let subscription = new Subscription();

View File

@ -1,183 +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 rename = require('gulp-rename');
var del = require('del');
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('../../arvo/app/contacts/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('../../arvo/app/contacts/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('../../arvo/app/contacts/js/'))
.on('end', cb);
});
gulp.task('js-minify', function () {
return gulp.src('../../arvo/app/contacts/js/index.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/contacts/js/'));
});
gulp.task('tile-js-minify', function () {
return gulp.src('../../arvo/app/contacts/js/tile.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/contacts/js/'));
});
gulp.task('rename-index-min', function() {
return gulp.src('../../arvo/app/contacts/js/index-min.js')
.pipe(rename('index.js'))
.pipe(gulp.dest('../../arvo/app/contacts/js/'))
});
gulp.task('rename-tile-min', function() {
return gulp.src('../../arvo/app/contacts/js/tile-min.js')
.pipe(rename('tile.js'))
.pipe(gulp.dest('../../arvo/app/contacts/js/'))});
gulp.task('clean-min', function() {
return del(['../../arvo/app/contacts/js/index-min.js', '../../arvo/app/contacts/js/tile-min.js'], {force: true})
});
gulp.task('urbit-copy', function () {
let ret = gulp.src('../../arvo/**/*');
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',
),
'rename-index-min',
'rename-tile-min',
'clean-min',
'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('../../arvo/**/*', gulp.parallel('urbit-copy'));
}));

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
{
"name": "urbit-apps",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@sucrase/gulp-plugin": "^2.0.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-better-rollup": "^4.0.1",
"gulp-cssimport": "^7.0.0",
"gulp-minify": "^3.1.0",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.4.0",
"rollup": "^1.6.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-root-import": "^0.2.3",
"sucrase": "^3.8.0"
},
"dependencies": {
"classnames": "^2.2.6",
"del": "^5.1.0",
"lodash": "^4.17.11",
"moment": "^2.20.1",
"mousetrap": "^1.6.3",
"react": "^16.5.2",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
"urbit-ob": "^5.0.0",
"urbit-sigil-js": "^1.3.2"
},
"resolutions": {
"natives": "1.1.3"
}
}

View File

@ -1,4 +0,0 @@
@import "css/indigo-static.css";
@import "css/fonts.css";
@import "css/custom.css";

View File

@ -1,16 +0,0 @@
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((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,300 +0,0 @@
import React, { Component } from 'react';
import { BrowserRouter, Route, Link } from "react-router-dom";
import classnames from 'classnames';
import _ from 'lodash';
import { api } from '/api';
import { subscription } from '/subscription';
import { store } from '/store';
import { Skeleton } from '/components/skeleton';
import { NewScreen } from '/components/new';
import { ContactSidebar } from '/components/lib/contact-sidebar';
import { ContactCard } from '/components/lib/contact-card';
import { AddScreen } from '/components/lib/add-contact';
import GroupDetail from './lib/group-detail';
export class Root extends Component {
constructor(props) {
super(props);
this.state = store.state;
store.setStateHandler(this.setState.bind(this));
}
componentDidMount() {
new Image().src = "/~groups/img/Spinner.png";
}
render() {
const { props, state } = this;
let contacts = !!state.contacts ? state.contacts : {};
let defaultContacts =
(!!state.contacts && '/~/default' in state.contacts) ?
state.contacts['/~/default'] : {};
let groups = !!state.groups ? state.groups : {};
let s3 = !!state.s3 ? state.s3 : {};
let invites =
(!!state.invites && '/contacts' in state.invites) ?
state.invites['/contacts'] : {};
let associations = !!state.associations ? state.associations : {};
let selectedGroups = !!state.selectedGroups ? state.selectedGroups : [];
return (
<BrowserRouter>
<div className="h-100 w-100">
<Route exact path="/~groups"
render={ (props) => {
return (
<Skeleton
activeDrawer="groups"
selectedGroups={selectedGroups}
history={props.history}
api={api}
contacts={contacts}
groups={groups}
invites={invites}
associations={associations}>
<div className="h-100 w-100 overflow-x-hidden bg-white bg-gray0-d dn db-ns">
<div className="pl3 pr3 pt2 dt pb3 w-100 h-100">
<p className="f9 pt3 gray2 w-100 h-100 dtc v-mid tc">
Select a group to begin.
</p>
</div>
</div>
</Skeleton>
);
}} />
<Route exact path="/~groups/new"
render={ (props) => {
return (
<Skeleton
history={props.history}
selectedGroups={selectedGroups}
api={api}
contacts={contacts}
groups={groups}
invites={invites}
associations={associations}
activeDrawer="rightPanel">
<NewScreen
history={props.history}
groups={groups}
contacts={contacts}
api={api}
/>
</Skeleton>
);
}} />
<Route exact path="/~groups/(detail)?/(settings)?/:ship/:group/"
render={ (props) => {
let groupPath =
`/${props.match.params.ship}/${props.match.params.group}`;
let groupContacts = contacts[groupPath] || {};
let group = groups[groupPath] || new Set([]);
let detail = !!(props.match.url.includes("/detail"));
let settings = !!(props.match.url.includes("/settings"));
let association = (associations[groupPath])
? associations[groupPath]
: {};
return (
<Skeleton
history={props.history}
selectedGroups={selectedGroups}
api={api}
contacts={contacts}
invites={invites}
groups={groups}
activeDrawer={(detail || settings) ? "detail" : "contacts"}
selected={groupPath}
associations={associations}>
<ContactSidebar
contacts={groupContacts}
defaultContacts={defaultContacts}
group={group}
activeDrawer={(detail || settings) ? "detail" : "contacts"}
api={api}
path={groupPath}
{...props}
/>
<GroupDetail
association={association}
path={groupPath}
group={group}
activeDrawer={(detail || settings) ? "detail" : "contacts"}
settings={settings}
api={api}
{...props}
/>
</Skeleton>
);
}}
/>
<Route exact path="/~groups/add/:ship/:group"
render={(props) => {
let groupPath =
`/${props.match.params.ship}/${props.match.params.group}`;
let groupContacts = contacts[groupPath] || {};
let group = groups[groupPath] || new Set([]);
return (
<Skeleton
history={props.history}
selectedGroups={selectedGroups}
api={api}
contacts={contacts}
groups={groups}
invites={invites}
activeDrawer="rightPanel"
selected={groupPath}
associations={associations}>
<ContactSidebar
contacts={groupContacts}
defaultContacts={defaultContacts}
group={group}
activeDrawer="rightPanel"
path={groupPath}
api={api}
{...props}
/>
<AddScreen
api={api}
groups={groups}
path={groupPath}
history={props.history}
contacts={contacts}
/>
</Skeleton>
);
}} />
<Route exact path="/~groups/share/:ship/:group"
render={(props) => {
let groupPath =
`/${props.match.params.ship}/${props.match.params.group}`;
let shipPath = `${groupPath}/${window.ship}`;
let rootIdentity = defaultContacts[window.ship] || {};
let groupContacts = contacts[groupPath] || {};
let contact =
(window.ship in groupContacts) ?
groupContacts[window.ship] : {};
let group = groups[groupPath] || new Set([]);
return (
<Skeleton
history={props.history}
api={api}
selectedGroups={selectedGroups}
contacts={contacts}
groups={groups}
invites={invites}
activeDrawer="rightPanel"
selected={groupPath}
associations={associations}>
<ContactSidebar
activeDrawer="rightPanel"
contacts={groupContacts}
defaultContacts={defaultContacts}
group={group}
path={groupPath}
api={api}
selectedContact={shipPath}
{...props}
/>
<ContactCard
history={props.history}
contact={contact}
path={groupPath}
ship={window.ship}
share={true}
rootIdentity={rootIdentity}
s3={s3}
/>
</Skeleton>
);
}} />
<Route exact path="/~groups/view/:ship/:group/:contact"
render={ (props) => {
let groupPath =
`/${props.match.params.ship}/${props.match.params.group}`;
let shipPath =
`${groupPath}/${props.match.params.contact}`;
let groupContacts = contacts[groupPath] || {};
let contact =
(props.match.params.contact in groupContacts) ?
groupContacts[props.match.params.contact] : {};
let group = groups[groupPath] || new Set([]);
let rootIdentity =
props.match.params.contact === window.ship ?
defaultContacts[window.ship] : null;
return (
<Skeleton
history={props.history}
api={api}
selectedGroups={selectedGroups}
contacts={contacts}
groups={groups}
invites={invites}
activeDrawer="rightPanel"
selected={groupPath}
associations={associations}>
<ContactSidebar
activeDrawer="rightPanel"
contacts={groupContacts}
defaultContacts={defaultContacts}
group={group}
path={groupPath}
api={api}
selectedContact={shipPath}
{...props}
/>
<ContactCard
history={props.history}
contact={contact}
path={groupPath}
ship={props.match.params.contact}
rootIdentity={rootIdentity}
s3={s3}
/>
</Skeleton>
);
}} />
<Route exact path="/~groups/me"
render={ (props) => {
let me = defaultContacts[window.ship] || {};
return (
<Skeleton
history={props.history}
api={api}
selectedGroups={selectedGroups}
contacts={contacts}
groups={groups}
invites={invites}
activeDrawer="rightPanel"
selected="me"
associations={associations}>
<ContactCard
history={props.history}
path="/~/default"
contact={me}
ship={window.ship}
s3={s3}
/>
</Skeleton>
);
}} />
</div>
</BrowserRouter>
);
}
}

View File

@ -1,222 +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 rename = require('gulp-rename');
var del = require('del');
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');
var rollupReplace = require('@rollup/plugin-replace');
/***
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('../../arvo/app/soto/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', 'cloneElement',
'createContext', 'createElement', 'useState', 'useRef',
'useLayoutEffect', 'useMemo', 'useEffect', 'forwardRef', 'useContext', 'Children' ],
'node_modules/react-is/index.js': [ 'isValidElementType', 'isElement', 'ForwardRef' ],
'node_modules/react-dom/index.js': [ 'createPortal' ]
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/soto/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('../../arvo/app/soto/js/'))
.on('end', cb);
});
gulp.task('js-imports-prod', function(cb) {
return gulp.src('dist/index.js')
.pipe(rollup({
plugins: [
rollupReplace({'process.env.NODE_ENV': JSON.stringify('production')}),
commonjs({
namedExports: {
'node_modules/react/index.js': ['Component', 'cloneElement',
'createContext', 'createElement', 'useState', 'useRef',
'useLayoutEffect', 'useMemo', 'useEffect', 'forwardRef', 'useContext', 'Children' ],
'node_modules/react-is/index.js': [ 'isValidElementType', 'isElement', 'ForwardRef' ],
'node_modules/react-dom/index.js': [ 'createPortal' ]
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/soto/js/'))
.on('end', cb);
});
gulp.task('js-minify', function () {
return gulp.src('../../arvo/app/soto/js/index.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/soto/js/'));
});
gulp.task('tile-js-minify', function () {
return gulp.src('../../arvo/app/soto/js/tile.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/soto/js/'));
});
gulp.task('rename-index-min', function () {
return gulp.src('../../arvo/app/soto/js/index-min.js')
.pipe(rename('index.js'))
.pipe(gulp.dest('../../arvo/app/soto/js/'))
});
gulp.task('rename-tile-min', function () {
return gulp.src('../../arvo/app/soto/js/tile-min.js')
.pipe(rename('tile.js'))
.pipe(gulp.dest('../../arvo/app/soto/js/'))
});
gulp.task('clean-min', function () {
return del(['../../arvo/app/soto/js/index-min.js', '../../arvo/app/soto/js/tile-min.js'], { force: true })
});
gulp.task('urbit-copy', function () {
let ret = gulp.src('../../arvo/**/*');
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-prod', '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',
),
'rename-index-min',
'rename-tile-min',
'clean-min',
'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('../../arvo/**/*', gulp.parallel('urbit-copy'));
}));

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +0,0 @@
{
"name": "soto",
"version": "1.0.0",
"description": "Dojo relay for Urbit.",
"scripts": {
"build": "gulp",
"serve": "gulp watch"
},
"author": "Tlon Corp",
"license": "MIT",
"repository": "https://github.com/urbit/urbit",
"devDependencies": {
"@rollup/plugin-replace": "^2.3.0",
"@sucrase/gulp-plugin": "^2.0.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-better-rollup": "^4.0.1",
"gulp-cssimport": "^7.0.0",
"gulp-minify": "^3.1.0",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.4.0",
"rollup": "^1.6.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-root-import": "^0.2.3",
"sucrase": "^3.8.0"
},
"dependencies": {
"classnames": "^2.2.6",
"del": "^5.1.0",
"lodash": "^4.17.11",
"moment": "^2.20.1",
"mousetrap": "^1.6.3",
"react": "^16.5.2",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
"urbit-ob": "^4.1.2",
"urbit-sigil-js": "^1.3.2"
},
"resolutions": {
"natives": "1.1.3"
}
}

View File

@ -1,135 +0,0 @@
html, body {
-webkit-font-smoothing: antialiased;
height: 100%;
width: 100%;
overflow: hidden;
}
p, input {
margin-block-end: unset;
margin-block-start: unset;
-webkit-margin-before: unset;
-webkit-margin-after: unset;
font-family: "Source Code Pro", monospace;
}
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;
}
a {
text-decoration: none;
}
.label-small-mono {
font-size: 12px;
line-height: 24px;
font-family: "Source Code Pro", monospace;
}
.mono {
font-family: "Source Code Pro", monospace;
}
.inter {
font-family: "Inter", sans-serif;
}
.mix-blend-diff {
mix-blend-mode: difference;
}
input {
background-color: inherit;
color: inherit;
}
/* spinner */
.spin-active {
animation: spin 2s infinite;
}
@keyframes spin {
0% {transform: rotate(0deg);}
25% {transform: rotate(90deg);}
50% {transform: rotate(180deg);}
75% {transform: rotate(270deg);}
100% {transform: rotate(360deg);}
}
/* responsive */
@media all and (max-width: 34.375em) {
.h-100-m40-s {
height: calc(100% - 40px);
}
}
@media all and (min-width: 34.375em) {
.h-100-m40-p1-ns {
height: calc(100% - (40px + 1rem));
}
}
@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;
}
.invert-d {
filter: invert(1);
}
a {
color: #fff;
}
}

View File

@ -1,63 +0,0 @@
@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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
@import 'css/indigo-static.css';
@import 'css/fonts.css';
@import 'css/custom.css';

View File

@ -1,16 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Root } from '/components/root';
import { api } from '/api';
import { subscription } from "/subscription";
api.setAuthTokens({
ship: window.ship,
dojoId: "soto-" + Math.random().toString(36).substring(2),
});
subscription.start();
ReactDOM.render((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,49 +0,0 @@
import _ from 'lodash';
class UrbitApi {
setAuthTokens(authTokens) {
this.authTokens = authTokens;
this.bindPaths = [];
}
bind(path, method, ship = this.authTokens.ship, appl = "dojo", 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);
});
}
soto(data) {
return this.action("dojo", "sole-action",
{id: this.authTokens.dojoId, dat: 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

@ -1,29 +0,0 @@
import React, { Component } from 'react';
export class History extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div
className="relative flex flex-column-reverse overflow-container flex-auto"
style={{ height: "calc(100% - 1rem)", resize: "none" }}>
<div style={{ marginTop: "auto" }}>
{this.props.commandLog.map((text, index) => {
return (
<p className="mono" key={index}
style={{overflowWrap: "break-word"}}>
{text}
</p>
);
})}
</div>
</div>
);
}
}
export default History;

View File

@ -1,118 +0,0 @@
import React, { Component } from 'react';
import { store } from '../store';
import { api } from '../api';
import { cite } from '../lib/util';
import { Spinner } from './lib/icons/icon-spinner';
export class Input extends Component {
constructor(props) {
super(props);
this.state = {
awaiting: false,
type: "Sending to Dojo"
}
this.keyPress = this.keyPress.bind(this);
this.inputRef = React.createRef();
}
componentDidUpdate() {
this.inputRef.current.setSelectionRange(this.props.cursor, this.props.cursor);
}
keyPress = (e) => {
if ((e.getModifierState("Control") || event.getModifierState("Meta"))
&& e.key === "v") {
return;
}
e.preventDefault();
let allowedKeys = [
"Enter", "Backspace", "ArrowLeft", "ArrowRight", "Tab"
];
if ((e.key.length > 1) && (!(allowedKeys.includes(e.key)))) {
return;
}
// submit on enter
if (e.key === "Enter") {
this.setState({ awaiting: true, type: "Sending to Dojo"});
api.soto("ret").then(() => {
this.setState({awaiting: false});
});
}
else if ((e.key === "Backspace") && (this.props.cursor > 0)) {
store.doEdit({ del: this.props.cursor - 1});
return store.setState({ cursor: this.props.cursor - 1});
} else if (e.key === "Backspace") {
return;
}
else if (e.key.startsWith("Arrow")) {
if (e.key === "ArrowLeft") {
if (this.props.cursor > 0) {
store.setState({ cursor: this.props.cursor - 1 });
}
}
else if (e.key === "ArrowRight") {
if (this.props.cursor < this.props.input.length) {
store.setState({ cursor: this.props.cursor + 1});
}
}
}
// tab completion
else if (e.key === "Tab") {
this.setState({awaiting: true, type: "Getting suggestions"})
api.soto({tab: this.props.cursor}).then(() => {
this.setState({awaiting: false})
});
}
// capture and transmit most characters
else {
store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
store.setState({ cursor: this.props.cursor + 1 });
}
}
render() {
return (
<div className="flex flex-row flex-grow-1 relative">
<div className="flex-shrink-0">{cite(this.props.ship)}:dojo
</div>
<span id="prompt">
{this.props.prompt}
</span>
<input
autoCorrect="false"
autoFocus={true}
className="mono ml1 flex-auto dib w-100"
cursor={this.props.cursor}
onClick={e => store.setState({ cursor: e.target.selectionEnd })}
onKeyDown={this.keyPress}
onPaste={e => {
let clipboardData = e.clipboardData || window.clipboardData;
let paste = Array.from(clipboardData.getData('Text'));
paste.reduce(async (previous, next) => {
await previous;
this.setState({cursor: this.props.cursor + 1});
return store.doEdit({ ins: { cha: next, at: this.props.cursor } });
}, Promise.resolve());
e.preventDefault();
}}
ref={this.inputRef}
defaultValue={this.props.input}
/>
<Spinner awaiting={this.state.awaiting} text={`${this.state.type}...`} classes="absolute right-0 bottom-0 inter pa ba pa2 b--gray1-d"/>
</div>
)
}
}
export default Input;

View File

@ -1,37 +0,0 @@
import React, { Component } from "react";
import { Sigil } from "/components/lib/icons/sigil";
export class HeaderBar extends Component {
render() {
let popout = window.location.href.includes("popout/")
? "dn" : "dn db-m db-l db-xl";
let invites = (this.props.invites && this.props.invites.contacts)
? this.props.invites.contacts
: {};
return (
<div
className={
"bg-white bg-gray1-d w-100 justify-between relative tc pt3 " + popout
}
style={{ height: 45 }}>
<div className="fl lh-copy absolute left-1" style={{ top: 8 }}>
<a href="/~groups/me" className="dib v-top inter">
<Sigil
ship={"~" + window.ship}
classes="v-mid mix-blend-diff"
size={16}
color={"#000000"}
/>
</a>
<a
className="dib f9 v-mid inter ml2 black white-d"
href="/"
style={{ top: 14 }}>
</a> <p className="dib f9 v-mid inter ml2 white-d">Dojo</p>
</div>
</div>
);
}
}

View File

@ -1,141 +0,0 @@
// See /lib/sole/hoon
const str = JSON.stringify;
export class Share {
constructor(buf, ven, leg) {
if (buf == null) { buf = ""; }
this.buf = buf;
if (ven == null) { ven = [0, 0]; }
this.ven = ven;
if (leg == null) { leg = []; }
this.leg = leg;
}
abet() {
return { buf:this.buf,
leg:this.leg.slice(),
ven:this.ven.slice()
};
}
apply(ted){
switch (false) {
case 'nop' !== ted: return;
case !ted.map: return ted.map(this.apply, this);
default: switch (Object.keys(ted)[0]) {
case 'set': return this.buf = ted.set;
case 'del': return this.buf = this.buf.slice(0,ted.del) + this.buf.slice(ted.del + 1);
case 'ins':
var { at, cha } = ted.ins;
return this.buf = this.buf.slice(0,at) + cha + this.buf.slice(at);
default: throw `%sole-edit -lost.${str(ted)}`;
}
}
}
transmute(sin,dex){
switch (false) {
case (sin !== 'nop') && (dex !== 'nop'): return dex;
case !sin.reduce:
return sin.reduce(((dex,syn) => this.transmute(syn,dex)), dex);
case !dex.map: return dex.map(dax => this.transmute(sin,dax));
case dex.set === undefined: return dex;
default: switch (Object.keys(sin)[0]) {
case 'set': return 'nop';
case 'del':
if (sin.del === dex.del) { return 'nop'; }
dex = { ...dex }
switch (Object.keys(dex)[0]) {
case 'del': if (sin.del < dex.del) { dex.del--; } break;
case 'ins': if (sin.del < dex.ins.at) { dex.ins.at--; } break;
}
return dex;
case 'ins':
dex = { ...dex };
var {at,cha} = sin.ins;
switch (Object.keys(dex)[0]) {
case 'del': if (at < dex.del) { dex.del++; } break;
case 'ins': if ((at < dex.ins.at) ||
((at === dex.ins.at) && !(cha <= dex.ins.cha))) {
dex.ins.at++;
}
else if (at >= dex.ins.at) {
dex.ins.at = at; //NOTE possibly unpredictable behaviour
dex.ins.at++; // for sole inserts that aren't tabs
}
break;
}
return dex;
default: throw `%sole-edit -lost.${str(sin)}`;
}
}
}
commit(ted){
this.ven[0]++;
this.leg.push(ted);
return this.apply(ted);
}
inverse(ted){
switch (false) {
case 'nop' !== ted: return ted;
case !ted.map:
return ted.map( tad => {
const res = this.inverse(tad);
this.apply(tad);
return res;
}).reverse();
default: switch (Object.keys(ted)[0]) {
case 'set': return {set: this.buf};
case 'ins': return {del: ted.ins};
case 'del': return {ins: {at: ted.del, cha: this.buf[ted.del]}};
default: throw `%sole-edit -lost.${str(ted)}`;
}
}
}
receive({ler,ted}){
if (!(ler[1] === this.ven[1])) {
throw `-out-of-sync.[${str(ler)} ${str(this.ven)}]`;
}
this.leg = this.leg.slice((this.leg.length + ler[0]) - this.ven[0]);
const dat = this.transmute(this.leg, ted);
this.ven[1]++;
this.apply(dat);
return dat;
}
remit() {
throw 'stub';
}
transmit(ted){
const act = {ted, ler:[this.ven[1], this.ven[0]]};
this.commit(ted);
return act;
}
transceive({ler,ted}){
const old = new Share(this.buf);
const dat = this.receive({ler, ted});
return old.inverse(dat);
}
transpose(ted,pos){
if (pos === undefined) {
return this.transpose(this.leg, ted);
}
else {
let left;
return ((left =
(this.transmute(
ted, {ins: {at: pos}})).ins) != null ?
left : { at:0 }
).at;
}
}
};
export default Share;

View File

@ -1,74 +0,0 @@
import React, { Component } from 'react';
import { BrowserRouter, Route } from "react-router-dom";
import classnames from 'classnames';
import _ from 'lodash';
import { HeaderBar } from './lib/header-bar';
import { Popout } from './lib/icons/popout';
import { History } from './history';
import { Input } from './input';
import { api } from '../api';
import { store } from '../store';
export class Root extends Component {
constructor(props) {
super(props);
this.state = store.state;
store.setStateHandler(this.setState.bind(this));
}
componentDidMount() {
//preload spinner asset
new Image().src = "/~dojo/img/Spinner.png";
}
render() {
return (
<BrowserRouter>
<div className="w-100 h-100 bg-white bg-gray1-d">
<HeaderBar/>
<Route
exact path="/~dojo/:popout?"
render={(props) => {
let popout = !!props.match.params.popout;
let popoutClasses = classnames({
"h-100-m40-p1-ns": !popout,
"h-100-m h-100-l h-100-xl": popout,
"mh4-m mh4-l mh4-xl": !popout,
"mb4-m mb4-l mb4-xl": !popout,
"ba-m ba-l ba-xl": !popout
})
return (
<div className="w-100 h-100 flex-m flex-l flex-xl">
<div
className="db dn-m dn-l dn-xl inter bg-white bg-gray0-d dt w-100"
style={{ height: 40 }}>
<a className="f8 pl3 black white-d dtc h-100 v-mid" href="/">
Landscape
</a>
</div>
<div className={"pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative" +
" h-100-m40-s b--gray2 br1 flex-auto " + popoutClasses}
style={{
lineHeight: "1.4",
cursor: "text"
}}>
<Popout popout={popout}/>
<History commandLog={this.state.txt} />
<Input
ship={ship}
cursor={this.state.cursor}
prompt={this.state.prompt}
input={this.state.input}
/>
</div>
</div>
);
}}
/>
</div>
</BrowserRouter>
);
}
}

View File

@ -1,18 +0,0 @@
// 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}`;
}

View File

@ -1,83 +0,0 @@
import { Share } from './components/lib/sole';
import { api } from './api';
export const buffer = new Share;
export class Store {
constructor() {
this.state = {
txt: [],
prompt: '',
cursor: 0,
input: ""
}
this.sync = this.sync.bind(this);
this.print = this.print.bind(this);
}
handleEvent(data) {
// recursive handler
if (data.data) {
var dojoReply = data.data;
}
else {
var dojoReply = data;
}
// %mor sole-effects are nested, so throw back to handler
if (dojoReply.map) {
return dojoReply.map(reply => this.handleEvent(reply));
}
switch(Object.keys(dojoReply)[0]) {
case 'txt':
return this.print(dojoReply.txt);
case 'tab':
this.print(dojoReply.tab.match + " " + dojoReply.tab.info);
return;
case 'tan':
return dojoReply.tan.split("\n").map(this.print);
case 'pro':
return this.setState({ prompt: dojoReply.pro.cad });
case 'hop':
return this.setState({ cursor: dojoReply.hop });
case 'det':
buffer.receive(dojoReply.det);
return this.sync(dojoReply.det.ted);
case 'act':
switch(dojoReply.act) {
case 'clr': return this.setState({txt: []});
case 'nex': return this.setState({
input: "",
cursor: 0
});
} break;
default: console.log(dojoReply);
}
}
doEdit(ted) {
let detSend = buffer.transmit(ted);
this.sync(ted);
return api.soto({det: detSend});
}
print(txt) {
let textLog = this.state.txt;
textLog.push(txt);
return this.setState({ txt: textLog });
}
sync(ted) {
return this.setState({ input: buffer.buf,
cursor: buffer.transpose(ted, this.state.cursor)
});
}
setStateHandler(setState) {
this.setState = setState;
}
}
export let store = new Store();
window.store = store;

View File

@ -1,34 +0,0 @@
import { api } from './api';
import { store } from './store';
export class Subscription {
start() {
if (api.authTokens) {
this.initializesoto();
} else {
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
}
}
initializesoto() {
api.bind('/sole/'+api.authTokens.dojoId,
'PUT', api.authTokens.ship, 'dojo',
this.handleEvent.bind(this),
this.handleError.bind(this));
}
handleEvent(diff) {
store.handleEvent(diff);
}
handleError(err) {
console.error(err);
api.bind('/sole/'+api.authTokens.dojoId,
'PUT', api.authTokens.ship, 'dojo',
this.handleEvent.bind(this),
this.handleError.bind(this));
}
}
export let subscription = new Subscription();