Created a waveform component to display the recording's waveform
This commit is contained in:
32
.pnp.cjs
generated
32
.pnp.cjs
generated
@@ -37,6 +37,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/react", "npm:18.0.27"],\
|
||||
["@types/react-dom", "npm:18.0.10"],\
|
||||
["@types/uuid", "npm:9.0.1"],\
|
||||
["@types/wavesurfer.js", "npm:6.0.6"],\
|
||||
["@wixc3/react-board", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:2.2.0"],\
|
||||
["autoprefixer", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:10.4.14"],\
|
||||
["axios", "npm:1.3.5"],\
|
||||
@@ -68,6 +69,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["tailwindcss", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:3.3.1"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.5#~builtin<compat/typescript>::version=4.9.5&hash=289587"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["wavesurfer.js", "npm:6.6.4"],\
|
||||
["zustand", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:4.3.7"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -1770,6 +1772,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/debounce", [\
|
||||
["npm:3.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/@types-debounce-npm-3.0.0-b7858a5be9-af99f44f8c.zip/node_modules/@types/debounce/",\
|
||||
"packageDependencies": [\
|
||||
["@types/debounce", "npm:3.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/express", [\
|
||||
["npm:4.17.17", {\
|
||||
"packageLocation": "./.yarn/cache/@types-express-npm-4.17.17-46fe8173db-0196dacc27.zip/node_modules/@types/express/",\
|
||||
@@ -1989,6 +2000,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/wavesurfer.js", [\
|
||||
["npm:6.0.6", {\
|
||||
"packageLocation": "./.yarn/cache/@types-wavesurfer.js-npm-6.0.6-465818fff7-732e998507.zip/node_modules/@types/wavesurfer.js/",\
|
||||
"packageDependencies": [\
|
||||
["@types/wavesurfer.js", "npm:6.0.6"],\
|
||||
["@types/debounce", "npm:3.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@typescript-eslint/parser", [\
|
||||
["npm:5.51.0", {\
|
||||
"packageLocation": "./.yarn/cache/@typescript-eslint-parser-npm-5.51.0-884b6bb8aa-096ec81913.zip/node_modules/@typescript-eslint/parser/",\
|
||||
@@ -5343,6 +5364,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/react", "npm:18.0.27"],\
|
||||
["@types/react-dom", "npm:18.0.10"],\
|
||||
["@types/uuid", "npm:9.0.1"],\
|
||||
["@types/wavesurfer.js", "npm:6.0.6"],\
|
||||
["@wixc3/react-board", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:2.2.0"],\
|
||||
["autoprefixer", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:10.4.14"],\
|
||||
["axios", "npm:1.3.5"],\
|
||||
@@ -5374,6 +5396,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["tailwindcss", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:3.3.1"],\
|
||||
["typescript", "patch:typescript@npm%3A4.9.5#~builtin<compat/typescript>::version=4.9.5&hash=289587"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["wavesurfer.js", "npm:6.6.4"],\
|
||||
["zustand", "virtual:bf6aaa3c042cc1a42ee2910afd2615e1727d392da84fae76c4ff4b04654d9bc15e6952fab427843d598f4a94d8eaa3198f30dab7b7c8d523ed6cd30ef92cfb66#npm:4.3.7"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -7209,6 +7232,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["wavesurfer.js", [\
|
||||
["npm:6.6.4", {\
|
||||
"packageLocation": "./.yarn/cache/wavesurfer.js-npm-6.6.4-ee0823a013-cee2a98695.zip/node_modules/wavesurfer.js/",\
|
||||
"packageDependencies": [\
|
||||
["wavesurfer.js", "npm:6.6.4"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["webcrypto-core", [\
|
||||
["npm:1.7.7", {\
|
||||
"packageLocation": "./.yarn/cache/webcrypto-core-npm-1.7.7-bb22025843-1dc5aedb25.zip/node_modules/webcrypto-core/",\
|
||||
|
||||
@@ -43,11 +43,13 @@
|
||||
"swr": "^2.1.3",
|
||||
"typescript": "4.9.5",
|
||||
"uuid": "^9.0.0",
|
||||
"wavesurfer.js": "^6.6.4",
|
||||
"zustand": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@types/wavesurfer.js": "^6.0.6",
|
||||
"@wixc3/react-board": "^2.2.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"postcss": "^8.4.21",
|
||||
|
||||
56
src/components/Waveform.tsx
Normal file
56
src/components/Waveform.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import React, {useEffect, useRef} from "react";
|
||||
import WaveSurfer from "wavesurfer.js";
|
||||
|
||||
interface Props {
|
||||
audio: string;
|
||||
isPlaying: boolean;
|
||||
onEnd: () => void;
|
||||
}
|
||||
|
||||
const Waveform = ({audio, isPlaying, onEnd}: Props) => {
|
||||
const containerRef = useRef(null);
|
||||
const waveSurferRef = useRef<WaveSurfer | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const waveSurfer = WaveSurfer.create({
|
||||
container: containerRef?.current || "",
|
||||
responsive: true,
|
||||
cursorWidth: 0,
|
||||
height: 24,
|
||||
waveColor: "#FCDDEC",
|
||||
progressColor: "#EF5DA8",
|
||||
barGap: 4,
|
||||
barWidth: 4,
|
||||
barRadius: 2,
|
||||
fillParent: true,
|
||||
hideScrollbar: true,
|
||||
normalize: true,
|
||||
});
|
||||
waveSurfer.load(audio);
|
||||
waveSurfer.on("ready", () => {
|
||||
waveSurferRef.current = waveSurfer;
|
||||
});
|
||||
waveSurfer.on("finish", onEnd);
|
||||
|
||||
return () => {
|
||||
waveSurfer.destroy();
|
||||
};
|
||||
}, [audio, onEnd]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlaying) waveSurferRef.current?.play();
|
||||
if (!isPlaying) waveSurferRef.current?.pause();
|
||||
}, [isPlaying]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => waveSurferRef.current?.playPause()} type="button">
|
||||
{" "}
|
||||
play/pause{" "}
|
||||
</button>
|
||||
<div className="w-full h-fit" ref={containerRef} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Waveform;
|
||||
@@ -8,9 +8,10 @@ import {sessionOptions} from "@/lib/session";
|
||||
import useUser from "@/hooks/useUser";
|
||||
import Sidebar from "@/components/Sidebar";
|
||||
import dynamic from "next/dynamic";
|
||||
import {BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPlayCircle, BsPlayFill, BsTrashFill} from "react-icons/bs";
|
||||
import {BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPauseFill, BsPlayCircle, BsPlayFill, BsTrashFill} from "react-icons/bs";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
const Waveform = dynamic(() => import("../components/Waveform"), {ssr: false});
|
||||
const ReactMediaRecorder = dynamic(() => import("react-media-recorder").then((mod) => mod.ReactMediaRecorder), {
|
||||
ssr: false,
|
||||
});
|
||||
@@ -38,6 +39,7 @@ export default function Page() {
|
||||
const {user} = useUser({redirectTo: "/login"});
|
||||
const [recordingDuration, setRecordingDuration] = useState(0);
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let recordingInterval: NodeJS.Timer | undefined = undefined;
|
||||
@@ -78,7 +80,7 @@ export default function Page() {
|
||||
<div className="flex gap-8 items-center justify-center py-8">
|
||||
{status === "idle" && (
|
||||
<>
|
||||
{!mediaBlobUrl && <div className="w-full h-2 max-w-4xl bg-mti-gray-smoke rounded-full" />}
|
||||
<div className="w-full h-2 max-w-4xl bg-mti-gray-smoke rounded-full" />
|
||||
{status === "idle" && (
|
||||
<BsMicFill
|
||||
onClick={() => {
|
||||
@@ -155,10 +157,21 @@ export default function Page() {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{status === "stopped" && (
|
||||
{status === "stopped" && mediaBlobUrl && (
|
||||
<>
|
||||
<BsPlayFill className="text-mti-gray-cool cursor-pointer w-5 h-5" />
|
||||
<div className="w-full h-2 max-w-4xl bg-mti-gray-smoke rounded-full" />
|
||||
{isPlaying && (
|
||||
<BsPauseFill
|
||||
className="text-mti-gray-cool cursor-pointer w-5 h-5"
|
||||
onClick={() => setIsPlaying(false)}
|
||||
/>
|
||||
)}
|
||||
{!isPlaying && (
|
||||
<BsPlayFill
|
||||
className="text-mti-gray-cool cursor-pointer w-5 h-5"
|
||||
onClick={() => setIsPlaying(true)}
|
||||
/>
|
||||
)}
|
||||
<Waveform audio={mediaBlobUrl} isPlaying={isPlaying} onEnd={() => setIsPlaying(false)} />
|
||||
<div className="flex gap-4 items-center">
|
||||
<BsTrashFill
|
||||
className="text-mti-gray-cool cursor-pointer w-5 h-5"
|
||||
|
||||
25
yarn.lock
25
yarn.lock
@@ -1071,6 +1071,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/debounce@npm:*":
|
||||
version: 3.0.0
|
||||
resolution: "@types/debounce@npm:3.0.0"
|
||||
checksum: af99f44f8ce90388aa5a909066c64b4ddc5efdff72bccf7dcef1fe8a04f03d03a7a42cc1f42ff14620c66923f92600ccfeb768bd77ad250f12a6ebca116ca719
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/express-serve-static-core@npm:^4.17.33":
|
||||
version: 4.17.33
|
||||
resolution: "@types/express-serve-static-core@npm:4.17.33"
|
||||
@@ -1256,6 +1263,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/wavesurfer.js@npm:^6.0.6":
|
||||
version: 6.0.6
|
||||
resolution: "@types/wavesurfer.js@npm:6.0.6"
|
||||
dependencies:
|
||||
"@types/debounce": "*"
|
||||
checksum: 732e9985075dfd4a9fa9cfa0dd959a3d4243fa16a7a11abe953a98a9a391a76878e0451f9bf1b8f2356d6822fbf34c8e5b278af60b6818c1c47e1fbe2cc1a5eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:^5.42.0":
|
||||
version: 5.51.0
|
||||
resolution: "@typescript-eslint/parser@npm:5.51.0"
|
||||
@@ -3998,6 +4014,7 @@ __metadata:
|
||||
"@types/react": 18.0.27
|
||||
"@types/react-dom": 18.0.10
|
||||
"@types/uuid": ^9.0.1
|
||||
"@types/wavesurfer.js": ^6.0.6
|
||||
"@wixc3/react-board": ^2.2.0
|
||||
autoprefixer: ^10.4.13
|
||||
axios: ^1.3.5
|
||||
@@ -4029,6 +4046,7 @@ __metadata:
|
||||
tailwindcss: ^3.2.4
|
||||
typescript: 4.9.5
|
||||
uuid: ^9.0.0
|
||||
wavesurfer.js: ^6.6.4
|
||||
zustand: ^4.3.6
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@@ -5593,6 +5611,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wavesurfer.js@npm:^6.6.4":
|
||||
version: 6.6.4
|
||||
resolution: "wavesurfer.js@npm:6.6.4"
|
||||
checksum: cee2a98695241ab08edaab8d7b2a5ac59a428b8c8d79fa9c2692b4f95b15da9a61a7f81cd18114da2b37d59dabf7dc4854d0862bedfa98b2650620f05bea567b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webcrypto-core@npm:^1.7.7":
|
||||
version: 1.7.7
|
||||
resolution: "webcrypto-core@npm:1.7.7"
|
||||
|
||||
Reference in New Issue
Block a user