soto: add spinner, fix overflow case

This commit is contained in:
Matilde Park 2020-02-21 19:52:01 -05:00
parent 08e511db87
commit 79ad3fa12c
16 changed files with 59 additions and 64 deletions

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,6 @@
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png">
</head>
<body class="w-100 h-100">
<div id="header" class="w-100"></div>
<div id="root" class="w-100 h-100">
</div>
<script src="/~/channel/channel.js"></script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -62,6 +62,20 @@ input {
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 {

View File

@ -1,38 +0,0 @@
.spinner-pending {
position: relative;
content: "";
border-radius: 100%;
height: 16px;
width: 16px;
background-color: rgba(255,255,255,1);
}
.spinner-pending::after {
content: "";
background-color: rgba(128,128,128,1);
width: 16px;
height: 16px;
position: absolute;
border-radius: 100%;
clip: rect(0, 16px, 16px, 8px);
animation: spin 1s cubic-bezier(0.745, 0.045, 0.355, 1.000) infinite;
}
@keyframes spin {
0% {transform:rotate(0deg)}
25% {transform:rotate(90deg)}
50% {transform:rotate(180deg)}
75% {transform:rotate(270deg)}
100% {transform:rotate(360deg)}
}
.spinner-nostart {
width: 8px;
height: 8px;
border-radius: 100%;
content:'';
background-color: black;
}

View File

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

View File

@ -1,6 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { HeaderBar } from '/components/lib/header-bar';
import { Root } from '/components/root';
import { api } from '/api';
import { subscription } from "/subscription";
@ -12,8 +11,6 @@ api.setAuthTokens({
subscription.start();
ReactDOM.render(<HeaderBar />, document.getElementById("header"));
ReactDOM.render((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,5 +1,3 @@
import React from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
class UrbitApi {

View File

@ -9,12 +9,13 @@ export class History extends Component {
return (
<div
className="relative flex flex-column-reverse overflow-container"
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}>
<p className="mono" key={index}
style={{overflowWrap: "break-word"}}>
{text}
</p>
);

View File

@ -25,6 +25,7 @@ export class Input extends Component {
// submit on enter
if (e.key === "Enter") {
store.setSpinner(true);
api.soto("ret");
}
@ -51,6 +52,7 @@ export class Input extends Component {
// tab completion
else if (e.key === "Tab") {
store.setSpinner(true);
api.soto({tab: this.props.cursor});
}

View File

@ -14,6 +14,15 @@ export class HeaderBar extends Component {
? ""
: document.title;
let spinner = !!this.props.spinner
? this.props.spinner : false;
let spinnerClasses = "";
if (spinner === true) {
spinnerClasses = "spin-active";
}
return (
<div className={"bg-white bg-gray1-d w-100 justify-between relative tc pt3 "
+ popout}
@ -21,7 +30,7 @@ export class HeaderBar extends Component {
<a className="dib black white-d f9 inter absolute left-1"
href='/'
style={{ top: 14 }}>
<IconHome />
<IconHome classes={spinnerClasses} />
<span className="ml2 black white-d v-top lh-title"
style={{ paddingTop: 3 }}>
Home

View File

@ -2,9 +2,11 @@ import React, { Component } from "react";
export class IconHome extends Component {
render() {
let classes = !!this.props.classes ? this.props.classes : "";
return (
<img
className="invert-d"
className={"invert-d " + classes}
src="/~link/img/Home.png"
width={16}
height={16}

View File

@ -1,9 +0,0 @@
import React, { Component } from 'react';
export class IconSpinner extends Component {
render() {
return (
<div className="spinner-pending"></div>
);
}
}

View File

@ -2,6 +2,7 @@ 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';
@ -19,6 +20,7 @@ export class Root extends Component {
return (
<BrowserRouter>
<div className="w-100 h-100 bg-white bg-gray1-d">
<HeaderBar spinner={this.state.spinner}/>
<Route
exact path="/~dojo/:popout?"
render={(props) => {
@ -42,7 +44,7 @@ export class Root extends Component {
</a>
</div>
<div className={"pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative" +
" h-100-m40-s b--gray0 br2 " + popoutClasses}
" h-100-m40-s b--gray0 br2 flex-auto " + popoutClasses}
style={{
lineHeight: "1.4",
cursor: "text"

View File

@ -9,7 +9,8 @@ export class Store {
txt: [],
prompt: '',
cursor: 0,
input: ""
input: "",
spinner: false
}
this.sync = this.sync.bind(this);
this.print = this.print.bind(this);
@ -19,9 +20,19 @@ export class Store {
// recursive handler
if (data.data) {
var dojoReply = data.data;
} else {
}
else if (data.local) {
if (data.local.spinner) {
return this.setState({spinner: data.local.spinner})
}
}
else {
var dojoReply = data;
}
// on response, disable spinner
this.setState({spinner: false});
// %mor sole-effects are nested, so throw back to handler
if (dojoReply.map) {
return dojoReply.map(reply => this.handleEvent(reply));
@ -75,6 +86,14 @@ export class Store {
setStateHandler(setState) {
this.setState = setState;
}
setSpinner(boolean) {
store.handleEvent({
local: {
spinner: boolean
}
})
}
}
export let store = new Store();