Favorite weapons in user weapon pool Closes #1346
@@ -3,6 +3,7 @@ import type { MainWeaponId, ModeShort, StageId } from "~/modules/in-game-lists";
|
||||
import {
|
||||
mainWeaponImageUrl,
|
||||
modeImageUrl,
|
||||
outlinedFiveStarMainWeaponImageUrl,
|
||||
outlinedMainWeaponImageUrl,
|
||||
stageImageUrl,
|
||||
} from "~/utils/urls";
|
||||
@@ -59,7 +60,7 @@ export function Image({
|
||||
|
||||
type WeaponImageProps = {
|
||||
weaponSplId: MainWeaponId;
|
||||
variant: "badge" | "build";
|
||||
variant: "badge" | "badge-5-star" | "build";
|
||||
} & Omit<ImageProps, "path" | "alt" | "title">;
|
||||
|
||||
export function WeaponImage({
|
||||
@@ -79,6 +80,8 @@ export function WeaponImage({
|
||||
path={
|
||||
variant === "badge"
|
||||
? outlinedMainWeaponImageUrl(weaponSplId)
|
||||
: variant == "badge-5-star"
|
||||
? outlinedFiveStarMainWeaponImageUrl(weaponSplId)
|
||||
: mainWeaponImageUrl(weaponSplId)
|
||||
}
|
||||
/>
|
||||
|
||||
18
app/components/icons/Star.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
export function StarIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
16
app/components/icons/StarFilled.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
export function StarFilledIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.007 5.404.433c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.433 2.082-5.006z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
insert into
|
||||
"UserWeapon" ("userId", "weaponSplId", "order")
|
||||
"UserWeapon" ("userId", "weaponSplId", "order", "isFavorite")
|
||||
values
|
||||
(@userId, @weaponSplId, @order);
|
||||
(@userId, @weaponSplId, @order, @isFavorite);
|
||||
|
||||
@@ -5,7 +5,14 @@ select
|
||||
"Team"."id" as "teamId",
|
||||
"UserSubmittedImage"."url" as "teamAvatarUrl",
|
||||
"PlusTier"."tier" as "plusTier",
|
||||
json_group_array("UserWeapon"."weaponSplId") as "weapons"
|
||||
json_group_array(
|
||||
json_object(
|
||||
'weaponSplId',
|
||||
"UserWeapon"."weaponSplId",
|
||||
'isFavorite',
|
||||
"UserWeapon"."isFavorite"
|
||||
)
|
||||
) as "weapons"
|
||||
from
|
||||
"User"
|
||||
left join "PlusTier" on "PlusTier"."userId" = "User"."id"
|
||||
|
||||
@@ -3,9 +3,9 @@ import type {
|
||||
CalendarEventResultTeam,
|
||||
SplatoonPlayer,
|
||||
User,
|
||||
UserWeapon,
|
||||
UserWithPlusTier,
|
||||
} from "../../types";
|
||||
import type { MainWeaponId } from "~/modules/in-game-lists";
|
||||
import { parseDBArray } from "~/utils/sql";
|
||||
import { dateToDatabaseTimestamp } from "~/utils/dates";
|
||||
|
||||
@@ -68,10 +68,15 @@ export const updateProfile = sql.transaction(
|
||||
| "css"
|
||||
| "favoriteBadgeId"
|
||||
| "showDiscordUniqueName"
|
||||
> & { weapons: MainWeaponId[] }) => {
|
||||
> & { weapons: Pick<UserWeapon, "weaponSplId" | "isFavorite">[] }) => {
|
||||
deleteUserWeaponsStm.run({ userId: rest.id });
|
||||
for (const [i, weaponSplId] of weapons.entries()) {
|
||||
addUserWeaponStm.run({ userId: rest.id, weaponSplId, order: i + 1 });
|
||||
for (const [i, weapon] of weapons.entries()) {
|
||||
addUserWeaponStm.run({
|
||||
userId: rest.id,
|
||||
weaponSplId: weapon.weaponSplId,
|
||||
isFavorite: weapon.isFavorite,
|
||||
order: i + 1,
|
||||
});
|
||||
}
|
||||
|
||||
return updateProfileStm.get(rest) as User;
|
||||
@@ -151,7 +156,7 @@ export function findByIdentifier(identifier: string | number) {
|
||||
} as
|
||||
| (Omit<UserWithPlusTier, "css"> & {
|
||||
css: Record<string, string>;
|
||||
weapons: MainWeaponId[];
|
||||
weapons: Pick<UserWeapon, "weaponSplId" | "isFavorite">[];
|
||||
team?: {
|
||||
name: string;
|
||||
customUrl: string;
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface UserWeapon {
|
||||
weaponSplId: MainWeaponId;
|
||||
createdAt: number;
|
||||
order: number;
|
||||
isFavorite: number;
|
||||
}
|
||||
|
||||
export interface PlusSuggestion {
|
||||
|
||||
@@ -22,12 +22,13 @@ import { Label } from "~/components/Label";
|
||||
import { SubmitButton } from "~/components/SubmitButton";
|
||||
import { USER } from "~/constants";
|
||||
import { db } from "~/db";
|
||||
import type { UserWeapon } from "~/db/types";
|
||||
import { type User } from "~/db/types";
|
||||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { requireUser, requireUserId } from "~/modules/auth/user.server";
|
||||
import { i18next } from "~/modules/i18n";
|
||||
import { mainWeaponIds, type MainWeaponId } from "~/modules/in-game-lists";
|
||||
import { type MainWeaponId } from "~/modules/in-game-lists";
|
||||
import { canAddCustomizedColorsToUserProfile } from "~/permissions";
|
||||
import styles from "~/styles/u-edit.css";
|
||||
import { translatedCountry } from "~/utils/i18n.server";
|
||||
@@ -43,12 +44,14 @@ import {
|
||||
id,
|
||||
jsonParseable,
|
||||
processMany,
|
||||
removeDuplicates,
|
||||
weaponSplId,
|
||||
safeJSONParse,
|
||||
undefinedToNull,
|
||||
} from "~/utils/zod";
|
||||
import { userParamsSchema, type UserPageLoaderData } from "../u.$identifier";
|
||||
import { Toggle } from "~/components/Toggle";
|
||||
import { StarIcon } from "~/components/icons/Star";
|
||||
import { StarFilledIcon } from "~/components/icons/StarFilled";
|
||||
|
||||
export const links: LinksFunction = () => {
|
||||
return [{ rel: "stylesheet", href: styles }];
|
||||
@@ -114,14 +117,13 @@ const userEditActionSchema = z
|
||||
),
|
||||
css: z.preprocess(falsyToNull, z.string().refine(jsonParseable).nullable()),
|
||||
weapons: z.preprocess(
|
||||
processMany(safeJSONParse, removeDuplicates),
|
||||
safeJSONParse,
|
||||
z
|
||||
.array(
|
||||
z
|
||||
.number()
|
||||
.refine((val) =>
|
||||
mainWeaponIds.includes(val as (typeof mainWeaponIds)[number])
|
||||
)
|
||||
z.object({
|
||||
weaponSplId,
|
||||
isFavorite: dbBoolean,
|
||||
})
|
||||
)
|
||||
.max(USER.WEAPON_POOL_MAX_SIZE)
|
||||
),
|
||||
@@ -163,7 +165,9 @@ export const action: ActionFunction = async ({ request }) => {
|
||||
try {
|
||||
const editedUser = db.users.updateProfile({
|
||||
...data,
|
||||
weapons: data.weapons as MainWeaponId[],
|
||||
weapons: data.weapons as Array<
|
||||
Pick<UserWeapon, "weaponSplId" | "isFavorite">
|
||||
>,
|
||||
inGameName:
|
||||
inGameNameText && inGameNameDiscriminator
|
||||
? `${inGameNameText}#${inGameNameDiscriminator}`
|
||||
@@ -389,11 +393,11 @@ function WeaponPoolSelect({
|
||||
}: {
|
||||
parentRouteData: UserPageLoaderData;
|
||||
}) {
|
||||
const [weapons, setWeapons] = React.useState<Array<MainWeaponId>>(
|
||||
parentRouteData.weapons
|
||||
);
|
||||
const [weapons, setWeapons] = React.useState(parentRouteData.weapons);
|
||||
const { t } = useTranslation(["user"]);
|
||||
|
||||
const latestWeapon = weapons[weapons.length - 1];
|
||||
|
||||
return (
|
||||
<div className="stack md u-edit__weapon-pool">
|
||||
<input type="hidden" name="weapons" value={JSON.stringify(weapons)} />
|
||||
@@ -405,11 +409,17 @@ function WeaponPoolSelect({
|
||||
id="weapon"
|
||||
onChange={(weapon) => {
|
||||
if (!weapon) return;
|
||||
setWeapons([...weapons, Number(weapon.value) as MainWeaponId]);
|
||||
setWeapons([
|
||||
...weapons,
|
||||
{
|
||||
weaponSplId: Number(weapon.value) as MainWeaponId,
|
||||
isFavorite: 0,
|
||||
},
|
||||
]);
|
||||
}}
|
||||
// empty on selection
|
||||
key={weapons[weapons.length - 1]}
|
||||
weaponIdsToOmit={new Set(weapons)}
|
||||
key={latestWeapon?.weaponSplId ?? "empty"}
|
||||
weaponIdsToOmit={new Set(weapons.map((w) => w.weaponSplId))}
|
||||
fullWidth
|
||||
/>
|
||||
) : (
|
||||
@@ -421,22 +431,48 @@ function WeaponPoolSelect({
|
||||
<div className="stack horizontal sm justify-center">
|
||||
{weapons.map((weapon) => {
|
||||
return (
|
||||
<div key={weapon} className="stack xs">
|
||||
<div key={weapon.weaponSplId} className="stack xs">
|
||||
<div className="u__weapon">
|
||||
<WeaponImage
|
||||
weaponSplId={weapon}
|
||||
variant="badge"
|
||||
weaponSplId={weapon.weaponSplId}
|
||||
variant={weapon.isFavorite ? "badge-5-star" : "badge"}
|
||||
width={38}
|
||||
height={38}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
icon={<TrashIcon />}
|
||||
variant="minimal-destructive"
|
||||
aria-label="Delete weapon"
|
||||
onClick={() => setWeapons(weapons.filter((w) => w !== weapon))}
|
||||
testId={`delete-weapon-${weapon}`}
|
||||
/>
|
||||
<div className="stack sm horizontal items-center justify-center">
|
||||
<Button
|
||||
icon={weapon.isFavorite ? <StarFilledIcon /> : <StarIcon />}
|
||||
variant="minimal"
|
||||
aria-label="Favorite weapon"
|
||||
onClick={() =>
|
||||
setWeapons(
|
||||
weapons.map((w) =>
|
||||
w.weaponSplId === weapon.weaponSplId
|
||||
? {
|
||||
...weapon,
|
||||
isFavorite: weapon.isFavorite === 1 ? 0 : 1,
|
||||
}
|
||||
: w
|
||||
)
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
icon={<TrashIcon />}
|
||||
variant="minimal-destructive"
|
||||
aria-label="Delete weapon"
|
||||
onClick={() =>
|
||||
setWeapons(
|
||||
weapons.filter(
|
||||
(w) => w.weaponSplId !== weapon.weaponSplId
|
||||
)
|
||||
)
|
||||
}
|
||||
testId={`delete-weapon-${weapon.weaponSplId}`}
|
||||
size="tiny"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -216,11 +216,11 @@ function WeaponPool() {
|
||||
<div className="stack horizontal sm justify-center">
|
||||
{data.weapons.map((weapon, i) => {
|
||||
return (
|
||||
<div key={weapon} className="u__weapon">
|
||||
<div key={weapon.weaponSplId} className="u__weapon">
|
||||
<WeaponImage
|
||||
testId={`${weapon}-${i + 1}`}
|
||||
weaponSplId={weapon}
|
||||
variant="badge"
|
||||
testId={`${weapon.weaponSplId}-${i + 1}`}
|
||||
weaponSplId={weapon.weaponSplId}
|
||||
variant={weapon.isFavorite ? "badge-5-star" : "badge"}
|
||||
width={38}
|
||||
height={38}
|
||||
/>
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.u__extra-info__heading > svg {
|
||||
width: 0.8rem;
|
||||
}
|
||||
|
||||
.u__social-link > svg {
|
||||
width: 0.9rem;
|
||||
}
|
||||
@@ -110,10 +114,6 @@
|
||||
font-weight: var(--bold);
|
||||
}
|
||||
|
||||
.u__extra-info__heading > svg {
|
||||
width: 0.8rem;
|
||||
}
|
||||
|
||||
.u__badges {
|
||||
display: flex;
|
||||
max-width: 24rem;
|
||||
|
||||
@@ -265,6 +265,9 @@ export const mainWeaponImageUrl = (mainWeaponSplId: MainWeaponId) =>
|
||||
`/static-assets/img/main-weapons/${mainWeaponSplId}`;
|
||||
export const outlinedMainWeaponImageUrl = (mainWeaponSplId: MainWeaponId) =>
|
||||
`/static-assets/img/main-weapons-outlined/${mainWeaponSplId}`;
|
||||
export const outlinedFiveStarMainWeaponImageUrl = (
|
||||
mainWeaponSplId: MainWeaponId
|
||||
) => `/static-assets/img/main-weapons-outlined-2/${mainWeaponSplId}`;
|
||||
export const subWeaponImageUrl = (subWeaponSplId: SubWeaponId) =>
|
||||
`/static-assets/img/sub-weapons/${subWeaponSplId}`;
|
||||
export const specialWeaponImageUrl = (specialWeaponSplId: SpecialWeaponId) =>
|
||||
|
||||
@@ -3,4 +3,7 @@ module.exports.up = function (db) {
|
||||
db.prepare(
|
||||
/* sql */ `alter table "User" add "showDiscordUniqueName" integer not null default 1`
|
||||
).run();
|
||||
db.prepare(
|
||||
/* sql */ `alter table "UserWeapon" add "isFavorite" integer not null default 0`
|
||||
).run();
|
||||
};
|
||||
|
||||
BIN
public/static-assets/img/main-weapons-outlined-2/0.avif
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/0.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1.avif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/10.avif
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/10.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/100.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/100.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1000.avif
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1000.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1001.avif
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1001.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1010.avif
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1010.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1011.avif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1011.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1020.avif
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1020.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1030.avif
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1030.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1040.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1040.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/11.avif
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/11.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1100.avif
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1100.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1101.avif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1101.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1110.avif
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/1110.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/20.avif
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/20.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/200.avif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/200.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2000.avif
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2000.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/201.avif
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/201.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2010.avif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2010.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2011.avif
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2011.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2020.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2020.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2021.avif
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2021.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2030.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2030.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2040.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2040.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2050.avif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2050.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2060.avif
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2060.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2070.avif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/2070.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/21.avif
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/21.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/210.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/210.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/220.avif
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/220.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/230.avif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/230.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/231.avif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/231.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/240.avif
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/240.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/241.avif
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/241.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/250.avif
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/250.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/30.avif
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/30.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/300.avif
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/300.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3000.avif
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3000.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3001.avif
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3001.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/301.avif
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/301.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3010.avif
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3010.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3011.avif
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3011.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3020.avif
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/static-assets/img/main-weapons-outlined-2/3020.png
Normal file
|
After Width: | Height: | Size: 12 KiB |