Skip to content

Commit

Permalink
Add card tooltips based on react-hs-components
Browse files Browse the repository at this point in the history
Use hotfixed file-loader for now, until webpack-contrib/file-loader#183
is released.
  • Loading branch information
beheh committed Sep 23, 2017
1 parent 39892e2 commit d76351d
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"cross-env": "^5.0.5",
"file-loader": "http://libs.hearthsim.net/file-loader-1.0.1-fix-exports-raw-value.0.tgz",
"hearthstonejson": "^0.6.6",
"html-webpack-plugin": "^2.30.1",
"license-webpack-plugin": "^1.0.1",
Expand Down
5 changes: 5 additions & 0 deletions src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
declare module "*.png" {
const content: string;
export default content;
}

declare const APPLICATION_VERSION: string;
10 changes: 10 additions & 0 deletions src/utils/portal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { makeHOC } from "./hocs";
import * as PropTypes from "prop-types";

export interface PortalProps {
portal: HTMLDivElement;
}

export const withPortal = makeHOC<PortalProps>({
portal: PropTypes.object,
});
35 changes: 35 additions & 0 deletions src/viewer/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from "react";
import { Card as ComponentCard } from "react-hs-components";
import { CardsProps, withCards } from "../utils/cards";
import { getPlaceholder } from "./placeholders";

interface CardProps extends React.ClassAttributes<Card> {
dbfId: number;
x?: number;
y?: number;
}

class Card extends React.Component<CardProps & CardsProps, {}> {
render() {
const card = this.props.cards.getByDbfId(this.props.dbfId);
if (!card || !card.id) {
return <div>Invalid card</div>;
}
return (
<ComponentCard
id={card.id}
style={{
position: "absolute",
height: "40vh",
top: this.props.y ? `calc(${this.props.y}px - 7.5vh - 20vh)` : 0,
left: this.props.x || 0,
pointerEvents: "none",
}}
resolution={512}
placeholder={getPlaceholder(card.type || "")}
/>
);
}
}

export default withCards(Card);
55 changes: 49 additions & 6 deletions src/viewer/Minion.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import styled from "styled-components";
import { CardsProps, withCards } from "../utils/cards";
import Card from "./Card";
import { PortalProps, withPortal } from "../utils/portal";

const MinionDiv = styled.div`
width: 11vh;
Expand All @@ -26,28 +29,68 @@ interface MinionProps extends React.ClassAttributes<Minion> {

interface MinionState {
isHovering?: boolean;
x?: number | null;
y?: number | null;
}

class Minion extends React.Component<MinionProps & CardsProps, MinionState> {
constructor(props: MinionProps & CardsProps, context: any) {
class Minion extends React.Component<
MinionProps & CardsProps & PortalProps,
MinionState
> {
ref: HTMLDivElement | null;

constructor(props: MinionProps & CardsProps & PortalProps, context: any) {
super(props, context);
this.state = {
isHovering: false,
x: null,
y: null,
};
}

render() {
const card = this.props.cards.getByDbfId(this.props.dbfId);

let tooltip = null;
if (this.state.isHovering && this.props.portal && card && card.id) {
tooltip = (ReactDOM as any).createPortal(
<Card
dbfId={this.props.dbfId}
x={this.state.x || 0}
y={this.state.y || 0}
/>,
this.props.portal,
);
}

return (
<MinionDiv
onMouseEnter={() => this.setState({ isHovering: true })}
onMouseLeave={() => this.setState({ isHovering: false })}
onMouseEnter={e => {
let { clientX, clientY } = e;
const rect = this.ref && this.ref.getBoundingClientRect();
if (rect) {
clientX += rect.width - (clientX - rect.left);
clientY = rect.bottom;
}

this.setState({
isHovering: true,
x: clientX,
y: clientY,
});
}}
onMouseLeave={() =>
this.setState({
isHovering: false,
x: null,
y: null,
})}
innerRef={(ref: HTMLDivElement | null) => (this.ref = ref)}
>
{this.state.isHovering && card && card.id ? card.id : null}
{tooltip}
</MinionDiv>
);
}
}

export default withCards(Minion);
export default withPortal(withCards(Minion));
16 changes: 16 additions & 0 deletions src/viewer/Overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from "styled-components";
import Minion from "./Minion";
import { withProps } from "../utils/styled";
import { BoardStateData } from "../twitch-hdt";
import * as PropTypes from "prop-types";

interface OverlayProps extends React.ClassAttributes<Overlay> {
boardState?: BoardStateData | null;
Expand All @@ -22,6 +23,13 @@ const Portal = styled.div`
width: 100vw;
height: 100vh;
position: absolute;
z-index: 999;
pointer-events: none;
overflow: hidden;
& * {
pointer-events: auto;
}
`;

const Board = withProps<TopProps>()(styled.div)`
Expand All @@ -45,6 +53,14 @@ class Overlay extends React.Component<OverlayProps, {}> {
));
}

static childContextTypes = {
portal: PropTypes.object,
};

getChildContext() {
return { portal: this.portal };
}

render() {
const playerBoard = this.props.boardState
? this.props.boardState.player_board.map((dbfId: number) => (
Expand Down
Binary file added src/viewer/placeholders/hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/viewer/placeholders/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import MinionPlaceholder from "./minion.png";
import SpellPlaceholder from "./spell.png";
import WeaponPlaceholder from "./weapon.png";
import HeroPlaceholder from "./hero.png";

const getPlaceholder = (type: string): string => {
switch (type) {
case "SPELL":
return SpellPlaceholder;
case "WEAPON":
return WeaponPlaceholder;
case "HERO":
return HeroPlaceholder;
default:
case "MINION":
return MinionPlaceholder;
}
};

export {
getPlaceholder,
MinionPlaceholder,
SpellPlaceholder,
HeroPlaceholder,
WeaponPlaceholder,
};
Binary file added src/viewer/placeholders/minion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/viewer/placeholders/spell.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/viewer/placeholders/weapon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@ module.exports = {
},
],
},
{
test: /\.png$/,
exclude: /node_modules/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "img/",
},
},
],
},
],
},
devServer: {
Expand Down
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1786,6 +1786,12 @@ fbjs@^0.8.5, fbjs@^0.8.9:
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"

"file-loader@http://libs.hearthsim.net/file-loader-1.0.1-fix-exports-raw-value.0.tgz":
version "1.0.1-fix-exports-raw-value.0"
resolved "http://libs.hearthsim.net/file-loader-1.0.1-fix-exports-raw-value.0.tgz#22e0c8bf80348bdb36407b82d698a6245a46b182"
dependencies:
loader-utils "^1.0.2"

filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
Expand Down

0 comments on commit d76351d

Please sign in to comment.