Add /playground and initial tooltips

This commit is contained in:
Melvin Valster
2019-07-24 21:52:38 +02:00
parent 94a0a97fbf
commit 36742ea22e
14 changed files with 260 additions and 32 deletions
+1
View File
@@ -5,6 +5,7 @@
- [ ] General: Responsive on mobile - [ ] General: Responsive on mobile
- [ ] Talent tree: Reset button per tree (?) - [ ] Talent tree: Reset button per tree (?)
- [ ] Fix: Initial load `pointString` validation (make sure all talents are valid and their deps are met) - [ ] Fix: Initial load `pointString` validation (make sure all talents are valid and their deps are met)
- [ ] Fix: Arrow should start underneath the icon
- [x] Talent tree: Arrows for dependencies - [x] Talent tree: Arrows for dependencies
- [x] System: Generate URL for chosen talents - [x] System: Generate URL for chosen talents
- [x] Talent tree: Prettier talent frames - [x] Talent tree: Prettier talent frames
+29 -3
View File
@@ -1,10 +1,33 @@
@import "sass/config"; @import "sass/config";
body { body {
color: white;
background-color: #111; background-color: #111;
font-family: Verdana; font-family: Verdana;
} }
a {
text-decoration: none;
color: pink;
&:hover {
color: lighten(pink, 50%);
}
}
.container {
max-width: 900px;
margin: 0 auto;
}
.inline-items {
display: flex;
& > * {
margin-right: 1em;
}
}
.calculator { .calculator {
&__points { &__points {
color: white; color: white;
@@ -48,10 +71,13 @@ body {
.class-picker { .class-picker {
display: flex; display: flex;
justify-content: center;
list-style: none; list-style: none;
margin-top: 2em; padding: 0;
margin-bottom: 2em; margin: 2em 0;
&--center {
justify-content: center;
}
&__class { &__class {
margin-right: 1em; margin-right: 1em;
+5 -1
View File
@@ -1,14 +1,18 @@
import React from 'react' import React from 'react'
import './App.scss' import './App.scss'
import { IndexRoute } from './components/IndexRoute' import { IndexRoute } from './components/IndexRoute'
import { BrowserRouter as Router, Route } from 'react-router-dom' import { PlaygroundRoute } from './components/PlaygroundRoute'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
const App: React.FC = () => { const App: React.FC = () => {
return ( return (
<Router basename={process.env.NODE_ENV === 'production' ? '/wow-talent-calculator' : ''}> <Router basename={process.env.NODE_ENV === 'production' ? '/wow-talent-calculator' : ''}>
{/* <Router basename={process.env.NODE_ENV !== 'development' ? '%PUBLIC_URL%' : ''}> */} {/* <Router basename={process.env.NODE_ENV !== 'development' ? '%PUBLIC_URL%' : ''}> */}
<div className="App"> <div className="App">
<Switch>
<Route exact path="/playground" component={PlaygroundRoute} />
<Route path="/:selectedClass?/:pointString?" component={IndexRoute} /> <Route path="/:selectedClass?/:pointString?" component={IndexRoute} />
</Switch>
</div> </div>
</Router> </Router>
); );
+1 -2
View File
@@ -110,8 +110,7 @@
} }
} }
&--right-down, &--side-down {
&--left-down {
// Position based on row // Position based on row
@for $i from 0 through 6 { @for $i from 0 through 6 {
&[data-row="#{$i}"] { &[data-row="#{$i}"] {
+1
View File
@@ -42,6 +42,7 @@ export const Arrow: FC<Props> = ({ from, to, active = false }) => {
const className = classNames('arrow', `arrow--${dir}`, { const className = classNames('arrow', `arrow--${dir}`, {
'arrow--active': active, 'arrow--active': active,
'arrow--side-down': dir === 'right-down' || dir === 'left-down'
}) })
return <div className={className} {...props} /> return <div className={className} {...props} />
+1 -2
View File
@@ -99,8 +99,7 @@ export class Calculator extends React.PureComponent<Props> {
<ul> <ul>
<li><a href="/shaman/-5505000055523051-55">Shaman test</a></li> <li><a href="/shaman/-5505000055523051-55">Shaman test</a></li>
<li><a href="/shaman/-5595000055523051-55">Shaman test broken</a></li> <li><a href="/shaman/-5595000055523051-55">Shaman test broken</a></li>
<li><a href="/rogue/-005055-50205302332212051">Rogue (should break, does not meet requirement)</a></li> <li><a href="/rogue/325323125551351-3253552122555155231-55225313333212151">Full Rogue</a></li>
<li><a href="/rogue/-005055-50205302333212041">Rogue can unlearn first row AND dependency</a></li>
</ul> </ul>
</div> </div>
) )
+4 -2
View File
@@ -7,6 +7,7 @@ import classNames from 'classnames'
interface Props { interface Props {
/** Name of the selected class, lowercase */ /** Name of the selected class, lowercase */
selected?: string selected?: string
center?: boolean
} }
const classNameForItem = (c: ClassData, selected: string) => classNames('class-picker__class', { const classNameForItem = (c: ClassData, selected: string) => classNames('class-picker__class', {
@@ -18,10 +19,11 @@ export class ClassPicker extends React.PureComponent<Props> {
static whyDidYouRender = true static whyDidYouRender = true
render() { render() {
const { selected } = this.props const { selected, center = false } = this.props
const cn = classNames('class-picker', { const cn = classNames('class-picker', {
'class-picker--has-selection': !!selected 'class-picker--has-selection': !!selected,
'class-picker--center': center,
}) })
return ( return (
+32 -15
View File
@@ -1,11 +1,34 @@
@import "../sass/_config"; @import "../sass/_config";
@mixin icon-size($size) {
$offset: $size * 0.1;
width: $size;
height: $size;
.icon__bg {
width: ceil($size - $offset);
height: ceil($size - $offset);
border-radius: $size / 8;
top: $size * 0.05;
left: $size * 0.05;
}
.icon__frame {
width: $size + $offset;
height: $size + $offset;
top: -($offset * .5);
left: -($offset * .5);
}
}
.icon { .icon {
position: relative; position: relative;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;
background-color: #222; background-color: #222;
border-radius: 5px;
&:hover { &:hover {
.icon__bg { .icon__bg {
@@ -19,17 +42,16 @@
} }
} }
&--medium { &--small {
width: 40px; @include icon-size(20px);
height: 40px;
border-radius: 5px;
.icon__bg {
width: 36px;
height: 36px;
top: 2px;
left: 2px;
} }
&--medium {
@include icon-size(40px);
}
&--large {
@include icon-size(60px);
} }
&--golden { &--golden {
@@ -47,17 +69,12 @@
&__bg { &__bg {
position: absolute; position: absolute;
background-size: cover; background-size: cover;
border-radius: 5px;
opacity: 1; opacity: 1;
transition: all 100ms ease-out; transition: all 100ms ease-out;
} }
&__frame { &__frame {
position: absolute; position: absolute;
width: 44px;
height: 44px;
top: -2px;
left: -2px;
background-image: url('../images/icons/large/default.png'); background-image: url('../images/icons/large/default.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;
+1 -1
View File
@@ -11,7 +11,7 @@ interface Props {
export const Icon: FC<Props> = ({ name, size = 'medium', golden = false, children }) => { export const Icon: FC<Props> = ({ name, size = 'medium', golden = false, children }) => {
const [hasLoadedImage, setHasLoadedImage] = useState(false) const [hasLoadedImage, setHasLoadedImage] = useState(false)
const bgSize = size === 'medium' ? 'large' : 'medium' const bgSize = size !== 'small' ? 'large' : 'medium'
const url = `https://wow.zamimg.com/images/wow/icons/${bgSize}/${name}.jpg` const url = `https://wow.zamimg.com/images/wow/icons/${bgSize}/${name}.jpg`
useEffect(() => { useEffect(() => {
+1 -1
View File
@@ -33,7 +33,7 @@ export class IndexRoute extends React.PureComponent<Props> {
return ( return (
<div className="index"> <div className="index">
<ClassPicker selected={selectedClass} /> <ClassPicker center selected={selectedClass} />
{selectedClass && {selectedClass &&
<Calculator <Calculator
+71
View File
@@ -0,0 +1,71 @@
import React from 'react'
import { ClassPicker } from './ClassPicker'
import { match } from 'react-router-dom'
import { RouteComponentProps } from 'react-router'
import { Icon } from './Icon';
import { Tooltip } from './Tooltip';
interface Props extends RouteComponentProps {
match: match<{
selectedClass: string
pointString: string
}>
}
const iconNames = [
'foo',
'spell_holy_prayerofhealing',
'ability_sap',
'class_shaman',
'inv_ammo_firetar',
'spell_shadow_requiem',
]
export class PlaygroundRoute extends React.PureComponent<Props> {
static whyDidYouRender = true
render() {
const { match, history } = this.props
return (
<div className="playground container">
<h2>Class Picker</h2>
<ClassPicker />
<h2>Icons</h2>
<h3>Small Icons</h3>
<div className="inline-items">
{iconNames.map((n) => <Icon key={n} name={n} size="small" />)}
</div>
<h3>Medium Icons</h3>
<div className="inline-items">
{iconNames.map((n) => <Icon key={n} name={n} size="medium" />)}
</div>
<h3>Large Icons</h3>
<div className="inline-items">
{iconNames.map((n) => <Icon key={n} name={n} size="large" />)}
</div>
<h2>Tooltip</h2>
<Tooltip inline />
<Tooltip>
<strong>I can use normal HTML in here</strong>
<br />
And even <a href="#">link</a> to exciting places!
</Tooltip>
<Tooltip title="Sanctuary Post" />
<Tooltip title="Fixed width" fixed />
<Tooltip title="Override fixed width" fixed width="600px" />
</div>
)
}
}
+69
View File
@@ -0,0 +1,69 @@
@mixin tooltip-base {
font-size: 12px;
font-family: Verdana, Geneva, Tahoma, sans-serif;
line-height: 1.4;
&__inner {
display: inline-block;
flex-direction: column;
align-items: flex-start;
}
&__top {
display: flex;
&:after {
content: '';
padding: 3px;
background: url('../images/tooltip-background.png');
background-position: top right;
}
}
&__body {
min-height: 2px;
padding: 8px 4px 2px 10px;
background: url('../images/tooltip-background.png');
background-position: top left;
}
&__footer {
display: flex;
width: 100%;
&:before {
content: '';
flex: 1;
padding: 3px;
background: url('../images/tooltip-background.png');
background-position: bottom left;
}
&:after {
content: '';
padding: 3px;
background: url('../images/tooltip-background.png');
background-position: bottom right;
}
}
}
.tooltip {
@include tooltip-base;
&--inline {
display: inline-block;
}
&--fixed {
width: 320px;
.tooltip__inner {
width: 100%;
}
.tooltip__body {
flex: 1;
}
}
}
+29 -1
View File
@@ -1,11 +1,39 @@
import './Tooltip.scss' import './Tooltip.scss'
import React, { FC } from 'react' import React, { FC } from 'react'
import classNames from 'classnames'
interface Props { interface Props {
title?: string
/** Override width of tooltip. Needs `fixed` to be true to have effect. */
width?: string
/** Fixed width */
fixed?: boolean
/** Display tooltip inline */
inline?: boolean
} }
export const Tooltip: FC<Props> = (props) => { export const Tooltip: FC<Props> = (props) => {
return <div className="tooltip"> const { title, children } = props
const cn = classNames('tooltip', {
'tooltip--fixed': props.fixed,
'tooltip--inline': props.inline,
})
const style = {
width: props.width
}
return <div className={cn} style={style}>
<div className="tooltip__inner">
<div className="tooltip__top">
<div className="tooltip__body">
{title}
{children}
</div>
</div>
<div className="tooltip__footer" />
</div>
</div> </div>
} }
+11
View File
@@ -12,3 +12,14 @@ $color-green: #1eff00;
$color-dark-green: #40bf40; $color-dark-green: #40bf40;
$color-subtle: #9d9d9d; $color-subtle: #9d9d9d;
$color-icon-overlay: #6396d6; $color-icon-overlay: #6396d6;
// Class colours
$color-warrior: #c69b6d;
$color-paladin: #f48cba;
$color-hunter: #aad372;
$color-rogue: #fff468;
$color-priest: #fff;
$color-shaman: #2359ff;
$color-mage: #68ccef;
$color-warlock: #9382c9;
$color-druid: #ff7c0a;