mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 23:19:39 -05:00
Maplist generator: Custom Order (#346)
* new select for multiple modes * add custom order generation * remove log + better select position * little optimization * import fix * add icons for modes in select * pretty * rename variable * import replace * arrow function * render only if selected * Update pages/maps.tsx Co-authored-by: Kalle <38327916+Sendouc@users.noreply.github.com> Co-authored-by: Kalle <38327916+Sendouc@users.noreply.github.com>
This commit is contained in:
parent
fdeb541e64
commit
10951fe39e
177
components/common/MultipleModeSelector.tsx
Normal file
177
components/common/MultipleModeSelector.tsx
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import { ChevronDownIcon } from "@chakra-ui/icons";
|
||||
import { useMyTheme } from "hooks/common";
|
||||
import { useState } from "react";
|
||||
import ReactSelect, {
|
||||
components,
|
||||
GroupedOptionsType,
|
||||
OptionsType,
|
||||
OptionTypeBase,
|
||||
ValueType,
|
||||
} from "react-select";
|
||||
import { SelectComponents } from "react-select/src/components";
|
||||
import { Box, Flex } from "@chakra-ui/react";
|
||||
import ModeImage from "./ModeImage";
|
||||
|
||||
interface SelectProps {
|
||||
options?:
|
||||
| OptionsType<{
|
||||
label: string;
|
||||
value: any;
|
||||
data?: any;
|
||||
}>
|
||||
| GroupedOptionsType<{
|
||||
label: string;
|
||||
value: string;
|
||||
data?: any;
|
||||
}>;
|
||||
width?: string;
|
||||
value?: ValueType<OptionTypeBase, boolean>;
|
||||
setValue: (value: any) => void;
|
||||
components?: Partial<SelectComponents<OptionTypeBase, boolean>>;
|
||||
isDisabled?: boolean;
|
||||
menuIsOpen?: boolean;
|
||||
hideMenuBeforeTyping?: boolean;
|
||||
}
|
||||
|
||||
const DropdownIndicator = (props: any) => {
|
||||
const { textColor } = useMyTheme();
|
||||
return (
|
||||
<components.DropdownIndicator {...props}>
|
||||
<ChevronDownIcon fontSize="1.3rem" color={textColor} />
|
||||
</components.DropdownIndicator>
|
||||
);
|
||||
};
|
||||
|
||||
const Option = (props: any) => {
|
||||
return (
|
||||
<components.Option {...props}>
|
||||
<Flex alignItems="center">
|
||||
<Box mr="0.5em">
|
||||
<ModeImage size={24} mode={props.value} />
|
||||
</Box>
|
||||
{props.label}
|
||||
</Flex>
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
|
||||
const MultipleModeSelector: React.FC<SelectProps> = ({
|
||||
options,
|
||||
components,
|
||||
setValue,
|
||||
isDisabled = false,
|
||||
menuIsOpen = false,
|
||||
hideMenuBeforeTyping,
|
||||
}) => {
|
||||
const {
|
||||
borderColor,
|
||||
themeColorHex,
|
||||
bgColor,
|
||||
themeColorOpaque,
|
||||
textColor,
|
||||
} = useMyTheme();
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [selectedModes, setSelectedModes] = useState([]);
|
||||
|
||||
const handleChange = (selectedOption: any) => {
|
||||
if (!selectedOption) {
|
||||
setSelectedModes([]);
|
||||
return;
|
||||
}
|
||||
const newSelectedOption = selectedOption.map(
|
||||
(opt: { label: string; data: string }) => ({
|
||||
label: opt.label,
|
||||
data: opt.data,
|
||||
value: Math.random(),
|
||||
})
|
||||
);
|
||||
setSelectedModes(newSelectedOption);
|
||||
setValue(newSelectedOption);
|
||||
};
|
||||
|
||||
const menuIsOpenCheck = () => {
|
||||
if (menuIsOpen) return true;
|
||||
if (hideMenuBeforeTyping) {
|
||||
return !!(inputValue.length >= 3);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactSelect
|
||||
className="basic-single"
|
||||
classNamePrefix="select"
|
||||
value={selectedModes}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(newValue) => setInputValue(newValue)}
|
||||
menuIsOpen={menuIsOpenCheck()}
|
||||
onChange={handleChange}
|
||||
placeholder={null}
|
||||
isMulti={true}
|
||||
isDisabled={isDisabled}
|
||||
isClearable={true}
|
||||
options={options}
|
||||
components={
|
||||
hideMenuBeforeTyping
|
||||
? {
|
||||
IndicatorSeparator: () => null,
|
||||
DropdownIndicator: () => null,
|
||||
Option,
|
||||
...components,
|
||||
}
|
||||
: {
|
||||
IndicatorSeparator: () => null,
|
||||
DropdownIndicator,
|
||||
Option,
|
||||
...components,
|
||||
}
|
||||
}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
borderRadius: 5,
|
||||
colors: {
|
||||
...theme.colors,
|
||||
primary25: `${themeColorHex}`,
|
||||
primary: themeColorHex,
|
||||
neutral0: bgColor,
|
||||
neutral5: bgColor,
|
||||
},
|
||||
})}
|
||||
styles={{
|
||||
singleValue: (base) => ({
|
||||
...base,
|
||||
padding: 5,
|
||||
borderRadius: 5,
|
||||
color: textColor,
|
||||
display: "flex",
|
||||
}),
|
||||
input: (base) => ({
|
||||
...base,
|
||||
color: textColor,
|
||||
}),
|
||||
multiValue: (base) => ({
|
||||
...base,
|
||||
background: themeColorHex,
|
||||
color: "black",
|
||||
}),
|
||||
option: (styles, { isFocused }) => {
|
||||
return {
|
||||
...styles,
|
||||
backgroundColor: isFocused ? themeColorOpaque : undefined,
|
||||
color: textColor,
|
||||
};
|
||||
},
|
||||
menu: (styles) => ({ ...styles, zIndex: 999 }),
|
||||
control: (base) => ({
|
||||
...base,
|
||||
borderColor,
|
||||
minHeight: "2.5rem",
|
||||
background: "hsla(0, 0%, 0%, 0)",
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default MultipleModeSelector;
|
||||
|
|
@ -25,6 +25,7 @@ import { RankedMode } from "@prisma/client";
|
|||
import ModeImage from "components/common/ModeImage";
|
||||
import SubText from "components/common/SubText";
|
||||
import HeaderBanner from "components/layout/HeaderBanner";
|
||||
import MultipleModeSelector from "components/common/MultipleModeSelector";
|
||||
import { useRouter } from "next/router";
|
||||
import { ChangeEvent, Fragment, useEffect, useState } from "react";
|
||||
import { FiCheck, FiFilter, FiRotateCw } from "react-icons/fi";
|
||||
|
|
@ -40,9 +41,12 @@ const MapsGeneratorPage = () => {
|
|||
Record<string, RankedMode[]>
|
||||
>(getInitialStages());
|
||||
const [generationMode, setGenerationMode] = useState<
|
||||
"EQUAL" | "SZ_EVERY_OTHER"
|
||||
"EQUAL" | "SZ_EVERY_OTHER" | "CUSTOM_ORDER"
|
||||
>("EQUAL");
|
||||
const [maplist, setMaplist] = useState("");
|
||||
const [modes, setModes] = useState<
|
||||
{ label: string; value: number; data?: string }[]
|
||||
>([]);
|
||||
const [count, setCount] = useState(9);
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [copied, setCopied] = useState<null | "URL" | "LIST">(null);
|
||||
|
|
@ -127,15 +131,22 @@ const MapsGeneratorPage = () => {
|
|||
const modesFromGenerationMode =
|
||||
generationMode === "SZ_EVERY_OTHER"
|
||||
? ["TC", "RM", "CB"]
|
||||
: ["SZ", "TC", "RM", "CB"];
|
||||
: generationMode === "EQUAL"
|
||||
? ["SZ", "TC", "RM", "CB"]
|
||||
: transformModesToStringArray();
|
||||
|
||||
const modes = (shuffleArray(
|
||||
modesFromGenerationMode
|
||||
) as RankedMode[]).filter((mode) => modeStages[mode].length > 0);
|
||||
const filteredModes = (modesFromGenerationMode as RankedMode[]).filter(
|
||||
(mode) => modeStages[mode].length > 0
|
||||
);
|
||||
const modes =
|
||||
generationMode === "CUSTOM_ORDER"
|
||||
? filteredModes
|
||||
: shuffleArray(filteredModes);
|
||||
if (modes.length === 0) {
|
||||
return "I can't generate a maplist without any maps in it you know.";
|
||||
return generationMode === "CUSTOM_ORDER"
|
||||
? "I can't generate a maplist without any modes you know."
|
||||
: "I can't generate a maplist without any maps in it you know.";
|
||||
}
|
||||
|
||||
const stagesAlreadyPicked = new Set<string>();
|
||||
|
||||
const isSZFirst = false;
|
||||
|
|
@ -149,8 +160,8 @@ const MapsGeneratorPage = () => {
|
|||
generationMode !== "SZ_EVERY_OTHER" ||
|
||||
i % 2 === Number(isSZFirst)
|
||||
) {
|
||||
modes.push(modes.shift() as RankedMode);
|
||||
modeOfRound = modes[0];
|
||||
modes.push(modes.shift() as RankedMode);
|
||||
}
|
||||
|
||||
const stageArray = modeStages[modeOfRound];
|
||||
|
|
@ -336,7 +347,9 @@ const MapsGeneratorPage = () => {
|
|||
</Stack>
|
||||
<RadioGroup
|
||||
onChange={(value) =>
|
||||
setGenerationMode(value as "EQUAL" | "SZ_EVERY_OTHER")
|
||||
setGenerationMode(
|
||||
value as "EQUAL" | "SZ_EVERY_OTHER" | "CUSTOM_ORDER"
|
||||
)
|
||||
}
|
||||
value={generationMode}
|
||||
>
|
||||
|
|
@ -347,9 +360,23 @@ const MapsGeneratorPage = () => {
|
|||
<Radio value="SZ_EVERY_OTHER">
|
||||
<Trans>SZ every other</Trans>
|
||||
</Radio>
|
||||
<Radio value="CUSTOM_ORDER">
|
||||
<Trans>Custom order</Trans>
|
||||
</Radio>
|
||||
</Stack>
|
||||
</RadioGroup>
|
||||
<FormLabel htmlFor="count" fontSize="sm">
|
||||
{generationMode === "CUSTOM_ORDER" && <MultipleModeSelector
|
||||
options={[
|
||||
{ label: "Splat Zones", value: "SZ", data: "SZ" },
|
||||
{ label: "Tower Control", value: "TC", data: "TC" },
|
||||
{ label: "Rainmaker", value: "RM", data: "RM" },
|
||||
{ label: "Clam Blitz", value: "CB", data: "CB" },
|
||||
]}
|
||||
isDisabled={generationMode !== "CUSTOM_ORDER"}
|
||||
setValue={getModeValues}
|
||||
width={"90%"}
|
||||
/>}
|
||||
<FormLabel htmlFor="count" fontSize="sm" mt={4}>
|
||||
<Trans>Amount of maps to generate</Trans>
|
||||
</FormLabel>
|
||||
<NumberInput
|
||||
|
|
@ -390,6 +417,19 @@ const MapsGeneratorPage = () => {
|
|||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
function getModeValues(
|
||||
value: { label: string; value: number; data?: string }[]
|
||||
) {
|
||||
setModes(value);
|
||||
}
|
||||
|
||||
function transformModesToStringArray() {
|
||||
return modes.map(mode => {
|
||||
if (mode.data) return mode.data;
|
||||
else return "";
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MapsGeneratorPage.header = (
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user