cleanup: small touchups, updates readme for electron

This commit is contained in:
@wwwjim 2020-08-03 01:10:58 -07:00
parent 8ab55ffc46
commit d293e479aa
12 changed files with 335 additions and 79 deletions

View File

@ -71,14 +71,8 @@ npm run dev
- Visit `localhost:1337` in a browser.
### BROKEN: Run electron (MacOS)
@jimmylee broke the current version of the client.
### Run electron (MacOS)
```sh
rm -rf .next
npm run build-electron
npm run electron-pack
npm run electron-dev
```
Open **Slate.app** in `dist/mac/slate.app`.

View File

@ -31,12 +31,11 @@ export const getCurrentById = (navigation, targetId) => {
};
const constructFilesTreeForNavigation = (library) => {
let bytes = 0;
library[0].children.forEach((o) => {
bytes = o.size + bytes;
});
return { ...library[0], name: `Data (${Strings.bytesToSize(bytes)})`, children: [] };
return {
...library[0],
name: `Data`,
children: [],
};
};
const constructSlatesTreeForNavigation = (slates) => {
@ -103,7 +102,7 @@ export const generate = ({ library = [], slates = [] }) => [
},
{
id: 16,
name: "Developer API",
name: "API",
pageTitle: "Developer API",
decorator: "SETTINGS_DEVELOPER",
children: null,
@ -116,16 +115,9 @@ export const generate = ({ library = [], slates = [] }) => [
children: null,
ignore: true,
},
{
id: 5,
name: "Public profile",
pageTitle: "Profile Page",
decorator: "PROFILE_PAGE",
children: [],
},
{
id: 2,
name: "Filecoin Wallet",
name: "Wallet",
pageTitle: "Your wallet and addresses",
decorator: "WALLET",
children: [

View File

@ -100,12 +100,13 @@ export const injectTooltipStyles = () =>
}
.tippy-tooltip {
font-family: ${Constants.font.text};
font-family: ${Constants.font.code};
color: ${Constants.system.white};
background-color: ${Constants.system.pitchBlack};
position: relative;
border-radius: 4px;
font-size: 1rem;
font-size: 11px;
text-transform: uppercase;
padding: 12px;
text-align: center;
will-change: transform;

View File

@ -350,12 +350,6 @@ export default class ApplicationPage extends React.Component {
};
_handleNavigateTo = (next, data = null) => {
// TODO(jim): Refactor this hack for profile pages.
if (next.id === 5) {
window.open(`/@${this.state.viewer.username}`);
return;
}
this.state.history[this.state.currentIndex].scrollTop = window.scrollY;
this.state.history[this.state.currentIndex].data = data;

View File

@ -0,0 +1,78 @@
import * as React from "react";
import * as Constants from "~/common/constants";
import { css } from "@emotion/react";
import Dismissible from "~/components/core/Dismissible";
const STYLES_AVATAR = css`
display: inline-flex;
background-size: cover;
background-position: 50% 50%;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
position: relative;
background-color: ${Constants.system.black};
color: ${Constants.system.white};
transition: 100ms ease all;
align-items: center;
justify-content: center;
:hover {
background-color: ${Constants.system.brand};
}
`;
const STYLES_AVATAR_ONLINE = css`
height: 16px;
width: 16px;
background-color: ${Constants.system.green};
border: 2px solid ${Constants.system.white};
position: absolute;
bottom: -4px;
right: -4px;
border-radius: 16px;
`;
export default class ApplicationControlMenu extends React.Component {
state = {};
_handleClick = (e) => {
if (this.props.popover) {
this.setState({ visible: !this.state.visible });
}
if (this.props.onClick) {
this.props.onClick(e);
}
};
_handleHide = () => {
this.setState({ visible: false });
};
render() {
return (
<Dismissible
css={STYLES_AVATAR}
captureResize={false}
captureScroll={true}
enabled={this.state.visible}
onOutsideRectEvent={this._handleHide}
onClick={this._handleClick}
style={{
...this.props.style,
width: `${this.props.size}px`,
height: `${this.props.size}px`,
borderRadius: `${this.props.size}px`,
backgroundImage: `url('${this.props.url}')`,
cursor: this.props.onClick ? "pointer" : this.props.style,
backgroundColor: this.state.visible ? Constants.system.brand : null,
}}
>
{this.props.icon ? this.props.icon : null}
{this.state.visible ? this.props.popover : null}
{this.props.online ? <span css={STYLES_AVATAR_ONLINE} /> : null}
</Dismissible>
);
}
}

View File

@ -2,10 +2,12 @@ import * as React from "react";
import * as Constants from "~/common/constants";
import * as System from "~/components/system";
import * as SVG from "~/common/svg";
import * as OldSVG from "~/components/system/svg";
import { css } from "@emotion/react";
import { Tooltip } from "react-tippy";
import Avatar from "~/components/core/Avatar";
import ApplicationControlMenu from "~/components/core/ApplicationControlMenu";
const STYLES_CIRCLE = css`
height: 32px;
@ -55,7 +57,7 @@ const STYLES_HOME = css`
user-select: none;
margin-right: 24px;
margin-left: 24px;
font-size: 11px;
font-size: 14px;
text-transform: uppercase;
font-family: ${Constants.font.codeBold};
`;
@ -92,27 +94,37 @@ const STYLES_RIGHT = css`
padding-right: 16px;
`;
const STYLES_INPUT = css`
width: 100%;
max-width: 1024px;
font-size: 16px;
height: 40px;
padding: 0 16px 0 16px;
background-color: ${Constants.system.white};
border-radius: 4px;
box-shadow: inset 0 0 0 1px #e0e0e0, 0 1px 4px rgba(0, 0, 0, 0.04);
border: 0;
outline: 0;
box-sizing: border-box;
const STYLES_PROFILE = css`
font-family: ${Constants.font.semiBold};
background-color: ${Constants.system.pitchBlack};
color: ${Constants.system.white};
font-size: 12px;
line-height: 12px;
text-decoration: none;
height: 36px;
padding-right: 24px;
border-radius: 36px;
display: flex;
align-items: center;
justify-content: flex-start;
transition: 200ms ease all;
:focus {
box-shadow: 0 1px 4px rgba(0, 71, 255, 0.3),
inset 0 0 0 1px ${Constants.system.brand};
outline: 0;
:hover {
background-color: ${Constants.system.brand};
}
`;
const STYLES_IMAGE = css`
background-size: cover;
background-position: 50% 50%;
flex-shrink: 0;
height: 32px;
width: 32px;
border-radius: 32px;
margin-right: 16px;
margin-left: 2px;
`;
export default class ApplicationHeader extends React.Component {
render() {
const isBackDisabled =
@ -125,7 +137,7 @@ export default class ApplicationHeader extends React.Component {
return (
<header css={STYLES_APPLICATION_HEADER}>
<div css={STYLES_LEFT}>
<span css={STYLES_HOME}>Slate {Constants.values.version}</span>
<span css={STYLES_HOME}>Slate</span>
<span
css={STYLES_ICON_ELEMENT}
style={
@ -154,25 +166,47 @@ export default class ApplicationHeader extends React.Component {
</div>
<div css={STYLES_MIDDLE} />
<div css={STYLES_RIGHT}>
<Avatar
style={{ marginLeft: 12 }}
onClick={() => {}}
size={32}
url={this.props.viewer.data.photo}
popover={
<System.PopoverNavigation
style={{ right: 0, top: "48px", cursor: "pointer" }}
onNavigateTo={this.props.onNavigateTo}
onAction={this.props.onAction}
onSignOut={this.props.onSignOut}
navigation={[
{ text: "Profile & account settings", value: 13 },
{ text: "Filecoin settings", value: 14 },
{ text: "Sign out", value: 0, action: "SIGN_OUT" },
]}
<Tooltip
animation="fade"
animateFill={false}
title="View your profile"
>
<a
css={STYLES_PROFILE}
href={`/@${this.props.viewer.username}`}
target="_blank"
>
<span
css={STYLES_IMAGE}
style={{
backgroundImage: `url('${this.props.viewer.data.photo}')`,
}}
/>
}
/>
{this.props.viewer.username}
</a>
</Tooltip>
<Tooltip animation="fade" animateFill={false} title="Settings Menu">
<ApplicationControlMenu
style={{ marginLeft: 12 }}
onClick={() => {}}
size={36}
icon={<OldSVG.ChevronDown height="20px" />}
popover={
<System.PopoverNavigation
style={{ right: 0, top: "48px", cursor: "pointer" }}
onNavigateTo={this.props.onNavigateTo}
onAction={this.props.onAction}
onSignOut={this.props.onSignOut}
navigation={[
{ text: "Profile & account settings", value: 13 },
{ text: "Filecoin settings", value: 14 },
{ text: "Sign out", value: 0, action: "SIGN_OUT" },
]}
/>
}
/>
</Tooltip>
</div>
</header>
);

View File

@ -6,6 +6,7 @@ import * as SVG from "~/common/svg";
import { css } from "@emotion/react";
import Pill from "~/components/core/Pill";
import DataMeter from "~/components/core/DataMeter";
const IconMap = {
HOME: <SVG.Home height="20px" />,
@ -235,6 +236,13 @@ class NodeReference extends React.Component {
export default class ApplicationNavigation extends React.Component {
render() {
// TODO(jim):
// Calculate this idea elsewhere if you keep it.
let bytes = 0;
this.props.viewer.library[0].children.forEach((each) => {
bytes = each.size + bytes;
});
return (
<nav css={STYLES_NAVIGATION}>
{this.props.navigation.map((each) => {
@ -262,6 +270,8 @@ export default class ApplicationNavigation extends React.Component {
</NodeReference>
);
})}
<br />
<DataMeter currentBytes={bytes} />
</nav>
);
}

View File

@ -0,0 +1,130 @@
import * as React from "react";
import * as Constants from "~/common/constants";
import * as Strings from "~/common/strings";
import * as System from "~/components/system";
import { css } from "@emotion/react";
// NOTE(jim): 10 GB
const MAX_IN_BYTES = 10737418240;
const STYLES_CONTAINER = css`
border-radius: 4px;
border: 1px solid ${Constants.system.border};
padding: 16px;
`;
const STYLES_GUTTER = css`
padding: 16px 16px 16px 16px;
`;
const STYLES_DATA = css`
width: 100%;
display: flex;
align-items: center;
height: 8px;
border-radius: 3px;
background-color: ${Constants.system.border};
overflow: hidden;
`;
const STYLES_DATA_METER = css`
flex-shrink: 0;
height: 100%;
background-color: ${Constants.system.brand};
background-image: linear-gradient(
315deg,
${Constants.system.brand} 0%,
#009ffd 74%
);
`;
const STYLES_ROW = css`
display: flex;
align-items: flex-end;
justify-content: space-between;
font-family: ${Constants.font.code};
color: ${Constants.system.darkGray};
font-size: 10px;
margin-top: 2px;
text-transform: uppercase;
`;
const STYLES_STATS_ROW = css`
display: flex;
align-items: flex-end;
justify-content: space-between;
font-family: ${Constants.font.code};
color: ${Constants.system.black};
font-size: 12px;
text-transform: uppercase;
`;
const STYLES_LEFT = css`
min-width: 10%;
width: 100% "";
`;
const STYLES_RIGHT = css`
flex-shrink: 0;
`;
const STYLES_TITLE = css`
font-family: ${Constants.font.semiBold};
font-weight: 400;
font-size: 14px;
display: block;
margin-bottom: 4px;
`;
const STYLES_HREF = css`
font-family: ${Constants.font.semiBold};
font-weight: 400;
cursor: pointer;
transition: 200ms ease color;
:hover {
color: ${Constants.system.brand};
}
`;
export default (props) => {
const percentage = props.currentBytes / MAX_IN_BYTES;
console.log(percentage * 100);
return (
<div css={STYLES_GUTTER}>
<div css={STYLES_CONTAINER}>
<System.P style={{ fontSize: 12 }}>
<strong css={STYLES_TITLE}>Usage</strong>
Slate users get 10GB of IPFS storage for free.{" "}
<strong
css={STYLES_HREF}
onClick={() => alert("TODO: SUBSCRIPTION OPTIONS")}
>
(upgrade)
</strong>
<br />
<br />
</System.P>
<div css={STYLES_STATS_ROW}>
<div css={STYLES_LEFT}>{Strings.bytesToSize(props.currentBytes)}</div>
<div css={STYLES_RIGHT}>{Strings.bytesToSize(MAX_IN_BYTES)}</div>
</div>
<div css={STYLES_ROW}>
<div css={STYLES_LEFT}>Used</div>
<div css={STYLES_RIGHT}>Total</div>
</div>
<div css={STYLES_DATA} style={{ marginTop: 4 }}>
<div
css={STYLES_DATA_METER}
style={{ width: `${percentage * 100}%` }}
/>
</div>
</div>
</div>
);
};

View File

@ -160,6 +160,7 @@ export class Input extends React.Component {
full={this.props.full}
tooltip={this.props.tooltip}
label={this.props.label}
style={this.props.descriptionStyle}
description={this.props.description}
/>
<div style={{ position: "relative" }}>

View File

@ -9,7 +9,9 @@ const STYLES_POPOVER = css`
position: absolute;
width: 288px;
border-radius: 4px;
user-select: none;
background-color: ${Constants.system.white};
color: ${Constants.system.pitchBlack};
box-shadow: inset 0 0 0 1px ${Constants.system.border},
0 1px 4px rgba(0, 0, 0, 0.07);
`;

View File

@ -1,6 +1,7 @@
import * as React from "react";
import * as Actions from "~/common/actions";
import * as System from "~/components/system";
import * as Strings from "~/common/strings";
import { css } from "@emotion/react";
@ -53,10 +54,15 @@ export default class SceneFilesFolder extends React.Component {
}
render() {
let bytes = 0;
let rows = this.props.viewer.library[0].children.map((each) => {
bytes = each.size + bytes;
return {
...each,
button: each.networks && each.networks.includes("FILECOIN") ? null : "Store on Filecoin",
button:
each.networks && each.networks.includes("FILECOIN")
? null
: "Store on Filecoin",
};
});
@ -102,14 +108,15 @@ export default class SceneFilesFolder extends React.Component {
<System.H1>{this.props.current.name}</System.H1>
<Section
onAction={this.props.onAction}
title="All data"
title={`${Strings.bytesToSize(bytes)} uploaded`}
buttons={[
{
name: "Upload data",
type: "SIDEBAR",
value: "SIDEBAR_ADD_FILE_TO_BUCKET",
},
]}>
]}
>
<System.Table
key={this.props.current.folderId}
data={data}

View File

@ -108,7 +108,9 @@ export default class SceneSlate extends React.Component {
},
];
const slateURL = `https://slate.host/@${this.props.viewer.username}/${slatename}`;
const slateURL = `https://slate.host/@${
this.props.viewer.username
}/${slatename}`;
return (
<ScenePage>
@ -116,10 +118,12 @@ export default class SceneSlate extends React.Component {
label="Will the Slate page look like this in the final product?"
description="No! Consider this page just a functionality test. Slates will be collaborative mood boards and will have a much more intuitive experience than this."
/>
<System.H1 style={{ marginTop: 48 }}>
https://slate.host/@{this.props.viewer.username}/{slatename}
</System.H1>
<Section title="Slate elements" buttons={slateButtons} onAction={this.props.onAction}>
<System.H1 style={{ marginTop: 48 }}>{slatename}</System.H1>
<Section
title="Slate elements"
buttons={slateButtons}
onAction={this.props.onAction}
>
<System.Table
data={slates}
name={slateURL}
@ -130,10 +134,12 @@ export default class SceneSlate extends React.Component {
<System.Input
containerStyle={{ marginTop: 48 }}
style={{ marginTop: 24 }}
label="Slatename"
description={
<React.Fragment>
Changing the slatename will change your public slate URL. Your slate URL is:{" "}
Changing the slatename will change your public slate URL. Your
slate URL is:{" "}
<a href={slateURL} target="_blank">
{slateURL}
</a>
@ -154,12 +160,19 @@ export default class SceneSlate extends React.Component {
/>
</div>
<div css={STYLES_RIGHT}>
<System.Toggle name="public" onChange={this._handleChange} active={this.state.public} />
<System.Toggle
name="public"
onChange={this._handleChange}
active={this.state.public}
/>
</div>
</div>
<div style={{ marginTop: 32 }}>
<System.ButtonPrimary onClick={this._handleSave} loading={this.state.loading}>
<System.ButtonPrimary
onClick={this._handleSave}
loading={this.state.loading}
>
Save changes
</System.ButtonPrimary>
</div>