add in-recording step buttons
This commit is contained in:
parent
44e78b16d9
commit
e757f7cfd8
2 changed files with 80 additions and 49 deletions
|
|
@ -2,6 +2,9 @@ import React, { useState, useRef, Fragment, useEffect } from "react";
|
||||||
import RecordRTC, { invokeSaveAsDialog } from "recordrtc";
|
import RecordRTC, { invokeSaveAsDialog } from "recordrtc";
|
||||||
import { Listbox, Transition } from "@headlessui/react";
|
import { Listbox, Transition } from "@headlessui/react";
|
||||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid";
|
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid";
|
||||||
|
import { MicrophoneIcon, PauseIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { TrashIcon } from "@radix-ui/react-icons";
|
||||||
|
import { StopIcon } from "@heroicons/react/24/solid";
|
||||||
|
|
||||||
export default function Recorder() {
|
export default function Recorder() {
|
||||||
const [steam, setStream] = useState<null | MediaStream>(null);
|
const [steam, setStream] = useState<null | MediaStream>(null);
|
||||||
|
|
@ -13,6 +16,7 @@ export default function Recorder() {
|
||||||
const [selectedDevice, setSelectedDevice] = useState<MediaDeviceInfo | null>(
|
const [selectedDevice, setSelectedDevice] = useState<MediaDeviceInfo | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
const [step, setStep] = useState<"pre" | "in" | "post">("pre");
|
||||||
|
|
||||||
const handleRecording = async () => {
|
const handleRecording = async () => {
|
||||||
const screenStream = await navigator.mediaDevices.getDisplayMedia({
|
const screenStream = await navigator.mediaDevices.getDisplayMedia({
|
||||||
|
|
@ -41,6 +45,8 @@ export default function Recorder() {
|
||||||
setStream(mediaStream);
|
setStream(mediaStream);
|
||||||
recorderRef.current = new RecordRTC(mediaStream, { type: "video" });
|
recorderRef.current = new RecordRTC(mediaStream, { type: "video" });
|
||||||
recorderRef.current.startRecording();
|
recorderRef.current.startRecording();
|
||||||
|
|
||||||
|
setStep("in");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStop = () => {
|
const handleStop = () => {
|
||||||
|
|
@ -53,6 +59,14 @@ export default function Recorder() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
if (recorderRef.current === null) return;
|
||||||
|
setBlob(null);
|
||||||
|
recorderRef.current.stopRecording(() => {
|
||||||
|
steam?.getTracks().map((track) => track.stop());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handlePause = () => {
|
const handlePause = () => {
|
||||||
if (recorderRef.current) {
|
if (recorderRef.current) {
|
||||||
console.log(recorderRef.current?.state);
|
console.log(recorderRef.current?.state);
|
||||||
|
|
@ -89,40 +103,16 @@ export default function Recorder() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div>
|
||||||
<header className="App-header">
|
{step === "pre" ? (
|
||||||
<button
|
<div className="w-full">
|
||||||
type="button"
|
|
||||||
className="mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
|
||||||
onClick={() => void handleRecording()}
|
|
||||||
>
|
|
||||||
start
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="mx-4 mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
|
||||||
onClick={handleStop}
|
|
||||||
>
|
|
||||||
stop
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="mx-4 mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
|
||||||
onClick={handlePause}
|
|
||||||
>
|
|
||||||
{pause ? "resume" : "pause"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="mt-4 inline-flex items-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
|
||||||
onClick={handleSave}
|
|
||||||
>
|
|
||||||
save
|
|
||||||
</button>
|
|
||||||
<div className="top-16 mb-52 w-72">
|
|
||||||
<Listbox value={selectedDevice} onChange={setSelectedDevice}>
|
<Listbox value={selectedDevice} onChange={setSelectedDevice}>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
<Listbox.Button className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm">
|
<Listbox.Button className="relative flex w-full cursor-default flex-row items-center justify-start rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 sm:text-sm">
|
||||||
|
<MicrophoneIcon
|
||||||
|
className="mr-2 h-5 w-5 text-gray-400"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
<span className="block truncate">
|
<span className="block truncate">
|
||||||
{selectedDevice?.label ?? "No device selected"}
|
{selectedDevice?.label ?? "No device selected"}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -135,7 +125,10 @@ export default function Recorder() {
|
||||||
</Listbox.Button>
|
</Listbox.Button>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
leave="transition ease-in duration-100"
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -144,10 +137,8 @@ export default function Recorder() {
|
||||||
<Listbox.Option
|
<Listbox.Option
|
||||||
key={i}
|
key={i}
|
||||||
className={({ active }) =>
|
className={({ active }) =>
|
||||||
`relative cursor-default select-none py-2 pl-10 pr-4 ${
|
`relative cursor-default select-none py-2 pl-10 pr-4 text-gray-900 ${
|
||||||
active
|
active ? "bg-gray-200" : ""
|
||||||
? "bg-amber-100 text-amber-900"
|
|
||||||
: "text-gray-900"
|
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
value={audioDevice}
|
value={audioDevice}
|
||||||
|
|
@ -177,7 +168,42 @@ export default function Recorder() {
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="mt-4 flex inline-flex w-full items-center items-center justify-center rounded-md bg-indigo-500 px-4 py-2 text-sm font-semibold leading-6 text-white shadow transition duration-150 ease-in-out hover:bg-indigo-400 disabled:cursor-not-allowed"
|
||||||
|
onClick={() => void handleRecording()}
|
||||||
|
>
|
||||||
|
<span>Start recording</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
|
{step === "in" ? (
|
||||||
|
<div className="flex flex-row items-center justify-center">
|
||||||
|
<div
|
||||||
|
onClick={handleStop}
|
||||||
|
className="flex cursor-pointer flex-row items-center justify-center rounded pr-2 text-lg hover:bg-gray-200"
|
||||||
|
>
|
||||||
|
<StopIcon className="h-8 w-8 text-[#ff623f]" aria-hidden="true" />
|
||||||
|
<span className="ml-1 text-sm">0:15</span>
|
||||||
|
</div>
|
||||||
|
<div className="mx-2 h-6 w-px bg-[#E7E9EB]"></div>
|
||||||
|
<div
|
||||||
|
onClick={handlePause}
|
||||||
|
className="cursor-pointer rounded p-1 hover:bg-gray-200"
|
||||||
|
>
|
||||||
|
<PauseIcon className="h-6 w-6 text-gray-400" aria-hidden="true" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={handleDelete}
|
||||||
|
className="ml-1 cursor-pointer rounded p-1 hover:bg-gray-200"
|
||||||
|
>
|
||||||
|
<TrashIcon className="h-6 w-6 text-gray-400" aria-hidden="true" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{step === "post" ? (
|
||||||
|
<div>
|
||||||
|
<span>post recording</span>
|
||||||
{blob && (
|
{blob && (
|
||||||
<video
|
<video
|
||||||
src={URL.createObjectURL(blob)}
|
src={URL.createObjectURL(blob)}
|
||||||
|
|
@ -187,7 +213,8 @@ export default function Recorder() {
|
||||||
style={{ width: "700px", margin: "1em" }}
|
style={{ width: "700px", margin: "1em" }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</header>
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,11 @@ export default function VideoUploadModal() {
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<Transition appear show={isOpen} as={Fragment}>
|
<Transition appear show={isOpen} as={Fragment}>
|
||||||
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
<Dialog
|
||||||
|
as="div"
|
||||||
|
className="relative z-10"
|
||||||
|
onClose={() => void closeModal}
|
||||||
|
>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
|
|
@ -82,7 +86,7 @@ export default function VideoUploadModal() {
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all">
|
<Dialog.Panel className="w-full max-w-md transform rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all">
|
||||||
{1 + 1 === 2 ? (
|
{1 + 1 === 2 ? (
|
||||||
<Recorder />
|
<Recorder />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue