From 0bc185ef38b776fe136a957ecc1857a84e991630 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 27 Aug 2022 15:40:41 +0200 Subject: [PATCH] feat(web): developer drawer Move all debug functions into a single developer drawer, Not the best implementation as there is focus fighting going on between some elements and the drawer but will do for now without state management --- web/src/App.tsx | 3 + web/src/features/dev/debug/alert.ts | 16 ++ web/src/features/dev/debug/context.ts | 38 +++++ web/src/features/dev/debug/input.ts | 30 ++++ web/src/features/dev/debug/menu.ts | 41 +++++ web/src/features/dev/debug/notification.ts | 34 ++++ web/src/features/dev/debug/progress.ts | 26 +++ web/src/features/dev/debug/settings.ts | 10 ++ web/src/features/dev/debug/textui.ts | 15 ++ web/src/features/dev/index.tsx | 96 +++++++++++ web/src/features/dialog/AlertDialog.tsx | 24 +-- web/src/features/dialog/InputDialog.tsx | 158 ++++++++++-------- web/src/features/menu/context/ContextMenu.tsx | 35 ---- web/src/features/menu/list/index.tsx | 113 ++++++++----- .../notifications/NotificationWrapper.tsx | 38 +---- .../features/progress/CircleProgressbar.tsx | 15 +- web/src/features/progress/Progressbar.tsx | 15 +- web/src/features/settings/index.tsx | 8 - web/src/features/textui/TextUI.tsx | 18 +- 19 files changed, 487 insertions(+), 246 deletions(-) create mode 100644 web/src/features/dev/debug/alert.ts create mode 100644 web/src/features/dev/debug/context.ts create mode 100644 web/src/features/dev/debug/input.ts create mode 100644 web/src/features/dev/debug/menu.ts create mode 100644 web/src/features/dev/debug/notification.ts create mode 100644 web/src/features/dev/debug/progress.ts create mode 100644 web/src/features/dev/debug/settings.ts create mode 100644 web/src/features/dev/debug/textui.ts create mode 100644 web/src/features/dev/index.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index e697d388..75f525d4 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -10,6 +10,8 @@ import { setClipboard } from "./utils/setClipboard"; import { fetchNui } from "./utils/fetchNui"; import AlertDialog from "./features/dialog/AlertDialog"; import ListMenu from "./features/menu/list"; +import Dev from "./features/dev"; +import { isEnvBrowser } from "./utils/misc"; const App: React.FC = () => { useNuiEvent("setClipboard", (data: string) => { @@ -29,6 +31,7 @@ const App: React.FC = () => { + {isEnvBrowser() && } ); }; diff --git a/web/src/features/dev/debug/alert.ts b/web/src/features/dev/debug/alert.ts new file mode 100644 index 00000000..56fb0b8c --- /dev/null +++ b/web/src/features/dev/debug/alert.ts @@ -0,0 +1,16 @@ +import { debugData } from "../../../utils/debugData"; +import { AlertProps } from "../../dialog/AlertDialog"; + +export const debugAlert = () => { + debugData([ + { + action: "sendAlert", + data: { + header: "Hello there", + content: "General kenobi \n Markdown works", + centered: true, + cancel: true, + }, + }, + ]); +}; diff --git a/web/src/features/dev/debug/context.ts b/web/src/features/dev/debug/context.ts new file mode 100644 index 00000000..3f869b7c --- /dev/null +++ b/web/src/features/dev/debug/context.ts @@ -0,0 +1,38 @@ +import { ContextMenuProps } from "../../../interfaces/context"; +import { debugData } from "../../../utils/debugData"; + +export const debugContext = () => { + debugData([ + { + action: "showContext", + data: { + title: "Vehicle garage", + options: [ + { title: "Empty button" }, + { + title: "Example button", + description: "Example button description", + icon: "inbox", + image: "https://i.imgur.com/YAe7k17.jpeg", + metadata: [{ label: "Value 1", value: 300 }], + }, + { + title: "Menu button", + icon: "bars", + menu: "other_example_menu", + description: "Takes you to another menu", + metadata: ["It also has metadata support"], + }, + { + title: "Event button", + description: "Open a menu and send event data", + icon: "check", + arrow: true, + event: "some_event", + args: { value1: 300, value2: "Other value" }, + }, + ], + }, + }, + ]); +}; diff --git a/web/src/features/dev/debug/input.ts b/web/src/features/dev/debug/input.ts new file mode 100644 index 00000000..3a9b4fad --- /dev/null +++ b/web/src/features/dev/debug/input.ts @@ -0,0 +1,30 @@ +import { debugData } from "../../../utils/debugData"; +import {InputProps} from "../../dialog/InputDialog"; + +export const debugInput = () => { + debugData([ + { + action: "openDialog", + data: { + heading: "Police locker", + rows: [ + { type: "input", label: "Locker number", placeholder: "420" }, + { type: "checkbox", label: "Some checkbox" }, + { type: "input", label: "Locker PIN", password: true, icon: "lock" }, + { type: "checkbox", label: "Some other checkbox", checked: true }, + { + type: "select", + label: "Locker type", + options: [ + { value: "option1" }, + { value: "option2", label: "Option 2" }, + { value: "option3", label: "Option 3" }, + ], + }, + { type: "number", label: "Number counter", default: 12 }, + { type: "slider", label: "Slide bar", min: 10, max: 50, step: 2 }, + ], + }, + }, +]); +} \ No newline at end of file diff --git a/web/src/features/dev/debug/menu.ts b/web/src/features/dev/debug/menu.ts new file mode 100644 index 00000000..607e3bce --- /dev/null +++ b/web/src/features/dev/debug/menu.ts @@ -0,0 +1,41 @@ +import { debugData } from "../../../utils/debugData"; +import { MenuSettings } from "../../menu/list"; + +export const debugMenu = () => { + debugData([ + { + action: "setMenu", + data: { + // position: "bottom-left", + title: "Vehicle garage", + items: [ + { label: "Option 1", icon: "heart" }, + { + label: "Option 2", + icon: "basket-shopping", + description: "Tooltip description 1", + }, + { + label: "Vehicle class", + values: ["Nice", "Super nice", "Extra nice"], + icon: "tag", + description: "Tooltip description 2", + }, + { label: "Option 1" }, + { label: "Option 2" }, + { + label: "Vehicle class", + values: ["Nice", "Super nice", "Extra nice"], + defaultIndex: 1, + }, + { label: "Option 1" }, + { label: "Option 2" }, + { + label: "Vehicle class", + values: ["Nice", "Super nice", "Extra nice"], + }, + ], + }, + }, + ]); +}; diff --git a/web/src/features/dev/debug/notification.ts b/web/src/features/dev/debug/notification.ts new file mode 100644 index 00000000..ce4d706f --- /dev/null +++ b/web/src/features/dev/debug/notification.ts @@ -0,0 +1,34 @@ +import { + CustomNotifiactionProps, + NotificationProps, +} from "../../notifications/NotificationWrapper"; +import { debugData } from "../../../utils/debugData"; + +export const debugNotification = () => { + debugData([ + { + action: "notify", + data: { + description: "Dunak is nerd", + title: "Dunak", + id: 1, + }, + }, + ]); +}; + +export const debugCustomNotification = () => { + debugData([ + { + action: "customNotify", + data: { + description: "Dunak is nerd", + icon: "basket-shopping", + style: { + backgroundColor: "#2D3748", + color: "white", + }, + }, + }, + ]); +}; diff --git a/web/src/features/dev/debug/progress.ts b/web/src/features/dev/debug/progress.ts new file mode 100644 index 00000000..6183d40e --- /dev/null +++ b/web/src/features/dev/debug/progress.ts @@ -0,0 +1,26 @@ +import { debugData } from "../../../utils/debugData"; +import { ProgressbarProps } from "../../progress/Progressbar"; + +export const debugProgressbar = () => { + debugData([ + { + action: "progress", + data: { + label: "Using Lockpick", + duration: 8000, + }, + }, + ]); +}; + +export const debugCircleProgressbar = () => { + debugData([ + { + action: "circleProgress", + data: { + duration: 8000, + label: "Using Armour", + }, + }, + ]); +}; diff --git a/web/src/features/dev/debug/settings.ts b/web/src/features/dev/debug/settings.ts new file mode 100644 index 00000000..11a5ebdd --- /dev/null +++ b/web/src/features/dev/debug/settings.ts @@ -0,0 +1,10 @@ +import { debugData } from "../../../utils/debugData"; + +export const debugSettings = () => { + debugData([ + { + action: "openSettings", + data: true, + }, +]); +} \ No newline at end of file diff --git a/web/src/features/dev/debug/textui.ts b/web/src/features/dev/debug/textui.ts new file mode 100644 index 00000000..12ee87c5 --- /dev/null +++ b/web/src/features/dev/debug/textui.ts @@ -0,0 +1,15 @@ +import { TextUiProps } from "../../textui/TextUI"; +import { debugData } from "../../../utils/debugData"; + +export const debugTextUI = () => { + debugData([ + { + action: "textUi", + data: { + text: "[E] - Access locker inventory \n [G] - Do something else", + position: "right-center", + icon: "door-open", + }, + }, + ]); +}; diff --git a/web/src/features/dev/index.tsx b/web/src/features/dev/index.tsx new file mode 100644 index 00000000..6a3d45e7 --- /dev/null +++ b/web/src/features/dev/index.tsx @@ -0,0 +1,96 @@ +import { + Button, + Drawer, + DrawerBody, + DrawerContent, + DrawerHeader, + DrawerOverlay, + IconButton, + Tooltip, + VStack, + Divider, + useDisclosure, +} from "@chakra-ui/react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { debugAlert } from "./debug/alert"; +import { debugContext } from "./debug/context"; +import { debugInput } from "./debug/input"; +import { debugMenu } from "./debug/menu"; +import { + debugCustomNotification, + debugNotification, +} from "./debug/notification"; +import { debugCircleProgressbar, debugProgressbar } from "./debug/progress"; +import { debugTextUI } from "./debug/textui"; +import { debugSettings } from "./debug/settings"; + +const Dev: React.FC = () => { + const { isOpen, onOpen, onClose } = useDisclosure(); + + return ( + <> + + } + colorScheme="orange" + size="lg" + aria-label="Dev tools" + onClick={() => onOpen()} + /> + + + + + Developer drawer + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Dev; diff --git a/web/src/features/dialog/AlertDialog.tsx b/web/src/features/dialog/AlertDialog.tsx index b8a58646..5693d95f 100644 --- a/web/src/features/dialog/AlertDialog.tsx +++ b/web/src/features/dialog/AlertDialog.tsx @@ -11,34 +11,21 @@ import { import { useRef, useState } from "react"; import ReactMarkdown from "react-markdown"; import { useNuiEvent } from "../../hooks/useNuiEvent"; -import { debugData } from "../../utils/debugData"; import { fetchNui } from "../../utils/fetchNui"; import { useLocales } from "../../providers/LocaleProvider"; -interface DialogProps { +export interface AlertProps { header: string; content: string; centered?: boolean; cancel?: boolean; } -// debugData([ -// { -// action: "sendAlert", -// data: { -// header: "Hello there", -// content: "General kenobi \n Markdown works", -// centered: true, -// cancel: true, -// }, -// }, -// ]); - const AlertDialog: React.FC = () => { const { locale } = useLocales(); const { isOpen, onOpen, onClose } = useDisclosure(); const cancelRef = useRef(null); - const [dialogData, setDialogData] = useState({ + const [dialogData, setDialogData] = useState({ header: "", content: "", }); @@ -48,7 +35,7 @@ const AlertDialog: React.FC = () => { fetchNui("closeAlert", button); }; - useNuiEvent("sendAlert", (data: DialogProps) => { + useNuiEvent("sendAlert", (data: AlertProps) => { setDialogData(data); onOpen(); }); @@ -77,7 +64,10 @@ const AlertDialog: React.FC = () => { {locale.ui.cancel} )} - diff --git a/web/src/features/dialog/InputDialog.tsx b/web/src/features/dialog/InputDialog.tsx index d0059c4b..3ccea826 100644 --- a/web/src/features/dialog/InputDialog.tsx +++ b/web/src/features/dialog/InputDialog.tsx @@ -1,54 +1,42 @@ -import { Modal, ModalOverlay, ModalContent, ModalFooter, ModalHeader, ModalBody, Button } from '@chakra-ui/react'; -import React from 'react'; -import { useNuiEvent } from '../../hooks/useNuiEvent'; -import { useKeyPress } from '../../hooks/useKeyPress'; -import { useLocales } from '../../providers/LocaleProvider'; -import { debugData } from '../../utils/debugData'; -import { fetchNui } from '../../utils/fetchNui'; -import { IInput, ICheckbox, ISelect, INumber, ISlider } from '../../interfaces/dialog'; -import InputField from './components/input'; -import CheckboxField from './components/checkbox'; -import SelectField from './components/select'; -import NumberField from './components/number'; -import SliderField from './components/slider'; +import { + Modal, + ModalOverlay, + ModalContent, + ModalFooter, + ModalHeader, + ModalBody, + Button, +} from "@chakra-ui/react"; +import React from "react"; +import { useNuiEvent } from "../../hooks/useNuiEvent"; +import { useLocales } from "../../providers/LocaleProvider"; +import { fetchNui } from "../../utils/fetchNui"; +import { + IInput, + ICheckbox, + ISelect, + INumber, + ISlider, +} from "../../interfaces/dialog"; +import InputField from "./components/input"; +import CheckboxField from "./components/checkbox"; +import SelectField from "./components/select"; +import NumberField from "./components/number"; +import SliderField from "./components/slider"; -interface Props { +export interface InputProps { heading: string; rows: Array; } -// debugData([ -// { -// action: "openDialog", -// data: { -// heading: "Police locker", -// rows: [ -// { type: "input", label: "Locker number", placeholder: "420" }, -// { type: "checkbox", label: "Some checkbox" }, -// { type: "input", label: "Locker PIN", password: true, icon: "lock" }, -// { type: "checkbox", label: "Some other checkbox", checked: true }, -// { -// type: "select", -// label: "Locker type", -// options: [ -// { value: "option1" }, -// { value: "option2", label: "Option 2" }, -// { value: "option3", label: "Option 3" }, -// ], -// }, -// { type: "number", label: "Number counter", default: 12 }, -// { type: "slider", label: "Slide bar", min: 10, max: 50, step: 2 }, -// ], -// }, -// }, -// ]); - const InputDialog: React.FC = () => { - const [fields, setFields] = React.useState({ - heading: '', - rows: [{ type: 'input', label: '' }], + const [fields, setFields] = React.useState({ + heading: "", + rows: [{ type: "input", label: "" }], }); - const [inputData, setInputData] = React.useState>([]); + const [inputData, setInputData] = React.useState< + Array + >([]); const [passwordStates, setPasswordStates] = React.useState([]); const [visible, setVisible] = React.useState(false); const { locale } = useLocales(); @@ -60,7 +48,7 @@ const InputDialog: React.FC = () => { }); }; - useNuiEvent('openDialog', (data) => { + useNuiEvent("openDialog", (data) => { setPasswordStates([]); setFields(data); setInputData([]); @@ -69,7 +57,7 @@ const InputDialog: React.FC = () => { const handleClose = () => { setVisible(false); - fetchNui('inputData'); + fetchNui("inputData"); }; const handleChange = (value: string | number | boolean, index: number) => { @@ -81,38 +69,74 @@ const InputDialog: React.FC = () => { const handleConfirm = () => { setVisible(false); - fetchNui('inputData', inputData); + fetchNui("inputData", inputData); }; return ( <> - + { - if (e.key === 'Enter' && visible) return handleConfirm(); + if (e.key === "Enter" && visible) return handleConfirm(); }} > {fields.heading} - {fields.rows.map((row: IInput | ICheckbox | ISelect | INumber | ISlider, index) => ( - - {row.type === 'input' && ( - - )} - {row.type === 'checkbox' && } - {row.type === 'select' && } - {row.type === 'number' && } - {row.type === 'slider' && } - - ))} + {fields.rows.map( + ( + row: IInput | ICheckbox | ISelect | INumber | ISlider, + index + ) => ( + + {row.type === "input" && ( + + )} + {row.type === "checkbox" && ( + + )} + {row.type === "select" && ( + + )} + {row.type === "number" && ( + + )} + {row.type === "slider" && ( + + )} + + ) + )}