Merge pull request #2340 from urbit/mp/os1/soto/spinner

soto: add light/dark mode, spinner, prevent overflow
This commit is contained in:
matildepark 2020-02-24 13:58:39 -05:00 committed by GitHub
commit f8dd807ae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 121 additions and 87 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 1.5 KiB

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

@ -53,13 +53,27 @@ a {
font-family: "Inter", sans-serif;
}
.mix-blend-diff {
mix-blend-mode: difference;
}
input {
background-color: inherit;
color: inherit;
}
.invert {
filter: invert(1);
/* 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 */
@ -73,4 +87,49 @@ input {
.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,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

@ -1,17 +1,10 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import { IconHome } from '/components/lib/icons/icon-home';
import { IconSpinner } from '/components/lib/icons/icon-spinner';
import { Sigil } from '/components/lib/icons/sigil';
export class HeaderBar extends Component {
render() {
// let spin = (this.props.spinner)
// ? <div className="absolute"
// style={{width: 16, height: 16, top: 16, left: 55}}>
// <IconSpinner/>
// </div>
// : null;
let popout = (window.location.href.includes("popout"))
? "dn"
@ -21,33 +14,42 @@ 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-gray1 w-100 justify-between relative tc pt3 "
<div className={"bg-white bg-gray1-d w-100 justify-between relative tc pt3 "
+ popout}
style={{ height: 40 }}>
<a className="dib white f9 inter absolute left-1"
<a className="dib black white-d f9 inter absolute left-1"
href='/'
style={{ top: 14 }}>
<IconHome />
<span className="ml2 white v-top lh-title"
<IconHome classes={spinnerClasses} />
<span className="ml2 black white-d v-top lh-title"
style={{ paddingTop: 3 }}>
Home
</span>
</a>
<span className="f9 white inter dib"
<span className="f9 black white-d inter dib"
style={{
verticalAlign: "text-top",
paddingTop: 3
}}>{title}</span>
{/* {spin} */}
<div className="absolute right-1 lh-copy"
style={{ top: 12 }}>
<Sigil
ship={"~" + window.ship}
size={16}
color={"#4d4d4d"}
color={"#000000"}
classes="mix-blend-diff"
/>
<span className="mono white f9 ml2 v-top">{"~" + window.ship}</span>
<span className="mono black white-d f9 ml2 v-top">{"~" + window.ship}</span>
</div>
</div>
);

View File

@ -2,10 +2,11 @@ import React, { Component } from "react";
export class IconHome extends Component {
render() {
let classes = !!this.props.classes ? this.props.classes : "";
return (
//TODO relocate to ~launch when OS1 is ported
<img
className="invert"
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

@ -6,6 +6,8 @@ export class Sigil extends Component {
render() {
const { props } = this;
let classes = !!this.props.classes ? this.props.classes : "";
if (props.ship.length > 14) {
return (
<div className="bg-black flex-shrink-0" style={{ width: props.size, height: props.size }}>
@ -13,7 +15,7 @@ export class Sigil extends Component {
);
} else {
return (
<div className="dib flex-shrink-0" style={{ flexBasis: 32, backgroundColor: props.color }}>
<div className={"dib flex-shrink-0 " + classes} style={{ flexBasis: 32, backgroundColor: props.color }}>
{sigil({
patp: props.ship,
renderer: reactRenderer,

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';
@ -18,7 +19,8 @@ export class Root extends Component {
render() {
return (
<BrowserRouter>
<div className="w-100 h-100 bg-gray1">
<div className="w-100 h-100 bg-white bg-gray1-d">
<HeaderBar spinner={this.state.spinner}/>
<Route
exact path="/~dojo/:popout?"
render={(props) => {
@ -35,14 +37,14 @@ export class Root extends Component {
return (
<div className="w-100 h-100 flex-m flex-l flex-xl">
<div
className="db dn-m dn-l dn-xl inter bg-gray0 dt w-100"
className="db dn-m dn-l dn-xl inter bg-white bg-gray0-d dt w-100"
style={{ height: 40 }}>
<a className="f8 pl3 white dtc h-100 v-mid" href="/">
<a className="f8 pl3 black white-d dtc h-100 v-mid" href="/">
Landscape
</a>
</div>
<div className={"pa3 bg-gray0 white mono w-100 f8 relative" +
" h-100-m40-s b--gray0 br2 " + popoutClasses}
<div className={"pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative" +
" 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();