mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
highlight player dot/spec on hover
This commit is contained in:
parent
04ae714282
commit
3644dbda6e
7 changed files with 355 additions and 298 deletions
|
|
@ -51,6 +51,7 @@ export const Analyser = (props: AnalyseProps) => {
|
||||||
const closeDialogs = () => {
|
const closeDialogs = () => {
|
||||||
setModalState(ModalState.Closed);
|
setModalState(ModalState.Closed);
|
||||||
};
|
};
|
||||||
|
const [highlighted, setHighlighted] = createSignal<number>(0);
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const e = event();
|
const e = event();
|
||||||
|
|
@ -243,7 +244,10 @@ export const Analyser = (props: AnalyseProps) => {
|
||||||
projectiles={projectiles()}
|
projectiles={projectiles()}
|
||||||
header={props.header}
|
header={props.header}
|
||||||
world={backgroundBoundaries}
|
world={backgroundBoundaries}
|
||||||
scale={scale()}/>
|
scale={scale()}
|
||||||
|
onHover={setHighlighted}
|
||||||
|
highlighted={highlighted()}
|
||||||
|
/>
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
<AnalyseMenu sessionName={sessionName()}
|
<AnalyseMenu sessionName={sessionName()}
|
||||||
onShare={() => {
|
onShare={() => {
|
||||||
|
|
@ -261,7 +265,9 @@ export const Analyser = (props: AnalyseProps) => {
|
||||||
inShared={inShared}
|
inShared={inShared}
|
||||||
/>
|
/>
|
||||||
<SpecHUD parser={parser} tick={tick()}
|
<SpecHUD parser={parser} tick={tick()}
|
||||||
players={players()} events={events}/>
|
players={players()} events={events}
|
||||||
|
highlighted={highlighted()}
|
||||||
|
onHover={setHighlighted}/>
|
||||||
</div>
|
</div>
|
||||||
<div class="time-control"
|
<div class="time-control"
|
||||||
title={timeTitle()}>
|
title={timeTitle()}>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ export interface MapRenderProps {
|
||||||
},
|
},
|
||||||
world: WorldBoundaries;
|
world: WorldBoundaries;
|
||||||
scale: number;
|
scale: number;
|
||||||
|
onHover: (userId: number) => void;
|
||||||
|
highlighted: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const map_root = document.querySelector('[data-maps]').getAttribute('data-maps');
|
const map_root = document.querySelector('[data-maps]').getAttribute('data-maps');
|
||||||
|
|
@ -30,7 +32,10 @@ export function MapRender(props: MapRenderProps) {
|
||||||
style={{"background-image": background}}>
|
style={{"background-image": background}}>
|
||||||
<For each={props.players}>{(player) =>
|
<For each={props.players}>{(player) =>
|
||||||
<Show when={player.health}>
|
<Show when={player.health}>
|
||||||
<PlayerDot player={player} mapBoundary={props.world} targetSize={props.size} scale={props.scale}/>
|
<PlayerDot player={player} mapBoundary={props.world} targetSize={props.size} scale={props.scale}
|
||||||
|
onHover={props.onHover}
|
||||||
|
highlighted={props.highlighted === player.info.userId}
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
}</For>
|
}</For>
|
||||||
<For each={props.buildings}>{(building) =>
|
<For each={props.buildings}>{(building) =>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ export function KillFeedDestroyedItem(props: KillFeedDestroyedItemProps) {
|
||||||
return <li class="kill">
|
return <li class="kill">
|
||||||
<PlayerNames players={[attacker, assister]}/>
|
<PlayerNames players={[attacker, assister]}/>
|
||||||
<KillIcon kill={props.event}/>
|
<KillIcon kill={props.event}/>
|
||||||
<PlayerName player={victim}/><span className={teamMap[victim.team]}>({props.event.building_type})</span>
|
<PlayerName player={victim}/><span class={teamMap[victim.team]}>({props.event.building_type})</span>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ interface PlayerNameProps {
|
||||||
|
|
||||||
export function PlayerName(props: PlayerNameProps) {
|
export function PlayerName(props: PlayerNameProps) {
|
||||||
return <Show when={props.player}>
|
return <Show when={props.player}>
|
||||||
<span className={"player " + teamMap[props.player.team]}>
|
<span class={"player " + teamMap[props.player.team]}>
|
||||||
{props.player.info.name}
|
{props.player.info.name}
|
||||||
</span>
|
</span>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -111,7 +111,7 @@ interface PlayerNamesProps {
|
||||||
export function PlayerNames(props: PlayerNamesProps) {
|
export function PlayerNames(props: PlayerNamesProps) {
|
||||||
return <For each={props.players}>{(player, i) => <>
|
return <For each={props.players}>{(player, i) => <>
|
||||||
<Show when={i() > 0 && player}>
|
<Show when={i() > 0 && player}>
|
||||||
<span className={teamMap[player.team]}>+</span>
|
<span class={teamMap[player.team]}>+</span>
|
||||||
</Show>
|
</Show>
|
||||||
<PlayerName player={player}/>
|
<PlayerName player={player}/>
|
||||||
</>}</For>
|
</>}</For>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ export interface PlayerProp {
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
scale: number;
|
scale: number;
|
||||||
|
onHover: (userId: number) => void;
|
||||||
|
highlighted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const healthMap = {
|
const healthMap = {
|
||||||
|
|
@ -51,12 +53,15 @@ export function Player(props: PlayerProp) {
|
||||||
const rotate = () => `rotate(${270 - props.player.angle})`;
|
const rotate = () => `rotate(${270 - props.player.angle})`;
|
||||||
|
|
||||||
return <g
|
return <g
|
||||||
|
onmouseover={() => props.onHover(props.player.info.userId)}
|
||||||
|
onmouseout={() => props.onHover(0)}
|
||||||
transform={transform()}>
|
transform={transform()}>
|
||||||
<polygon points="-6,14 0, 16 6,14 0,24" fill="white"
|
<polygon points="-6,14 0, 16 6,14 0,24" fill="white"
|
||||||
opacity={imageOpacity()}
|
opacity={imageOpacity()}
|
||||||
transform={rotate()}/>
|
transform={rotate()}/>
|
||||||
<circle r={16} stroke-width={1.5} stroke="white" fill={teamColor()}
|
<circle r={16} stroke-width={props.highlighted ? 5 : 1.5} stroke="white" fill={teamColor()}
|
||||||
opacity={alpha()}/>
|
opacity={alpha()}
|
||||||
|
/>
|
||||||
{getClassImage(props.player, imageOpacity())}
|
{getClassImage(props.player, imageOpacity())}
|
||||||
</g>
|
</g>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,146 +2,162 @@ import {PlayerState} from "../Data/Parser";
|
||||||
import {KillFeedItem} from "./KillFeed";
|
import {KillFeedItem} from "./KillFeed";
|
||||||
|
|
||||||
export interface PlayerSpecProps {
|
export interface PlayerSpecProps {
|
||||||
player: PlayerState;
|
player: PlayerState;
|
||||||
|
onHover: (userId: number) => void;
|
||||||
|
highlighted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const healthMap = {
|
const healthMap = {
|
||||||
0: 100, //fallback
|
0: 100, //fallback
|
||||||
1: 125, //scout
|
1: 125, //scout
|
||||||
2: 150, //sniper
|
2: 150, //sniper
|
||||||
3: 200, //soldier,
|
3: 200, //soldier,
|
||||||
4: 175, //demoman,
|
4: 175, //demoman,
|
||||||
5: 150, //medic,
|
5: 150, //medic,
|
||||||
6: 300, //heavy,
|
6: 300, //heavy,
|
||||||
7: 175, //pyro
|
7: 175, //pyro
|
||||||
8: 125, //spy
|
8: 125, //spy
|
||||||
9: 125, //engineer
|
9: 125, //engineer
|
||||||
};
|
};
|
||||||
|
|
||||||
const classMap = {
|
const classMap = {
|
||||||
1: "scout",
|
1: "scout",
|
||||||
2: "sniper",
|
2: "sniper",
|
||||||
3: "soldier",
|
3: "soldier",
|
||||||
4: "demoman",
|
4: "demoman",
|
||||||
5: "medic",
|
5: "medic",
|
||||||
6: "heavy",
|
6: "heavy",
|
||||||
7: "pyro",
|
7: "pyro",
|
||||||
8: "spy",
|
8: "spy",
|
||||||
9: "engineer"
|
9: "engineer"
|
||||||
};
|
};
|
||||||
|
|
||||||
const classSort = {
|
const classSort = {
|
||||||
1: 1, //scout
|
1: 1, //scout
|
||||||
3: 2, //soldier
|
3: 2, //soldier
|
||||||
7: 3, //pyro
|
7: 3, //pyro
|
||||||
4: 4, //demoman
|
4: 4, //demoman
|
||||||
6: 5, //heavy
|
6: 5, //heavy
|
||||||
9: 6, //engineer
|
9: 6, //engineer
|
||||||
5: 7, //medic
|
5: 7, //medic
|
||||||
2: 8, //sniper
|
2: 8, //sniper
|
||||||
8: 9, //spy
|
8: 9, //spy
|
||||||
};
|
};
|
||||||
|
|
||||||
const teamMap = {
|
const teamMap = {
|
||||||
0: "other",
|
0: "other",
|
||||||
1: "spectator",
|
1: "spectator",
|
||||||
2: "red",
|
2: "red",
|
||||||
3: "blue",
|
3: "blue",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayersSpecProps {
|
export interface PlayersSpecProps {
|
||||||
players: PlayerState[];
|
players: PlayerState[];
|
||||||
|
onHover: (userId: number) => void;
|
||||||
|
highlighted: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortPlayer(a, b) {
|
function sortPlayer(a, b) {
|
||||||
return classSort[a.playerClass] - classSort[b.playerClass];
|
return classSort[a.playerClass] - classSort[b.playerClass];
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterPlayers(players: PlayerState[], team: number): PlayerState[] {
|
function filterPlayers(players: PlayerState[], team: number): PlayerState[] {
|
||||||
const filtered = players.filter((player) => player.team === team);
|
const filtered = players.filter((player) => player.team === team);
|
||||||
filtered.sort(sortPlayer);
|
filtered.sort(sortPlayer);
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
function medics(players: PlayerState[]): PlayerState[] {
|
function medics(players: PlayerState[]): PlayerState[] {
|
||||||
return players.filter(player => player.playerClass === 5);
|
return players.filter(player => player.playerClass === 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PlayersSpec(props: PlayersSpecProps) {
|
export function PlayersSpec(props: PlayersSpecProps) {
|
||||||
const redPlayers = () => filterPlayers(props.players, 2);
|
const redPlayers = () => filterPlayers(props.players, 2);
|
||||||
const bluePlayers = () => filterPlayers(props.players, 3);
|
const bluePlayers = () => filterPlayers(props.players, 3);
|
||||||
const redMedics = () => medics(redPlayers());
|
const redMedics = () => medics(redPlayers());
|
||||||
const blueMedics = () => medics(bluePlayers());
|
const blueMedics = () => medics(bluePlayers());
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
<div class="redSpecHolder">
|
<div class="redSpecHolder">
|
||||||
<For each={redPlayers()}>{(player) =>
|
<For each={redPlayers()}>{(player: PlayerState) =>
|
||||||
<PlayerSpec player={player}/>
|
<PlayerSpec player={player} highlighted={player.info.userId == props.highlighted}
|
||||||
}</For>
|
onHover={props.onHover}/>
|
||||||
<For each={redMedics()}>{(player) =>
|
}</For>
|
||||||
<UberSpec
|
<For each={redMedics()}>{(player) =>
|
||||||
team={teamMap[player.team]}
|
<UberSpec
|
||||||
chargeLevel={player.charge}
|
team={teamMap[player.team]}
|
||||||
isDeath={player.health < 1}
|
chargeLevel={player.charge}
|
||||||
/>
|
isDeath={player.health < 1}
|
||||||
}</For>
|
/>
|
||||||
</div>
|
}</For>
|
||||||
<div class="blueSpecHolder">
|
</div>
|
||||||
<For each={bluePlayers()}>{(player) =>
|
<div class="blueSpecHolder">
|
||||||
<PlayerSpec player={player}/>
|
<For each={bluePlayers()}>{(player) =>
|
||||||
}</For>
|
<PlayerSpec player={player} highlighted={player.info.userId == props.highlighted}
|
||||||
<For each={blueMedics()}>{(player) =>
|
onHover={props.onHover}/>
|
||||||
<UberSpec
|
}</For>
|
||||||
team={teamMap[player.team]}
|
<For each={blueMedics()}>{(player) =>
|
||||||
chargeLevel={player.charge}
|
<UberSpec
|
||||||
isDeath={player.health < 1}
|
team={teamMap[player.team]}
|
||||||
/>
|
chargeLevel={player.charge}
|
||||||
}</For>
|
isDeath={player.health < 1}
|
||||||
</div>
|
/>
|
||||||
</div>);
|
}</For>
|
||||||
|
</div>
|
||||||
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PlayerSpec({player}: PlayerSpecProps) {
|
export function PlayerSpec(props: PlayerSpecProps) {
|
||||||
const healthPercent = Math.min(100, player.health / healthMap[player.playerClass] * 100);
|
const healthPercent = () => Math.min(100, props.player.health / healthMap[props.player.playerClass] * 100);
|
||||||
const healthStatusClass = (player.health > healthMap[player.playerClass]) ? 'overhealed' : (player.health <= 0 ? 'dead' : '');
|
const healthStatusClass = () => (props.player.health > healthMap[props.player.playerClass]) ? 'overhealed' : (props.player.health <= 0 ? 'dead' : '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={"playerspec " + teamMap[player.team] + " webp " + healthStatusClass}>
|
onmouseover={() => props.onHover(props.player.info.userId)}
|
||||||
{getPlayerIcon(player)}
|
onmouseout={() => props.onHover(0)}
|
||||||
<div class="health-container">
|
classList={{
|
||||||
<div class="healthbar"
|
"playerspec": true,
|
||||||
style={{width: healthPercent + '%'}}/>
|
[teamMap[props.player.team]]: true,
|
||||||
<span class="player-name">{player.info.name}</span>
|
"webp": true,
|
||||||
<span class="health">{player.health}</span>
|
[healthStatusClass()]: true,
|
||||||
</div>
|
highlighted: props.highlighted,
|
||||||
</div>
|
}}>
|
||||||
);
|
{getPlayerIcon(props.player)}
|
||||||
|
<div class="health-container">
|
||||||
|
<div class="healthbar"
|
||||||
|
style={{width: healthPercent() + '%'}}/>
|
||||||
|
<span class="player-name">{props.player.info.name}</span>
|
||||||
|
<span class="health">{props.player.health}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlayerIcon(player: PlayerState) {
|
function getPlayerIcon(player: PlayerState) {
|
||||||
if (classMap[player.playerClass]) {
|
if (classMap[player.playerClass]) {
|
||||||
return <div class={classMap[player.playerClass] + " class-icon"}/>
|
return <div class={classMap[player.playerClass] + " class-icon"}/>
|
||||||
} else {
|
} else {
|
||||||
return <div class={"class-icon"}/>
|
return <div class={"class-icon"}/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UberSpecProps {
|
export interface UberSpecProps {
|
||||||
chargeLevel: number;
|
chargeLevel: number;
|
||||||
team: string;
|
team: string;
|
||||||
isDeath: boolean;
|
isDeath: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UberSpec({chargeLevel, team, isDeath}: UberSpecProps) {
|
export function UberSpec({chargeLevel, team, isDeath}: UberSpecProps) {
|
||||||
const healthStatusClass = (isDeath) ? 'dead' : '';
|
const healthStatusClass = (isDeath) ? 'dead' : '';
|
||||||
return (
|
return (
|
||||||
<div class={`playerspec uber ${team} ${healthStatusClass}`}>
|
<div class={`playerspec uber ${team} ${healthStatusClass}`}>
|
||||||
<div class={"uber class-icon"}/>
|
<div class={"uber class-icon"}/>
|
||||||
<div class="health-container">
|
<div class="health-container">
|
||||||
<div class="healthbar"
|
<div class="healthbar"
|
||||||
style={{width: chargeLevel + '%'}}/>
|
style={{width: chargeLevel + '%'}}/>
|
||||||
<span class="player-name">Charge</span>
|
<span class="player-name">Charge</span>
|
||||||
<span class="health">{Math.round(chargeLevel)}</span>
|
<span class="health">{Math.round(chargeLevel)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,15 @@ export interface SpecHUDProps {
|
||||||
tick: number;
|
tick: number;
|
||||||
parser: AsyncParser;
|
parser: AsyncParser;
|
||||||
players: PlayerState[];
|
players: PlayerState[];
|
||||||
events: Event[]
|
events: Event[];
|
||||||
|
onHover: (userId: number) => void;
|
||||||
|
highlighted: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SpecHUD(props: SpecHUDProps) {
|
export function SpecHUD(props: SpecHUDProps) {
|
||||||
return (<div class="spechud">
|
return (<div class="spechud">
|
||||||
<KillFeed tick={props.tick} events={props.events} players={props.players}/>
|
<KillFeed tick={props.tick} events={props.events} players={props.players}/>
|
||||||
<PlayersSpec players={props.players}/>
|
<PlayersSpec players={props.players} onHover={props.onHover} highlighted={props.highlighted}/>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,218 +1,241 @@
|
||||||
.blueSpecHolder {
|
.blueSpecHolder {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.redSpecHolder {
|
.redSpecHolder {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.playerspec {
|
.playerspec {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
color: white;
|
color: white;
|
||||||
height: 42px;
|
|
||||||
width: 200px;
|
|
||||||
position: relative;
|
|
||||||
font-family: sans-serif;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&.uber {
|
|
||||||
height: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .class-icon, .steam-avatar {
|
|
||||||
width: 42px;
|
|
||||||
height: 42px;
|
height: 42px;
|
||||||
display: inline-block;
|
width: 200px;
|
||||||
position: absolute;
|
position: relative;
|
||||||
top: 0;
|
font-family: sans-serif;
|
||||||
left: 0;
|
margin-bottom: 2px;
|
||||||
background-position: top left;
|
user-select: none;
|
||||||
background-size: 100% 100%;
|
|
||||||
|
|
||||||
&.uber {
|
&.uber {
|
||||||
height: 28px;
|
height: 28px;
|
||||||
background-size: 28px 28px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 50% 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .player-name {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
padding: 0 5px;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 120px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .health-container {
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
left: 42px;
|
|
||||||
top: 0;
|
|
||||||
height: 28px;
|
|
||||||
width: calc(100% - 42px);
|
|
||||||
line-height: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
& .health {
|
|
||||||
position: relative;
|
|
||||||
float: right;
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& .healthbar {
|
& .class-icon, .steam-avatar {
|
||||||
position: absolute;
|
width: 42px;
|
||||||
top: 0;
|
height: 42px;
|
||||||
left: 0;
|
display: inline-block;
|
||||||
height: 28px;
|
position: absolute;
|
||||||
}
|
top: 0;
|
||||||
}
|
left: 0;
|
||||||
|
background-position: top left;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
|
||||||
&.red {
|
&.uber {
|
||||||
& .health-container {
|
height: 28px;
|
||||||
background-color: #a75d50aa;
|
background-size: 28px 28px;
|
||||||
}
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
& .healthbar {
|
}
|
||||||
background-color: #a75d50;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .class-icon.scout {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_scout.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.soldier {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_soldier.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.pyro {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_pyro.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.demoman {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_demoman.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.engineer {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_engineer.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.heavy {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_heavy.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.medic {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_medic.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.sniper {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_sniper.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.spy{
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_spy.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.uber {
|
|
||||||
background-image: url('inline://images/charge_red.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
& .class-icon, & .steam-avatar {
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .health-container {
|
|
||||||
right: 42px;
|
|
||||||
left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .health {
|
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& .player-name {
|
& .player-name {
|
||||||
float: right;
|
display: inline-block;
|
||||||
direction: ltr;
|
position: relative;
|
||||||
text-align: right;
|
padding: 0 5px;
|
||||||
}
|
white-space: nowrap;
|
||||||
}
|
width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
&.blue {
|
text-overflow: ellipsis;
|
||||||
& .health-container {
|
|
||||||
background-color: #5b818faa;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .healthbar {
|
|
||||||
background-color: #5b818f;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .class-icon.scout {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_scout_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.soldier {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_soldier_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.pyro {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_pyro_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.demoman {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_demoman_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.engineer {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_engineer_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.heavy {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_heavy_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.medic {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_medic_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.sniper {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_sniper_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.spy {
|
|
||||||
background-image: url('inline://images/class_portraits/Icon_spy_blue.webp');
|
|
||||||
}
|
|
||||||
& .class-icon.uber {
|
|
||||||
background-image: url('inline://images/charge_blue.svg');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.overhealed {
|
|
||||||
& .health {
|
|
||||||
color: #79d297;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .health:after {
|
|
||||||
position: absolute;
|
|
||||||
top: 21px;
|
|
||||||
right: 0;
|
|
||||||
padding: 0 5px;
|
|
||||||
font-size: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
content: 'OVERHEALED'
|
|
||||||
}
|
|
||||||
|
|
||||||
&.red .health:after {
|
|
||||||
position: absolute;
|
|
||||||
top: 21px;
|
|
||||||
left: 0;
|
|
||||||
right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.dead {
|
|
||||||
& .healthbar, & .health {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& .health-container {
|
& .health-container {
|
||||||
background-color: transparent;
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
left: 42px;
|
||||||
|
top: 0;
|
||||||
|
height: 28px;
|
||||||
|
width: calc(100% - 42px);
|
||||||
|
line-height: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
& .health {
|
||||||
|
position: relative;
|
||||||
|
float: right;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .healthbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& .class-icon {
|
&.red {
|
||||||
opacity: 0.5;
|
& .health-container {
|
||||||
|
background-color: #a75d50aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .healthbar {
|
||||||
|
background-color: #a75d50;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.scout {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_scout.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.soldier {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_soldier.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.pyro {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_pyro.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.demoman {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_demoman.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.engineer {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_engineer.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.heavy {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_heavy.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.medic {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_medic.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.sniper {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_sniper.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.spy {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_spy.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.uber {
|
||||||
|
background-image: url('inline://images/charge_red.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon, & .steam-avatar {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .health-container {
|
||||||
|
right: 42px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .health {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .player-name {
|
||||||
|
float: right;
|
||||||
|
direction: ltr;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.blue {
|
||||||
|
& .health-container {
|
||||||
|
background-color: #5b818faa;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .healthbar {
|
||||||
|
background-color: #5b818f;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.scout {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_scout_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.soldier {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_soldier_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.pyro {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_pyro_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.demoman {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_demoman_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.engineer {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_engineer_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.heavy {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_heavy_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.medic {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_medic_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.sniper {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_sniper_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.spy {
|
||||||
|
background-image: url('inline://images/class_portraits/Icon_spy_blue.webp');
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon.uber {
|
||||||
|
background-image: url('inline://images/charge_blue.svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.highlighted:not(.dead) {
|
||||||
|
outline: white 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.overhealed {
|
||||||
|
& .health {
|
||||||
|
color: #79d297;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .health:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 21px;
|
||||||
|
right: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
content: 'OVERHEALED'
|
||||||
|
}
|
||||||
|
|
||||||
|
&.red .health:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 21px;
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dead {
|
||||||
|
& .healthbar, & .health {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .health-container {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .class-icon {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue