mirror of
https://github.com/lexogrine/dota2-react-hud.git
synced 2026-05-04 12:33:11 +02:00
init
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
.skill-container {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
|
||||
&.unavailable {
|
||||
filter:grayscale(1);
|
||||
}
|
||||
|
||||
.level-container {
|
||||
color: gold;
|
||||
text-shadow: 0 0 5px black;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
}
|
||||
.cooldown-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
font-size: 34px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from 'react';
|
||||
import './abilities.scss';
|
||||
|
||||
const Ability = ({ name, cooldown, available, level } : { name: string, cooldown: number, available: boolean, level: number | string }) => {
|
||||
return (
|
||||
<div className={`skill-container ${cooldown ? 'cooldown':''} ${!available ? 'unavailable':''}`} style={{backgroundImage: `url('./abilities/${name}_lg.png')`}}>
|
||||
{ cooldown ? <div className="cooldown-container">{cooldown}</div> : null}
|
||||
<div className="level-container">{level}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Ability;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
import Observed from "./../Players/Observed";
|
||||
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
game: any,
|
||||
}
|
||||
|
||||
export default class Layout extends React.Component<Props> {
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { game } = this.props;
|
||||
|
||||
|
||||
return (
|
||||
<div className="layout">
|
||||
|
||||
<Observed player={game.player}/>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
.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);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
import React from "react";
|
||||
import * as I from "csgogsi-socket";
|
||||
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) {
|
||||
if (typeof time === "string") {
|
||||
time = parseFloat(time);
|
||||
}
|
||||
const countdown = Math.abs(Math.ceil(time));
|
||||
const minutes = Math.floor(countdown / 60);
|
||||
const seconds = countdown - minutes * 60;
|
||||
if (pad && seconds < 10) {
|
||||
return `${minutes}:0${seconds}`;
|
||||
}
|
||||
return `${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
match: Match | null;
|
||||
map: I.Map;
|
||||
phase: I.PhaseRaw,
|
||||
bomb: I.Bomb | null,
|
||||
}
|
||||
|
||||
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)`;
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
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>
|
||||
<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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
import * as I from "csgogsi-socket";
|
||||
import { Match } from "../../api/interfaces";
|
||||
|
||||
interface Props {
|
||||
map: I.Map;
|
||||
phase: I.PhaseRaw;
|
||||
match: Match | null;
|
||||
}
|
||||
|
||||
export default class SeriesBox extends React.Component<Props> {
|
||||
render() {
|
||||
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;
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
<div id="series_container">
|
||||
<div id="series_text">{ bo ? `BEST OF ${bo}` : '' }</div>
|
||||
</div>
|
||||
<div className="container right">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import { Team } from 'csgogsi-socket';
|
||||
import * as I from '../../api/interfaces';
|
||||
import { apiUrl } from './../../api/api';
|
||||
|
||||
export default class TeamLogo extends React.Component<{ team?: Team | I.Team | null, height?: number, width?: number}> {
|
||||
render(){
|
||||
const { team } = this.props;
|
||||
if(!team) return null;
|
||||
let id = '';
|
||||
const { logo } = team;
|
||||
if('_id' in team){
|
||||
id = team._id;
|
||||
} else if('id' in team && team.id){
|
||||
id = team.id;
|
||||
}
|
||||
return (
|
||||
<div className={`logo`}>
|
||||
{ logo && id ? <img src={`${apiUrl}api/teams/logo/${id}`} width={this.props.width} height={this.props.height} alt={'Team logo'} /> : ''}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import * as I from "csgogsi-socket";
|
||||
import WinIndicator from "./WinIndicator";
|
||||
import { Timer } from "./MatchBar";
|
||||
import TeamLogo from './TeamLogo';
|
||||
import PlantDefuse from "../Timers/PlantDefuse"
|
||||
|
||||
interface IProps {
|
||||
team: I.Team;
|
||||
orientation: "left" | "right";
|
||||
timer: Timer | null;
|
||||
showWin: boolean;
|
||||
}
|
||||
|
||||
export default class TeamScore extends React.Component<IProps> {
|
||||
render() {
|
||||
const { orientation, timer, team, showWin } = this.props;
|
||||
return (
|
||||
<>
|
||||
<div className={`team ${orientation} ${team.side}`}>
|
||||
<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}/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
@keyframes ShowWinCycle {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
5% {
|
||||
opacity: 1;
|
||||
height: 50px;
|
||||
}
|
||||
95% {
|
||||
opacity: 1;
|
||||
height: 50px;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
#matchbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: fixed;
|
||||
justify-content: center;
|
||||
width: 1148px;
|
||||
height: 70px;
|
||||
top: 10px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
#bomb_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
z-index: 0;
|
||||
.bomb_timer {
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 0;
|
||||
background-color: var(--color-bomb);
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.bomb_icon {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
svg {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: 6px;
|
||||
max-height: 80%;
|
||||
max-width: 80%;
|
||||
}
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
#round_timer_text {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 55px;
|
||||
justify-content: center;
|
||||
font-size: 34px;
|
||||
font-weight: bold;
|
||||
z-index: 1;
|
||||
color: var(--white-full);
|
||||
align-items: flex-end;
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#round_now {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 27px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
z-index: 1;
|
||||
color: var(--white-full);
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.team {
|
||||
width: 426px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.logo {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 105px;
|
||||
height: 70px;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--sub-panel-color);
|
||||
img {
|
||||
max-width: 90%;
|
||||
max-height: 65%;
|
||||
}
|
||||
}
|
||||
&.left {
|
||||
justify-content: center;
|
||||
flex-direction: row-reverse;
|
||||
.round-thingy {
|
||||
left: -30px;
|
||||
}
|
||||
.logo {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
&.right {
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
.round-thingy {
|
||||
right: -30px;
|
||||
}
|
||||
.logo {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
.team-name {
|
||||
display: flex;
|
||||
width: 360px;
|
||||
height: 70px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 30px;
|
||||
background-color: var(--sub-panel-color);
|
||||
}
|
||||
.round-thingy {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
.inner {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.score {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 77px;
|
||||
height: 70px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 36px;
|
||||
background-color: var(--sub-panel-color);
|
||||
}
|
||||
.bar {
|
||||
display: flex;
|
||||
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;
|
||||
flex-direction: row;
|
||||
position: fixed;
|
||||
justify-content: center;
|
||||
top: 80px;
|
||||
width: 1148px;
|
||||
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;
|
||||
width: 126px;
|
||||
height: 30px;
|
||||
}
|
||||
#series_text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: var(--white-full);
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 511px;
|
||||
height: 100%;
|
||||
}
|
||||
.container.left {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.container.right {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.series_wins {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 400px;
|
||||
height: 30px;
|
||||
z-index: 1;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
top: -30px;
|
||||
transition: top 0.5s;
|
||||
}
|
||||
.series_wins.show {
|
||||
top: 0px;
|
||||
}
|
||||
.wins_box_container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.series_wins.left {
|
||||
.wins_box_container {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
}
|
||||
.wins_box {
|
||||
width: 77px;
|
||||
height: 7px;
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
import Ability from "../Ability";
|
||||
import "./observed.scss";
|
||||
|
||||
|
||||
export default class Observed extends React.Component<{ player: any | null }> {
|
||||
|
||||
render() {
|
||||
const { player } = this.props;
|
||||
if (!player) return '';
|
||||
return (
|
||||
<div className={`observed`}>
|
||||
<div className="main_row">
|
||||
|
||||
<div className={`avatar`}>
|
||||
|
||||
<img src={`./heroes/${player.hero.name.replace('npc_dota_hero_','')}_full.png`} width={140}alt={'Avatar'} />
|
||||
|
||||
</div>
|
||||
<div className="username_container">
|
||||
<div className="username">[{player.hero.name.replace('npc_dota_hero_','').toUpperCase()}] {player.player.name}, level {player.hero.level}</div>
|
||||
</div>
|
||||
<div className="grenade_container">
|
||||
{/*grenades.map(grenade => <React.Fragment key={`${player.steamid}_${grenade.name}_${grenade.ammo_reserve || 1}`}>
|
||||
<Weapon weapon={grenade.name} active={grenade.state === "active"} isGrenade />
|
||||
{
|
||||
grenade.ammo_reserve === 2 ? <Weapon weapon={grenade.name} active={grenade.state === "active"} isGrenade /> : null}
|
||||
</React.Fragment>)*/}
|
||||
</div>
|
||||
</div>
|
||||
<div className="stats_row">
|
||||
<div className="statistics">
|
||||
{
|
||||
player.abilities.map((ability: any) => <Ability name={ability.name} level={ability.level} available={ability.level > 0} cooldown={ability.cooldown}/>)
|
||||
}
|
||||
</div>
|
||||
<div className="statistics">
|
||||
{
|
||||
player.items.slots.map((item: any) => item.name !== "empty" ? <img src={`./items/${item.name.replace('item_','')}_lg.png`} height={43}/> : null)
|
||||
}
|
||||
</div>
|
||||
<div className="bar-container">
|
||||
<div className="health-bar bar" style={{ width: player.hero.max_health ? `${player.hero.health*100/player.hero.max_health}%` : 0}}></div>{player.hero.health}/{player.hero.max_health}
|
||||
</div>
|
||||
<div className="bar-container">
|
||||
<div className="mana-bar bar" style={{ width: player.hero.max_health ? `${player.hero.health*100/player.hero.max_health}%` : 0}}></div>{player.hero.mana}/{player.hero.max_mana}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
.observed {
|
||||
position: fixed;
|
||||
width: 620px;
|
||||
bottom: 120px;
|
||||
margin-left: -310px;
|
||||
left: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: white;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
.bar-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
.bar {
|
||||
position: absolute;
|
||||
left:0;
|
||||
height:100%;
|
||||
z-index: -1;
|
||||
}
|
||||
.mana-bar {
|
||||
background-color: blue;
|
||||
}
|
||||
.health-bar {
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
.main_row, .stats_row {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
height: 43px;
|
||||
}
|
||||
|
||||
.stats_row {
|
||||
height: 28px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.stats_cell {
|
||||
height: 100%;
|
||||
width: 56px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.7);
|
||||
|
||||
.label {
|
||||
height: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: #b2b2b2;
|
||||
}
|
||||
|
||||
.stat {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.ammo {
|
||||
height: 100%;
|
||||
width: 140px;
|
||||
display: flex;
|
||||
.ammo_counter {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
> div {
|
||||
width: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.ammo_clip {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.ammo_reserve {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
.ammo_icon_container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 48px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
svg {
|
||||
max-width: 30px;
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
.health_armor_container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 140px;
|
||||
justify-content: center;
|
||||
.text {
|
||||
width: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 21px;
|
||||
height: 100%;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
width: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
svg {
|
||||
max-height:30px;
|
||||
max-width:22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.statistics {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.stat {
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main_row {
|
||||
font-weight: 600;
|
||||
.logo {
|
||||
height: 43px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.grenade_container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 140px;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
.username_container {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.real_name {
|
||||
font-size: 7pt;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
.weapon.grenade {
|
||||
height: 28px;
|
||||
/*filter: invert(1);*/
|
||||
|
||||
&:last-child {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.sidebar {
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
&:first-child {
|
||||
left: -10px;
|
||||
}
|
||||
&:last-child {
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
.flag {
|
||||
height: 43px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
img {
|
||||
height: 43px;
|
||||
}
|
||||
}
|
||||
.avatar {
|
||||
align-self: flex-end;
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
&.T {
|
||||
border-bottom: 6px solid var(--color-new-t);
|
||||
.main_row .username_container .username, .stats_row .ammo .ammo_counter .ammo_reserve {
|
||||
color: var(--color-new-t)
|
||||
}
|
||||
.sidebar {
|
||||
background-color: var(--color-new-t)
|
||||
}
|
||||
.stats_row .statistics .stat .label {
|
||||
color: var(--color-new-t);
|
||||
margin-right: 2px;
|
||||
}
|
||||
.stats_row .health_armor_container .icon, .stats_row .ammo .ammo_icon_container {
|
||||
svg {
|
||||
fill: var(--color-new-t);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.CT {
|
||||
border-bottom: 6px solid var(--color-new-ct);
|
||||
.main_row .username_container .username, .stats_row .ammo .ammo_counter .ammo_reserve {
|
||||
color: var(--color-new-ct)
|
||||
}
|
||||
.sidebar {
|
||||
background-color: var(--color-new-ct)
|
||||
}
|
||||
.stats_row .statistics .stat .label {
|
||||
color: var(--color-new-ct);
|
||||
margin-right: 2px;
|
||||
}
|
||||
.stats_row .health_armor_container .icon, .stats_row .ammo .ammo_icon_container {
|
||||
svg {
|
||||
fill: var(--color-new-ct);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#cameraFeed {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
transform: scale(0.94);
|
||||
left: 0px;
|
||||
bottom: 0;
|
||||
transform-origin: bottom left;
|
||||
iframe {
|
||||
position: relative;
|
||||
border: none;
|
||||
width: 750px;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
export const countries: any = {
|
||||
'AF' : 'Afghanistan',
|
||||
'AX' : 'Aland Islands',
|
||||
'AL' : 'Albania',
|
||||
'DZ' : 'Algeria',
|
||||
'AS' : 'American Samoa',
|
||||
'AD' : 'Andorra',
|
||||
'AO' : 'Angola',
|
||||
'AI' : 'Anguilla',
|
||||
'AQ' : 'Antarctica',
|
||||
'AG' : 'Antigua And Barbuda',
|
||||
'AR' : 'Argentina',
|
||||
'AM' : 'Armenia',
|
||||
'AW' : 'Aruba',
|
||||
'AU' : 'Australia',
|
||||
'AT' : 'Austria',
|
||||
'AZ' : 'Azerbaijan',
|
||||
'BS' : 'Bahamas',
|
||||
'BH' : 'Bahrain',
|
||||
'BD' : 'Bangladesh',
|
||||
'BB' : 'Barbados',
|
||||
'BY' : 'Belarus',
|
||||
'BE' : 'Belgium',
|
||||
'BZ' : 'Belize',
|
||||
'BJ' : 'Benin',
|
||||
'BM' : 'Bermuda',
|
||||
'BT' : 'Bhutan',
|
||||
'BO' : 'Bolivia',
|
||||
'BA' : 'Bosnia And Herzegovina',
|
||||
'BW' : 'Botswana',
|
||||
'BV' : 'Bouvet Island',
|
||||
'BR' : 'Brazil',
|
||||
'IO' : 'British Indian Ocean Territory',
|
||||
'BN' : 'Brunei',
|
||||
'BG' : 'Bulgaria',
|
||||
'BF' : 'Burkina Faso',
|
||||
'BI' : 'Burundi',
|
||||
'CIS': 'CIS',
|
||||
'KH' : 'Cambodia',
|
||||
'CM' : 'Cameroon',
|
||||
'CA' : 'Canada',
|
||||
'CV' : 'Cape Verde',
|
||||
'KY' : 'Cayman Islands',
|
||||
'CF' : 'Central African Republic',
|
||||
'TD' : 'Chad',
|
||||
'CL' : 'Chile',
|
||||
'CN' : 'China',
|
||||
'CX' : 'Christmas Island',
|
||||
'CC' : 'Cocos (Keeling) Islands',
|
||||
'CO' : 'Colombia',
|
||||
'KM' : 'Comoros',
|
||||
'CG' : 'Congo',
|
||||
'CD' : 'Congo, Democratic Republic',
|
||||
'CK' : 'Cook Islands',
|
||||
'CR' : 'Costa Rica',
|
||||
'CI' : 'Cote D\'Ivoire',
|
||||
'HR' : 'Croatia',
|
||||
'CU' : 'Cuba',
|
||||
'EU' : 'European Union',
|
||||
'CY' : 'Cyprus',
|
||||
'CZ' : 'Czech Republic',
|
||||
'DK' : 'Denmark',
|
||||
'DJ' : 'Djibouti',
|
||||
'DM' : 'Dominica',
|
||||
'DO' : 'Dominican Republic',
|
||||
'EC' : 'Ecuador',
|
||||
'EG' : 'Egypt',
|
||||
'SV' : 'El Salvador',
|
||||
'GQ' : 'Equatorial Guinea',
|
||||
'ER' : 'Eritrea',
|
||||
'EE' : 'Estonia',
|
||||
'ET' : 'Ethiopia',
|
||||
'FK' : 'Falkland Islands',
|
||||
'FO' : 'Faroes',
|
||||
'FJ' : 'Fiji',
|
||||
'FI' : 'Finland',
|
||||
'FR' : 'France',
|
||||
'GF' : 'French Guiana',
|
||||
'PF' : 'French Polynesia',
|
||||
'TF' : 'French Southern Territories',
|
||||
'GA' : 'Gabon',
|
||||
'GM' : 'Gambia',
|
||||
'GE' : 'Georgia',
|
||||
'DE' : 'Germany',
|
||||
'GH' : 'Ghana',
|
||||
'GI' : 'Gibraltar',
|
||||
'GR' : 'Greece',
|
||||
'GL' : 'Greenland',
|
||||
'GD' : 'Grenada',
|
||||
'GP' : 'Guadeloupe',
|
||||
'GU' : 'Guam',
|
||||
'GT' : 'Guatemala',
|
||||
'GG' : 'Guernsey',
|
||||
'GN' : 'Guinea',
|
||||
'GW' : 'Guinea-Bissau',
|
||||
'GY' : 'Guyana',
|
||||
'HT' : 'Haiti',
|
||||
'HM' : 'Heard Island & Mcdonald Islands',
|
||||
'VA' : 'Holy See (Vatican City State)',
|
||||
'HN' : 'Honduras',
|
||||
'HK' : 'Hong Kong',
|
||||
'HU' : 'Hungary',
|
||||
'IS' : 'Iceland',
|
||||
'IN' : 'India',
|
||||
'ID' : 'Indonesia',
|
||||
'IR' : 'Iran',
|
||||
'IQ' : 'Iraq',
|
||||
'IE' : 'Ireland',
|
||||
'IM' : 'Isle of Man',
|
||||
'IL' : 'Israel',
|
||||
'IT' : 'Italy',
|
||||
'JM' : 'Jamaica',
|
||||
'JP' : 'Japan',
|
||||
'JE' : 'Jersey',
|
||||
'JO' : 'Jordan',
|
||||
'KZ' : 'Kazakhstan',
|
||||
'KE' : 'Kenya',
|
||||
'KI' : 'Kiribati',
|
||||
'KR' : 'South Korea',
|
||||
'KP' : 'North Korea',
|
||||
'KW' : 'Kuwait',
|
||||
'KG' : 'Kyrgyzstan',
|
||||
'LA' : 'Laos',
|
||||
'LV' : 'Latvia',
|
||||
'LB' : 'Lebanon',
|
||||
'LS' : 'Lesotho',
|
||||
'LR' : 'Liberia',
|
||||
'LY' : 'Libya',
|
||||
'LI' : 'Liechtenstein',
|
||||
'LT' : 'Lithuania',
|
||||
'LU' : 'Luxembourg',
|
||||
'MO' : 'Macau',
|
||||
'MK' : 'Macedonia',
|
||||
'MG' : 'Madagascar',
|
||||
'MW' : 'Malawi',
|
||||
'MY' : 'Malaysia',
|
||||
'MV' : 'Maldives',
|
||||
'ML' : 'Mali',
|
||||
'MT' : 'Malta',
|
||||
'MH' : 'Marshall Islands',
|
||||
'MQ' : 'Martinique',
|
||||
'MR' : 'Mauritania',
|
||||
'MU' : 'Mauritius',
|
||||
'YT' : 'Mayotte',
|
||||
'MX' : 'Mexico',
|
||||
'FM' : 'Micronesia',
|
||||
'MD' : 'Moldova',
|
||||
'MC' : 'Monaco',
|
||||
'MN' : 'Mongolia',
|
||||
'ME' : 'Montenegro',
|
||||
'MS' : 'Montserrat',
|
||||
'MA' : 'Morocco',
|
||||
'MZ' : 'Mozambique',
|
||||
'MM' : 'Myanmar',
|
||||
'NA' : 'Namibia',
|
||||
'NR' : 'Nauru',
|
||||
'NP' : 'Nepal',
|
||||
'NL' : 'Netherlands',
|
||||
'AN' : 'Netherlands Antilles',
|
||||
'NC' : 'New Caledonia',
|
||||
'NZ' : 'New Zealand',
|
||||
'NI' : 'Nicaragua',
|
||||
'NE' : 'Niger',
|
||||
'NG' : 'Nigeria',
|
||||
'NU' : 'Niue',
|
||||
'NF' : 'Norfolk Island',
|
||||
'MP' : 'Northern Mariana Islands',
|
||||
'NO' : 'Norway',
|
||||
'OM' : 'Oman',
|
||||
'PK' : 'Pakistan',
|
||||
'PW' : 'Palau',
|
||||
'PS' : 'Palestine',
|
||||
'PA' : 'Panama',
|
||||
'PG' : 'Papua New Guinea',
|
||||
'PY' : 'Paraguay',
|
||||
'PE' : 'Peru',
|
||||
'PH' : 'Philippines',
|
||||
'PN' : 'Pitcairn Islands',
|
||||
'PL' : 'Poland',
|
||||
'PT' : 'Portugal',
|
||||
'PR' : 'Puerto Rico',
|
||||
'QA' : 'Qatar',
|
||||
'RE' : 'Reunion',
|
||||
'RO' : 'Romania',
|
||||
'RU' : 'Russia',
|
||||
'RW' : 'Rwanda',
|
||||
'BL' : 'Saint Barthelemy',
|
||||
'SH' : 'Saint Helena',
|
||||
'KN' : 'Saint Kitts and Nevis',
|
||||
'LC' : 'Saint Lucia',
|
||||
'MF' : 'Saint Martin',
|
||||
'PM' : 'Saint Pierre And Miquelon',
|
||||
'VC' : 'Saint Vincent and the Grenadines',
|
||||
'WS' : 'Samoa',
|
||||
'SM' : 'San Marino',
|
||||
'ST' : 'Sao Tome and Principe',
|
||||
'SA' : 'Saudi Arabia',
|
||||
'SN' : 'Senegal',
|
||||
'RS' : 'Serbia',
|
||||
'SC' : 'Seychelles',
|
||||
'SL' : 'Sierra Leone',
|
||||
'SG' : 'Singapore',
|
||||
'SK' : 'Slovakia',
|
||||
'SI' : 'Slovenia',
|
||||
'SB' : 'Solomon Islands',
|
||||
'SO' : 'Somalia',
|
||||
'ZA' : 'South Africa',
|
||||
'GS' : 'South Georgia and the South Sandwich Islands',
|
||||
'ES' : 'Spain',
|
||||
'LK' : 'Sri Lanka',
|
||||
'SD' : 'Sudan',
|
||||
'SR' : 'Suriname',
|
||||
'SS' : 'South Sudan',
|
||||
'SJ' : 'Svalbard And Jan Mayen',
|
||||
'SZ' : 'Swaziland',
|
||||
'SE' : 'Sweden',
|
||||
'CH' : 'Switzerland',
|
||||
'SY' : 'Syria',
|
||||
'TW' : 'Taiwan',
|
||||
'TJ' : 'Tajikistan',
|
||||
'TZ' : 'Tanzania',
|
||||
'TH' : 'Thailand',
|
||||
'TL' : 'Timor-Leste',
|
||||
'TG' : 'Togo',
|
||||
'TK' : 'Tokelau',
|
||||
'TO' : 'Tonga',
|
||||
'TT' : 'Trinidad and Tobago',
|
||||
'TN' : 'Tunisia',
|
||||
'TR' : 'Turkey',
|
||||
'TM' : 'Turkmenistan',
|
||||
'TC' : 'Turks and Caicos Islands',
|
||||
'TV' : 'Tuvalu',
|
||||
'UG' : 'Uganda',
|
||||
'UA' : 'Ukraine',
|
||||
'AE' : 'United Arab Emirates',
|
||||
'GB' : 'United Kingdom',
|
||||
'US' : 'United States',
|
||||
'UM' : 'United States Outlying Islands',
|
||||
'UY' : 'Uruguay',
|
||||
'UZ' : 'Uzbekistan',
|
||||
'VU' : 'Vanuatu',
|
||||
'VE' : 'Venezuela',
|
||||
'VN' : 'Vietnam',
|
||||
'VG' : 'Virgin Islands, British',
|
||||
'VI' : 'Virgin Islands, U.S.',
|
||||
'WF' : 'Wallis And Futuna',
|
||||
'EH' : 'Western Sahara',
|
||||
'YE' : 'Yemen',
|
||||
'ZM' : 'Zambia',
|
||||
'ZW' : 'Zimbabwe',
|
||||
'XK' : 'Kosovo'
|
||||
};
|
||||
|
||||
export const getCountry = (iso: string) => {
|
||||
return countries[iso.toUpperCase()];
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const regex = /^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*\s*(?:\[?(?:\s*<![^>]*>\s*)*\]?)*[^>]*>\s*)?(?:<svg[^>]*>[^]*<\/svg>|<svg[^/>]*\/\s*>)\s*$/i;
|
||||
|
||||
const isSvg = (img: Buffer) =>
|
||||
regex.test(
|
||||
img
|
||||
.toString()
|
||||
.replace(/\s*<!Entity\s+\S*\s*(?:"|')[^"]+(?:"|')\s*>/gim, '')
|
||||
.replace(/<!--([\s\S]*?)-->/g, '')
|
||||
);
|
||||
|
||||
export default isSvg;
|
||||
Reference in New Issue
Block a user