mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
UI improvements
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { faArrowTurnDown, faSpinner } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||
import { Participant } from "../../../../api";
|
||||
import getApi from "../../../../lib/getApi";
|
||||
import { UseParticipants } from "../../useParticipants";
|
||||
@@ -60,30 +60,7 @@ const ParticipantList = ({
|
||||
setAction(null);
|
||||
}
|
||||
}
|
||||
}, [selectedText]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
participants.response &&
|
||||
(action == "Create and assign" || action == "Create to rename")
|
||||
) {
|
||||
if (
|
||||
participants.response.filter((p) => p.name.startsWith(participantInput))
|
||||
.length == 1
|
||||
) {
|
||||
setOneMatch(
|
||||
participants.response.find((p) =>
|
||||
p.name.startsWith(participantInput),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
setOneMatch(undefined);
|
||||
}
|
||||
}
|
||||
if (participantInput && !action) {
|
||||
setAction("Create");
|
||||
}
|
||||
}, [participantInput]);
|
||||
}, [selectedText, participants]);
|
||||
|
||||
useEffect(() => {
|
||||
document.onkeyup = (e) => {
|
||||
@@ -251,6 +228,9 @@ const ParticipantList = ({
|
||||
topicWithWords.refetch();
|
||||
participants.refetch();
|
||||
setLoading(false);
|
||||
setAction(null);
|
||||
setSelectedText(undefined);
|
||||
setSelectedParticipant(undefined);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -271,23 +251,48 @@ const ParticipantList = ({
|
||||
e?.stopPropagation();
|
||||
e?.preventDefault();
|
||||
};
|
||||
const changeParticipantInput = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value.replaceAll(/,|\.| /g, "");
|
||||
setParticipantInput(value);
|
||||
if (
|
||||
value.length > 0 &&
|
||||
participants.response &&
|
||||
(action == "Create and assign" || action == "Create to rename")
|
||||
) {
|
||||
if (
|
||||
participants.response.filter((p) => p.name.startsWith(value)).length ==
|
||||
1
|
||||
) {
|
||||
setOneMatch(
|
||||
participants.response.find((p) => p.name.startsWith(value)),
|
||||
);
|
||||
} else {
|
||||
setOneMatch(undefined);
|
||||
}
|
||||
}
|
||||
if (value.length > 0 && !action) {
|
||||
setAction("Create");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full" onClick={clearSelection}>
|
||||
<div onClick={preventClick}>
|
||||
<div>
|
||||
<div className="grid grid-cols-2 gap-2 mb-2">
|
||||
<input
|
||||
ref={inputRef}
|
||||
onChange={(e) => setParticipantInput(e.target.value)}
|
||||
onChange={changeParticipantInput}
|
||||
value={participantInput}
|
||||
className="border border-blue-400 p-1"
|
||||
/>
|
||||
{action && (
|
||||
<button onClick={doAction}>
|
||||
<button onClick={doAction} className="p-2 bg-blue-200 w-full">
|
||||
[
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2"
|
||||
className="rotate-90 h-2"
|
||||
/>
|
||||
{action}
|
||||
]{" " + action}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -306,14 +311,14 @@ const ParticipantList = ({
|
||||
<li
|
||||
onClick={selectParticipant(participant)}
|
||||
className={
|
||||
"flex flex-row justify-between " +
|
||||
"flex flex-row justify-between border-b last:border-b-0 py-2 " +
|
||||
(participantInput.length > 0 &&
|
||||
selectedText &&
|
||||
participant.name.startsWith(participantInput)
|
||||
? "bg-blue-100 "
|
||||
: "") +
|
||||
(participant.id == selectedParticipant?.id
|
||||
? "border-blue-400 border"
|
||||
? "bg-blue-200 border"
|
||||
: "")
|
||||
}
|
||||
key={participant.id}
|
||||
@@ -324,41 +329,52 @@ const ParticipantList = ({
|
||||
{selectedTextIsSpeaker(selectedText) &&
|
||||
!selectedParticipant &&
|
||||
!loading && (
|
||||
<button onClick={mergeSpeaker(selectedText, participant)}>
|
||||
{oneMatch &&
|
||||
action == "Create to rename" &&
|
||||
participant.name.startsWith(participantInput) && (
|
||||
<button
|
||||
onClick={mergeSpeaker(selectedText, participant)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
>
|
||||
{oneMatch?.id == participant.id &&
|
||||
action == "Create to rename" && (
|
||||
<>
|
||||
{" "}
|
||||
<span>CTRL + </span>{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2"
|
||||
/>{" "}
|
||||
<span className="text-xs">
|
||||
[CTRL +{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2 h-2"
|
||||
/>
|
||||
]
|
||||
</span>
|
||||
</>
|
||||
)}{" "}
|
||||
Merge
|
||||
</button>
|
||||
)}
|
||||
{selectedTextIsTimeSlice(selectedText) && !loading && (
|
||||
<button onClick={assignTo(participant)}>
|
||||
{oneMatch &&
|
||||
action == "Create and assign" &&
|
||||
participant.name.startsWith(participantInput) && (
|
||||
<button
|
||||
onClick={assignTo(participant)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
>
|
||||
{oneMatch?.id == participant.id &&
|
||||
action == "Create and assign" && (
|
||||
<>
|
||||
{" "}
|
||||
<span>CTRL + </span>{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2"
|
||||
/>{" "}
|
||||
<span className="text-xs">
|
||||
[CTRL +{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2 h-2"
|
||||
/>
|
||||
]
|
||||
</span>
|
||||
</>
|
||||
)}{" "}
|
||||
Assign
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button onClick={deleteParticipant(participant.id)}>
|
||||
<button
|
||||
onClick={deleteParticipant(participant.id)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
export default ({ playing }) => (
|
||||
<div className="flex justify-between w-16 h-8 m-auto">
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-quiet" : ""
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-normal" : ""
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-quiet" : ""
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-loud" : ""
|
||||
}`}
|
||||
></div>
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-normal" : ""
|
||||
}`}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
@@ -1,5 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import useMp3 from "../../useMp3";
|
||||
import { formatTime } from "../../../../lib/time";
|
||||
import SoundWaveCss from "./soundWaveCss";
|
||||
|
||||
const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
const mp3 = useMp3(transcriptId);
|
||||
@@ -7,9 +9,10 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
const [endTopicCallback, setEndTopicCallback] = useState<() => void>();
|
||||
const [endSelectionCallback, setEndSelectionCallback] =
|
||||
useState<() => void>();
|
||||
const [showTime, setShowTime] = useState("");
|
||||
|
||||
const keyHandler = (e) => {
|
||||
if (e.key == "!") {
|
||||
if (e.key == " ") {
|
||||
if (isPlaying) {
|
||||
mp3.media?.pause();
|
||||
setIsPlaying(false);
|
||||
@@ -17,6 +20,8 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
mp3.media?.play();
|
||||
setIsPlaying(true);
|
||||
}
|
||||
} else if (selectedTime && e.key == ",") {
|
||||
playSelection();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
@@ -26,6 +31,24 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
};
|
||||
});
|
||||
|
||||
const calcShowTime = () => {
|
||||
setShowTime(
|
||||
`${
|
||||
mp3.media?.currentTime
|
||||
? formatTime(mp3.media?.currentTime - topicTime.start)
|
||||
: "00:00"
|
||||
}/${formatTime(topicTime.end - topicTime.start)}`,
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let i;
|
||||
if (isPlaying) {
|
||||
i = setInterval(calcShowTime, 1000);
|
||||
}
|
||||
return () => i && clearInterval(i);
|
||||
}, [isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
setEndTopicCallback(
|
||||
() =>
|
||||
@@ -38,6 +61,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
mp3.media.pause();
|
||||
setIsPlaying(false);
|
||||
mp3.media.currentTime = topicTime.start;
|
||||
calcShowTime();
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -47,6 +71,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
setTimeout(() => {
|
||||
if (mp3.media) {
|
||||
mp3.media.currentTime = topicTime.start;
|
||||
setShowTime(`00:00/${formatTime(topicTime.end - topicTime.start)}`);
|
||||
}
|
||||
}, 10);
|
||||
setIsPlaying(false);
|
||||
@@ -65,9 +90,12 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
};
|
||||
}, [endTopicCallback]);
|
||||
|
||||
const playSelection = () => {
|
||||
const playSelection = (e?) => {
|
||||
e?.preventDefault();
|
||||
e?.target?.blur();
|
||||
if (mp3.media && selectedTime?.start !== undefined) {
|
||||
mp3.media.currentTime = selectedTime.start;
|
||||
calcShowTime();
|
||||
setEndSelectionCallback(
|
||||
() =>
|
||||
function () {
|
||||
@@ -99,7 +127,9 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
};
|
||||
}, [endSelectionCallback]);
|
||||
|
||||
const playTopic = () => {
|
||||
const playTopic = (e) => {
|
||||
e?.preventDefault();
|
||||
e?.target?.blur();
|
||||
if (mp3.media) {
|
||||
mp3.media.currentTime = topicTime.start;
|
||||
mp3.media.play();
|
||||
@@ -109,28 +139,46 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const playCurrent = () => {
|
||||
const playCurrent = (e) => {
|
||||
e.preventDefault();
|
||||
e?.target?.blur();
|
||||
|
||||
mp3.media?.play();
|
||||
setIsPlaying(true);
|
||||
};
|
||||
|
||||
const pause = (e) => {
|
||||
e.preventDefault();
|
||||
e?.target?.blur();
|
||||
|
||||
mp3.media?.pause();
|
||||
setIsPlaying(false);
|
||||
};
|
||||
|
||||
if (mp3.media) {
|
||||
return (
|
||||
<div id="audioContainer">
|
||||
<div className="mb-4 grid grid-cols-3 gap-2">
|
||||
<SoundWaveCss playing={isPlaying} />
|
||||
<div className="col-span-2">{showTime}</div>
|
||||
{topicTime && (
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={playTopic}>
|
||||
Play From Start
|
||||
</button>
|
||||
)}
|
||||
{!isPlaying ? (
|
||||
<button onClick={playCurrent}>Play</button>
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={playCurrent}>
|
||||
<span className="text-xs">[SPACE]</span> Play
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={pause}>Pause</button>
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={pause}>
|
||||
<span className="text-xs">[SPACE]</span> Pause
|
||||
</button>
|
||||
)}
|
||||
{selectedTime && (
|
||||
<button onClick={playSelection}>Play Selection</button>
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={playSelection}>
|
||||
<span className="text-xs">[,]</span>Play Selection
|
||||
</button>
|
||||
)}
|
||||
{topicTime && <button onClick={playTopic}>Play Topic</button>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,44 @@ module.exports = {
|
||||
},
|
||||
animation: {
|
||||
"spin-slow": "spin 3s linear infinite",
|
||||
"wave-quiet": "wave-quiet 1.2s ease-in-out infinite",
|
||||
"wave-normal": "wave-normal 1.2s ease-in-out infinite",
|
||||
"wave-loud": "wave-loud 1.2s ease-in-out infinite",
|
||||
},
|
||||
keyframes: {
|
||||
"wave-quiet": {
|
||||
"25%": {
|
||||
transform: "scaleY(.6)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "scaleY(.4)",
|
||||
},
|
||||
"75%": {
|
||||
transform: "scaleY(.4)",
|
||||
},
|
||||
},
|
||||
"wave-normal": {
|
||||
"25%": {
|
||||
transform: "scaleY(1)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "scaleY(.4)",
|
||||
},
|
||||
"75%": {
|
||||
transform: "scaleY(.6)",
|
||||
},
|
||||
},
|
||||
"wave-loud": {
|
||||
"25%": {
|
||||
transform: "scaleY(1)",
|
||||
},
|
||||
"50%": {
|
||||
transform: "scaleY(.4)",
|
||||
},
|
||||
"75%": {
|
||||
transform: "scaleY(1.2)",
|
||||
},
|
||||
},
|
||||
},
|
||||
colors: {
|
||||
bluegrey: "RGB(90, 122, 158)",
|
||||
|
||||
Reference in New Issue
Block a user