mirror of
https://github.com/CommunityOx/ox_lib.git
synced 2026-08-18 23:46:03 +01:00
feat(web): Settings modal, locale state provider
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
{
|
{
|
||||||
"language": "English",
|
"language": "English",
|
||||||
"ui.close": "Close",
|
"ui": {
|
||||||
"ui.confirm": "Confirm"
|
"settings": {
|
||||||
|
"title": "Settings",
|
||||||
|
"language": "Language"
|
||||||
|
},
|
||||||
|
"close": "Close",
|
||||||
|
"confirm": "Confirm"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
{
|
{
|
||||||
"language": "Français",
|
"language": "Français",
|
||||||
"ui.close": "Fermer",
|
"ui": {
|
||||||
"ui.confirm": "Confirmer"
|
"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 userLocale = GetResourceKvpString('locale')
|
||||||
|
|
||||||
local function loadLocale(locale, cb)
|
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))
|
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)
|
SetResourceKvp('locale', locale)
|
||||||
TriggerEvent('ox_lib:setLocale', locale)
|
TriggerEvent('ox_lib:setLocale', locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
RegisterNUICallback('getLocale', loadLocale)
|
RegisterNUICallback('getLocale', loadLocale)
|
||||||
|
|
||||||
if not userLocale then
|
RegisterNUICallback('closeSettings', function(_, cb)
|
||||||
local default = { 'en', 'fr', 'de', 'it', 'es', 'pt-BR', 'pl', 'ru', 'ko', 'zh-TW', 'ja', 'es-MX', 'zh-CN' }
|
cb(1)
|
||||||
userLocale = default[GetCurrentLanguage() + 1]
|
SetNuiFocus(false, false)
|
||||||
end
|
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, _)
|
RegisterCommand('setlocale', function(_, args, _)
|
||||||
if args?[1] then
|
if args?[1] then
|
||||||
|
|||||||
@@ -4,16 +4,21 @@ import Progressbar from "./features/progress/Progressbar";
|
|||||||
import TextUI from "./features/textui/TextUI";
|
import TextUI from "./features/textui/TextUI";
|
||||||
import InputDialog from "./features/dialog/InputDialog";
|
import InputDialog from "./features/dialog/InputDialog";
|
||||||
import ContextMenu from "./features/menu/ContextMenu";
|
import ContextMenu from "./features/menu/ContextMenu";
|
||||||
|
import Settings from "./features/settings";
|
||||||
import { useNuiEvent } from "./hooks/useNuiEvent";
|
import { useNuiEvent } from "./hooks/useNuiEvent";
|
||||||
import { setClipboard } from "./utils/setClipboard";
|
import { setClipboard } from "./utils/setClipboard";
|
||||||
|
import { fetchNui } from "./utils/fetchNui";
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
useNuiEvent("setClipboard", (data: string) => {
|
useNuiEvent("setClipboard", (data: string) => {
|
||||||
setClipboard(data);
|
setClipboard(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fetchNui("init");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Settings />
|
||||||
<Progressbar />
|
<Progressbar />
|
||||||
<CircleProgressbar />
|
<CircleProgressbar />
|
||||||
<Notifications />
|
<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 { fab } from "@fortawesome/free-brands-svg-icons";
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import { isEnvBrowser } from "./utils/misc";
|
import { isEnvBrowser } from "./utils/misc";
|
||||||
|
import LocaleProvider from "./providers/LocaleProvider";
|
||||||
|
|
||||||
library.add(fas, far, fab);
|
library.add(fas, far, fab);
|
||||||
|
|
||||||
@@ -33,11 +34,13 @@ debugData([
|
|||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<VisibilityProvider>
|
<LocaleProvider>
|
||||||
<ChakraProvider theme={theme}>
|
<VisibilityProvider>
|
||||||
<App />
|
<ChakraProvider theme={theme}>
|
||||||
</ChakraProvider>
|
<App />
|
||||||
</VisibilityProvider>
|
</ChakraProvider>
|
||||||
|
</VisibilityProvider>
|
||||||
|
</LocaleProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById("root")
|
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