mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-15 23:41:53 -05:00
* Tables * Clocks * Maplist preference selector * Fix SSR * Nav icon * RankedOrScrim * Map pool * Create group * Redirect logic * Persist map pool * Advance from preparing page * Rename query * Fix merge * Fix migration order * Seed groups * Find looking groups SQL * Renders something * More UI work * Back to 30min * Likes/dislikes * Always return own group * Fix like order * 3 tc/rm/cb -> 2 * Show only 3 weapons * Pass group size * Handle both liked and liked by same group * Fix SQL * Group preference frontend work * Morphing * Styling * Don't show group controls if not manager * Give/remove manager * Leave group * Leave with confirm * Delete likes when morphing groups * Clocks consistency * Remove bad invariant * Persist settings to local storage * Fix initial value flashing * Fix never resolving loading indicator * REFRESH_GROUP * Flip animations * Tweaks * Auto refresh logic * Groups of 4 seed * Reduce throwing * Load full groups initial * Create match * Match UI initial * Score reporter initial * Push footer down on match page * Score reporter knows when set ended * Score reporting untested * Show score after report * Align better * Look again with same group functionality * More migrations * Team on match page * Show confirmer before reporting score * Report weapons * Report weapos again by admin + skill changing * Handle no tiebreaker given to MapPool * Remove unranked * Remove support for "team id skill" * no-wrap -> nowrap * Preparing page work * Use common GroupCard component * Add some metas * MemberAdder in looking page * Fix GroupCard actions * Fix SZ only map list including other modes * Add season info * Prompt login * Joining team * Manage group on preparing page * Manage group on preparing page * Seed past matches * Add to seed * No map list preference when full group + fix expiry * Fix skill matchesCount calculation * Tiers initial work * Some progress on tiers * Tiering logic * MMR in group cards * Name to challenge * Team MMR * Big team rank icons * Adjust todos * Match score report with confirm * Allow regular members to report score * Handle reporting weapons edge cases * Add tier images * Improve GroupCard spacing * Refactor looking page * Looking mobile UI * Calculate skill only for current season * Divide groups visually when reporting weapons * Fix match page weapons sorting * Add cache to user skills+tier calculation * Admin report match score * Initial leaderboard * Cached leaderboard * Weapon category lb's * Populate SkillTeamUser in SendouQ * Team leaderboard filtered down * Add TODOs * Seasons initlal * Season weapons initial * Weapons stylized * Show rest weapons as + * Hide peak if same as current * Load matches SQL initial * Season matches UI initial * Take user id in account * Add weapons * Paginated matches * Fix pages count logic * Scroll top on data change * Day headers for matches * Link from user page to user seasons page * Summarize maps + ui initial * Map stats * Player info tabs * MMR chart * Chart adjustments * Handle basing team MMR on player MMR * Set initial MMR * Add info about discord to match page * Season support to tournaments * Get tournament skills as well for the graph * WIP * New team rating logic + misc other * tiered -> tiered.server * Update season starting time * TODOs * Add rules page * Hide elements correctly when off-season * Fix crash when only one player with skill * How-to video * Fix StartRank showing when not logged in * Make user leaderboard the default * Make Skill season non-nullable * Add suggested pass to match * Add rule * identifierToUserIds helper * Fix tiers not showing
163 lines
3.6 KiB
TypeScript
163 lines
3.6 KiB
TypeScript
import type { TierName } from "~/features/mmr/mmr-constants";
|
|
import { useTranslation } from "~/hooks/useTranslation";
|
|
import type { MainWeaponId, ModeShort, StageId } from "~/modules/in-game-lists";
|
|
import {
|
|
TIER_PLUS_URL,
|
|
mainWeaponImageUrl,
|
|
modeImageUrl,
|
|
outlinedFiveStarMainWeaponImageUrl,
|
|
outlinedMainWeaponImageUrl,
|
|
stageImageUrl,
|
|
tierImageUrl,
|
|
} from "~/utils/urls";
|
|
|
|
interface ImageProps {
|
|
path: string;
|
|
alt: string;
|
|
title?: string;
|
|
className?: string;
|
|
containerClassName?: string;
|
|
width?: number;
|
|
height?: number;
|
|
size?: number;
|
|
style?: React.CSSProperties;
|
|
testId?: string;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
export function Image({
|
|
path,
|
|
alt,
|
|
title,
|
|
className,
|
|
width,
|
|
height,
|
|
size,
|
|
style,
|
|
testId,
|
|
containerClassName,
|
|
onClick,
|
|
}: ImageProps) {
|
|
return (
|
|
<picture title={title} className={containerClassName} onClick={onClick}>
|
|
<source
|
|
type="image/avif"
|
|
srcSet={`${path}.avif`}
|
|
width={width}
|
|
height={height}
|
|
style={style}
|
|
/>
|
|
<img
|
|
alt={alt}
|
|
src={`${path}.png`}
|
|
className={className}
|
|
width={size ?? width}
|
|
height={size ?? height}
|
|
style={style}
|
|
draggable="false"
|
|
data-testid={testId}
|
|
/>
|
|
</picture>
|
|
);
|
|
}
|
|
|
|
type WeaponImageProps = {
|
|
weaponSplId: MainWeaponId;
|
|
variant: "badge" | "badge-5-star" | "build";
|
|
} & Omit<ImageProps, "path" | "alt">;
|
|
|
|
export function WeaponImage({
|
|
weaponSplId,
|
|
variant,
|
|
testId,
|
|
title,
|
|
...rest
|
|
}: WeaponImageProps) {
|
|
const { t } = useTranslation(["weapons"]);
|
|
|
|
return (
|
|
<Image
|
|
{...rest}
|
|
alt={title ?? t(`weapons:MAIN_${weaponSplId}`)}
|
|
title={title ?? t(`weapons:MAIN_${weaponSplId}`)}
|
|
testId={testId}
|
|
path={
|
|
variant === "badge"
|
|
? outlinedMainWeaponImageUrl(weaponSplId)
|
|
: variant == "badge-5-star"
|
|
? outlinedFiveStarMainWeaponImageUrl(weaponSplId)
|
|
: mainWeaponImageUrl(weaponSplId)
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
|
|
type ModeImageProps = {
|
|
mode: ModeShort;
|
|
} & Omit<ImageProps, "path" | "alt">;
|
|
|
|
export function ModeImage({ mode, testId, title, ...rest }: ModeImageProps) {
|
|
const { t } = useTranslation(["game-misc"]);
|
|
|
|
return (
|
|
<Image
|
|
{...rest}
|
|
alt={title ?? t(`game-misc:MODE_LONG_${mode}`)}
|
|
title={title ?? t(`game-misc:MODE_LONG_${mode}`)}
|
|
testId={testId}
|
|
path={modeImageUrl(mode)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
type StageImageProps = {
|
|
stageId: StageId;
|
|
} & Omit<ImageProps, "path" | "alt" | "title">;
|
|
|
|
export function StageImage({ stageId, testId, ...rest }: StageImageProps) {
|
|
const { t } = useTranslation(["game-misc"]);
|
|
|
|
return (
|
|
<Image
|
|
{...rest}
|
|
alt={t(`game-misc:STAGE_${stageId}`)}
|
|
title={t(`game-misc:STAGE_${stageId}`)}
|
|
testId={testId}
|
|
path={stageImageUrl(stageId)}
|
|
height={rest.height ?? (rest.width ? rest.width * 0.5625 : undefined)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
type TierImageProps = {
|
|
tier: { name: TierName; isPlus: boolean };
|
|
} & Omit<ImageProps, "path" | "alt" | "title" | "size" | "height">;
|
|
|
|
export function TierImage({ tier, width = 200 }: TierImageProps) {
|
|
const title = `${tier.name}${tier.isPlus ? "+" : ""}`;
|
|
|
|
const height = width * 0.8675;
|
|
|
|
return (
|
|
<div className="tier__container">
|
|
<Image
|
|
path={tierImageUrl(tier.name)}
|
|
width={width}
|
|
height={height}
|
|
alt={title}
|
|
title={title}
|
|
containerClassName="tier__img"
|
|
/>
|
|
{tier.isPlus ? (
|
|
<Image
|
|
path={TIER_PLUS_URL}
|
|
width={width}
|
|
height={height}
|
|
alt=""
|
|
containerClassName="tier__img"
|
|
/>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|