mirror of
https://github.com/CommunityOx/ox_lib.git
synced 2026-08-16 22:46:03 +01:00
feat(web): Settings modal, locale state provider
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"language": "English",
|
||||
"ui.close": "Close",
|
||||
"ui.confirm": "Confirm"
|
||||
"ui": {
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
"language": "Language"
|
||||
},
|
||||
"close": "Close",
|
||||
"confirm": "Confirm"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"language": "Français",
|
||||
"ui.close": "Fermer",
|
||||
"ui.confirm": "Confirmer"
|
||||
"ui": {
|
||||
"settings": {
|
||||
"title": "Réglages",
|
||||
"language": "Langue"
|
||||
},
|
||||
"close": "Fermer",
|
||||
"confirm": "Confirmer"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,42 @@
|
||||
local default = { 'en', 'fr', 'de', 'it', 'es', 'pt-BR', 'pl', 'ru', 'ko', 'zh-TW', 'ja', 'es-MX', 'zh-CN' }
|
||||
local userLocale = GetResourceKvpString('locale')
|
||||
|
||||
local function loadLocale(locale, cb)
|
||||
if cb then cb(1) end
|
||||
local JSON = LoadResourceFile('ox_lib', ('locales/%s.json'):format(locale)) or LoadResourceFile('ox_lib', ('locales/en.json'):format(locale))
|
||||
if cb then cb(JSON) end
|
||||
|
||||
SendNUIMessage({
|
||||
action = 'setLocale',
|
||||
data = json.decode(JSON)
|
||||
})
|
||||
SetResourceKvp('locale', locale)
|
||||
TriggerEvent('ox_lib:setLocale', locale)
|
||||
end
|
||||
|
||||
RegisterNUICallback('getLocale', loadLocale)
|
||||
|
||||
if not userLocale then
|
||||
local default = { 'en', 'fr', 'de', 'it', 'es', 'pt-BR', 'pl', 'ru', 'ko', 'zh-TW', 'ja', 'es-MX', 'zh-CN' }
|
||||
userLocale = default[GetCurrentLanguage() + 1]
|
||||
end
|
||||
RegisterNUICallback('closeSettings', function(_, cb)
|
||||
cb(1)
|
||||
SetNuiFocus(false, false)
|
||||
end)
|
||||
|
||||
loadLocale(userLocale)
|
||||
if not userLocale then userLocale = default[GetCurrentLanguage() + 1] end
|
||||
|
||||
RegisterNUICallback('init', function(_, cb)
|
||||
cb(1)
|
||||
loadLocale(userLocale)
|
||||
SendNUIMessage({ -- Loads the `default` array into select options
|
||||
action = 'loadLocales',
|
||||
data = default
|
||||
})
|
||||
end)
|
||||
|
||||
RegisterCommand('ox_lib', function()
|
||||
SendNUIMessage({
|
||||
action = 'openSettings',
|
||||
data = GetResourceKvpString('locale') -- Sets the value for language select
|
||||
})
|
||||
SetNuiFocus(true, true)
|
||||
end)
|
||||
|
||||
RegisterCommand('setlocale', function(_, args, _)
|
||||
if args?[1] then
|
||||
|
||||
@@ -4,16 +4,21 @@ import Progressbar from "./features/progress/Progressbar";
|
||||
import TextUI from "./features/textui/TextUI";
|
||||
import InputDialog from "./features/dialog/InputDialog";
|
||||
import ContextMenu from "./features/menu/ContextMenu";
|
||||
import Settings from "./features/settings";
|
||||
import { useNuiEvent } from "./hooks/useNuiEvent";
|
||||
import { setClipboard } from "./utils/setClipboard";
|
||||
import { fetchNui } from "./utils/fetchNui";
|
||||
|
||||
const App: React.FC = () => {
|
||||
useNuiEvent("setClipboard", (data: string) => {
|
||||
setClipboard(data);
|
||||
});
|
||||
|
||||
fetchNui("init");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Settings />
|
||||
<Progressbar />
|
||||
<CircleProgressbar />
|
||||
<Notifications />
|
||||
|
||||
38
web/src/features/settings/components/locale.tsx
Normal file
38
web/src/features/settings/components/locale.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { HStack, Text, Select, Spacer } from "@chakra-ui/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNuiEvent } from "../../../hooks/useNuiEvent";
|
||||
import { useLocales } from "../../../providers/LocaleProvider";
|
||||
import { fetchNui } from "../../../utils/fetchNui";
|
||||
|
||||
const LocaleSetting: React.FC<{
|
||||
languages: string[];
|
||||
selectValue: string;
|
||||
setSelectValue: React.Dispatch<React.SetStateAction<string>>;
|
||||
}> = (props) => {
|
||||
const { locale } = useLocales();
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
props.setSelectValue(e.target.value);
|
||||
fetchNui("getLocale", e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<HStack spacing={5}>
|
||||
<Text>{locale.ui.settings.language}</Text>
|
||||
<Spacer />
|
||||
<Select
|
||||
onChange={(e) => handleChange(e)}
|
||||
value={props.selectValue}
|
||||
w={150}
|
||||
>
|
||||
{props.languages.map((language) => (
|
||||
<option key={language} value={language}>
|
||||
{language}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default LocaleSetting;
|
||||
74
web/src/features/settings/index.tsx
Normal file
74
web/src/features/settings/index.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import LocaleSetting from "./components/locale";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNuiEvent } from "../../hooks/useNuiEvent";
|
||||
import { debugData } from "../../utils/debugData";
|
||||
import { fetchNui } from "../../utils/fetchNui";
|
||||
import { useLocales } from "../../providers/LocaleProvider";
|
||||
|
||||
debugData([
|
||||
{
|
||||
action: "openSettings",
|
||||
data: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { locale } = useLocales();
|
||||
const [languages, setLanguages] = useState([""]);
|
||||
const [selectValue, setSelectValue] = useState("");
|
||||
|
||||
const closeSettings = () => {
|
||||
onClose();
|
||||
fetchNui("closeSettings");
|
||||
};
|
||||
|
||||
useNuiEvent("loadLocales", (data) => setLanguages(data));
|
||||
useNuiEvent("openSettings", (data: string) => {
|
||||
onOpen();
|
||||
setSelectValue(data);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
isCentered
|
||||
closeOnEsc
|
||||
closeOnOverlayClick={false}
|
||||
size="xs"
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>{locale.ui.settings.title}</ModalHeader>
|
||||
<ModalBody>
|
||||
<LocaleSetting
|
||||
languages={languages}
|
||||
selectValue={selectValue}
|
||||
setSelectValue={setSelectValue}
|
||||
/>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button colorScheme="blue" onClick={closeSettings}>
|
||||
{locale.ui.close}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -11,6 +11,7 @@ import { far } from "@fortawesome/free-regular-svg-icons";
|
||||
import { fab } from "@fortawesome/free-brands-svg-icons";
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import { isEnvBrowser } from "./utils/misc";
|
||||
import LocaleProvider from "./providers/LocaleProvider";
|
||||
|
||||
library.add(fas, far, fab);
|
||||
|
||||
@@ -33,11 +34,13 @@ debugData([
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<VisibilityProvider>
|
||||
<ChakraProvider theme={theme}>
|
||||
<App />
|
||||
</ChakraProvider>
|
||||
</VisibilityProvider>
|
||||
<LocaleProvider>
|
||||
<VisibilityProvider>
|
||||
<ChakraProvider theme={theme}>
|
||||
<App />
|
||||
</ChakraProvider>
|
||||
</VisibilityProvider>
|
||||
</LocaleProvider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
87
web/src/providers/LocaleProvider.tsx
Normal file
87
web/src/providers/LocaleProvider.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Context, createContext, useContext, useEffect, useState } from "react";
|
||||
import { useNuiEvent } from "../hooks/useNuiEvent";
|
||||
import { debugData } from "../utils/debugData";
|
||||
|
||||
debugData([
|
||||
{
|
||||
action: "loadLocales",
|
||||
data: [
|
||||
"en",
|
||||
"fr",
|
||||
"de",
|
||||
"it",
|
||||
"es",
|
||||
"pt-BR",
|
||||
"pl",
|
||||
"ru",
|
||||
"ko",
|
||||
"zh-TW",
|
||||
"ja",
|
||||
"es-MX",
|
||||
"zh-CN",
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
debugData([
|
||||
{
|
||||
action: "setLocale",
|
||||
data: {
|
||||
language: "English",
|
||||
ui: {
|
||||
settings: {
|
||||
title: "Settings",
|
||||
language: "Language",
|
||||
},
|
||||
close: "Close",
|
||||
confirm: "Confirm",
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
interface Locale {
|
||||
language: string;
|
||||
ui: {
|
||||
settings: {
|
||||
title: string;
|
||||
language: string;
|
||||
};
|
||||
close: string;
|
||||
confirm: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface LocaleContextValue {
|
||||
locale: Locale;
|
||||
setLocale: (locales: Locale) => void;
|
||||
}
|
||||
|
||||
const LocaleCtx = createContext<LocaleContextValue | null>(null);
|
||||
|
||||
const LocaleProvider: React.FC = ({ children }) => {
|
||||
const [locale, setLocale] = useState<Locale>({
|
||||
language: "",
|
||||
ui: {
|
||||
settings: {
|
||||
title: "",
|
||||
language: "",
|
||||
},
|
||||
close: "",
|
||||
confirm: "",
|
||||
},
|
||||
});
|
||||
|
||||
useNuiEvent("setLocale", async (data: Locale) => setLocale(data));
|
||||
|
||||
return (
|
||||
<LocaleCtx.Provider value={{ locale, setLocale }}>
|
||||
{children}
|
||||
</LocaleCtx.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default LocaleProvider;
|
||||
|
||||
export const useLocales = () =>
|
||||
useContext<LocaleContextValue>(LocaleCtx as Context<LocaleContextValue>);
|
||||
Reference in New Issue
Block a user