You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.1 KiB
JavaScript

import { faCode } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Form } from "react-bootstrap";
import colorSets from "./variables.module.scss";
import { drumPadKeys } from "./drumPadKeys.js";
import "./App.scss";
class App extends React.Component {
constructor() {
super({});
const processedColorSets = {};
let noOfColorSets = 0;
for (const key in colorSets) {
if (/rgba/.test(colorSets[key])) {
processedColorSets[key] = colorSets[key].split(/(?<=\))\s/g);
} else if (/,\s/.test(colorSets[key])) {
processedColorSets[key] = colorSets[key].split(/,\s/g);
} else if (/\s/.test(colorSets[key])) {
processedColorSets[key] = colorSets[key].split(/\s/g);
} else if (/,[?=#]/.test(colorSets[key])) {
processedColorSets[key] = colorSets[key].split(/,/g);
} else {
console.log("Error: split pattern not implemented");
}
noOfColorSets = processedColorSets[key].length;
}
this.state = {
colorSets: processedColorSets,
noOfColorSets: noOfColorSets,
drumPadKeys: drumPadKeys,
power: true,
bank: false,
volume: 100,
displayPanelText: "Drum Machine",
};
this.updateColors = this.updateColors.bind(this);
this.togglePower = this.togglePower.bind(this);
this.togglePowerColor = this.togglePowerColor.bind(this);
this.handleVolumeChange = this.handleVolumeChange.bind(this);
this.toggleBank = this.toggleBank.bind(this);
this.displayDrumPadPress = this.displayDrumPadPress.bind(this);
this.updateColors();
}
togglePower() {
this.setState((state) => ({
power: !state.power,
displayPanelText: `Power: ${!state.power ? "ON" : "OFF"}`,
}));
this.togglePowerColor();
}
displayDrumPadPress(note) {
this.setState({
displayPanelText: note,
});
}
togglePowerColor() {
if (!this.state.power) {
this.updateColors();
} else {
const root = document.documentElement;
root.style.setProperty("--custom-color", "#666");
root.style.setProperty("--custom-darker-color", "#555");
root.style.setProperty("--custom-super-light-color", "#eee");
}
}
toggleBank() {
this.setState((state) => ({
bank: !state.bank,
displayPanelText: !state.bank ? "Smooth Piano Kit" : "Heater Kit",
}));
if (this.state.power) {
this.updateColors();
}
}
handleVolumeChange(event) {
this.setState({
volume: event.target.value,
displayPanelText: `Volume: ${event.target.value}`,
});
}
updateColors() {
const randomColorIndex = Math.floor(
Math.random() * this.state.noOfColorSets
);
const root = document.documentElement;
root.style.setProperty("--bs-body-font-weight", "bold");
root.style.setProperty(
"--custom-color",
this.state.colorSets.colors[randomColorIndex]
);
root.style.setProperty(
"--custom-darker-color",
this.state.colorSets.darkerColors[randomColorIndex]
);
root.style.setProperty(
"--custom-super-light-color",
this.state.colorSets.superLightColors[randomColorIndex]
);
}
render() {
const drumPadKeys = [];
this.state.drumPadKeys.forEach((drumPad, index) => {
drumPadKeys.push(
<DrumPad
drumPadKey={drumPad.key}
noteName={this.state.bank ? drumPad.altName : drumPad.name}
audioSrc={this.state.bank ? drumPad.altAudioSrc : drumPad.audioSrc}
power={this.state.power}
volume={this.state.volume}
displayDrumPadPress={this.displayDrumPadPress}
/>
);
if (index % 3 === 2) {
drumPadKeys.push(<div className="w-100"></div>);
}
});
return (
<div
className="text-center d-flex align-items-center min-vh-100 custom-bg-color"
id="drum-machine"
>
<div className="container">
<div
className="row p-4 justify-content-center justify-content-md-left bg-white text-black"
id="drum-pads-and-controls"
>
<div className="col-md-8 col-12">
<div className="row pe-auto pe-md-3">{drumPadKeys}</div>
</div>
<div className="col-md-4 col-sm-6 col-8">
<div className="row h-100">
<div className="col-12 mt-2 mb-0 my-md-0">
<p className="m-0">Power</p>
<Form.Switch
id="Power"
checked={this.state.power}
onChange={this.togglePower}
></Form.Switch>
</div>
<p
className="col-12 my-2 my-md-auto panel-bg-color"
id="display"
>
{this.state.displayPanelText}
</p>
<div className="col-12 my-2 my-md-auto">
<p className="m-0">Volume</p>
<Form.Range
onChange={this.handleVolumeChange}
value={this.state.volume}
/>
</div>
<div className="col-12 my-0">
<p className="m-0">Bank</p>
<Form.Switch
id="bank"
checked={this.state.bank}
onChange={this.toggleBank}
></Form.Switch>
</div>
</div>
</div>
</div>
<footer className="mt-2">
<p>
<a
className="link-light"
href="https://radii.dev/freeCodeCamp.org-Front-End-Dev-Libraries/Build-a-Drum-Machine"
>
<FontAwesomeIcon icon={faCode} /> {`Source Code & License`}
</a>
</p>
</footer>
</div>
</div>
);
}
}
class DrumPad extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.playSound = this.playSound.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
handleKeyPress(event) {
if (String(event.key).toUpperCase() === this.props.drumPadKey) {
this.playSound();
}
}
componentDidMount() {
this.audio = document.getElementById(this.props.drumPadKey);
document.addEventListener("keydown", this.handleKeyPress, false);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleKeyPress, false);
}
playSound() {
this.props.displayDrumPadPress(this.props.noteName);
this.audio.play();
}
render() {
return (
<div className="col-4 p-1">
<button
id={`${this.props.drumPadKey}-button`}
className={`drum-pad w-100 h-100 btn custom-el-color rounded-0`}
style={{
paddingTop: "20%",
paddingBottom: "20%",
fontWeight: "bold",
}}
onClick={this.playSound}
>
{this.props.drumPadKey}
<audio
className="clip"
id={this.props.drumPadKey}
src={this.props.audioSrc}
preload="auto"
/>
</button>
</div>
);
}
}
export default App;