WIP
This commit is contained in:
+2
-3
@@ -19,10 +19,9 @@
|
|||||||
"react": "^18.0.0-alpha-dbe3363cc",
|
"react": "^18.0.0-alpha-dbe3363cc",
|
||||||
"react-dom": "^18.0.0-alpha-dbe3363cc",
|
"react-dom": "^18.0.0-alpha-dbe3363cc",
|
||||||
"react-flags-select": "^2.1.2",
|
"react-flags-select": "^2.1.2",
|
||||||
"react-hook-form": "^7.8.4",
|
"react-hook-form": "^7.8.6",
|
||||||
"react-json-pretty": "^2.2.0",
|
"react-json-pretty": "^2.2.0",
|
||||||
"rxjs": "^7.1.0",
|
"rxjs": "^7.1.0"
|
||||||
"yarn": "^1.22.10"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@snowpack/plugin-dotenv": "^2.0.5",
|
"@snowpack/plugin-dotenv": "^2.0.5",
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/** @type {import("snowpack").SnowpackUserConfig } */
|
/** @type {import("snowpack").SnowpackUserConfig } */
|
||||||
module.exports = {
|
export default {
|
||||||
mount: {
|
mount: {
|
||||||
public: { url: '/', static: true },
|
public: { url: '/', static: true },
|
||||||
src: { url: '/static' },
|
src: { url: '/static' },
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
'@snowpack/plugin-postcss',
|
|
||||||
'@snowpack/plugin-react-refresh',
|
'@snowpack/plugin-react-refresh',
|
||||||
'@snowpack/plugin-dotenv',
|
'@snowpack/plugin-dotenv',
|
||||||
|
'@snowpack/plugin-postcss',
|
||||||
[
|
[
|
||||||
'@snowpack/plugin-typescript',
|
'@snowpack/plugin-typescript',
|
||||||
{
|
{
|
||||||
@@ -21,6 +21,7 @@ module.exports = {
|
|||||||
// {"match": "routes", "src": ".*", "dest": "/index.html"},
|
// {"match": "routes", "src": ".*", "dest": "/index.html"},
|
||||||
],
|
],
|
||||||
optimize: {
|
optimize: {
|
||||||
|
/* Example: Bundle your final build: */
|
||||||
bundle: true,
|
bundle: true,
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
splitting: true,
|
splitting: true,
|
||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import Main from './Main';
|
import Main from './Main';
|
||||||
import { channelSubject$, nodeSubject$, preferencesSubject$ } from './streams';
|
import { channelSubject$, nodeSubject$, preferencesSubject$ } from './streams';
|
||||||
import { LanguageEnum } from './translations/TranslationContext';
|
|
||||||
|
|
||||||
const App = (): JSX.Element => {
|
const App = (): JSX.Element => {
|
||||||
const [deviceStatus, setDeviceStatus] =
|
const [deviceStatus, setDeviceStatus] =
|
||||||
@@ -31,10 +30,6 @@ const App = (): JSX.Element => {
|
|||||||
const [isReady, setIsReady] = React.useState<boolean>(false);
|
const [isReady, setIsReady] = React.useState<boolean>(false);
|
||||||
const [lastMeshInterraction, setLastMeshInterraction] =
|
const [lastMeshInterraction, setLastMeshInterraction] =
|
||||||
React.useState<number>(0);
|
React.useState<number>(0);
|
||||||
|
|
||||||
const [language, setLanguage] = React.useState<LanguageEnum>(
|
|
||||||
LanguageEnum.ENGLISH,
|
|
||||||
);
|
|
||||||
const [darkmode, setDarkmode] = React.useState<boolean>(false);
|
const [darkmode, setDarkmode] = React.useState<boolean>(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -115,8 +110,6 @@ const App = (): JSX.Element => {
|
|||||||
isReady={isReady}
|
isReady={isReady}
|
||||||
myNodeInfo={myNodeInfo}
|
myNodeInfo={myNodeInfo}
|
||||||
connection={connection}
|
connection={connection}
|
||||||
language={language}
|
|
||||||
setLanguage={setLanguage}
|
|
||||||
darkmode={darkmode}
|
darkmode={darkmode}
|
||||||
setDarkmode={setDarkmode}
|
setDarkmode={setDarkmode}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+34
-36
@@ -11,21 +11,21 @@ import type {
|
|||||||
import ChatMessage from './components/ChatMessage';
|
import ChatMessage from './components/ChatMessage';
|
||||||
import MessageBox from './components/MessageBox';
|
import MessageBox from './components/MessageBox';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
import type { LanguageEnum } from './translations/TranslationContext';
|
import { useTranslationsContextValue } from './hooks/useTranslationsContextValue';
|
||||||
import { TranslationContext } from './translations/TranslationContext';
|
import { TranslationsContext } from './translations/TranslationsContext';
|
||||||
|
|
||||||
interface MainProps {
|
interface MainProps {
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
myNodeInfo: Protobuf.MyNodeInfo;
|
myNodeInfo: Protobuf.MyNodeInfo;
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
language: LanguageEnum;
|
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Main = (props: MainProps): JSX.Element => {
|
const Main = (props: MainProps): JSX.Element => {
|
||||||
const { translations } = React.useContext(TranslationContext);
|
const translationsContextValue = useTranslationsContextValue();
|
||||||
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
|
|
||||||
const [messages, setMessages] = React.useState<
|
const [messages, setMessages] = React.useState<
|
||||||
{ message: Types.TextPacket; ack: boolean }[]
|
{ message: Types.TextPacket; ack: boolean }[]
|
||||||
>([]);
|
>([]);
|
||||||
@@ -65,41 +65,39 @@ const Main = (props: MainProps): JSX.Element => {
|
|||||||
}, [props.connection, messages]);
|
}, [props.connection, messages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col md:flex-row flex-grow m-3 space-y-2 md:space-y-0 space-x-0 md:space-x-2">
|
<TranslationsContext.Provider value={translationsContextValue}>
|
||||||
<div className="flex flex-col flex-grow container mx-auto">
|
<div className="flex flex-col md:flex-row flex-grow m-3 space-y-2 md:space-y-0 space-x-0 md:space-x-2">
|
||||||
<div className="flex flex-col flex-grow py-6 space-y-2">
|
<div className="flex flex-col flex-grow container mx-auto">
|
||||||
{messages.length ? (
|
<div className="flex flex-col flex-grow py-6 space-y-2">
|
||||||
messages.map((message, Main) => (
|
{messages.length ? (
|
||||||
<ChatMessage
|
messages.map((message, Main) => (
|
||||||
key={Main}
|
<ChatMessage
|
||||||
message={message}
|
key={Main}
|
||||||
myId={props.myNodeInfo.myNodeNum}
|
message={message}
|
||||||
/>
|
myId={props.myNodeInfo.myNodeNum}
|
||||||
))
|
/>
|
||||||
) : (
|
))
|
||||||
<div className="m-auto text-2xl text-gray-500">
|
) : (
|
||||||
{translations.no_messages_message}
|
<div className="m-auto text-2xl text-gray-500">
|
||||||
</div>
|
{translations.no_messages_message}
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<MessageBox
|
||||||
|
connection={props.connection}
|
||||||
|
isReady={props.isReady}
|
||||||
|
sidebarOpen={sidebarOpen}
|
||||||
|
setSidebarOpen={setSidebarOpen}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<MessageBox
|
<Sidebar
|
||||||
connection={props.connection}
|
myId={props.myNodeInfo.myNodeNum}
|
||||||
isReady={props.isReady}
|
|
||||||
sidebarOpen={sidebarOpen}
|
sidebarOpen={sidebarOpen}
|
||||||
setSidebarOpen={setSidebarOpen}
|
darkmode={props.darkmode}
|
||||||
|
setDarkmode={props.setDarkmode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Sidebar
|
</TranslationsContext.Provider>
|
||||||
isReady={props.isReady}
|
|
||||||
connection={props.connection}
|
|
||||||
language={props.language}
|
|
||||||
setLanguage={props.setLanguage}
|
|
||||||
myId={props.myNodeInfo.myNodeNum}
|
|
||||||
sidebarOpen={sidebarOpen}
|
|
||||||
darkmode={props.darkmode}
|
|
||||||
setDarkmode={props.setDarkmode}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import type {
|
|||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import { TranslationContext } from '../translations/TranslationContext';
|
import { TranslationsContext } from '../translations/TranslationsContext';
|
||||||
|
|
||||||
export interface MessageBoxProps {
|
export interface MessageBoxProps {
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
@@ -17,7 +17,7 @@ export interface MessageBoxProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MessageBox = (props: MessageBoxProps): JSX.Element => {
|
const MessageBox = (props: MessageBoxProps): JSX.Element => {
|
||||||
const { translations } = React.useContext(TranslationContext);
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
const [currentMessage, setCurrentMessage] = React.useState('');
|
const [currentMessage, setCurrentMessage] = React.useState('');
|
||||||
const sendMessage = () => {
|
const sendMessage = () => {
|
||||||
if (props.isReady) {
|
if (props.isReady) {
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type {
|
|
||||||
IBLEConnection,
|
|
||||||
IHTTPConnection,
|
|
||||||
ISerialConnection,
|
|
||||||
} from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
import type { LanguageEnum } from '../translations/TranslationContext';
|
|
||||||
import Channels from './Sidebar/Channels/Index';
|
import Channels from './Sidebar/Channels/Index';
|
||||||
import Device from './Sidebar/Device/Index';
|
import Device from './Sidebar/Device/Index';
|
||||||
import Nodes from './Sidebar/Nodes/Index';
|
import Nodes from './Sidebar/Nodes/Index';
|
||||||
import UI from './Sidebar/UI/Index';
|
import UI from './Sidebar/UI/Index';
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
isReady: boolean;
|
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
|
||||||
language: LanguageEnum;
|
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
|
||||||
myId: number;
|
myId: number;
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
@@ -31,15 +20,10 @@ const Sidebar = (props: SidebarProps): JSX.Element => {
|
|||||||
} flex-col rounded-md md:ml-0 shadow-md border w-full max-w-sm`}
|
} flex-col rounded-md md:ml-0 shadow-md border w-full max-w-sm`}
|
||||||
>
|
>
|
||||||
<Nodes myId={props.myId} />
|
<Nodes myId={props.myId} />
|
||||||
<Device isReady={props.isReady} connection={props.connection} />
|
<Device />
|
||||||
<Channels />
|
<Channels />
|
||||||
<div className="flex-grow border-b"></div>
|
<div className="flex-grow border-b"></div>
|
||||||
<UI
|
<UI darkmode={props.darkmode} setDarkmode={props.setDarkmode} />
|
||||||
language={props.language}
|
|
||||||
setLanguage={props.setLanguage}
|
|
||||||
darkmode={props.darkmode}
|
|
||||||
setDarkmode={props.setDarkmode}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import {
|
|||||||
HashtagIcon,
|
HashtagIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
|
|
||||||
import { TranslationContext } from '../../../translations/TranslationContext';
|
import { TranslationsContext } from '../../../translations/TranslationsContext';
|
||||||
import ChannelList from './ChannelList';
|
import ChannelList from './ChannelList';
|
||||||
|
|
||||||
const Channels = (): JSX.Element => {
|
const Channels = (): JSX.Element => {
|
||||||
const { translations } = React.useContext(TranslationContext);
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
|
|||||||
@@ -6,22 +6,12 @@ import {
|
|||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
import type {
|
|
||||||
IBLEConnection,
|
|
||||||
IHTTPConnection,
|
|
||||||
ISerialConnection,
|
|
||||||
} from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
import { TranslationContext } from '../../../translations/TranslationContext';
|
import { TranslationsContext } from '../../../translations/TranslationsContext';
|
||||||
import Settings from './Settings';
|
import Settings from './Settings';
|
||||||
|
|
||||||
interface DeviceProps {
|
const Device = (): JSX.Element => {
|
||||||
isReady: boolean;
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Device = (props: DeviceProps): JSX.Element => {
|
|
||||||
const { translations } = React.useContext(TranslationContext);
|
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -46,10 +36,7 @@ const Device = (props: DeviceProps): JSX.Element => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Settings
|
<Settings />
|
||||||
connection={props.connection}
|
|
||||||
isReady={props.isReady}
|
|
||||||
/>
|
|
||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
</>
|
</>
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
|
|||||||
@@ -5,23 +5,13 @@ import { useForm } from 'react-hook-form';
|
|||||||
import JSONPretty from 'react-json-pretty';
|
import JSONPretty from 'react-json-pretty';
|
||||||
|
|
||||||
import { SaveIcon } from '@heroicons/react/outline';
|
import { SaveIcon } from '@heroicons/react/outline';
|
||||||
import type {
|
|
||||||
IBLEConnection,
|
|
||||||
IHTTPConnection,
|
|
||||||
ISerialConnection,
|
|
||||||
} from '@meshtastic/meshtasticjs';
|
|
||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import { preferencesResource } from '../../../streams';
|
import { preferencesResource } from '../../../streams';
|
||||||
import { TranslationContext } from '../../../translations/TranslationContext';
|
import { TranslationsContext } from '../../../translations/TranslationsContext';
|
||||||
|
|
||||||
export interface SettingsProps {
|
const Settings = (): JSX.Element => {
|
||||||
isReady: boolean;
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Settings = (props: SettingsProps): JSX.Element => {
|
|
||||||
const { translations } = React.useContext(TranslationContext);
|
|
||||||
const preferences = useObservableSuspense(preferencesResource);
|
const preferences = useObservableSuspense(preferencesResource);
|
||||||
|
|
||||||
const { register, handleSubmit } =
|
const { register, handleSubmit } =
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
UsersIcon,
|
UsersIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
|
|
||||||
import { TranslationContext } from '../../../translations/TranslationContext';
|
import { TranslationsContext } from '../../../translations/TranslationsContext';
|
||||||
import NodeList from './NodeList';
|
import NodeList from './NodeList';
|
||||||
|
|
||||||
interface NodesProps {
|
interface NodesProps {
|
||||||
@@ -15,7 +15,7 @@ interface NodesProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Nodes = (props: NodesProps): JSX.Element => {
|
const Nodes = (props: NodesProps): JSX.Element => {
|
||||||
const { translations } = React.useContext(TranslationContext);
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const Node = (props: NodeProps): JSX.Element => {
|
|||||||
) : null}
|
) : null}
|
||||||
<Avatar
|
<Avatar
|
||||||
size={30}
|
size={30}
|
||||||
name={props.node.data.user?.longName}
|
name={props.node.data.user?.longName ?? 'Unknown'}
|
||||||
variant="beam"
|
variant="beam"
|
||||||
colors={[
|
colors={[
|
||||||
'#213435',
|
'#213435',
|
||||||
|
|||||||
@@ -7,19 +7,16 @@ import {
|
|||||||
CogIcon,
|
CogIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
|
|
||||||
import type { LanguageEnum } from '../../../translations/TranslationContext';
|
import { TranslationsContext } from '../../../translations/TranslationsContext';
|
||||||
import { TranslationContext } from '../../../translations/TranslationContext';
|
|
||||||
import Translations from './Translations';
|
import Translations from './Translations';
|
||||||
|
|
||||||
interface UIProps {
|
interface UIProps {
|
||||||
language: LanguageEnum;
|
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UI = (props: UIProps): JSX.Element => {
|
const UI = (props: UIProps): JSX.Element => {
|
||||||
const { translations } = React.useContext(TranslationContext);
|
const { translations } = React.useContext(TranslationsContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -36,10 +33,7 @@ const UI = (props: UIProps): JSX.Element => {
|
|||||||
</div>
|
</div>
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
<Disclosure.Panel>
|
<Disclosure.Panel>
|
||||||
<Translations
|
<Translations />
|
||||||
language={props.language}
|
|
||||||
setLanguage={props.setLanguage}
|
|
||||||
/>
|
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -7,16 +7,12 @@ import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/outline';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
LanguageEnum,
|
LanguageEnum,
|
||||||
TranslationContext,
|
TranslationsContext,
|
||||||
} from '../../../translations/TranslationContext';
|
} from '../../../translations/TranslationsContext';
|
||||||
|
|
||||||
export interface TranslationsProps {
|
const Translations = (): JSX.Element => {
|
||||||
language: LanguageEnum;
|
const { translations, language, setLanguage } =
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
React.useContext(TranslationsContext);
|
||||||
}
|
|
||||||
|
|
||||||
const Translations = (props: TranslationsProps): JSX.Element => {
|
|
||||||
const { translations } = React.useContext(TranslationContext);
|
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -30,11 +26,11 @@ const Translations = (props: TranslationsProps): JSX.Element => {
|
|||||||
)}
|
)}
|
||||||
{translations.language_title}
|
{translations.language_title}
|
||||||
<div className="my-auto">
|
<div className="my-auto">
|
||||||
{props.language === LanguageEnum.ENGLISH ? (
|
{language === LanguageEnum.ENGLISH ? (
|
||||||
<Us className="ml-2 w-8" />
|
<Us className="ml-2 w-8" />
|
||||||
) : props.language === LanguageEnum.JAPANESE ? (
|
) : language === LanguageEnum.JAPANESE ? (
|
||||||
<Jp className="ml-2 w-8" />
|
<Jp className="ml-2 w-8" />
|
||||||
) : props.language === LanguageEnum.PORTUGUESE ? (
|
) : language === LanguageEnum.PORTUGUESE ? (
|
||||||
<Br className="ml-2 w-8" />
|
<Br className="ml-2 w-8" />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -44,7 +40,7 @@ const Translations = (props: TranslationsProps): JSX.Element => {
|
|||||||
<div
|
<div
|
||||||
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.setLanguage(LanguageEnum.ENGLISH);
|
setLanguage(LanguageEnum.ENGLISH);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
English <Us className="w-8 my-auto" />
|
English <Us className="w-8 my-auto" />
|
||||||
@@ -52,7 +48,7 @@ const Translations = (props: TranslationsProps): JSX.Element => {
|
|||||||
<div
|
<div
|
||||||
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.setLanguage(LanguageEnum.PORTUGUESE);
|
setLanguage(LanguageEnum.PORTUGUESE);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Português <Br className="w-8 my-auto" />
|
Português <Br className="w-8 my-auto" />
|
||||||
@@ -60,7 +56,7 @@ const Translations = (props: TranslationsProps): JSX.Element => {
|
|||||||
<div
|
<div
|
||||||
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
className="flex bg-gray-100 hover:bg-gray-200 cursor-pointer justify-between p-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.setLanguage(LanguageEnum.JAPANESE);
|
setLanguage(LanguageEnum.JAPANESE);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
日本語 <Jp className="w-8 my-auto" />
|
日本語 <Jp className="w-8 my-auto" />
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Translations_EN from '../translations/en';
|
||||||
|
import Translations_JP from '../translations/jp';
|
||||||
|
import Translations_PT from '../translations/pt';
|
||||||
|
import type {
|
||||||
|
languageTemplate,
|
||||||
|
TranslationsContextData,
|
||||||
|
} from '../translations/TranslationsContext';
|
||||||
|
import { LanguageEnum } from '../translations/TranslationsContext';
|
||||||
|
|
||||||
|
export const useTranslationsContextValue = (): TranslationsContextData => {
|
||||||
|
const [currentLanguage, setcurrentLanguage] = React.useState<LanguageEnum>(
|
||||||
|
LanguageEnum.ENGLISH,
|
||||||
|
);
|
||||||
|
const [translation, setTranslation] =
|
||||||
|
React.useState<languageTemplate>(Translations_EN);
|
||||||
|
|
||||||
|
const setLanguage = React.useCallback(
|
||||||
|
(language: LanguageEnum) => {
|
||||||
|
setcurrentLanguage(language);
|
||||||
|
switch (language) {
|
||||||
|
case LanguageEnum.ENGLISH:
|
||||||
|
setTranslation(Translations_EN);
|
||||||
|
break;
|
||||||
|
case LanguageEnum.JAPANESE:
|
||||||
|
setTranslation(Translations_JP);
|
||||||
|
break;
|
||||||
|
case LanguageEnum.PORTUGUESE:
|
||||||
|
setTranslation(Translations_PT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setcurrentLanguage, setTranslation],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
language: currentLanguage,
|
||||||
|
setLanguage: setLanguage,
|
||||||
|
translations: translation,
|
||||||
|
};
|
||||||
|
};
|
||||||
+1
-4
@@ -4,7 +4,6 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { TranslationContext } from './translations/TranslationContext';
|
|
||||||
|
|
||||||
const rootElement = document.getElementById('root');
|
const rootElement = document.getElementById('root');
|
||||||
if (!rootElement) throw new Error('Failed to find the root element');
|
if (!rootElement) throw new Error('Failed to find the root element');
|
||||||
@@ -12,9 +11,7 @@ const root = ReactDOM.createRoot(rootElement);
|
|||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<TranslationContext>
|
<App />
|
||||||
<App />
|
|
||||||
</TranslationContext>
|
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import Translations_EN from './en';
|
|
||||||
import Translations_JP from './jp';
|
|
||||||
import Translations_PT from './pt';
|
|
||||||
|
|
||||||
export interface languageTemplate {
|
|
||||||
no_messages_message: string;
|
|
||||||
ui_settings_title: string;
|
|
||||||
nodes_title: string;
|
|
||||||
color_scheme_title: string;
|
|
||||||
language_title: string;
|
|
||||||
device_settings_title: string;
|
|
||||||
device_channels_title: string;
|
|
||||||
device_region_title: string;
|
|
||||||
device_wifi_ssid: string;
|
|
||||||
device_wifi_psk: string;
|
|
||||||
save_changes_button: string;
|
|
||||||
no_nodes_message: string;
|
|
||||||
no_message_placeholder: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LanguageEnum {
|
|
||||||
ENGLISH,
|
|
||||||
JAPANESE,
|
|
||||||
PORTUGUESE,
|
|
||||||
}
|
|
||||||
|
|
||||||
const Context = React.createContext<{
|
|
||||||
language: LanguageEnum;
|
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
|
||||||
translations: languageTemplate;
|
|
||||||
}>({
|
|
||||||
language: LanguageEnum.ENGLISH,
|
|
||||||
setLanguage: () => {},
|
|
||||||
translations: Translations_EN,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const TranslationContext = ({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}): JSX.Element => {
|
|
||||||
const [language, setLanguage] = React.useState<LanguageEnum>(
|
|
||||||
LanguageEnum.ENGLISH,
|
|
||||||
);
|
|
||||||
const [translation, setTranslation] =
|
|
||||||
React.useState<languageTemplate>(Translations_EN);
|
|
||||||
React.useEffect(() => {
|
|
||||||
switch (language) {
|
|
||||||
case LanguageEnum.ENGLISH:
|
|
||||||
setTranslation(Translations_EN);
|
|
||||||
break;
|
|
||||||
case LanguageEnum.JAPANESE:
|
|
||||||
setTranslation(Translations_JP);
|
|
||||||
break;
|
|
||||||
case LanguageEnum.PORTUGUESE:
|
|
||||||
setTranslation(Translations_PT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}, [language]);
|
|
||||||
return (
|
|
||||||
<Context.Provider
|
|
||||||
value={{
|
|
||||||
language: language,
|
|
||||||
setLanguage: setLanguage,
|
|
||||||
translations: translation,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Context.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Translations_EN from './en';
|
||||||
|
|
||||||
|
export interface languageTemplate {
|
||||||
|
no_messages_message: string;
|
||||||
|
ui_settings_title: string;
|
||||||
|
nodes_title: string;
|
||||||
|
color_scheme_title: string;
|
||||||
|
language_title: string;
|
||||||
|
device_settings_title: string;
|
||||||
|
device_channels_title: string;
|
||||||
|
device_region_title: string;
|
||||||
|
device_wifi_ssid: string;
|
||||||
|
device_wifi_psk: string;
|
||||||
|
save_changes_button: string;
|
||||||
|
no_nodes_message: string;
|
||||||
|
no_message_placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LanguageEnum {
|
||||||
|
ENGLISH,
|
||||||
|
JAPANESE,
|
||||||
|
PORTUGUESE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TranslationsContextData {
|
||||||
|
language: LanguageEnum;
|
||||||
|
setLanguage: (postId: number) => void;
|
||||||
|
translations: languageTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const translationsContextDefaultValue: TranslationsContextData = {
|
||||||
|
language: LanguageEnum.ENGLISH,
|
||||||
|
setLanguage: () => null,
|
||||||
|
translations: Translations_EN,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TranslationsContext = React.createContext<TranslationsContextData>(
|
||||||
|
translationsContextDefaultValue,
|
||||||
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from './TranslationContext';
|
import type { languageTemplate } from './TranslationsContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'No messages yet',
|
no_messages_message: 'No messages yet',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from './TranslationContext';
|
import type { languageTemplate } from './TranslationsContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'まだメッセージはありません',
|
no_messages_message: 'まだメッセージはありません',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from './TranslationContext';
|
import type { languageTemplate } from './TranslationsContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'Não a mensagens ainda',
|
no_messages_message: 'Não a mensagens ainda',
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,6 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"types": ["react/next", "react-dom/next"],
|
|
||||||
/* paths - import rewriting/resolving */
|
/* paths - import rewriting/resolving */
|
||||||
"paths": {
|
"paths": {
|
||||||
// If you configured any Snowpack aliases, add them here.
|
// If you configured any Snowpack aliases, add them here.
|
||||||
@@ -20,6 +19,7 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
"types": ["react/next", "react-dom/next", "snowpack-env"],
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
|||||||
@@ -3302,10 +3302,10 @@ react-flags-select@^2.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
|
|
||||||
react-hook-form@^7.8.4:
|
react-hook-form@^7.8.6:
|
||||||
version "7.8.4"
|
version "7.8.6"
|
||||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.8.4.tgz#4405b242db7b946f387f2a6c01f92390a2564893"
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.8.6.tgz#93335fbada5eae3ddee8f6dffe5bac868295ec4d"
|
||||||
integrity sha512-hVh7uAJZS4/c20kNjW4rW+pD7+4RhuMDF3qY82f8wFuuPkoO+Pg5JHSJUqGdPdlI82snOlZ4DK/avIBn5SxItg==
|
integrity sha512-kKdaySvv21tyH8WM5jYpKRxTFdknmHi7ssdBrU7cW0qRwXcr9lxVyO14MjUFlfEGe9S5VzBmTz7NKNSarV3AFw==
|
||||||
|
|
||||||
react-is@^16.8.1:
|
react-is@^16.8.1:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
@@ -4156,8 +4156,3 @@ yargs@^16.0.0:
|
|||||||
string-width "^4.2.0"
|
string-width "^4.2.0"
|
||||||
y18n "^5.0.5"
|
y18n "^5.0.5"
|
||||||
yargs-parser "^20.2.2"
|
yargs-parser "^20.2.2"
|
||||||
|
|
||||||
yarn@^1.22.10:
|
|
||||||
version "1.22.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.10.tgz#c99daa06257c80f8fa2c3f1490724e394c26b18c"
|
|
||||||
integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA==
|
|
||||||
|
|||||||
Reference in New Issue
Block a user