mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-24 01:23:08 +03:00
mobile menu: uses new tooltip wrapper
This commit is contained in:
parent
607c4b91ea
commit
8465d8a481
@ -2,8 +2,8 @@ import * as React from "react";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as OldSVG from "~/components/system/svg";
|
||||
|
||||
import { TooltipWrapper, dispatchCustomEvent, PopoverNavigation } from "~/components/system";
|
||||
import { css } from "@emotion/react";
|
||||
import { Tooltip } from "react-tippy";
|
||||
|
||||
import Dismissible from "~/components/core/Dismissible";
|
||||
import CircleButtonLight from "~/components/core/CircleButtonLight";
|
||||
@ -12,34 +12,79 @@ const STYLES_ANCHOR = css`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const APPLICATION_CONTROL_MENU_ID = "application-control-menu";
|
||||
|
||||
export default class ApplicationControlMenu extends React.Component {
|
||||
state = {};
|
||||
state = { visible: false };
|
||||
|
||||
_handleClick = (e) => {
|
||||
if (this.props.popover) {
|
||||
this.setState({ visible: !this.state.visible });
|
||||
}
|
||||
this.setState({ visible: !this.state.visible });
|
||||
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick(e);
|
||||
}
|
||||
dispatchCustomEvent({
|
||||
name: "show-tooltip",
|
||||
detail: {
|
||||
id: APPLICATION_CONTROL_MENU_ID,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
_handleHide = () => {
|
||||
this.setState({ visible: false });
|
||||
return dispatchCustomEvent({
|
||||
name: "hide-tooltip",
|
||||
detail: {
|
||||
id: APPLICATION_CONTROL_MENU_ID,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
_handleNavigateTo = (data) => {
|
||||
this._handleHide();
|
||||
return this.props.onNavigateTo(data);
|
||||
};
|
||||
|
||||
_handleAction = (data) => {
|
||||
this._handleHide();
|
||||
return this.props.onAction(data);
|
||||
};
|
||||
|
||||
_handleSignOut = (data) => {
|
||||
this._handleHide();
|
||||
return this.props.onSignOut(data);
|
||||
};
|
||||
|
||||
render() {
|
||||
const title = this.state.visible ? "Close menu" : "Open settings menu";
|
||||
|
||||
return (
|
||||
<Dismissible
|
||||
css={STYLES_ANCHOR}
|
||||
captureResize={false}
|
||||
captureScroll={true}
|
||||
enabled={this.state.visible}
|
||||
onOutsideRectEvent={this._handleHide}
|
||||
style={this.props.style}>
|
||||
<TooltipWrapper
|
||||
id={APPLICATION_CONTROL_MENU_ID}
|
||||
type="navigation"
|
||||
horizontal="right"
|
||||
vertical="below"
|
||||
content={
|
||||
<Dismissible
|
||||
css={STYLES_ANCHOR}
|
||||
captureResize={true}
|
||||
captureScroll={false}
|
||||
enabled
|
||||
onOutsideRectEvent={this._handleHide}
|
||||
style={this.props.style}>
|
||||
<PopoverNavigation
|
||||
style={{
|
||||
left: 0,
|
||||
top: "24px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onNavigateTo={this._handleNavigateTo}
|
||||
onAction={this._handleAction}
|
||||
onSignOut={this._handleSignOut}
|
||||
navigation={[
|
||||
{ text: "Profile & account settings", value: 13 },
|
||||
{ text: "Filecoin settings", value: 14 },
|
||||
{ text: "Sign out", value: 0, action: "SIGN_OUT" },
|
||||
]}
|
||||
/>
|
||||
</Dismissible>
|
||||
}>
|
||||
<CircleButtonLight
|
||||
onClick={this._handleClick}
|
||||
style={{
|
||||
@ -48,9 +93,7 @@ export default class ApplicationControlMenu extends React.Component {
|
||||
}}>
|
||||
<OldSVG.ChevronDown height="20px" />
|
||||
</CircleButtonLight>
|
||||
|
||||
{this.state.visible ? this.props.popover : null}
|
||||
</Dismissible>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,23 @@ const STYLES_SCROLL = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_NO_VISIBLE_SCROLL = css`
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-y: scroll;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
display: none;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: ${Constants.system.foreground};
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: ${Constants.system.darkGray};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_LAYOUT = css`
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@ -74,12 +91,13 @@ const STYLES_BODY_MOBILE = css`
|
||||
`;
|
||||
|
||||
const STYLES_NAVIGATION = css`
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
height: 100vh;
|
||||
z-index: ${Constants.zindex.navigation};
|
||||
width: ${Constants.sizes.navigation}px;
|
||||
border-right: 1px solid ${Constants.system.border};
|
||||
${STYLES_SCROLL}
|
||||
${STYLES_NO_VISIBLE_SCROLL}
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
width: auto;
|
||||
}
|
||||
@ -130,16 +148,13 @@ export default class ApplicationLayout extends React.Component {
|
||||
if (this.props.sidebar) {
|
||||
sidebarElements = (
|
||||
<React.Fragment>
|
||||
<GlobalTooltip elementRef={this._sidebar} allowedTypes={["sidebar"]} />
|
||||
<div css={STYLES_SIDEBAR_HEADER}>
|
||||
<div css={STYLES_BLOCK} onClick={this.props.onDismissSidebar}>
|
||||
<SVG.Dismiss height="24px" />
|
||||
</div>
|
||||
</div>
|
||||
<div css={STYLES_SIDEBAR_CONTENT}>{this.props.sidebar}</div>
|
||||
<GlobalTooltip
|
||||
elementRef={this._sidebar}
|
||||
allowedTypes={["sidebar"]}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@ -149,36 +164,28 @@ export default class ApplicationLayout extends React.Component {
|
||||
css={STYLES_NAVIGATION}
|
||||
ref={(c) => {
|
||||
this._navigation = c;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
<GlobalTooltip elementRef={this._navigation} allowedTypes={["navigation"]} />
|
||||
{this.props.navigation}
|
||||
<GlobalTooltip
|
||||
elementRef={this._navigation}
|
||||
allowedTypes={["navigation"]}
|
||||
/>
|
||||
</div>
|
||||
<div css={STYLES_CONTENT}>
|
||||
<GlobalTooltip elementRef={this._body} allowedTypes={["body"]} />
|
||||
<div css={STYLES_HEADER}>{this.props.header}</div>
|
||||
<div
|
||||
css={STYLES_BODY_WEB}
|
||||
ref={(c) => {
|
||||
this._body = c;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
<div css={STYLES_BODY_MOBILE}>
|
||||
{this.props.sidebar ? sidebarElements : this.props.children}
|
||||
</div>
|
||||
<GlobalTooltip elementRef={this._body} allowedTypes={["body"]} />
|
||||
<div css={STYLES_BODY_MOBILE}>{this.props.sidebar ? sidebarElements : this.props.children}</div>
|
||||
</div>
|
||||
{this.props.sidebar ? (
|
||||
<div
|
||||
css={STYLES_SIDEBAR_WEB}
|
||||
ref={(c) => {
|
||||
this._sidebar = c;
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{sidebarElements}
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -152,34 +152,17 @@ const STYLES_ICON_ELEMENT = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const Item = ({
|
||||
data,
|
||||
id,
|
||||
activeIds,
|
||||
level,
|
||||
children,
|
||||
showActive,
|
||||
decorator,
|
||||
onToggleShow,
|
||||
onNavigateTo,
|
||||
}) => {
|
||||
const Item = ({ data, id, activeIds, level, children, showActive, decorator, onToggleShow, onNavigateTo }) => {
|
||||
return (
|
||||
<span
|
||||
css={STYLES_NAVIGATION_ITEM}
|
||||
style={{ padding: `0 0 0 ${level * 16}px` }}
|
||||
>
|
||||
<span css={STYLES_NAVIGATION_ITEM} style={{ padding: `0 0 0 ${level * 16}px` }}>
|
||||
<span css={STYLES_EXPANDER} onClick={onToggleShow ? onToggleShow : null}>
|
||||
<span
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={{
|
||||
color: activeIds[id] ? Constants.system.brand : null,
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{onToggleShow ? (
|
||||
<SVG.ExpandArrow
|
||||
height="8px"
|
||||
style={showActive ? { transform: `rotate(90deg)` } : null}
|
||||
/>
|
||||
<SVG.ExpandArrow height="8px" style={showActive ? { transform: `rotate(90deg)` } : null} />
|
||||
) : null}
|
||||
</span>
|
||||
</span>
|
||||
@ -188,8 +171,7 @@ const Item = ({
|
||||
css={STYLES_ICON_ELEMENT}
|
||||
style={{
|
||||
color: activeIds[id] ? Constants.system.brand : null,
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{IconMap[decorator]}
|
||||
</span>
|
||||
</span>
|
||||
@ -198,8 +180,7 @@ const Item = ({
|
||||
onClick={() => onNavigateTo({ id }, data)}
|
||||
style={{
|
||||
color: activeIds[id] ? Constants.system.brand : null,
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
</span>
|
||||
@ -216,17 +197,7 @@ class NodeReference extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
activeId,
|
||||
activeIds,
|
||||
level,
|
||||
children,
|
||||
treeChildren,
|
||||
decorator,
|
||||
onNavigateTo,
|
||||
data,
|
||||
} = this.props;
|
||||
const { id, activeId, activeIds, level, children, treeChildren, decorator, onNavigateTo, data } = this.props;
|
||||
const { showTreeChildren } = this.state;
|
||||
|
||||
let showActive = showTreeChildren || activeIds[id];
|
||||
@ -244,10 +215,7 @@ class NodeReference extends React.Component {
|
||||
treeChildren={treeChildren}
|
||||
onNavigateTo={onNavigateTo}
|
||||
decorator={decorator}
|
||||
onToggleShow={
|
||||
treeChildren && treeChildren.length ? this._handleToggleShow : null
|
||||
}
|
||||
>
|
||||
onToggleShow={treeChildren && treeChildren.length ? this._handleToggleShow : null}>
|
||||
{children}
|
||||
</Item>
|
||||
|
||||
@ -271,8 +239,7 @@ class NodeReference extends React.Component {
|
||||
onNavigateTo={onNavigateTo}
|
||||
level={level + 1}
|
||||
treeChildren={child.children}
|
||||
decorator={child.decorator}
|
||||
>
|
||||
decorator={child.decorator}>
|
||||
{child.name}
|
||||
</NodeReference>
|
||||
);
|
||||
@ -289,31 +256,12 @@ export default class ApplicationNavigation extends React.Component {
|
||||
<nav css={STYLES_NAVIGATION}>
|
||||
<div css={STYLES_NAVIGATION_HEADER}>
|
||||
<ApplicationControlMenu
|
||||
popover={
|
||||
<System.PopoverNavigation
|
||||
style={{
|
||||
left: 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" },
|
||||
]}
|
||||
/>
|
||||
}
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
onAction={this.props.onAction}
|
||||
onSignOut={this.props.onSignOut}
|
||||
/>
|
||||
|
||||
<a
|
||||
css={STYLES_PROFILE}
|
||||
style={{ marginLeft: 16 }}
|
||||
href={`/${this.props.viewer.username}`}
|
||||
target="_blank"
|
||||
>
|
||||
<a css={STYLES_PROFILE} style={{ marginLeft: 16 }} href={`/${this.props.viewer.username}`} target="_blank">
|
||||
<span
|
||||
css={STYLES_PROFILE_IMAGE}
|
||||
style={{
|
||||
@ -342,8 +290,7 @@ export default class ApplicationNavigation extends React.Component {
|
||||
onNavigateTo={this.props.onNavigateTo}
|
||||
level={0}
|
||||
treeChildren={each.children}
|
||||
decorator={each.decorator}
|
||||
>
|
||||
decorator={each.decorator}>
|
||||
{each.name}
|
||||
</NodeReference>
|
||||
);
|
||||
|
@ -105,8 +105,7 @@ export default class WebRectBoundary extends React.PureComponent {
|
||||
this._root = c;
|
||||
}}
|
||||
style={this.props.style}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
onClick={this.props.onClick}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
|
@ -13,8 +13,7 @@ const STYLES_POPOVER = css`
|
||||
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);
|
||||
box-shadow: inset 0 0 0 1px ${Constants.system.border}, 0 1px 4px rgba(0, 0, 0, 0.07);
|
||||
`;
|
||||
|
||||
const STYLES_POPOVER_ITEM = css`
|
||||
@ -51,22 +50,14 @@ export class PopoverNavigation extends React.Component {
|
||||
{this.props.navigation.map((each) => {
|
||||
if (each.action === "SIGN_OUT") {
|
||||
return (
|
||||
<div
|
||||
key={each.value}
|
||||
css={STYLES_POPOVER_ITEM}
|
||||
onClick={this.props.onSignOut}
|
||||
>
|
||||
<div key={each.value} css={STYLES_POPOVER_ITEM} onClick={this.props.onSignOut}>
|
||||
{each.text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={each.value}
|
||||
css={STYLES_POPOVER_ITEM}
|
||||
onClick={() => this.props.onNavigateTo({ id: each.value })}
|
||||
>
|
||||
<div key={each.value} css={STYLES_POPOVER_ITEM} onClick={() => this.props.onNavigateTo({ id: each.value })}>
|
||||
{each.text}
|
||||
</div>
|
||||
);
|
||||
|
@ -33,12 +33,8 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
getStyle = (rect, bubbleRect, vertical, horizontal) => {
|
||||
let yOffset = this.props.elementRef
|
||||
? this.props.elementRef.scrollTop
|
||||
: window.pageYOffset;
|
||||
let xOffset = this.props.elementRef
|
||||
? this.props.elementRef.scrollLeft
|
||||
: window.pageXOffset;
|
||||
let yOffset = this.props.elementRef ? this.props.elementRef.scrollTop : window.pageYOffset;
|
||||
let xOffset = this.props.elementRef ? this.props.elementRef.scrollLeft : window.pageXOffset;
|
||||
let style = { position: "absolute" };
|
||||
switch (vertical) {
|
||||
case "above":
|
||||
@ -48,9 +44,7 @@ export class GlobalTooltip extends React.Component {
|
||||
style.top = `${rect.bottom - bubbleRect.height + yOffset}px`;
|
||||
break;
|
||||
case "center":
|
||||
style.top = `${
|
||||
rect.top + 0.5 * rect.height - 0.5 * bubbleRect.height + yOffset
|
||||
}px`;
|
||||
style.top = `${rect.top + 0.5 * rect.height - 0.5 * bubbleRect.height + yOffset}px`;
|
||||
break;
|
||||
case "down":
|
||||
style.top = `${rect.top + yOffset}px`;
|
||||
@ -67,9 +61,7 @@ export class GlobalTooltip extends React.Component {
|
||||
style.left = `${rect.right - bubbleRect.width + xOffset}px`;
|
||||
break;
|
||||
case "center":
|
||||
style.left = `${
|
||||
rect.left + 0.5 * rect.width - 0.5 * bubbleRect.width + xOffset
|
||||
}px`;
|
||||
style.left = `${rect.left + 0.5 * rect.width - 0.5 * bubbleRect.width + xOffset}px`;
|
||||
break;
|
||||
case "right":
|
||||
style.left = `${rect.left + xOffset}px`;
|
||||
@ -82,12 +74,8 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
getOrientation = (rect, bubbleRect, vertical, horizontal) => {
|
||||
let yOffset = this.props.elementRef
|
||||
? this.props.elementRef.scrollTop
|
||||
: window.pageYOffset;
|
||||
let xOffset = this.props.elementRef
|
||||
? this.props.elementRef.scrollLeft
|
||||
: window.pageXOffset;
|
||||
let yOffset = this.props.elementRef ? this.props.elementRef.scrollTop : window.pageYOffset;
|
||||
let xOffset = this.props.elementRef ? this.props.elementRef.scrollLeft : window.pageXOffset;
|
||||
if (!vertical) {
|
||||
if (bubbleRect.height > rect.top + yOffset) {
|
||||
vertical = "below";
|
||||
@ -116,12 +104,12 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
_handleAdd = (e) => {
|
||||
if (
|
||||
this.props.allowedTypes &&
|
||||
!this.props.allowedTypes.includes(e.detail.type)
|
||||
)
|
||||
if (this.props.allowedTypes && !this.props.allowedTypes.includes(e.detail.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltips = this.state.tooltips;
|
||||
|
||||
tooltips[e.detail.id] = {
|
||||
id: e.detail.id,
|
||||
show: false,
|
||||
@ -135,11 +123,10 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
_handleRemove = (e) => {
|
||||
if (
|
||||
this.props.allowedTypes &&
|
||||
!this.props.allowedTypes.includes(e.detail.type)
|
||||
)
|
||||
if (this.props.allowedTypes && !this.props.allowedTypes.includes(e.detail.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.tooltips[e.detail.id]) {
|
||||
let tooltips = this.state.tooltips;
|
||||
delete tooltips[e.detail.id];
|
||||
@ -148,11 +135,6 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
_handleShow = (e) => {
|
||||
if (
|
||||
this.props.allowedTypes &&
|
||||
!this.props.allowedTypes.includes(e.detail.type)
|
||||
)
|
||||
return;
|
||||
if (this.state.tooltips[e.detail.id]) {
|
||||
let tooltips = this.state.tooltips;
|
||||
if (!tooltips[e.detail.id].style) {
|
||||
@ -171,11 +153,6 @@ export class GlobalTooltip extends React.Component {
|
||||
};
|
||||
|
||||
_handleHide = (e) => {
|
||||
if (
|
||||
this.props.allowedTypes &&
|
||||
!this.props.allowedTypes.includes(e.detail.type)
|
||||
)
|
||||
return;
|
||||
if (this.state.tooltips[e.detail.id]) {
|
||||
let tooltips = this.state.tooltips;
|
||||
tooltips[e.detail.id].show = false;
|
||||
@ -214,8 +191,9 @@ export class TooltipWrapper extends React.Component {
|
||||
sample: true,
|
||||
};
|
||||
|
||||
componentDidMount = () => {
|
||||
componentDidMount = async () => {
|
||||
let bubbleRect = this._bubble.getBoundingClientRect();
|
||||
|
||||
dispatchCustomEvent({
|
||||
name: "add-tooltip",
|
||||
detail: {
|
||||
@ -247,8 +225,7 @@ export class TooltipWrapper extends React.Component {
|
||||
this._bubble = c;
|
||||
}}
|
||||
style={{ display: "inline-flex" }}
|
||||
css={STYLES_INVISIBLE}
|
||||
>
|
||||
css={STYLES_INVISIBLE}>
|
||||
{this.props.content}
|
||||
</div>
|
||||
) : null}
|
||||
@ -256,8 +233,7 @@ export class TooltipWrapper extends React.Component {
|
||||
ref={(c) => {
|
||||
this._root = c;
|
||||
}}
|
||||
style={{ display: "inline-flex" }}
|
||||
>
|
||||
style={{ display: "inline-flex" }}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
@ -328,20 +304,16 @@ export class TooltipAnchor extends React.Component {
|
||||
content={content}
|
||||
horizontal={this.props.horizontal}
|
||||
vertical={this.props.vertical}
|
||||
type={this.props.type}
|
||||
>
|
||||
type={this.props.type}>
|
||||
<span
|
||||
css={STYLES_TOOLTIP_ANCHOR}
|
||||
style={this.props.anchorStyle}
|
||||
onMouseEnter={this._handleMouseEnter}
|
||||
onMouseLeave={this._handleMouseLeave}
|
||||
>
|
||||
onMouseLeave={this._handleMouseLeave}>
|
||||
{this.props.children ? (
|
||||
this.props.children
|
||||
) : (
|
||||
<SVG.Information
|
||||
height={this.props.height ? this.props.height : "24px"}
|
||||
/>
|
||||
<SVG.Information height={this.props.height ? this.props.height : "24px"} />
|
||||
)}
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
|
Loading…
Reference in New Issue
Block a user