Compare commits

...

3 Commits

6 changed files with 213 additions and 101 deletions

View File

@@ -1,9 +1,15 @@
export function Float({ float }: { float: number }) { export function Float({ float }: { float: number }) {
return ( return (
<> <>
<div className="w-full flex justify-center"> <div className="w-full flex justify-center relative">
<div className="absolute mx-2 h-4 w-1 mt-1 rounded-xl bg-white" style={{left: `calc(${float}*100% - var(--spacing))`}}></div> <div
<div className="w-full h-2 flex my-2 px-2"> className="absolute mx-1 h-4 w-1 mt-1 rounded-xl bg-white"
style={{
left: `calc(${float}*100% - var(--spacing))`,
transform: "translateX(-50%)",
}}
></div>
<div className="w-full h-2 flex my-2">
<div className="w-7/100 h-full rounded-l-xl bg-green-800"></div> <div className="w-7/100 h-full rounded-l-xl bg-green-800"></div>
<div className="w-8/100 h-full bg-green-500"></div> <div className="w-8/100 h-full bg-green-500"></div>
<div className="w-23/100 h-full bg-lime-400"></div> <div className="w-23/100 h-full bg-lime-400"></div>

View File

@@ -1,25 +1,16 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Skeleton, Surface } from "@heroui/react"; import { Skeleton, Surface } from "@heroui/react";
import { Agent } from "./agent"; import { Agent } from "./agent";
import { Weapon } from "./weapon"; import { SkinTile } from "./skin_tile";
import { useNotification } from "~/hooks/notification"; import { useNotification } from "~/hooks/notification";
import { WeaponInfo, AgentInfo } from "~/types/skin";
interface SkinInfo {
id: string;
name: string;
color: string;
display: string;
paint_index: number;
float: number;
pattern: number;
}
export function Inventory({ side }: { side: "T" | "CT" }) { export function Inventory({ side }: { side: "T" | "CT" }) {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [agent, setAgent] = useState<SkinInfo>(); const [agent, setAgent] = useState<AgentInfo>();
const [gloves, setGloves] = useState<SkinInfo>(); const [gloves, setGloves] = useState<WeaponInfo>();
const [knife, setKnife] = useState<SkinInfo>(); const [knife, setKnife] = useState<WeaponInfo>();
const [weapons, setWeapons] = useState<Array<SkinInfo>>([]); const [weapons, setWeapons] = useState<Array<WeaponInfo>>([]);
const { notify } = useNotification(); const { notify } = useNotification();
useEffect(() => { useEffect(() => {
@@ -41,7 +32,7 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
); );
}); });
setKnife(response[0]); setKnife(new WeaponInfo(response[0]));
response = await fetch( response = await fetch(
`${import.meta.env.VITE_BASE_API_URL}/skin?team=${side}&category=Gloves`, `${import.meta.env.VITE_BASE_API_URL}/skin?team=${side}&category=Gloves`,
@@ -60,7 +51,7 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
); );
}); });
setGloves(response[0]); setGloves(new WeaponInfo(response[0]));
response = await fetch( response = await fetch(
`${import.meta.env.VITE_BASE_API_URL}/skin?team=${side}`, `${import.meta.env.VITE_BASE_API_URL}/skin?team=${side}`,
@@ -79,7 +70,7 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
); );
}); });
setWeapons(response); setWeapons(response.map((item: any) => (new WeaponInfo(item))));
response = await fetch( response = await fetch(
`${import.meta.env.VITE_BASE_API_URL}/agent?team=${side}`, `${import.meta.env.VITE_BASE_API_URL}/agent?team=${side}`,
@@ -98,7 +89,7 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
); );
}); });
setAgent(response); setAgent(new AgentInfo(response));
setLoading(false); setLoading(false);
}; };
@@ -149,31 +140,19 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
{agent && <Agent agent_id={agent["name"]}></Agent>} {agent && <Agent agent_id={agent["name"]}></Agent>}
<div className="flex gap-2"> <div className="flex gap-2">
{knife && ( {knife && (
<Weapon <SkinTile
weapon_id={knife["name"]} skin={knife}
color={knife["color"]} ></SkinTile>
paint_index={knife["paint_index"]}
display={knife["display"]}
float={knife["float"]}
pattern={knife["pattern"]}
></Weapon>
)} )}
{gloves && ( {gloves && (
<Weapon <SkinTile
weapon_id={gloves["name"]} skin={gloves}
color={gloves["color"]} ></SkinTile>
paint_index={gloves["paint_index"]}
display={gloves["display"]}
float={gloves["float"]}
pattern={gloves["pattern"]}
></Weapon>
)} )}
{agent && ( {agent && (
<Weapon <SkinTile
weapon_id={agent["name"]} skin={agent}
color={agent["color"]} ></SkinTile>
display={agent["display"]}
></Weapon>
)} )}
</div> </div>
</Surface> </Surface>
@@ -183,14 +162,9 @@ export function Inventory({ side }: { side: "T" | "CT" }) {
> >
<div className="absolute inset-4 flex-1 grid grid-cols-5 gap-2 overflow-y-scroll"> <div className="absolute inset-4 flex-1 grid grid-cols-5 gap-2 overflow-y-scroll">
{weapons.map((v, i) => ( {weapons.map((v, i) => (
<Weapon <SkinTile
key={i} key={i}
weapon_id={v.name} skin={v}
color={v.color}
paint_index={v.paint_index}
display={v.display}
float={v.float}
pattern={v.pattern}
/> />
))} ))}
</div> </div>

View File

@@ -0,0 +1,101 @@
import { Button, Modal, Surface, Typography } from "@heroui/react";
import type { Dispatch, SetStateAction } from "react";
import { AgentInfo, WeaponInfo } from "~/types/skin";
import { Float } from "./float";
export function SkinDialog({
isOpen,
setIsOpen,
skin,
}: {
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
skin: WeaponInfo | AgentInfo;
}) {
const acolor = `${skin.color}64`;
return (
<Modal isOpen={isOpen}>
<Modal.Backdrop
variant="blur"
shouldCloseOnInteractOutside={(_element) => {
setIsOpen(false);
return true;
}}
>
<Modal.Container size="lg">
<Modal.Dialog>
<Modal.CloseTrigger
onPress={() => {
setIsOpen(false);
}}
/>
<Modal.Body>
<div className="flex flex-col gap-2">
<Typography.Heading
level={4}
className="py-1 text-wrap"
>
{skin.display}
</Typography.Heading>
<Button className="bg-mist-700 flex flex-col h-full p-0 rounded-none gap-0 hover:bg-indigo-800 active:bg-indigo-900">
<div className="flex flex-col w-full h-full">
<div
className="bg-linear-to-b pointer-events-none w-full h-full relative"
style={{
background: `linear-gradient(to bottom, #1f2937, ${acolor})`,
}}
>
<img
src={`/skins/${skin.name}_${skin instanceof WeaponInfo ? skin.paint_index : 0}.png`}
className="pointer-events-none object-contain object-bottom h-full"
alt="Weapon image"
/>
<Surface className="rounded-full w-fit h-fit p-2 absolute bottom-2 right-2" variant="secondary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="size-6 m-0"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
/>
</svg>
</Surface>
</div>
<div
className={`h-1 w-full`}
style={{
background: `${skin.color}`,
}}
></div>
</div>
</Button>
{skin instanceof WeaponInfo && (
<>
<Typography.Paragraph>
Float: {skin.float}
</Typography.Paragraph>
<Float float={skin.float} />
</>
)}
{skin instanceof WeaponInfo && (
<Typography.Paragraph>
Pattern: {skin.pattern}
</Typography.Paragraph>
)}
<Typography.Code>
Transaction id: {skin.id}
</Typography.Code>
</div>
</Modal.Body>
</Modal.Dialog>
</Modal.Container>
</Modal.Backdrop>
</Modal>
);
}

View File

@@ -0,0 +1,58 @@
import { Button, Typography } from "@heroui/react";
import { Float } from "./float";
import { useState } from "react";
import { SkinDialog } from "./skin_dialog";
import { WeaponInfo, AgentInfo } from "~/types/skin";
export function SkinTile({ skin }: { skin: WeaponInfo | AgentInfo }) {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const acolor = `${skin.color}64`;
return (
<>
<SkinDialog
isOpen={isDialogOpen}
setIsOpen={setIsDialogOpen}
skin={skin}
/>
<Button
onClick={() => setIsDialogOpen(true)}
className="bg-mist-700 flex flex-col h-full p-0 rounded-none gap-0 hover:bg-indigo-800 active:bg-indigo-900"
>
<div className="flex flex-col w-full h-full">
<div
className="bg-linear-to-b pointer-events-none w-full h-full"
style={{
background: `linear-gradient(to bottom, #1f2937, ${acolor})`,
}}
>
<img
src={`/skins/${skin.name}_${skin instanceof WeaponInfo ? skin.paint_index : 0}.png`}
className="pointer-events-none object-contain object-bottom h-full"
alt="Weapon image"
/>
</div>
<div
className={`h-1 w-full`}
style={{ background: `${skin.color}` }}
></div>
<div className="px-2">
<Typography.Heading
level={6}
className="py-1 text-wrap"
>
{skin.display}
</Typography.Heading>
{skin instanceof WeaponInfo && (
<Float float={skin.float} />
)}
{skin instanceof WeaponInfo && (
<Typography.Paragraph>
Pattern: {skin.pattern}
</Typography.Paragraph>
)}
</div>
</div>
</Button>
</>
);
}

View File

@@ -1,51 +0,0 @@
import { Button, Surface, Typography } from "@heroui/react";
import { Float } from "./float";
export function Weapon({
weapon_id,
color,
display = "Weapon",
float,
pattern,
paint_index = 0,
}: {
weapon_id: string;
color: string;
display?: string;
float?: number;
pattern?: number;
paint_index?: number;
}) {
const acolor = `${color}64`;
return (
<Button className="bg-mist-700 flex flex-col h-full p-0 rounded-none gap-0 hover:bg-indigo-800 active:bg-indigo-900">
<div className="flex flex-col w-full h-full">
<div
className="bg-linear-to-b pointer-events-none w-full h-full"
style={{
background: `linear-gradient(to bottom, #1f2937, ${acolor})`,
}}
>
<img
src={`/skins/${weapon_id}_${paint_index || 0}.png`}
className="pointer-events-none object-contain object-bottom h-full"
alt="Weapon image"
/>
</div>
<div
className={`h-1 w-full`}
style={{ background: `${color}` }}
></div>
<Typography.Heading level={6} className="px-2 py-1 text-wrap">
{display}
</Typography.Heading>
{float !== undefined && <Float float={float} />}
{pattern !== undefined && (
<Typography.Paragraph className="px-2">
Pattern: {pattern}
</Typography.Paragraph>
)}
</div>
</Button>
);
}

24
app/types/skin.ts Normal file
View File

@@ -0,0 +1,24 @@
export class WeaponInfo {
id!: string;
name!: string;
color!: string;
display!: string;
paint_index!: number;
float!: number;
pattern!: number;
constructor(data: WeaponInfo) {
Object.assign(this, data);
}
}
export class AgentInfo {
id!: string;
name!: string;
color!: string;
display!: string;
constructor(data: AgentInfo) {
Object.assign(this, data);
}
}