add @reach/tooltip

This commit is contained in:
Sean Yesmunt 2019-06-20 02:13:26 -04:00
parent 033037e61c
commit f39ca4dd57
27 changed files with 325 additions and 4805 deletions

View file

@ -39,6 +39,7 @@
"space-before-function-paren": ["error", "never"], "space-before-function-paren": ["error", "never"],
"standard/object-curly-even-spacing": 0, "standard/object-curly-even-spacing": 0,
"standard/no-callback-literal": 0, "standard/no-callback-literal": 0,
"react/display-name": 0,
"semi": [ "semi": [
"error", "error",
"always", "always",

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
declare module 'react-feather' {
declare module.exports: any;
}

View file

@ -147,7 +147,6 @@
"rc-progress": "^2.0.6", "rc-progress": "^2.0.6",
"react": "^16.8.2", "react": "^16.8.2",
"react-dom": "^16.8.2", "react-dom": "^16.8.2",
"react-feather": "^1.0.8",
"react-ga": "^2.5.7", "react-ga": "^2.5.7",
"react-hot-loader": "^4.11.1", "react-hot-loader": "^4.11.1",
"react-modal": "^3.1.7", "react-modal": "^3.1.7",

View file

@ -1,5 +1,5 @@
// @flow // @flow
import * as React from 'react'; import React, { forwardRef } from 'react';
import Icon from 'component/common/icon'; import Icon from 'component/common/icon';
import classnames from 'classnames'; import classnames from 'classnames';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
@ -31,18 +31,10 @@ type Props = {
onMouseLeave: ?(any) => any, onMouseLeave: ?(any) => any,
}; };
class Button extends React.PureComponent<Props> { const Button = forwardRef((props: Props, ref) => {
static defaultProps = {
type: 'button',
};
render() {
const { const {
id, type = 'button',
onClick, onClick,
onMouseEnter,
onMouseLeave,
innerRef,
href, href,
title, title,
label, label,
@ -56,13 +48,12 @@ class Button extends React.PureComponent<Props> {
className, className,
description, description,
button, button,
type,
iconColor, iconColor,
iconSize, iconSize,
constrict, constrict,
activeClass, activeClass,
...otherProps ...otherProps
} = this.props; } = props;
const combinedClassName = classnames( const combinedClassName = classnames(
'button', 'button',
@ -111,7 +102,7 @@ class Button extends React.PureComponent<Props> {
return path ? ( return path ? (
<NavLink <NavLink
id={id} ref={ref}
exact exact
to={path} to={path}
title={title} title={title}
@ -122,17 +113,14 @@ class Button extends React.PureComponent<Props> {
onClick(); onClick();
} }
}} }}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className={combinedClassName} className={combinedClassName}
activeClassName={activeClass} activeClassName={activeClass}
innerRef={innerRef}
> >
{content} {content}
</NavLink> </NavLink>
) : ( ) : (
<button <button
id={id} ref={ref}
title={title} title={title}
aria-label={description || label || title} aria-label={description || label || title}
className={combinedClassName} className={combinedClassName}
@ -144,7 +132,6 @@ class Button extends React.PureComponent<Props> {
{content} {content}
</button> </button>
); );
} });
}
export default Button; export default Button;

View file

@ -1,6 +1,7 @@
// @flow // @flow
// A housing for all of our icons. Mostly taken fromhttps://github.com/feathericons/react-feather
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React from 'react'; import React, { forwardRef } from 'react';
type IconProps = { type IconProps = {
size: number, size: number,
@ -8,10 +9,12 @@ type IconProps = {
}; };
// Returns a react component // Returns a react component
const buildIcon = (iconStrokes: React$Node, options?: {} = {}) => (props: IconProps) => { const buildIcon = (iconStrokes: React$Node, options?: {} = {}) =>
forwardRef((props: IconProps, ref) => {
const { size = 24, color = 'currentColor', ...otherProps } = props; const { size = 24, color = 'currentColor', ...otherProps } = props;
return ( return (
<svg <svg
ref={ref}
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width={size} width={size}
@ -27,9 +30,16 @@ const buildIcon = (iconStrokes: React$Node, options?: {} = {}) => (props: IconPr
{iconStrokes} {iconStrokes}
</svg> </svg>
); );
}; });
export const customIcons = { export const icons = {
// The LBRY icon is different from the base icon set so don't use buildIcon()
[ICONS.LBRY]: (
<svg stroke="currentColor" fill="currentColor" x="0px" y="0px" viewBox="0 0 322 254" className="icon lbry-icon">
<path d="M296,85.9V100l-138.8,85.3L52.6,134l0.2-7.9l104,51.2L289,96.1v-5.8L164.2,30.1L25,116.2v38.5l131.8,65.2 l137.6-84.4l3.9,6l-141.1,86.4L18.1,159.1v-46.8l145.8-90.2C163.9,22.1,296,85.9,296,85.9z" />
<path d="M294.3,150.9l2-12.6l-12.2-2.1l0.8-4.9l17.1,2.9l-2.8,17.5L294.3,150.9L294.3,150.9z" />
</svg>
),
[ICONS.ARROW_LEFT]: buildIcon( [ICONS.ARROW_LEFT]: buildIcon(
<g fill="none" fillRule="evenodd" strokeLinecap="round"> <g fill="none" fillRule="evenodd" strokeLinecap="round">
<path d="M4, 12 L21, 12" /> <path d="M4, 12 L21, 12" />
@ -46,48 +56,12 @@ export const customIcons = {
<polyline strokeLinejoin="round" points="13 4 21 12 13 20" /> <polyline strokeLinejoin="round" points="13 4 21 12 13 20" />
</g> </g>
), ),
[ICONS.VIEW]: buildIcon(
<g fill="none" fillRule="evenodd">
<path
d="M2, 12 C2, 12 5, 5 12, 5 C19, 5 22, 12 22, 12 C22, 12 19, 19 12, 19 C5, 19 2, 12 2, 12 Z"
strokeLinejoin="round"
/>
<circle cx="12" cy="12" r="3" />
<path d="M12, 5 L12, 3" strokeLinecap="round" />
<path d="M18, 6.5 L19, 5" strokeLinecap="round" />
<path d="M21, 10 L22.5, 9" strokeLinecap="round" />
<path
d="M1.5, 10 L3, 9"
strokeLinecap="round"
transform="translate(2.250000, 9.500000) scale(1, -1) translate(-2.250000, -9.500000)"
/>
<path
d="M5, 6.5 L6, 5"
strokeLinecap="round"
transform="translate(5.500000, 5.750000) scale(-1, 1) translate(-5.500000, -5.750000)"
/>
</g>
),
[ICONS.HOME]: buildIcon( [ICONS.HOME]: buildIcon(
<g strokeWidth="2" fill="none" fillRule="evenodd" strokeLinecap="round" strokeLinejoin="round"> <g strokeWidth="2" fill="none" fillRule="evenodd" strokeLinecap="round" strokeLinejoin="round">
<path d="M1, 11 L12, 2 C12, 2 22.9999989, 11.0000005 23, 11" /> <path d="M1, 11 L12, 2 C12, 2 22.9999989, 11.0000005 23, 11" />
<path d="M3, 10 C3, 10 3, 10.4453982 3, 10.9968336 L3, 20.0170446 C3, 20.5675806 3.43788135, 21.0138782 4.00292933, 21.0138781 L8.99707067, 21.0138779 C9.55097324, 21.0138779 10, 20.5751284 10, 20.0089602 L10, 15.0049177 C10, 14.449917 10.4433532, 14 11.0093689, 14 L12.9906311, 14 C13.5480902, 14 14, 14.4387495 14, 15.0049177 L14, 20.0089602 C14, 20.5639609 14.4378817, 21.0138779 15.0029302, 21.0138779 L19.9970758, 21.0138781 C20.5509789, 21.0138782 21.000006, 20.56848 21.000006, 20.0170446 L21.0000057, 10" /> <path d="M3, 10 C3, 10 3, 10.4453982 3, 10.9968336 L3, 20.0170446 C3, 20.5675806 3.43788135, 21.0138782 4.00292933, 21.0138781 L8.99707067, 21.0138779 C9.55097324, 21.0138779 10, 20.5751284 10, 20.0089602 L10, 15.0049177 C10, 14.449917 10.4433532, 14 11.0093689, 14 L12.9906311, 14 C13.5480902, 14 14, 14.4387495 14, 15.0049177 L14, 20.0089602 C14, 20.5639609 14.4378817, 21.0138779 15.0029302, 21.0138779 L19.9970758, 21.0138781 C20.5509789, 21.0138782 21.000006, 20.56848 21.000006, 20.0170446 L21.0000057, 10" />
</g> </g>
), ),
[ICONS.MENU]: buildIcon(
<path
d="M3.5, 7 C3.5, 7.27910535 3.72002141, 7.5 3.99339768, 7.5 L20.0066023, 7.5 C20.2782464, 7.5 20.5, 7.27680164 20.5, 7 C20.5, 6.72089465 20.2799786, 6.5 20.0066023, 6.5 L3.99339768, 6.5 C3.72175357, 6.5 3.5, 6.72319836 3.5, 7 Z M3.5, 12 C3.5, 12.2791054 3.72002141, 12.5 3.99339768, 12.5 L20.0066023, 12.5 C20.2782464, 12.5 20.5, 12.2768016 20.5, 12 C20.5, 11.7208946 20.2799786, 11.5 20.0066023, 11.5 L3.99339768, 11.5 C3.72175357, 11.5 3.5, 11.7231984 3.5, 12 Z M3.5, 17 C3.5, 17.2791054 3.72002141, 17.5 3.99339768, 17.5 L20.0066023, 17.5 C20.2782464, 17.5 20.5, 17.2768016 20.5, 17 C20.5, 16.7208946 20.2799786, 16.5 20.0066023, 16.5 L3.99339768, 16.5 C3.72175357, 16.5 3.5, 16.7231984 3.5, 17 Z"
fill="none"
fillRule="evenodd"
strokeWidth="1"
/>
),
[ICONS.PLAY]: buildIcon(
<g fill="white" fillRule="evenodd" strokeLinejoin="round">
<polygon points="5 21 5 3 21 12" />
</g>
),
[ICONS.UPLOAD]: buildIcon( [ICONS.UPLOAD]: buildIcon(
<g fill="none" fillRule="evenodd" strokeLinecap="round"> <g fill="none" fillRule="evenodd" strokeLinecap="round">
<path <path
@ -111,15 +85,129 @@ export const customIcons = {
/> />
</g> </g>
), ),
// Extended from the feather-icons Heart [ICONS.SUBSCRIPTION]: buildIcon(
[ICONS.UNSUBSCRIBE]: buildIcon( <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
<path d="M 12,5.67 10.94,4.61 C 5.7533356,-0.57666427 -2.0266644,7.2033357 3.16,12.39 l 1.06,1.06 7.78,7.78 7.78,-7.78 1.06,-1.06 c 2.149101,-2.148092 2.149101,-5.6319078 0,-7.78 -2.148092,-2.1491008 -5.631908,-2.1491008 -7.78,0 L 9.4481298,8.2303201 15.320603,9.2419066 11.772427,13.723825" />
), ),
// The LBRY icon is different from the base icon set so don't use buildIcon() [ICONS.SETTINGS]: buildIcon(
[ICONS.LBRY]: props => ( <g>
<svg stroke="currentColor" fill="currentColor" x="0px" y="0px" viewBox="0 0 322 254" className="icon lbry-icon"> <circle cx="12" cy="12" r="3" />
<path d="M296,85.9V100l-138.8,85.3L52.6,134l0.2-7.9l104,51.2L289,96.1v-5.8L164.2,30.1L25,116.2v38.5l131.8,65.2 l137.6-84.4l3.9,6l-141.1,86.4L18.1,159.1v-46.8l145.8-90.2C163.9,22.1,296,85.9,296,85.9z" /> <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
<path d="M294.3,150.9l2-12.6l-12.2-2.1l0.8-4.9l17.1,2.9l-2.8,17.5L294.3,150.9L294.3,150.9z" /> </g>
</svg> ),
[ICONS.ACCOUNT]: buildIcon(
<g>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</g>
),
[ICONS.OVERVIEW]: buildIcon(<polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />),
[ICONS.WALLET]: buildIcon(
<g>
<line x1="8" y1="6" x2="21" y2="6" />
<line x1="8" y1="12" x2="21" y2="12" />
<line x1="8" y1="18" x2="21" y2="18" />
<line x1="3" y1="6" x2="3" y2="6" />
<line x1="3" y1="12" x2="3" y2="12" />
<line x1="3" y1="18" x2="3" y2="18" />
</g>
),
[ICONS.LIBRARY]: buildIcon(<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />),
[ICONS.EDIT]: buildIcon(
<g>
<path d="M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34" />
<polygon points="18 2 22 6 12 16 8 16 8 12 18 2" />
</g>
),
[ICONS.DOWNLOAD]: buildIcon(
<g>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" />
</g>
),
[ICONS.HELP]: buildIcon(
<g>
<circle cx="12" cy="12" r="10" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<line x1="12" y1="17" x2="12" y2="17" />
</g>
),
[ICONS.LIGHT]: buildIcon(
<g>
<circle cx="12" cy="12" r="5" />
<line x1="12" y1="1" x2="12" y2="3" />
<line x1="12" y1="21" x2="12" y2="23" />
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
<line x1="1" y1="12" x2="3" y2="12" />
<line x1="21" y1="12" x2="23" y2="12" />
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
</g>
),
[ICONS.DARK]: buildIcon(<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />),
[ICONS.SEARCH]: buildIcon(
<g>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</g>
),
[ICONS.TIP]: buildIcon(
<g>
<polyline points="20 12 20 22 4 22 4 12" />
<rect x="2" y="7" width="20" height="5" />
<line x1="12" y1="22" x2="12" y2="7" />
<path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z" />
<path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z" />
</g>
),
[ICONS.SHARE]: buildIcon(
<g>
<circle cx="18" cy="5" r="3" />
<circle cx="6" cy="12" r="3" />
<circle cx="18" cy="19" r="3" />
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
</g>
),
[ICONS.REPORT]: buildIcon(
<g>
<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" />
<line x1="4" y1="22" x2="4" y2="15" />
</g>
),
[ICONS.EXTERNAL]: buildIcon(
<g>
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
<polyline points="15 3 21 3 21 9" />
<line x1="10" y1="14" x2="21" y2="3" />
</g>
),
[ICONS.DELETE]: buildIcon(
<g>
<polyline points="3 6 5 6 21 6" />
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
</g>
),
[ICONS.COPY]: buildIcon(
<g>
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" />
<rect x="8" y="2" width="8" height="4" rx="1" ry="1" />
</g>
),
[ICONS.REMOVE]: buildIcon(
<g>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</g>
),
[ICONS.ADD]: buildIcon(
<g>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</g>
),
[ICONS.CHAT]: buildIcon(
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
), ),
}; };

View file

@ -1,10 +1,9 @@
// @flow // @flow
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import * as FEATHER_ICONS from 'react-feather';
import React from 'react'; import React from 'react';
import Tooltip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
import classnames from 'classnames'; import classnames from 'classnames';
import { customIcons } from './icon-custom'; import { icons } from './icon-custom';
// It would be nice to standardize this somehow // It would be nice to standardize this somehow
// These are copied from `scss/vars`, can they both come from the same source? // These are copied from `scss/vars`, can they both come from the same source?
@ -27,6 +26,10 @@ class IconComponent extends React.PureComponent<Props> {
return __('Featured content. Earn rewards for watching.'); return __('Featured content. Earn rewards for watching.');
case ICONS.DOWNLOAD: case ICONS.DOWNLOAD:
return __('This file is downloaded.'); return __('This file is downloaded.');
case ICONS.SUBSCRIPTION:
return __('You are subscribed to this channel.');
case ICONS.SETTINGS:
return __('Your settings.');
default: default:
return null; return null;
} }
@ -47,9 +50,10 @@ class IconComponent extends React.PureComponent<Props> {
render() { render() {
const { icon, tooltip, iconColor, size, className } = this.props; const { icon, tooltip, iconColor, size, className } = this.props;
const Icon = customIcons[this.props.icon] || FEATHER_ICONS[this.props.icon]; const Icon = icons[this.props.icon];
if (!Icon) { if (!Icon) {
console.error('no icon found for ', icon);
return null; return null;
} }
@ -67,13 +71,7 @@ class IconComponent extends React.PureComponent<Props> {
const inner = <Icon size={iconSize} className={classnames(`icon icon--${icon}`, className)} color={color} />; const inner = <Icon size={iconSize} className={classnames(`icon icon--${icon}`, className)} color={color} />;
return tooltipText ? ( return tooltipText ? <Tooltip label={tooltipText}>{inner}</Tooltip> : inner;
<Tooltip icon body={tooltipText} direction={tooltip}>
{inner}
</Tooltip>
) : (
inner
);
} }
} }

View file

@ -1,71 +1,17 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import classnames from 'classnames'; import ReachTooltip from '@reach/tooltip';
import '@reach/tooltip/styles.css';
type Props = { type Props = {
body: string, label: string,
label?: string,
children?: React.Node, children?: React.Node,
icon?: boolean,
direction: string,
onComponent?: boolean, // extra padding to account for button/form field size
alwaysVisible?: boolean, // should tooltip stay open, guide callbacks will close it manually
}; };
type State = { function Tooltip(props: Props) {
direction: string, const { children, label } = props;
};
class ToolTip extends React.PureComponent<Props, State> { return <ReachTooltip label={label}>{children}</ReachTooltip>;
static defaultProps = {
direction: 'bottom',
alwaysVisible: false,
};
constructor(props: Props) {
super(props);
this.state = {
direction: this.props.direction,
};
}
tooltip: ?HTMLSpanElement;
render() {
const { direction } = this.state;
const { children, label, body, icon, onComponent, alwaysVisible } = this.props;
const tooltipContent = children || label;
const bodyLength = body.length;
const isShortDescription = bodyLength < 30;
return (
<span
className={classnames('tooltip', {
'tooltip--label': label && !icon,
'tooltip--icon': icon,
'tooltip--top': direction === 'top',
'tooltip--right': direction === 'right',
'tooltip--bottom': direction === 'bottom',
'tooltip--left': direction === 'left',
'tooltip--on-component': onComponent,
'tooltip--always-visible': alwaysVisible,
})}
>
{tooltipContent}
<span
ref={ref => {
this.tooltip = ref;
}}
className={classnames('tooltip__body', {
'tooltip__body--short': isShortDescription,
})}
>
{body}
</span>
</span>
);
}
} }
export default ToolTip; export default Tooltip;

View file

@ -45,7 +45,7 @@ export default class CopyableText extends React.PureComponent<Props> {
inputButton={ inputButton={
<Button <Button
button="inverse" button="inverse"
icon={ICONS.CLIPBOARD} icon={ICONS.COPY}
onClick={() => { onClick={() => {
clipboard.writeText(copyable); clipboard.writeText(copyable);
doToast({ doToast({

View file

@ -38,14 +38,19 @@ class FileActions extends React.PureComponent<Props> {
return ( return (
<React.Fragment> <React.Fragment>
{showFullscreen && ( {showFullscreen && (
<Tooltip onComponent body={__('Full screen (f)')}> <Tooltip label={__('Full screen (f)')}>
<Button button="alt" description={__('Fullscreen')} icon={ICONS.FULLSCREEN} onClick={this.maximizeViewer} /> <Button
button="link"
description={__('Fullscreen')}
icon={ICONS.FULLSCREEN}
onClick={this.maximizeViewer}
/>
</Tooltip> </Tooltip>
)} )}
{showDelete && ( {showDelete && (
<Tooltip onComponent body={__('Delete this file')}> <Tooltip label={__('Remove from your library')}>
<Button <Button
button="alt" button="link"
icon={ICONS.DELETE} icon={ICONS.DELETE}
description={__('Delete')} description={__('Delete')}
onClick={() => openModal(MODALS.CONFIRM_FILE_REMOVE, { uri })} onClick={() => openModal(MODALS.CONFIRM_FILE_REMOVE, { uri })}
@ -53,8 +58,8 @@ class FileActions extends React.PureComponent<Props> {
</Tooltip> </Tooltip>
)} )}
{!claimIsMine && ( {!claimIsMine && (
<Tooltip onComponent body={__('Report content')}> <Tooltip label={__('Report content')}>
<Button icon={ICONS.REPORT} href={`https://lbry.com/dmca?claim_id=${claimId}`} /> <Button button="link" icon={ICONS.REPORT} href={`https://lbry.com/dmca?claim_id=${claimId}`} />
</Tooltip> </Tooltip>
)} )}
</React.Fragment> </React.Fragment>

View file

@ -57,11 +57,10 @@ class FileDownloadLink extends React.PureComponent<Props> {
} }
return ( return (
<ToolTip onComponent body={__('Download')}> <ToolTip label={__('Download')}>
<Button <Button
button="alt" button="link"
icon={ICONS.DOWNLOAD} icon={ICONS.DOWNLOAD}
iconColor="green"
onClick={() => { onClick={() => {
purchaseUri(uri); purchaseUri(uri);
@ -76,10 +75,9 @@ class FileDownloadLink extends React.PureComponent<Props> {
); );
} else if (fileInfo && fileInfo.download_path) { } else if (fileInfo && fileInfo.download_path) {
return ( return (
<ToolTip onComponent body={__('Open file')}> <ToolTip label={__('Open file')}>
<Button <Button
button="alt" button="link"
iconColor="green"
icon={ICONS.EXTERNAL} icon={ICONS.EXTERNAL}
onClick={() => { onClick={() => {
pause(); pause();

View file

@ -21,9 +21,9 @@ export default function FileProperties(props: Props) {
return ( return (
<div className="file-properties"> <div className="file-properties">
{isSubscribed && <Icon icon={icons.SUBSCRIPTION} />} {isSubscribed && <Icon tooltip icon={icons.SUBSCRIPTION} />}
{!claimIsMine && downloaded && <Icon icon={icons.DOWNLOAD} />} {!claimIsMine && downloaded && <Icon tooltip icon={icons.DOWNLOAD} />}
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />} {isRewardContent && <Icon tooltip iconColor="red" icon={icons.FEATURED} />}
<FilePrice hideFree uri={uri} /> <FilePrice hideFree uri={uri} />
</div> </div>
); );

View file

@ -4,12 +4,10 @@ import React from 'react';
import LoadingScreen from 'component/common/loading-screen'; import LoadingScreen from 'component/common/loading-screen';
import VideoViewer from 'component/viewers/videoViewer'; import VideoViewer from 'component/viewers/videoViewer';
const AudioViewer = React.lazy<*>(() => // const AudioViewer = React.lazy<*>(() =>
import( // import(/* webpackChunkName: "audioViewer" */
/* webpackChunkName: "audioViewer" */ // 'component/viewers/audioViewer')
'component/viewers/audioViewer' // );
)
);
const DocumentViewer = React.lazy<*>(() => const DocumentViewer = React.lazy<*>(() =>
import( import(
@ -166,7 +164,7 @@ class FileRender extends React.PureComponent<Props> {
video: ( video: (
<VideoViewer claim={claim} source={{ downloadPath, fileName }} contentType={contentType} poster={poster} /> <VideoViewer claim={claim} source={{ downloadPath, fileName }} contentType={contentType} poster={poster} />
), ),
audio: <AudioViewer claim={claim} source={{ downloadPath, fileName }} contentType={contentType} />, // audio: <AudioViewer claim={claim} source={{ downloadPath, fileName }} contentType={contentType} />,
// Add routes to viewer... // Add routes to viewer...
}; };
@ -208,7 +206,7 @@ class FileRender extends React.PureComponent<Props> {
render() { render() {
return ( return (
<div className="file-render"> <div className="file-render">
<React.Suspense fallback={<div />}>{this.renderViewer()}</React.Suspense> <Suspense fallback={<div />}>{this.renderViewer()}</Suspense>
</div> </div>
); );
} }

View file

@ -53,7 +53,7 @@ const Header = (props: Props) => {
description={__('Navigate back')} description={__('Navigate back')}
onClick={() => window.history.back()} onClick={() => window.history.back()}
icon={ICONS.ARROW_LEFT} icon={ICONS.ARROW_LEFT}
iconSize={15} iconSize={18}
/> />
<Button <Button
@ -61,7 +61,7 @@ const Header = (props: Props) => {
description={__('Navigate forward')} description={__('Navigate forward')}
onClick={() => window.history.forward()} onClick={() => window.history.forward()}
icon={ICONS.ARROW_RIGHT} icon={ICONS.ARROW_RIGHT}
iconSize={15} iconSize={18}
/> />
</div> </div>
{/* @endif */} {/* @endif */}
@ -98,11 +98,11 @@ const Header = (props: Props) => {
</Menu> </Menu>
<Menu> <Menu>
<MenuButton className="header__navigation-item menu__title"> <MenuButton className="header__navigation-item menu__title">
<Icon icon={ICONS.SETTINGS} /> <Icon size={18} icon={ICONS.SETTINGS} />
</MenuButton> </MenuButton>
<MenuList> <MenuList>
<MenuItem className="menu__link" onSelect={() => history.push(`/$/settings`)}> <MenuItem className="menu__link" onSelect={() => history.push(`/$/settings`)}>
<Icon aria-hidden icon={ICONS.SETTINGS} /> <Icon aria-hidden tootlip icon={ICONS.SETTINGS} />
{__('Settings')} {__('Settings')}
</MenuItem> </MenuItem>
<MenuItem className="menu__link" onSelect={() => history.push(`/$/help`)}> <MenuItem className="menu__link" onSelect={() => history.push(`/$/help`)}>

View file

@ -344,7 +344,7 @@ class PublishForm extends React.PureComponent<Props> {
<h2 className="card__title card__title--flex-between"> <h2 className="card__title card__title--flex-between">
{__('Content')} {__('Content')}
{(filePath || !!editingURI) && ( {(filePath || !!editingURI) && (
<Button button="inverse" icon={ICONS.CLOSE} label={__('Clear')} onClick={clearPublish} /> <Button button="inverse" icon={ICONS.REMOVE} label={__('Clear')} onClick={clearPublish} />
)} )}
</h2> </h2>
<p className="card__subtitle"> <p className="card__subtitle">

View file

@ -40,7 +40,7 @@ function SideBar(props: Props) {
...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISHED), ...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISHED),
}, },
{ {
...buildLink(PAGES.LIBRARY, __('Library'), ICONS.DOWNLOAD), ...buildLink(PAGES.LIBRARY, __('Library'), ICONS.LIBRARY),
}, },
].map(renderLink)} ].map(renderLink)}

View file

@ -3,7 +3,7 @@ import * as ICONS from 'constants/icons';
import React from 'react'; import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import CopyableText from 'component/copyableText'; import CopyableText from 'component/copyableText';
import ToolTip from 'component/common/tooltip'; import Tooltip from 'component/common/tooltip';
type Props = { type Props = {
claim: StreamClaim, claim: StreamClaim,
@ -73,7 +73,7 @@ class SocialShare extends React.PureComponent<Props> {
<label className="help">{__('Web link')}</label> <label className="help">{__('Web link')}</label>
<CopyableText copyable={speechURL} /> <CopyableText copyable={speechURL} />
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<ToolTip onComponent body={__('Facebook')}> <Tooltip label={__('Facebook')}>
<Button <Button
iconColor="blue" iconColor="blue"
icon={ICONS.FACEBOOK} icon={ICONS.FACEBOOK}
@ -81,8 +81,8 @@ class SocialShare extends React.PureComponent<Props> {
label={__('')} label={__('')}
href={`https://facebook.com/sharer/sharer.php?u=${encodedSpeechURL}`} href={`https://facebook.com/sharer/sharer.php?u=${encodedSpeechURL}`}
/> />
</ToolTip> </Tooltip>
<ToolTip onComponent body={__('Twitter')}> <Tooltip label={__('Twitter')}>
<Button <Button
iconColor="blue" iconColor="blue"
icon={ICONS.TWITTER} icon={ICONS.TWITTER}
@ -90,10 +90,10 @@ class SocialShare extends React.PureComponent<Props> {
label={__('')} label={__('')}
href={`https://twitter.com/home?status=${encodedSpeechURL}`} href={`https://twitter.com/home?status=${encodedSpeechURL}`}
/> />
</ToolTip> </Tooltip>
<ToolTip onComponent body={__('View on Spee.ch')}> <Tooltip label={__('View on Spee.ch')}>
<Button icon={ICONS.WEB} iconColor="blue" button="alt" label={__('')} href={`${speechURL}`} /> <Button icon={ICONS.WEB} iconColor="blue" button="alt" label={__('')} href={`${speechURL}`} />
</ToolTip> </Tooltip>
</div> </div>
</div> </div>
)} )}
@ -101,7 +101,7 @@ class SocialShare extends React.PureComponent<Props> {
<label className="help">{__('LBRY App link')}</label> <label className="help">{__('LBRY App link')}</label>
<CopyableText copyable={lbryURL} noSnackbar /> <CopyableText copyable={lbryURL} noSnackbar />
<div className="card__actions card__actions--center"> <div className="card__actions card__actions--center">
<ToolTip onComponent body={__('Facebook')}> <Tooltip label={__('Facebook')}>
<Button <Button
iconColor="blue" iconColor="blue"
icon={ICONS.FACEBOOK} icon={ICONS.FACEBOOK}
@ -109,8 +109,8 @@ class SocialShare extends React.PureComponent<Props> {
label={__('')} label={__('')}
href={`https://facebook.com/sharer/sharer.php?u=${encodedLbryURL}`} href={`https://facebook.com/sharer/sharer.php?u=${encodedLbryURL}`}
/> />
</ToolTip> </Tooltip>
<ToolTip onComponent body={__('Twitter')}> <Tooltip label={__('Twitter')}>
<Button <Button
iconColor="blue" iconColor="blue"
icon={ICONS.TWITTER} icon={ICONS.TWITTER}
@ -118,7 +118,7 @@ class SocialShare extends React.PureComponent<Props> {
label={__('')} label={__('')}
href={`https://twitter.com/home?status=${encodedLbryURL}`} href={`https://twitter.com/home?status=${encodedLbryURL}`}
/> />
</ToolTip> </Tooltip>
</div> </div>
</div> </div>
<div className="card__actions"> <div className="card__actions">

View file

@ -26,7 +26,7 @@ export default function Tag(props: Props) {
})} })}
label={name} label={name}
iconSize={12} iconSize={12}
iconRight={type !== 'link' && (type === 'remove' ? ICONS.CLOSE : ICONS.ADD)} iconRight={type !== 'link' && (type === 'remove' ? ICONS.REMOVE : ICONS.ADD)}
/> />
); );
} }

View file

@ -35,7 +35,7 @@ export default function TagSelect(props: Props) {
<div className="card--section"> <div className="card--section">
<h2 className="card__title card__title--flex-between"> <h2 className="card__title card__title--flex-between">
{title} {title}
{showClose && !hasClosed && <Button button="close" icon={ICONS.CLOSE} onClick={handleClose} />} {showClose && !hasClosed && <Button button="close" icon={ICONS.REMOVE} onClick={handleClose} />}
</h2> </h2>
<p className="help">{__("The tags you follow will change what's trending for you.")}</p> <p className="help">{__("The tags you follow will change what's trending for you.")}</p>

View file

@ -1,296 +0,0 @@
import React from 'react';
import * as ICONS from 'constants/icons';
import Button from 'component/button';
import Tooltip from 'component/common/tooltip';
import { stopContextMenu } from 'util/context-menu';
import butterchurn from 'butterchurn';
import detectButterchurnSupport from 'butterchurn/lib/isSupported.min';
import butterchurnPresets from 'butterchurn-presets';
import jsmediatags from 'jsmediatags/dist/jsmediatags';
import WaveSurfer from 'wavesurfer.js';
import styles from './audioViewer.module.scss';
const isButterchurnSupported = detectButterchurnSupport();
const EQ_BANDS_SIMPLE = [55, 150, 250, 400, 500, 1000, 2000, 4000, 8000, 16000];
/*
const EQ_LOWSHELF = EQ_BANDS_SIMPLE.shift();
const EQ_HIGHSHELF = EQ_BANDS_SIMPLE.pop();
const eqFilters = EQ.map(function(band) {
var filter = wavesurfer.backend.ac.createBiquadFilter();
filter.type = 'peaking';
filter.gain.value = 0;
filter.Q.value = 1;
filter.frequency.value = band.f;
return filter;
});
*/
// type Props = {
// source: {
// downloadPath: string,
// fileName: string,
// },
// contentType: string,
// poster?: string,
// claim: StreamClaim,
// };
const presets = [
require('butterchurn-presets/presets/converted/Flexi - when monopolies were the future [simple warp + non-reactive moebius].json'),
require('butterchurn-presets/presets/converted/Rovastar & Loadus - FractalDrop (Active Sparks Mix).json'),
require('butterchurn-presets/presets/converted/shifter - tumbling cubes (ripples).json'),
require('butterchurn-presets/presets/converted/ORB - Blue Emotion.json'),
require('butterchurn-presets/presets/converted/shifter - urchin mod.json'),
require('butterchurn-presets/presets/converted/Stahlregen & fishbrain + flexi + geiss - The Machine that conquered the Aether.json'),
require('butterchurn-presets/presets/converted/Zylot - Crosshair Dimension (Light of Ages).json'),
];
class AudioVideoViewer extends React.PureComponent {
// audioNode: ?HTMLAudioElement;
// player: ?{ dispose: () => void };
state = {
playing: false,
enableMilkdrop: isButterchurnSupported,
showEqualizer: false,
showSongDetails: true,
enableArt: true,
artLoaded: false,
artist: null,
title: null,
album: null,
};
componentDidMount() {
const me = this;
const { contentType, poster, claim } = me.props;
const path = `https://api.lbry.tv/content/claims/${claim.name}/${claim.claim_id}/stream.mp4`;
const sources = [
{
src: path,
type: contentType,
},
];
const audioNode = this.audioNode;
audioNode.crossOrigin = 'anonymous';
const canvasHeight = me.canvasNode.offsetHeight;
const canvasWidth = me.canvasNode.offsetWidth;
// Required for canvas, nuance of rendering
me.canvasNode.height = canvasHeight;
me.canvasNode.width = canvasWidth;
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioContext = new AudioContext();
const audioSource = audioContext.createMediaElementSource(audioNode);
audioSource.connect(audioContext.destination);
if (isButterchurnSupported) {
const visualizer = (me.visualizer = butterchurn.createVisualizer(audioContext, me.canvasNode, {
height: canvasHeight,
width: canvasWidth,
pixelRatio: window.devicePixelRatio || 1,
textureRatio: 1,
}));
visualizer.connectAudio(audioSource);
visualizer.loadPreset(presets[Math.floor(Math.random() * presets.length)], 2.0);
me._frameCycle = () => {
requestAnimationFrame(me._frameCycle);
if (me.state.enableMilkdrop === true) {
visualizer.render();
}
};
me._frameCycle();
}
const wavesurfer = WaveSurfer.create({
barWidth: 3,
container: this.waveNode,
waveColor: '#000',
progressColor: '#fff',
mediaControls: true,
responsive: true,
normalize: true,
backend: 'MediaElement',
minPxPerSec: 100,
height: this.waveNode.offsetHeight,
});
wavesurfer.load(audioNode);
jsmediatags.Config.setDisallowedXhrHeaders(['If-Modified-Since', 'Range']);
jsmediatags.read(path, {
onSuccess: function(result) {
const { album, artist, title, picture } = result.tags;
if (picture) {
const byteArray = new Uint8Array(picture.data);
const blob = new Blob([byteArray], { type: picture.type });
const albumArtUrl = URL.createObjectURL(blob);
me.artNode.src = albumArtUrl;
me.setState({ artLoaded: true });
}
me.setState({
album,
artist,
title,
});
},
onError: function(error) {
console.log(':(', error.type, error.info);
},
});
}
componentWillUnmount() {
if (this.player) {
this.player.dispose();
}
// Kill the render loop
this._frameCycle = () => {};
}
render() {
const me = this;
const { contentType, poster, claim } = me.props;
const {
album,
artist,
title,
enableMilkdrop,
showEqualizer,
showSongDetails,
enableArt,
artLoaded,
playing,
userActive,
} = this.state;
const renderArt = enableArt && artLoaded;
const path = `https://api.lbry.tv/content/claims/${claim.name}/${claim.claim_id}/stream.mp4`;
const playButton = (
<div
onClick={() => {
const audioNode = this.audioNode;
if (audioNode.paused) {
audioNode.play();
} else {
audioNode.pause();
}
}}
className={playing ? styles.playButtonPause : styles.playButtonPlay}
/>
);
return (
<div
className={userActive ? styles.userActive : styles.wrapper}
onMouseEnter={() => me.setState({ userActive: true })}
onMouseLeave={() => me.setState({ userActive: false })}
onContextMenu={stopContextMenu}
>
<div className={enableMilkdrop ? styles.containerWithMilkdrop : styles.container}>
<div style={{ position: 'absolute', top: 0, right: 0 }}>
<Tooltip onComponent body={__('Toggle Visualizer')}>
<Button
icon={enableMilkdrop ? ICONS.VISUALIZER_ON : ICONS.VISUALIZER_OFF}
onClick={() => {
if (!isButterchurnSupported) {
return;
}
// Get new preset
this.visualizer.loadPreset(presets[Math.floor(Math.random() * presets.length)], 2.0);
this.setState({ enableMilkdrop: !enableMilkdrop });
}}
/>
</Tooltip>
<Tooltip onComponent body={__('Toggle Album Art')}>
<Button
icon={enableArt ? ICONS.MUSIC_ART_ON : ICONS.MUSIC_ART_OFF}
onClick={() => this.setState({ enableArt: !enableArt })}
/>
</Tooltip>
<Tooltip onComponent body={__('Toggle Details')}>
<Button
icon={showSongDetails ? ICONS.MUSIC_DETAILS_ON : ICONS.MUSIC_DETAILS_OFF}
onClick={() => this.setState({ showSongDetails: !showSongDetails })}
/>
</Tooltip>
<Tooltip onComponent body={__('Equalizer')}>
<Button icon={ICONS.MUSIC_EQUALIZER} onClick={() => this.setState({ showEqualizer: !showEqualizer })} />
</Tooltip>
</div>
<div ref={node => (this.waveNode = node)} className={styles.wave} />
<div className={styles.infoContainer}>
<div className={renderArt ? styles.infoArtContainer : styles.infoArtContainerHidden}>
<img className={styles.infoArtImage} ref={node => (this.artNode = node)} />
{renderArt && playButton}
</div>
<div
className={
showSongDetails
? renderArt
? styles.songDetailsContainer
: styles.songDetailsContainerNoArt
: styles.songDetailsContainerHidden
}
>
<div className={renderArt ? styles.songDetails : styles.songDetailsNoArt}>
{artist && (
<div className={styles.detailsLineArtist}>
<Button icon={ICONS.MUSIC_ARTIST} className={styles.detailsIconArtist} />
{artist}
</div>
)}
{title && (
<div className={styles.detailsLineSong}>
<Button icon={ICONS.MUSIC_SONG} className={styles.detailsIconSong} />
{title}
</div>
)}
{album && (
<div className={styles.detailsLineAlbum}>
<Button icon={ICONS.MUSIC_ALBUM} className={styles.detailsIconAlbum} />
{album}
</div>
)}
</div>
</div>
</div>
{!renderArt && <div className={styles.playButtonDetachedContainer}>{playButton}</div>}
</div>
<canvas
ref={node => (this.canvasNode = node)}
className={enableMilkdrop ? styles.milkdrop : styles.milkdropDisabled}
/>
<audio
ref={node => (this.audioNode = node)}
src={path}
style={{ position: 'absolute', top: '-100px' }}
onPlay={() => this.setState({ playing: true })}
onPause={() => this.setState({ playing: false })}
/>
</div>
);
}
}
export default AudioVideoViewer;

View file

@ -1,193 +0,0 @@
.wrapper {
composes: 'file-render__viewer' from global;
}
.userActive {
composes: wrapper;
}
.container {
background: #212529;
position: absolute;
height: 100%;
width: 100%;
display: flex;
}
.containerWithMilkdrop {
composes: container;
background: rgba(50, 50, 55, .7);
}
.wave {
position: absolute;
bottom: -20%;
height: 40%;
opacity: 0.5;
overflow: hidden;
width: 100%;
}
.infoContainer {
padding: 0 20%;
display: flex;
align-items: center;
justify-content: center;
min-height: 42%;
align-self: center;
width: 100%;
margin-top: -10%;
}
.infoArtContainer {
align-self: flex-start;
width: 40%;
float: left;
position: relative;
background: rgba(0, 0, 0 , 0.4);
}
.infoArtContainerHidden {
display: none;
}
.infoArtImage {
display: block;
opacity: 1;
transition: opacity 0.7s;
.userActive & {
opacity: 0.2;
}
}
.songDetailsContainer {
text-align: left;
padding: 3%;
width: 50%;
}
.songDetailsContainerHidden {
display: none;
}
.songDetailsContainerNoArt {
composes: songDetailsContainer;
text-align: center;
}
.songDetails {
width: 150%;
text-shadow: 2px 2px 3px #000;
}
.songDetailsNoArt {
composes: songDetails;
width: 200%;
margin-left: -50%;
}
.detailsIcon {
color: rgba(255, 255, 255, .5);
top: -3px;
padding-right: 10px;
width: 30px;
}
.detailsIconArtist {
composes: detailsIcon;
top: -3px;
}
.detailsIconSong {
composes: detailsIcon;
top: -5px;
}
.detailsIconAlbum {
composes: detailsIcon;
}
.detailsLineArtist {
font-size: 26px;
padding-bottom: 5px;
}
.detailsLineSong {
font-size: 34px;
line-height: 36px;
}
.detailsLineAlbum {
font-size: 20px;
padding-top: 8px;
}
.playButton {
position: absolute;
border: 5px solid #fff;
border-radius: 45px;
color: #fff;
font-family: arial;
font-size: 60px;
left: 50%;
line-height: 80px;
margin-left: -45px;
padding-left: 20px;
bottom: 50%;
margin-bottom: -45px;
height: 90px;
width: 90px;
opacity: 0;
transition: opacity .7s;
.userActive & {
opacity: 0.6;
}
}
.playButtonPlay {
composes: playButton;
&::after {
display: block;
content: "";
}
}
.playButtonPause {
composes: playButton;
font-size: 50px;
line-height: 75px;
padding-left: 20px;
letter-spacing: -24px;
&::after {
display: block;
content: "▎▎";
}
}
.playButtonDetachedContainer {
bottom: 35%;
position: absolute;
left: 50%;
}
.milkdrop {
top: 0;
z-index: 100;
height: 100%;
width: 100%;
display: block;
}
.milkdropDisabled {
display: none;
}

View file

@ -6,15 +6,15 @@
export const FEATURED = 'Award'; export const FEATURED = 'Award';
export const LOCAL = 'Folder'; export const LOCAL = 'Folder';
export const ALERT = 'AlertCircle'; export const ALERT = 'AlertCircle';
export const CLIPBOARD = 'Clipboard'; export const COPY = 'Clipboard';
export const ARROW_LEFT = 'ChevronLeft'; export const ARROW_LEFT = 'ChevronLeft';
export const ARROW_RIGHT = 'ChevronRight'; export const ARROW_RIGHT = 'ChevronRight';
export const DOWNLOAD = 'Download'; export const DOWNLOAD = 'Download';
export const UPLOAD = 'UploadCloud'; export const UPLOAD = 'UploadCloud';
export const PUBLISHED = 'Cloud'; export const PUBLISHED = 'Cloud';
export const CLOSE = 'X'; export const REMOVE = 'X';
export const ADD = 'Plus'; export const ADD = 'Plus';
export const EDIT = 'Edit3'; export const EDIT = 'Edit';
export const DELETE = 'Trash'; export const DELETE = 'Trash';
export const REPORT = 'Flag'; export const REPORT = 'Flag';
export const HELP = 'HelpCircle'; export const HELP = 'HelpCircle';
@ -69,4 +69,4 @@ export const MUSIC_SONG = 'Music';
export const MUSIC_EQUALIZER = 'Sliders'; export const MUSIC_EQUALIZER = 'Sliders';
export const LIGHT = 'Sun'; export const LIGHT = 'Sun';
export const DARK = 'Moon'; export const DARK = 'Moon';
export const AUTO = 'Clock'; export const LIBRARY = 'Folder';

View file

@ -307,17 +307,7 @@ class FilePage extends React.Component<Props> {
}} }}
/> />
<div className="file-properties"> <div className="file-properties">
{isRewardContent && ( {isRewardContent && <Icon size={20} iconColor="red" icon={icons.FEATURED} />}
<Icon
size={20}
iconColor="red"
icon={icons.FEATURED}
// Figure out how to get the tooltip to overlap the navbar on the file page and I will love you
// https://stackoverflow.com/questions/6421966/css-overflow-x-visible-and-overflow-y-hidden-causing-scrollbar-issue
// https://spee.ch/4/overflow-issue
// tooltip="bottom"
/>
)}
{nsfw && <div className="badge badge--nsfw">MATURE</div>} {nsfw && <div className="badge badge--nsfw">MATURE</div>}
<FilePrice badge uri={normalizeURI(uri)} /> <FilePrice badge uri={normalizeURI(uri)} />
</div> </div>

View file

@ -46,6 +46,5 @@
@import 'component/tags'; @import 'component/tags';
@import 'component/time'; @import 'component/time';
@import 'component/toggle'; @import 'component/toggle';
@import 'component/tooltip';
@import 'component/wunderbar'; @import 'component/wunderbar';
@import 'component/yrbl'; @import 'component/yrbl';

View file

@ -1,152 +0,0 @@
.tooltip {
display: inline-block;
position: relative;
.tooltip__body {
visibility: hidden;
}
&:hover {
.tooltip__body {
visibility: visible;
}
}
.tooltip__body {
font-size: 1rem;
color: $lbry-black;
font-weight: 400;
padding: var(--spacing-miniscule);
position: absolute;
text-align: center;
white-space: pre-wrap;
width: 200px;
background-color: $lbry-white;
border: 1px solid $lbry-gray-1;
box-shadow: 0 2px 5px rgba($lbry-black, 0.15);
&.tooltip__body--short {
width: 110px;
}
&::after {
width: 0;
height: 0;
border-style: solid;
border-width: 5px;
content: ' ';
position: absolute;
}
}
$tooltip-border: $lbry-gray-5;
&.tooltip--bottom .tooltip__body::after {
border-color: transparent transparent $tooltip-border transparent;
}
&.tooltip--left .tooltip__body::after {
border-color: transparent transparent transparent $tooltip-border;
}
&.tooltip--right .tooltip__body::after {
border-color: transparent $tooltip-border transparent transparent;
}
&.tooltip--top .tooltip__body::after {
border-color: $tooltip-border transparent transparent transparent;
}
html[data-mode='dark'] & {
.tooltip__body {
border: none;
}
$tooltip-border: $lbry-white;
&.tooltip--bottom .tooltip__body::after {
border-color: transparent transparent $tooltip-border transparent;
}
&.tooltip--left .tooltip__body::after {
border-color: transparent transparent transparent $tooltip-border;
}
&.tooltip--right .tooltip__body::after {
border-color: transparent $tooltip-border transparent transparent;
}
&.tooltip--top .tooltip__body::after {
border-color: $tooltip-border transparent transparent transparent;
}
}
}
.tooltip--always-visible {
.tooltip__body {
visibility: visible;
}
}
.tooltip--label {
// When there is a label for the tooltip and not just using a button or icon
font-size: 14px;
padding-left: $spacing-vertical * 1/3;
height: 100%;
display: flex;
align-items: center;
}
.tooltip--on-component,
.tooltip--icon {
.tooltip__body {
margin-top: 10px;
}
}
.tooltip--left .tooltip__body {
top: -5px;
right: 105%;
&::after {
top: 17px;
left: 100%;
margin-top: -5px;
}
}
.tooltip--right .tooltip__body {
margin-top: -28px;
margin-left: 110%;
&::after {
top: 14px;
right: 100%; // To the left of the tooltip
margin-top: -5px;
}
}
.tooltip--bottom .tooltip__body {
top: 90%;
left: 50%;
margin-left: -100px;
&.tooltip__body--short {
margin-left: -56px;
}
&::after {
bottom: 100%;
left: 50%;
margin-left: -5px;
}
}
.tooltip--top .tooltip__body {
bottom: 120%;
left: 50%;
margin-left: -100px;
&.tooltip__body--short {
margin-left: -56px;
}
&::after {
top: 100%;
left: 50%;
margin-left: -5px;
}
}

View file

@ -91,7 +91,14 @@
.icon { .icon {
margin-right: var(--spacing-small); margin-right: var(--spacing-small);
margin-bottom: 0.2rem; margin-bottom: 0.2rem;
stroke: $lbry-gray-5; stroke: $lbry-gray-5;
} }
[data-mode='dark'] & {
color: $lbry-gray-2;
.icon {
stroke: $lbry-gray-2;
}
}
} }

View file

@ -9459,11 +9459,6 @@ react-dom@^16.8.2, react-dom@^16.8.6:
prop-types "^15.6.2" prop-types "^15.6.2"
scheduler "^0.13.6" scheduler "^0.13.6"
react-feather@^1.0.8:
version "1.1.6"
resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-1.1.6.tgz#2a547e3d5cd5e383d3da0128d593cbdb3c1b32f7"
integrity sha512-iCofWhTjX+vQwvDmg7o6vg0XrUg1c41yBDZG+l83nz1FiCsleJoUgd3O+kHpOeWMXuPrRIFfCixvcqyOLGOgIg==
react-ga@^2.5.7: react-ga@^2.5.7:
version "2.5.7" version "2.5.7"
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.5.7.tgz#1c80a289004bf84f84c26d46f3a6a6513081bf2e" resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.5.7.tgz#1c80a289004bf84f84c26d46f3a6a6513081bf2e"