feat(nui): Context menu sub menus

This commit is contained in:
Luke
2022-03-28 16:49:07 +02:00
parent edce4b4a82
commit a7dd713b6b
3 changed files with 82 additions and 37 deletions

View File

@@ -2,41 +2,38 @@ import { useNuiEvent } from "../../../hooks/useNuiEvent";
import { Box, Text, Flex, ScaleFade } from "@chakra-ui/react"; import { Box, Text, Flex, ScaleFade } from "@chakra-ui/react";
import { debugData } from "../../../utils/debugData"; import { debugData } from "../../../utils/debugData";
import { useState } from "react"; import { useState } from "react";
import { Options } from "../../../interfaces"; import { ContextMenuProps } from "../../../interfaces";
import Item from "./Item"; import Item from "./Item";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { fetchNui } from "../../../utils/fetchNui";
interface Props { debugData<ContextMenuProps>([
title: string;
options: Options;
}
debugData<Props>([
{ {
action: "showContext", action: "showContext",
data: { data: {
title: "Vehicle garage", title: "Vehicle garage",
options: { options: {
["Dinka Blista"]: { "Dinka Blista": {
description: "Super cool vehicle", description: "Super cool vehicle",
subMenu: true, menu: "some_other_identifier",
metadata: { metadata: {
["Plate"]: "KLT 192", Plate: "KLT 192",
["Status"]: "In garage", Status: "In garage",
["Health"]: "30%", Health: "30%",
}, },
}, },
["Elegy Nitro"]: { "Elegy Nitro": {
description: "Even cooler vehicle", description: "Even cooler vehicle",
metadata: ["Plate: JGM 971", "Status: In garage"], metadata: ["Plate: JGM 971", "Status: In garage"],
}, },
["Burger"]: { Burger: {
description: "Make a delicious burger", description: "Make a delicious burger",
metadata: { metadata: {
["Bun"]: 3, Bun: 3,
["Lettuce"]: 2, Lettuce: 2,
["Meat"]: 1, Meat: 1,
["Tomato"]: 1, Tomato: 1,
["Cheese"]: 2, Cheese: 2,
}, },
}, },
}, },
@@ -44,14 +41,22 @@ debugData<Props>([
}, },
]); ]);
const openMenu = (id: string | undefined) => {
fetchNui<ContextMenuProps>("openContext", id);
};
const ContextMenu: React.FC = () => { const ContextMenu: React.FC = () => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [contextMenu, setContextMenu] = useState<Props>({ const [contextMenu, setContextMenu] = useState<ContextMenuProps>({
title: "", title: "",
options: { [""]: { description: "", metadata: [""] } }, options: { "": { description: "", metadata: [] } },
}); });
useNuiEvent<Props>("showContext", (data) => { useNuiEvent<ContextMenuProps>("showContext", async (data) => {
if (visible) {
setVisible(false);
await new Promise((resolve) => setTimeout(resolve, 100));
}
setContextMenu(data); setContextMenu(data);
setVisible(true); setVisible(true);
}); });
@@ -63,10 +68,28 @@ const ContextMenu: React.FC = () => {
h="80%" h="80%"
justifyContent="flex-end" justifyContent="flex-end"
alignItems="center" alignItems="center"
bg="red"
> >
<ScaleFade in={visible} unmountOnExit> <ScaleFade in={visible} unmountOnExit>
<Box w="xs" h={580}> <Box w="xs" h={580}>
<Box borderRadius="md" bg="gray.800" mb={3}> <Flex justifyContent="center" alignItems="center" mb={3}>
{contextMenu.menu && (
<Box
borderRadius="md"
bg="gray.800"
h="100%"
flex="1 15%"
textAlign="center"
marginRight={2}
p={2}
_hover={{ bg: "gray.700" }}
transition="300ms"
onClick={() => openMenu(contextMenu.menu)}
>
<FontAwesomeIcon icon="chevron-left" />
</Box>
)}
<Box borderRadius="md" bg="gray.800" flex="1 85%">
<Text <Text
fontFamily="Poppins" fontFamily="Poppins"
fontSize="md" fontSize="md"
@@ -77,6 +100,7 @@ const ContextMenu: React.FC = () => {
{contextMenu.title} {contextMenu.title}
</Text> </Text>
</Box> </Box>
</Flex>
<Box maxH={560} overflowY="scroll"> <Box maxH={560} overflowY="scroll">
{Object.entries(contextMenu.options).map((option, index) => ( {Object.entries(contextMenu.options).map((option, index) => (
<Item option={option} key={`context-item-${index}`} /> <Item option={option} key={`context-item-${index}`} />

View File

@@ -10,7 +10,17 @@ import {
Spacer, Spacer,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Option } from "../../../interfaces"; import { Option, ContextMenuProps } from "../../../interfaces";
import { fetchNui } from "../../../utils/fetchNui";
const openMenu = (id: string | undefined) => {
fetchNui<ContextMenuProps>("openContext", id);
};
const clickContext = () => {
// todo
fetchNui("clickContext");
};
const Item: React.FC<{ const Item: React.FC<{
option: [string, Option]; option: [string, Option];
@@ -36,7 +46,12 @@ const Item: React.FC<{
transition="300ms" transition="300ms"
_hover={{ bg: "gray.700" }} _hover={{ bg: "gray.700" }}
> >
<Flex w="100%"> <Flex
w="100%"
onClick={() =>
option[1].menu ? openMenu(option[1].menu) : clickContext()
}
>
<Box> <Box>
<Box paddingBottom={1}> <Box paddingBottom={1}>
<Text w="100%" fontWeight="medium"> <Text w="100%" fontWeight="medium">
@@ -49,7 +64,7 @@ const Item: React.FC<{
</Box> </Box>
)} )}
</Box> </Box>
{option[1].subMenu && ( {option[1].menu && (
<> <>
<Spacer /> <Spacer />
<Box <Box

View File

@@ -1,9 +1,15 @@
export interface Option { export interface Option {
menu?: string;
description?: string; description?: string;
metadata?: string[] | { [key: string]: any }; metadata?: string[] | { [key: string]: any };
subMenu?: boolean;
} }
export interface Options { export interface Options {
[key: string]: Option; [key: string]: Option;
} }
export interface ContextMenuProps {
title: string;
menu?: string;
options: Options;
}