mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-14 23:26:15 -05:00
Subbed out
This commit is contained in:
@@ -2,11 +2,7 @@
|
||||
& [class*="tabPanel"] {
|
||||
background-color: var(--color-bg-high);
|
||||
border-radius: 0 0 var(--radius-box) var(--radius-box);
|
||||
padding: var(--s-4);
|
||||
|
||||
&:has([class*="chatContainer"]) {
|
||||
padding: var(--s-1) var(--s-4);
|
||||
}
|
||||
padding: var(--s-6) var(--s-4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +50,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
.subbedOutTrigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-1-5);
|
||||
}
|
||||
|
||||
.subbedOutIcon {
|
||||
--subbed-out-icon-size: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--subbed-out-icon-size);
|
||||
height: var(--subbed-out-icon-size);
|
||||
border-radius: 100%;
|
||||
background-color: var(--color-bg-higher);
|
||||
}
|
||||
|
||||
.subbedOutPopover {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-2);
|
||||
}
|
||||
|
||||
.subbedOutHeader {
|
||||
font-size: var(--font-xs);
|
||||
font-weight: var(--weight-semi);
|
||||
color: var(--color-text-high);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.teamOneDot {
|
||||
border-radius: 100%;
|
||||
background-color: var(--color-accent);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { DoorOpen, Tally5, Users } from "lucide-react";
|
||||
import { Armchair, DoorOpen, Tally5, Users } from "lucide-react";
|
||||
import { QRCodeSVG } from "qrcode.react";
|
||||
import type * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useSearchParams } from "react-router";
|
||||
import { Alert } from "~/components/Alert";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
import { SendouButton } from "~/components/elements/Button";
|
||||
import { SendouPopover } from "~/components/elements/Popover";
|
||||
import invariant from "~/utils/invariant";
|
||||
import type { CommonUser } from "~/utils/kysely.server";
|
||||
import { userPage } from "~/utils/urls";
|
||||
@@ -80,6 +82,8 @@ interface RosterTabTeam {
|
||||
avatar?: string;
|
||||
};
|
||||
members: Array<CommonUser>;
|
||||
/** Sub user ids i.e. those who are not the current active roster */
|
||||
subbedOut?: Array<number>;
|
||||
}
|
||||
|
||||
interface MatchRosterTabProps {
|
||||
@@ -107,6 +111,14 @@ function TeamRoster({
|
||||
const dotClassName = side === "alpha" ? styles.teamOneDot : styles.teamTwoDot;
|
||||
const label = side === "alpha" ? "Alpha" : "Bravo";
|
||||
|
||||
const subbedOutSet = new Set(team.subbedOut);
|
||||
const activeMembers = team.members.filter(
|
||||
(member) => !subbedOutSet.has(member.id),
|
||||
);
|
||||
const subbedOutMembers = team.members.filter((member) =>
|
||||
subbedOutSet.has(member.id),
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="stack xxs">
|
||||
{team.team ? (
|
||||
@@ -127,7 +139,7 @@ function TeamRoster({
|
||||
) : null}
|
||||
{team.members.length > 0 ? (
|
||||
<ul className={styles.rosterMembers}>
|
||||
{team.members.map((member) => (
|
||||
{activeMembers.map((member) => (
|
||||
<li key={member.id}>
|
||||
<Link
|
||||
to={userPage(member)}
|
||||
@@ -138,12 +150,50 @@ function TeamRoster({
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
{subbedOutMembers.length > 0 ? (
|
||||
<li>
|
||||
<SubbedOutPopover members={subbedOutMembers} />
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SubbedOutPopover({ members }: { members: Array<CommonUser> }) {
|
||||
const { t } = useTranslation(["q"]);
|
||||
|
||||
return (
|
||||
<SendouPopover
|
||||
trigger={
|
||||
<SendouButton variant="minimal" size="small">
|
||||
<div className={styles.subbedOutTrigger}>
|
||||
<div className={styles.subbedOutIcon}>
|
||||
<Armchair size={16} />
|
||||
</div>
|
||||
+{members.length}
|
||||
</div>
|
||||
</SendouButton>
|
||||
}
|
||||
>
|
||||
<div className={styles.subbedOutPopover}>
|
||||
<div className={styles.subbedOutHeader}>{t("q:match.subbedOut")}</div>
|
||||
{members.map((member) => (
|
||||
<Link
|
||||
key={member.id}
|
||||
to={userPage(member)}
|
||||
className="stack horizontal sm items-center"
|
||||
>
|
||||
<Avatar user={member} size="xxs" />
|
||||
<span>{member.username}</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</SendouPopover>
|
||||
);
|
||||
}
|
||||
|
||||
export function MatchActionTab() {
|
||||
return <SendouTabPanel id={TAB_KEYS.ACTION}>Report content</SendouTabPanel>;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,15 @@ export default function MatchPageTestRoute() {
|
||||
discordAvatar: null,
|
||||
customUrl: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
username: "Poppy",
|
||||
discordId: "567",
|
||||
discordAvatar: null,
|
||||
customUrl: null,
|
||||
},
|
||||
],
|
||||
subbedOut: [9],
|
||||
},
|
||||
{
|
||||
team: { name: "Question Mark", url: "/t/question-mark" },
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "loss",
|
||||
"match.screen.ban": "Weapons with {{special}} are not allowed in this match",
|
||||
"match.screen.allowed": "Weapons with {{special}} are allowed in this match",
|
||||
"match.subbedOut": "Subbed out",
|
||||
"preparing.joinQ": "Join the queue",
|
||||
"tiers.currentCriteria": "Current criteria",
|
||||
"tiers.info.p1": "For example, Leviathan is the top 5% of players. Diamond is the 85th percentile etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "perdida",
|
||||
"match.screen.ban": "Armas con {{special}} son prohibidas para este partido",
|
||||
"match.screen.allowed": "Armas con {{special}} se permiten para este partido",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Unirte a la fila",
|
||||
"tiers.currentCriteria": "Criterios actuales",
|
||||
"tiers.info.p1": "Por ejemplo, Leviathan se encuentra entre el 5% de los mejores jugadores. Diamond es el percentil 85, etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "perdida",
|
||||
"match.screen.ban": "Armas con {{special}} son prohibidas para este partido",
|
||||
"match.screen.allowed": "Armas con {{special}} se permiten para este partido",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Unirte a la fila",
|
||||
"tiers.currentCriteria": "Criterios actuales",
|
||||
"tiers.info.p1": "Por ejemplo, Leviathan se encuentra entre el 5% de los mejores jugadores. Diamond es el percentil 85, etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "Perdu",
|
||||
"match.screen.ban": "Les armes avec {{special}} ne sont pas autoriser pendant ce match",
|
||||
"match.screen.allowed": "Les armes avec {{special}} sont autoriser pendant ce match",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Rejoindre la queue",
|
||||
"tiers.currentCriteria": "Critères actuels",
|
||||
"tiers.info.p1": "Par exemple, Les Léviathans font partie des 5 % des meilleurs joueurs. Le diamant est le top 15%, etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "sconfitta",
|
||||
"match.screen.ban": "Armi con {{special}} non sono permesse in questo match",
|
||||
"match.screen.allowed": "Armi con {{special}} non sono permesse in questo match",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Unisciti alla coda",
|
||||
"tiers.currentCriteria": "Criterio corrente",
|
||||
"tiers.info.p1": "Per esempio Leviathan è la top 5% dei giocatori. Diamante è l' 85esimo percentile etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "負け",
|
||||
"match.screen.ban": "{{special}}が付いてる武器はこのマッチでは禁止です",
|
||||
"match.screen.allowed": "{{special}}が付いてる武器は使用可能です",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "列に入る",
|
||||
"tiers.currentCriteria": "現在の基準",
|
||||
"tiers.info.p1": "例として、Leviathanはプレイヤーの上位5%、Diamondは上位15%",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "",
|
||||
"match.screen.ban": "",
|
||||
"match.screen.allowed": "",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "",
|
||||
"tiers.currentCriteria": "",
|
||||
"tiers.info.p1": "",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "derrota",
|
||||
"match.screen.ban": "Armas com o/a {{special}} não são permitidas nessa partida",
|
||||
"match.screen.allowed": "Armas com o/a {{special}} são permitidas nessa partida",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Entrar na fila",
|
||||
"tiers.currentCriteria": "Critérios atuais",
|
||||
"tiers.info.p1": "Por exemplo, Leviathan é o top 5% dos jogadores. Diamond é top 15% e etc.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "проигрыш",
|
||||
"match.screen.ban": "Оружия с {{special}} запрещены в этом матче",
|
||||
"match.screen.allowed": "Оружия с {{special}} разрешены в этом матче",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "Присоединиться к очереди",
|
||||
"tiers.currentCriteria": "Текущие критерии",
|
||||
"tiers.info.p1": "Например, Leviathan - топ 5% игроков, Diamond - 85 процентиль и т.д.",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"match.outcome.loss": "负",
|
||||
"match.screen.ban": "本次对战禁止使用特殊武器为 {{special}} 的武器",
|
||||
"match.screen.allowed": "本次对战允许使用特殊武器为 {{special}} 的武器",
|
||||
"match.subbedOut": "",
|
||||
"preparing.joinQ": "开始匹配",
|
||||
"tiers.currentCriteria": "当前规则",
|
||||
"tiers.info.p1": "比如说,Leviathan是前5%的玩家,Diamond是前15%的玩家。",
|
||||
|
||||
Reference in New Issue
Block a user