Vibe-code дизайн dark theme re-vibecode
This commit is contained in:
parent
63455578b1
commit
b603732dd6
BIN
public/images/dowdelogo.png
Normal file
BIN
public/images/dowdelogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
128
src/App.tsx
128
src/App.tsx
@ -4,14 +4,16 @@ import {
|
|||||||
AppBar,
|
AppBar,
|
||||||
Box,
|
Box,
|
||||||
Container,
|
Container,
|
||||||
createTheme,
|
IconButton,
|
||||||
ThemeProvider,
|
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Typography,
|
Typography,
|
||||||
useTheme
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { useNavigate, BrowserRouter } from "react-router-dom";
|
||||||
import { MyRoutes } from "./Routes";
|
import { MyRoutes } from "./Routes";
|
||||||
import { styled } from '@mui/material/styles';
|
import { styled } from '@mui/material/styles';
|
||||||
|
import { ThemeProvider as CustomThemeProvider, useThemeContext } from './context/ThemeContext';
|
||||||
|
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||||
|
import LightModeIcon from '@mui/icons-material/LightMode';
|
||||||
|
|
||||||
// Styled components
|
// Styled components
|
||||||
const StyledAppBar = styled(AppBar)(({ theme }) => ({
|
const StyledAppBar = styled(AppBar)(({ theme }) => ({
|
||||||
@ -20,12 +22,20 @@ const StyledAppBar = styled(AppBar)(({ theme }) => ({
|
|||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledAppBarLight = styled(AppBar)(({ theme }) => ({
|
||||||
|
background: 'linear-gradient(135deg, #ffffff 0%, #f0f0f0 50%, #e0e0e0 100%)',
|
||||||
|
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)',
|
||||||
|
borderBottom: '1px solid rgba(0, 0, 0, 0.1)',
|
||||||
|
}));
|
||||||
|
|
||||||
const LogoText = styled(Typography)(({ theme }) => ({
|
const LogoText = styled(Typography)(({ theme }) => ({
|
||||||
fontSize: '1.5rem',
|
fontSize: '1.5rem',
|
||||||
fontWeight: 800,
|
fontWeight: 800,
|
||||||
background: 'linear-gradient(135deg, #e94560 0%, #ff6b6b 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(135deg, #dee2e6 0%, #cccccc 100%)'
|
||||||
|
: 'linear-gradient(135deg, #1a1a2e 0%, #333333 100%)',
|
||||||
WebkitBackgroundClip: 'text',
|
WebkitBackgroundClip: 'text',
|
||||||
WebkitTextFillColor: 'transparent',
|
WebkitTextFillColor: theme.palette.mode === 'dark' ? '#dee2e6' : '#1a1a2e',
|
||||||
letterSpacing: '-0.5px',
|
letterSpacing: '-0.5px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
@ -34,68 +44,78 @@ const LogoText = styled(Typography)(({ theme }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function App() {
|
const ThemeToggle = styled(IconButton)(({ theme }) => ({
|
||||||
const theme = useTheme();
|
color: 'inherit',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const themeConfig = createTheme({
|
const ThemeToggleLight = styled(IconButton)(({ theme }) => ({
|
||||||
breakpoints: {
|
color: 'inherit',
|
||||||
values: {
|
'&:hover': {
|
||||||
xs: 0,
|
backgroundColor: 'rgba(0, 0, 0, 0.05)',
|
||||||
sm: 600,
|
},
|
||||||
md: 900,
|
}));
|
||||||
lg: 1320,
|
|
||||||
xl: 1536,
|
function AppBarContent() {
|
||||||
},
|
const { mode, toggleTheme } = useThemeContext();
|
||||||
},
|
const navigate = useNavigate();
|
||||||
palette: {
|
const isDark = mode === 'dark';
|
||||||
primary: {
|
|
||||||
main: "#1a1a2e",
|
const handleLogoClick = () => navigate('/');
|
||||||
},
|
|
||||||
background: {
|
|
||||||
default: '#0a0a0a',
|
|
||||||
paper: '#1a1a2e',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
typography: {
|
|
||||||
fontFamily: '"Inter", "Roboto", "Helvetica", sans-serif',
|
|
||||||
},
|
|
||||||
shape: {
|
|
||||||
borderRadius: 12,
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MuiTableCell: {
|
|
||||||
styleOverrides: {
|
|
||||||
root: {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ minHeight: '100vh', backgroundColor: '#0a0a0a' }}>
|
<>
|
||||||
<ThemeProvider theme={themeConfig}>
|
{isDark ? (
|
||||||
<a href="/">
|
|
||||||
<StyledAppBar position="sticky">
|
<StyledAppBar position="sticky">
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
<Toolbar disableGutters sx={{ justifyContent: 'space-between' }}>
|
<Toolbar disableGutters sx={{ justifyContent: 'space-between' }}>
|
||||||
{/* Left side - Logo */}
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
<LogoText variant="h6" sx={{ textDecoration: 'none' }}>
|
<img src="/images/dowdelogo.png" alt="logo" style={{ height: 32, cursor: 'pointer' }} onClick={handleLogoClick}/>
|
||||||
🎮 Autogenerated wiki
|
<LogoText variant="h6" sx={{ textDecoration: 'none', cursor: 'pointer' }} onClick={handleLogoClick}>
|
||||||
|
Autogenerated wiki
|
||||||
</LogoText>
|
</LogoText>
|
||||||
</Box>
|
</Box>
|
||||||
|
<ThemeToggle onClick={toggleTheme} size="large">
|
||||||
|
<LightModeIcon />
|
||||||
|
</ThemeToggle>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</Container>
|
</Container>
|
||||||
</StyledAppBar>
|
</StyledAppBar>
|
||||||
</a>
|
) : (
|
||||||
|
<StyledAppBarLight position="sticky">
|
||||||
|
<Container maxWidth="lg">
|
||||||
|
<Toolbar disableGutters sx={{ justifyContent: 'space-between' }}>
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||||
|
<img src="/images/dowdelogo.png" alt="logo" style={{ height: 32, cursor: 'pointer' }} onClick={handleLogoClick}/>
|
||||||
|
<LogoText variant="h6" sx={{ textDecoration: 'none', cursor: 'pointer' }} onClick={handleLogoClick}>
|
||||||
|
Autogenerated wiki
|
||||||
|
</LogoText>
|
||||||
|
</Box>
|
||||||
|
<ThemeToggleLight onClick={toggleTheme} size="large">
|
||||||
|
<DarkModeIcon />
|
||||||
|
</ThemeToggleLight>
|
||||||
|
</Toolbar>
|
||||||
|
</Container>
|
||||||
|
</StyledAppBarLight>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
function App() {
|
||||||
<MyRoutes />
|
return (
|
||||||
</Container>
|
<CustomThemeProvider>
|
||||||
</ThemeProvider>
|
<Box sx={{ minHeight: '100vh' }}>
|
||||||
</Box>
|
<BrowserRouter>
|
||||||
|
<AppBarContent />
|
||||||
|
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||||
|
<MyRoutes />
|
||||||
|
</Container>
|
||||||
|
</BrowserRouter>
|
||||||
|
</Box>
|
||||||
|
</CustomThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {Routes, Route, BrowserRouter} from "react-router-dom";
|
import {Routes, Route} from "react-router-dom";
|
||||||
import ModsPage from "./pages/ModsPage";
|
import ModsPage from "./pages/ModsPage";
|
||||||
import ModPage from "./pages/ModPage";
|
import ModPage from "./pages/ModPage";
|
||||||
import RacePageFast from "./pages/RacePageFast";
|
import RacePageFast from "./pages/RacePageFast";
|
||||||
@ -8,14 +8,12 @@ import BuildingPage from "./pages/BuildingPage";
|
|||||||
export const MyRoutes = () => {
|
export const MyRoutes = () => {
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<BrowserRouter>
|
<Routes>
|
||||||
<Routes>
|
|
||||||
<Route path="/" element={<ModsPage/>}/>
|
<Route path="/" element={<ModsPage/>}/>
|
||||||
<Route path="/mod/:modId" element={<ModPage/>}/>
|
<Route path="/mod/:modId" element={<ModPage/>}/>
|
||||||
<Route path="/mod/:modId/race/:raceId" element={<RacePageFast/>}/>
|
<Route path="/mod/:modId/race/:raceId" element={<RacePageFast/>}/>
|
||||||
<Route path="/mod/:modId/race/:raceId/unit/:unitId" element={<UnitPage/>}/>
|
<Route path="/mod/:modId/race/:raceId/unit/:unitId" element={<UnitPage/>}/>
|
||||||
<Route path="/mod/:modId/race/:raceId/building/:buildingId" element={<BuildingPage/>}/>
|
<Route path="/mod/:modId/race/:raceId/building/:buildingId" element={<BuildingPage/>}/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -20,18 +20,18 @@ function Ability(props: IAbilityProps){
|
|||||||
|
|
||||||
return <div className='addon-research-accordion' id={"research-" + ability.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
return <div className='addon-research-accordion' id={"research-" + ability.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
sx={{color: '#dee2e6', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
|
expandIcon={<ExpandMore sx={{color: '#dee2e6'}}/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20, color: '#dee2e6', display: 'flex', alignItems: 'center'}}>
|
||||||
{ability.activationType === "Passive ability" ? <img className="abilityIcon" src="/images/PassiveIcon.gif"/> : <img className="abilityIcon" src={getIcon(ability.icon)}/>}
|
{ability.activationType === "Passive ability" ? <img className="abilityIcon" src="/images/PassiveIcon.gif"/> : <img className="abilityIcon" src={getIcon(ability.icon)}/>}
|
||||||
{ability.name ? ability.name : ability.fileName.charAt(0).toUpperCase() + ability.fileName.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
{ability.name ? ability.name : ability.fileName.charAt(0).toUpperCase() + ability.fileName.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
||||||
<i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> ({ability.activationType})</i>
|
<i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> ({ability.activationType})</i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails sx={{color: '#dee2e6'}}>
|
||||||
<AbilityFull abilityId={ability.id} mod={props.mod} race={props.race} />
|
<AbilityFull abilityId={ability.id} mod={props.mod} race={props.race} />
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</StyledAccordion></div>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import ArmorTypeNames from "../types/ArmorTypeValues";
|
|||||||
import {
|
import {
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
Grid2,
|
Grid2,
|
||||||
Paper,
|
|
||||||
styled,
|
styled,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -28,6 +27,7 @@ import ability from "./Ability";
|
|||||||
import AbilitySpawnedObject from "./AbilitySpawnedObject";
|
import AbilitySpawnedObject from "./AbilitySpawnedObject";
|
||||||
import DpsTable from "./DpsTable";
|
import DpsTable from "./DpsTable";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
|
|
||||||
interface IAbilityFullState {
|
interface IAbilityFullState {
|
||||||
ability?: IAbilityFill;
|
ability?: IAbilityFill;
|
||||||
@ -42,36 +42,22 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.15)',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
borderBottom: `2px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)'}`,
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
color: '#dee2e6',
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
if(props.abilityFull !== undefined){
|
if(props.abilityFull !== undefined){
|
||||||
@ -108,11 +94,11 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
const showTargetTable = !showDpsTable && ability.abilityEnvironment == null && (ability.targetFilter.length > 0 || ability.radius !== 0)
|
const showTargetTable = !showDpsTable && ability.abilityEnvironment == null && (ability.targetFilter.length > 0 || ability.radius !== 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div style={{color: '#dee2e6'}}>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12}}>
|
<Grid2 size={{xs: 12}}>
|
||||||
{ability.initialDelayTime !== undefined && props.isChild === true &&
|
{ability.initialDelayTime !== undefined && props.isChild === true &&
|
||||||
<b><br/><center style={{color: 'rgba(255,255,255,0.7)'}}> After {ability.initialDelayTime.toFixed(1)}s
|
<b><br/><center style={{color: '#dee2e6'}}> After {ability.initialDelayTime.toFixed(1)}s
|
||||||
<img style={{verticalAlign: "top"}}
|
<img style={{verticalAlign: "top"}}
|
||||||
src="/images/Time_icon.webp"/></center></b>}
|
src="/images/Time_icon.webp"/></center></b>}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
@ -215,7 +201,7 @@ export default function AbilityFull(props: { abilityId?: number, mod: IMod, race
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
{showDpsTable ?
|
{showDpsTable ?
|
||||||
<Grid2 size={12}>
|
<Grid2 size={12}>
|
||||||
{(ability.refreshTime !== undefined && ability.durationTime !== undefined && ability.refreshTime * 2 < ability.durationTime) && <i style={{color: 'rgba(255,255,255,0.7)'}}>Every <b style={{color: '#ffffff'}}>{ability.refreshTime.toFixed(1)}s</b> deal damege:</i>}
|
{(ability.refreshTime !== undefined && ability.durationTime !== undefined && ability.refreshTime * 2 < ability.durationTime) && <i style={{color: '#dee2e6'}}>Every <b style={{color: '#dee2e6'}}>{ability.refreshTime.toFixed(1)}s</b> deal damege:</i>}
|
||||||
<DpsTable mod={props.mod} minDamageValue={ability.minDamageValue} minDamage={ability.minDamage} maxDamage={ability.maxDamage} piercings={ability.piercings} targetFilter={ability.targetFilter} moraleDamage={ability.moraleDamage}
|
<DpsTable mod={props.mod} minDamageValue={ability.minDamageValue} minDamage={ability.minDamage} maxDamage={ability.maxDamage} piercings={ability.piercings} targetFilter={ability.targetFilter} moraleDamage={ability.moraleDamage}
|
||||||
/>
|
/>
|
||||||
</Grid2> : showTargetTable ?
|
</Grid2> : showTargetTable ?
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary, Grid2, Paper,
|
AccordionSummary, Grid2,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell, TableContainer,
|
TableCell, TableContainer,
|
||||||
@ -24,6 +24,7 @@ import Ability from "./Ability";
|
|||||||
import DeathExplosion from "./DeathExplosion";
|
import DeathExplosion from "./DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
const SectionTitle = styled(Typography)(({ theme }) => ({
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
@ -31,20 +32,6 @@ const SectionTitle = styled(Typography)(({ theme }) => ({
|
|||||||
fontSize: '1.25rem',
|
fontSize: '1.25rem',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface AbilityEnvironmentProps {
|
interface AbilityEnvironmentProps {
|
||||||
abilityEnvironment: IAbilityEnvironment,
|
abilityEnvironment: IAbilityEnvironment,
|
||||||
@ -56,7 +43,7 @@ function AbilitySpawnedObject(props: AbilityEnvironmentProps) {
|
|||||||
|
|
||||||
const abilityEnvironment = props.abilityEnvironment
|
const abilityEnvironment = props.abilityEnvironment
|
||||||
|
|
||||||
return <div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
return <div style={{color: '#dee2e6'}}>
|
||||||
<SectionTitle>
|
<SectionTitle>
|
||||||
{props.abilityEnvironment.name ?? props.abilityEnvironment.filename.charAt(0).toUpperCase() + props.abilityEnvironment.filename.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
{props.abilityEnvironment.name ?? props.abilityEnvironment.filename.charAt(0).toUpperCase() + props.abilityEnvironment.filename.slice(1).replaceAll('_', ' ').replace('.rgd', '')}
|
||||||
<i style={{fontSize: 11, color: 'rgba(255,255,255,0.5)'}}> (Spawned object)</i>
|
<i style={{fontSize: 11, color: 'rgba(255,255,255,0.5)'}}> (Spawned object)</i>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary, Grid2, Paper,
|
AccordionSummary, Grid2,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell, TableContainer, TableHead,
|
TableCell, TableContainer, TableHead,
|
||||||
@ -24,22 +24,9 @@ import Required from "./Required";
|
|||||||
import ArmorTypeNames from "../types/ArmorTypeValues";
|
import ArmorTypeNames from "../types/ArmorTypeValues";
|
||||||
import DpsTable from "./DpsTable";
|
import DpsTable from "./DpsTable";
|
||||||
import {StyledAccordion} from "../commons/StyledAccordion";
|
import {StyledAccordion} from "../commons/StyledAccordion";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
import {styled} from "@mui/material/styles";
|
import {styled} from "@mui/material/styles";
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface DeathExpProps {
|
interface DeathExpProps {
|
||||||
deathExplosion: IDeathExplosion,
|
deathExplosion: IDeathExplosion,
|
||||||
@ -54,15 +41,15 @@ function DeathExplosion(props: DeathExpProps) {
|
|||||||
return chanceTotalNotZero ?
|
return chanceTotalNotZero ?
|
||||||
<div className='addon-research-accordion' id='death-explosion'><StyledAccordion>
|
<div className='addon-research-accordion' id='death-explosion'><StyledAccordion>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
sx={{color: '#dee2e6', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
|
expandIcon={<ExpandMore sx={{color: '#dee2e6'}}/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20, color: '#dee2e6', display: 'flex', alignItems: 'center'}}>
|
||||||
Death Explosion
|
Death Explosion
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails sx={{color: '#dee2e6'}}>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={StyledPaper} elevation={0}>
|
||||||
|
|||||||
@ -19,17 +19,17 @@ export default function DpsTable(props: { mod: IMod, minDamageValue?: number, mi
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.15)',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
borderBottom: `2px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)'}`,
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
color: '#dee2e6',
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,17 +8,7 @@ import {IMod} from "../types/Imod";
|
|||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
import {StyledLink} from "../commons/StyledLink";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
// Styled components for dark theme
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface IModifiersProvidesTable {
|
interface IModifiersProvidesTable {
|
||||||
@ -162,8 +152,8 @@ export function ModifiersProvidesAddonTable(props: IModifiersProvidesTable) {
|
|||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModName(m.reference)}</TableCell>
|
<TableCell component="th" scope="row" sx={{color: '#dee2e6'}}>{getModName(m.reference)}</TableCell>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}</TableCell>
|
<TableCell component="th" scope="row" sx={{color: '#dee2e6'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</Table>
|
</Table>
|
||||||
@ -247,9 +237,9 @@ export function ModifiersProvidesTable(props: IModifiersProvidesResearchTable) {
|
|||||||
<TableRow
|
<TableRow
|
||||||
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
||||||
>
|
>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getTarget(m.target)}</TableCell>
|
<TableCell component="th" scope="row" sx={{color: '#dee2e6'}}>{getTarget(m.target)}</TableCell>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)', minWidth: 120}}>{getModName(m.reference)}</TableCell>
|
<TableCell component="th" scope="row" sx={{color: '#dee2e6', minWidth: 120}}>{getModName(m.reference)}</TableCell>
|
||||||
<TableCell component="th" scope="row" sx={{color: 'rgba(255,255,255,0.85)'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}
|
<TableCell component="th" scope="row" sx={{color: '#dee2e6'}}>{getModIcon(m.reference)} {getChangeDescription(m.usageType, m.value)}
|
||||||
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 &&
|
{m.maxLifeTime !== undefined && m.maxLifeTime > 0 &&
|
||||||
<span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s
|
<span><img style={{verticalAlign: "top"}} src='/images/Time_icon.webp'/>{m.maxLifeTime}s
|
||||||
</span>}
|
</span>}
|
||||||
|
|||||||
@ -115,20 +115,20 @@ function Required (props: IRequiredProps) {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div style={{color: '#dee2e6'}}>
|
||||||
<h4 style={{color: '#ffffff', fontWeight: 700}}>Required: </h4>
|
<h4 style={{color: '#dee2e6', fontWeight: 700}}>Required: </h4>
|
||||||
{requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null &&
|
{requirement.requiredTotalPop !== undefined && requirement.requiredTotalPop !== null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Population: <img style={{verticalAlign: "top", height: 25}}
|
<div style={{color: '#dee2e6'}}> Population: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src="/images/Resource_orksquadcap.gif"/>
|
src="/images/Resource_orksquadcap.gif"/>
|
||||||
{requirement.requiredTotalPop}</div>
|
{requirement.requiredTotalPop}</div>
|
||||||
}
|
}
|
||||||
{requirement.mobBonus !== null && requirement.mobBonus !== undefined &&
|
{requirement.mobBonus !== null && requirement.mobBonus !== undefined &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Mob requirement: <img style={{verticalAlign: "top", height: 25}}
|
<div style={{color: '#dee2e6'}}> Mob requirement: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src="/images/Mob_bonus.gif"/>
|
src="/images/Mob_bonus.gif"/>
|
||||||
{requirement.mobBonus.mobvalueRequired} in radius {requirement.mobBonus.proximityRequired}</div>
|
{requirement.mobBonus.mobvalueRequired} in radius {requirement.mobBonus.proximityRequired}</div>
|
||||||
}
|
}
|
||||||
{requirement.requireAddon !== null &&
|
{requirement.requireAddon !== null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}> Addon: <img style={{verticalAlign: "top", height: 25}}
|
<div style={{color: '#dee2e6'}}> Addon: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + requirement.requireAddon.icon.replaceAll('\\', '/')}/>
|
||||||
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirement.requireAddon.buildingId}#addon-${requirement.requireAddon.id}`}>
|
<StyledLink href={`/mod/${props.modId}/race/${props.raceId}/building/${requirement.requireAddon.buildingId}#addon-${requirement.requireAddon.id}`}>
|
||||||
{requirement.requireAddon.name}
|
{requirement.requireAddon.name}
|
||||||
@ -137,26 +137,26 @@ function Required (props: IRequiredProps) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{requirement.requirementAddonExclusive != null &&
|
{requirement.requirementAddonExclusive != null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequiremenAddonExclusive(requirement.requirementAddonExclusive,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequiremenAddonExclusive(requirement.requirementAddonExclusive,)}</div>}
|
||||||
{requirement.requirementBuildings.map(b =>
|
{requirement.requirementBuildings.map(b =>
|
||||||
<div key={b.id} style={{color: 'rgba(255, 255, 255, 0.85)'}}> Building: <img style={{verticalAlign: "top", height: 25}}
|
<div key={b.id} style={{color: '#dee2e6'}}> Building: <img style={{verticalAlign: "top", height: 25}}
|
||||||
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
src={IconUrl + b.icon.replaceAll('\\', '/')}/>
|
||||||
<StyledLink href= {'/mod/'+ props.modId +'/race/'+ props.raceId +'/building/' + b.id + "/"}>{b.name}</StyledLink></div>)
|
<StyledLink href= {'/mod/'+ props.modId +'/race/'+ props.raceId +'/building/' + b.id + "/"}>{b.name}</StyledLink></div>)
|
||||||
}
|
}
|
||||||
{requirement.requirementResearches.length !== 0 &&
|
{requirement.requirementResearches.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementResearches(requirement.requirementResearches,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequirementResearches(requirement.requirementResearches,)}</div>}
|
||||||
{requirement.requirementSquads.length !== 0 &&
|
{requirement.requirementSquads.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementSquads(requirement.requirementSquads,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequirementSquads(requirement.requirementSquads,)}</div>}
|
||||||
{requirement.requirementResearchesEither.length !== 0 &&
|
{requirement.requirementResearchesEither.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementResearchesEither(requirement.requirementResearchesEither,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequirementResearchesEither(requirement.requirementResearchesEither,)}</div>}
|
||||||
{requirement.requirementBuildingsEither.length !== 0 &&
|
{requirement.requirementBuildingsEither.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementBuildingEither(requirement.requirementBuildingsEither,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequirementBuildingEither(requirement.requirementBuildingsEither,)}</div>}
|
||||||
{requirement.requirementStructureExclusive != null &&
|
{requirement.requirementStructureExclusive != null &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequiremenStructureExclusive(requirement.requirementStructureExclusive,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequiremenStructureExclusive(requirement.requirementStructureExclusive,)}</div>}
|
||||||
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && <div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderLimitPerBuilding(requirement.limitByBuilding)}</div>}
|
{requirement.limitByBuilding !== undefined && requirement.limitByBuilding !== null && <div style={{color: '#dee2e6'}}>{renderLimitPerBuilding(requirement.limitByBuilding)}</div>}
|
||||||
{requirement.requirementsGlobalAddons.length !== 0 &&
|
{requirement.requirementsGlobalAddons.length !== 0 &&
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}</div>}
|
<div style={{color: '#dee2e6'}}>{renderRequirementGlobalAddons(requirement.requirementsGlobalAddons,)}</div>}
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>{renderRequirementOwnership(requirement.requiredOwnership)}</div>
|
<div style={{color: '#dee2e6'}}>{renderRequirementOwnership(requirement.requiredOwnership)}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {ISergeant, IShortWeapon} from "../types/IUnit";
|
import {ISergeant, IShortWeapon} from "../types/IUnit";
|
||||||
import {Grid2, Paper, Table, TableBody, TableCell, TableContainer, TableRow, Tooltip, Typography} from "@mui/material";
|
import {Grid2, Table, TableBody, TableCell, TableContainer, TableRow, Tooltip, Typography} from "@mui/material";
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
import ArmorType from "./ArmorType";
|
import ArmorType from "./ArmorType";
|
||||||
import WeaponSlot from "./WeaponSlot";
|
import WeaponSlot from "./WeaponSlot";
|
||||||
@ -14,20 +14,7 @@ import Ability from "./Ability";
|
|||||||
import DeathExplosion from "./DeathExplosion";
|
import DeathExplosion from "./DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const SectionTitle = styled(Typography)(({ theme }) => ({
|
const SectionTitle = styled(Typography)(({ theme }) => ({
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
@ -60,7 +47,7 @@ const Sergeant = (props: SergeantProps) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div style={{color: '#dee2e6'}}>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size= {{xs: 12, md: 4}}>
|
<Grid2 size= {{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={StyledPaper} elevation={0}>
|
||||||
|
|||||||
@ -5,30 +5,22 @@ import {styled} from '@mui/material/styles';
|
|||||||
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
||||||
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
import {StyledLink} from "../commons/StyledLink";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
|
|
||||||
// Styled components for dark theme
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledTable = styled(Table)(({ theme }) => ({
|
const StyledTable = styled(Table)(({ theme }) => ({
|
||||||
'& .MuiTableCell-head': {
|
'& .MuiTableCell-head': {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.15)',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
borderBottom: `2px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)'}`,
|
||||||
},
|
},
|
||||||
'& .MuiTableCell-body': {
|
'& .MuiTableCell-body': {
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
color: theme.palette.text.primary,
|
||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
|
borderBottom: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)'}`,
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
},
|
},
|
||||||
'& .MuiTableRow-hover:hover': {
|
'& .MuiTableRow-hover:hover': {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.08)',
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(233, 69, 96, 0.08)',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -36,7 +28,7 @@ const StyledHeaderLink = styled(StyledLink)(({ theme }) => ({
|
|||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
color: '#e94560',
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@ -37,21 +37,21 @@ class Weapon extends React.Component<IWeaponProps, any> {
|
|||||||
return (
|
return (
|
||||||
<div style={{marginBottom: 10}}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
<div style={{marginBottom: 10}}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore sx={{color: '#dee2e6'}}/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
id="panel1-header"
|
id="panel1-header"
|
||||||
sx={{color: '#ffffff'}}
|
sx={{color: '#dee2e6', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 18, color: '#ffffff'}}> {!this.props.isDefault && weapon.icon && !weapon.icon.endsWith("upgrade.png") ?
|
<span style={{fontSize: 18, color: '#dee2e6', display: 'flex', alignItems: 'center'}}> {!this.props.isDefault && weapon.icon && !weapon.icon.endsWith("upgrade.png") ?
|
||||||
<img className="weaponIcon" src={IconUrl + weapon.icon.replaceAll('\\', '/')}/> : (
|
<img className="weaponIcon" src={IconUrl + weapon.icon.replaceAll('\\', '/')}/> : (
|
||||||
weapon.isMeleeWeapon ?
|
weapon.isMeleeWeapon ?
|
||||||
<img className="weaponIcon" src="/images/MeleeStance_icon_bw.jpg"/> :
|
<img className="weaponIcon" src="/images/MeleeStance_icon_bw.jpg"/> :
|
||||||
<img className="weaponIcon" src="/images/RangedStance_icon_bw.jpg"/>
|
<img className="weaponIcon" src="/images/RangedStance_icon_bw.jpg"/>
|
||||||
)} {weapon.name ? weapon.name : this.humanReadableName(weapon.filename)}
|
)} {weapon.name ? weapon.name : this.humanReadableName(weapon.filename)}
|
||||||
{this.props.isDefault && <i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> (default)</i>}
|
{this.props.isDefault && <i style={{fontSize: 12, color: 'rgba(255,255,255,0.5)'}}> (default)</i>}
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails sx={{color: '#dee2e6'}}>
|
||||||
<WeaponFull weaponId={weapon.id} isDefault={this.props.isDefault} mod={this.props.mod} race={this.props.race} haveReinforceMenu={this.props.haveReinforceMenu}/>
|
<WeaponFull weaponId={weapon.id} isDefault={this.props.isDefault} mod={this.props.mod} race={this.props.race} haveReinforceMenu={this.props.haveReinforceMenu}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</StyledAccordion></div>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import ArmorTypeNames from "../types/ArmorTypeValues";
|
|||||||
import {
|
import {
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
Grid2,
|
Grid2,
|
||||||
Paper,
|
|
||||||
styled,
|
styled,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -23,6 +22,7 @@ import {IRaceUnits} from "../types/IUnitShort";
|
|||||||
import {IRaceBuildings} from "../types/IBuildingShort";
|
import {IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
import {ModifiersProvidesTable} from "./ModifiersProvideTable";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../commons/StyledPaper";
|
||||||
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
||||||
|
|
||||||
interface IWeaponFull {
|
interface IWeaponFull {
|
||||||
@ -39,35 +39,21 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
const StyledTableCell = styled(TableCell)(({theme}) => ({
|
||||||
[`&.${tableCellClasses.head}`]: {
|
[`&.${tableCellClasses.head}`]: {
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.15)',
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.15)',
|
||||||
marginRight: 'auto',
|
marginRight: 'auto',
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
borderBottom: '2px solid rgba(233, 69, 96, 0.3)',
|
borderBottom: `2px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)'}`,
|
||||||
},
|
},
|
||||||
[`&.${tableCellClasses.body}`]: {
|
[`&.${tableCellClasses.body}`]: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
color: '#dee2e6',
|
||||||
paddingRight: 18,
|
paddingRight: 18,
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
fetch(WeaponUrl + "/" + props.mod.id + "/" + props.weaponId)
|
fetch(WeaponUrl + "/" + props.mod.id + "/" + props.weaponId)
|
||||||
@ -151,7 +137,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<div style={{color: '#dee2e6'}}>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{!props.isDefault && <Grid2 size={12}>
|
{!props.isDefault && <Grid2 size={12}>
|
||||||
<DescriptionBox>
|
<DescriptionBox>
|
||||||
@ -262,8 +248,8 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
sx={{ mb: 2 }}
|
sx={{ mb: 2 }}
|
||||||
>
|
>
|
||||||
<ToggleButton size="small" value="dps" sx={{ color: '#ffffff', '&.Mui-selected': { borderColor: '#e94560', color: '#e94560', backgroundColor: 'rgba(233, 69, 96, 0.15)' } }}>Dps</ToggleButton>
|
<ToggleButton size="small" value="dps" sx={{ color: '#dee2e6', '&.Mui-selected': { borderColor: '#dee2e6', color: '#dee2e6', backgroundColor: 'rgba(255, 255, 255, 0.15)' } }}>Dps</ToggleButton>
|
||||||
<ToggleButton size="small" value="one hit" sx={{ color: '#ffffff', '&.Mui-selected': {borderColor: '#e94560', color: '#e94560', backgroundColor: 'rgba(233, 69, 96, 0.15)' } }}>One hit average damage</ToggleButton>
|
<ToggleButton size="small" value="one hit" sx={{ color: '#dee2e6', '&.Mui-selected': {borderColor: '#dee2e6', color: '#dee2e6', backgroundColor: 'rgba(255, 255, 255, 0.15)' } }}>One hit average damage</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
{ props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
|
{ props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
|
||||||
@ -327,7 +313,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
||||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||||
src="/images/ARM_Morale.webp"/>
|
src="/images/ARM_Morale.webp"/>
|
||||||
<div style={{width: 20, fontSize: 12, height: 50, color: 'rgba(255,255,255,0.7)'}}>
|
<div style={{width: 20, fontSize: 12, height: 50, color: '#dee2e6'}}>
|
||||||
<i>Morale</i></div>
|
<i>Morale</i></div>
|
||||||
</StyledTableCell>
|
</StyledTableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -381,7 +367,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
||||||
<StyledTableCell><img style={{verticalAlign: "top"}}
|
<StyledTableCell><img style={{verticalAlign: "top"}}
|
||||||
src="/images/ARM_Morale.webp"/>
|
src="/images/ARM_Morale.webp"/>
|
||||||
<div style={{width: 20, fontSize: 12, height: 50, color: 'rgba(255,255,255,0.7)'}}>
|
<div style={{width: 20, fontSize: 12, height: 50, color: '#dee2e6'}}>
|
||||||
<i>Morale</i></div>
|
<i>Morale</i></div>
|
||||||
</StyledTableCell>
|
</StyledTableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -413,7 +399,7 @@ export default function WeaponFull(props: {weaponId: number, isDefault: Boolean,
|
|||||||
|
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{weapon.modifiers.length > 0 && <Grid2 size={12}>
|
{weapon.modifiers.length > 0 && <Grid2 size={12}>
|
||||||
<h3 style={{color: '#ffffff', fontWeight: 700}}>Modifiers</h3>
|
<h3 style={{color: '#dee2e6', fontWeight: 700}}>Modifiers</h3>
|
||||||
<ModifiersProvidesTable modifiers={weapon.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
<ModifiersProvidesTable modifiers={weapon.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
{weapon.requirements !== null && !props.isDefault && props.haveReinforceMenu &&
|
{weapon.requirements !== null && !props.isDefault && props.haveReinforceMenu &&
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
Grid2,
|
Grid2,
|
||||||
Paper,
|
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
@ -19,24 +18,10 @@ import {getIcon, ModifiersProvidesTable,} from "../ModifiersProvideTable";
|
|||||||
import Required from "../Required";
|
import Required from "../Required";
|
||||||
import {StyledAccordion} from "../../commons/StyledAccordion";
|
import {StyledAccordion} from "../../commons/StyledAccordion";
|
||||||
import {DescriptionBox} from "../../commons/DescriptionBox";
|
import {DescriptionBox} from "../../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../../commons/StyledPaper";
|
||||||
import {styled} from "@mui/material/styles";
|
import {styled} from "@mui/material/styles";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface IBuildingAddonProps {
|
interface IBuildingAddonProps {
|
||||||
addon: IBuildingAddon,
|
addon: IBuildingAddon,
|
||||||
building: IBuilding,
|
building: IBuilding,
|
||||||
@ -52,16 +37,16 @@ function BuildingAddon(props: IBuildingAddonProps){
|
|||||||
|
|
||||||
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><StyledAccordion>
|
return <div className='addon-research-accordion' id={"addon-" + addon.id} ><StyledAccordion>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
sx={{color: '#dee2e6', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
|
expandIcon={<ExpandMore sx={{color: '#dee2e6'}}/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20, color: '#dee2e6', display: 'flex', alignItems: 'center'}}>
|
||||||
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
|
<img className="sergeantIcon" src={getIcon(addon.icon)}/>
|
||||||
{addon.name}
|
{addon.name}
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails sx={{color: '#dee2e6'}}>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<TableContainer component={StyledPaper} elevation={0}>
|
<TableContainer component={StyledPaper} elevation={0}>
|
||||||
|
|||||||
@ -23,10 +23,10 @@ import {StyledAccordion} from "../../commons/StyledAccordion";
|
|||||||
import {styled} from "@mui/material/styles";
|
import {styled} from "@mui/material/styles";
|
||||||
|
|
||||||
const StyledLink = styled('a')(({ theme }) => ({
|
const StyledLink = styled('a')(({ theme }) => ({
|
||||||
color: '#e94560',
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560',
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
color: '#ff6b6b',
|
color: theme.palette.mode === 'dark' ? '#cccccc' : '#ff6b6b',
|
||||||
textDecoration: 'underline',
|
textDecoration: 'underline',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@ -45,16 +45,16 @@ function Research(props: IResearchProps){
|
|||||||
|
|
||||||
return <div className='addon-research-accordion' id={"research-" + research.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
return <div className='addon-research-accordion' id={"research-" + research.id}><StyledAccordion TransitionProps={{ unmountOnExit: true, timeout: 100 }}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
sx={{color: '#dee2e6', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
|
expandIcon={<ExpandMore sx={{color: '#dee2e6'}}/>}
|
||||||
aria-controls="panel1-content"
|
aria-controls="panel1-content"
|
||||||
sx={{color: '#ffffff'}}
|
|
||||||
>
|
>
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20, color: '#dee2e6', display: 'flex', alignItems: 'center'}}>
|
||||||
<img className="sergeantIcon" src={getIcon(research.icon)}/>
|
<img className="sergeantIcon" src={getIcon(research.icon)}/>
|
||||||
{research.name}
|
{research.name}
|
||||||
</span>
|
</span>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255,255,255,0.85)'}}>
|
<AccordionDetails sx={{color: '#dee2e6'}}>
|
||||||
<ResearchFull id={research.id} building={building}/>
|
<ResearchFull id={research.id} building={building}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</StyledAccordion></div>
|
</StyledAccordion></div>
|
||||||
@ -71,7 +71,7 @@ export function renderAffectedResearches(researches: IResearchShort[], modId: nu
|
|||||||
</StyledLink></span>
|
</StyledLink></span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div style={{color: 'rgba(255, 255, 255, 0.85)'}}> {researches.map(rs =>
|
return <div style={{color: '#dee2e6'}}> {researches.map(rs =>
|
||||||
rs.buildingId == null ? <span key={rs.id}></span> :
|
rs.buildingId == null ? <span key={rs.id}></span> :
|
||||||
<span key={rs.id}>Research affect: {researchLink(rs)}<br/></span>
|
<span key={rs.id}>Research affect: {researchLink(rs)}<br/></span>
|
||||||
)}</div>
|
)}</div>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
Grid2,
|
Grid2,
|
||||||
Paper,
|
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
@ -24,20 +23,7 @@ import {ResearchUrl, WeaponUrl} from "../../core/api";
|
|||||||
import {IWeapon} from "../../types/IUnit";
|
import {IWeapon} from "../../types/IUnit";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
import {DescriptionBox} from "../../commons/DescriptionBox";
|
import {DescriptionBox} from "../../commons/DescriptionBox";
|
||||||
|
import {StyledPaper} from "../../commons/StyledPaper";
|
||||||
const StyledPaper = styled(Paper)(({ theme }) => ({
|
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
},
|
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
|
||||||
color: '#e94560',
|
|
||||||
fontWeight: 600,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
interface IResearchFull {
|
interface IResearchFull {
|
||||||
|
|||||||
@ -3,12 +3,12 @@ import {styled} from '@mui/material/styles';
|
|||||||
|
|
||||||
export const BackButton = styled(Button)(({ theme }) => ({
|
export const BackButton = styled(Button)(({ theme }) => ({
|
||||||
marginBottom: theme.spacing(3),
|
marginBottom: theme.spacing(3),
|
||||||
color: '#e94560BB',
|
color: '#FFD700',
|
||||||
borderColor: 'rgba(233, 69, 96, 0.5)',
|
borderColor: 'rgba(255, 215, 0, 0.5)',
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
borderColor: '#e94560',
|
borderColor: '#FFD700',
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.1)',
|
backgroundColor: 'rgba(255, 215, 0, 0.1)',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
|
||||||
export const DescriptionBox = styled('div')(({ theme }) => ({
|
export const DescriptionBox = styled('div')(({ theme }) => ({
|
||||||
color: 'rgba(255, 255, 255, 0.85)',
|
color: theme.palette.text.primary,
|
||||||
lineHeight: 1.7,
|
lineHeight: 1.7,
|
||||||
fontSize: '0.95rem',
|
fontSize: '0.95rem',
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
background: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.03)' : 'rgba(0, 0, 0, 0.03)',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)'}`,
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
}));
|
}));
|
||||||
@ -2,8 +2,10 @@ import {Accordion} from '@mui/material';
|
|||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
|
||||||
export const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
export const StyledAccordion = styled(Accordion)(({ theme }) => ({
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
'&:before': { display: 'none' },
|
'&:before': { display: 'none' },
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
||||||
|
|||||||
@ -2,11 +2,11 @@ import {Link} from "@mui/material";
|
|||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
|
||||||
export const StyledLink = styled(Link)(({ theme }) => ({
|
export const StyledLink = styled(Link)(({ theme }) => ({
|
||||||
color: '#e94560BB',
|
color: theme.palette.mode === 'dark' ? '#abc3ff' : '#e94560BB',
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
transition: 'all 0.2s ease',
|
transition: 'all 0.2s ease',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
color: '#ff6b6bBB',
|
color: theme.palette.mode === 'dark' ? '#ffffff' : '#ff6b6bBB',
|
||||||
textDecoration: 'underline',
|
textDecoration: 'underline',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
19
src/commons/StyledPaper.tsx
Normal file
19
src/commons/StyledPaper.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import {Paper} from '@mui/material';
|
||||||
|
import {styled} from '@mui/material/styles';
|
||||||
|
|
||||||
|
export const StyledPaper = styled(Paper)(({ theme }) => ({
|
||||||
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
|
borderRadius: '12px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
},
|
||||||
|
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
||||||
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560',
|
||||||
|
fontWeight: 600,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
48
src/context/ThemeContext.tsx
Normal file
48
src/context/ThemeContext.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||||
|
import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
|
||||||
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
|
import { darkTheme, lightTheme } from '../themes/theme';
|
||||||
|
|
||||||
|
type ThemeMode = 'dark' | 'light';
|
||||||
|
|
||||||
|
interface ThemeContextType {
|
||||||
|
mode: ThemeMode;
|
||||||
|
toggleTheme: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
||||||
|
|
||||||
|
|
||||||
|
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const [mode, setMode] = useState<ThemeMode>(() => {
|
||||||
|
const saved = localStorage.getItem('theme');
|
||||||
|
return (saved === 'light' ? 'light' : 'dark') as ThemeMode;
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem('theme', mode);
|
||||||
|
}, [mode]);
|
||||||
|
|
||||||
|
const toggleTheme = () => {
|
||||||
|
setMode(prev => prev === 'dark' ? 'light' : 'dark');
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = mode === 'dark' ? darkTheme : lightTheme;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ mode, toggleTheme }}>
|
||||||
|
<MuiThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
|
{children}
|
||||||
|
</MuiThemeProvider>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useThemeContext = () => {
|
||||||
|
const context = useContext(ThemeContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('useThemeContext must be used within a ThemeProvider');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@ -1,4 +1,7 @@
|
|||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
export const UserUrl = process.env.REACT_APP_HOST_URL + '/api/v1/user';
|
export const UserUrl = process.env.REACT_APP_HOST_URL + '/api/v1/user';
|
||||||
export const WeaponUrl = process.env.REACT_APP_HOST_URL + '/api/v1/weapon';
|
export const WeaponUrl = process.env.REACT_APP_HOST_URL + '/api/v1/weapon';
|
||||||
export const AbilityUrl = process.env.REACT_APP_HOST_URL + '/api/v1/ability';
|
export const AbilityUrl = process.env.REACT_APP_HOST_URL + '/api/v1/ability';
|
||||||
@ -8,3 +11,11 @@ export const AvailableRacesPart = process.env.REACT_APP_HOST_URL + '/api/v1/race
|
|||||||
export const AvailableUnits = process.env.REACT_APP_HOST_URL + '/api/v1/units';
|
export const AvailableUnits = process.env.REACT_APP_HOST_URL + '/api/v1/units';
|
||||||
export const AvailableBuildings = process.env.REACT_APP_HOST_URL + '/api/v1/buildings';
|
export const AvailableBuildings = process.env.REACT_APP_HOST_URL + '/api/v1/buildings';
|
||||||
export const IconUrl = process.env.REACT_APP_HOST_URL + '/api/v1/grapics/icon/';
|
export const IconUrl = process.env.REACT_APP_HOST_URL + '/api/v1/grapics/icon/';
|
||||||
|
|
||||||
|
export function withTheme(Component) {
|
||||||
|
return function WithTheme(props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
return <Component theme={theme} {...props} />;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,35 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-primary: #0a0a0a;
|
||||||
|
--bg-secondary: #1a1a2e;
|
||||||
|
--bg-tertiary: #16213e;
|
||||||
|
--text-primary: #dee2e6;
|
||||||
|
--text-secondary: #dee2e6;
|
||||||
|
--text-muted: rgba(255, 255, 255, 0.5);
|
||||||
|
--border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
--border-light: rgba(255, 255, 255, 0.05);
|
||||||
|
--card-bg: rgba(255, 255, 255, 0.03);
|
||||||
|
--accent: #dee2e6;
|
||||||
|
--accent-light: #cccccc;
|
||||||
|
--scrollbar-track: #1a1a2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.light-theme {
|
||||||
|
--bg-primary: #f5f5f5;
|
||||||
|
--bg-secondary: #ffffff;
|
||||||
|
--bg-tertiary: #e8e8e8;
|
||||||
|
--text-primary: rgba(0, 0, 0, 0.85);
|
||||||
|
--text-secondary: rgba(0, 0, 0, 0.6);
|
||||||
|
--text-muted: rgba(0, 0, 0, 0.5);
|
||||||
|
--border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
--border-light: rgba(0, 0, 0, 0.05);
|
||||||
|
--card-bg: rgba(0, 0, 0, 0.03);
|
||||||
|
--accent: #e94560;
|
||||||
|
--accent-light: #ff6b6b;
|
||||||
|
--scrollbar-track: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
@ -7,8 +37,12 @@ body {
|
|||||||
sans-serif;
|
sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
background-color: #0a0a0a;
|
background-color: var(--bg-primary);
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.light-theme code {
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@ -21,7 +55,7 @@ code {
|
|||||||
|
|
||||||
* {
|
* {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: #e94560 #1a1a2e;
|
scrollbar-color: var(--accent) var(--scrollbar-track);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
@ -29,11 +63,11 @@ code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
*::-webkit-scrollbar-track {
|
||||||
background: #1a1a2e;
|
background: var(--scrollbar-track);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: #e94560;
|
background-color: var(--accent);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography, LinearProgress
|
Typography, LinearProgress, Theme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import ArmorType from "../classes/ArmorType";
|
import ArmorType from "../classes/ArmorType";
|
||||||
import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer';
|
import AvTimerOutlinedIcon from '@mui/icons-material/AvTimer';
|
||||||
@ -34,6 +34,7 @@ import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
|||||||
import Ability from "../classes/Ability";
|
import Ability from "../classes/Ability";
|
||||||
import DeathExplosion from "../classes/DeathExplosion";
|
import DeathExplosion from "../classes/DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
import {withTheme} from "../core/api";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
import {ArrowBack} from "@mui/icons-material";
|
import {ArrowBack} from "@mui/icons-material";
|
||||||
import {BackButton} from "../commons/BackButton";
|
import {BackButton} from "../commons/BackButton";
|
||||||
@ -46,51 +47,80 @@ const SectionTitle = styled(Typography)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const StatsPaper = styled(Paper)(({ theme }) => ({
|
const StatsPaper = styled(Paper)(({ theme }) => ({
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-root': {
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
||||||
color: '#e94560',
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledDivider = styled(Divider)(({ theme }) => ({
|
||||||
|
my: 3,
|
||||||
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BuildingTitle = styled(Typography)(({ theme }) => ({
|
||||||
|
fontWeight: 800,
|
||||||
|
mb: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 2,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BuildingSubtitle = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
fontWeight: 500,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UnitLink = styled(Link)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': { color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560' },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UnitListItem = styled(ListItem)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
padding: '8px 12px',
|
||||||
|
background: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.03)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)'}`,
|
||||||
|
transition: 'all 0.2s ease',
|
||||||
|
'&:hover': { background: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(233, 69, 96, 0.1)', borderColor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : 'rgba(233, 69, 96, 0.3)' },
|
||||||
|
}));
|
||||||
|
|
||||||
interface UintPageState {
|
interface UintPageState {
|
||||||
building: IBuilding,
|
building: IBuilding,
|
||||||
mod: IMod,
|
mod: IMod,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Unit (unit: IUnitShort, modId: number, raceId: String) {
|
function Unit (unit: IUnitShort, modId: number, raceId: String, theme: Theme) {
|
||||||
|
|
||||||
return (<Grid2 key={unit.id} size={{xs: 12, md: 3}}>
|
return (<Grid2 key={unit.id} size={{xs: 12, md: 3}}>
|
||||||
<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id} sx={{color: 'rgba(255,255,255,0.85)', textDecoration: 'none', '&:hover': {color: '#e94560'}}}>
|
<UnitLink href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
||||||
<ListItem sx={{
|
<UnitListItem>
|
||||||
color: 'rgba(255,255,255,0.85)',
|
|
||||||
padding: '8px 12px',
|
|
||||||
background: 'rgba(255,255,255,0.03)',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
'&:hover': { background: 'rgba(233, 69, 96, 0.1)', borderColor: 'rgba(233, 69, 96, 0.3)' }
|
|
||||||
}}>
|
|
||||||
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/> }
|
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/> }
|
||||||
{unit.name}
|
{unit.name}
|
||||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
src="/images/DETECT_YES.webp"/></span>}
|
src="/images/DETECT_YES.webp"/></span>}
|
||||||
</ListItem>
|
</UnitListItem>
|
||||||
</Link>
|
</UnitLink>
|
||||||
</Grid2>)
|
</Grid2>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Building(building: IBuilding, mod: IMod) {
|
function Building(building: IBuilding, mod: IMod, theme: Theme) {
|
||||||
|
|
||||||
document.title = building.name + " — " + mod.name
|
document.title = building.name + " — " + mod.name
|
||||||
|
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
|
||||||
let mapBuildingWeapons: Map<number, Map<number, IShortWeapon>> = new Map();
|
let mapBuildingWeapons: Map<number, Map<number, IShortWeapon>> = new Map();
|
||||||
|
|
||||||
@ -113,23 +143,14 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box sx={{ mb: 3 }}>
|
<Box sx={{ mb: 3 }}>
|
||||||
<Typography variant="h4" component="h2" sx={{
|
<BuildingTitle variant="h4">
|
||||||
fontWeight: 800,
|
|
||||||
mb: 1,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 2,
|
|
||||||
}}>
|
|
||||||
{building.icon &&
|
{building.icon &&
|
||||||
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
|
<img className="unitIcon" src={IconUrl + building.icon.replaceAll('\\', '/')}/>}
|
||||||
{buildingName}
|
{buildingName}
|
||||||
</Typography>
|
</BuildingTitle>
|
||||||
<Typography variant="subtitle1" sx={{
|
<BuildingSubtitle variant="subtitle1">
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
{mod.name} ({mod.version})
|
{mod.name} ({mod.version})
|
||||||
</Typography>
|
</BuildingSubtitle>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Grid2 container spacing={3}>
|
<Grid2 container spacing={3}>
|
||||||
@ -232,7 +253,7 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
<SectionTitle>Unit production</SectionTitle>
|
<SectionTitle>Unit production</SectionTitle>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{building.units.map(unit =>
|
{building.units.map(unit =>
|
||||||
Unit(unit, mod.id, building.race.id)
|
Unit(unit, mod.id, building.race.id, theme)
|
||||||
)}
|
)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>}
|
</Grid2>}
|
||||||
@ -271,7 +292,7 @@ function Building(building: IBuilding, mod: IMod) {
|
|||||||
</Grid2>
|
</Grid2>
|
||||||
<b className="hotkey" >Hotkey: {building.hotkey}</b>
|
<b className="hotkey" >Hotkey: {building.hotkey}</b>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Divider sx={{ my: 3, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
<StyledDivider />
|
||||||
<UnitsTable modId={mod.id}/>
|
<UnitsTable modId={mod.id}/>
|
||||||
</Box>)
|
</Box>)
|
||||||
}
|
}
|
||||||
@ -298,9 +319,10 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
|||||||
|
|
||||||
if (this.state != null && this.state.building != null && this.state.mod != null) {
|
if (this.state != null && this.state.building != null && this.state.mod != null) {
|
||||||
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
||||||
|
const { theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg">
|
||||||
<BackButton
|
<BackButton
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
startIcon={<ArrowBack/>}
|
startIcon={<ArrowBack/>}
|
||||||
@ -308,7 +330,7 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
|||||||
>
|
>
|
||||||
Back to race
|
Back to race
|
||||||
</BackButton>
|
</BackButton>
|
||||||
{Building(this.state.building, this.state.mod)}
|
{Building(this.state.building, this.state.mod, theme)}
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -321,4 +343,4 @@ class BuildingPage extends React.Component<any, UintPageState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(BuildingPage);
|
export default withRouter(withTheme(BuildingPage));
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
import {AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import {withRouter} from "../core/withrouter";
|
import {withRouter} from "../core/withrouter";
|
||||||
|
import {withTheme} from "../core/api";
|
||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {
|
import {
|
||||||
ArrowBack,
|
ArrowBack,
|
||||||
@ -19,6 +20,12 @@ import UnitsTable from "../classes/UnitsTable";
|
|||||||
import {BackButton} from "../commons/BackButton";
|
import {BackButton} from "../commons/BackButton";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const ModNotFound = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
interface ModPageState {
|
interface ModPageState {
|
||||||
mod: IMod | null,
|
mod: IMod | null,
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
@ -60,6 +67,7 @@ class ModPage extends React.Component<any, ModPageState> {
|
|||||||
|
|
||||||
if (this.state != null && this.state.mod != null) {
|
if (this.state != null && this.state.mod != null) {
|
||||||
document.title = this.state.mod.name + " — ModWiki";
|
document.title = this.state.mod.name + " — ModWiki";
|
||||||
|
const isDark = this.props.theme.palette.mode === 'dark';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
@ -71,12 +79,20 @@ class ModPage extends React.Component<any, ModPageState> {
|
|||||||
Back to mods list
|
Back to mods list
|
||||||
</BackButton>
|
</BackButton>
|
||||||
|
|
||||||
<Typography variant="h6" sx={{
|
<Typography variant="h3" component="h1" sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
fontWeight: 800,
|
||||||
fontWeight: 500,
|
mb: 1,
|
||||||
paddingBottom: 1
|
WebkitBackgroundClip: isDark ? 'text' : 'initial',
|
||||||
|
WebkitTextFillColor: isDark ? '#dee2e6' : 'initial',
|
||||||
|
color: isDark ? '#dee2e6' : '#000000',
|
||||||
}}>
|
}}>
|
||||||
{this.state.mod.name} ({this.state.mod.version})
|
{this.state.mod.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h6" sx={{
|
||||||
|
color: this.props.theme.palette.text.secondary,
|
||||||
|
fontWeight: 500,
|
||||||
|
}}>
|
||||||
|
({this.state.mod.version})
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
@ -87,9 +103,9 @@ class ModPage extends React.Component<any, ModPageState> {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 8, textAlign: 'center' }}>
|
<Container maxWidth="lg" sx={{ py: 8, textAlign: 'center' }}>
|
||||||
<Typography variant="h5" sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>
|
<ModNotFound variant="h5">
|
||||||
Mod not found
|
Mod not found
|
||||||
</Typography>
|
</ModNotFound>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -98,4 +114,4 @@ class ModPage extends React.Component<any, ModPageState> {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default withRouter(ModPage);
|
export default withRouter(withTheme(ModPage));
|
||||||
|
|||||||
@ -23,7 +23,9 @@ import { styled } from '@mui/material/styles';
|
|||||||
const PageHeader = styled(Paper)(({ theme }) => ({
|
const PageHeader = styled(Paper)(({ theme }) => ({
|
||||||
padding: theme.spacing(6, 4),
|
padding: theme.spacing(6, 4),
|
||||||
marginBottom: theme.spacing(6),
|
marginBottom: theme.spacing(6),
|
||||||
background: 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)'
|
||||||
|
: 'linear-gradient(135deg, #ffffff 0%, #f0f0f0 50%, #e0e0e0 100%)',
|
||||||
borderRadius: '16px',
|
borderRadius: '16px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
@ -34,7 +36,7 @@ const PageHeader = styled(Paper)(({ theme }) => ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
background: 'radial-gradient(circle at 30% 50%, rgba(233, 69, 96, 0.1) 0%, transparent 50%)',
|
background: 'radial-gradient(circle at 30% 50%, rgba(255, 255, 255, 0.05) 0%, #dee2e6 50%)',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@ -43,8 +45,10 @@ const ModCard = styled(Card)(({ theme }) => ({
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
borderRadius: '16px',
|
borderRadius: '16px',
|
||||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@ -56,14 +60,15 @@ const ModCard = styled(Card)(({ theme }) => ({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: '3px',
|
height: '3px',
|
||||||
background: 'linear-gradient(90deg, #e94560 0%, #ff6b6b 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(90deg, #dee2e6 0%, #cccccc 100%)'
|
||||||
|
: 'linear-gradient(90deg, #e94560 0%, #ff6b6b 100%)',
|
||||||
transform: 'scaleX(0)',
|
transform: 'scaleX(0)',
|
||||||
transition: 'transform 0.3s ease',
|
transition: 'transform 0.3s ease',
|
||||||
},
|
},
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
transform: 'translateY(-8px)',
|
boxShadow: theme.palette.mode === 'dark' ? '0 20px 40px rgba(255, 255, 255, 0.1)' : '0 20px 40px rgba(233, 69, 96, 0.2)',
|
||||||
boxShadow: '0 20px 40px rgba(233, 69, 96, 0.2)',
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)',
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
|
||||||
'&::before': {
|
'&::before': {
|
||||||
transform: 'scaleX(1)',
|
transform: 'scaleX(1)',
|
||||||
},
|
},
|
||||||
@ -75,16 +80,79 @@ const VersionLink = styled(NavLink)(({ theme }) => ({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: theme.spacing(1.5, 2),
|
padding: theme.spacing(1.5, 2),
|
||||||
marginBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
background: 'rgba(255, 255, 255, 0.05)',
|
background: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
color: 'inherit',
|
color: 'inherit',
|
||||||
transition: 'all 0.2s ease',
|
transition: 'all 0.2s ease',
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
background: 'rgba(233, 69, 96, 0.15)',
|
background: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.15)',
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)',
|
||||||
transform: 'translateX(4px)',
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ModTitle = styled(Typography)(({ theme }) => ({
|
||||||
|
fontWeight: 700,
|
||||||
|
mb: 1,
|
||||||
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(135deg, #dee2e6 0%, #e0e0e0 100%)'
|
||||||
|
: 'linear-gradient(135deg, #000000 0%, #333333 100%)',
|
||||||
|
WebkitBackgroundClip: theme.palette.mode === 'dark' ? 'text' : 'initial',
|
||||||
|
WebkitTextFillColor: theme.palette.mode === 'dark' ? '#dee2e6' : 'initial',
|
||||||
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#000000',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ModDescription = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
lineHeight: 1.6,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const VersionsChip = styled(Chip)(({ theme }) => ({
|
||||||
|
backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.15)' : 'rgba(233, 69, 96, 0.2)',
|
||||||
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#ff6b6b',
|
||||||
|
fontWeight: 600,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledDivider = styled(Divider)(({ theme }) => ({
|
||||||
|
my: 2,
|
||||||
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const MainVersionsLabel = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
fontWeight: 600,
|
||||||
|
mb: 1.5,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const VersionText = styled(Typography)(({ theme }) => ({
|
||||||
|
fontWeight: 600,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const VersionArrow = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BetaVersionsLabel = styled(Typography)(({ theme }) => ({
|
||||||
|
color: 'rgba(255, 193, 7, 0.9)',
|
||||||
|
fontWeight: 600,
|
||||||
|
mb: 1,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const OpenLatestButton = styled(Button)(({ theme }) => ({
|
||||||
|
width: '100%',
|
||||||
|
color: '#FFD700',
|
||||||
|
borderColor: 'rgba(255, 215, 0, 0.5)',
|
||||||
|
fontWeight: 600,
|
||||||
|
borderRadius: '10px',
|
||||||
|
textTransform: 'none',
|
||||||
|
fontSize: '1rem',
|
||||||
|
py: 1.5,
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: '#FFD700',
|
||||||
|
backgroundColor: 'rgba(255, 215, 0, 0.1)',
|
||||||
|
boxShadow: '0 8px 20px rgba(255, 215, 0, 0.2)',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -128,88 +196,48 @@ function Mods({ mods }: ModsProps) {
|
|||||||
const { latest, hasBeta, betaVersion } = getLatestVersion(modName);
|
const { latest, hasBeta, betaVersion } = getLatestVersion(modName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModCard sx={{ animationDelay: `${index * 100}ms` }}>
|
<ModCard>
|
||||||
<CardContent sx={{ flexGrow: 1, p: 3 }}>
|
<CardContent sx={{ flexGrow: 1, p: 3 }}>
|
||||||
<Box sx={{ mb: 2 }}>
|
<Box sx={{ mb: 2 }}>
|
||||||
<Typography variant="h5" component="h2" sx={{
|
<ModTitle variant="h5">
|
||||||
fontWeight: 700,
|
|
||||||
mb: 1,
|
|
||||||
background: 'linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%)',
|
|
||||||
WebkitBackgroundClip: 'text',
|
|
||||||
WebkitTextFillColor: 'transparent',
|
|
||||||
}}>
|
|
||||||
{modName}
|
{modName}
|
||||||
</Typography>
|
</ModTitle>
|
||||||
<Typography variant="body2" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
|
||||||
lineHeight: 1.6,
|
|
||||||
}}>
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
||||||
<Chip
|
<VersionsChip
|
||||||
label={`${sameMods.length} versions`}
|
label={`${sameMods.length} versions`}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.2)',
|
|
||||||
color: '#ff6b6b',
|
|
||||||
fontWeight: 600,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{hasBeta && (
|
|
||||||
<Chip
|
|
||||||
label="Beta"
|
|
||||||
size="small"
|
|
||||||
color="warning"
|
|
||||||
sx={{ fontWeight: 600 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Divider sx={{ my: 2, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
|
||||||
|
|
||||||
<Typography variant="subtitle2" sx={{
|
|
||||||
color: 'rgba(255, 255, 255, 0.9)',
|
|
||||||
fontWeight: 600,
|
|
||||||
mb: 1.5,
|
|
||||||
}}>
|
|
||||||
Main versions:
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{sameMods.filter(m => !m.isBeta).map(mod => (
|
{sameMods.filter(m => !m.isBeta).map(mod => (
|
||||||
<VersionLink key={mod.id} to={"/mod/" + mod.id} state={mod.id}>
|
<VersionLink key={mod.id} to={"/mod/" + mod.id} state={mod.id}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: 'rgba(255, 255, 255, 0.7)' }}>
|
<VersionText variant="body2">
|
||||||
Version {mod.version}
|
Version {mod.version}
|
||||||
</Typography>
|
</VersionText>
|
||||||
<Typography variant="caption" sx={{
|
<VersionArrow variant="caption">
|
||||||
color: 'rgba(255, 255, 255, 0.5)',
|
|
||||||
}}>
|
|
||||||
→
|
→
|
||||||
</Typography>
|
</VersionArrow>
|
||||||
</Box>
|
</Box>
|
||||||
</VersionLink>
|
</VersionLink>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{hasBeta && (
|
{hasBeta && (
|
||||||
<Box sx={{ mt: 2 }}>
|
<Box sx={{ mt: 2 }}>
|
||||||
<Typography variant="subtitle2" sx={{
|
<BetaVersionsLabel variant="subtitle2">
|
||||||
color: 'rgba(255, 193, 7, 0.9)',
|
|
||||||
fontWeight: 600,
|
|
||||||
mb: 1,
|
|
||||||
}}>
|
|
||||||
Beta versions:
|
Beta versions:
|
||||||
</Typography>
|
</BetaVersionsLabel>
|
||||||
{betaVersion && (
|
{betaVersion && (
|
||||||
<VersionLink to={"/mod/" + betaVersion.id} state={betaVersion.id}>
|
<VersionLink to={"/mod/" + betaVersion.id} state={betaVersion.id}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
||||||
Version {betaVersion.version} (Beta)
|
Version {betaVersion.version} (Beta)
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="caption" sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>
|
<VersionArrow variant="caption">
|
||||||
→
|
→
|
||||||
</Typography>
|
</VersionArrow>
|
||||||
</Box>
|
</Box>
|
||||||
</VersionLink>
|
</VersionLink>
|
||||||
)}
|
)}
|
||||||
@ -226,18 +254,17 @@ function Mods({ mods }: ModsProps) {
|
|||||||
state={latest?.id}
|
state={latest?.id}
|
||||||
sx={{
|
sx={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
color: '#e94560',
|
color: '#FFD700',
|
||||||
borderColor: 'rgba(233, 69, 96, 0.5)',
|
borderColor: 'rgba(255, 215, 0, 0.5)',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
py: 1.5,
|
py: 1.5,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
borderColor: '#e94560',
|
borderColor: '#FFD700',
|
||||||
backgroundColor: 'rgba(233, 69, 96, 0.1)',
|
backgroundColor: 'rgba(255, 215, 0, 0.1)',
|
||||||
transform: 'translateY(-2px)',
|
boxShadow: '0 8px 20px rgba(255, 215, 0, 0.2)',
|
||||||
boxShadow: '0 8px 20px rgba(233, 69, 96, 0.2)',
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {AvailableBuildings, AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
import {AvailableBuildings, AvailableMods, AvailableRacesPart, AvailableUnits, IconUrl} from "../core/api";
|
||||||
import React, {useState} from "react";
|
import React from "react";
|
||||||
import {withRouter} from "../core/withrouter";
|
import {withRouter} from "../core/withrouter";
|
||||||
import {IMod} from "../types/Imod";
|
import {IMod} from "../types/Imod";
|
||||||
import {Irace} from "../types/Irace";
|
import {Irace} from "../types/Irace";
|
||||||
@ -18,11 +18,13 @@ import {
|
|||||||
ListItem,
|
ListItem,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
|
Theme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
||||||
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
import {IRaceUnits, IUnitShort} from "../types/IUnitShort";
|
||||||
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
import {IBuildingShort, IRaceBuildings} from "../types/IBuildingShort";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
import {withTheme} from "../core/api";
|
||||||
import {StyledLink} from "../commons/StyledLink";
|
import {StyledLink} from "../commons/StyledLink";
|
||||||
import {BackButton} from "../commons/BackButton";
|
import {BackButton} from "../commons/BackButton";
|
||||||
|
|
||||||
@ -33,19 +35,30 @@ const SectionTitle = styled(Typography)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const UnitCard = styled(Paper)(({ theme }) => ({
|
const UnitCard = styled(Paper)(({ theme }) => ({
|
||||||
background: 'rgba(255, 255, 255, 0.03)',
|
background: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.03)' : 'rgba(0, 0, 0, 0.03)',
|
||||||
border: '1px solid rgba(255, 255, 255, 0.05)',
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.05)'}`,
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
padding: theme.spacing(1.5, 2),
|
padding: theme.spacing(1.5, 2),
|
||||||
transition: 'all 0.2s ease',
|
transition: 'all 0.2s ease',
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
background: 'rgba(233, 69, 96, 0.1)',
|
background: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(233, 69, 96, 0.1)',
|
||||||
borderColor: 'rgba(233, 69, 96, 0.3)',
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(233, 69, 96, 0.3)',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const BuildingCard = styled(UnitCard)(({ theme }) => ({}));
|
const BuildingCard = styled(UnitCard)(({ theme }) => ({}));
|
||||||
|
|
||||||
|
const UnitLink = styled(Link)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
textDecoration: 'none',
|
||||||
|
display: 'block',
|
||||||
|
'&:hover': { color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560' }
|
||||||
|
}));
|
||||||
|
|
||||||
|
const LoadingText = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
}));
|
||||||
|
|
||||||
interface RacePageState {
|
interface RacePageState {
|
||||||
mod: IMod,
|
mod: IMod,
|
||||||
race: Irace,
|
race: Irace,
|
||||||
@ -53,29 +66,29 @@ interface RacePageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Unit(unit: IUnitShort, modId: number, raceId: String) {
|
function Unit(unit: IUnitShort, modId: number, raceId: String, theme: Theme) {
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
const borderColor = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)';
|
||||||
|
const bgColor = isDark ? 'rgba(255,255,255,0.02)' : 'rgba(0,0,0,0.02)';
|
||||||
|
|
||||||
return (<Link href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id} sx={{
|
return (
|
||||||
color: 'rgba(255,255,255,0.85)',
|
<UnitLink href={"/mod/" + modId + "/race/" + raceId + "/unit/" + unit.id}>
|
||||||
textDecoration: 'none',
|
<ListItem sx={{
|
||||||
display: 'block',
|
color: theme.palette.text.primary,
|
||||||
'&:hover': { color: '#e94560' }
|
padding: '6px 12px',
|
||||||
}}>
|
background: bgColor,
|
||||||
<ListItem sx={{
|
borderRadius: '8px',
|
||||||
color: 'rgba(255,255,255,0.85)',
|
border: `1px solid ${borderColor}`,
|
||||||
padding: '6px 12px',
|
transition: 'all 0.2s ease',
|
||||||
background: 'rgba(255,255,255,0.02)',
|
'&:hover': { background: isDark ? 'rgba(255,255,255,0.1)' : 'rgba(233, 69, 96, 0.1)', borderColor: isDark ? 'rgba(255,255,255,0.3)' : 'rgba(233, 69, 96, 0.3)' }
|
||||||
borderRadius: '8px',
|
}}>
|
||||||
border: '1px solid rgba(255,255,255,0.05)',
|
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
||||||
transition: 'all 0.2s ease',
|
{unit.name}
|
||||||
'&:hover': { background: 'rgba(233, 69, 96, 0.1)', borderColor: 'rgba(233, 69, 96, 0.3)' }
|
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
}}>
|
src="/images/DETECT_YES.webp"/></span>}
|
||||||
{unit.icon && <img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
</ListItem>
|
||||||
{unit.name}
|
</UnitLink>
|
||||||
{unit.canDetect && <span> <img style={{verticalAlign: "top"}}
|
)
|
||||||
src="/images/DETECT_YES.webp"/></span>}
|
|
||||||
</ListItem>
|
|
||||||
</Link>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
||||||
@ -94,13 +107,14 @@ function UnitSmall(unit: IUnitShort, modId: number, raceId: String) {
|
|||||||
src="/images/DETECT_YES.webp"/></span>}<br/></StyledLink>)
|
src="/images/DETECT_YES.webp"/></span>}<br/></StyledLink>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Building(building: IBuildingShort, modId: number, raceId: String) {
|
function Building(building: IBuildingShort, modId: number, raceId: String, theme: Theme) {
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
|
||||||
return (<Grid2 size={{xs: 12, md: 3}}>
|
return (<Grid2 size={{xs: 12, md: 3}}>
|
||||||
<Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id} sx={{
|
<Link href={"/mod/" + modId + "/race/" + raceId + "/building/" + building.id} sx={{
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
display: 'block',
|
display: 'block',
|
||||||
'&:hover': { color: '#e94560' }
|
'&:hover': { color: isDark ? '#dee2e6' : '#e94560' }
|
||||||
}}>
|
}}>
|
||||||
<BuildingCard elevation={0}>
|
<BuildingCard elevation={0}>
|
||||||
<ListItem sx={{
|
<ListItem sx={{
|
||||||
@ -128,7 +142,7 @@ interface UnitsState {
|
|||||||
buildings: IRaceBuildings | null,
|
buildings: IRaceBuildings | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
class Units extends React.Component<UnitsProps, UnitsState> {
|
class Units extends React.Component<UnitsProps & { theme: Theme }, UnitsState> {
|
||||||
|
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@ -157,7 +171,8 @@ class Units extends React.Component<UnitsProps, UnitsState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { theme } = this.props;
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
|
||||||
if (this.state && this.state.units) {
|
if (this.state && this.state.units) {
|
||||||
|
|
||||||
@ -165,65 +180,73 @@ class Units extends React.Component<UnitsProps, UnitsState> {
|
|||||||
document.title = this.state.buildings?.race.name
|
document.title = this.state.buildings?.race.name
|
||||||
}
|
}
|
||||||
|
|
||||||
const accordionSx = {
|
const accordionSx = isDark ? {
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
border: '1px solid rgba(255, 255, 255, 0.1)',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
'&:before': { display: 'none' },
|
'&:before': { display: 'none' },
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
||||||
|
} : {
|
||||||
|
background: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: '1px solid rgba(0, 0, 0, 0.1)',
|
||||||
|
borderRadius: '12px',
|
||||||
|
'&:before': { display: 'none' },
|
||||||
|
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
||||||
};
|
};
|
||||||
|
|
||||||
return (this.state.buildings != null ?
|
return (this.state.buildings != null ?
|
||||||
<Box>
|
<Box>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{this.state.buildings.buildings.map(building => Building(building, this.props.modId, this.props.raceId))}
|
{this.state.buildings.buildings.map(building => Building(building, this.props.modId, this.props.raceId, theme))}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
{this.state.buildings.buildingsAdvanced.length > 0 && <Box sx={{ mt: 3 }}>
|
{this.state.buildings.buildingsAdvanced.length > 0 && <Box sx={{ mt: 3 }}>
|
||||||
<Divider sx={{ my: 2, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
<Divider sx={{ my: 2, borderColor: isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)' }} />
|
||||||
<SectionTitle>Advanced buildings</SectionTitle>
|
<SectionTitle>Advanced buildings</SectionTitle>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{this.state.buildings.buildingsAdvanced.map(building => Building(building, this.props.modId, this.props.raceId))}
|
{this.state.buildings.buildingsAdvanced.map(building => Building(building, this.props.modId, this.props.raceId, theme))}
|
||||||
</Grid2><br/></Box>}
|
</Grid2><br/></Box>}
|
||||||
<Box sx={{ mt: 3 }}>
|
<Box sx={{ mt: 3 }}>
|
||||||
<Accordion sx={accordionSx}>
|
<Accordion sx={accordionSx}>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMore sx={{color: '#ffffff'}}/>}
|
expandIcon={<ExpandMore sx={{color: isDark ? '#dee2e6' : '#000000'}}/>}
|
||||||
aria-controls="units-accordion"
|
aria-controls="units-accordion"
|
||||||
id="units-accordion"
|
id="units-accordion"
|
||||||
sx={{color: '#ffffff'}}
|
sx={{color: isDark ? '#dee2e6' : '#000000', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}
|
||||||
>
|
>
|
||||||
<SectionTitle sx={{ mb: 0 }}>All units</SectionTitle>
|
<SectionTitle sx={{ mb: 0, display: 'flex', alignItems: 'center' }}>All units</SectionTitle>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Infantry</Typography>
|
<Typography variant="h6" sx={{ color: isDark ? '#dee2e6' : '#000000', fontWeight: 600, mb: 2 }}>Infantry</Typography>
|
||||||
{this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.infantry.map(unit => Unit(unit, this.props.modId, this.props.raceId, theme))}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Tech</Typography>
|
<Typography variant="h6" sx={{ color: isDark ? '#dee2e6' : '#000000', fontWeight: 600, mb: 2 }}>Tech</Typography>
|
||||||
<List>
|
<List>
|
||||||
{this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.tech.map(unit => Unit(unit, this.props.modId, this.props.raceId, theme))}
|
||||||
</List>
|
</List>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{xs: 12, md: 4}}>
|
<Grid2 size={{xs: 12, md: 4}}>
|
||||||
<Typography variant="h6" sx={{ color: '#ffffff', fontWeight: 600, mb: 2 }}>Support</Typography>
|
<Typography variant="h6" sx={{ color: isDark ? '#dee2e6' : '#000000', fontWeight: 600, mb: 2 }}>Support</Typography>
|
||||||
<List>
|
<List>
|
||||||
{this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId))}
|
{this.state.units.support.map(unit => Unit(unit, this.props.modId, this.props.raceId, theme))}
|
||||||
</List>
|
</List>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Box>
|
</Box>
|
||||||
</Box> : <Box sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>Loading</Box>
|
</Box> : <LoadingText>Loading</LoadingText>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return <Box sx={{ color: 'rgba(255, 255, 255, 0.5)' }}>Loading...</Box>;
|
return <LoadingText>Loading...</LoadingText>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UnitsWithTheme = withTheme(Units) as React.ComponentType<UnitsProps>;
|
||||||
|
|
||||||
class RacePageFast extends React.Component<any, RacePageState> {
|
class RacePageFast extends React.Component<any, RacePageState> {
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@ -252,9 +275,11 @@ class RacePageFast extends React.Component<any, RacePageState> {
|
|||||||
|
|
||||||
if (this.state != null && this.state.mod != null && this.state.race != null) {
|
if (this.state != null && this.state.mod != null && this.state.race != null) {
|
||||||
const backRef = "/mod/" + this.state.mod.id
|
const backRef = "/mod/" + this.state.mod.id
|
||||||
|
const theme = this.props.theme;
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg">
|
||||||
<BackButton
|
<BackButton
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
startIcon={<ArrowBack/>}
|
startIcon={<ArrowBack/>}
|
||||||
@ -267,26 +292,29 @@ class RacePageFast extends React.Component<any, RacePageState> {
|
|||||||
<Typography variant="h3" component="h1" sx={{
|
<Typography variant="h3" component="h1" sx={{
|
||||||
fontWeight: 800,
|
fontWeight: 800,
|
||||||
mb: 1,
|
mb: 1,
|
||||||
background: 'linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%)',
|
background: isDark
|
||||||
WebkitBackgroundClip: 'text',
|
? 'linear-gradient(135deg, #dee2e6 0%, #e0e0e0 100%)'
|
||||||
WebkitTextFillColor: 'transparent',
|
: 'linear-gradient(135deg, #000000 0%, #333333 100%)',
|
||||||
|
WebkitBackgroundClip: isDark ? 'text' : 'initial',
|
||||||
|
WebkitTextFillColor: isDark ? '#dee2e6' : 'initial',
|
||||||
|
color: isDark ? '#dee2e6' : '#000000',
|
||||||
}}>
|
}}>
|
||||||
{this.state.race.name}
|
{this.state.race.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" sx={{
|
<Typography variant="h6" sx={{
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
color: theme.palette.text.secondary,
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
}}>
|
}}>
|
||||||
{this.state.mod.name} ({this.state.mod.version})
|
{this.state.mod.name} ({this.state.mod.version})
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Units raceId={this.state.race.id} modId={this.state.mod.id}/>
|
<UnitsWithTheme raceId={this.state.race.id} modId={this.state.mod.id}/>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg">
|
||||||
<LinearProgress sx={{ width: '200px', mx: 'auto', display: 'block' }} />
|
<LinearProgress sx={{ width: '200px', mx: 'auto', display: 'block' }} />
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
@ -294,4 +322,4 @@ class RacePageFast extends React.Component<any, RacePageState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(RacePageFast);
|
export default withRouter(withTheme(RacePageFast));
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import {
|
|||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography, Theme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
import {ArrowBack, ExpandMore} from "@mui/icons-material";
|
||||||
import ArmorType from "../classes/ArmorType";
|
import ArmorType from "../classes/ArmorType";
|
||||||
@ -34,6 +34,7 @@ import {ModifiersProvidesTable} from "../classes/ModifiersProvideTable";
|
|||||||
import Ability from "../classes/Ability";
|
import Ability from "../classes/Ability";
|
||||||
import DeathExplosion from "../classes/DeathExplosion";
|
import DeathExplosion from "../classes/DeathExplosion";
|
||||||
import {styled} from '@mui/material/styles';
|
import {styled} from '@mui/material/styles';
|
||||||
|
import {withTheme} from "../core/api";
|
||||||
import {DescriptionBox} from "../commons/DescriptionBox";
|
import {DescriptionBox} from "../commons/DescriptionBox";
|
||||||
import {BackButton} from "../commons/BackButton";
|
import {BackButton} from "../commons/BackButton";
|
||||||
|
|
||||||
@ -44,19 +45,50 @@ const SectionTitle = styled(Typography)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const StatsPaper = styled(Paper)(({ theme }) => ({
|
const StatsPaper = styled(Paper)(({ theme }) => ({
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
background: theme.palette.mode === 'dark'
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
'& .MuiTableBody .MuiTableRow-root': {
|
'& .MuiTableBody .MuiTableRow-root': {
|
||||||
'&:last-child td, &:last-child th': { border: 0 },
|
'&:last-child td, &:last-child th': { border: 0 },
|
||||||
},
|
},
|
||||||
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
'& .MuiTableBody .MuiTableRow-root .MuiTableCell-head': {
|
||||||
color: '#e94560',
|
color: theme.palette.mode === 'dark' ? '#dee2e6' : '#e94560',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const SergeantAccordion = styled(Accordion)(({ theme }) => ({
|
||||||
|
background: theme.palette.mode === 'dark'
|
||||||
|
? 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)'
|
||||||
|
: 'linear-gradient(145deg, #ffffff 0%, #f5f5f5 100%)',
|
||||||
|
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`,
|
||||||
|
borderRadius: '12px',
|
||||||
|
mb: 1,
|
||||||
|
'&:before': { display: 'none' },
|
||||||
|
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledDivider = styled(Divider)(({ theme }) => ({
|
||||||
|
my: 3,
|
||||||
|
borderColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UnitTitle = styled(Typography)(({ theme }) => ({
|
||||||
|
fontWeight: 800,
|
||||||
|
mb: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 2,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UnitSubtitle = styled(Typography)(({ theme }) => ({
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
fontWeight: 500,
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
interface UintPageState {
|
interface UintPageState {
|
||||||
unit: IUnit,
|
unit: IUnit,
|
||||||
@ -64,10 +96,12 @@ interface UintPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function Unit(unit: IUnit, mod: IMod) {
|
function Unit(unit: IUnit, mod: IMod, theme: Theme) {
|
||||||
|
|
||||||
document.title = unit.name + " — " + mod.name
|
document.title = unit.name + " — " + mod.name
|
||||||
|
|
||||||
|
const isDark = theme.palette.mode === 'dark';
|
||||||
|
|
||||||
const morale = (unit.moraleMax !== null) ? <span>
|
const morale = (unit.moraleMax !== null) ? <span>
|
||||||
<img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> {unit.moraleMax}
|
<img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/> {unit.moraleMax}
|
||||||
+{unit.moraleRegeneration}/s
|
+{unit.moraleRegeneration}/s
|
||||||
@ -98,7 +132,7 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
const SergeantShort = (props: sergeantProps) => {
|
const SergeantShort = (props: sergeantProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{fontSize: 20, color: '#ffffff'}}>
|
<span style={{fontSize: 20, color: isDark ? '#dee2e6' : '#000000', display: 'flex', alignItems: 'center'}}>
|
||||||
{props.icon && <img className="sergeantIcon" src={IconUrl + props.icon.replaceAll('\\', '/')}/> }
|
{props.icon && <img className="sergeantIcon" src={IconUrl + props.icon.replaceAll('\\', '/')}/> }
|
||||||
{props.name}
|
{props.name}
|
||||||
{props.canDetect && <span> <img style={{verticalAlign: "top"}}
|
{props.canDetect && <span> <img style={{verticalAlign: "top"}}
|
||||||
@ -111,23 +145,14 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box sx={{ mb: 3 }}>
|
<Box sx={{ mb: 3 }}>
|
||||||
<Typography variant="h4" component="h2" sx={{
|
<UnitTitle variant="h4">
|
||||||
fontWeight: 800,
|
|
||||||
mb: 1,
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 2,
|
|
||||||
}}>
|
|
||||||
{unit.icon &&
|
{unit.icon &&
|
||||||
<img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
<img className="unitIcon" src={IconUrl + unit.icon.replaceAll('\\', '/')}/>}
|
||||||
{unit.name}
|
{unit.name}
|
||||||
</Typography>
|
</UnitTitle>
|
||||||
<Typography variant="subtitle1" sx={{
|
<UnitSubtitle variant="subtitle1">
|
||||||
color: 'rgba(255, 255, 255, 0.6)',
|
|
||||||
fontWeight: 500,
|
|
||||||
}}>
|
|
||||||
{mod.name} ({mod.version})
|
{mod.name} ({mod.version})
|
||||||
</Typography>
|
</UnitSubtitle>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Grid2 container spacing={3}>
|
<Grid2 container spacing={3}>
|
||||||
@ -297,22 +322,15 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
</Grid2>}
|
</Grid2>}
|
||||||
<Grid2 size={12}>
|
<Grid2 size={12}>
|
||||||
{unit.sergeants.map(s =>
|
{unit.sergeants.map(s =>
|
||||||
<Accordion key={s.id} sx={{
|
<SergeantAccordion key={s.id}>
|
||||||
background: 'linear-gradient(145deg, #1a1a2e 0%, #16213e 100%)',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
||||||
borderRadius: '12px',
|
|
||||||
mb: 1,
|
|
||||||
'&:before': { display: 'none' },
|
|
||||||
'&.Mui-expanded': { margin: '0 0 8px 0' },
|
|
||||||
}}>
|
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
sx={{color: '#ffffff'}}>
|
sx={{color: isDark ? '#dee2e6' : '#000000', '& .MuiAccordionSummary-content': { margin: '12px 0' }, '& .MuiAccordionSummary-content.Mui-expanded': { margin: '12px 0' }}}>
|
||||||
<SergeantShort name={s.name} icon={s.icon} canDetect={s.detectRadius > 0}/>
|
<SergeantShort name={s.name} icon={s.icon} canDetect={s.detectRadius > 0}/>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{color: 'rgba(255, 255, 255, 0.85)'}}>
|
<AccordionDetails sx={{color: theme.palette.text.primary}}>
|
||||||
<Sergeant mod={mod} sergeant={s} race={unit.race}/>
|
<Sergeant mod={mod} sergeant={s} race={unit.race}/>
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>)}
|
</SergeantAccordion>)}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
||||||
{unit.moraleMax !== null && !(unit.moraleBrakeModifiers.find(m => m.reference.includes("accuracy_weapon_modifier") && m.value === 0.2) !== undefined &&
|
{unit.moraleMax !== null && !(unit.moraleBrakeModifiers.find(m => m.reference.includes("accuracy_weapon_modifier") && m.value === 0.2) !== undefined &&
|
||||||
@ -355,7 +373,7 @@ function Unit(unit: IUnit, mod: IMod) {
|
|||||||
<Box sx={{ mt: 3, mb: 2, fontWeight: 600, fontSize: '0.85rem' }}>
|
<Box sx={{ mt: 3, mb: 2, fontWeight: 600, fontSize: '0.85rem' }}>
|
||||||
Hotkey: {unit.hotkey}
|
Hotkey: {unit.hotkey}
|
||||||
</Box>
|
</Box>
|
||||||
<Divider sx={{ my: 3, borderColor: 'rgba(255, 255, 255, 0.1)' }} />
|
<StyledDivider />
|
||||||
<UnitsTable modId={mod.id}/>
|
<UnitsTable modId={mod.id}/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
@ -387,9 +405,10 @@ class UnitPage extends React.Component<any, UintPageState> {
|
|||||||
|
|
||||||
if (this.state != null && this.state.unit != null && this.state.mod != null) {
|
if (this.state != null && this.state.unit != null && this.state.mod != null) {
|
||||||
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
const backRef = "/mod/" + this.props.match.params.modId + "/race/" + this.props.match.params.raceId
|
||||||
|
const { theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg">
|
||||||
<BackButton
|
<BackButton
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
startIcon={<ArrowBack/>}
|
startIcon={<ArrowBack/>}
|
||||||
@ -397,7 +416,7 @@ class UnitPage extends React.Component<any, UintPageState> {
|
|||||||
>
|
>
|
||||||
Back to race
|
Back to race
|
||||||
</BackButton>
|
</BackButton>
|
||||||
{Unit(this.state.unit, this.state.mod)}
|
{Unit(this.state.unit, this.state.mod, theme)}
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -410,4 +429,4 @@ class UnitPage extends React.Component<any, UintPageState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(UnitPage);
|
export default withRouter(withTheme(UnitPage));
|
||||||
|
|||||||
83
src/themes/theme.ts
Normal file
83
src/themes/theme.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
export const darkTheme = createTheme({
|
||||||
|
breakpoints: {
|
||||||
|
values: {
|
||||||
|
xs: 0,
|
||||||
|
sm: 600,
|
||||||
|
md: 900,
|
||||||
|
lg: 1320,
|
||||||
|
xl: 1536,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
mode: 'dark',
|
||||||
|
primary: {
|
||||||
|
main: "#1a1a2e",
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: '#0a0a0a',
|
||||||
|
paper: '#1a1a2e',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: '#dee2e6',
|
||||||
|
secondary: '#dee2e6',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: '"Inter", "Roboto", "Helvetica", sans-serif',
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
borderRadius: 12,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiTableCell: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#dee2e6',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const lightTheme = createTheme({
|
||||||
|
breakpoints: {
|
||||||
|
values: {
|
||||||
|
xs: 0,
|
||||||
|
sm: 600,
|
||||||
|
md: 900,
|
||||||
|
lg: 1320,
|
||||||
|
xl: 1536,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
mode: 'light',
|
||||||
|
primary: {
|
||||||
|
main: "#1a1a2e",
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: '#f5f5f5',
|
||||||
|
paper: '#ffffff',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
secondary: 'rgba(0, 0, 0, 0.6)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: '"Inter", "Roboto", "Helvetica", sans-serif',
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
borderRadius: 12,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
MuiTableCell: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'rgba(0, 0, 0, 0.85)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user