modified: src/app/component/Bus.tsx
modified: src/app/component/Strip.tsx modified: src/app/layout.tsx modified: src/app/page.tsx new file: src/utils/EventCounter.ts
This commit is contained in:
parent
df1bb8c35a
commit
16b2de18a9
|
@ -3,52 +3,55 @@ import { Button, ButtonGroup, Grid, Input, Slider, Stack } from "@mui/material";
|
|||
import React from "react";
|
||||
import { StripBusOutput, StripBusOutputEvent } from "./StripBusOutput";
|
||||
|
||||
export interface StripProps {
|
||||
physicalBuses: number;
|
||||
virtualBuses: number;
|
||||
default?: Partial<StripState>;
|
||||
export interface BusProps {
|
||||
values?: Partial<BusState>;
|
||||
onChange: (event: BusEvent) => any;
|
||||
}
|
||||
|
||||
export interface StripState {
|
||||
export interface BusState {
|
||||
gain: number;
|
||||
buses: boolean[];
|
||||
muted: boolean;
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
export type BusEvent = StripBusOutputChanged | StripMuted | StripGainChanged;
|
||||
export type BusEvent = BusMuted | BusGainChanged | BusSelectToggle;
|
||||
|
||||
export interface StripBusOutputChanged extends StripBusOutputEvent {
|
||||
type: "StripBusOutputChanged";
|
||||
}
|
||||
|
||||
export interface StripGainChanged {
|
||||
export interface BusGainChanged {
|
||||
type: "StripGainChanged";
|
||||
gain: number;
|
||||
}
|
||||
export interface StripMuted {
|
||||
export interface BusMuted {
|
||||
type: "StripMuted";
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
export class Bus extends React.Component<StripProps, StripState> {
|
||||
constructor(props: StripProps) {
|
||||
super(props);
|
||||
const buses = (props.default && props.default.buses) || [];
|
||||
this.state = {
|
||||
gain:
|
||||
props.default && props.default.gain !== undefined
|
||||
? props.default.gain
|
||||
: 0,
|
||||
buses: [...Array(props.physicalBuses + props.virtualBuses)].map((_v, k) =>
|
||||
buses[k] === undefined ? false : buses[k]
|
||||
),
|
||||
muted:
|
||||
props.default && props.default.muted !== undefined
|
||||
? props.default.muted
|
||||
: false,
|
||||
};
|
||||
export interface BusSelectToggle {
|
||||
type: "BusSelectToggle";
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
export class Bus extends React.Component<BusProps, BusState> {
|
||||
constructor(props: BusProps) {
|
||||
super(props);
|
||||
const { values: initialValues } = props;
|
||||
const defaultValues: BusState = {
|
||||
gain: 0,
|
||||
selected: false,
|
||||
muted: false,
|
||||
};
|
||||
const getValue = (name: keyof typeof defaultValues) => {
|
||||
if (initialValues === undefined) return defaultValues[name];
|
||||
return initialValues[name] !== undefined
|
||||
? defaultValues[name]
|
||||
: initialValues[name];
|
||||
};
|
||||
this.state = Object.fromEntries(
|
||||
Object.entries(defaultValues).map(([name]) => [
|
||||
name,
|
||||
getValue(name as keyof typeof defaultValues) as any,
|
||||
])
|
||||
) as BusState;
|
||||
}
|
||||
onResetDefaults(e: React.MouseEvent) {}
|
||||
onKeyDown(event: React.KeyboardEvent) {
|
||||
console.log(event);
|
||||
|
||||
|
@ -70,21 +73,6 @@ export class Bus extends React.Component<StripProps, StripState> {
|
|||
gain: changedGain,
|
||||
});
|
||||
}
|
||||
onBusChange(event: StripBusOutputEvent) {
|
||||
const buses = this.state.buses;
|
||||
buses[
|
||||
event.isVirtual ? this.props.physicalBuses + event.busId : event.busId
|
||||
] = event.enabled;
|
||||
this.setState({
|
||||
buses,
|
||||
});
|
||||
this.props.onChange({
|
||||
type: "StripBusOutputChanged",
|
||||
busId: event.busId,
|
||||
isVirtual: event.isVirtual,
|
||||
enabled: event.enabled,
|
||||
});
|
||||
}
|
||||
onStripWheel(event: React.WheelEvent) {
|
||||
console.log(event);
|
||||
}
|
||||
|
@ -96,11 +84,21 @@ export class Bus extends React.Component<StripProps, StripState> {
|
|||
}
|
||||
);
|
||||
}
|
||||
onSelectToggle() {
|
||||
this.setState(
|
||||
(state) => ({ selected: !state.selected }),
|
||||
() => {
|
||||
this.props.onChange({
|
||||
type: "BusSelectToggle",
|
||||
selected: this.state.selected,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<Grid container sx={{ width: "100%"}}>
|
||||
<Stack alignItems={"center"} direction={"row"}>
|
||||
<Stack alignItems={"center"} direction={"row"} spacing={0}>
|
||||
<Input
|
||||
inputProps={{
|
||||
"aria-labelledby": "input-slider",
|
||||
|
@ -114,6 +112,7 @@ export class Bus extends React.Component<StripProps, StripState> {
|
|||
<Slider
|
||||
sx={{
|
||||
margin: "5px",
|
||||
marginInline: "15px",
|
||||
}}
|
||||
// orientation="vertical"
|
||||
defaultValue={0.0}
|
||||
|
@ -138,9 +137,9 @@ export class Bus extends React.Component<StripProps, StripState> {
|
|||
Mute
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => this.onMuteToggle()}
|
||||
onClick={() => this.onSelectToggle()}
|
||||
sx={{}}
|
||||
variant={this.state.muted ? "contained" : "outlined"}
|
||||
variant={this.state.selected ? "contained" : "outlined"}
|
||||
color={"warning"}
|
||||
>
|
||||
S
|
||||
|
@ -170,7 +169,6 @@ export class Bus extends React.Component<StripProps, StripState> {
|
|||
))}
|
||||
</ButtonGroup>
|
||||
</Stack> */}
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
"use client";
|
||||
import { Button, ButtonGroup, Grid, Input, Slider, Stack } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Grid,
|
||||
Input,
|
||||
Slider,
|
||||
Stack,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { StripBusOutput, StripBusOutputEvent } from "./StripBusOutput";
|
||||
|
||||
export interface StripProps {
|
||||
physicalBuses: number;
|
||||
virtualBuses: number;
|
||||
default?: Partial<StripState>;
|
||||
values?: Partial<StripState>;
|
||||
onChange: (event: StripEvent) => any;
|
||||
}
|
||||
|
||||
export interface StripState {
|
||||
gain: number;
|
||||
buses: boolean[];
|
||||
outputBuses: boolean[];
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
|
@ -34,20 +42,30 @@ export interface StripMuted {
|
|||
export class Strip extends React.Component<StripProps, StripState> {
|
||||
constructor(props: StripProps) {
|
||||
super(props);
|
||||
const buses = (props.default && props.default.buses) || [];
|
||||
this.state = {
|
||||
gain:
|
||||
props.default && props.default.gain !== undefined
|
||||
? props.default.gain
|
||||
: 0,
|
||||
buses: [...Array(props.physicalBuses + props.virtualBuses)].map((_v, k) =>
|
||||
buses[k] === undefined ? false : buses[k]
|
||||
const { values: initialValues } = props;
|
||||
const defaultValues: StripState = {
|
||||
gain: 0,
|
||||
outputBuses: [...Array(props.physicalBuses + props.virtualBuses)].map(
|
||||
(_v, k) => false
|
||||
),
|
||||
muted:
|
||||
props.default && props.default.muted !== undefined
|
||||
? props.default.muted
|
||||
: false,
|
||||
muted: false,
|
||||
};
|
||||
const getValue = (name: keyof typeof defaultValues) => {
|
||||
if (initialValues === undefined) return defaultValues[name];
|
||||
return initialValues[name] !== undefined
|
||||
? defaultValues[name]
|
||||
: initialValues[name];
|
||||
};
|
||||
this.state = Object.fromEntries(
|
||||
Object.entries(defaultValues).map(([name]) => [
|
||||
name,
|
||||
getValue(name as keyof typeof defaultValues) as any,
|
||||
])
|
||||
) as StripState;
|
||||
}
|
||||
onResetDefaults(e: React.MouseEvent) {
|
||||
e.stopPropagation();
|
||||
this.setState({ gain: 0 });
|
||||
}
|
||||
onKeyDown(event: React.KeyboardEvent) {
|
||||
console.log(event);
|
||||
|
@ -71,12 +89,12 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
});
|
||||
}
|
||||
onBusChange(event: StripBusOutputEvent) {
|
||||
const buses = this.state.buses;
|
||||
const buses = this.state.outputBuses;
|
||||
buses[
|
||||
event.isVirtual ? this.props.physicalBuses + event.busId : event.busId
|
||||
] = event.enabled;
|
||||
this.setState({
|
||||
buses,
|
||||
outputBuses: buses,
|
||||
});
|
||||
this.props.onChange({
|
||||
type: "StripBusOutputChanged",
|
||||
|
@ -87,7 +105,6 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
}
|
||||
onStripWheel(event: React.WheelEvent) {
|
||||
console.log(event);
|
||||
|
||||
}
|
||||
onMuteToggle() {
|
||||
this.setState(
|
||||
|
@ -100,8 +117,8 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<Grid container sx={{ minHeight: "263px", minWidth: "112px" }}>
|
||||
<Stack alignItems={"center"}>
|
||||
<Stack direction={"row"}>
|
||||
<Stack alignItems={"center"} style={{ maxWidth: "min-content" }}>
|
||||
<Input
|
||||
inputProps={{
|
||||
"aria-labelledby": "input-slider",
|
||||
|
@ -110,11 +127,12 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
value={this.state.gain}
|
||||
onWheel={(ev) => this.onStripWheel(ev)}
|
||||
size="small"
|
||||
sx={{ width: "50px" }}
|
||||
sx={{ marginInline: "5px" }}
|
||||
/>
|
||||
<Slider
|
||||
sx={{
|
||||
margin: "5px",
|
||||
marginBlock: "15px",
|
||||
}}
|
||||
orientation="vertical"
|
||||
defaultValue={0.0}
|
||||
|
@ -135,6 +153,8 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
onClick={() => this.onMuteToggle()}
|
||||
variant={this.state.muted ? "contained" : "outlined"}
|
||||
color={"error"}
|
||||
style={{ paddingInline: "0px", maxWidth: "5px" }}
|
||||
size="large"
|
||||
>
|
||||
Mute
|
||||
</Button>
|
||||
|
@ -157,12 +177,12 @@ export class Strip extends React.Component<StripProps, StripState> {
|
|||
}
|
||||
isVirtual={i < this.props.physicalBuses ? false : true}
|
||||
onChange={(ev) => this.onBusChange(ev)}
|
||||
default={{ enabled: this.state.buses[i] }}
|
||||
default={{ enabled: this.state.outputBuses[i] }}
|
||||
/>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function RootLayout({
|
|||
<Head>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
</Head>
|
||||
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
|
|
191
src/app/page.tsx
191
src/app/page.tsx
|
@ -1,5 +1,5 @@
|
|||
"use client";
|
||||
import React from "react";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Strip, StripEvent } from "./component/Strip";
|
||||
import {
|
||||
Button,
|
||||
|
@ -7,11 +7,15 @@ import {
|
|||
createTheme,
|
||||
CssBaseline,
|
||||
Divider,
|
||||
Slide,
|
||||
Snackbar,
|
||||
Stack,
|
||||
ThemeProvider,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
} from "@mui/material";
|
||||
import { Bus } from "./component/Bus";
|
||||
import Grid from "@mui/material/Unstable_Grid2";
|
||||
|
||||
function random(min: number, max: number, floor: boolean = true) {
|
||||
const value = Math.random() * (max - min + 1) + min;
|
||||
|
@ -19,92 +23,175 @@ function random(min: number, max: number, floor: boolean = true) {
|
|||
}
|
||||
|
||||
export default function Home() {
|
||||
const theme = useMemo(() => createTheme({ palette: { mode: "dark" } }), []);
|
||||
function onStripEvent(event: StripEvent) {
|
||||
console.log(event);
|
||||
}
|
||||
const physicalBuses = 5;
|
||||
const virtualBuses = 3;
|
||||
const strips = physicalBuses + virtualBuses;
|
||||
const isSnackBarHidden = useMemo(() => {
|
||||
if (typeof localStorage === "undefined") return false;
|
||||
return localStorage.getItem("snackBarHidden") === "true";
|
||||
}, []);
|
||||
const [snackBarVisible, setSnackBarVisibility] = useState(false);
|
||||
const breakPoints = useMemo(() => theme.breakpoints.values, []);
|
||||
const [width, setWidth] = useState(
|
||||
typeof document !== "undefined" ? window.innerWidth : 0
|
||||
);
|
||||
useEffect(() => {
|
||||
setSnackBarVisibility(!isSnackBarHidden);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const values = {} as Record<string, [number, "bigger" | "smaller" | "equal"]>;
|
||||
type valuesKey = keyof typeof breakPoints;
|
||||
for (const key in breakPoints) {
|
||||
if (Object.prototype.hasOwnProperty.call(breakPoints, key)) {
|
||||
const breakPointWidth = breakPoints[key as keyof typeof breakPoints];
|
||||
values[key as valuesKey] =
|
||||
[breakPointWidth, breakPointWidth === width
|
||||
? "equal"
|
||||
: breakPointWidth > width
|
||||
? "bigger"
|
||||
: "smaller"];
|
||||
}
|
||||
}
|
||||
console.clear()
|
||||
console.log(
|
||||
width,
|
||||
`Closest: ${
|
||||
Object.entries(breakPoints).reduce((acc, i) => {
|
||||
const equation = Math.abs(i[1] - width) <= Math.abs(acc[1] - width) ? i : acc;
|
||||
return equation;
|
||||
})[0]
|
||||
}`,
|
||||
);
|
||||
console.table(values);
|
||||
}, [width]);
|
||||
const strips = { virtual: 3, physical: 5 };
|
||||
const buses = { virtual: 3, physical: 5 };
|
||||
const amountOfStrips = strips.physical + strips.virtual;
|
||||
const amountOfBuses = buses.physical + buses.virtual;
|
||||
let clicks = 0;
|
||||
let timeout: NodeJS.Timeout | undefined;
|
||||
document.body.onclick = (e) => {
|
||||
if (typeof document !== "undefined") {
|
||||
document.onclick = (e) => {
|
||||
clicks++;
|
||||
if (timeout !== undefined) {
|
||||
clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
}
|
||||
timeout = setTimeout(() => (clicks = 0), 500);
|
||||
timeout = setTimeout(() => (clicks = 0), 250);
|
||||
console.log(e);
|
||||
if (clicks < 2) return;
|
||||
clearTimeout(timeout);
|
||||
clicks = 0;
|
||||
console.log(e.target);
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (document.fullscreenElement !== null) document.exitFullscreen();
|
||||
else document.body.requestFullscreen({ navigationUI: "hide" });
|
||||
// e.stopPropagation();
|
||||
|
||||
// if (document.fullscreenElement !== null) document.exitFullscreen();
|
||||
// else document.body.requestFullscreen({ navigationUI: "hide" });
|
||||
};
|
||||
window.onresize = () => {
|
||||
setWidth(window.innerWidth);
|
||||
};
|
||||
}
|
||||
|
||||
const snackBarActionButton = (
|
||||
<>
|
||||
<Button
|
||||
onClick={() => {
|
||||
localStorage.setItem("snackBarHidden", "true");
|
||||
setSnackBarVisibility(false);
|
||||
}}
|
||||
color="secondary"
|
||||
>
|
||||
Gotcha
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<ThemeProvider theme={createTheme({ palette: { mode: "dark" } })}>
|
||||
<Container maxWidth="xl" sx={{ height: "100%" }}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Container maxWidth={"xl"} sx={{ height: "100%", paddingInline: "5px" }}>
|
||||
<div>
|
||||
<CssBaseline />
|
||||
<Typography variant="h5">Inputs</Typography>
|
||||
<Stack direction={"row"}>
|
||||
{[...Array(strips)].map((_v, i) => (
|
||||
<Grid
|
||||
container
|
||||
spacing={width ? 0 : 1}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"space-evenly"}
|
||||
columns={{ xs: 8, sm: 12, md: 5, lg: 12 }}
|
||||
>
|
||||
{[...Array(amountOfStrips)].map((_v, stripId) => (
|
||||
<React.Fragment
|
||||
key={`${i < physicalBuses ? "a" : "b"}${
|
||||
i < physicalBuses ? i : i - physicalBuses
|
||||
key={`${stripId < amountOfStrips ? "a" : "b"}${
|
||||
stripId < amountOfStrips
|
||||
? stripId + 1
|
||||
: stripId + 1 - amountOfStrips
|
||||
}`}
|
||||
>
|
||||
{i === physicalBuses ? (
|
||||
{stripId === amountOfStrips && width > breakPoints.lg && (
|
||||
<Grid>
|
||||
<Divider
|
||||
sx={{ marginBlock: "15px", borderWidth: "1px" }}
|
||||
variant="fullWidth"
|
||||
orientation="vertical"
|
||||
variant="middle"
|
||||
sx={{ marginInlineEnd: "15px" }}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
>
|
||||
Virtual Inputs
|
||||
</Divider>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid
|
||||
lg={stripId + 1 === strips.physical ? 2 : 0}
|
||||
xs={1}
|
||||
sm={1}
|
||||
md={0}
|
||||
sx={{ minWidth: "fit-content" }}
|
||||
>
|
||||
<Typography variant="overline">{`Strip #${
|
||||
stripId + 1
|
||||
}`}</Typography>
|
||||
<Strip
|
||||
onChange={(ev) => onStripEvent(ev)}
|
||||
physicalBuses={physicalBuses}
|
||||
virtualBuses={virtualBuses}
|
||||
physicalBuses={buses.physical}
|
||||
virtualBuses={buses.virtual}
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Stack>
|
||||
<Typography variant="h5">Outputs</Typography>
|
||||
<Stack direction={"column"}>
|
||||
{[...Array(strips)].map((_v, i) => (
|
||||
<React.Fragment
|
||||
key={`${i < physicalBuses ? "a" : "b"}${
|
||||
i < physicalBuses ? i : i - physicalBuses
|
||||
}`}
|
||||
>
|
||||
{i === physicalBuses ? (
|
||||
<Divider
|
||||
orientation="vertical"
|
||||
variant="middle"
|
||||
sx={{ margin: "5px" }}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Bus
|
||||
onChange={(ev) => onStripEvent(ev)}
|
||||
physicalBuses={physicalBuses}
|
||||
virtualBuses={virtualBuses}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Button></Button>
|
||||
<Typography variant="h5">Outputs</Typography>
|
||||
<Grid container spacing={1} direction={"column"}>
|
||||
{[...Array(amountOfBuses)].map((_v, busId) => (
|
||||
<Grid
|
||||
key={`${busId < buses.physical ? "a" : "b"}${
|
||||
busId < buses.physical
|
||||
? busId + 1
|
||||
: busId + 1 - buses.physical
|
||||
}`}
|
||||
xs={12}
|
||||
>
|
||||
<Typography variant="overline">{`Bus ${
|
||||
busId < buses.physical ? "a" : "b"
|
||||
}${
|
||||
busId < buses.physical
|
||||
? busId + 1
|
||||
: busId + 1 - buses.physical
|
||||
}`}</Typography>
|
||||
<Bus onChange={console.log} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</div>
|
||||
</Container>
|
||||
<Snackbar
|
||||
anchorOrigin={{ horizontal: "center", vertical: "top" }}
|
||||
TransitionComponent={Slide}
|
||||
transitionDuration={250}
|
||||
open={snackBarVisible}
|
||||
message="Triple tap on empty space for toggle fullscreen"
|
||||
action={snackBarActionButton}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
|
29
src/utils/EventCounter.ts
Normal file
29
src/utils/EventCounter.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
interface EventListener {
|
||||
name: keyof EventCounter["events"];
|
||||
callback: Function | Promise<any>;
|
||||
count: number;
|
||||
}
|
||||
type EventName = string;
|
||||
type EventInfo = number[];
|
||||
|
||||
export class EventCounter {
|
||||
events: Record<EventName, EventInfo> = {};
|
||||
|
||||
listeners: Record<EventName, EventListener[]> = {};
|
||||
|
||||
private checkListeners(eventName: EventListener["name"]) {
|
||||
this.events[eventName];
|
||||
}
|
||||
private countEmits(eventName: EventListener["name"], periodOfTime: number) {}
|
||||
emit(eventName: EventListener["name"]) {
|
||||
|
||||
this.events[eventName].length >= 100 && this.events[eventName].shift();
|
||||
}
|
||||
on(args: EventListener) {
|
||||
const { name: eventName, callback, count } = args;
|
||||
if (eventName in this.events === undefined) this.events[eventName] = [];
|
||||
if (!Object.prototype.hasOwnProperty.call(this.listeners, eventName))
|
||||
this.listeners[eventName] = [];
|
||||
this.listeners[eventName].push({ callback, count, name: eventName });
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user