mirror of https://github.com/cocosolos/ixion.git
Change interfaces to types, adjust theme context
This commit is contained in:
parent
2d1a162100
commit
5d041d5e77
|
|
@ -4,8 +4,8 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||||
import AlertComponent from './components/Alert';
|
import AlertComponent from './components/Alert';
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import SearchState, { SearchStateDefaults } from './data/SearchState';
|
import { SearchState, SearchStateDefaults } from './data/SearchState';
|
||||||
import ServerData from './data/ServerData';
|
import { ServerData } from './data/ServerData';
|
||||||
import About from './pages/About';
|
import About from './pages/About';
|
||||||
import Home from './pages/Home';
|
import Home from './pages/Home';
|
||||||
import NotFound from './pages/NotFound';
|
import NotFound from './pages/NotFound';
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { postData } from '../apiUtil';
|
import { postData } from '../apiUtil';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
import { AlertResponse } from './Alert';
|
import { AlertResponse } from './Alert';
|
||||||
|
|
||||||
const AddServerInput = styled('div')(({ theme }) => ({
|
const AddServerInput = styled('div')(({ theme }) => ({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ToggleButton, ToggleButtonGroup } from '@mui/material';
|
import { ToggleButton, ToggleButtonGroup } from '@mui/material';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
|
|
||||||
const expansions = [
|
const expansions = [
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
import { Brightness4, Brightness7, QuestionMark } from '@mui/icons-material';
|
import { Brightness4, Brightness7, QuestionMark } from '@mui/icons-material';
|
||||||
import { AppBar, Box, Toolbar, Tooltip, useTheme } from '@mui/material';
|
import { AppBar, Box, Toolbar, Tooltip } from '@mui/material';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { ThemeContext } from '../context/ThemeContext';
|
import { ThemeMode, useThemeModeContext } from '../context/ThemeContext';
|
||||||
|
|
||||||
function scrollToTop() {
|
function scrollToTop() {
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' }); // Scrolls to the top of the page smoothly
|
window.scrollTo({ top: 0, behavior: 'smooth' }); // Scrolls to the top of the page smoothly
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
const theme = useTheme();
|
const { themeMode, setThemeMode } = useThemeModeContext();
|
||||||
const { switchColorMode } = useContext(ThemeContext);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className="bottom-0 w-full flex-none">
|
<Box className="bottom-0 w-full flex-none">
|
||||||
|
|
@ -42,12 +40,14 @@ export default function Footer() {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Toggle Theme" arrow disableInteractive>
|
<Tooltip title="Toggle Theme" arrow disableInteractive>
|
||||||
<IconButton onClick={switchColorMode}>
|
<IconButton
|
||||||
{theme.palette.mode === 'dark' ? (
|
onClick={() => {
|
||||||
<Brightness7 />
|
setThemeMode((prev: ThemeMode) =>
|
||||||
) : (
|
prev === 'light' ? 'dark' : 'light'
|
||||||
<Brightness4 />
|
);
|
||||||
)}
|
}}
|
||||||
|
>
|
||||||
|
{themeMode === 'dark' ? <Brightness7 /> : <Brightness4 />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import IconButton from '@mui/material/IconButton';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { fetchDataFromBackend } from '../apiUtil';
|
import { fetchDataFromBackend } from '../apiUtil';
|
||||||
import SearchState from '../data/SearchState';
|
import { SearchState } from '../data/SearchState';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
import AddServer from './AddServer';
|
import AddServer from './AddServer';
|
||||||
import { AlertResponse } from './Alert';
|
import { AlertResponse } from './Alert';
|
||||||
import SearchServers from './SearchServers';
|
import SearchServers from './SearchServers';
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import SearchState from '../data/SearchState';
|
import { SearchState } from '../data/SearchState';
|
||||||
|
|
||||||
export default function SearchServers({
|
export default function SearchServers({
|
||||||
showSearchServer,
|
showSearchServer,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ import {
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import ServerData, {
|
import {
|
||||||
|
ServerData,
|
||||||
ServerSetting,
|
ServerSetting,
|
||||||
ServerSettingsInfo,
|
ServerSettingsInfo,
|
||||||
} from '../data/ServerData';
|
} from '../data/ServerData';
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Card, IconButton, Tooltip, Typography } from '@mui/material';
|
||||||
import Modal from '@mui/material/Modal';
|
import Modal from '@mui/material/Modal';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { fetchDataFromBackend } from '../apiUtil';
|
import { fetchDataFromBackend } from '../apiUtil';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
import ServerSettingsDataGrid from './ServerSettingsDataGrid';
|
import ServerSettingsDataGrid from './ServerSettingsDataGrid';
|
||||||
|
|
||||||
export default function ServerDetailsModal({ id }: { id: number }) {
|
export default function ServerDetailsModal({ id }: { id: number }) {
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@ import {
|
||||||
ServerSettingsInfo,
|
ServerSettingsInfo,
|
||||||
} from '../data/ServerData';
|
} from '../data/ServerData';
|
||||||
|
|
||||||
interface KeyValueRow {
|
type KeyValueRow = {
|
||||||
id: number;
|
id: number;
|
||||||
key: string;
|
key: string;
|
||||||
rawValue: string | number | boolean;
|
rawValue: string | number | boolean;
|
||||||
name: string;
|
name: string;
|
||||||
value: string | number | boolean;
|
value: string | number | boolean;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{ field: 'key', headerName: 'Key', align: 'right', flex: 4 },
|
{ field: 'key', headerName: 'Key', align: 'right', flex: 4 },
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,93 @@
|
||||||
import { useMediaQuery } from '@mui/material';
|
import { useMediaQuery } from '@mui/material';
|
||||||
import { createTheme, StyledEngineProvider } from '@mui/material/styles';
|
import { createTheme, StyledEngineProvider } from '@mui/material/styles';
|
||||||
import ThemeProvider from '@mui/material/styles/ThemeProvider';
|
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 = {
|
export type ThemeMode = 'dark' | 'light';
|
||||||
switchColorMode: () => void;
|
|
||||||
|
type ThemeModeState = {
|
||||||
|
themeMode: ThemeMode;
|
||||||
|
setThemeMode: React.Dispatch<React.SetStateAction<ThemeMode>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ThemeProviderProps = {
|
export const ThemeModeContext = createContext<ThemeModeState | null>(null);
|
||||||
|
|
||||||
|
type ThemeModeContextProviderProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ThemeContext = createContext<ThemeContextType>({
|
export function ThemeContextProvider({
|
||||||
switchColorMode: () => {},
|
children,
|
||||||
});
|
}: ThemeModeContextProviderProps) {
|
||||||
|
|
||||||
export function ThemeContextProvider({ children }: ThemeProviderProps) {
|
|
||||||
const rootElement = document.getElementById('root');
|
const rootElement = document.getElementById('root');
|
||||||
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
|
||||||
const [mode, setMode] = useState<'light' | 'dark'>(() => {
|
const [themeMode, setThemeMode] = useState<ThemeMode>(() => {
|
||||||
const manualTheme = localStorage.getItem('theme');
|
const manualThemeMode = localStorage.getItem('themeMode') as ThemeMode;
|
||||||
if (manualTheme && (manualTheme === 'light' || manualTheme === 'dark')) {
|
if (manualThemeMode) {
|
||||||
return manualTheme;
|
return manualThemeMode;
|
||||||
}
|
}
|
||||||
return prefersDarkMode ? 'dark' : 'light';
|
return prefersDarkMode ? 'dark' : 'light';
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem('theme', mode);
|
localStorage.setItem('themeMode', themeMode as ThemeMode);
|
||||||
}, [mode]);
|
}, [themeMode]);
|
||||||
|
|
||||||
const switchColorMode = () => {
|
const muiTheme = createTheme({
|
||||||
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
|
palette: {
|
||||||
};
|
mode: themeMode,
|
||||||
|
},
|
||||||
const theme = useMemo(
|
// 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.
|
||||||
createTheme({
|
components: {
|
||||||
palette: {
|
MuiPopover: {
|
||||||
mode,
|
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.
|
MuiPopper: {
|
||||||
components: {
|
defaultProps: {
|
||||||
MuiPopover: {
|
container: rootElement,
|
||||||
defaultProps: {
|
|
||||||
container: rootElement,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiPopper: {
|
|
||||||
defaultProps: {
|
|
||||||
container: rootElement,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiDialog: {
|
|
||||||
defaultProps: {
|
|
||||||
container: rootElement,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
MuiModal: {
|
|
||||||
defaultProps: {
|
|
||||||
container: rootElement,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
[rootElement, mode]
|
MuiDialog: {
|
||||||
);
|
defaultProps: {
|
||||||
|
container: rootElement,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiModal: {
|
||||||
|
defaultProps: {
|
||||||
|
container: rootElement,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledEngineProvider injectFirst>
|
<StyledEngineProvider injectFirst>
|
||||||
<ThemeContext.Provider
|
<ThemeModeContext.Provider
|
||||||
value={
|
value={
|
||||||
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
||||||
{ switchColorMode }
|
{ themeMode, setThemeMode }
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ThemeProvider theme={theme}>{children}</ThemeProvider>
|
<ThemeProvider theme={muiTheme}>{children}</ThemeProvider>
|
||||||
</ThemeContext.Provider>
|
</ThemeModeContext.Provider>
|
||||||
</StyledEngineProvider>
|
</StyledEngineProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
export default interface SearchState {
|
export type SearchState = {
|
||||||
name: string;
|
name: string;
|
||||||
multibox: string[] | null;
|
multibox: string[] | null;
|
||||||
trusts: string[] | null;
|
trusts: string[] | null;
|
||||||
levelSync: string[] | null;
|
levelSync: string[] | null;
|
||||||
maxLevel: number[];
|
maxLevel: number[];
|
||||||
expansions: string[] | null;
|
expansions: string[] | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const SearchStateDefaults: SearchState = {
|
export const SearchStateDefaults: SearchState = {
|
||||||
name: '',
|
name: '',
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
import LsbDefaults from '../../../api/defaultLsbSettings.json';
|
import LsbDefaults from '../../../api/defaultLsbSettings.json';
|
||||||
|
|
||||||
export interface ServerSetting {
|
export type ServerSetting = {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
unit?: string;
|
unit?: string;
|
||||||
transform?: (arg: boolean | string | number) => boolean | string | number;
|
transform?: (arg: boolean | string | number) => boolean | string | number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface ServerSettings {
|
export type ServerSettings = {
|
||||||
[key: string]: boolean | string | number;
|
[key: string]: boolean | string | number;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default interface ServerData {
|
export type ServerData = {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
location: string;
|
location: string;
|
||||||
|
|
@ -22,7 +22,7 @@ export default interface ServerData {
|
||||||
active_sessions: number;
|
active_sessions: number;
|
||||||
updated: string;
|
updated: string;
|
||||||
up: boolean;
|
up: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const DemoServerData: ServerData = {
|
export const DemoServerData: ServerData = {
|
||||||
name: 'LandSandBoat Demo',
|
name: 'LandSandBoat Demo',
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import ErrorCard from '../components/ErrorCard';
|
import ErrorCard from '../components/ErrorCard';
|
||||||
import ServerCard from '../components/ServerCard';
|
import ServerCard from '../components/ServerCard';
|
||||||
import SearchState from '../data/SearchState';
|
import { SearchState } from '../data/SearchState';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
|
|
||||||
export default function Home({
|
export default function Home({
|
||||||
servers,
|
servers,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { AlertResponse } from '../components/Alert';
|
||||||
import ErrorCard from '../components/ErrorCard';
|
import ErrorCard from '../components/ErrorCard';
|
||||||
import ExpansionBar from '../components/ExpansionsBar';
|
import ExpansionBar from '../components/ExpansionsBar';
|
||||||
import ServerSettingsDataGrid from '../components/ServerSettingsDataGrid';
|
import ServerSettingsDataGrid from '../components/ServerSettingsDataGrid';
|
||||||
import ServerData from '../data/ServerData';
|
import { ServerData } from '../data/ServerData';
|
||||||
import CopyImageIcon from '../images/copy-image.png';
|
import CopyImageIcon from '../images/copy-image.png';
|
||||||
|
|
||||||
export default function ServerDetails({
|
export default function ServerDetails({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue