mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-22 23:21:52 -05:00
* Mode Map Pool picker component initial
* Component in settings
* Lottery initial
* Fix tests
* useTrusters as perf optimization
* unionAll -> union
* Fancy picker for tournaments
* Map pools memento
* FC's initial
* Friend code when registering for tournament
* FC in flows
* SHow FC in places
* Add catch in case
* Fix disabling
* Show ELO changed
* Wiggle MapPool button if already selected
* CSS vars typing
* Rechallenging
* Team (all) leaderboard
* Preview groups
* Fix chat width changing
* Solid reported weapons
* Clearer cancel requested header
* Dynamic revalidates
* spDiff from memento
* (Partly) Revert "Remove screen banning"
This reverts commit 076cabfbfa.
* Screen indicators in looking view
* FC i18n
* noscreen = 0
* E2E test
* E2E 2
90 lines
2.1 KiB
TypeScript
90 lines
2.1 KiB
TypeScript
import clsx from "clsx";
|
|
import React from "react";
|
|
import type { AbilityWithUnknown } from "~/modules/in-game-lists/types";
|
|
import { abilityImageUrl } from "~/utils/urls";
|
|
import { Image } from "./Image";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
const sizeMap = {
|
|
MAIN: 42,
|
|
SUB: 32,
|
|
SUBTINY: 26,
|
|
TINY: 22,
|
|
} as const;
|
|
|
|
export function Ability({
|
|
ability,
|
|
size,
|
|
dragStarted = false,
|
|
dropAllowed = false,
|
|
onClick,
|
|
onDrop,
|
|
className,
|
|
}: {
|
|
ability: AbilityWithUnknown;
|
|
size: keyof typeof sizeMap;
|
|
dragStarted?: boolean;
|
|
dropAllowed?: boolean;
|
|
onClick?: () => void;
|
|
onDrop?: (event: React.DragEvent) => void;
|
|
className?: string;
|
|
}) {
|
|
const { t } = useTranslation(["game-misc", "builds"]);
|
|
const sizeNumber = sizeMap[size];
|
|
|
|
const [isDragTarget, setIsDragTarget] = React.useState(false);
|
|
|
|
const onDragOver = (event: React.DragEvent) => {
|
|
event.preventDefault();
|
|
setIsDragTarget(true);
|
|
};
|
|
|
|
const onDragLeave = () => {
|
|
setIsDragTarget(false);
|
|
};
|
|
|
|
const readonly = typeof onClick === "undefined" || ability === "UNKNOWN"; // Force "UNKNOWN" ability icons to be readonly
|
|
|
|
// Render an ability as a button only if it is meant to be draggable (i.e., not readonly)
|
|
const AbilityTag = readonly ? "div" : "button";
|
|
|
|
const altText =
|
|
ability !== "UNKNOWN"
|
|
? t(`game-misc:ABILITY_${ability}`)
|
|
: t("builds:emptyAbilitySlot");
|
|
|
|
return (
|
|
<AbilityTag
|
|
className={clsx(
|
|
"build__ability",
|
|
{
|
|
"is-drag-target": isDragTarget,
|
|
"drag-started": dragStarted,
|
|
"drop-allowed": dropAllowed,
|
|
readonly,
|
|
},
|
|
className,
|
|
)}
|
|
style={{
|
|
"--ability-size": `${sizeNumber}px`,
|
|
}}
|
|
onClick={onClick}
|
|
data-testid={`${ability}-ability`}
|
|
onDragOver={onDragOver}
|
|
onDragLeave={onDragLeave}
|
|
onDrop={(event) => {
|
|
setIsDragTarget(false);
|
|
onDrop?.(event);
|
|
}}
|
|
type={readonly ? undefined : "button"}
|
|
>
|
|
<Image
|
|
alt={altText}
|
|
title={altText}
|
|
path={abilityImageUrl(ability)}
|
|
size={sizeNumber}
|
|
/>
|
|
</AbilityTag>
|
|
);
|
|
}
|