1
0
mirror of https://github.com/lexogrine/dota2-react-hud.git synced 2026-05-04 12:33:11 +02:00

Fixed naming

This commit is contained in:
Hubert Walczak
2021-07-23 10:57:33 +02:00
parent dbe53ec4a6
commit 9c95656cd2
1344 changed files with 78 additions and 2020 deletions
+2 -1
View File
@@ -2,8 +2,9 @@ import React from 'react';
import './abilities.scss';
const Ability = ({ name, cooldown, available, level } : { name: string, cooldown: number, available: boolean, level: number | string }) => {
if(name.startsWith("plus_")) return null;
return (
<div className={`skill-container ${cooldown ? 'cooldown':''} ${!available ? 'unavailable':''}`} style={{backgroundImage: `url('./abilities/${name}_lg.png')`}}>
<div className={`skill-container ${cooldown ? 'cooldown':''} ${!available ? 'unavailable':''}`} style={{backgroundImage: `url('./abilities/${name}.png')`}}>
{ cooldown ? <div className="cooldown-container">{cooldown}</div> : null}
<div className="level-container">{level}</div>
</div>
+7 -2
View File
@@ -1,5 +1,8 @@
import { Dota2 } from "dotagsi";
import React from "react";
import { Match } from "../../api/interfaces";
import MatchBar from "../MatchBar/MatchBar";
import SeriesBox from "../MatchBar/SeriesBox";
import Observed from "./../Players/Observed";
@@ -7,6 +10,7 @@ import Observed from "./../Players/Observed";
interface Props {
game: Dota2,
match: Match | null
}
export default class Layout extends React.Component<Props> {
@@ -18,12 +22,13 @@ export default class Layout extends React.Component<Props> {
render() {
const { game } = this.props;
const { game, match } = this.props;
return (
<div className="layout">
<MatchBar map={game.map} match={match} time={game.map.clock_time} players={game.players} />
<SeriesBox map={game.map} match={match} />
<Observed player={game.player}/>
</div>
-62
View File
@@ -1,62 +0,0 @@
import React from "react";
import * as I from "csgogsi-socket";
import { Match, Veto } from '../../api/interfaces';
import TeamLogo from "../MatchBar/TeamLogo";
import "./mapseries.scss";
interface IProps {
match: Match | null;
teams: I.Team[];
isFreezetime: boolean;
map: I.Map
}
interface IVetoProps {
veto: Veto;
teams: I.Team[];
active: boolean;
}
class VetoEntry extends React.Component<IVetoProps> {
render(){
const { veto, teams, active } = this.props;
return <div className={`veto_container ${active ? 'active' : ''}`}>
<div className="veto_map_name">
{veto.mapName}
</div>
<div className="veto_picker">
<TeamLogo team={teams.filter(team => team.id === veto.teamId)[0]} />
</div>
<div className="veto_winner">
<TeamLogo team={teams.filter(team => team.id === veto.winner)[0]} />
</div>
<div className="veto_score">
{Object.values((veto.score || ['-','-'])).sort().join(":")}
</div>
<div className='active_container'>
<div className='active'>Currently playing</div>
</div>
</div>
}
}
export default class MapSeries extends React.Component<IProps> {
render() {
const { match, teams, isFreezetime, map } = this.props;
if (!match || !match.vetos.length) return null;
return (
<div className={`map_series_container ${isFreezetime ? 'show': 'hide'}`}>
<div className="title_bar">
<div className="picked">Picked</div>
<div className="winner">Winner</div>
<div className="score">Score</div>
</div>
{match.vetos.filter(veto => veto.type !== "ban").map(veto => {
if(!veto.mapName) return null;
return <VetoEntry key={`${match.id}${veto.mapName}${veto.teamId}${veto.side}`} veto={veto} teams={teams} active={map.name.includes(veto.mapName)}/>
})}
</div>
);
}
}
-153
View File
@@ -1,153 +0,0 @@
.map_series_container {
position: fixed;
top: 100px;
right: 20px;
width: 347px;
display: flex;
opacity: 0;
transition: opacity 0.5s;
flex-direction: column;
font-size: 13px;
.veto_container {
display: flex;
background-color: rgba(0,0,0,0.8);
color: white;
align-items: center;
height: 40px;
&.active {
.veto_winner {
display: none;
}
.veto_score {
display: none;
}
}
.veto_map_name {
width: 116px;
text-transform: uppercase;
background-color: rgba(255,255,255,1);
color: black;
height: 100%;
display: flex;
font-family: Montserrat;
font-weight: 700;
align-items: center;
justify-content: center;
}
div {
img {
max-height: 30px;
max-width: 30px;
}
}
.veto_picker {
width: 77px;
text-align: center;
}
.veto_winner {
width: 77px;
text-align: center;
}
.active_container {
width: 154px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.active {
background: white;
color: black;
width: 117px;
height: 25px;
display: flex;
align-items: center;
justify-content: center;
font-size: 9px;
font-weight: 700;
font-family: Montserrat;
text-transform: uppercase;
}
}
&:not(.active) {
.active_container {
display: none;
}
}
.veto_score {
width: 77px;
text-align: center;
font-size: 14px;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
}
}
.title_bar {
display: flex;
background-color: rgba(0,0,0,0.64);
height: 25px;
color: white;
border-radius: 6px 6px 0 0;
font-family: Montserrat;
font-size: 13px;
font-weight: 600;
margin-bottom: 2px;
div {
width: 77px;
display: flex;
align-items: center;
justify-content: center;
}
.picked {
margin-left: auto;
}
}
&.show {
opacity: 1;
}
}
#timeout {
text-transform: uppercase;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 150px;
background-color: var(--sub-panel-color);
width: 600px;
display: flex;
align-items: center;
justify-content: center;
height: 100px;
font-size: 35px;
transition: opacity 1.5s;
opacity: 0;
}
#pause {
text-transform: uppercase;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 150px;
background-color: var(--sub-panel-color);
width: 600px;
display: flex;
align-items: center;
justify-content: center;
height: 100px;
font-size: 35px;
transition: opacity 1.5s;
opacity: 0;
color: white;
}
#timeout.show, #pause.show {
opacity: 1;
}
#timeout.t {
color: var(--color-new-t);
}
#timeout.ct {
color: var(--color-new-ct);
}
+17 -168
View File
@@ -1,10 +1,7 @@
import React from "react";
import * as I from "csgogsi-socket";
import * as I from "dotagsi";
import "./matchbar.scss";
import TeamScore from "./TeamScore";
import Bomb from "./../Timers/BombTimer";
import Countdown from "./../Timers/Countdown";
import { GSI } from "../../App";
import { Match } from "../../api/interfaces";
function stringToClock(time: string | number, pad = true) {
@@ -23,179 +20,31 @@ function stringToClock(time: string | number, pad = true) {
interface IProps {
match: Match | null;
map: I.Map;
phase: I.PhaseRaw,
bomb: I.Bomb | null,
players: I.Player[];
time: number;
}
export interface Timer {
width: number;
active: boolean;
countdown: number;
side: "left"|"right";
type: "defusing" | "planting";
player: I.Player | null;
}
interface IState {
defusing: Timer,
planting: Timer,
winState: {
side: "left"|"right",
show: boolean
}
}
export default class TeamBox extends React.Component<IProps, IState> {
constructor(props: IProps){
super(props);
this.state = {
defusing: {
width: 0,
active: false,
countdown: 10,
side: "left",
type: "defusing",
player: null
},
planting: {
width: 0,
active: false,
countdown: 10, // Fake
side: "right",
type: "planting",
player: null
},
winState: {
side: 'left',
show: false
}
}
}
plantStop = () => this.setState(state => {
state.planting.active = false;
return state;
});
setWidth = (type: 'defusing' | 'planting', width: number) => {
this.setState(state => {
state[type].width = width;
return state;
})
}
initPlantTimer = () => {
const bomb = new Countdown(time => {
let width = time * 100;
this.setWidth("planting", width/3);
});
GSI.on("bombPlantStart", player => {
if(!player || !player.team) return;
this.setState(state => {
state.planting.active = true;
state.planting.side = player.team.orientation;
state.planting.player = player;
})
})
GSI.on("data", data => {
if(!data.bomb || !data.bomb.countdown || data.bomb.state !== "planting") return this.plantStop();
this.setState(state => {
state.planting.active = true;
})
return bomb.go(data.bomb.countdown);
});
}
defuseStop = () => this.setState(state => {
state.defusing.active = false;
state.defusing.countdown = 10;
return state;
});
initDefuseTimer = () => {
const bomb = new Countdown(time => {
let width = time > this.state.defusing.countdown ? this.state.defusing.countdown*100 : time * 100;
this.setWidth("defusing", width/this.state.defusing.countdown);
});
GSI.on("defuseStart", player => {
if(!player || !player.team) return;
this.setState(state => {
state.defusing.active = true;
state.defusing.countdown = !Boolean(player.state.defusekit) ? 10 : 5;
state.defusing.side = player.team.orientation;
state.defusing.player = player;
return state;
})
})
GSI.on("data", data => {
if(!data.bomb || !data.bomb.countdown || data.bomb.state !== "defusing") return this.defuseStop();
this.setState(state => {
state.defusing.active = true;
return state;
})
return bomb.go(data.bomb.countdown);
});
}
resetWin = () => {
setTimeout(() => {
this.setState(state => {
state.winState.show = false;
return state;
})
}, 6000);
}
componentDidMount(){
this.initDefuseTimer();
this.initPlantTimer();
GSI.on("roundEnd", score => {
this.setState(state => {
state.winState.show = true;
state.winState.side = score.winner.orientation;
return state;
}, this.resetWin);
});
}
getRoundLabel = () => {
const { map } = this.props;
const round = map.round + 1;
if (round <= 30) {
return `Round ${round}/30`;
}
const additionalRounds = round - 30;
const OT = Math.ceil(additionalRounds/6);
return `OT ${OT} (${additionalRounds - (OT - 1)*6}/6)`;
}
export default class TeamBox extends React.Component<IProps> {
render() {
const { defusing, planting, winState } = this.state;
const { bomb, match, map, phase } = this.props;
const time = stringToClock(phase.phase_ends_in);
const left = map.team_ct.orientation === "left" ? map.team_ct : map.team_t;
const right = map.team_ct.orientation === "left" ? map.team_t : map.team_ct;
const isPlanted = bomb && (bomb.state === "defusing" || bomb.state === "planted");
const { match, map, players, time } = this.props;
const left = map.radiant;
const right = map.dire;
const bo = (match && Number(match.matchType.substr(-1))) || 0;
let leftTimer: Timer | null = null, rightTimer: Timer | null = null;
if(defusing.active || planting.active){
if(defusing.active){
if(defusing.side === "left") leftTimer = defusing;
else rightTimer = defusing;
} else {
if(planting.side === "left") leftTimer = planting;
else rightTimer = planting;
}
}
const leftScore = players.filter(player => player.team_name === 'radiant').map(player => player.kills).reduce((a, b) => a + b, 0);
const rightScore = players.filter(player => player.team_name === 'dire').map(player => player.kills).reduce((a, b) => a + b, 0);
return (
<>
<div id={`matchbar`}>
<TeamScore team={left} orientation={"left"} timer={leftTimer} showWin={winState.show && winState.side === "left"} />
<div className={`score left ${left.side}`}>{left.score}</div>
<TeamScore team={left} orientation={"left"} type={'radiant'} />
<div className={`score left radiant`}>{leftScore}</div>
<div id="timer" className={bo === 0 ? 'no-bo' : ''}>
<div id={`round_timer_text`} className={isPlanted ? "hide":""}>{time}</div>
<div id="round_now" className={isPlanted ? "hide":""}>{this.getRoundLabel()}</div>
<Bomb />
</div>
<div className={`score right ${right.side}`}>{right.score}</div>
<TeamScore team={right} orientation={"right"} timer={rightTimer} showWin={winState.show && winState.side === "right"} />
<div id={`round_timer_text`}>{stringToClock(time)}</div>
</div>
<div className={`score right dire`}>{rightScore}</div>
<TeamScore team={right} orientation={"right"} type={'dire'} />
</div>
</>
);
+5 -6
View File
@@ -1,10 +1,9 @@
import React from "react";
import * as I from "csgogsi-socket";
import * as I from "dotagsi";
import { Match } from "../../api/interfaces";
interface Props {
map: I.Map;
phase: I.PhaseRaw;
match: Match | null;
}
@@ -13,15 +12,15 @@ export default class SeriesBox extends React.Component<Props> {
const { match, map } = this.props;
const amountOfMaps = (match && Math.floor(Number(match.matchType.substr(-1)) / 2) + 1) || 0;
const bo = (match && Number(match.matchType.substr(-1))) || 0;
const left = map.team_ct.orientation === "left" ? map.team_ct : map.team_t;
const right = map.team_ct.orientation === "left" ? map.team_t : map.team_ct;
const left = map.radiant;
const right = map.dire;
return (
<div id="encapsulator">
<div className="container left">
<div className={`series_wins left `}>
<div className={`wins_box_container`}>
{new Array(amountOfMaps).fill(0).map((_, i) => (
<div key={i} className={`wins_box ${left.matches_won_this_series > i ? "win" : ""} ${left.side}`} />
<div key={i} className={`wins_box ${left.map_score > i ? "win" : ""} radiant`} />
))}
</div>
</div>
@@ -33,7 +32,7 @@ export default class SeriesBox extends React.Component<Props> {
<div className={`series_wins right `}>
<div className={`wins_box_container`}>
{new Array(amountOfMaps).fill(0).map((_, i) => (
<div key={i} className={`wins_box ${right.matches_won_this_series > i ? "win" : ""} ${right.side}`} />
<div key={i} className={`wins_box ${right.map_score > i ? "win" : ""} dire`} />
))}
</div>
</div>
+1 -1
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { Team } from 'csgogsi-socket';
import { Team } from 'dotagsi';
import * as I from '../../api/interfaces';
import { apiUrl } from './../../api/api';
+4 -11
View File
@@ -1,29 +1,22 @@
import React from "react";
import * as I from "csgogsi-socket";
import WinIndicator from "./WinIndicator";
import { Timer } from "./MatchBar";
import * as I from "dotagsi";
import TeamLogo from './TeamLogo';
import PlantDefuse from "../Timers/PlantDefuse"
interface IProps {
team: I.Team;
orientation: "left" | "right";
timer: Timer | null;
showWin: boolean;
type: I.Faction
}
export default class TeamScore extends React.Component<IProps> {
render() {
const { orientation, timer, team, showWin } = this.props;
const { orientation, team, type } = this.props;
return (
<>
<div className={`team ${orientation} ${team.side}`}>
<div className={`team ${orientation} ${type}`}>
<div className="team-name">{team.name}</div>
<TeamLogo team={team} />
<div className="round-thingy"><div className="inner"></div></div>
</div>
<PlantDefuse timer={timer} side={orientation} />
<WinIndicator team={team} show={showWin}/>
</>
);
}
-12
View File
@@ -1,12 +0,0 @@
import React from 'react';
import { Team } from 'csgogsi-socket';
export default class WinAnnouncement extends React.Component<{ team: Team | null, show: boolean }> {
render() {
const { team, show } = this.props;
if(!team) return null;
return <div className={`win_text ${show ? 'show' : ''} ${team.orientation} ${team.side}`}>
WINS THE ROUND!
</div>
}
}
+9 -124
View File
@@ -24,36 +24,18 @@
width: 1148px;
height: 70px;
top: 10px;
color: white;
left: 50%;
transform: translateX(-50%);
.CT {
color: var(--color-new-ct);
.round-thingy {
.inner {
background-color: #28abff;
}
background-color: #28abff80;
}
}
.T {
color: var(--color-new-t);
.round-thingy {
.inner {
background-color: #ffc600;
}
background-color: #ffc60080;
}
}
#timer {
display: flex;
flex-direction: column;
position: relative;
width: 126px;
height: 115px;
margin-left: 8px;
margin-right: 8px;
background-color: var(--sub-panel-color);
top: -10px;
&.no-bo {
height: 87px;
}
@@ -200,84 +182,10 @@
flex-direction: row;
width: 10px;
height: 70px;
&.CT {
background-color: var(--color-new-ct);
}
&.T {
background-color: var(--color-new-t);
}
}
}
.win_text {
position: fixed;
display: none;
opacity: 1;
width: 503px;
height: 50px;
top: 70px;
align-items: center;
color: black;
justify-content: center;
background-color: white;
font-size: 20px;
font-family: Montserrat;
font-weight: 600;
&.show {
display: flex;
animation: ShowWinCycle 5s linear 1;
animation-fill-mode: forwards;
}
&.right {
left: calc(50% + 71px);
}
&.left {
right: calc(50% + 71px);
}
}
.defuse_plant_container {
position: fixed;
display: flex;
opacity: 1;
width: 503px;
height: 49px;
top: 70px;
align-items: center;
color: white;
justify-content: center;
background-color: rgba(0,0,0,0.65);
.defuse_plant_bar {
height: 49px;
background-color: #3c3c3c;
position: absolute;
width: 0%;
}
.defuse_plant_caption {
z-index: 1;
display: flex;
text-transform: uppercase;
align-items: flex-end;
svg {
margin-right: 13px;
}
}
&.right {
left: calc(50% + 71px);
.defuse_plant_bar {
left: 0;
}
}
&.left {
right: calc(50% + 71px);
.defuse_plant_bar {
right: 0;
}
}
&.hide {
opacity: 0;
}
}
#encapsulator {
overflow: hidden;
display: flex;
@@ -289,31 +197,16 @@
height: 50px;
left: 50%;
transform: translateX(-50%);
.CT {
color: var(--color-new-ct);
}
.T {
color: var(--color-new-t);
}
.wins_bar {
display: flex;
flex-direction: row;
width: 10px;
height: 30px;
}
.wins_bar.CT {
background-color: var(--color-new-ct);
}
.wins_bar.T {
background-color: var(--color-new-t);
}
}
.alert_bar.CT {
background-color: var(--color-new-ct);
}
.alert_bar.T {
background-color: var(--color-new-t);
}
#series_container {
display: flex;
flex-direction: row;
@@ -376,16 +269,8 @@
margin-left: 2px;
margin-right: 2px;
box-sizing: border-box;
}
.wins_box.CT {
background-color: rgba(0,0,0,0.6);
}
.wins_box.CT.win {
background-color: var(--color-new-ct);
}
.wins_box.T {
background-color: rgba(0,0,0,0.6);
}
.wins_box.T.win {
background-color: var(--color-new-t);
background-color:rgba(0,0,0,0.25);
&.win {
background-color: rgba(255,255,255,1);
}
}
-52
View File
@@ -1,52 +0,0 @@
import React from 'react';
import { isDev, port } from '../../api/api';
import { actions } from '../../App';
import { avatars } from './../../api/avatars';
import { Skull } from './../../assets/Icons';
interface IProps {
steamid: string,
slot?: number,
height?: number,
width?: number,
showSkull?: boolean,
showCam?: boolean
}
interface IState {
enableCams: boolean
}
export default class Avatar extends React.Component<IProps, IState> {
state = {
enableCams: !!this.props.showCam
}
componentDidMount(){
actions.on("toggleCams", () => {
this.setState({enableCams: !this.state.enableCams})
});
}
render(){
const { enableCams } = this.state;
//const url = avatars.filter(avatar => avatar.steamid === this.props.steamid)[0];
const avatarData = avatars[this.props.steamid];
if(!avatarData || !avatarData.url){
return '';
}
const slot = this.props.slot === 0 ? 10 : this.props.slot || 1;
const leftPosition = - 150*((slot-1)%5);
const topPosition = slot > 5 ? -150 : 0;
return (
<div className={`avatar`}>
{
this.props.showCam ? <div id="cameraFeed" style={{ display: enableCams ? 'block' : 'none'}}><iframe style={{top: `${topPosition}px`, left: `${leftPosition}px`}} src={isDev ? `http://localhost:${port}/rmtp.html` : '/rmtp.html'} title="Camera feed" /></div> : null
}
{
this.props.showSkull ? <Skull height={this.props.height} width={this.props.width} /> : <img src={avatarData.url} height={this.props.height} width={this.props.width} alt={'Avatar'} />
}
</div>
);
}
}
+2 -2
View File
@@ -16,7 +16,7 @@ export default class Observed extends React.Component<{ player: Player | null }>
<div className={`avatar`}>
<img src={`./heroes/${player.hero.name.replace('npc_dota_hero_', '')}_full.png`} width={140} alt={'Avatar'} />
<img src={`./heroes/${player.hero.name.replace('npc_dota_hero_', '')}.png`} width={140} alt={'Avatar'} />
</div>
<div className="username_container">
@@ -35,7 +35,7 @@ export default class Observed extends React.Component<{ player: Player | null }>
</div>
<div className="statistics">
{
player.items.filter(item => item.type === "slot").map(item => item.name !== "empty" ? <img src={`./items/${item.name.replace('item_', '')}_lg.png`} height={43} /> : null)
player.items.filter(item => item.type === "slot").map(item => item.name !== "empty" ? <img src={`./items/${item.name.replace('item_', '')}.png`} height={43} /> : null)
}
</div>
<div className="bar-container">
-73
View File
@@ -1,73 +0,0 @@
import React from "react";
import { Player, WeaponRaw } from "csgogsi-socket";
import Weapon from "./../Weapon/Weapon";
import Avatar from "./Avatar";
import Armor from "./../Indicators/Armor";
import Bomb from "./../Indicators/Bomb";
import Defuse from "./../Indicators/Defuse";
interface IProps {
player: Player,
isObserved: boolean,
isFreezetime: boolean,
}
export default class PlayerBox extends React.Component<IProps> {
render() {
const { player } = this.props;
const weapons: WeaponRaw[] = Object.values(player.weapons).map(weapon => ({ ...weapon, name: weapon.name.replace("weapon_", "") }));
const primary = weapons.filter(weapon => !['C4', 'Pistol', 'Knife', 'Grenade', undefined].includes(weapon.type))[0] || null;
const secondary = weapons.filter(weapon => weapon.type === "Pistol")[0] || null;
const grenades = weapons.filter(weapon => weapon.type === "Grenade");
const isLeft = player.team.orientation === "left";
return (
<div className={`player ${player.state.health === 0 ? "dead" : ""} ${this.props.isObserved ? 'active' : ''}`}>
<div className="player_data">
<Avatar steamid={player.steamid} height={57} width={57} showSkull={false}/>
<div className="dead-stats">
<div className="labels">
<div className="stat-label">K</div>
<div className="stat-label">A</div>
<div className="stat-label">D</div>
</div>
<div className="values">
<div className="stat-value">{player.stats.kills}</div>
<div className="stat-value">{player.stats.assists}</div>
<div className="stat-value">{player.stats.deaths}</div>
</div>
</div>
<div className="player_stats">
<div className="row">
<div className="health">
{player.state.health}
</div>
<div className="username">
<div>{isLeft ? <span>{player.observer_slot}</span> : null} {player.name} {!isLeft ? <span>{player.observer_slot}</span> : null}</div>
{primary || secondary ? <Weapon weapon={primary ? primary.name : secondary.name} active={primary ? primary.state === "active" : secondary.state === "active"} /> : ""}
{player.state.round_kills ? <div className="roundkills-container">{player.state.round_kills}</div> : null}
</div>
</div>
<div className={`hp_bar ${player.state.health <= 20 ? 'low':''}`} style={{ width: `${player.state.health}%` }}></div>
<div className="row">
<div className="armor_and_utility">
<Bomb player={player} />
<Armor player={player} />
<Defuse player={player} />
</div>
<div className="money">${player.state.money}</div>
<div className="grenades">
{grenades.map(grenade => (
[
<Weapon key={`${grenade.name}-${grenade.state}`} weapon={grenade.name} active={grenade.state === "active"} isGrenade />,
grenade.ammo_reserve === 2 ? <Weapon key={`${grenade.name}-${grenade.state}-double`} weapon={grenade.name} active={grenade.state === "active"} isGrenade /> : null,
]
))}
</div>
<div className="secondary_weapon">{primary && secondary ? <Weapon weapon={secondary.name} active={secondary.state === "active"} /> : ""}</div>
</div>
<div className="active_border"></div>
</div>
</div>
</div>
);
}
}
-27
View File
@@ -1,27 +0,0 @@
import React from 'react';
import Player from './Player'
import * as I from 'csgogsi-socket';
import './players.scss';
interface Props {
players: I.Player[],
team: I.Team,
side: 'right' | 'left',
current: I.Player | null,
isFreezetime: boolean,
}
export default class TeamBox extends React.Component<Props> {
render() {
return (
<div className={`teambox ${this.props.team.side} ${this.props.side}`}>
{this.props.players.map(player => <Player
key={player.steamid}
player={player}
isObserved={!!(this.props.current && this.props.current.steamid === player.steamid)}
isFreezetime={this.props.isFreezetime}
/>)}
</div>
);
}
}
-358
View File
@@ -1,358 +0,0 @@
.teambox {
position: fixed;
bottom: 10px;
display: flex;
flex-direction: column;
opacity: 1;
transition: opacity 0.75s;
&.CT {
.player .hp_bar {
background-color: var(--color-new-ct);
}
}
&.T {
.player .hp_bar {
background-color: var(--color-new-t);
}
}
&.hide {
opacity: 0;
}
&.left {
left: 10px;
.player {
.row {
flex-direction: row;
.grenades {
padding-right: 5px;
}
.armor_and_utility {
justify-content: flex-start;
}
.money {
margin-right: auto;
}
.username .roundkills-container {
right: 115px;
}
.secondary_weapon {
padding-right: 10px;
}
}
.dead-stats {
right: 8px;
}
}
}
&.right {
right: 10px;
.player {
flex-direction: row-reverse;
.dead-stats {
left: 8px;
}
.player_data {
flex-direction: row-reverse;
.hp_bar {
align-self: flex-end;
}
.row {
flex-direction: row-reverse;
.grenades {
padding-left: 5px;
}
.username {
flex-direction: row-reverse;
.roundkills-container {
left: 115px;
}
}
.secondary_weapon {
padding-left: 10px;
}
.armor_and_utility {
justify-content: flex-end;
}
.money {
margin-left: auto;
justify-content: flex-end;
}
.weapon {
transform: scaleX(-1);
}
}
.avatar {
justify-content: flex-start;
}
}
}
}
.player {
width: 645px;
height: 70px;
margin-bottom: 4px;
display: flex;
flex-direction: row;
align-items: center;
&.active {
.player_data {
border: 2px solid white;
}
}
&.dead {
opacity: 0.7;
.player_side_bar {
background-color: var(--main-panel-color) !important;
}
.player_data {
.avatar {
filter: grayscale(100%);
}
.dead-stats {
display: flex;
}
.row {
.hp_background_2 {
opacity: 0;
}
.health {
color: #b2b2b2;
overflow: hidden;
}
.username {
color: #b2b2b2;
}
.armor_and_utility {
width: 0px;
overflow: hidden;
}
.money {
color: #466722;
}
}
}
}
&:last-child .player_data {
border-radius: 0 0 20px 20px;
}
.player_side_bar {
width: 10px;
height: 70px;
&.CT {
background-color: var(--color-new-ct);
}
&.T {
background-color: var(--color-new-t);
}
}
.dead-stats {
position: absolute;
height: 85%;
width: 60px;
display: none;
flex-direction: column;
font-weight: 600;
color: white;
opacity: 0.75;
top: 10%;
.labels, .values {
display: flex;
flex-direction: row;
flex: 1;
.stat-label, .stat-value {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
}
}
}
.player_data {
background-color: var(--sub-panel-color);
width: 415px;
display: flex;
flex-direction: row;
position: relative;
height: 100%;
.player_stats {
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
.hp_bar {
height: 2px;
&.low {
background-color: red;
}
}
.row {
flex: 1;
display: flex;
position: relative;
svg.weapon {
filter: invert(45%);
&.active {
filter: invert(0);
}
}
.hp_background, .hp_background_2 {
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.hp_background_2 {
background-color: var(--color-bomb);
transition: width 0.75s 1.5s;
}
.armor_and_utility {
width: 39px;
display: flex;
align-items: center;
padding-left: 5px;
padding-right: 5px;
.armor_indicator, .bomb_indicator, .defuse_indicator {
svg {
max-height: 20px;
fill: white;
}
}
div {
display: flex;
width: 50%;
}
}
.username {
flex: 1;
display: flex;
align-items: center;
z-index: 1;
color: white;
font-weight: 600;
max-width: calc(100% - 49px);
justify-content: space-between;
overflow: hidden;
font-size: 18px;
text-overflow: ellipsis;
white-space: nowrap;
.roundkills-container {
position: absolute;
background-image: url('./../../assets/images/icon_skull_default.svg');
background-repeat: no-repeat;
background-size: 10px;
background-position: left 2px;
padding-left: 16px;
font-size: 13px;
}
div span {
opacity: 0.6;
font-size:15px;
}
svg.weapon {
max-height: 30px;
width: auto;
margin-left: 5px;
margin-right: 5px;
max-width: 100px;
height: 30px;
}
}
.money {
width: 60px;
color: var(--color-moneys);
font-weight: 600;
display: flex;
align-items: center;
justify-content: flex-start;
}
.grenades {
display: flex;
align-items: center;
justify-content: space-around;
svg.grenade {
max-height: 20px;
height: 20px;
}
}
.health {
width: 49px;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
color: white;
font-weight: 600;
font-size:18px;
}
.secondary_weapon {
display: flex;
align-items: center;
svg {
max-height: 30px;
height: 30px;
}
}
}
}
.avatar {
width: 70px;
display: flex;
align-items: center;
justify-content: flex-end;
img {
border-radius:50%;
}
}
}
}
}
.players_alive {
display: flex;
flex-direction: column;
width: 180px;
background-color: rgba(0,0,0,0.5);
position: fixed;
right: 10px;
top: 10px;
opacity: 1;
transition: opacity 1s;
.counter_container {
display: flex;
height: 45px;
> div {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size:30px;
color: white;
background-color: rgba(0,0,0,0.5);
}
.team_counter {
background-color: rgba(0,0,0,0.75);
}
.CT {
color: var(--color-new-ct);
}
.T {
color: var(--color-new-t);
}
}
.title_container {
color: white;
text-transform: uppercase;
text-align: center;
height:20px;
font-size:14px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0,0,0,0.75);
}
&.hide {
opacity: 0;
}
}