/ concept-collection / ans-visualizer
Sign in
concept-collection / ans-visualizer
ans-visualizer / src / App.tsx
94 lines · 2.8 KBBlameHistoryRaw
1import { useState, useEffect } from 'react';
2import { Container, Typography, Box, CssBaseline, ThemeProvider, createTheme, Paper } from '@mui/material';
3import ReactMarkdown from 'react-markdown';
4import remarkMath from 'remark-math';
5import rehypeKatex from 'rehype-katex';
6import 'katex/dist/katex.min.css';
7import MobileWarning from './components/MobileWarning';
8import FrequencyInput from './components/FrequencyInput';
9import StateGrid from './components/StateGrid';
10import type { Symbol } from './types';
11import { isMobileDevice } from './utils/deviceDetection';
12import { getDefaultColors } from './utils/ansLogic';
13import explanationText from './explanation.md?raw';
15const theme = createTheme({
16 palette: {
17 mode: 'light',
18 primary: {
19 main: '#1976d2',
20 },
21 },
22});
24function App() {
25 const [isMobile, setIsMobile] = useState(false);
26 const [symbols, setSymbols] = useState<Symbol[]>([]);
28 useEffect(() => {
29 // Check if mobile
30 setIsMobile(isMobileDevice());
32 // Initialize with default symbols: A-1, B-1, C-1
33 const defaultColors = getDefaultColors();
34 const defaultSymbols: Symbol[] = [
35 { name: 'A', frequency: 3, color: defaultColors[0] },
36 { name: 'B', frequency: 2, color: defaultColors[1] },
37 { name: 'C', frequency: 1, color: defaultColors[2] },
38 ];
39 setSymbols(defaultSymbols);
41 // Re-check on resize
42 const handleResize = () => {
43 setIsMobile(isMobileDevice());
44 };
45 window.addEventListener('resize', handleResize);
46 return () => window.removeEventListener('resize', handleResize);
47 }, []);
49 if (isMobile) {
50 return (
51 <ThemeProvider theme={theme}>
52 <CssBaseline />
53 <MobileWarning />
54 </ThemeProvider>
55 );
56 }
58 return (
59 <ThemeProvider theme={theme}>
60 <CssBaseline />
61 <Container maxWidth="xl" sx={{ py: 2 }}>
62 <Box sx={{ mb: 2 }}>
63 <Typography variant="h4" component="h1" gutterBottom>
64 ANS Visualizer
65 </Typography>
66 <Typography variant="body2" color="text.secondary">
67 Illustration of the Asymmetric Numeral Systems algorithm
68 </Typography>
69 </Box>
71 <Box sx={{ display: 'flex', gap: 3 }}>
72 <Box sx={{ flex: 1 }}>
73 <FrequencyInput symbols={symbols} onSymbolsChange={setSymbols} />
75 <Paper sx={{ p: 2, mt: 3, maxHeight: '600px', overflowY: 'auto' }}>
76 <ReactMarkdown
77 remarkPlugins={[remarkMath]}
78 rehypePlugins={[rehypeKatex]}
79 >
80 {explanationText}
81 </ReactMarkdown>
82 </Paper>
83 </Box>
85 <Box sx={{ flex: 1 }}>
86 <StateGrid symbols={symbols} />
87 </Box>
88 </Box>
89 </Container>
90 </ThemeProvider>
91 );
94export default App;
moveopenescclose