mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
switch to chackra, bugfixes
This commit is contained in:
@@ -91,7 +91,7 @@ export default async function RootLayout({ children, params }: LayoutProps) {
|
||||
<Providers>
|
||||
<div
|
||||
id="container"
|
||||
className="items-center h-[100svh] w-[100svw] p-2 md:p-4 grid grid-rows-layout gap-2 md:gap-4"
|
||||
className="items-center h-[100svh] w-[100svw] p-2 md:p-4 grid grid-rows-layout-topbar gap-2 md:gap-4"
|
||||
>
|
||||
<header className="flex justify-between items-center w-full">
|
||||
{/* Logo on the left */}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import TopicHeader from "./topicHeader";
|
||||
import TopicWords from "./topicWords";
|
||||
import TopicPlayer from "./topicPlayer";
|
||||
@@ -12,6 +12,7 @@ import getApi from "../../../../lib/getApi";
|
||||
import useTranscript from "../../useTranscript";
|
||||
import { useError } from "../../../../(errors)/errorContext";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Box, Grid } from "@chakra-ui/react";
|
||||
|
||||
export type TranscriptCorrect = {
|
||||
params: {
|
||||
@@ -50,57 +51,76 @@ export default function TranscriptCorrect({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full grid grid-cols-2 gap-4">
|
||||
<div className="flex flex-col h-full ">
|
||||
<Grid
|
||||
templateRows="auto minmax(0, 1fr)"
|
||||
h="100%"
|
||||
maxW={{ lg: "container.lg" }}
|
||||
mx="auto"
|
||||
minW={{ base: "100%", lg: "container.lg" }}
|
||||
>
|
||||
<Box display="flex" flexDir="column" minW="100%" mb={{ base: 4, lg: 10 }}>
|
||||
<TopicHeader
|
||||
minW="100%"
|
||||
stateCurrentTopic={stateCurrentTopic}
|
||||
transcriptId={transcriptId}
|
||||
topicWithWordsLoading={topicWithWords.loading}
|
||||
/>
|
||||
|
||||
<TopicPlayer
|
||||
transcriptId={transcriptId}
|
||||
selectedTime={
|
||||
selectedTextIsTimeSlice(selectedText) ? selectedText : undefined
|
||||
}
|
||||
topicTime={
|
||||
currentTopic
|
||||
? {
|
||||
start: currentTopic?.timestamp,
|
||||
end: currentTopic?.timestamp + currentTopic?.duration,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Grid
|
||||
templateColumns={{
|
||||
base: "minmax(0, 1fr)",
|
||||
md: "4fr 3fr",
|
||||
lg: "2fr 1fr",
|
||||
}}
|
||||
templateRows={{
|
||||
base: "repeat(2, minmax(0, 1fr)) auto",
|
||||
md: "minmax(0, 1fr)",
|
||||
}}
|
||||
gap={{ base: "2", md: "4", lg: "4" }}
|
||||
h="100%"
|
||||
maxH="100%"
|
||||
w="100%"
|
||||
>
|
||||
<TopicWords
|
||||
stateSelectedText={stateSelectedText}
|
||||
participants={participants}
|
||||
topicWithWords={topicWithWords}
|
||||
mb={{ md: "-3rem" }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col justify-stretch">
|
||||
{currentTopic ? (
|
||||
<TopicPlayer
|
||||
transcriptId={transcriptId}
|
||||
selectedTime={
|
||||
selectedTextIsTimeSlice(selectedText) ? selectedText : undefined
|
||||
}
|
||||
topicTime={{
|
||||
start: currentTopic?.timestamp,
|
||||
end: currentTopic?.timestamp + currentTopic?.duration,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
{participants.response && (
|
||||
<div className="h-full flex flex-col justify-between">
|
||||
<ParticipantList
|
||||
{...{
|
||||
transcriptId,
|
||||
participants,
|
||||
topicWithWords,
|
||||
stateSelectedText,
|
||||
}}
|
||||
/>
|
||||
{!transcript.response?.reviewed && (
|
||||
<div className="flex flex-row justify-end">
|
||||
<button
|
||||
className="p-2 px-4 rounded bg-green-400"
|
||||
onClick={markAsDone}
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ParticipantList
|
||||
{...{
|
||||
transcriptId,
|
||||
participants,
|
||||
topicWithWords,
|
||||
stateSelectedText,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{transcript.response && !transcript.response?.reviewed && (
|
||||
<div className="flex flex-row justify-end">
|
||||
<button
|
||||
className="p-2 px-4 rounded bg-green-400"
|
||||
onClick={markAsDone}
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,18 @@ import getApi from "../../../../lib/getApi";
|
||||
import { UseParticipants } from "../../useParticipants";
|
||||
import { selectedTextIsSpeaker, selectedTextIsTimeSlice } from "./types";
|
||||
import { useError } from "../../../../(errors)/errorContext";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Text,
|
||||
UnorderedList,
|
||||
Input,
|
||||
Kbd,
|
||||
Spinner,
|
||||
ListItem,
|
||||
Grid,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
type ParticipantList = {
|
||||
participants: UseParticipants;
|
||||
@@ -13,7 +25,6 @@ type ParticipantList = {
|
||||
topicWithWords: any;
|
||||
stateSelectedText: any;
|
||||
};
|
||||
// NTH re-order list when searching
|
||||
const ParticipantList = ({
|
||||
transcriptId,
|
||||
participants,
|
||||
@@ -58,12 +69,14 @@ const ParticipantList = ({
|
||||
setAction("Create and assign");
|
||||
setSelectedParticipant(undefined);
|
||||
}
|
||||
if (typeof selectedText == undefined) {
|
||||
|
||||
if (typeof selectedText == "undefined") {
|
||||
inputRef.current?.blur();
|
||||
setSelectedParticipant(undefined);
|
||||
setAction(null);
|
||||
}
|
||||
}
|
||||
}, [selectedText, participants.response]);
|
||||
}, [selectedText, !participants.response]);
|
||||
|
||||
useEffect(() => {
|
||||
document.onkeyup = (e) => {
|
||||
@@ -250,6 +263,7 @@ const ParticipantList = ({
|
||||
participants.refetch();
|
||||
setParticipantInput("");
|
||||
setLoading(false);
|
||||
inputRef.current?.focus();
|
||||
})
|
||||
.catch((e) => {
|
||||
setError(e, "There was an error creating");
|
||||
@@ -320,48 +334,56 @@ const ParticipantList = ({
|
||||
}
|
||||
};
|
||||
|
||||
const anyLoading = loading || participants.loading || topicWithWords.loading;
|
||||
|
||||
return (
|
||||
<div className="h-full" onClick={clearSelection}>
|
||||
<div onClick={preventClick}>
|
||||
<div className="grid grid-cols-7 gap-2 mb-2">
|
||||
<input
|
||||
<Box h="100%" onClick={clearSelection} width="100%">
|
||||
<Grid
|
||||
onClick={preventClick}
|
||||
maxH="100%"
|
||||
templateRows="auto minmax(0, 1fr)"
|
||||
min-w="100%"
|
||||
>
|
||||
<Flex direction="column" p="2">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
onChange={changeParticipantInput}
|
||||
value={participantInput}
|
||||
className="border col-span-3 border-blue-400 p-1"
|
||||
mb="2"
|
||||
placeholder="Participant Name"
|
||||
/>
|
||||
{action ? (
|
||||
<button
|
||||
onClick={doAction}
|
||||
className="p-2 bg-blue-200 w-full col-span-3"
|
||||
>
|
||||
[
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 h-2"
|
||||
/>
|
||||
]{" " + action}
|
||||
</button>
|
||||
) : (
|
||||
<div className="col-span-3" />
|
||||
)}
|
||||
{loading ||
|
||||
participants.loading ||
|
||||
(topicWithWords.loading && (
|
||||
<FontAwesomeIcon
|
||||
icon={faSpinner}
|
||||
className="animate-spin-slow text-gray-300 h-8"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
onClick={doAction}
|
||||
colorScheme="blue"
|
||||
disabled={!action || anyLoading}
|
||||
>
|
||||
{action || !anyLoading ? (
|
||||
<>
|
||||
<Kbd color="blue.500" pt="1" mr="1">
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 h-3"
|
||||
/>
|
||||
</Kbd>
|
||||
{action || "Create"}
|
||||
</>
|
||||
) : (
|
||||
<Spinner />
|
||||
)}
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{participants.response && (
|
||||
<ul>
|
||||
<UnorderedList
|
||||
mx="0"
|
||||
mb={{ base: 2, md: 4 }}
|
||||
maxH="100%"
|
||||
overflow="scroll"
|
||||
>
|
||||
{participants.response.map((participant: Participant) => (
|
||||
<li
|
||||
<ListItem
|
||||
onClick={selectParticipant(participant)}
|
||||
className={
|
||||
"flex flex-row justify-between border-b last:border-b-0 py-2 " +
|
||||
(participantInput.length > 0 &&
|
||||
selectedText &&
|
||||
participant.name.startsWith(participantInput)
|
||||
@@ -371,69 +393,88 @@ const ParticipantList = ({
|
||||
? "bg-blue-200 border"
|
||||
: "")
|
||||
}
|
||||
key={participant.id}
|
||||
display="flex"
|
||||
flexDirection="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
borderBottom="1px"
|
||||
borderColor="gray.300"
|
||||
py="2"
|
||||
mx="2"
|
||||
_last={{ borderBottom: "0" }}
|
||||
key={participant.name}
|
||||
>
|
||||
<span>{participant.name}</span>
|
||||
<Text mt="1">{participant.name}</Text>
|
||||
|
||||
<div>
|
||||
<Box>
|
||||
{selectedTextIsSpeaker(selectedText) &&
|
||||
!selectedParticipant &&
|
||||
!loading && (
|
||||
<button
|
||||
<Button
|
||||
onClick={mergeSpeaker(selectedText, participant)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
colorScheme="blue"
|
||||
ml="2"
|
||||
size="sm"
|
||||
>
|
||||
{oneMatch?.id == participant.id &&
|
||||
action == "Create to rename" && (
|
||||
<>
|
||||
<span className="text-xs">
|
||||
[CTRL +{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2 h-2"
|
||||
/>
|
||||
]
|
||||
</span>
|
||||
</>
|
||||
)}{" "}
|
||||
<Kbd
|
||||
letterSpacing="-1px"
|
||||
color="blue.500"
|
||||
mr="1"
|
||||
pt="3px"
|
||||
>
|
||||
Ctrl +
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 h-2"
|
||||
/>
|
||||
</Kbd>
|
||||
)}
|
||||
Merge
|
||||
</button>
|
||||
</Button>
|
||||
)}
|
||||
{selectedTextIsTimeSlice(selectedText) && !loading && (
|
||||
<button
|
||||
<Button
|
||||
onClick={assignTo(participant)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
colorScheme="blue"
|
||||
ml="2"
|
||||
size="sm"
|
||||
>
|
||||
{oneMatch?.id == participant.id &&
|
||||
action == "Create and assign" && (
|
||||
<>
|
||||
<span className="text-xs">
|
||||
[CTRL +{" "}
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 mr-2 h-2"
|
||||
/>
|
||||
]
|
||||
</span>
|
||||
</>
|
||||
<Kbd
|
||||
letterSpacing="-1px"
|
||||
color="blue.500"
|
||||
mr="1"
|
||||
pt="3px"
|
||||
>
|
||||
Ctrl +
|
||||
<FontAwesomeIcon
|
||||
icon={faArrowTurnDown}
|
||||
className="rotate-90 h-2"
|
||||
/>
|
||||
</Kbd>
|
||||
)}{" "}
|
||||
Assign
|
||||
</button>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<button
|
||||
<Button
|
||||
onClick={deleteParticipant(participant.id)}
|
||||
className="bg-blue-400 px-2 ml-2"
|
||||
colorScheme="blue"
|
||||
ml="2"
|
||||
size="sm"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</Button>
|
||||
</Box>
|
||||
</ListItem>
|
||||
))}
|
||||
</ul>
|
||||
</UnorderedList>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default ({ playing }) => (
|
||||
<div className="flex justify-between w-16 h-8 m-auto">
|
||||
<div className="flex justify-between w-14 h-6">
|
||||
<div
|
||||
className={`bg-blue-400 rounded w-2 ${
|
||||
playing ? "animate-wave-quiet" : ""
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import { faArrowLeft, faArrowRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import useTopics from "../../useTopics";
|
||||
import { Dispatch, SetStateAction, useEffect } from "react";
|
||||
import { GetTranscriptTopic } from "../../../../api";
|
||||
import {
|
||||
BoxProps,
|
||||
Box,
|
||||
Circle,
|
||||
Heading,
|
||||
Kbd,
|
||||
Skeleton,
|
||||
SkeletonCircle,
|
||||
chakra,
|
||||
Flex,
|
||||
Center,
|
||||
} from "@chakra-ui/react";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons";
|
||||
|
||||
type TopicHeader = {
|
||||
stateCurrentTopic: [
|
||||
@@ -17,7 +28,8 @@ export default function TopicHeader({
|
||||
stateCurrentTopic,
|
||||
transcriptId,
|
||||
topicWithWordsLoading,
|
||||
}: TopicHeader) {
|
||||
...chakraProps
|
||||
}: TopicHeader & BoxProps) {
|
||||
const [currentTopic, setCurrentTopic] = stateCurrentTopic;
|
||||
const topics = useTopics(transcriptId);
|
||||
|
||||
@@ -26,17 +38,13 @@ export default function TopicHeader({
|
||||
const sessionTopic = window.localStorage.getItem(
|
||||
transcriptId + "correct",
|
||||
);
|
||||
console.log(sessionTopic, window.localStorage);
|
||||
if (sessionTopic && topics?.topics?.find((t) => t.id == sessionTopic)) {
|
||||
setCurrentTopic(topics?.topics?.find((t) => t.id == sessionTopic));
|
||||
console.log("he", sessionTopic, !!sessionTopic);
|
||||
} else {
|
||||
setCurrentTopic(topics?.topics?.at(0));
|
||||
console.log("hi");
|
||||
}
|
||||
}
|
||||
}, [topics.loading]);
|
||||
// console.log(currentTopic)
|
||||
|
||||
const number = topics.topics?.findIndex(
|
||||
(topic) => topic.id == currentTopic?.id,
|
||||
@@ -75,35 +83,85 @@ export default function TopicHeader({
|
||||
};
|
||||
});
|
||||
|
||||
if (topics.topics && currentTopic && typeof number == "number") {
|
||||
return (
|
||||
<div className="flex flex-row">
|
||||
<button
|
||||
className={`w-10 h-10 rounded-full p-2 border border-gray-300 disabled:bg-white ${
|
||||
canGoPrevious ? "text-gray-500" : "text-gray-300"
|
||||
}`}
|
||||
const isLoaded = !!(
|
||||
topics.topics &&
|
||||
currentTopic &&
|
||||
typeof number == "number"
|
||||
);
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
w="100%"
|
||||
justifyContent="space-between"
|
||||
{...chakraProps}
|
||||
>
|
||||
<SkeletonCircle
|
||||
isLoaded={isLoaded}
|
||||
h={isLoaded ? "auto" : "40px"}
|
||||
w={isLoaded ? "auto" : "40px"}
|
||||
mb="2"
|
||||
fadeDuration={1}
|
||||
>
|
||||
<Circle
|
||||
as="button"
|
||||
onClick={onPrev}
|
||||
disabled={!canGoPrevious}
|
||||
size="40px"
|
||||
border="1px"
|
||||
color={canGoPrevious ? "inherit" : "gray"}
|
||||
borderColor={canGoNext ? "body-text" : "gray"}
|
||||
>
|
||||
<FontAwesomeIcon icon={faArrowLeft} />
|
||||
</button>
|
||||
<h1 className="flex-grow">
|
||||
{currentTopic.title}{" "}
|
||||
<span>
|
||||
{number + 1}/{total}
|
||||
</span>
|
||||
</h1>
|
||||
<button
|
||||
className={`w-10 h-10 rounded-full p-2 border border-gray-300 disabled:bg-white ${
|
||||
canGoNext ? "text-gray-500" : "text-gray-300"
|
||||
}`}
|
||||
{canGoPrevious ? (
|
||||
<Kbd>
|
||||
<ChevronLeftIcon />
|
||||
</Kbd>
|
||||
) : (
|
||||
<ChevronLeftIcon />
|
||||
)}
|
||||
</Circle>
|
||||
</SkeletonCircle>
|
||||
<Skeleton
|
||||
isLoaded={isLoaded}
|
||||
h={isLoaded ? "auto" : "40px"}
|
||||
mb="2"
|
||||
fadeDuration={1}
|
||||
flexGrow={1}
|
||||
mx={6}
|
||||
>
|
||||
<Flex wrap="nowrap" justifyContent="center">
|
||||
<Heading size="lg" textAlign="center" noOfLines={1}>
|
||||
{currentTopic?.title}{" "}
|
||||
</Heading>
|
||||
<Heading size="lg" ml="3">
|
||||
{(number || 0) + 1}/{total}
|
||||
</Heading>
|
||||
</Flex>
|
||||
</Skeleton>
|
||||
<SkeletonCircle
|
||||
isLoaded={isLoaded}
|
||||
h={isLoaded ? "auto" : "40px"}
|
||||
w={isLoaded ? "auto" : "40px"}
|
||||
mb="2"
|
||||
fadeDuration={1}
|
||||
>
|
||||
<Circle
|
||||
as="button"
|
||||
onClick={onNext}
|
||||
disabled={!canGoNext}
|
||||
size="40px"
|
||||
border="1px"
|
||||
color={canGoNext ? "inherit" : "gray"}
|
||||
borderColor={canGoNext ? "body-text" : "gray"}
|
||||
>
|
||||
<FontAwesomeIcon icon={faArrowRight} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
{canGoNext ? (
|
||||
<Kbd>
|
||||
<ChevronRightIcon />
|
||||
</Kbd>
|
||||
) : (
|
||||
<ChevronRightIcon />
|
||||
)}
|
||||
</Circle>
|
||||
</SkeletonCircle>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,18 +3,29 @@ import useMp3 from "../../useMp3";
|
||||
import { formatTime } from "../../../../lib/time";
|
||||
import SoundWaveCss from "./soundWaveCss";
|
||||
import { TimeSlice } from "./types";
|
||||
import {
|
||||
BoxProps,
|
||||
Button,
|
||||
Wrap,
|
||||
Text,
|
||||
WrapItem,
|
||||
Kbd,
|
||||
Skeleton,
|
||||
chakra,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
type TopicPlayer = {
|
||||
transcriptId: string;
|
||||
selectedTime: TimeSlice | undefined;
|
||||
topicTime: TimeSlice;
|
||||
topicTime: TimeSlice | undefined;
|
||||
};
|
||||
|
||||
const TopicPlayer = ({
|
||||
transcriptId,
|
||||
selectedTime,
|
||||
topicTime,
|
||||
}: TopicPlayer) => {
|
||||
...chakraProps
|
||||
}: TopicPlayer & BoxProps) => {
|
||||
const mp3 = useMp3(transcriptId);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [endTopicCallback, setEndTopicCallback] = useState<() => void>();
|
||||
@@ -46,6 +57,7 @@ const TopicPlayer = ({
|
||||
});
|
||||
|
||||
const calcShowTime = () => {
|
||||
if (!topicTime) return;
|
||||
setShowTime(
|
||||
`${
|
||||
mp3.media?.currentTime
|
||||
@@ -67,6 +79,7 @@ const TopicPlayer = ({
|
||||
setEndTopicCallback(
|
||||
() =>
|
||||
function () {
|
||||
if (!topicTime) return;
|
||||
if (mp3.media && mp3.media.currentTime >= topicTime.end) {
|
||||
mp3.media.pause();
|
||||
setIsPlaying(false);
|
||||
@@ -81,13 +94,14 @@ const TopicPlayer = ({
|
||||
// there's no callback on pause but apparently changing the time while palying doesn't work... so here is a timeout
|
||||
setTimeout(() => {
|
||||
if (mp3.media) {
|
||||
if (!topicTime) return;
|
||||
mp3.media.currentTime = topicTime.start;
|
||||
setShowTime(`00:00/${formatTime(topicTime.end - topicTime.start)}`);
|
||||
}
|
||||
}, 10);
|
||||
setIsPlaying(false);
|
||||
}
|
||||
}, [!mp3.media, topicTime.start, topicTime.end]);
|
||||
}, [!mp3.media, topicTime?.start, topicTime?.end]);
|
||||
|
||||
useEffect(() => {
|
||||
endTopicCallback &&
|
||||
@@ -141,6 +155,7 @@ const TopicPlayer = ({
|
||||
const playTopic = (e) => {
|
||||
e?.preventDefault();
|
||||
e?.target?.blur();
|
||||
if (!topicTime) return;
|
||||
if (mp3.media) {
|
||||
mp3.media.currentTime = topicTime.start;
|
||||
mp3.media.play();
|
||||
@@ -165,37 +180,65 @@ const TopicPlayer = ({
|
||||
mp3.media?.pause();
|
||||
setIsPlaying(false);
|
||||
};
|
||||
console.log(topicTime);
|
||||
|
||||
if (mp3.media) {
|
||||
return (
|
||||
<div className="mb-4 grid grid-cols-3 gap-2">
|
||||
<SoundWaveCss playing={isPlaying} />
|
||||
<div className="col-span-2">{showTime}</div>
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={playTopic}>
|
||||
Play From Start
|
||||
</button>
|
||||
{!isPlaying ? (
|
||||
<button
|
||||
ref={playButton}
|
||||
id="playButton"
|
||||
className="p-2 bg-blue-200 w-full"
|
||||
onClick={playCurrent}
|
||||
const isLoaded = !!(mp3.media && topicTime);
|
||||
return (
|
||||
<Skeleton
|
||||
isLoaded={isLoaded}
|
||||
h={isLoaded ? "auto" : "40px"}
|
||||
fadeDuration={1}
|
||||
w={isLoaded ? "auto" : "container.md"}
|
||||
margin="auto"
|
||||
{...chakraProps}
|
||||
>
|
||||
<Wrap spacing="4" justify="center" align="center">
|
||||
<WrapItem>
|
||||
<SoundWaveCss playing={isPlaying} />
|
||||
<Text fontSize="sm" pt="1" pl="2">
|
||||
{showTime}
|
||||
</Text>
|
||||
</WrapItem>
|
||||
<WrapItem>
|
||||
<Button onClick={playTopic} colorScheme="blue">
|
||||
Play from start
|
||||
</Button>
|
||||
</WrapItem>
|
||||
<WrapItem>
|
||||
{!isPlaying ? (
|
||||
<Button
|
||||
onClick={playCurrent}
|
||||
ref={playButton}
|
||||
id="playButton"
|
||||
colorScheme="blue"
|
||||
w="120px"
|
||||
>
|
||||
<Kbd color="blue.600">Space</Kbd> Play
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={pause}
|
||||
ref={playButton}
|
||||
id="playButton"
|
||||
colorScheme="blue"
|
||||
w="120px"
|
||||
>
|
||||
<Kbd color="blue.600">Space</Kbd> Pause
|
||||
</Button>
|
||||
)}
|
||||
</WrapItem>
|
||||
<WrapItem visibility={selectedTime ? "visible" : "hidden"}>
|
||||
<Button
|
||||
disabled={!selectedTime}
|
||||
onClick={playSelection}
|
||||
colorScheme="blue"
|
||||
>
|
||||
<span className="text-xs">[SPACE]</span> Play
|
||||
</button>
|
||||
) : (
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={pause}>
|
||||
<span className="text-xs">[SPACE]</span> Pause
|
||||
</button>
|
||||
)}
|
||||
{selectedTime && (
|
||||
<button className="p-2 bg-blue-200 w-full" onClick={playSelection}>
|
||||
<span className="text-xs">[,]</span>Play Selection
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<Kbd color="blue.600">,</Kbd> Play selection
|
||||
</Button>
|
||||
</WrapItem>
|
||||
</Wrap>
|
||||
</Skeleton>
|
||||
);
|
||||
};
|
||||
|
||||
export default TopicPlayer;
|
||||
|
||||
@@ -3,6 +3,14 @@ import WaveformLoading from "../../waveformLoading";
|
||||
import { UseParticipants } from "../../useParticipants";
|
||||
import { UseTopicWithWords } from "../../useTopicWithWords";
|
||||
import { TimeSlice, selectedTextIsTimeSlice } from "./types";
|
||||
import {
|
||||
BoxProps,
|
||||
Box,
|
||||
Container,
|
||||
Text,
|
||||
chakra,
|
||||
Spinner,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
type TopicWordsProps = {
|
||||
stateSelectedText: [
|
||||
@@ -17,7 +25,8 @@ const topicWords = ({
|
||||
stateSelectedText,
|
||||
participants,
|
||||
topicWithWords,
|
||||
}: TopicWordsProps) => {
|
||||
...chakraProps
|
||||
}: TopicWordsProps & BoxProps) => {
|
||||
const [selectedText, setSelectedText] = stateSelectedText;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -150,45 +159,54 @@ const topicWords = ({
|
||||
participants.response
|
||||
) {
|
||||
return (
|
||||
<div onMouseUp={onMouseUp} className="p-5 h-full w-full overflow-scroll">
|
||||
<Container
|
||||
onMouseUp={onMouseUp}
|
||||
max-h="100%"
|
||||
width="100%"
|
||||
overflow="scroll"
|
||||
maxW={{ lg: "container.md" }}
|
||||
{...chakraProps}
|
||||
>
|
||||
{topicWithWords.response.wordsPerSpeaker.map(
|
||||
(speakerWithWords, index) => (
|
||||
<p key={index} className="mb-2 last:mb-0">
|
||||
<span
|
||||
<Text key={index} className="mb-2 last:mb-0">
|
||||
<Box
|
||||
as="span"
|
||||
data-speaker={speakerWithWords.speaker}
|
||||
className={`
|
||||
font-semibold ${
|
||||
selectedText == speakerWithWords.speaker
|
||||
? "bg-yellow-200"
|
||||
: ""
|
||||
}`}
|
||||
pt="1"
|
||||
fontWeight="semibold"
|
||||
bgColor={
|
||||
selectedText == speakerWithWords.speaker ? "yellow.200" : ""
|
||||
}
|
||||
>
|
||||
{getSpeakerName(speakerWithWords.speaker)} :
|
||||
</span>
|
||||
</Box>
|
||||
{speakerWithWords.words.map((word, index) => (
|
||||
<span
|
||||
<Box
|
||||
as="span"
|
||||
data-start={word.start}
|
||||
data-end={word.end}
|
||||
key={index}
|
||||
className={
|
||||
pt="1"
|
||||
bgColor={
|
||||
selectedTextIsTimeSlice(selectedText) &&
|
||||
selectedText.start <= word.start &&
|
||||
selectedText.end >= word.end
|
||||
? "bg-yellow-200"
|
||||
? "yellow.200"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{word.text}
|
||||
</span>
|
||||
</Box>
|
||||
))}
|
||||
</p>
|
||||
</Text>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
if (topicWithWords.loading || participants.loading)
|
||||
return <WaveformLoading />;
|
||||
return <Spinner size="xl" margin="auto" />;
|
||||
if (topicWithWords.error || participants.error) return <p>error</p>;
|
||||
return null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user