From a27ef78eadbe4941542240a1279c351f20fb4938 Mon Sep 17 00:00:00 2001 From: Martina Date: Mon, 7 Sep 2020 14:45:58 -0700 Subject: [PATCH] updated data page --- common/svg.js | 42 +++- components/core/ApplicationNavigation.js | 1 - components/core/ApplicationUserControls.js | 4 +- components/core/CircleButtonGray.js | 1 - components/core/DataMeter.js | 43 ++-- components/core/DataView.js | 229 +++++++++++++++------ components/core/SceneContent.js | 2 - components/core/SlateMediaObjectPreview.js | 2 +- components/core/SlatePreviewBlock.js | 18 +- components/core/TabGroup.js | 11 +- components/system/components/Table.js | 14 +- scenes/SceneFilesFolder.js | 194 ++++++++++++++--- scenes/SceneHome.js | 59 +++--- 13 files changed, 447 insertions(+), 173 deletions(-) diff --git a/common/svg.js b/common/svg.js index c3defb15..5679bb1e 100644 --- a/common/svg.js +++ b/common/svg.js @@ -699,7 +699,7 @@ export const Book = (props) => ( ); -export const Music = (props) => ( +export const Sound = (props) => ( ( strokeLinecap="round" strokeLinejoin="round" > - - - + + ); @@ -1087,6 +1086,7 @@ export const LocationPin = (props) => { ); }; + export const MoreHorizontal = (props) => ( ( ); + +export const GridView = (props) => ( + + + + + + +); + +export const ListView = (props) => ( + + + + +); diff --git a/components/core/ApplicationNavigation.js b/components/core/ApplicationNavigation.js index 9302fa51..1715d2cc 100644 --- a/components/core/ApplicationNavigation.js +++ b/components/core/ApplicationNavigation.js @@ -26,7 +26,6 @@ const STYLES_NAVIGATION = css` width: 100%; display: block; padding: 24px 0 0 0; - font-size: 18px; `; const STYLES_NAVIGATION_ITEM = css` diff --git a/components/core/ApplicationUserControls.js b/components/core/ApplicationUserControls.js index a2f50de7..fa2d4052 100644 --- a/components/core/ApplicationUserControls.js +++ b/components/core/ApplicationUserControls.js @@ -18,10 +18,10 @@ const STYLES_HEADER = css` display: block; position: relative; width: 100%; - padding: 64px 24px 48px 42px; + padding: 64px 24px 40px 42px; @media (max-width: ${Constants.sizes.mobile}px) { - padding: 64px 0 48px 16px; + padding: 68px 0 56px 16px; } `; diff --git a/components/core/CircleButtonGray.js b/components/core/CircleButtonGray.js index f4267508..69716b9d 100644 --- a/components/core/CircleButtonGray.js +++ b/components/core/CircleButtonGray.js @@ -23,7 +23,6 @@ const STYLES_BUTTON = css` :hover { background-color: ${Constants.system.brand}; color: ${Constants.system.white}; - transform: scale(1.2); } `; diff --git a/components/core/DataMeter.js b/components/core/DataMeter.js index 4f6c6a47..79c36238 100644 --- a/components/core/DataMeter.js +++ b/components/core/DataMeter.js @@ -11,7 +11,7 @@ const MAX_IN_BYTES = 10737418240; const STYLES_CONTAINER = css` border-radius: 4px; border: 1px solid ${Constants.system.border}; - padding: 24px; + padding: 32px; max-width: 100%; width: 100%; `; @@ -20,31 +20,23 @@ const STYLES_DATA = css` width: 100%; display: flex; align-items: center; - height: 8px; + height: 16px; border-radius: 3px; - background-color: ${Constants.system.border}; + background-color: ${Constants.system.foreground}; overflow: hidden; `; const STYLES_DATA_METER = css` flex-shrink: 0; - height: 100%; - background-color: #2935ff; - background-image: linear-gradient( - to left, - #2935ff, - #342fc4, - #33288b, - #2b2157, - #1d1927 - ); + height: 16px; + background-color: ${Constants.system.brand}; `; const STYLES_ROW = css` display: flex; align-items: flex-end; justify-content: space-between; - font-family: ${Constants.font.code}; + font-family: ${Constants.font.text}; color: ${Constants.system.darkGray}; font-size: 10px; margin-top: 2px; @@ -55,7 +47,7 @@ const STYLES_STATS_ROW = css` display: flex; align-items: flex-end; justify-content: space-between; - font-family: ${Constants.font.code}; + font-family: ${Constants.font.text}; color: ${Constants.system.black}; font-size: 12px; text-transform: uppercase; @@ -71,9 +63,8 @@ const STYLES_RIGHT = css` `; const STYLES_TITLE = css` - font-family: ${Constants.font.semiBold}; - font-weight: 400; - font-size: 14px; + font-family: ${Constants.font.medium}; + font-size: ${Constants.typescale.lvl1}; display: block; margin-bottom: 4px; overflow-wrap: break-word; @@ -84,15 +75,16 @@ export const DataMeterBar = (props) => { return ( -
-
{Strings.bytesToSize(props.bytes)}
-
{Strings.bytesToSize(props.maximumBytes)}
+
+ {Strings.bytesToSize(props.bytes)} of Available{" "} + {Strings.bytesToSize(props.maximumBytes)} Used
+ style={{ color: props.failed ? Constants.system.red : null }} + > {props.leftLabel}
{props.rightLabel}
@@ -101,9 +93,10 @@ export const DataMeterBar = (props) => {
+ }} + >
{ return (
diff --git a/components/core/DataView.js b/components/core/DataView.js index afd66c89..b757c355 100644 --- a/components/core/DataView.js +++ b/components/core/DataView.js @@ -3,55 +3,98 @@ import * as Constants from "~/common/constants"; import * as Strings from "~/common/strings"; import * as System from "~/components/system"; import * as Actions from "~/common/actions"; +import * as SVG from "~/common/svg"; import { css } from "@emotion/react"; +import { Boundary } from "~/components/system/components/fragments/Boundary"; +import { PopoverNavigation } from "~/components/system/components/PopoverNavigation"; -import Section from "~/components/core/Section"; import SlateMediaObject from "~/components/core/SlateMediaObject"; +import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview"; const COLUMNS_SCHEMA = [ - { key: "cid", name: "CID", width: "100%" }, + { + key: "name", + name: Name, + width: "100%", + }, { key: "size", - name: "Size", - width: "84px", - }, - { key: "type", name: "Type", type: "TEXT_TAG", width: "172px" }, - { - key: "networks", - name: "Networks", - type: "NETWORK_TYPE", + name: Size, + width: "104px", }, { - key: "storage", - name: "Storage Deal Status", - width: "148px", - type: "STORAGE_DEAL_STATUS", + key: "more", + name:
, + width: "64px", }, ]; const STYLES_LINK = css` - font-family: ${Constants.font.semiBold}; - font-weight: 400; cursor: pointer; transition: 200ms ease all; + font-size: 0.9rem; + padding: 12px 0px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; :hover { color: ${Constants.system.brand}; } `; -const STYLES_LABEL = css` - letter-spacing: 0.1px; - font-size: 12px; - text-transform: uppercase; - font-family: ${Constants.font.semiBold}; - font-weight: 400; - color: ${Constants.system.black}; +const STYLES_VALUE = css` + font-size: 0.9rem; + padding: 12px 0px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; `; -const STYLES_SECTION = css` - margin: 12px 0 16px 0; +const STYLES_TABLE_VALUE = { + fontFamily: Constants.font.medium, + padding: "0px 24px", +}; + +const STYLES_TABLE_CONTAINER = css` + border: 1px solid rgba(229, 229, 229, 0.75); +`; + +const STYLES_ICON_BOX = css` + display: flex; + justify-content: flex-end; + align-items: center; + padding: 8px; + cursor: pointer; + + :hover { + color: ${Constants.system.brand}; + } +`; + +const STYLES_COPY_INPUT = css` + pointer-events: none; + position: absolute; + opacity: 0; +`; + +const STYLES_IMAGE_GRID = css` + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0 -27px; +`; + +const STYLES_IMAGE_BOX = css` + width: 160px; + height: 160px; + margin: 27px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0px 0px 0px 1px rgba(229, 229, 229, 0.5) inset; + cursor: pointer; `; const delay = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms)); @@ -70,6 +113,7 @@ const delay = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms)); export default class DataView extends React.Component { state = { selectedRowId: null, + menu: null, }; async componentDidMount() { @@ -108,14 +152,27 @@ export default class DataView extends React.Component { }); }; - _handleMakeDeal = (data) => { - this.props.onAction({ - type: "SIDEBAR", - value: "SIDEBAR_FILE_STORAGE_DEAL", - data, + // _handleMakeDeal = (data) => { + // this.props.onAction({ + // type: "SIDEBAR", + // value: "SIDEBAR_FILE_STORAGE_DEAL", + // data, + // }); + // }; + + _handleCopy = (e, value) => { + this._handleHide(); + e.stopPropagation(); + this.setState({ copyValue: value }, () => { + this._ref.select(); + document.execCommand("copy"); }); }; + _handleHide = (e) => { + this.setState({ menu: null }); + }; + _handleDelete = async (cid) => { this.setState({ loading: true }); if ( @@ -152,6 +209,27 @@ export default class DataView extends React.Component { }; render() { + if (this.props.view === "grid") { + return ( +
+ {this.props.items.map((each, index) => ( +
this._handleSelect(index)} + > + +
+ ))} +
+ ); + } const columns = COLUMNS_SCHEMA; const rows = this.props.items.map((each, index) => { const cid = each.ipfs.replace("/ipfs/", ""); @@ -159,32 +237,47 @@ export default class DataView extends React.Component { return { ...each, - cid: ( - this._handleSelect(index)}> - {cid} - + name: ( +
this._handleSelect(index)}> + {each.file || each.name} +
), - size: {Strings.bytesToSize(each.size)}, - children: ( -
- -
Actions
-
- this._handleDelete(cid)} - > - Delete - -
-
- {each.error ? ( - -
- Errors -
-
{each.error}
-
+ size:
{Strings.bytesToSize(each.size)}
, + more: ( +
this.setState({ menu: each.id })} + > + + {this.state.menu === each.id ? ( + + this._handleCopy(e, cid), + }, + { + text: "Delete", + onClick: (e) => { + e.stopPropagation(); + this.setState({ menu: null }, () => + this._handleDelete(cid) + ); + }, + }, + ]} + /> + ) : null}
), @@ -197,22 +290,32 @@ export default class DataView extends React.Component { }; return ( -
+
-
+ { + this._ref = c; + }} + value={this.state.copyValue} + css={STYLES_COPY_INPUT} + /> +
); } } diff --git a/components/core/SceneContent.js b/components/core/SceneContent.js index ea876b4c..25305d5f 100644 --- a/components/core/SceneContent.js +++ b/components/core/SceneContent.js @@ -5,8 +5,6 @@ import { css } from "@emotion/react"; const STYLES_PAGE_CONTENT = css` width: 100%; - ${"" /* max-width: 1074px; - padding: 0px 24px; */} max-width: 1024px; padding: 0px; margin: 0 auto; diff --git a/components/core/SlateMediaObjectPreview.js b/components/core/SlateMediaObjectPreview.js index 48252aae..5d5dfcbc 100644 --- a/components/core/SlateMediaObjectPreview.js +++ b/components/core/SlateMediaObjectPreview.js @@ -78,7 +78,7 @@ export default class SlateMediaObjectPreview extends React.Component { element = (
- +
{this.props.title && !this.props.small ? (
{title}
diff --git a/components/core/SlatePreviewBlock.js b/components/core/SlatePreviewBlock.js index 3711847e..2067e656 100644 --- a/components/core/SlatePreviewBlock.js +++ b/components/core/SlatePreviewBlock.js @@ -17,7 +17,6 @@ const STYLES_IMAGE_ROW = css` flex-wrap: wrap; height: 160px; overflow: hidden; - margin: 0px -18px; @media (max-width: ${Constants.sizes.mobile}px) { justify-content: center; @@ -41,6 +40,14 @@ const STYLES_ITEM_BOX = css` :hover { color: ${Constants.system.brand}; } + + :last-child { + margin-right: 0px; + } + + :first-child { + margin-left: 0px; + } `; const STYLES_IMAGE_ROW_SMALL = css` @@ -49,7 +56,6 @@ const STYLES_IMAGE_ROW_SMALL = css` flex-wrap: wrap; height: 56px; overflow: hidden; - margin: 0px -8px; `; const STYLES_ITEM_BOX_SMALL = css` @@ -60,6 +66,14 @@ const STYLES_ITEM_BOX_SMALL = css` align-items: center; justify-content: center; box-shadow: 0px 0px 0px 1px rgba(229, 229, 229, 0.5) inset; + + :first-child { + margin-left: 0px; + } + + :last-child { + margin-right: 0px; + } `; export function SlatePreviewRow(props) { diff --git a/components/core/TabGroup.js b/components/core/TabGroup.js index 72ea2440..a97f84d4 100644 --- a/components/core/TabGroup.js +++ b/components/core/TabGroup.js @@ -17,7 +17,6 @@ const STYLES_TAB_GROUP = css` const STYLES_TAB = css` padding: 8px 8px 8px 0px; margin-right: 24px; - cursor: pointer; display: inline-block; font-size: ${Constants.typescale.lvl1}; font-family: ${Constants.font.medium}; @@ -31,18 +30,22 @@ const STYLES_TAB = css` export class TabGroup extends React.Component { render() { return ( -
+
{this.props.tabs.map((tab, i) => (
this.props.onChange(i)} + onClick={ + this.props.disabled ? () => {} : () => this.props.onChange(i) + } > {tab}
diff --git a/components/system/components/Table.js b/components/system/components/Table.js index 5a95c37e..cbecf164 100644 --- a/components/system/components/Table.js +++ b/components/system/components/Table.js @@ -54,7 +54,7 @@ const STYLES_TABLE_ROW = css` position: relative; box-sizing: border-box; padding: 0 8px 0 8px; - border-bottom: 1px solid ${Constants.system.gray}; + border-bottom: 1px solid rgba(229, 229, 229, 0.75); display: flex; align-items: flex-start; width: 100%; @@ -69,14 +69,14 @@ const STYLES_TABLE_SELECTED_ROW = css` background-color: ${Constants.system.foreground}; box-sizing: border-box; display: block; - border-bottom: 1px solid ${Constants.system.gray}; + border-bottom: 1px solid rgba(229, 229, 229, 0.75); `; const STYLES_TABLE_TOP_ROW = css` box-sizing: border-box; font-family: ${Constants.font.semiBold}; padding: 0 8px 0 8px; - border-bottom: 1px solid ${Constants.system.gray}; + border-bottom: 1px solid rgba(229, 229, 229, 0.75); display: flex; width: 100%; align-items: flex-start; @@ -130,7 +130,7 @@ export class Table extends React.Component { return ( {this.props.noLabel ? null : ( -
+
{data.columns.map((c, cIndex) => { const text = c.hideLabel ? "" @@ -149,7 +149,9 @@ export class Table extends React.Component { key={`table-top-${c.key}-${cIndex}`} style={{ width: localWidth, - backgroundColor: ac[c.key].color, + backgroundColor: this.props.noColor + ? null + : ac[c.key].color, flexShrink, }} tooltip={c.tooltip} @@ -169,7 +171,7 @@ export class Table extends React.Component { return ( -
+
{Object.keys(ac).map((each, cIndex) => { const field = ac[each]; const text = r[each]; diff --git a/scenes/SceneFilesFolder.js b/scenes/SceneFilesFolder.js index 42c3cb7b..0b575b1b 100644 --- a/scenes/SceneFilesFolder.js +++ b/scenes/SceneFilesFolder.js @@ -1,19 +1,74 @@ import * as React from "react"; import * as Actions from "~/common/actions"; import * as System from "~/components/system"; +import * as SVG from "~/common/svg"; +import * as Constants from "~/common/constants"; import { css } from "@emotion/react"; +import { TabGroup } from "~/components/core/TabGroup"; +import { ButtonPrimary } from "~/components/system/components/Buttons"; import ScenePage from "~/components/core/ScenePage"; import DataView from "~/components/core/DataView"; import DataMeter from "~/components/core/DataMeter"; import ScenePageHeader from "~/components/core/ScenePageHeader"; +import SceneContent from "~/components/core/SceneContent"; + +const VIEW_LIMIT = 20; + +const STYLES_ICON_BOX = css` + height: 32px; + width: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + margin-left: 16px; +`; + +const STYLES_HEADER_LINE = css` + display: flex; + align-items: center; + margin-top: 80px; + margin-bottom: 42px; +`; + +const STYLES_ARROWS = css` + text-align: end; +`; + +const STYLES_ICON_ELEMENT = css` + height: 40px; + width: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + color: #565151; + user-select: none; + cursor: pointer; + pointer-events: auto; + margin: 16px 8px; + + :hover { + color: ${Constants.system.brand}; + } + + svg { + transform: rotate(0deg); + transition: 200ms ease transform; + } +`; const POLLING_INTERVAL = 10000; export default class SceneFilesFolder extends React.Component { _interval; + state = { + view: "list", + startIndex: 0, + }; + loop = async () => { let jobs = []; @@ -46,7 +101,7 @@ export default class SceneFilesFolder extends React.Component { }; componentDidMount() { - this._interval = this.loop(); + this.loop(); } componentWillUnmount() { @@ -61,37 +116,120 @@ export default class SceneFilesFolder extends React.Component { } } + _increment = (direction) => { + if ( + direction > 0 && + this.state.startIndex + VIEW_LIMIT < + this.props.viewer.library[0].children.length + ) { + this.setState({ startIndex: this.state.startIndex + VIEW_LIMIT }); + } else if (direction < 0 && this.state.startIndex - VIEW_LIMIT >= 0) { + this.setState({ startIndex: this.state.startIndex - VIEW_LIMIT }); + } + }; + render() { return ( - - Manage all the data used across your Slates and archive backups on to - the Filecoin Network. - - - - - { + this.props.onAction({ + type: "SIDEBAR", + value: "SIDEBAR_ADD_FILE_TO_BUCKET", + }); + }} + > + Upload Data + + } /> + + + + +
+ + +
{ + this.setState({ view: "list" }); + }} + > + +
+
{ + this.setState({ view: "grid" }); + }} + > + +
+
+
+ + +
+ = 0 + ? null + : { cursor: "not-allowed", color: Constants.system.border } + } + onClick={() => this._increment(-1)} + > + + + this._increment(1)} + > + + +
+
); } diff --git a/scenes/SceneHome.js b/scenes/SceneHome.js index eeec575f..c763462d 100644 --- a/scenes/SceneHome.js +++ b/scenes/SceneHome.js @@ -8,6 +8,7 @@ import Section from "~/components/core/Section"; import ScenePage from "~/components/core/ScenePage"; import DataView from "~/components/core/DataView"; import ScenePageHeader from "~/components/core/ScenePageHeader"; +import SceneContent from "~/components/core/SceneContent"; const STYLES_NUMBER = css` font-family: ${Constants.font.semiBold}; @@ -91,41 +92,33 @@ export default class SceneHome extends React.Component { return ( - Welcome back! Here is your data and slates. + Welcome back! Here is your data. -
- -
- - {this.props.viewer.library[0] ? ( - - ) : null} + + {this.props.viewer.library[0] ? ( +
+ +
+ ) : null} +
); }