diff --git a/client/src/App.tsx b/client/src/App.tsx index 167ea1a..e003023 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -4,8 +4,8 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom'; import AlertComponent from './components/Alert'; import Footer from './components/Footer'; import Header from './components/Header'; -import SearchState, { SearchStateDefaults } from './data/SearchState'; -import ServerData from './data/ServerData'; +import { SearchState, SearchStateDefaults } from './data/SearchState'; +import { ServerData } from './data/ServerData'; import About from './pages/About'; import Home from './pages/Home'; import NotFound from './pages/NotFound'; diff --git a/client/src/components/AddServer.tsx b/client/src/components/AddServer.tsx index 86b14f0..bbf4300 100644 --- a/client/src/components/AddServer.tsx +++ b/client/src/components/AddServer.tsx @@ -12,7 +12,7 @@ import { import { useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { postData } from '../apiUtil'; -import ServerData from '../data/ServerData'; +import { ServerData } from '../data/ServerData'; import { AlertResponse } from './Alert'; const AddServerInput = styled('div')(({ theme }) => ({ diff --git a/client/src/components/ExpansionsBar.tsx b/client/src/components/ExpansionsBar.tsx index c8d98c0..823da03 100644 --- a/client/src/components/ExpansionsBar.tsx +++ b/client/src/components/ExpansionsBar.tsx @@ -1,5 +1,5 @@ import { ToggleButton, ToggleButtonGroup } from '@mui/material'; -import ServerData from '../data/ServerData'; +import { ServerData } from '../data/ServerData'; const expansions = [ @@ -42,12 +40,14 @@ export default function Footer() { - - {theme.palette.mode === 'dark' ? ( - - ) : ( - - )} + { + setThemeMode((prev: ThemeMode) => + prev === 'light' ? 'dark' : 'light' + ); + }} + > + {themeMode === 'dark' ? : } diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx index 2f2fd60..16f60df 100644 --- a/client/src/components/Header.tsx +++ b/client/src/components/Header.tsx @@ -11,8 +11,8 @@ import IconButton from '@mui/material/IconButton'; import { useCallback, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { fetchDataFromBackend } from '../apiUtil'; -import SearchState from '../data/SearchState'; -import ServerData from '../data/ServerData'; +import { SearchState } from '../data/SearchState'; +import { ServerData } from '../data/ServerData'; import AddServer from './AddServer'; import { AlertResponse } from './Alert'; import SearchServers from './SearchServers'; diff --git a/client/src/components/SearchServers.tsx b/client/src/components/SearchServers.tsx index 7cb0c30..1c430d6 100644 --- a/client/src/components/SearchServers.tsx +++ b/client/src/components/SearchServers.tsx @@ -10,7 +10,7 @@ import { Typography, } from '@mui/material'; import { useEffect, useRef, useState } from 'react'; -import SearchState from '../data/SearchState'; +import { SearchState } from '../data/SearchState'; export default function SearchServers({ showSearchServer, diff --git a/client/src/components/ServerCard.tsx b/client/src/components/ServerCard.tsx index e22569f..aad877a 100644 --- a/client/src/components/ServerCard.tsx +++ b/client/src/components/ServerCard.tsx @@ -22,7 +22,8 @@ import { } from '@mui/material'; import { useState } from 'react'; import { Link } from 'react-router-dom'; -import ServerData, { +import { + ServerData, ServerSetting, ServerSettingsInfo, } from '../data/ServerData'; diff --git a/client/src/components/ServerDetailsModal.tsx b/client/src/components/ServerDetailsModal.tsx index 638bafb..c5359e5 100644 --- a/client/src/components/ServerDetailsModal.tsx +++ b/client/src/components/ServerDetailsModal.tsx @@ -3,7 +3,7 @@ import { Card, IconButton, Tooltip, Typography } from '@mui/material'; import Modal from '@mui/material/Modal'; import { useState } from 'react'; import { fetchDataFromBackend } from '../apiUtil'; -import ServerData from '../data/ServerData'; +import { ServerData } from '../data/ServerData'; import ServerSettingsDataGrid from './ServerSettingsDataGrid'; export default function ServerDetailsModal({ id }: { id: number }) { diff --git a/client/src/components/ServerSettingsDataGrid.tsx b/client/src/components/ServerSettingsDataGrid.tsx index 8696ae7..0e6371e 100644 --- a/client/src/components/ServerSettingsDataGrid.tsx +++ b/client/src/components/ServerSettingsDataGrid.tsx @@ -6,14 +6,14 @@ import { ServerSettingsInfo, } from '../data/ServerData'; -interface KeyValueRow { +type KeyValueRow = { id: number; key: string; rawValue: string | number | boolean; name: string; value: string | number | boolean; description: string; -} +}; const columns: GridColDef[] = [ { field: 'key', headerName: 'Key', align: 'right', flex: 4 }, diff --git a/client/src/context/ThemeContext.tsx b/client/src/context/ThemeContext.tsx index 005fb7b..3271184 100644 --- a/client/src/context/ThemeContext.tsx +++ b/client/src/context/ThemeContext.tsx @@ -1,83 +1,93 @@ import { useMediaQuery } from '@mui/material'; import { createTheme, StyledEngineProvider } from '@mui/material/styles'; import ThemeProvider from '@mui/material/styles/ThemeProvider'; -import { createContext, ReactNode, useEffect, useMemo, useState } from 'react'; +import React, { + createContext, + ReactNode, + useContext, + useEffect, + useState, +} from 'react'; -type ThemeContextType = { - switchColorMode: () => void; +export type ThemeMode = 'dark' | 'light'; + +type ThemeModeState = { + themeMode: ThemeMode; + setThemeMode: React.Dispatch>; }; -type ThemeProviderProps = { +export const ThemeModeContext = createContext(null); + +type ThemeModeContextProviderProps = { children: ReactNode; }; -export const ThemeContext = createContext({ - switchColorMode: () => {}, -}); - -export function ThemeContextProvider({ children }: ThemeProviderProps) { +export function ThemeContextProvider({ + children, +}: ThemeModeContextProviderProps) { const rootElement = document.getElementById('root'); const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); - const [mode, setMode] = useState<'light' | 'dark'>(() => { - const manualTheme = localStorage.getItem('theme'); - if (manualTheme && (manualTheme === 'light' || manualTheme === 'dark')) { - return manualTheme; + const [themeMode, setThemeMode] = useState(() => { + const manualThemeMode = localStorage.getItem('themeMode') as ThemeMode; + if (manualThemeMode) { + return manualThemeMode; } return prefersDarkMode ? 'dark' : 'light'; }); useEffect(() => { - localStorage.setItem('theme', mode); - }, [mode]); + localStorage.setItem('themeMode', themeMode as ThemeMode); + }, [themeMode]); - const switchColorMode = () => { - setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light')); - }; - - const theme = useMemo( - () => - createTheme({ - palette: { - mode, + const muiTheme = createTheme({ + palette: { + mode: themeMode, + }, + // All `Portal`-related components need to have the the main app wrapper element as a container + // so that they are in the subtree under the element used in the `important` option of the Tailwind's config. + components: { + MuiPopover: { + defaultProps: { + container: rootElement, }, - // All `Portal`-related components need to have the the main app wrapper element as a container - // so that they are in the subtree under the element used in the `important` option of the Tailwind's config. - components: { - MuiPopover: { - defaultProps: { - container: rootElement, - }, - }, - MuiPopper: { - defaultProps: { - container: rootElement, - }, - }, - MuiDialog: { - defaultProps: { - container: rootElement, - }, - }, - MuiModal: { - defaultProps: { - container: rootElement, - }, - }, + }, + MuiPopper: { + defaultProps: { + container: rootElement, }, - }), - [rootElement, mode] - ); + }, + MuiDialog: { + defaultProps: { + container: rootElement, + }, + }, + MuiModal: { + defaultProps: { + container: rootElement, + }, + }, + }, + }); return ( - - {children} - + {children} + ); } + +// eslint-disable-next-line react-refresh/only-export-components +export function useThemeModeContext() { + const context = useContext(ThemeModeContext); + if (!context) { + throw new Error('Theme context error.'); + } + return context; +} diff --git a/client/src/data/SearchState.tsx b/client/src/data/SearchState.tsx index 9d0606e..0622673 100644 --- a/client/src/data/SearchState.tsx +++ b/client/src/data/SearchState.tsx @@ -1,11 +1,11 @@ -export default interface SearchState { +export type SearchState = { name: string; multibox: string[] | null; trusts: string[] | null; levelSync: string[] | null; maxLevel: number[]; expansions: string[] | null; -} +}; export const SearchStateDefaults: SearchState = { name: '', diff --git a/client/src/data/ServerData.tsx b/client/src/data/ServerData.tsx index 8aa4116..1283ed0 100644 --- a/client/src/data/ServerData.tsx +++ b/client/src/data/ServerData.tsx @@ -1,17 +1,17 @@ import LsbDefaults from '../../../api/defaultLsbSettings.json'; -export interface ServerSetting { +export type ServerSetting = { name: string; description: string; unit?: string; transform?: (arg: boolean | string | number) => boolean | string | number; -} +}; -export interface ServerSettings { +export type ServerSettings = { [key: string]: boolean | string | number; -} +}; -export default interface ServerData { +export type ServerData = { name: string; url: string; location: string; @@ -22,7 +22,7 @@ export default interface ServerData { active_sessions: number; updated: string; up: boolean; -} +}; export const DemoServerData: ServerData = { name: 'LandSandBoat Demo', diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 3136f43..da47c6d 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -1,8 +1,8 @@ import { Box } from '@mui/material'; import ErrorCard from '../components/ErrorCard'; import ServerCard from '../components/ServerCard'; -import SearchState from '../data/SearchState'; -import ServerData from '../data/ServerData'; +import { SearchState } from '../data/SearchState'; +import { ServerData } from '../data/ServerData'; export default function Home({ servers, diff --git a/client/src/pages/ServerDetails.tsx b/client/src/pages/ServerDetails.tsx index 4397764..babb6b6 100644 --- a/client/src/pages/ServerDetails.tsx +++ b/client/src/pages/ServerDetails.tsx @@ -22,7 +22,7 @@ import { AlertResponse } from '../components/Alert'; import ErrorCard from '../components/ErrorCard'; import ExpansionBar from '../components/ExpansionsBar'; import ServerSettingsDataGrid from '../components/ServerSettingsDataGrid'; -import ServerData from '../data/ServerData'; +import { ServerData } from '../data/ServerData'; import CopyImageIcon from '../images/copy-image.png'; export default function ServerDetails({