update tooltip component to show on hover and add different directions

This commit is contained in:
Sean Yesmunt 2018-05-22 20:11:20 -04:00
parent 7c4e4c24ad
commit f86bb14591
11 changed files with 181 additions and 140 deletions

View file

@ -223,6 +223,7 @@ class CategoryList extends React.PureComponent<Props, State> {
{category && {category &&
category.match(/^community/i) && ( category.match(/^community/i) && (
<ToolTip <ToolTip
direction="bottom"
label={__("What's this?")} label={__("What's this?")}
body={__( body={__(
'Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!' 'Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!'

View file

@ -2,22 +2,35 @@
import React from 'react'; import React from 'react';
import * as FeatherIcons from 'react-feather'; import * as FeatherIcons from 'react-feather';
import * as icons from 'constants/icons'; import * as icons from 'constants/icons';
import Tooltip from 'component/common/tooltip';
const RED_COLOR = '#e2495e'; const RED_COLOR = '#e2495e';
const PURPLE_COLOR = '#8165b0'; const PURPLE_COLOR = '#8165b0';
type Props = { type Props = {
icon: string, icon: string,
tooltip: ?string, // tooltip direction
}; };
class IconComponent extends React.PureComponent<Props> { class IconComponent extends React.PureComponent<Props> {
// TODO: Move all icons to constants and add titles for all getTooltip = (icon: string) => {
// Add some some sort of hover flyout with the title? switch (icon) {
case icons.FEATURED:
return __('Featured content. Earn rewards for watching.');
case icons.LOCAL:
return __('This file is downloaded.');
default:
return null;
}
};
render() { render() {
const { icon } = this.props; const { icon, tooltip } = this.props;
const Icon = FeatherIcons[icon]; const Icon = FeatherIcons[icon];
if (!Icon) {
return null;
}
let color; let color;
if (icon === icons.TRASH || icon === icons.FEATURED) { if (icon === icons.TRASH || icon === icons.FEATURED) {
color = RED_COLOR; color = RED_COLOR;
@ -30,7 +43,19 @@ class IconComponent extends React.PureComponent<Props> {
size = 20; size = 20;
} }
return Icon ? <Icon size={size} className="icon" color={color} /> : null; let tooltipText;
if (tooltip) {
tooltipText = this.getTooltip(icon);
}
const inner = <Icon size={size} className="icon" color={color} />;
return tooltip ? (
<Tooltip icon body={tooltipText} direction={tooltip}>
{inner}
</Tooltip>
) : (
inner
);
} }
} }

View file

@ -1,55 +1,41 @@
// @flow // @flow
import React from 'react'; import * as React from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import Icon from 'component/common/icon';
import Button from 'component/button';
import * as icons from 'constants/icons';
type Props = { type Props = {
body: string, body: ?string,
label: string, label?: string,
children: ?React.Node,
icon: ?boolean,
direction: string,
}; };
type State = { class ToolTip extends React.PureComponent<Props> {
showTooltip: boolean, static defaultProps = {
}; direction: 'top',
};
class ToolTip extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
showTooltip: false,
};
(this: any).handleClick = this.handleClick.bind(this);
}
handleClick() {
const { showTooltip } = this.state;
if (!showTooltip) {
document.addEventListener('click', this.handleClick);
} else {
document.removeEventListener('click', this.handleClick);
}
this.setState({
showTooltip: !showTooltip,
});
}
render() { render() {
const { label, body } = this.props; const { children, label, body, icon, direction } = this.props;
const { showTooltip } = this.state;
const tooltipContent = children || label;
return ( return (
<span className="tooltip"> <span
<Button button="link" className="help tooltip__link" onClick={this.handleClick}> className={classnames('tooltip', {
{label} 'tooltip--label': label && !icon,
{showTooltip && <Icon icon={icons.CLOSE} />} 'tooltip--icon': icon,
</Button> 'tooltip--top': direction === 'top',
<div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div> 'tooltip--right': direction === 'right',
'tooltip--bottom': direction === 'bottom',
'tooltip--left': direction === 'left',
})}
>
{tooltipContent}
{body && (
// body may be undefined for some icons until we add messages for them
<span className="tooltip__body">{body}</span>
)}
</span> </span>
); );
} }

View file

@ -98,14 +98,16 @@ class FileCard extends React.PureComponent<Props> {
<div className="card__title--small"> <div className="card__title--small">
<TruncatedText lines={3}>{title}</TruncatedText> <TruncatedText lines={3}>{title}</TruncatedText>
</div> </div>
<div className="card__subtitle card__subtitle--file-info"> <div className="card__subtitle">
{pending ? ( {pending ? (
<div>Pending...</div> <div>Pending...</div>
) : ( ) : (
<React.Fragment> <React.Fragment>
<UriIndicator uri={uri} link /> <UriIndicator uri={uri} link />
{isRewardContent && <Icon icon={icons.FEATURED} />} <div>
{fileInfo && <Icon icon={icons.LOCAL} />} {isRewardContent && <Icon icon={icons.FEATURED} />}
{fileInfo && <Icon icon={icons.LOCAL} />}
</div>
</React.Fragment> </React.Fragment>
)} )}
</div> </div>

View file

@ -158,7 +158,7 @@ class FilePage extends React.Component<Props> {
<h1 className="card__title card__title--file">{title}</h1> <h1 className="card__title card__title--file">{title}</h1>
<div className="card__title-identity-icons"> <div className="card__title-identity-icons">
<FilePrice uri={normalizeURI(uri)} /> <FilePrice uri={normalizeURI(uri)} />
{isRewardContent && <Icon icon={icons.FEATURED} />} {isRewardContent && <Icon tooltip="bottom" icon={icons.FEATURED} />}
</div> </div>
</div> </div>
<span className="card__subtitle card__subtitle--file"> <span className="card__subtitle card__subtitle--file">

View file

@ -5,6 +5,8 @@ import FileTile from 'component/fileTile';
import FileListSearch from 'component/fileListSearch'; import FileListSearch from 'component/fileListSearch';
import ToolTip from 'component/common/tooltip'; import ToolTip from 'component/common/tooltip';
import Page from 'component/page'; import Page from 'component/page';
import Icon from 'component/common/icon';
import * as icons from 'constants/icons';
const MODAL_ANIMATION_TIME = 250; const MODAL_ANIMATION_TIME = 250;
@ -50,10 +52,11 @@ class SearchPage extends React.PureComponent<Props> {
<div className="file-list__header"> <div className="file-list__header">
{__('Exact URL')} {__('Exact URL')}
<ToolTip <ToolTip
label="?" icon
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')} body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
className="tooltip--header" >
/> <Icon icon={icons.HELP} />
</ToolTip>
</div> </div>
<FileTile fullWidth uri={normalizeURI(query)} showUri /> <FileTile fullWidth uri={normalizeURI(query)} showUri />
</React.Fragment> </React.Fragment>

View file

@ -122,12 +122,11 @@ input::placeholder {
} }
select { select {
min-width: 100px; min-width: 60px;
height: 30px; height: 30px;
border-radius: 8px; border-radius: 8px;
background-color: var(--input-select-bg-color); background-color: var(--input-select-bg-color);
font: normal 12px/30px 'metropolis-medium'; font: normal 12px/30px 'metropolis-medium';
text-indent: 12px;
color: var(--input-select-color); color: var(--input-select-color);
&:disabled { &:disabled {

View file

@ -161,9 +161,8 @@ $large-breakpoint: 1760px;
--modal-btn-bg-color: var(--btn-bg-alt); --modal-btn-bg-color: var(--btn-bg-alt);
// /* Tooltip */ // /* Tooltip */
--tooltip-width: 300px; --tooltip-bg: #555;
--tooltip-bg: var(--color-bg); --tooltip-color: var(--color-white);
--tooltip-color: var(--text-color);
/* Scrollbar */ /* Scrollbar */
--scrollbar-radius: 10px; --scrollbar-radius: 10px;

View file

@ -17,7 +17,6 @@
.card--small { .card--small {
width: var(--card-small-width); width: var(--card-small-width);
overflow-x: hidden;
white-space: normal; white-space: normal;
.card__media { .card__media {
@ -86,8 +85,7 @@
align-items: center; align-items: center;
.credit-amount, .credit-amount,
.icon { .icon {
margin-top: $spacing-vertical * 1/3; margin: $spacing-vertical * 1/3;
margin-left: $spacing-vertical * 2/3;
} }
} }
@ -126,7 +124,11 @@
color: var(--card-text-color); color: var(--card-text-color);
.icon { .icon {
margin-left: $spacing-vertical * 1/3; margin-top: $spacing-vertical * 1/6;
&:not(:first-of-type) {
margin: 0 $spacing-vertical * 1/3;
}
} }
} }
@ -134,11 +136,6 @@
padding-top: $spacing-vertical * 1/3; padding-top: $spacing-vertical * 1/3;
} }
.card__subtitle--file-info {
display: flex;
align-items: center;
}
.card__subtitle--block { .card__subtitle--block {
display: block; display: block;
} }
@ -243,12 +240,11 @@
} }
/* /*
.card-row is used on the discover/subscriptions page .card-row is used on the discover page
It is a list of cards that extend past the right edge of the screen It is a list of cards that extend past the right edge of the screen
There are left/right arrows to scroll the cards and view hidden content There are left/right arrows to scroll the cards and view hidden content
*/ */
.card-row { .card-row {
overflow: hidden;
white-space: nowrap; white-space: nowrap;
width: 100%; width: 100%;
min-width: var(--card-small-width); min-width: var(--card-small-width);
@ -289,6 +285,18 @@
padding-top: $spacing-vertical * 2/3; padding-top: $spacing-vertical * 2/3;
overflow: hidden; overflow: hidden;
.card {
display: inline-block;
vertical-align: top;
overflow-y: visible;
// 31 px to handle to padding between cards
width: calc((100% / 4) - 31px);
}
.card:not(:first-of-type) {
margin-left: 20px;
}
.card:first-of-type { .card:first-of-type {
margin-left: $spacing-width; margin-left: $spacing-width;
} }
@ -327,27 +335,6 @@
} }
} }
.card-row__scrollhouse {
padding-top: $spacing-vertical * 2/3;
overflow: hidden;
.card {
display: inline-block;
vertical-align: top;
overflow: visible;
// 31 px to handle to padding between cards
width: calc((100% / 4) - 31px);
}
.card:not(:first-of-type) {
margin-left: 20px;
}
.card:last-of-type {
margin-right: 20px;
}
}
.card__success-msg { .card__success-msg {
border-left: 2px solid var(--success-msg-border); border-left: 2px solid var(--success-msg-border);
color: var(--success-msg-color); color: var(--success-msg-color);

View file

@ -1,30 +1,97 @@
@import '../mixin/link.scss';
.tooltip { .tooltip {
position: relative; position: relative;
padding: 0 $spacing-vertical / 3; display: inline-block;
font-size: 12px;
} }
.tooltip__body { // When there is a label for the tooltip and not just using a button or icon
.tooltip.tooltip--label {
font-size: 12px;
padding-left: $spacing-vertical * 1/3;
.tooltip__body {
margin-top: 5px;
}
}
.tooltip.tooltip--icon {
margin-top: 5px;
}
/* Tooltip text */
.tooltip .tooltip__body {
background-color: var(--tooltip-bg);
font-family: 'metropolis-medium';
font-size: 12px;
color: var(--tooltip-color);
border-radius: 8px;
position: absolute; position: absolute;
z-index: 1; z-index: 1;
left: 50%; width: 200px;
margin-left: calc(var(--tooltip-width) * -1 / 2); text-align: center;
white-space: normal; white-space: pre-wrap;
box-sizing: border-box; padding: $spacing-vertical * 1/3;
padding: $spacing-vertical / 2; visibility: hidden;
width: var(--tooltip-width);
color: var(--tooltip-color);
background-color: var(--tooltip-bg);
font-size: calc(var(--font-size) * 7 / 8);
line-height: var(--font-line-height);
box-shadow: var(--box-shadow-layer);
border-radius: var(--card-radius);
} }
.tooltip__link { .tooltip .tooltip__body::after {
font-size: calc(var(--font-size) * 3 / 4); content: ' ';
margin-left: var(--button-padding); width: 0;
vertical-align: middle; height: 0;
position: absolute;
border-width: 5px;
border-style: solid;
}
.tooltip.tooltip--top .tooltip__body {
bottom: 100%;
left: 50%;
margin-left: -100px;
&::after {
top: 100%;
left: 50%;
margin-left: -5px;
border-color: var(--tooltip-bg) transparent transparent transparent;
}
}
.tooltip.tooltip--right .tooltip__body {
margin-top: -5px;
margin-left: 10px;
&::after {
top: 17px;
right: 100%; /* To the left of the tooltip */
margin-top: -5px;
border-color: transparent var(--tooltip-bg) transparent transparent;
}
}
.tooltip.tooltip--bottom .tooltip__body {
top: 90%;
left: 50%;
margin-left: -100px;
&::after {
bottom: 100%;
left: 50%;
margin-left: -5px;
border-color: transparent transparent var(--tooltip-bg) transparent;
}
}
.tooltip.tooltip--left .tooltip__body {
top: -5px;
right: 105%;
&::after {
top: 17px;
left: 100%;
margin-top: -5px;
border-color: transparent transparent transparent var(--tooltip-bg);
}
}
.tooltip:hover .tooltip__body {
visibility: visible;
} }

View file

@ -1,28 +0,0 @@
@mixin text-link($color: var(--color-primary), $hover-opacity: 0.7) {
.icon {
&:first-child {
padding-right: 5px;
}
&:last-child:not(:only-child) {
padding-left: 5px;
}
}
&:not(.no-underline) {
text-decoration: underline;
.icon {
text-decoration: none;
}
}
&:hover {
opacity: $hover-opacity;
transition: opacity var(--transition-duration) var(--transition-type);
text-decoration: underline;
.icon {
text-decoration: none;
}
}
color: $color;
cursor: pointer;
}