mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-23 09:01:56 +03:00
mobile refactor
This commit is contained in:
parent
9e12cb402a
commit
bf079ffc8a
@ -51,6 +51,12 @@ const REJECT_LIST = [
|
||||
"data",
|
||||
];
|
||||
|
||||
export const onMobile = () => {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
||||
navigator.userAgent
|
||||
);
|
||||
};
|
||||
|
||||
export const userRoute = (text) => {
|
||||
if (!USERNAME_REGEX.test(text)) {
|
||||
return false;
|
||||
|
@ -19,13 +19,14 @@ const STYLES_ALERT = `
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
transition: top 0.25s;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
top: 56px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -139,7 +140,7 @@ export class Alert extends React.Component {
|
||||
// NOTE(jim): Replaces the filecoin banner on some navigation pages.
|
||||
if (this.props.filecoin) {
|
||||
return (
|
||||
<div css={STYLES_MESSAGE}>
|
||||
<div css={STYLES_MESSAGE} style={this.props.style}>
|
||||
<div css={STYLES_MESSAGE_BOX} style={{ fontSize: 14 }}>
|
||||
You are on the Filecoin Testnet. Test FIL may take a moment to
|
||||
reach your wallet.
|
||||
@ -149,7 +150,7 @@ export class Alert extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div css={STYLES_MESSAGE}>
|
||||
<div css={STYLES_MESSAGE} style={this.props.style}>
|
||||
<div css={STYLES_MESSAGE_BOX} style={{ fontSize: 14 }}>
|
||||
Please don't upload sensitive information to Slate yet. Private
|
||||
storage is coming soon.
|
||||
@ -165,7 +166,7 @@ export class Alert extends React.Component {
|
||||
return (
|
||||
<div
|
||||
css={STYLES_INFO}
|
||||
style={{ cursor: "pointer" }}
|
||||
style={{ cursor: "pointer", ...this.props.style }}
|
||||
onClick={() =>
|
||||
this.props.onAction({
|
||||
type: "SIDEBAR",
|
||||
|
@ -700,6 +700,7 @@ export default class ApplicationPage extends React.Component {
|
||||
<SceneSignIn
|
||||
onCreateUser={this._handleCreateUser}
|
||||
onAuthenticate={this._handleAuthenticate}
|
||||
onAction={this._handleAction}
|
||||
/>
|
||||
</WebsitePrototypeWrapper>
|
||||
);
|
||||
|
@ -160,6 +160,8 @@ export default class ApplicationHeader extends React.Component {
|
||||
style={{ transform: `rotate(180deg)` }}
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={
|
||||
@ -171,7 +173,8 @@ export default class ApplicationHeader extends React.Component {
|
||||
>
|
||||
<SVG.NavigationArrow height="24px" />
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<span
|
||||
css={this.state.isRefreshing ? STYLES_ROTATION : STYLES_STATIC}
|
||||
style={{ marginLeft: 24 }}
|
||||
@ -180,7 +183,8 @@ export default class ApplicationHeader extends React.Component {
|
||||
<SVG.Refresh height="20px" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={{ marginLeft: 24 }}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Validations from "~/common/validations";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { GlobalTooltip } from "~/components/system/components/fragments/GlobalTooltip";
|
||||
@ -51,6 +52,7 @@ const STYLES_HEADER = css`
|
||||
left: ${Constants.sizes.navigation}px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition: top 0.25s;
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
left: 0;
|
||||
}
|
||||
@ -163,11 +165,59 @@ const STYLES_BLOCK = css`
|
||||
color: rgba(0, 0, 0, 0.25);
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_ONLY = css`
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default class ApplicationLayout extends React.Component {
|
||||
_sidebar;
|
||||
_navigation;
|
||||
_body;
|
||||
|
||||
state = {
|
||||
alertTop: 56,
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
this.prevScrollPos = window.pageYOffset;
|
||||
if (Validations.onMobile()) {
|
||||
window.addEventListener("scroll", this._handleScroll);
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
if (Validations.onMobile()) {
|
||||
window.removeEventListener("scroll", this._handleScroll);
|
||||
}
|
||||
};
|
||||
|
||||
_handleScroll = () => {
|
||||
console.log(document.getElementById("slate-mobile-alert"));
|
||||
let currentScrollPos = window.pageYOffset;
|
||||
if (this.prevScrollPos > currentScrollPos) {
|
||||
if (document.getElementById("slate-mobile-header")) {
|
||||
document.getElementById("slate-mobile-header").style.top = "0px";
|
||||
}
|
||||
this.setState({ alertTop: 56 });
|
||||
} else {
|
||||
if (currentScrollPos > 56) {
|
||||
if (document.getElementById("slate-mobile-header")) {
|
||||
document.getElementById("slate-mobile-header").style.top = "-56px";
|
||||
}
|
||||
this.setState({ alertTop: 0 });
|
||||
}
|
||||
}
|
||||
this.prevScrollPos = currentScrollPos;
|
||||
};
|
||||
|
||||
_handleDismiss = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@ -184,11 +234,7 @@ export default class ApplicationLayout extends React.Component {
|
||||
allowedTypes={["sidebar"]}
|
||||
/>
|
||||
<div css={STYLES_SIDEBAR_HEADER}>
|
||||
<div
|
||||
css={STYLES_BLOCK}
|
||||
onMouseUp={this._handleDismiss}
|
||||
onTouchEnd={this._handleDismiss}
|
||||
>
|
||||
<div css={STYLES_BLOCK} onClick={this._handleDismiss}>
|
||||
<SVG.Dismiss height="24px" />
|
||||
</div>
|
||||
</div>
|
||||
@ -212,8 +258,16 @@ export default class ApplicationLayout extends React.Component {
|
||||
</div>
|
||||
|
||||
<div css={STYLES_CONTENT}>
|
||||
<GlobalTooltip elementRef={this._body} allowedTypes={["body"]} />
|
||||
{/* <GlobalTooltip elementRef={this._body} allowedTypes={["body"]} /> */}
|
||||
<GlobalTooltip allowedTypes={["body"]} />
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<div css={STYLES_HEADER}>{this.props.header}</div>
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_ONLY}>
|
||||
<div css={STYLES_HEADER} id="slate-mobile-header">
|
||||
{this.props.header}
|
||||
</div>
|
||||
</span>
|
||||
<div
|
||||
css={STYLES_BODY_WEB}
|
||||
ref={(c) => {
|
||||
@ -235,14 +289,10 @@ export default class ApplicationLayout extends React.Component {
|
||||
</div>
|
||||
<div css={STYLES_BODY_MOBILE}>
|
||||
<Alert
|
||||
id="slate-mobile-alert"
|
||||
fileLoading={this.props.fileLoading}
|
||||
onAction={this.props.onAction}
|
||||
style={{
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
zIndex: Constants.zindex.modal,
|
||||
}}
|
||||
style={{ top: this.state.alertTop }}
|
||||
/>
|
||||
{this.props.children}
|
||||
</div>
|
||||
|
@ -124,8 +124,7 @@ const Item = (props) => {
|
||||
>
|
||||
<span
|
||||
css={STYLES_EXPANDER}
|
||||
onMouseUp={props.onToggleShow ? props.onToggleShow : null}
|
||||
onTouchEnd={props.onToggleShow ? props.onToggleShow : null}
|
||||
onClick={props.onToggleShow ? props.onToggleShow : null}
|
||||
>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
@ -143,14 +142,7 @@ const Item = (props) => {
|
||||
</span>
|
||||
<span
|
||||
css={STYLES_ICON}
|
||||
onMouseUp={() =>
|
||||
props.onAction({
|
||||
type: "NAVIGATE",
|
||||
value: props.id,
|
||||
data: props.data,
|
||||
})
|
||||
}
|
||||
onTouchEnd={() =>
|
||||
onClick={() =>
|
||||
props.onAction({
|
||||
type: "NAVIGATE",
|
||||
value: props.id,
|
||||
@ -169,14 +161,7 @@ const Item = (props) => {
|
||||
<span
|
||||
css={STYLES_CHILDREN}
|
||||
children={props.children}
|
||||
onMouseUp={() =>
|
||||
props.onAction({
|
||||
type: "NAVIGATE",
|
||||
value: props.id,
|
||||
data: props.data,
|
||||
})
|
||||
}
|
||||
onTouchEnd={() =>
|
||||
onClick={() =>
|
||||
props.onAction({
|
||||
type: "NAVIGATE",
|
||||
value: props.id,
|
||||
@ -267,6 +252,7 @@ export default class ApplicationNavigation extends React.Component {
|
||||
|
||||
return (
|
||||
<div
|
||||
key={each.id}
|
||||
css={
|
||||
each.id === "V1_NAVIGATION_ARCHIVE" ||
|
||||
each.id === "V1_NAVIGATION_API"
|
||||
|
@ -15,6 +15,10 @@ const STYLES_CONTAINER = css`
|
||||
padding: 32px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
padding: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_DATA = css`
|
||||
|
@ -184,6 +184,12 @@ const STYLES_IMAGE_GRID = css`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(214px, 1fr));
|
||||
margin: 0 -27px;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin: 0px -12px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_IMAGE_BOX = css`
|
||||
@ -197,6 +203,18 @@ const STYLES_IMAGE_BOX = css`
|
||||
0 0 40px 0 ${Constants.system.shadow};
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
width: 144px;
|
||||
height: 144px;
|
||||
margin: 12px auto;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const delay = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
@ -601,7 +619,7 @@ export default class DataView extends React.Component {
|
||||
const header = (
|
||||
<div css={STYLES_HEADER_LINE}>
|
||||
<TabGroup disabled tabs={["Uploads"]} style={{ margin: 0 }} />
|
||||
<React.Fragment>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<div
|
||||
css={STYLES_ICON_BOX}
|
||||
onClick={() => {
|
||||
@ -634,7 +652,7 @@ export default class DataView extends React.Component {
|
||||
height="24px"
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
const footer = (
|
||||
@ -738,6 +756,7 @@ export default class DataView extends React.Component {
|
||||
title={each.file || each.name}
|
||||
type={each.type || each.icon}
|
||||
/>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
{numChecked ||
|
||||
this.state.hover === i ||
|
||||
this.state.menu === each.id ? (
|
||||
@ -759,7 +778,9 @@ export default class DataView extends React.Component {
|
||||
}
|
||||
>
|
||||
{this.state.loading[cid] ? (
|
||||
<LoaderSpinner style={{ height: 24, width: 24 }} />
|
||||
<LoaderSpinner
|
||||
style={{ height: 24, width: 24 }}
|
||||
/>
|
||||
) : (
|
||||
<SVG.MoreHorizontal height="24px" />
|
||||
)}
|
||||
@ -831,11 +852,16 @@ export default class DataView extends React.Component {
|
||||
? Constants.system.brand
|
||||
: "rgba(255, 255, 255, 0.75)",
|
||||
}}
|
||||
style={{ position: "absolute", bottom: 8, left: 8 }}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 8,
|
||||
left: 8,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
@ -36,6 +36,10 @@ const STYLES_HEADER = css`
|
||||
max-width: 688px;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
font-size: ${Constants.typescale.lvl3};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_DESCRIPTION = css`
|
||||
|
@ -8,7 +8,6 @@ import { LoaderSpinner } from "~/components/system/components/Loaders";
|
||||
const STYLES_DROPDOWN_CONTAINER = css`
|
||||
box-sizing: border-box;
|
||||
z-index: ${Constants.zindex.modal};
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const STYLES_DROPDOWN = css`
|
||||
@ -21,10 +20,16 @@ const STYLES_DROPDOWN = css`
|
||||
width: 100%;
|
||||
scrollbar-width: none;
|
||||
padding-bottom: 24px;
|
||||
height: calc(100% - 16px);
|
||||
overflow-y: scroll;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
height: calc(100% - 36px);
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_DROPDOWN_ITEM = css`
|
||||
|
@ -30,6 +30,11 @@ const STYLES_CONTAINER = css`
|
||||
border-radius: 4px;
|
||||
background-color: ${Constants.system.white};
|
||||
box-shadow: 0 0 60px 8px rgba(0, 0, 0, 0.03);
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
max-width: 95vw;
|
||||
padding: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MODAL = css`
|
||||
@ -42,8 +47,8 @@ const STYLES_MODAL = css`
|
||||
`;
|
||||
|
||||
const STYLES_SEARCH_DROPDOWN = {
|
||||
height: "calc(100% - 16px)",
|
||||
overflowY: "scroll",
|
||||
// height: "calc(100% - 16px)",
|
||||
// overflowY: "scroll",
|
||||
};
|
||||
|
||||
const STYLES_USER_ENTRY_CONTAINER = css`
|
||||
|
@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Validations from "~/common/validations";
|
||||
import * as Actions from "~/common/actions";
|
||||
|
||||
import { Responsive, WidthProvider } from "react-grid-layout";
|
||||
@ -88,6 +89,12 @@ const STYLES_ACTION_BUTTON = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const ResponsiveReactGridLayout = WidthProvider(Responsive);
|
||||
|
||||
const COLUMN_MAP = { lg: 12, md: 8, sm: 6, xs: 4, xxs: 2 };
|
||||
@ -178,16 +185,25 @@ export default class Slate extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={index} css={STYLES_ITEM}>
|
||||
<div
|
||||
key={index}
|
||||
css={STYLES_ITEM}
|
||||
onClick={
|
||||
Validations.onMobile()
|
||||
? (e) => this._handleSelect(e, index)
|
||||
: () => {}
|
||||
}
|
||||
>
|
||||
<SlateMediaObjectPreview
|
||||
charCap={70}
|
||||
type={data.type}
|
||||
url={data.url}
|
||||
title={data.title || data.name}
|
||||
/>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<figure css={STYLES_BUTTON}>
|
||||
<CircleButtonGray
|
||||
style={{ margin: 8 }}
|
||||
style={{ margin: 8, cursor: "pointer" }}
|
||||
onMouseUp={(e) => this._handleSelect(e, index)}
|
||||
onTouchEnd={(e) => this._handleSelect(e, index)}
|
||||
>
|
||||
@ -204,6 +220,7 @@ export default class Slate extends React.Component {
|
||||
</CircleButtonGray>
|
||||
) : null}
|
||||
</figure>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@ -245,8 +262,7 @@ export default class Slate extends React.Component {
|
||||
</span>
|
||||
<span
|
||||
css={STYLES_ACTION_BUTTON}
|
||||
onMouseUp={this._handleSaveLayout}
|
||||
onTouchEnd={this._handleSaveLayout}
|
||||
onClick={this._handleSaveLayout}
|
||||
style={{
|
||||
backgroundColor:
|
||||
this.props.saving === "IDLE" ? Constants.system.brand : null,
|
||||
|
@ -5,6 +5,14 @@ import * as SVG from "~/common/svg";
|
||||
import { css } from "@emotion/react";
|
||||
import { FileTypeIcon } from "~/components/core/FileTypeIcon";
|
||||
|
||||
const STYLES_IMAGE_CONTAINER = css`
|
||||
background-color: ${Constants.system.foreground};
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-position: 50% 50%;
|
||||
`;
|
||||
|
||||
const STYLES_IMAGE = css`
|
||||
background-color: ${Constants.system.foreground};
|
||||
display: block;
|
||||
@ -53,6 +61,14 @@ export default class SlateMediaObjectPreview extends React.Component {
|
||||
: this.props.title;
|
||||
|
||||
if (this.props.type && this.props.type.startsWith("image/")) {
|
||||
if (this.props.centeredImage) {
|
||||
return (
|
||||
<div
|
||||
css={STYLES_IMAGE_CONTAINER}
|
||||
style={{ backgroundImage: `url(${url})`, ...this.props.imageStyle }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <img css={STYLES_IMAGE} style={this.props.imageStyle} src={url} />;
|
||||
}
|
||||
|
||||
|
@ -323,8 +323,7 @@ export default class SlateMediaObjectSidebar extends React.Component {
|
||||
<span
|
||||
key="sidebar-media-object-delete"
|
||||
css={STYLES_BUTTON}
|
||||
onMouseUp={() => this.props.onDelete(this.props.id)}
|
||||
onTouchEnd={() => this.props.onDelete(this.props.id)}
|
||||
onClick={() => this.props.onDelete(this.props.id)}
|
||||
>
|
||||
{this.props.loading ? (
|
||||
<LoaderSpinner style={{ height: 16, width: 16 }} />
|
||||
|
@ -11,6 +11,18 @@ import { dispatchCustomEvent } from "~/common/custom-events";
|
||||
|
||||
import SlateMediaObjectPreview from "~/components/core/SlateMediaObjectPreview";
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_ONLY = css`
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_CREATE_NEW = css`
|
||||
color: ${Constants.system.darkGray};
|
||||
box-shadow: 0px 0px 0px 1px rgba(229, 229, 229, 0.5) inset;
|
||||
@ -23,7 +35,10 @@ const STYLES_CREATE_NEW = css`
|
||||
margin: 0px 12px;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin: 0 8px;
|
||||
margin: 0;
|
||||
border-radius: 8;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -161,6 +176,11 @@ const STYLES_BLOCK = css`
|
||||
margin: 24px auto 48px auto;
|
||||
max-width: ${Constants.sizes.desktop}px;
|
||||
cursor: pointer;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
padding: 16px;
|
||||
margin: 24px auto;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_TITLE_LINE = css`
|
||||
@ -170,6 +190,10 @@ const STYLES_TITLE_LINE = css`
|
||||
font-size: ${Constants.typescale.lvl1};
|
||||
margin-bottom: 16px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_COPY_INPUT = css`
|
||||
@ -195,6 +219,10 @@ const STYLES_BODY = css`
|
||||
line-height: 20px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_ICON_BOX = css`
|
||||
@ -227,6 +255,20 @@ export default class SlatePreviewBlock extends React.Component {
|
||||
state = {
|
||||
showMenu: false,
|
||||
copyValue: "",
|
||||
windowWidth: 360,
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
this.calculateWidth();
|
||||
window.addEventListener("resize", this.calculateWidth);
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
window.removeEventListener("resize", this.calculateWidth);
|
||||
};
|
||||
|
||||
calculateWidth = () => {
|
||||
this.setState({ windowWidth: window.innerWidth });
|
||||
};
|
||||
|
||||
_handleCopy = (e, value) => {
|
||||
@ -267,6 +309,9 @@ export default class SlatePreviewBlock extends React.Component {
|
||||
if (!this.props.editing && !this.props.slate.data.objects.length) {
|
||||
return null;
|
||||
}
|
||||
let first = this.props.slate.data.objects
|
||||
? this.props.slate.data.objects[0]
|
||||
: null;
|
||||
let contextMenu = (
|
||||
<React.Fragment>
|
||||
<Boundary
|
||||
@ -387,10 +432,47 @@ export default class SlatePreviewBlock extends React.Component {
|
||||
) : (
|
||||
<div style={{ height: "8px" }} />
|
||||
)}
|
||||
<span css={STYLES_MOBILE_ONLY}>
|
||||
<div
|
||||
css={STYLES_TITLE}
|
||||
style={{ marginBottom: 8, fontSize: Constants.typescale.lvl1 }}
|
||||
>
|
||||
{this.props.slate.data.name}
|
||||
</div>
|
||||
<div style={{ marginBottom: 16, fontSize: 12 }}>
|
||||
{this.props.slate.data.objects.length} Object
|
||||
{this.props.slate.data.objects.length === 1 ? "" : "s"}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: `${this.state.windowWidth - 80}px`,
|
||||
}}
|
||||
>
|
||||
{first ? (
|
||||
<SlateMediaObjectPreview
|
||||
centeredImage
|
||||
charCap={30}
|
||||
type={first.type}
|
||||
url={first.url}
|
||||
style={{ borderRadius: 8 }}
|
||||
imageStyle={{ borderRadius: 8 }}
|
||||
title={first.title || first.name}
|
||||
/>
|
||||
) : (
|
||||
<div css={STYLES_CREATE_NEW} key="add-files">
|
||||
<SVG.Plus height="24px" />
|
||||
<div>Add Files</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<SlatePreviewRow
|
||||
{...this.props}
|
||||
previewStyle={this.props.previewStyle}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -11,6 +11,11 @@ const STYLES_TAB_GROUP = css`
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin: 24px 0px 24px 0px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_TAB = css`
|
||||
@ -23,6 +28,7 @@ const STYLES_TAB = css`
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin-right: 12px;
|
||||
font-size: ${Constants.typescale.lvl1};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -87,6 +87,34 @@ const STYLES_EXPANDER = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_DISMISS_BOX = css`
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
color: ${Constants.system.darkGray};
|
||||
cursor: pointer;
|
||||
|
||||
:hover {
|
||||
color: ${Constants.system.black};
|
||||
}
|
||||
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_ONLY = css`
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export class GlobalViewerCID extends React.Component {
|
||||
state = {
|
||||
index: 0,
|
||||
@ -156,8 +184,11 @@ export class GlobalViewerCID extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
_handleClose = () =>
|
||||
_handleClose = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
this.setState({ visible: false, index: 0, loading: false, saving: false });
|
||||
};
|
||||
|
||||
_handleCreate = (e) => {
|
||||
const shouldPersist =
|
||||
@ -202,21 +233,20 @@ export class GlobalViewerCID extends React.Component {
|
||||
<div css={STYLES_ROOT_CONTENT} style={this.props.style}>
|
||||
<span
|
||||
css={STYLES_BOX}
|
||||
onMouseUp={this._handlePrevious}
|
||||
onTouchEnd={this._handlePrevious}
|
||||
onClick={this._handlePrevious}
|
||||
style={{ top: 0, left: 16, bottom: 0 }}
|
||||
>
|
||||
<SVG.ChevronLeft height="20px" />
|
||||
</span>
|
||||
<span
|
||||
css={STYLES_BOX}
|
||||
onMouseUp={this._handleNext}
|
||||
onTouchEnd={this._handleNext}
|
||||
onClick={this._handleNext}
|
||||
style={{ top: 0, right: 16, bottom: 0 }}
|
||||
>
|
||||
<SVG.ChevronRight height="20px" />
|
||||
</span>
|
||||
{current.component}
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<div
|
||||
css={STYLES_EXPANDER}
|
||||
onClick={() =>
|
||||
@ -229,7 +259,12 @@ export class GlobalViewerCID extends React.Component {
|
||||
<SVG.Minimize height="24px" />
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
<div css={STYLES_DISMISS_BOX} onClick={this._handleClose}>
|
||||
<SVG.Dismiss height="24px" />
|
||||
</div>
|
||||
</div>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<GlobalViewerCIDSidebar
|
||||
display={this.state.showSidebar ? "block" : "none"}
|
||||
onClose={this._handleClose}
|
||||
@ -240,6 +275,7 @@ export class GlobalViewerCID extends React.Component {
|
||||
onAction={this.props.onAction}
|
||||
{...current}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -116,12 +116,7 @@ export default class GlobalViewerCIDSidebar extends React.Component {
|
||||
|
||||
if (this.props.onClose) {
|
||||
elements.push(
|
||||
<div
|
||||
key="s-1"
|
||||
css={STYLES_DISMISS_BOX}
|
||||
onMouseUp={this.props.onClose}
|
||||
onTouchEnd={this.props.onClose}
|
||||
>
|
||||
<div key="s-1" css={STYLES_DISMISS_BOX} onClick={this.props.onClose}>
|
||||
<SVG.Dismiss height="24px" />
|
||||
</div>
|
||||
);
|
||||
|
@ -78,8 +78,7 @@ export const ButtonPrimary = (props) => {
|
||||
children={props.children}
|
||||
type={props.label}
|
||||
htmlFor={props.htmlFor}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -92,8 +91,7 @@ export const ButtonPrimary = (props) => {
|
||||
: STYLES_BUTTON_PRIMARY
|
||||
}
|
||||
style={{ ...props.style, width: props.full ? "100%" : "auto" }}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
@ -153,8 +151,7 @@ export const ButtonSecondary = (props) => {
|
||||
: STYLES_BUTTON_SECONDARY
|
||||
}
|
||||
style={{ ...props.style, width: props.full ? "100%" : "auto" }}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
children={props.children}
|
||||
type={props.label}
|
||||
htmlFor={props.htmlFor}
|
||||
@ -169,8 +166,7 @@ export const ButtonSecondary = (props) => {
|
||||
? STYLES_BUTTON_SECONDARY_TRANSPARENT
|
||||
: STYLES_BUTTON_SECONDARY
|
||||
}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
children={props.children}
|
||||
style={{ ...props.style, width: props.full ? "100%" : "auto" }}
|
||||
/>
|
||||
@ -208,8 +204,7 @@ export const ButtonDisabled = (props) => {
|
||||
? STYLES_BUTTON_DISABLED_TRANSPARENT
|
||||
: STYLES_BUTTON_DISABLED
|
||||
}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
children={props.children}
|
||||
type={props.label}
|
||||
htmlFor={props.htmlFor}
|
||||
@ -275,8 +270,7 @@ export const ButtonWarning = (props) => {
|
||||
children={props.children}
|
||||
type={props.label}
|
||||
htmlFor={props.htmlFor}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -289,8 +283,7 @@ export const ButtonWarning = (props) => {
|
||||
: STYLES_BUTTON_WARNING
|
||||
}
|
||||
style={{ ...props.style, width: props.full ? "100%" : "auto" }}
|
||||
onMouseUp={props.onClick}
|
||||
onTouchEnd={props.onClick}
|
||||
onClick={props.onClick}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
|
@ -36,6 +36,10 @@ const STYLES_USER = css`
|
||||
color: ${Constants.system.brand};
|
||||
font-family: ${Constants.font.medium};
|
||||
font-size: ${Constants.typescale.lvl1};
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin: 12px 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_BUTTONS = css`
|
||||
@ -43,6 +47,11 @@ const STYLES_BUTTONS = css`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-right: 48px;
|
||||
justify-content: flex-end;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_ITEM_BOX = css`
|
||||
@ -54,6 +63,10 @@ const STYLES_ITEM_BOX = css`
|
||||
padding: 8px;
|
||||
margin-right: 48px;
|
||||
color: ${Constants.system.darkGray};
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_ACTION_BUTTON = css`
|
||||
@ -114,6 +127,18 @@ const STYLES_COPY_INPUT = css`
|
||||
opacity: 0;
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_ONLY = css`
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default class SceneDirectory extends React.Component {
|
||||
_ref;
|
||||
|
||||
@ -180,6 +205,33 @@ export default class SceneDirectory extends React.Component {
|
||||
})
|
||||
.map((relation) => {
|
||||
let button = (
|
||||
<React.Fragment>
|
||||
<span css={STYLES_MOBILE_ONLY}>
|
||||
<div css={STYLES_BUTTONS}>
|
||||
<div
|
||||
css={STYLES_ITEM_BOX}
|
||||
onClick={(e) => this._handleAccept(e, relation.owner.id)}
|
||||
>
|
||||
<SVG.CheckBox
|
||||
height="24px"
|
||||
style={{ color: Constants.system.brand }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
css={STYLES_ITEM_BOX}
|
||||
style={{ marginRight: 0 }}
|
||||
onClick={(e) => {
|
||||
this._handleDelete(e, relation.id);
|
||||
}}
|
||||
>
|
||||
<SVG.Dismiss
|
||||
height="24px"
|
||||
style={{ color: Constants.system.gray }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<span css={STYLES_MOBILE_HIDDEN}>
|
||||
<div css={STYLES_BUTTONS}>
|
||||
<ButtonPrimary
|
||||
transparent
|
||||
@ -198,6 +250,8 @@ export default class SceneDirectory extends React.Component {
|
||||
Decline
|
||||
</ButtonSecondary>
|
||||
</div>
|
||||
</span>
|
||||
</React.Fragment>
|
||||
);
|
||||
return (
|
||||
<UserEntry
|
||||
|
@ -45,10 +45,7 @@ export default class SceneFilesFolder extends React.Component {
|
||||
/>
|
||||
|
||||
<TabGroup disabled tabs={["Usage"]} />
|
||||
<DataMeter
|
||||
stats={this.props.viewer.stats}
|
||||
style={{ margin: "48px 0 48px 0" }}
|
||||
/>
|
||||
<DataMeter stats={this.props.viewer.stats} />
|
||||
{this.props.viewer.library[0].children &&
|
||||
this.props.viewer.library[0].children.length ? (
|
||||
<DataView
|
||||
|
@ -2,6 +2,7 @@ import * as React from "react";
|
||||
import * as System from "~/components/system";
|
||||
import * as Actions from "~/common/actions";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as Validations from "~/common/validations";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Window from "~/common/window";
|
||||
@ -27,6 +28,12 @@ const STYLES_ICONS = css`
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const STYLES_ACTIONS = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
padding-left: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_USERNAME = css`
|
||||
cursor: pointer;
|
||||
|
||||
@ -35,6 +42,18 @@ const STYLES_USERNAME = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_HIDDEN = css`
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_MOBILE_ONLY = css`
|
||||
@media (min-width: ${Constants.sizes.mobile}px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const moveIndex = (set, fromIndex, toIndex) => {
|
||||
const element = set[fromIndex];
|
||||
set.splice(fromIndex, 1);
|
||||
@ -416,6 +435,45 @@ export default class SceneSlate extends React.Component {
|
||||
return subscription.target_slate_id === this.props.current.id;
|
||||
}).length;
|
||||
|
||||
let onMobile = Validations.onMobile();
|
||||
let actions = this.state.editing ? (
|
||||
<span css={STYLES_ACTIONS}>
|
||||
<CircleButtonGray onClick={this._handleAdd} style={{ marginRight: 16 }}>
|
||||
<SVG.Plus height="16px" />
|
||||
</CircleButtonGray>
|
||||
{isPublic ? (
|
||||
<CircleButtonGray
|
||||
onClick={() => this._handleSlateLink()}
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<SVG.DeepLink height="16px" />
|
||||
</CircleButtonGray>
|
||||
) : null}
|
||||
<CircleButtonGray onClick={this._handleShowSettings}>
|
||||
<SVG.Settings height="16px" />
|
||||
</CircleButtonGray>
|
||||
</span>
|
||||
) : (
|
||||
<div onClick={this._handleFollow}>
|
||||
{following ? (
|
||||
<ButtonSecondary
|
||||
transparent
|
||||
style={{ minWidth: 120, paddingLeft: 0 }}
|
||||
loading={this.state.followLoading}
|
||||
>
|
||||
Unfollow
|
||||
</ButtonSecondary>
|
||||
) : (
|
||||
<ButtonPrimary
|
||||
transparent
|
||||
style={{ minWidth: 120, paddingLeft: 0 }}
|
||||
loading={this.state.followLoading}
|
||||
>
|
||||
Follow
|
||||
</ButtonPrimary>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<ScenePage
|
||||
style={{ paddingLeft: "24px", paddingRight: "24px" }}
|
||||
@ -445,61 +503,15 @@ export default class SceneSlate extends React.Component {
|
||||
data.name
|
||||
)
|
||||
}
|
||||
actions={
|
||||
this.state.editing ? (
|
||||
<React.Fragment>
|
||||
<CircleButtonGray
|
||||
onMouseUp={this._handleAdd}
|
||||
onTouchEnd={this._handleAdd}
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<SVG.Plus height="16px" />
|
||||
</CircleButtonGray>
|
||||
{isPublic ? (
|
||||
<CircleButtonGray
|
||||
onMouseUp={() => this._handleSlateLink()}
|
||||
onTouchEnd={() => this._handleSlateLink()}
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<SVG.DeepLink height="16px" />
|
||||
</CircleButtonGray>
|
||||
) : null}
|
||||
<CircleButtonGray
|
||||
onMouseUp={this._handleShowSettings}
|
||||
onTouchEnd={this._handleShowSettings}
|
||||
>
|
||||
<SVG.Settings height="16px" />
|
||||
</CircleButtonGray>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<div onClick={this._handleFollow}>
|
||||
{following ? (
|
||||
<ButtonSecondary
|
||||
transparent
|
||||
style={{ minWidth: 120 }}
|
||||
loading={this.state.followLoading}
|
||||
>
|
||||
Unfollow
|
||||
</ButtonSecondary>
|
||||
) : (
|
||||
<ButtonPrimary
|
||||
transparent
|
||||
style={{ minWidth: 120 }}
|
||||
loading={this.state.followLoading}
|
||||
>
|
||||
Follow
|
||||
</ButtonPrimary>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
actions={<span css={STYLES_MOBILE_HIDDEN}>actions</span>}
|
||||
>
|
||||
<ProcessedText text={body} />
|
||||
</ScenePageHeader>
|
||||
<span css={STYLES_MOBILE_ONLY}>{actions}</span>
|
||||
{objects && objects.length ? (
|
||||
layouts ? (
|
||||
<Slate
|
||||
editing={this.state.editing}
|
||||
editing={onMobile ? false : this.state.editing}
|
||||
saving={this.state.saving}
|
||||
items={objects}
|
||||
layouts={layouts}
|
||||
|
@ -72,8 +72,7 @@ export default class SceneSlates extends React.Component {
|
||||
actions={
|
||||
this.state.tab === 0 ? (
|
||||
<CircleButtonGray
|
||||
onMouseUp={this._handleAdd}
|
||||
onTouchEnd={this._handleAdd}
|
||||
onClick={this._handleAdd}
|
||||
style={{ marginLeft: 12 }}
|
||||
>
|
||||
<SVG.Plus height="16px" />
|
||||
|
Loading…
Reference in New Issue
Block a user