Skip to content

Commit

Permalink
Stylings and componentized
Browse files Browse the repository at this point in the history
  • Loading branch information
Louis-Riel committed Feb 1, 2023
1 parent c0c6cf9 commit e7caee8
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 110 deletions.
Empty file removed data/empty.txt
Empty file.
232 changes: 178 additions & 54 deletions data/main.jsx

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
},
"scripts": {
"buildhtml": "cp ./src/index.html ../data/index.html",
"buildjsx": "(echo \"const httpPrefix='';\" && cat ./src/modules/modules.jsx && find ./src/theme -type f -name '*.jsx' -exec cat {} \\;&& find ./src/components -type f -name 'style.jsx' -exec cat {} \\; && find ./src/components -type f -name '*.jsx' | grep -v style.jsx | xargs cat && cat ./src/main.jsx) > ../data/main.jsx",
"buildlocaljsx": "(cat ./src/espaddr.jsx && cat ./src/modules/modules.jsx && find ./src/theme -type f -name '*.jsx' -exec cat {} \\;&& find ./src/components -type f -name 'style.jsx' -exec cat {} \\; && find ./src/components -type f -name '*.jsx' | grep -v style.jsx | xargs cat && cat ./src/main.jsx) > ../data/main.jsx",
"buildjsx": "(echo \"const httpPrefix='';\" && cat ./src/modules/modules.jsx && find ./src/theme -type f -name '*.jsx' -exec cat {} \\;&& find ./src/components -type f -name 'style.jsx' -exec cat {} \\; && find ./src/components -type f -name '*.jsx' ! -name 'style.jsx' | xargs cat && cat ./src/main.jsx) > ../data/main.jsx",
"buildlocaljsx": "(cat ./src/espaddr.jsx && cat ./src/modules/modules.jsx && find ./src/theme -type f -name '*.jsx' -exec cat {} \\; && find ./src/components -type f -name 'style.jsx' -exec cat {} \\; && find ./src/components -type f -name '*.jsx' ! -name 'style.jsx' | xargs cat && cat ./src/main.jsx) > ../data/main.jsx",
"build": "npm run buildjsx && npm run buildhtml",
"buildlocal": "npm run buildlocaljsx && npm run buildhtml",
"rebuild": "node ./node_modules/fs-watch-exec/index.js run -d ./src 'npm run buildlocal'",
Expand Down
30 changes: 30 additions & 0 deletions site/src/components/home/designer/countdown/countdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const Countdown = withStyles(countdownStyle)(props => {
const { classes, label, millisecondsRemaining, postUpdate } = props;
const [ timeRemaining, setTimeRemaining ] = useState(false);

useEffect(() => {
if (millisecondsRemaining) {
const timeReference = Date.now()+millisecondsRemaining;
setTimeRemaining(timeReference-Date.now());
var requestSent = false;
const interval = setInterval(()=>{
const remaining = timeReference-Date.now();
if (remaining >= 0) {
setTimeRemaining(remaining);
}
if ((remaining <= 100) && !requestSent) {
requestSent=true;
postUpdate();
}
},50);
return ()=>clearInterval(interval);
}
},[millisecondsRemaining]);

return (
<Box className={classes.root}>
<Typography variant="little" color="textSecondary">{label}</Typography>:
<Typography className={classes.timeremaining} width="100px" variant="little" color="textAttribute">{timeRemaining}</Typography>
</Box>)

});
11 changes: 11 additions & 0 deletions site/src/components/home/designer/countdown/style.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const countdownStyle = theme => ({
root: {
display: "flex",
flexDirection: "row",
columnGap: "3px",
alignItems: "center",
},
timeremaining: {
width: "50px"
}
});
45 changes: 15 additions & 30 deletions site/src/components/home/designer/designer.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
const DesignerPanel = withStyles(designStyle)(props => {
const { classes, open } = props;
const { classes, open, addNotification } = props;
const [ effects, setEffects ] = useState(undefined);
const [ abortControler, setAbortControler ] = useState(undefined);
const [ nextRefreshDate, setNextRefreshDate] = useState(undefined);
const [ editing, setEditing ] = useState(false);
const [ pendingInterval, setPendingInterval ] = useState(undefined);
const [ timeRemaining, setTimeRemaining ] = useState(undefined);

useEffect(() => {
if (abortControler) {
Expand All @@ -24,7 +23,7 @@ const DesignerPanel = withStyles(designStyle)(props => {
.then(resp => resp.json())
.then(setEffects)
.then(()=>clearTimeout(timer))
.catch(console.error);
.catch(err => addNotification("Error","Service","Get Effect List",err));

return () => {
abortControler && abortControler.abort();
Expand All @@ -33,37 +32,23 @@ const DesignerPanel = withStyles(designStyle)(props => {
}
},[open,nextRefreshDate]);

useEffect(() => {
if (effects) {
const timeReference = Date.now()+effects.millisecondsRemaining;
var requestSent = false;
setTimeRemaining(timeReference-Date.now());
const interval = setInterval(()=>{
const remaining = timeReference-Date.now();
if (remaining >= 0) {
setTimeRemaining(remaining);
}
if ((remaining <= 100) && !requestSent) {
setNextRefreshDate(Date.now());
requestSent=true;
}
},100);
return ()=>clearInterval(interval);
}
},[effects]);

const postUpdate = () => setTimeout(()=>setNextRefreshDate(Date.now()),50);

const navigate = (up)=>{
fetch(`${httpPrefix !== undefined ? httpPrefix : ""}/${up ? "nextEffect" : "previousEffect"}`,{method:"POST"})
.then(postUpdate)
.catch(console.error);
.catch(err => addNotification("Error","Service","Effect Navigation",err));
}

const updateEventInterval = (interval)=>{
fetch(`${httpPrefix !== undefined ? httpPrefix : ""}/settings`,{method:"POST", body: new URLSearchParams({effectInterval:interval})})
fetch(`${httpPrefix !== undefined ? httpPrefix : ""}/settings`,
{
method:"POST",
body: new URLSearchParams({effectInterval:interval}),
timeout: 3000
})
.then(postUpdate)
.catch(console.error);
.catch(err => addNotification("Error","Service","Update Settings",err));
}

const displayHeader = ()=>{
Expand Down Expand Up @@ -112,10 +97,10 @@ const DesignerPanel = withStyles(designStyle)(props => {
{editing ?
editingHeader():
displayHeader()}
<Box className={classes.effectsHeaderValue}>
<Typography variant="little" color="textSecondary">Time Remaining</Typography>:
<Typography className={classes.timeremaining} width="100px" variant="little" color="textAttribute">{timeRemaining}</Typography>
</Box>
<Countdown
label="Time Remaining"
postUpdate={postUpdate}
millisecondsRemaining={effects.millisecondsRemaining}/>
{(effects.Effects.length > 1) && <Box>
<IconButton onClick={()=>navigate(false)}><Icon>skip_previous</Icon></IconButton>
<IconButton onClick={()=>navigate(true)}><Icon>skip_next</Icon></IconButton>
Expand All @@ -130,7 +115,7 @@ const DesignerPanel = withStyles(designStyle)(props => {
postUpdate={postUpdate}
effectInterval={effects.effectInterval}
selected={idx === effects.currentEffect}
timeRemaining={timeRemaining}/>)}
millisecondsRemaining={effects.millisecondsRemaining}/>)}
</Box>
</Box>
});
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
const Effect = withStyles(effectStyle)(props => {
const { classes, effect, effectInterval, effectIndex, timeRemaining, selected, postUpdate } = props;
const { classes, effect, effectInterval, effectIndex, millisecondsRemaining, selected, postUpdate } = props;
const [ progress, setProgress ] = useState(undefined);

useEffect(()=>{
const timeout = setTimeout(() => selected && setProgress((timeRemaining/effectInterval)*100.0),300);
return () => clearTimeout(timeout);
},[progress,selected]);

useEffect(()=>{selected && setProgress((timeRemaining/effectInterval)*100.0)},[effect]);
useEffect(() => {
if (millisecondsRemaining && selected) {
const timeReference = Date.now()+millisecondsRemaining;
var timeRemaining = timeReference-Date.now();
const interval = setInterval(()=>{
const remaining = timeReference-Date.now();
if (remaining >= 0) {
timeRemaining = remaining;
setProgress((timeRemaining/effectInterval)*100.0);
}
},300);
return ()=>clearInterval(interval);
}
},[millisecondsRemaining,selected]);

const navigateTo = (idx)=>{
fetch(`${httpPrefix !== undefined ? httpPrefix : ""}/setCurrentEffectIndex?`,{method:"POST", body: new URLSearchParams({currentEffectIndex:idx})})
.then(postUpdate)
.catch(console.error);
.catch(err => addNotification("Error","Service","Effect Selection",err));
}

const effectEnable = (idx,enable)=>{
fetch(`${httpPrefix !== undefined ? httpPrefix : ""}/${enable?"enable":"disable"}Effect`,{method:"POST", body:new URLSearchParams({effectIndex:idx})})
.then(postUpdate)
.catch(console.error);
.catch(err => addNotification("Error","Service","Effect Enablement",err));
}

return <Box className={classes.effect}>
Expand Down
3 changes: 0 additions & 3 deletions site/src/components/home/designer/style.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,5 @@ const designStyle = theme => ({
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
},
timeremaining: {
width: "50px"
}
});
21 changes: 13 additions & 8 deletions site/src/components/home/home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const MainApp = withStyles(mainAppStyle)(props => {
const [statsRefreshRate, setStatsRefreshRate ] = useState(3);
const [maxSamples, setMaxSamples ] = useState(50);
const [animateChart, setAnimateChart ] = useState(false);
const [notifications, setNotifications] = useState([]);

const siteConfig = {
statsRefreshRate: {
Expand All @@ -30,6 +31,14 @@ const MainApp = withStyles(mainAppStyle)(props => {
}
};

const addNotification = (level,type,target,notification) => {
setNotifications(prevNotifs => {
const group = prevNotifs.find(notif=>(notif.level === level) && (notif.type == type) && (notif.target === target)) || {level,type,target,notifications:[]};
group.notifications.push({date:new Date(),notification});
return [...prevNotifs.filter(notif => notif !== group), group];
});
};

return <ThemeProvider theme={mode == "dark" ? darkTheme : lightTheme}>
<CssBaseline />
<Box className={classes.root}>
Expand All @@ -47,11 +56,7 @@ const MainApp = withStyles(mainAppStyle)(props => {
variant="h6">
Night Driver Strip
</Typography>
<IconButton>
<Badge aria-label="Alerts" badgeContent={4} color="secondary">
<Icon>notifications</Icon>
</Badge>
</IconButton>
<NotificationPanel notifications={notifications}/>
</Toolbar>
</AppBar>
<Drawer variant="permanent"
Expand Down Expand Up @@ -79,9 +84,9 @@ const MainApp = withStyles(mainAppStyle)(props => {
}</List>
</Drawer>
<Box className={[classes.content, drawerOpened && classes.contentShrinked].join(" ")}>
<StatsPanel siteConfig={siteConfig} open={stats}/>
<DesignerPanel siteConfig={siteConfig} open={designer}/>
<ConfigDialog siteConfig={siteConfig} open={config} onClose={() => {setConfig(false)}} />
<StatsPanel siteConfig={siteConfig} open={stats} addNotification={addNotification}/>
<DesignerPanel siteConfig={siteConfig} open={designer} addNotification={addNotification}/>
<ConfigDialog siteConfig={siteConfig} open={config} addNotification={addNotification} onClose={() => {setConfig(false)}} />
</Box>
</Box>
</ThemeProvider>;
Expand Down
74 changes: 74 additions & 0 deletions site/src/components/home/notifications/notifications.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const NotificationPanel = withStyles(notificationsStyle)(props => {
const { classes, notifications } = props;
const [numErrors, setNumErrors] = React.useState(undefined);
const [errorTargets, setErrorTargets] = React.useState({});
const [open, setOpen] = React.useState(false);
const inputRef = React.createRef();

useEffect(()=>{
setNumErrors(notifications.reduce((ret,notif) => ret+notif.notifications.length, 0));
setErrorTargets(notifications.reduce((ret,notif) =>
{return {...ret,[notif.target]:ret[notif.target] || false}}, {}));
},[notifications]);

return (
<Box className={classes.root}>
<IconButton
id="notifications"
ref={inputRef}
onClick={() => setOpen(wasOpen=>!wasOpen)}>
<Badge
aria-label="Alerts"
badgeContent={numErrors}
color="secondary">
<Icon>notifications</Icon>
</Badge>
</IconButton>
<Popover
open={open}
target="notifications"
onClose={()=>{setOpen(false)}}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}>
<Card className={classes.popup} elevation={9}>
<CardHeader
avatar={
<Avatar aria-label="error">
!
</Avatar>
}
action={
<IconButton onClick={()=>setOpen(false)} aria-label="settings">
<Icon>close</Icon>
</IconButton>
}
title={`${numErrors} Errors`}
/>
<CardContent>
{Object.entries(errorTargets).map(target =>
<CardContent key={target[0]} className={classes.errors}>
{Object.entries(notifications)
.filter(notif => notif[1].target === target[0])
.map(error =>
<Box key={error[0]}>
<Box className={classes.errorHeader} key="header">
<Typography>{target[0]}</Typography>
<Typography color="textSecondary">{error[1].type}</Typography>
<Typography>{error[1].level}</Typography>
</Box>
<Box className={classes.errors} key="errors">
{Object.entries(error[1].notifications.reduce((ret,error) => {return {...ret,[error.notification]:(ret[error.notification]||0)+1}},{}))
.map(entry => <Typography key={entry[1]} variant="tiny">{`${entry[1]}X ${entry[0]}`}</Typography>)
}
</Box>
</Box>
)}
</CardContent>
)}
</CardContent>
</Card>
</Popover>
</Box>);
});
18 changes: 18 additions & 0 deletions site/src/components/home/notifications/style.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const notificationsStyle = theme => ({
root: {
},
popup: {
},
errorTarget: {
},
errors: {
display: "flex",
flexDirection: "column"
},
errorHeader: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
borderBottom: "solid aquamarine 2px",
}
});
2 changes: 1 addition & 1 deletion site/src/components/home/statistics/stats.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const StatsPanel = withStyles(statsStyle)(props => {

getStats(aborter)
.then(setStatistics)
.catch(console.error);
.catch(err => addNotification("Error","Service","Get Statistics",err));

if (timer) {
clearTimeout(timer);
Expand Down
2 changes: 1 addition & 1 deletion site/src/main.jsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ReactDOM.createRoot(document.getElementById("root"))
.render(<MainApp/>);
.render(<StrictMode><MainApp/></StrictMode>);
5 changes: 3 additions & 2 deletions site/src/modules/modules.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const { useState, useEffect, useMemo, useRef } = window.React;
const { useState, useEffect, useMemo, useRef, StrictMode } = window.React;

const { createTheme, ThemeProvider, Checkbox, AppBar, Toolbar, IconButton, Icon, MenuIcon, Typography } = window.MaterialUI;
const { Badge, withStyles, CssBaseline, Drawer, Divider, List, ListItem, ListItemIcon, ListItemText } = window.MaterialUI;
const { Box, Dialog, Slide, Button, TextField, FormControlLabel, useTheme, LinearProgress } = window.MaterialUI;
const { Box, Dialog, Slide, Button, TextField, FormControlLabel, useTheme, LinearProgress, Popover } = window.MaterialUI;
const { Card, CardHeader, CardContent, Collapse, CardActions, CardActionArea, Avatar } = window.MaterialUI;

const { AreaChart, BarChart, Area, Bar, ResponsiveContainer, LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip, Legend } = window.Recharts;

0 comments on commit e7caee8

Please sign in to comment.