-
Blockly Toolbox
-
Blockly Workspace
-
+
+
+ Blockly Toolbox
+
+
+ Blockly Workspace
+
+
+
Generate Code
+
+ {displayCodeString()}
+
);
};
-export default BlocklyComponent;
\ No newline at end of file
+export default BlocklyComponent;
diff --git a/src/components/ButtonTabs.jsx b/src/components/ButtonTabs.jsx
new file mode 100644
index 0000000..cc09328
--- /dev/null
+++ b/src/components/ButtonTabs.jsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { setActiveTab } from "../features/soundTabReducers";
+
+
+
+function ButtonTabs(props) {
+ const dispatch = useDispatch();
+ const active = useSelector((state) => state.soundTab.activeTab);
+ const buttonStyles = {
+ backgroundColor: "#cccccc",
+ flexBasis: "100px",
+ fontSize: "1rem",
+ textAlign: "center",
+ textDecoration: "none",
+ cursor: "pointer",
+ color: "#1976d2",
+ borderRadius: "1rem 1rem 0 0",
+ border: "1px solid hsla(0, 0%, 0%, 0.15)",
+ padding: "0.125rem 1.25rem 0",
+ borderBottom: "0px",
+
+ transition: "background-color 0.2s",
+ };
+
+ const activeButton = {
+ ...buttonStyles,
+ fontSize: "1.1rem",
+ backgroundColor: "white",
+ transform: "scale(1.1)",
+ };
+
+ const handleButtonClick = (value) => {
+ dispatch(setActiveTab(value));
+ };
+
+ return (
+
+ handleButtonClick("Home")}
+ >
+ Home
+
+ handleButtonClick("Sounds")}
+ >
+ Sounds
+
+
+ );
+}
+
+export default ButtonTabs;
diff --git a/src/components/Canvas.jsx b/src/components/Canvas.jsx
index b219d0d..4574576 100644
--- a/src/components/Canvas.jsx
+++ b/src/components/Canvas.jsx
@@ -1,62 +1,160 @@
-import React from 'react';
-import { Card } from '@mui/material';
-import Draggable from 'react-draggable';
-import { Resizable } from 're-resizable';
+import React, { useEffect, useState, useRef } from "react";
+import * as tf from "@tensorflow/tfjs";
+import * as cocossd from "@tensorflow-models/coco-ssd";
+
+import { Card } from "@mui/material";
+import Draggable from "react-draggable";
+import { Resizable } from "re-resizable";
+import { useSelector } from "react-redux";
+import { drawRect } from "../features/utlities.js";
+import Webcam from "react-webcam";
// Import the button components
-import FlagButton from './Canvas/FlagButton';
-import StopButton from './Canvas/StopButton';
-import UndoButton from './Canvas/UndoButton';
-import RedoButton from './Canvas/RedoButton';
-import ZoomIn from './Canvas/ZoomIn';
-import ZoomOut from './Canvas/ZoomOut';
-import FullScreen from './Canvas/FullScreen';
+import FlagButton from "./Canvas/FlagButton";
+import StopButton from "./Canvas/StopButton";
+import UndoButton from "./Canvas/UndoButton";
+import RedoButton from "./Canvas/RedoButton";
+import ZoomIn from "./Canvas/ZoomIn";
+import ZoomOut from "./Canvas/ZoomOut";
+import FullScreen from "./Canvas/FullScreen";
+
+import { setDetectedObjs } from "../features/detection.js";
+import { useDispatch } from "react-redux";
const Canvas = () => {
+ const isCameraOn = useSelector((state) => state.camera.isCameraOn);
+ // const [net, setNet] = useState(null);
+ const webcamRef = useRef(null);
+ const canvasRef = useRef(null);
+
+ const dispatch = useDispatch();
+
+ const runCoco = async () => {
+ // 3. TODO - Load network
+ const net = await cocossd.load();
+
+ // Loop and detect hands
+ setInterval(() => {
+ detect(net);
+ });
+ };
+
+ const detect = async (net) => {
+ // Check data is available
+ if (
+ typeof webcamRef.current !== "undefined" &&
+ webcamRef.current !== null &&
+ webcamRef.current.video.readyState === 4
+ ) {
+ // Get Video Properties
+ const video = webcamRef.current.video;
+ const videoWidth = webcamRef.current.video.videoWidth;
+ const videoHeight = webcamRef.current.video.videoHeight;
+
+ // Set video width
+ webcamRef.current.video.width = videoWidth;
+ webcamRef.current.video.height = videoHeight;
+
+ // Set canvas height and width
+ canvasRef.current.width = videoWidth;
+ canvasRef.current.height = videoHeight;
+
+ // Make Detections
+
+ const obj = await net.detect(video);
+ console.log(obj);
+ dispatch(setDetectedObjs(obj));
+
+ // if ((obj.find(el => el.class == 'cell phone'))) {
+ // setFlag(1)
+ // count++;
+ // }
+ // if (obj.length > 1 || obj.length == 0) {
+ // setFlag(1);
+ // count++;
+ // } else {
+ // setFlag(0);
+ // }
+
+ // Draw mesh
+ const ctx = canvasRef.current.getContext("2d");
+ drawRect(obj, ctx);
+ }
+ };
+
+ // const[person,setperson] = useState("")
+ useEffect(() => {
+ // Speech()
+ runCoco();
+ // setperson(name)
+ }, []);
+
+ const { position, angle } = useSelector((state) => ({
+ position: state.motion.position,
+ angle: state.motion.angle,
+ }));
+
+ // useEffect(() => {
+ // const spriteElement = document.getElementById("sprite");
+ // if (spriteElement) {
+ // spriteElement.style.transform = `translate(${position.x}px, ${position.y}px) rotate(${angle}deg)`;
+ // }
+ // if (isCameraOn) {
+ // detect();
+ // }
+ // }, [position, angle, isCameraOn]);
+
return (
-
- Canvas
-
-
+
+ Canvas
+ {isCameraOn && }
+
+
+
+
+
+
+
-
-
-
-
-
-
- {}} />
- {}} />
- {}} />
- {}} />
-
-
-
{}} />
- {}} />
- {}} />
+
+ {}} />
+ {}} />
+ {}} />
+ {}} />
+ {}} />
+
+
+ {}} />
+ {}} />
+ {}} />
+
-
-
+
+
);
};
-export default Canvas;
\ No newline at end of file
+export default Canvas;
diff --git a/src/components/InitializeBlockly.jsx b/src/components/InitializeBlockly.jsx
index 685eb34..17b4df1 100644
--- a/src/components/InitializeBlockly.jsx
+++ b/src/components/InitializeBlockly.jsx
@@ -1,7 +1,15 @@
import Blockly from "blockly/core";
import "blockly/blocks";
+import { javascriptGenerator } from "blockly/javascript";
+import {store} from "../store/store.js";
+import {moveSteps, setX, setY, goTo, goToXY,moveSpriteToMousePointer,turnRight,turnLeft,pointInDirection, rotateSprite, glideSecsXY
+} from '../features/motionSlice';
+import { waitSeconds , repeatTimes} from '../features/controlSlice';
+import { setCodeString } from "../features/codeSlice";
+import { useSelector } from "react-redux";
const InitializeBlockly = (toolboxXml) => {
+
const workspace = Blockly.inject("blocklyDiv", {
toolbox: toolboxXml,
zoom: {
@@ -26,6 +34,39 @@ const InitializeBlockly = (toolboxXml) => {
wheel: true,
},
});
+ async function onBlockClick(event) {
+ // console.log('Event details:', event);
+ if (event.type === Blockly.Events.CLICK ) {
+ var clickedBlock = workspace.getBlockById(event.blockId);
+ // console.log('Clicked block:', clickedBlock);
+ if (clickedBlock) {
+ var codeToExecute = generateCodeForBlock(clickedBlock);
+ const codeString = store.getState().code.codeString;
+
+ if (codeToExecute !== codeString) {
+ store.dispatch(setCodeString(codeToExecute));
+ }
+ store.dispatch(setCodeString(codeToExecute));
+ // console.log('Executing block code:', codeToExecute);
+ try {
+ // Evaluate the code.
+ await eval(`(async () => { ${codeToExecute} })();`);
+ } catch (error) {
+ console.error('Error executing block code:', error);
+ }
+ }
+ }
+ }
+
+ // Function to generate code for a block
+ function generateCodeForBlock(block) {
+ javascriptGenerator.addReservedWords('code');
+ const blockCode = javascriptGenerator.blockToCode(block);
+ return blockCode;
+ }
+
+ workspace.addChangeListener(onBlockClick);
+
// Create custom zoom controls
const customUndoButton = createUndoButton(workspace, 30);
@@ -43,9 +84,16 @@ const InitializeBlockly = (toolboxXml) => {
const customResetButton = createResetButton(workspace, 30);
// Append custom controls to Blockly's div
+ // const blocklyDiv = workspace.getParentSvg().parentNode;
blocklyDiv.appendChild(customZoomInButton.button);
blocklyDiv.appendChild(customResetButton.button);
blocklyDiv.appendChild(customZoomOutButton.button);
+
+
+ // Define the custom Blockly block
+ //on DOM load
+
+
return workspace;
};
diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx
new file mode 100644
index 0000000..7817e4a
--- /dev/null
+++ b/src/components/Sidebar.jsx
@@ -0,0 +1,98 @@
+// Sidebar.jsx
+import React, { useState } from "react";
+import AudioCard from "./AudioCard";
+import { useSelector, useDispatch } from "react-redux";
+import { setAudioArray } from "../features/soundTabReducers.js";
+
+const Sidebar = (props) => {
+ const [isFabHovered, setIsFabHovered] = useState(false);
+
+ const audioArray = useSelector((state) => state.soundTab.audioArray);
+ const dispatch = useDispatch();
+
+ function handleCardDelete(id) {
+ props.onDelete(id);
+ }
+ return (
+
+ {audioArray.map((audioItem) => {
+ const { id, fileName, audioUrl } = audioItem;
+ return (
+
+ );
+ })}
+
setIsFabHovered(true)}
+ onMouseLeave={() => setIsFabHovered(false)}
+ >
+ {isFabHovered && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
+
+ +
+
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/src/components/Sounds.jsx b/src/components/Sounds.jsx
new file mode 100644
index 0000000..d2164e8
--- /dev/null
+++ b/src/components/Sounds.jsx
@@ -0,0 +1,44 @@
+// Sounds.jsx
+import React from "react";
+import UploadAudio from "./UploadAudio";
+
+export default function Books({ history }) {
+ return (
+
+ );
+}
diff --git a/src/components/UploadAudio.jsx b/src/components/UploadAudio.jsx
new file mode 100644
index 0000000..1f88af5
--- /dev/null
+++ b/src/components/UploadAudio.jsx
@@ -0,0 +1,181 @@
+// UploadAudio.jsx
+import React, { useState, useEffect, useRef, useContext } from "react";
+import { FileContext } from "../contexts/fileContext.jsx";
+import AudioWaveform from "./AudioWaveform"; // Import your AudioWaveform component
+import Sidebar from "./Sidebar";
+import "../index.css";
+import { useDispatch, useSelector } from "react-redux";
+import {
+ setAudioState,
+ setAudioArray,
+ setActiveWaveform,
+} from "../features/soundTabReducers.js";
+import { setIsPlaying } from "../features/audioSlice.js";
+import { v4 as uuidv4 } from "uuid";
+import RecordAudio from "./recordAudio/RecordAudio.jsx";
+
+const UploadAudio = () => {
+ const dispatch = useDispatch();
+ const inputFile = useRef(null);
+ const { fileURL, setFileURL } = useContext(FileContext);
+ const [file, setFile] = useState(null);
+ const audioState = useSelector((state) => state.soundTab.audioState);
+ const { showAudioWaveform, fileName } = audioState;
+ const audioArray = useSelector((state) => state.soundTab.audioArray);
+ const [isPopupOpen, setIsPopupOpen] = useState(false);
+
+ const openPopup = () => {
+ setIsPopupOpen(true);
+ };
+
+ const closePopup = () => {
+ setIsPopupOpen(false);
+ };
+
+ //For rendering default music
+ useEffect(() => {
+ const handleBeforeUnload = (event) => {
+ event.preventDefault();
+ };
+ window.addEventListener("beforeunload", handleBeforeUnload);
+ return () => {
+ window.removeEventListener("beforeunload", handleBeforeUnload);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (file) {
+ setFileURL(file);
+ }
+ }, [file, setFileURL]);
+
+ const handleButtonClick = () => {
+ inputFile.current.click();
+ };
+ const handleRecordClick = () => {
+ openPopup(); // Assuming `openPopup` handles opening the recording popup
+ };
+
+ const handleFileUpload = (e) => {
+ const name = e.target.files[0].name;
+ setFile(URL.createObjectURL(e.target.files[0]));
+
+ //redux actions
+ dispatch(setIsPlaying(false));
+ //Adding to array
+ const newSound = {
+ id: uuidv4(),
+ fileName: name.slice(0, name.length - 4),
+ audioUrl: URL.createObjectURL(e.target.files[0]),
+ };
+ const updatedAudioArray = [...audioArray, newSound];
+ dispatch(setAudioArray(updatedAudioArray));
+
+ dispatch(setActiveWaveform(newSound));
+ if (updatedAudioArray.length === 1) {
+ dispatch(
+ setAudioState({
+ showAudioWaveform: true,
+ fileName: name.slice(0, name.length - 4),
+ })
+ );
+ }
+ // Clear regions in the AudioWaveform component
+ if (wavesurferObj) {
+ wavesurferObj.clearRegions();
+ }
+ };
+
+ const handleDelete = async (id) => {
+ const updatedAudioArray = audioArray.filter(
+ (audioItem) => audioItem.id !== id
+ );
+ dispatch(setAudioArray(updatedAudioArray));
+
+ if (updatedAudioArray.length === 0) {
+ dispatch(
+ setAudioState({
+ showAudioWaveform: false,
+ fileName: "",
+ })
+ );
+ dispatch(setActiveWaveform({}));
+ } else {
+ dispatch(setActiveWaveform(updatedAudioArray[0]));
+ }
+ };
+
+ const handleSaveAudio = (audioSrc) => {
+ // setFileURL(audioSrc);
+ // dispatch(setAudioState({
+ // showAudioWaveform: true,
+ // fileName: "RecordedAudio", // You may set a default name for the recorded audio
+ // }));
+ dispatch(setIsPlaying(false));
+ const newSound = {
+ id: uuidv4(),
+ fileName: "Recorded Audio",
+ audioUrl: audioSrc,
+ };
+ const updatedAudioArray = [...audioArray, newSound];
+ dispatch(setAudioArray(updatedAudioArray));
+ dispatch(setActiveWaveform(newSound));
+ if (updatedAudioArray.length === 1) {
+ dispatch(
+ setAudioState({
+ showAudioWaveform: true,
+ fileName: "Recorded Audio",
+ })
+ );
+ }
+
+ closePopup();
+ };
+
+ return (
+
+
{" "}
+ {/* Add the Sidebar component here */}
+
+ {showAudioWaveform &&
}
+
+
+ {/* Upload audio button */}
+ {!showAudioWaveform && (
+ <>
+
+ library_music
+
+
Upload your audio file here
+ >
+ )}
+
+ {/*
+ Upload
+ */}
+
+
+ {/*
Record */}
+ {isPopupOpen && (
+
+ )}
+
+
+ );
+};
+
+export default UploadAudio;
diff --git a/src/components/audioArray.js b/src/components/audioArray.js
new file mode 100644
index 0000000..7cb16e1
--- /dev/null
+++ b/src/components/audioArray.js
@@ -0,0 +1,13 @@
+// Object constains:
+// id
+// fileName:"",
+// audioUrl:""
+
+const audioArray = [
+ {
+ id:"1",
+ fileName:"Default sound",
+ audioUrl:"defaultsound.wav",
+ }
+]
+export default audioArray;
\ No newline at end of file
diff --git a/src/components/bufferToWave.jsx b/src/components/bufferToWave.jsx
new file mode 100644
index 0000000..e3c95b1
--- /dev/null
+++ b/src/components/bufferToWave.jsx
@@ -0,0 +1,55 @@
+//To convert AudioBuffer to wav URL. Required to play sound
+
+export function bufferToWave(abuffer, offset, len) {
+
+ var numOfChan = abuffer.numberOfChannels,
+ length = len * numOfChan * 2 + 44,
+ buffer = new ArrayBuffer(length),
+ view = new DataView(buffer),
+ channels = [], i, sample,
+ pos = 0;
+
+ // write WAVE header
+ setUint32(0x46464952); // "RIFF"
+ setUint32(length - 8); // file length - 8
+ setUint32(0x45564157); // "WAVE"
+
+ setUint32(0x20746d66); // "fmt " chunk
+ setUint32(16); // length = 16
+ setUint16(1); // PCM (uncompressed)
+ setUint16(numOfChan);
+ setUint32(abuffer.sampleRate);
+ setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
+ setUint16(numOfChan * 2); // block-align
+ setUint16(16); // 16-bit (hardcoded in this demo)
+
+ setUint32(0x61746164); // "data" - chunk
+ setUint32(length - pos - 4); // chunk length
+
+ // write interleaved data
+ for(i = 0; i < abuffer.numberOfChannels; i++)
+ channels.push(abuffer.getChannelData(i));
+
+ while(pos < length) {
+ for(i = 0; i < numOfChan; i++) { // interleave channels
+ sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
+ sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
+ view.setInt16(pos, sample, true); // update data chunk
+ pos += 2;
+ }
+ offset++ // next source sample
+ }
+
+ // create Blob
+ return (URL || webkitURL).createObjectURL(new Blob([buffer], {type: "audio/wav"}));
+
+ function setUint16(data) {
+ view.setUint16(pos, data, true);
+ pos += 2;
+ }
+
+ function setUint32(data) {
+ view.setUint32(pos, data, true);
+ pos += 4;
+ }
+ }
\ No newline at end of file
diff --git a/src/components/recordAudio/AudioRecorder.jsx b/src/components/recordAudio/AudioRecorder.jsx
new file mode 100644
index 0000000..caaf5ab
--- /dev/null
+++ b/src/components/recordAudio/AudioRecorder.jsx
@@ -0,0 +1,135 @@
+import React, { useState, Component } from "react";
+import AudioAnalyser from "react-audio-analyser";
+import RecordButton from "./RecordButton.jsx";
+import WaveSurfer from "wavesurfer.js";
+
+export default class AudioRecorder extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ status: "",
+ audioType: "audio/mp3",
+ audioSrc: null, // Initialize audioSrc to null
+ saveAudio: false,
+ };
+
+ this.waveSurfer = null;
+ }
+
+ handleSaveAudioClick = () => {
+ this.setState(
+ (prevState) => ({
+ saveAudio: !prevState.saveAudio,
+ }),
+ () => {
+ if (this.state.saveAudio) {
+ this.props.onSaveAudio(this.state.audioSrc);
+ }
+ }
+ );
+ };
+
+ controlAudio(status) {
+ this.setState({
+ status,
+ });
+ }
+
+ // stopCallback = (e) => {
+ // const audioSrc = window.URL.createObjectURL(e);
+ // this.setState({ audioSrc }, () => {
+ // this.initWaveSurfer();
+ // });
+ // console.log("succ stop", e);
+ // };
+
+ componentDidMount() {
+ // this.setState({
+ // audioType: "audio/wav"
+ // });
+ }
+
+ toggleRecording() {
+ this.state.status === "recording"
+ ? this.controlAudio("inactive")
+ : this.controlAudio("recording");
+ }
+
+ render() {
+ const { status, audioSrc, audioType } = this.state;
+ const audioProps = {
+ audioType,
+ // audioOptions: {sampleRate: 30000}, // 设置输出音频采样率
+ status,
+ audioSrc,
+ timeslice: 1000, // timeslice(https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/start#Parameters)
+ startCallback: (e) => {
+ console.log("succ start", e);
+ },
+ pauseCallback: (e) => {
+ console.log("succ pause", e);
+ },
+ stopCallback: (e) => {
+ this.setState({
+ audioSrc: window.URL.createObjectURL(e),
+ });
+ console.log("succ stop", e);
+ },
+ onRecordCallback: (e) => {
+ console.log("recording", e);
+ },
+ errorCallback: (err) => {
+ console.log("error", err);
+ },
+ };
+ return (
+
+
+
+ {
+ this.toggleRecording();
+ // toggleIsRecording();
+ }}
+ />
+
+
+ {audioSrc && (
+
+ Save Audio
+
+ )}
+
+ {/*
this.changeScheme(e)}
+ value={audioType}
+ >
+ audio/webm(default)
+ audio/wav
+ audio/mp3
+ */}
+
+ );
+ }
+}
diff --git a/src/components/recordAudio/RecordAudio.css b/src/components/recordAudio/RecordAudio.css
new file mode 100644
index 0000000..3df4894
--- /dev/null
+++ b/src/components/recordAudio/RecordAudio.css
@@ -0,0 +1,25 @@
+/* Popup.css */
+.recordaudio-container {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1000;
+ }
+
+ .recordaudio {
+ background-color: white;
+ padding: 20px;
+ border-radius: 10px;
+ box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
+ }
+
+ /* Apply backdrop blur effect */
+ .recordaudio-container {
+ backdrop-filter: blur(5px);
+ }
\ No newline at end of file
diff --git a/src/components/recordAudio/RecordAudio.jsx b/src/components/recordAudio/RecordAudio.jsx
new file mode 100644
index 0000000..c72a97d
--- /dev/null
+++ b/src/components/recordAudio/RecordAudio.jsx
@@ -0,0 +1,38 @@
+// RecordAudio.js
+import React from "react";
+import "./RecordAudio.css";
+import AudioRecorder from "./AudioRecorder";
+
+const RecordAudio = ({ onClose, onSaveAudio }) => {
+ return (
+
+
+
Audio Recorder
+
+
+ Close
+
+
+
+ );
+};
+
+export default RecordAudio;
diff --git a/src/components/recordAudio/RecordButton.jsx b/src/components/recordAudio/RecordButton.jsx
new file mode 100644
index 0000000..f6c3d44
--- /dev/null
+++ b/src/components/recordAudio/RecordButton.jsx
@@ -0,0 +1,79 @@
+import React, { Fragment, useState } from "react";
+import MicIcon from "@material-ui/icons/Mic";
+import StopIcon from "@material-ui/icons/Stop";
+import Fab from "@material-ui/core/Fab";
+import Tooltip from "@material-ui/core/Tooltip";
+import styled from "styled-components";
+
+const StyledFab = styled(Fab)`
+ position: relative;
+ background-color: ${props => (props.recording ? "#272727" : "#ff3466")};
+ color: white;
+ opacity: 1;
+ margin: 12px;
+ transition: all 0.2s;
+ .pulse-bg {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ background-color: #ff3466;
+ border-radius: 100%;
+ opacity: 0.5;
+ z-index: -10;
+ animation: pulse 1s ease-out infinite;
+ }
+ :hover {
+ background-color: ${props => (props.recording ? "#272727" : "#ff3466")};
+ opacity: 0.9;
+ }
+ @keyframes pulse {
+ 0% {
+ transform: scale(1, 1);
+ }
+ 50% {
+ opacity: 0.3;
+ }
+ 100% {
+ transform: scale(1.5);
+ opacity: 0;
+ }
+ }
+`;
+
+export default function RecordButton(props) {
+ const [isRecording, setIsRecording] = useState(false);
+
+ return (
+
+ {isRecording ? (
+
+ {
+ setIsRecording(false);
+ props.onClick();
+ }}
+ color="secondary"
+ aria-label="record"
+ >
+
+
+
+
+ ) : (
+
+ {
+ setIsRecording(true);
+ props.onClick();
+ }}
+ color="secondary"
+ aria-label="record"
+ >
+
+
+
+ )}
+
+ );
+}
diff --git a/src/contexts/fileContext.jsx b/src/contexts/fileContext.jsx
new file mode 100644
index 0000000..682ef70
--- /dev/null
+++ b/src/contexts/fileContext.jsx
@@ -0,0 +1,13 @@
+import React, { createContext, useState } from "react";
+
+export const FileContext = createContext();
+
+export const FileProvider = ({ children }) => {
+ const [fileURL, setFileURL] = useState("defaultsound.wav");
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/contexts/waveSurferContext.jsx b/src/contexts/waveSurferContext.jsx
new file mode 100644
index 0000000..b369832
--- /dev/null
+++ b/src/contexts/waveSurferContext.jsx
@@ -0,0 +1,13 @@
+import { createContext, useContext, useState } from "react";
+
+export const WaveSurferContext = createContext();
+
+export const WaveSurferProvider = ({ children }) => {
+ const [wavesurferObj, setWavesurferObj] = useState(null);
+
+ return(
+
+ {children}
+
+ );
+};
diff --git a/src/features/audioSlice.js b/src/features/audioSlice.js
new file mode 100644
index 0000000..a682221
--- /dev/null
+++ b/src/features/audioSlice.js
@@ -0,0 +1,26 @@
+const initialState = {
+ isPlaying: false,
+ volume: 1,
+ audioObj: null,
+}
+
+import { createSlice } from "@reduxjs/toolkit"
+
+const audioSlice = createSlice({
+ name: "audio",
+ initialState: initialState,
+ reducers:{
+ setIsPlaying: (state, action) => {
+ state.isPlaying = action.payload;
+ },
+ setVolume: (state, action) => {
+ state.volume = action.payload;
+ },
+ setAudioObj: (state, action) => {
+ state.audioObj = action.payload;
+ }
+ }
+})
+
+export const {setIsPlaying, setVolume, setAudioObj} = audioSlice.actions;
+export default audioSlice.reducer;
\ No newline at end of file
diff --git a/src/features/cameraSlice.js b/src/features/cameraSlice.js
new file mode 100644
index 0000000..3233172
--- /dev/null
+++ b/src/features/cameraSlice.js
@@ -0,0 +1,17 @@
+import { createSlice } from "@reduxjs/toolkit"
+
+const cameraSlice = createSlice({
+ name: 'camera',
+ initialState: {
+ isCameraOn: false,
+ },
+ reducers: {
+ setCameraOn: (state, action) => {
+ state.isCameraOn = action.payload;
+ },
+ },
+});
+
+
+export const {setCameraOn} = cameraSlice.actions;
+export default cameraSlice.reducer;
\ No newline at end of file
diff --git a/src/features/codeSlice.js b/src/features/codeSlice.js
new file mode 100644
index 0000000..0ba6a6b
--- /dev/null
+++ b/src/features/codeSlice.js
@@ -0,0 +1,19 @@
+// codeSlice.js
+import { createSlice } from '@reduxjs/toolkit';
+
+const initialState = {
+ codeString: '',
+};
+
+const codeSlice = createSlice({
+ name: 'code',
+ initialState,
+ reducers: {
+ setCodeString: (state, action) => {
+ state.codeString = action.payload;
+ },
+ },
+});
+
+export const { setCodeString } = codeSlice.actions;
+export default codeSlice.reducer;
diff --git a/src/features/controlSlice.js b/src/features/controlSlice.js
new file mode 100644
index 0000000..2b615cc
--- /dev/null
+++ b/src/features/controlSlice.js
@@ -0,0 +1,41 @@
+// Currently nothing here
+import { createSlice } from "@reduxjs/toolkit";
+
+// Create an async thunk action to wait for seconds
+export async function waitSeconds(seconds) {
+ return new Promise(resolve => setTimeout(resolve, seconds * 1000));
+}
+
+export async function waitUntil(condition) {
+ return new Promise(resolve => {
+ const checkCondition = () => {
+ if (condition) {
+ resolve();
+ } else {
+ // Poll every 100 milliseconds (adjust as needed)
+ setTimeout(checkCondition, 100);
+ }
+ };
+ // Start checking the condition
+ checkCondition();
+ });
+}
+
+
+// Initial state of the control
+const initialState = {};
+
+export const controlSlice = createSlice({
+ name: "Control",
+ initialState,
+ reducers: {},
+});
+
+export const repeatTimes = (count, action) => async (dispatch) => {
+ for (let i = 0; i < count; i++) {
+ await dispatch(action);
+ }
+};
+
+
+export default controlSlice.reducer;
diff --git a/src/features/detection.js b/src/features/detection.js
new file mode 100644
index 0000000..e631cc5
--- /dev/null
+++ b/src/features/detection.js
@@ -0,0 +1,18 @@
+const initialState = {
+ objectArr: [],
+};
+
+import { createSlice } from "@reduxjs/toolkit";
+
+const detectSlice = createSlice({
+ name: "detect",
+ initialState: initialState,
+ reducers: {
+ setDetectedObjs: (state, action) => {
+ state.object = action.payload;
+ },
+ },
+});
+
+export const { setDetectedObjs } = detectSlice.actions;
+export default detectSlice.reducer;
diff --git a/src/features/motionSlice.js b/src/features/motionSlice.js
new file mode 100644
index 0000000..3fb3e4d
--- /dev/null
+++ b/src/features/motionSlice.js
@@ -0,0 +1,170 @@
+import { createSlice } from "@reduxjs/toolkit";
+import { useSelector } from 'react-redux';
+
+// Initial state of the sprite
+const initialState = {
+ position: { x: 150, y: 100 }, // Assuming default position
+ angle: 0,
+};
+
+// Create the slice
+export const motionSlice = createSlice({
+ name: "Motion",
+ initialState,
+ reducers: {
+ moveSteps: {
+ reducer: (state, action) => {
+ const { rightSteps, upSteps } = action.payload;
+ const angleInRadians = (state.angle * Math.PI) / 180;
+ const newX = state.position.x + rightSteps * Math.cos(angleInRadians) - upSteps * Math.sin(angleInRadians);
+ const newY = state.position.y + rightSteps * Math.sin(angleInRadians) + upSteps * Math.cos(angleInRadians);
+ state.position.x = newX;
+ state.position.y = newY;
+ },
+ prepare: (rightSteps, upSteps) => ({ payload: { rightSteps, upSteps } })
+ },
+ setX: {
+ reducer:(state,action)=> {
+ state.position.x = action.payload.rightSteps;
+ //state.position.y += action.payload.upSteps;
+ },
+ prepare: (rightSteps) => ({ payload: { rightSteps} })
+ },
+ setY: {
+ reducer:(state,action)=> {
+ //state.position.x = action.payload.rightSteps;
+ state.position.y = action.payload.upSteps;
+ },
+ prepare: (upSteps) => ({ payload: { upSteps} })
+ },
+ goTo: {
+ reducer: (state, action) => {
+ if(action.payload.destination === "random_position") {
+ state.position.x = Math.floor(Math.random() * 401) - 200;
+ state.position.y = Math.floor(Math.random() * 401) - 200;
+ }
+ },
+ prepare: (destination) => ({ payload: { destination } })
+ },
+ goToXY: {
+ reducer: (state, action) => {
+ state.position.x = action.payload.rightSteps;
+ state.position.y = action.payload.upSteps;
+ },
+ prepare: (rightSteps, upSteps) => ( { payload: {rightSteps, upSteps} } )
+ },
+
+ changeX: {
+ reducer: (state, action) => {
+ state.position.x += action.payload.dashUnits;
+ },
+ prepare: (dashUnits) => ({ payload: { dashUnits } })
+ },
+ changeY: {
+ reducer: (state, action) => {
+ state.position.y += action.payload.dashUnits;
+ },
+ prepare: (dashUnits) => ({ payload: { dashUnits } })
+ },
+ setSpritePosition: { //
+ reducer: (state, action) => {
+ state.position.x = action.payload.x;
+ state.position.y = action.payload.y;
+ },
+ prepare: (x, y) => ({ payload: { x, y } })
+ },
+ turnRight:{
+ reducer: (state, action) => {
+ state.angle += action.payload.angle;
+ console.log(state.angle);
+ },
+ prepare: (angle) => ({ payload: { angle } }),
+ },
+ turnLeft:{
+ reducer: (state, action) => {
+ state.angle -= action.payload.angle;
+ console.log(state.angle);
+ },
+ prepare: (angle) => ({ payload: { angle } }),
+ },
+ pointInDirection: {
+ reducer: (state, action) => {
+ state.angle = action.payload.angle % 360; // Ensure the angle stays within 0 to 359 degrees
+ },
+ prepare: (angle) => ({ payload: { angle } }),
+ },
+ rotateSprite: {
+ reducer: (state, action) => {
+ state.angle += action.payload.rotationAngle;
+ state.angle %= 360; // Ensure the angle stays within 0 to 359 degrees
+ },
+ prepare: (rotationAngle) => ({ payload: { rotationAngle } }),
+ },
+ // glideSecsXY: {
+ // reducer: (state, action) => {
+ // state.position.x = action.payload.x;
+ // state.position.y = action.payload.y;
+ // },
+ // prepare: (x, y) => ({ payload: { x, y } })
+ // }
+ },
+});
+
+// Export the action and reducer
+
+export const { moveSteps,setX, setY, goTo, goToXY,
+ setSpritePosition,turnRight,turnLeft,
+ pointInDirection, rotateSprite } = motionSlice.actions;
+
+export default motionSlice.reducer;
+
+export const moveSpriteToMousePointer = () => (dispatch) => {
+ const handleMouseMove = (e) => {
+ const mouseX = e.clientX;
+ const mouseY = e.clientY;
+
+ // Dispatch action to update sprite position
+ dispatch(setSpritePosition( mouseX, mouseY ));
+ };
+
+ const handleEscPress = (e) => {
+ if (e.key === 'Escape') {
+ // Cleanup: remove event listener when 'Esc' is pressed
+ window.removeEventListener('mousemove', handleMouseMove);
+ window.removeEventListener('keydown', handleEscPress);
+ }
+ };
+
+ // Add event listeners
+ window.addEventListener('mousemove', handleMouseMove);
+ window.addEventListener('keydown', handleEscPress);
+
+ // Cleanup: remove event listeners on component unmount or as needed
+ return () => {
+ window.removeEventListener('mousemove', handleMouseMove);
+ window.removeEventListener('keydown', handleEscPress);
+ };
+ };
+
+ export const glideSecsXY = (x, y, time) => (dispatch) =>{
+ const spritePosition = useSelector((state) => state.motionSlice.position);
+ console.log('Sprite Position:', spritePosition);
+ const startX = spritePosition.x;
+ const startY = spritePosition.y;
+ const distanceX = x - startX;
+ const distanceY = y - startY;
+ const steps = time / 10;
+ let currentStep = 0;
+
+ const intervalId = setInterval(() => {
+ currentStep++;
+ const newX = startX + (distanceX * currentStep / steps);
+ const newY = startY + (distanceY * currentStep / steps);
+ dispatch(glideSecsXY(newX, newY));
+
+ if (currentStep >= steps) {
+ clearInterval(intervalId);
+ dispatch(goToXY(x,y));
+ }
+ }, 10);
+}
\ No newline at end of file
diff --git a/src/features/soundTabReducers.js b/src/features/soundTabReducers.js
new file mode 100644
index 0000000..e36ade7
--- /dev/null
+++ b/src/features/soundTabReducers.js
@@ -0,0 +1,35 @@
+import audioArray from "../components/audioArray";
+
+export const initialState = {
+ activeTab: "Home",
+ audioState: {
+ showAudioWaveform: true,
+ fileName: '',
+ },
+ audioArray: audioArray,
+ activeWaveform: audioArray[0],
+}
+
+import { createSlice } from "@reduxjs/toolkit";
+
+const soundTabSlice = createSlice({
+ name: "soundTab",
+ initialState: initialState,
+ reducers: {
+ setActiveTab: (state, action) => {
+ state.activeTab = action.payload;
+ },
+ setAudioState: (state, action) => {
+ state.audioState = action.payload;
+ },
+ setAudioArray: (state, action) => {
+ state.audioArray = action.payload;
+ },
+ setActiveWaveform: (state, action) => {
+ state.activeWaveform = action.payload;
+ }
+ },
+});
+
+export const { setActiveTab, setAudioState, setAudioArray, setActiveWaveform } = soundTabSlice.actions;
+export default soundTabSlice.reducer;
\ No newline at end of file
diff --git a/src/features/utlities.js b/src/features/utlities.js
new file mode 100644
index 0000000..9c6c42e
--- /dev/null
+++ b/src/features/utlities.js
@@ -0,0 +1,16 @@
+export const drawRect = (detections, ctx) => {
+ detections.forEach((predictions) => {
+ const [x, y, width, height] = predictions["bbox"];
+ const text = predictions["class"];
+
+ const color = "green";
+ ctx.strokeStyle = color;
+ ctx.font = "38px Arial";
+ ctx.fillStyle = color;
+
+ ctx.beginPath();
+ ctx.fillText(text, x, y);
+ ctx.rect(x, y, width, height);
+ ctx.stroke();
+ });
+};
diff --git a/src/index.css b/src/index.css
index 3fcad91..cfd2396 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,5 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap");
-
+@import url("https://fonts.googleapis.com/css?family=Dosis:300,400");
* {
padding: 0;
margin: 0;
@@ -9,8 +9,478 @@ body {
width: 100vw;
padding: 0;
margin: 0;
+ /* overflow: hidden; */
+ overflow-x: hidden;
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ /* font-family: "Poppins", sans-serif; */
+}
+
+/* animation Floating action button */
+
+@keyframes comeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.card {
box-sizing: border-box;
- font-family: "Poppins", sans-serif;
+ margin: 10px auto;
+ width: 120px;
+ height: 120px;
+ background: rgba(217, 217, 217, 0.58);
+ border: 1px solid white;
+ box-shadow: 12px 17px 51px rgba(0, 0, 0, 0.22);
+ backdrop-filter: blur(6px);
+ border-radius: 17px;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.5s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ user-select: none;
+ font-weight: bolder;
+ color: black;
+}
+
+.card:hover {
+ border: 1px solid black;
+ transform: scale(1.05);
+}
+
+.card:active {
+ transform: scale(0.95) rotateZ(1.7deg);
+}
+
+h1 a {
+ color: #fff;
+ font-size: 2em;
+ text-decoration: none;
+ display: inline-block;
+ position: relative;
+ font-family: "Dosis", sans-serif;
+}
+.wrapper {
+ display: block;
+ position: absolute;
+ top: 20%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+}
+/* effect-shine */
+h1.effect-shine:hover {
+ -webkit-mask-image: linear-gradient(
+ -75deg,
+ rgba(0, 0, 0, 0.568) 30%,
+ #000 50%,
+ rgba(0, 0, 0, 0.568) 70%
+ );
+ -moz-mask-image: linear-gradient(
+ -75deg,
+ rgba(0, 0, 0, 0.568) 30%,
+ #000 50%,
+ rgba(0, 0, 0, 0.568) 70%
+ );
+ -ms-mask-image: linear-gradient(
+ -75deg,
+ rgba(0, 0, 0, 0.568) 30%,
+ #000 50%,
+ rgba(0, 0, 0, 0.568) 70%
+ );
+ mask-image: linear-gradient(
+ -75deg,
+ rgba(0, 0, 0, 0.568) 30%,
+ #000 50%,
+ rgba(0, 0, 0, 0.568) 70%
+ );
+ mask-size: 200%;
+ animation: shine 2s infinite;
+}
+
+@keyframes shine {
+ from {
+ mask-position: 150%;
+ }
+
+ to {
+ mask-position: -50%;
+ }
+}
+
+@-webkit-keyframes shine {
+ from {
+ -webkit-mask-position: 150%;
+ }
+
+ to {
+ -webkit-mask-position: -50%;
+ }
+}
+
+/* style for the upload audio component */
+.upload-audio {
+ width: 100%;
+ margin-top: 5vh;
+ display: flex;
+ flex-flow: column nowrap;
+ align-items: center;
+ justify-content: space-between;
+}
+
+/* the container where wavesurfer adds the audio waveform */
+.waveform-container {
+ width: 100%; /* Ensure the container takes up 100% of the width */
+ overflow-x: hidden;
+}
+
+/* Add a border to the waveform */
+
+div#soundBlocklyDiv.highlighted > div {
+ width: 90%;
+}
+
+#waveform {
+ width: 100%; /* Ensure the waveform takes up 100% of the width */
+}
+
+/* Remove the following styles */
+#waveform:nth-child(2) > canvas {
+ width: 100%;
+}
+
+/* style for the navbar */
+nav {
+ display: flex;
+ align-items: center;
+ height: 3.5em;
+ padding: 0 2em;
+ background-color: #1d0b22;
+ color: white;
+ font-size: large;
+ font-weight: bold;
+}
+
+nav > .brand {
+ display: flex;
+ color: white;
+ align-items: center;
+}
+
+nav a {
+ text-decoration: none;
+ color: inherit;
+}
+
+/* all icons */
+i.material-icons {
+ font-size: 1.5em;
+ color: #1976d2;
+}
+
+h1 {
+ color: #1d0b22;
+}
+
+i.material-icons.audio-icon {
+ font-size: 5em;
+ color: #1976d2 !important;
+ margin: 1rem auto;
+}
+
+/* style for the upload button */
+button.upload-btn {
+ width: 10em;
+ font-size: 1em;
+ padding: 0.5em;
+ background: #1976d2;
+ border-radius: 999px;
+ color: white;
+ border-color: #5b266b;
+ cursor: pointer;
+ margin: 1rem auto;
+}
+
+button.upload-btn:hover {
+ filter: brightness(1.1);
+}
+
+/* Container for the upload and delete buttons */
+div.upload-controls {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-direction: column;
+}
+
+/* style for the delete button */
+button.controls.delete-btn {
+ width: 2em; /* Adjust the width as needed */
+ font-size: 1em;
+ padding: 0.5em;
+ background: #fbfbfb;
+ border-radius: 999px;
+ color: #1976d2;
+ border-color: #b32b0a;
+ cursor: pointer;
+}
+
+/* style for the trim button */
+.trim {
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ background: #1976d2;
+ color: white;
+ width: 6.5em;
+ height: 2.5em;
+ border-radius: 2px;
+ cursor: pointer;
+ padding: 0.25em;
+ border: 1px solid rebeccapurple;
+}
+
+.fade {
+ width: 20px;
+ height: 20px;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+}
+
+/* CSS Started all the button controls */
+/* Container for all the button controls */
+div.all-controls {
+ margin: 2em auto;
+ max-width: 60vw;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+/* Container for the left and right sections */
+.all-controls .right-container,
+.all-controls .left-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ width: 50%;
+}
+.all-controls .right-container button.controls.fade-in {
+ margin-right: 2px; /* Adjust this value as needed */
+}
+
+/* Target the Fade Out button and reduce the left margin */
+.all-controls .right-container button.controls.fade-out {
+ margin-left: 2px; /* Adjust this value as needed */
+}
+/* Styling for the individual buttons */
+button.controls {
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ font-size: 1.2em;
+ position: relative;
+}
+
+/* Styling for the icons */
+button.controls i {
+ /* Add any common styling for the icons here */
+ color: #1976d2;
+}
+
+.custom-icon-color {
+ color: #1976d2;
+}
+/* Styling for the names below the icons */
+button.controls span {
+ font-size: 0.6em;
+ font-style: italic;
+ display: block;
+ text-align: center;
+}
+
+/*CSS End
+
+/* Volume slider container styling */
+.volume-slide-container {
+ display: flex;
+ align-items: center;
+}
+
+/* Styling for the volume icon */
+.volume-slide-container i {
+ margin-right: 0.5em;
+}
+
+/* style for both sliders */
+.slider {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 10px;
+ cursor: pointer;
+ background: rgba(213, 184, 255, 0.7);
+ border: 1px solid #1d0b22;
+ border-radius: 999px;
+ margin: 0;
+ -webkit-transition: 0.2s;
+ transition: opacity 0.2s;
+}
+
+.slider:hover {
+ filter: brightness(1.05);
+}
+
+.slider::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 15px;
+ height: 15px;
+ background: #1d0b22;
+ cursor: pointer;
+ border-radius: 50%;
+}
+
+.slider::-moz-range-thumb {
+ width: 15px;
+ height: 15px;
+ background: #1d0b22;
+ cursor: pointer;
+ border-radius: 50%;
+}
+
+.volume-slide-container {
+ display: flex;
+ align-items: center;
+}
+
+/* smaller icon for zoom slider */
+i.zoom-icon {
+ font-size: 0.8em;
+}
+
+/* toggle switch style*/
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 4em;
+ height: 1.2em;
+}
+
+.switch input {
+ display: none;
+}
+
+.toggle {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #1d0b22;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+ padding: 0;
+ border-radius: 999px;
+}
+
+.toggle:before {
+ position: absolute;
+ content: "";
+ top: -10%;
+ height: 1.3em;
+ width: 1.3em;
+ background-color: #923cac;
+ border: 0.05em solid rebeccapurple;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+ border-radius: 50%;
+}
+
+input:checked + .toggle:before {
+ -webkit-transform: translateX(180%);
+ -ms-transform: translateX(180%);
+ transform: translateX(180%);
+}
+
+.on {
+ display: none;
+ color: white;
+ position: absolute;
+ transform: translate(-50%, -50%);
+ top: 45%;
+ left: 35%;
+ font-size: 0.5em;
+}
+
+.off {
+ color: white;
+ position: absolute;
+ transform: translate(-50%, -50%);
+ top: 45%;
+ left: 65%;
+ font-size: 0.5em;
+}
+
+input:checked + .toggle .on {
+ display: block;
+}
+
+input:checked + .toggle .off {
+ display: none;
+}
+
+@media screen and (max-width: 430px) {
+ nav {
+ font-size: 1em;
+ }
+
+ .upload-audio i.audio-icon {
+ font-size: 4em;
+ }
+
+ /* all icons */
+ i.material-icons {
+ font-size: 1.5em;
+ }
+
+ h1 {
+ font-size: 1.5em;
+ }
+
+ div.all-controls {
+ max-width: 90vw;
+ flex-flow: column nowrap;
+ }
+
+ .waveform-container {
+ max-width: 90vw;
+ }
+
+ .all-controls .right-container,
+ .all-controls .left-container {
+ justify-content: space-evenly;
+ width: 100%;
+ margin-top: 1em;
+ }
+
+ /* smaller icon for zoom slider */
+ i.zoom-icon {
+ font-size: 1em;
+ }
}
.highlighted {
@@ -18,8 +488,25 @@ body {
}
.blocklyTreeRow {
- border: 2px solid #333; /* Add border */
- margin: 5px 0; /* Space between categories */
- border-radius: 5px; /* Optional rounded corners */
- padding: 5px; /* Some padding */
-}
\ No newline at end of file
+ border: 2px solid #333; /* Add border */
+ margin: 5px 0; /* Space between categories */
+ border-radius: 5px; /* Optional rounded corners */
+ padding: 5px; /* Some padding */
+}
+
+.content-container {
+ flex: 1;
+ box-sizing: border-box; /* Include padding and border in the element's total width and height */
+ padding-left: 20px; /* Adjust the value as needed */
+ margin-left: 127px;
+ overflow: hidden !important; /* Hide any content that overflows the container */
+ scrollbar-width: thin; /* Firefox */
+ scrollbar-color: transparent transparent; /* Firefox */
+}
+
+.content-container::-webkit-scrollbar {
+ display: none;
+}
+.container-inside-content {
+ overflow: hidden; /* or auto, depending on your design */
+}
diff --git a/src/main.jsx b/src/main.jsx
index 54b39dd..f9aaaaa 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -2,9 +2,13 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
+import { WaveSurferProvider } from './contexts/waveSurferContext.jsx'
+
ReactDOM.createRoot(document.getElementById('root')).render(
+
+
,
)
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index 1ce3226..f7dbcbb 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -1,18 +1,34 @@
-import React from 'react';
-import BlocklyComponent from '../components/BlocklyComponent';
-import Canvas from '../components/Canvas';
-import AnchorMenu from '../components/AnchorMenu';
-import FloatingActionButton from '../components/FloatingActionButton';
-import Header from '../components/Header';
+import React from "react";
+import { useState } from "react";
+import BlocklyComponent from "../components/BlocklyComponent";
+import Canvas from "../components/Canvas";
+import AnchorMenu from "../components/AnchorMenu";
+import FloatingActionButton from "../components/FloatingActionButton";
+import Header from "../components/Header";
+import ButtonTabs from "../components/ButtonTabs";
+import Sounds from "../components/Sounds";
+import FlagButton from "../components/Canvas/FlagButton";
+import { useDispatch, useSelector } from "react-redux";
+
const Home = () => {
+ const active = useSelector(state => state.soundTab.activeTab);
+
+
return (
-
-
-
-
-
+
+
+
+
+
+ {active === "Sounds" ? : }
diff --git a/src/store/store.js b/src/store/store.js
index d3a3e50..39b5b47 100644
--- a/src/store/store.js
+++ b/src/store/store.js
@@ -1,5 +1,23 @@
import { configureStore } from "@reduxjs/toolkit";
+import soundTabReducer, { initialState } from "../features/soundTabReducers";
+import audioReducer from "../features/audioSlice";
+
+import motionReducer from "../features/motionSlice";
+import controlReducer from "../features/controlSlice";
+import codeReducer from "../features/codeSlice";
+import cameraReducer from "../features/cameraSlice";
+
+import detectReducer from "../features/detection";
export const store = configureStore({
- reducer: {},
+ reducer: {
+ soundTab: soundTabReducer,
+ audio: audioReducer,
+ motion: motionReducer, // Add the sprite reducer to the store
+ control: controlReducer, // Add the control reducer to the store
+ code: codeReducer, // Add the code reducer to the store
+ camera: cameraReducer,
+ detect: detectReducer,
+ },
+ initialState,
});