1import { useState, useEffect } from 'react';
2import { createTheme, CssBaseline, ThemeProvider, Typography, Button, Box, CircularProgress, Select, MenuItem, FormControl, InputLabel, FormControlLabel, Checkbox, Alert } from '@mui/material';
3import { MultiplicationTable } from './components/MultiplicationTable';
4import { getNextPrime, getPreviousPrime, getInitialPrimeForViewport, PRIMES } from './utils/primeUtils';
6const theme = createTheme({
7 palette: {
8 mode: 'light',
9 primary: {
10 main: '#1976d2',
11 },
12 },
13});
15function App() {
16 const [currentPrime, setCurrentPrime] = useState(() => getInitialPrimeForViewport());
17 const [isComputing, setIsComputing] = useState(true);
18 const [showColorBar, setShowColorBar] = useState(false);
19 const [isMobile, setIsMobile] = useState(false);
21 // Detect mobile device
22 useEffect(() => {
23 const checkMobile = () => {
24 const isMobileDevice = window.innerWidth < 768; // Standard tablet/mobile breakpoint
25 setIsMobile(isMobileDevice);
26 };
28 checkMobile();
29 window.addEventListener('resize', checkMobile);
31 return () => window.removeEventListener('resize', checkMobile);
32 }, []);
34 const handleNextPrime = () => {
35 setCurrentPrime(prev => getNextPrime(prev));
36 };
38 const handlePreviousPrime = () => {
39 setCurrentPrime(prev => getPreviousPrime(prev));
40 };
42 return (
43 <ThemeProvider theme={theme}>
44 <CssBaseline />
45 <Box sx={{
46 display: 'flex',
47 flexDirection: { xs: 'column', md: 'row' },
48 height: '100vh',
49 overflow: 'hidden'
50 }}>
51 {/* Sidebar with controls */}
52 <Box sx={{
53 width: { xs: '100%', md: 300 },
54 maxHeight: { xs: 'auto', md: '100vh' },
55 p: { xs: 2, md: 3 },
56 borderRight: { xs: 0, md: 1 },
57 borderBottom: { xs: 1, md: 0 },
58 borderColor: 'divider',
59 display: 'flex',
60 flexDirection: 'column',
61 gap: 2,
62 overflowY: { xs: 'visible', md: 'auto' }
63 }}>
64 <Typography variant="h5" component="h1" gutterBottom>
65 Finite Field Multiplication Table
66 </Typography>
68 <Box>
69 <Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 1 }}>
70 <Typography variant="h6" component="h2">
71 Prime: {currentPrime}
72 </Typography>
73 {isComputing && <CircularProgress size={20} />}
74 </Box>
75 <Typography variant="body2" color="text.secondary" paragraph>
76 Multiplication table modulo {currentPrime}
77 </Typography>
78 <Typography variant="body2" color="text.secondary" paragraph>
79 Showing ({currentPrime - 1} × {currentPrime - 1}) grid
80 </Typography>
81 <FormControl fullWidth sx={{ mb: 2 }}>
82 <InputLabel id="prime-select-label">Select Prime</InputLabel>
83 <Select
84 labelId="prime-select-label"
85 id="prime-select"
86 value={currentPrime}
87 label="Select Prime"
88 onChange={(e) => setCurrentPrime(e.target.value as number)}
89 >
90 {PRIMES.map((prime) => (
91 <MenuItem key={prime} value={prime}>
92 {prime}
93 </MenuItem>
94 ))}
95 </Select>
96 </FormControl>
97 <Box sx={{ display: 'flex', gap: 1 }}>
98 <Button
99 variant="outlined"
100 onClick={handlePreviousPrime}
101 fullWidth
102 disabled={currentPrime === PRIMES[0]}
103 >
104 Previous
105 </Button>
106 <Button
107 variant="contained"
108 onClick={handleNextPrime}
109 fullWidth
110 disabled={currentPrime === PRIMES[PRIMES.length - 1]}
111 >
112 Next
113 </Button>
114 </Box>
115 </Box>
117 <Box sx={{ mt: 2 }}>
118 <Typography variant="body2" color="text.secondary">
119 Each cell (i, j) shows the value of (i × j) mod {currentPrime}
120 </Typography>
121 </Box>
123 {isMobile ? (
124 <Box sx={{ mt: 2 }}>
125 <Alert severity="info" sx={{ fontSize: '0.875rem' }}>
126 This visualization is best viewed on a desktop.
127 </Alert>
128 </Box>
129 ) : (
130 <Box sx={{ mt: 2 }}>
131 <FormControlLabel
132 control={
133 <Checkbox
134 checked={showColorBar}
135 onChange={(e) => setShowColorBar(e.target.checked)}
136 />
137 }
138 label="Show Color Bar"
139 />
140 </Box>
141 )}
142 </Box>
144 {/* Main content area */}
145 <Box sx={{
146 flex: 1,
147 display: 'flex',
148 alignItems: 'center',
149 justifyContent: 'center',
150 p: { xs: 1, md: 2 },
151 overflow: 'hidden',
152 minHeight: 0
153 }}>
154 <MultiplicationTable
155 prime={currentPrime}
156 onLoadingChange={setIsComputing}
157 showColorBar={showColorBar}
158 />
159 </Box>
160 </Box>
161 </ThemeProvider>
162 );
163}
165export default App;