Add icon support to tooltip and add SpellTooltip component

This commit is contained in:
Melvin Valster
2019-07-25 15:51:13 +02:00
parent 256118fd1a
commit ee0ed4b605
8 changed files with 72 additions and 21 deletions
+8 -6
View File
@@ -6,22 +6,24 @@ interface Props {
name?: string
size?: 'small' | 'medium' | 'large'
golden?: boolean
className?: string
}
const NOT_FOUND_ICON = 'inv_misc_questionmark'
export const Icon: FC<Props> = ({ name: defaultName, size = 'medium', golden = false, children }) => {
export const Icon: FC<Props> = (props) => {
const { name: defaultName, size = 'medium', golden = false, children } = props
const [hasLoadedImage, setLoadedImage] = useState(false)
const [fadeIn, setFadeIn] = useState(false)
const [name, setName] = useState(defaultName)
const bgSize = size !== 'small' ? 'large' : 'medium'
const url = `https://wow.zamimg.com/images/wow/icons/${bgSize}/${name}.jpg`
const url = name && `https://wow.zamimg.com/images/wow/icons/${bgSize}/${name}.jpg`
const start = Date.now()
useEffect(() => {
if (!name) return
if (!url) return
const img = new Image()
img.onload = () => {
const loadTime = Date.now() - start
@@ -32,9 +34,9 @@ export const Icon: FC<Props> = ({ name: defaultName, size = 'medium', golden = f
}
img.onerror = () => setName(NOT_FOUND_ICON)
img.src = url
}, [name, url, start])
}, [url, start])
const className = classNames('icon', `icon--${size}`, {
const className = classNames('icon', `icon--${size}`, props.className, {
'icon--golden': golden,
'icon--loaded': hasLoadedImage,
'icon--fade-in': fadeIn,
@@ -42,7 +44,7 @@ export const Icon: FC<Props> = ({ name: defaultName, size = 'medium', golden = f
return (
<div className={className}>
{name &&
{url &&
<div className="icon__bg" style={{ backgroundImage: `url(${url})` }} />
}
<div className="icon__frame" />
+6
View File
@@ -6,4 +6,10 @@
&:last-child {
margin-bottom: 0;
}
}
.playground-section__spelltooltip {
.tooltip {
margin-bottom: 1rem;
}
}
+14 -1
View File
@@ -7,6 +7,8 @@ import { Tooltip } from './Tooltip'
import { Talent } from './Talent'
import { talentsById } from '../data/talents'
import { Map } from 'immutable'
import { SpellTooltip } from './SpellTooltip';
import classNames from 'classnames'
interface Props extends RouteComponentProps {
//
@@ -38,7 +40,7 @@ const DEEP_WOUNDS = <Tooltip title="Deep Wounds" fixed>
const Section: FC<any> = (props) => {
return <div className="playground-section">
<div className="container">
<div className={classNames('container', `playground-section__${props.title.toLowerCase()}`)}>
<h2>{props.title}</h2>
{props.children}
@@ -152,6 +154,11 @@ export class Playground extends React.PureComponent<Props> {
And even <a href="/warrior">link</a> to exciting places!
</Tooltip>
<h3>With title and icon</h3>
<Tooltip title="Strongest Class in the World" icon="inv_pet_babymurlocs_blue">
<p className="yellow">And some description text here</p>
</Tooltip>
<h3>Fixed width</h3>
{DEEP_WOUNDS}
@@ -165,6 +172,12 @@ export class Playground extends React.PureComponent<Props> {
fixed: false
})}
</Section>
<Section title="SpellTooltip">
<SpellTooltip id={29086} />
<SpellTooltip id={20501} />
<SpellTooltip id={17793} />
</Section>
</div>
)
}
+21
View File
@@ -0,0 +1,21 @@
import React, { FC } from 'react'
import { Tooltip } from './Tooltip'
import spells from '../data/spells.json'
interface Props {
id: number
}
export const SpellTooltip: FC<Props> = ({ id }) => {
const spell: SpellData = spells[id.toString()]
if (!spell) {
return <Tooltip fixed>Spell not found :(</Tooltip>
}
return <Tooltip fixed title={spell.name} icon={spell.icon}>
{spell.rank &&
<p className="tight">Rank {spell.rank}</p>
}
<p className="yellow">{spell.description}</p>
</Tooltip>
}
+1 -1
View File
@@ -6,7 +6,7 @@
height: 40px;
border-radius: 5px;
transition: filter .1s linear;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, .75);
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, .75);
filter: none;
cursor: pointer;
+5 -7
View File
@@ -2,8 +2,8 @@ import './TalentTree.scss'
import React, { useCallback } from 'react'
import { Map } from 'immutable'
import { Talent } from './Talent';
import { getPointsInSpec, canLearnTalent, calcMeetsRequirements, SORT_TALENTS_DESC } from '../lib/tree';
import { talentsBySpec, specNames, talentsById, talentToSpec } from '../data/talents'
import { getPointsInSpec, canLearnTalent, SORT_TALENTS_DESC } from '../lib/tree';
import { talentsBySpec, specNames, talentsById } from '../data/talents'
import { Arrow } from './Arrow'
interface Props {
@@ -36,9 +36,8 @@ export const TalentTree: React.FC<Props> = ({ specId, knownTalents, availablePoi
const points = knownTalents.get(talent.id, 0)
const canLearn = canLearnTalent(knownTalents, talent)
return <React.Fragment>
<Talent
key={talent.id}
return <React.Fragment key={talent.id}>
<Talent
talent={talent}
points={points}
onClick={handleClick}
@@ -47,8 +46,7 @@ export const TalentTree: React.FC<Props> = ({ specId, knownTalents, availablePoi
/>
{!!talent.requires.length &&
<Arrow
key={`arrow-${talent.id}`}
<Arrow
from={talentsById[talent.requires[0].id]}
to={talent}
active={points > 0 || canLearn}
+9 -4
View File
@@ -22,7 +22,7 @@
&__body {
min-height: 2px;
padding: 8px 4px 2px 10px;
padding: 8px 3px 2px 9px;
background: url('../images/tooltip-background.png');
background-position: top left;
}
@@ -50,16 +50,17 @@
.tooltip {
@include tooltip-base;
display: flex;
&--inline {
display: inline-block;
}
&--fixed {
width: 320px;
.tooltip__inner {
width: 100%;
width: 320px;
}
.tooltip__body {
@@ -67,10 +68,14 @@
}
}
&__icon {
margin-right: .25em;
transform: translateY(2px);
}
&__title {
font-size: 14px;
line-height: 1.3;
// margin-bottom: 1px;
}
&__body {
+8 -2
View File
@@ -1,6 +1,7 @@
import './Tooltip.scss'
import React, { FC } from 'react'
import classNames from 'classnames'
import { Icon } from './Icon'
interface Props {
title?: string
@@ -10,6 +11,8 @@ interface Props {
fixed?: boolean
/** Display tooltip inline */
inline?: boolean
/** Icon to show next to tooltip */
icon?: string
}
export const Tooltip: FC<Props> = (props) => {
@@ -24,8 +27,11 @@ export const Tooltip: FC<Props> = (props) => {
width: props.width
}
return <div className={cn} style={style}>
<div className="tooltip__inner">
return <div className={cn}>
{props.icon &&
<Icon className="tooltip__icon" name={props.icon} />
}
<div className="tooltip__inner" style={style}>
<div className="tooltip__top">
<div className="tooltip__body">
{title && <div className="tooltip__title tight">{title}</div>}