mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-07 19:55:46 -05:00
filters look good
This commit is contained in:
130
components/builds/BuildFilters.tsx
Normal file
130
components/builds/BuildFilters.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Box, Button, Flex, Select } from "@chakra-ui/core";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { Ability } from "@prisma/client";
|
||||
import AbilityIcon from "components/common/AbilityIcon";
|
||||
import { abilities, isMainAbility } from "lib/lists/abilities";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
const abilityPointOptions = [
|
||||
0,
|
||||
3,
|
||||
6,
|
||||
9,
|
||||
10,
|
||||
12,
|
||||
13,
|
||||
15,
|
||||
16,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37,
|
||||
38,
|
||||
39,
|
||||
40,
|
||||
41,
|
||||
42,
|
||||
43,
|
||||
44,
|
||||
45,
|
||||
46,
|
||||
47,
|
||||
48,
|
||||
49,
|
||||
50,
|
||||
51,
|
||||
52,
|
||||
53,
|
||||
54,
|
||||
55,
|
||||
56,
|
||||
57,
|
||||
];
|
||||
|
||||
interface Props {
|
||||
filters: BuildFilter[];
|
||||
setFilters: Dispatch<SetStateAction<BuildFilter[]>>;
|
||||
}
|
||||
|
||||
interface BuildFilter {
|
||||
type: "AT_LEAST" | "AT_MOST" | "HAS" | "DOES_NOT_HAVE";
|
||||
abilityPoints: number;
|
||||
ability: Ability;
|
||||
}
|
||||
|
||||
const BuildFilters: React.FC<Props> = ({ filters, setFilters }) => {
|
||||
return (
|
||||
<>
|
||||
{filters.map((filter, i) => (
|
||||
<Flex alignItems="center" justifyContent="center">
|
||||
<Select
|
||||
value={filter.ability}
|
||||
onChange={(e) => {
|
||||
const newFilters = [...filters];
|
||||
newFilters[i] = { ...filter, ability: e.target.value as Ability };
|
||||
|
||||
setFilters(newFilters);
|
||||
}}
|
||||
variant="flushed"
|
||||
size="sm"
|
||||
width={48}
|
||||
m={2}
|
||||
>
|
||||
{abilities.map((ability) => (
|
||||
<option value={ability.code}>{ability.name}</option>
|
||||
))}
|
||||
</Select>
|
||||
<Box mx={4}>
|
||||
<AbilityIcon ability={filter.ability} size="TINY" />
|
||||
</Box>
|
||||
{isMainAbility(filter.ability) ? (
|
||||
<Select variant="flushed" size="sm" width={32} m={2}>
|
||||
<option value="HAS">{t`Has`}</option>
|
||||
<option value="DOES_NOT_HAVE">{t`Doesn't have`}</option>
|
||||
</Select>
|
||||
) : (
|
||||
<>
|
||||
<Select variant="flushed" size="sm" width={32} m={2}>
|
||||
<option value="AT_LEAST">{t`At least`}</option>
|
||||
<option value="AT_MOST">{t`At most`}</option>
|
||||
</Select>
|
||||
<Select variant="flushed" size="sm" width={20} m={2}>
|
||||
{abilityPointOptions.map((apOption) => (
|
||||
<option value={apOption}>{apOption} AP</option>
|
||||
))}
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
))}
|
||||
<Button
|
||||
onClick={() =>
|
||||
setFilters([
|
||||
...filters,
|
||||
{ ability: "ISM", type: "AT_LEAST", abilityPoints: 12 },
|
||||
])
|
||||
}
|
||||
>
|
||||
<Trans>Add filter</Trans>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BuildFilters;
|
||||
@@ -73,6 +73,7 @@ const ViewAP: React.FC<ViewAPProps> = ({ aps }) => {
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{/* FIXME: center */}
|
||||
<AbilityIcon ability={ability} size="SUB" />
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { t } from "@lingui/macro";
|
||||
|
||||
export const mainOnlyAbilities = [
|
||||
"CB",
|
||||
"LDE",
|
||||
@@ -12,3 +14,38 @@ export const mainOnlyAbilities = [
|
||||
"SJ",
|
||||
"OS",
|
||||
] as const;
|
||||
|
||||
export const abilities = [
|
||||
{ code: "ISM", name: t`Ink Saver (Main)`, type: "STACKABLE" },
|
||||
{ code: "ISS", name: t`Ink Saver (Sub)`, type: "STACKABLE" },
|
||||
{ code: "REC", name: t`Ink Recovery Up`, type: "STACKABLE" },
|
||||
{ code: "RSU", name: t`Run Speed Up`, type: "STACKABLE" },
|
||||
{ code: "SSU", name: t`Swim Speed Up`, type: "STACKABLE" },
|
||||
{ code: "SCU", name: t`Special Charge Up`, type: "STACKABLE" },
|
||||
{ code: "SS", name: t`Special Saver`, type: "STACKABLE" },
|
||||
{ code: "RSU", name: t`Special Power Up`, type: "STACKABLE" },
|
||||
{ code: "QR", name: t`Quick Respawn`, type: "STACKABLE" },
|
||||
{ code: "QSJ", name: t`Quick Super Jump`, type: "STACKABLE" },
|
||||
{ code: "BRU", name: t`Sub Power Up`, type: "STACKABLE" },
|
||||
{ code: "RES", name: t`Ink Resistance Up`, type: "STACKABLE" },
|
||||
{ code: "BDU", name: t`Bomb Defense Up DX`, type: "STACKABLE" },
|
||||
{ code: "MPU", name: t`Main Power Up`, type: "STACKABLE" },
|
||||
{ code: "OG", name: t`Opening Gambit`, type: "HEAD" },
|
||||
{ code: "LDE", name: t`Last-Ditch Effort`, type: "HEAD" },
|
||||
{ code: "T", name: t`Tenacity`, type: "HEAD" },
|
||||
{ code: "CB", name: t`Comeback`, type: "HEAD" },
|
||||
{ code: "NS", name: t`Ninja Squid`, type: "CLOTHING" },
|
||||
{ code: "H", name: t`Haunt`, type: "CLOTHING" },
|
||||
{ code: "TI", name: t`Thermal Ink`, type: "CLOTHING" },
|
||||
{ code: "RP", name: t`Respawn Punisher`, type: "CLOTHING" },
|
||||
{ code: "AD", name: t`Ability Doubler`, type: "CLOTHING" },
|
||||
{ code: "SJ", name: t`Stealth Jump`, type: "SHOES" },
|
||||
{ code: "OS", name: t`Object Shredder`, type: "SHOES" },
|
||||
{ code: "DR", name: t`Drop Roller`, type: "SHOES" },
|
||||
] as const;
|
||||
|
||||
export const isMainAbility = (ability: any) =>
|
||||
abilities.some(
|
||||
(abilityObject) =>
|
||||
abilityObject.code === ability && abilityObject.type !== "STACKABLE"
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Wrap, WrapItem } from "@chakra-ui/core";
|
||||
import { Box, Wrap, WrapItem } from "@chakra-ui/core";
|
||||
import { t } from "@lingui/macro";
|
||||
import { Ability } from "@prisma/client";
|
||||
import BuildCard from "components/builds/BuildCard";
|
||||
import BuildFilters from "components/builds/BuildFilters";
|
||||
import Breadcrumbs from "components/common/Breadcrumbs";
|
||||
import WeaponSelector from "components/common/WeaponSelector";
|
||||
import { weaponToCode } from "lib/lists/weaponCodes";
|
||||
@@ -8,9 +10,16 @@ import { GetBuildsByWeaponData } from "prisma/queries/getBuildsByWeapon";
|
||||
import { useState } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
interface BuildFilter {
|
||||
type: "AT_LEAST" | "AT_MOST" | "HAS" | "DOES_NOT_HAVE";
|
||||
abilityPoints: number;
|
||||
ability: Ability;
|
||||
}
|
||||
|
||||
const BuildsPage = () => {
|
||||
const [weapon, setWeapon] = useState("");
|
||||
const [expanded, setExpanded] = useState<Set<number>>(new Set());
|
||||
const [filters, setFilters] = useState<BuildFilter[]>([]);
|
||||
|
||||
const { data = [] } = useSWR<GetBuildsByWeaponData>(() => {
|
||||
if (!weapon) return null;
|
||||
@@ -23,6 +32,9 @@ const BuildsPage = () => {
|
||||
<>
|
||||
<Breadcrumbs pages={[{ name: t`Builds` }]} />
|
||||
<WeaponSelector value={weapon} onChange={setWeapon} excludeAlt isHeader />
|
||||
<Box mt={10}>
|
||||
<BuildFilters filters={filters} setFilters={setFilters} />
|
||||
</Box>
|
||||
<Wrap pt={16} justifyContent="center" spacing={8}>
|
||||
{data.flatMap((buildArray) => {
|
||||
const firstBuild = buildArray[0];
|
||||
|
||||
@@ -146,7 +146,7 @@ const main = async () => {
|
||||
top500: true,
|
||||
jpn: false,
|
||||
abilityPoints: {
|
||||
SS: 57,
|
||||
QR: 57,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user