past meeting transcript side

This commit is contained in:
Sara
2024-01-22 16:18:04 +01:00
parent 69ae5b281e
commit f36e8bc2cb
4 changed files with 175 additions and 82 deletions

View File

@@ -71,21 +71,30 @@ export default function TranscriptDetails(details: TranscriptDetails) {
return ( return (
<> <>
<Grid templateColumns="1fr" templateRows="minmax(0, 1fr) auto"> <Grid
templateColumns="1fr"
templateRows="minmax(0, 1fr) auto"
gap={4}
mb={4}
>
<Grid <Grid
templateColumns="repeat(2, 1fr)" templateColumns="repeat(2, 1fr)"
templateRows="auto minmax(0, 1fr)" templateRows="auto minmax(0, 1fr)"
gap={4} gap={2}
padding={4} padding={4}
background="gray.100" background="gray.100"
borderRadius={2} borderRadius={8}
> >
<GridItem display="flex" flexDir="row" colSpan={2}> <GridItem
display="flex"
flexDir="row"
alignItems={"center"}
colSpan={2}
>
<TranscriptTitle <TranscriptTitle
title={transcript.response.title || "Unamed Transcript"} title={transcript.response.title || "Unamed Transcript"}
transcriptId={transcriptId} transcriptId={transcriptId}
/> />
<IconButton icon={<FaPen />} aria-label="Edit Transcript Title" />
</GridItem> </GridItem>
<TopicList <TopicList
topics={topics.topics || []} topics={topics.topics || []}

View File

@@ -9,6 +9,18 @@ import ScrollToBottom from "./scrollToBottom";
import { Topic } from "./webSocketTypes"; import { Topic } from "./webSocketTypes";
import { generateHighContrastColor } from "../../lib/utils"; import { generateHighContrastColor } from "../../lib/utils";
import useParticipants from "./useParticipants"; import useParticipants from "./useParticipants";
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Box,
Flex,
Icon,
Text,
} from "@chakra-ui/react";
import { FaChevronDown, FaChevronRight } from "react-icons/fa";
type TopicListProps = { type TopicListProps = {
topics: Topic[]; topics: Topic[];
@@ -75,11 +87,16 @@ export function TopicList({
}; };
return ( return (
<section className="relative w-full h-full bg-blue-400/20 rounded-lg md:rounded-xl p-1 sm:p-2 md:px-4 flex flex-col justify-center align-center"> <Flex
position={"relative"}
w={"100%"}
h={"100%"}
dir="column"
justify={"center"}
align={"center"}
>
{topics.length > 0 ? ( {topics.length > 0 ? (
<> <>
<h2 className="ml-2 md:text-lg font-bold mb-2">Topics</h2>
{autoscroll && ( {autoscroll && (
<ScrollToBottom <ScrollToBottom
visible={!autoscrollEnabled} visible={!autoscrollEnabled}
@@ -87,80 +104,95 @@ export function TopicList({
/> />
)} )}
<div <Accordion
id="topics-div" id="topics-div"
className="overflow-y-auto h-full" overflowY={"auto"}
h={"100%"}
onScroll={handleScroll} onScroll={handleScroll}
defaultIndex={[
topics.findIndex((topic) => topic.id == activeTopic?.id),
]}
variant="custom"
allowToggle
> >
{topics.map((topic, index) => ( {topics.map((topic, index) => (
<button <AccordionItem
key={index} key={index}
className="rounded-none border-solid border-0 border-bluegrey border-b last:border-none last:rounded-b-lg p-2 hover:bg-blue-400/20 focus-visible:bg-blue-400/20 text-left block w-full" background={{
onClick={() => base: "light",
setActiveTopic(activeTopic?.id == topic.id ? null : topic) _hover: "gray.100",
} _focus: "gray.100",
}}
padding={2}
onClick={() => {
setActiveTopic(activeTopic?.id == topic.id ? null : topic);
}}
> >
<div className="w-full flex justify-between items-center rounded-lg md:rounded-xl xs:text-base sm:text-lg md:text-xl font-bold leading-tight"> <Flex dir="row" letterSpacing={".2"}>
<p> <AccordionButton>
<span className="font-light font-mono text-slate-500 text-base md:text-lg"> <AccordionIcon />
[{formatTime(topic.timestamp)}]&nbsp; <Box as="span" textAlign="left" ml="1">
</span> {topic.title}{" "}
<span>{topic.title}</span> <Text
</p> as="span"
<FontAwesomeIcon color="gray.500"
className="transform transition-transform duration-200 ml-2" fontSize="sm"
icon={ fontWeight="bold"
activeTopic?.id == topic.id >
? faChevronDown &nbsp;[{formatTime(topic.timestamp)}]&nbsp;-&nbsp;[
: faChevronRight {formatTime(topic.timestamp + (topic.duration || 0))}]
} </Text>
/> </Box>
</div> </AccordionButton>
{activeTopic?.id == topic.id && ( </Flex>
<div className="p-2"> <AccordionPanel>
{topic.segments ? ( {topic.segments ? (
<> <>
{topic.segments.map((segment, index: number) => ( {topic.segments.map((segment, index: number) => (
<p <Text
key={index} key={index}
className="text-left text-slate-500 text-sm md:text-base" className="text-left text-slate-500 text-sm md:text-base"
pb={2}
lineHeight={"1.3"}
>
<span className="font-mono text-slate-500">
[{formatTime(segment.start)}]
</span>
<span
className="font-bold text-slate-500"
style={{
color: generateHighContrastColor(
`Speaker ${segment.speaker}`,
[96, 165, 250],
),
}}
> >
<span className="font-mono text-slate-500"> {" "}
[{formatTime(segment.start)}] {getSpeakerName(segment.speaker)}:
</span> </span>{" "}
<span <span>{segment.text}</span>
className="font-bold text-slate-500" </Text>
style={{ ))}
color: generateHighContrastColor( </>
`Speaker ${segment.speaker}`, ) : (
[96, 165, 250], <>{topic.transcript}</>
), )}
}} </AccordionPanel>
> </AccordionItem>
{" "}
{getSpeakerName(segment.speaker)}:
</span>{" "}
<span>{segment.text}</span>
</p>
))}
</>
) : (
<>{topic.transcript}</>
)}
</div>
)}
</button>
))} ))}
</div> </Accordion>
</> </>
) : ( ) : (
<div className="text-center text-gray-500"> <Box textAlign={"center"} textColor="gray">
Discussion topics will appear here after you start recording. <Text>
<br /> Discussion topics will appear here after you start recording.
It may take up to 5 minutes of conversation for the first topic to </Text>
appear. <Text>
</div> It may take up to 5 minutes of conversation for the first topic to
appear.
</Text>
</Box>
)} )}
</section> </Flex>
); );
} }

View File

@@ -1,6 +1,8 @@
import { useState } from "react"; import { useState } from "react";
import { UpdateTranscript } from "../../api"; import { UpdateTranscript } from "../../api";
import useApi from "../../lib/useApi"; import useApi from "../../lib/useApi";
import { Heading, IconButton, Input } from "@chakra-ui/react";
import { FaPen } from "react-icons/fa";
type TranscriptTitle = { type TranscriptTitle = {
title: string; title: string;
@@ -19,7 +21,6 @@ const TranscriptTitle = (props: TranscriptTitle) => {
const requestBody: UpdateTranscript = { const requestBody: UpdateTranscript = {
title: newTitle, title: newTitle,
}; };
const api = useApi();
const updatedTranscript = await api?.v1TranscriptUpdate( const updatedTranscript = await api?.v1TranscriptUpdate(
transcriptId, transcriptId,
requestBody, requestBody,
@@ -46,6 +47,12 @@ const TranscriptTitle = (props: TranscriptTitle) => {
} }
}; };
const handleBlur = () => {
if (displayedTitle !== preEditTitle) {
updateTitle(displayedTitle, props.transcriptId);
}
setIsEditing(false);
};
const handleChange = (e) => { const handleChange = (e) => {
setDisplayedTitle(e.target.value); setDisplayedTitle(e.target.value);
}; };
@@ -63,21 +70,36 @@ const TranscriptTitle = (props: TranscriptTitle) => {
return ( return (
<> <>
{isEditing ? ( {isEditing ? (
<input <Input
type="text" type="text"
value={displayedTitle} value={displayedTitle}
onChange={handleChange} onChange={handleChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
autoFocus autoFocus
className="text-2xl lg:text-4xl font-extrabold text-center mb-4 w-full border-none bg-transparent overflow-hidden h-[fit-content]" onBlur={handleBlur}
size={"lg"}
fontSize={"xl"}
fontWeight={"bold"}
// className="text-2xl lg:text-4xl font-extrabold text-center mb-4 w-full border-none bg-transparent overflow-hidden h-[fit-content]"
/> />
) : ( ) : (
<h2 <>
className="text-2xl lg:text-4xl font-extrabold text-center mb-4 cursor-pointer" <Heading
onClick={handleTitleClick} // className="text-2xl lg:text-4xl font-extrabold text-center mb-4 cursor-pointer"
> onClick={handleTitleClick}
{displayedTitle} cursor={"pointer"}
</h2> size={"lg"}
noOfLines={1}
>
{displayedTitle}
</Heading>
<IconButton
icon={<FaPen />}
aria-label="Edit Transcript Title"
onClick={handleTitleClick}
fontSize={"15px"}
/>
</>
)} )}
</> </>
); );

View File

@@ -1,7 +1,34 @@
// 1. Import `extendTheme` // 1. Import `extendTheme`
import { extendTheme } from "@chakra-ui/react"; import { extendTheme } from "@chakra-ui/react";
// 2. Call `extendTheme` and pass your custom values import { accordionAnatomy } from "@chakra-ui/anatomy";
import { createMultiStyleConfigHelpers, defineStyle } from "@chakra-ui/react";
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(accordionAnatomy.keys);
const custom = definePartsStyle({
container: {
border: "0",
borderRadius: "8px",
backgroundColor: "white",
mb: 2,
mr: 2,
},
panel: {
pl: 8,
pb: 0,
},
button: {
justifyContent: "flex-start",
pl: 2,
},
});
const accordionTheme = defineMultiStyleConfig({
variants: { custom },
});
const theme = extendTheme({ const theme = extendTheme({
colors: { colors: {
blue: { blue: {
@@ -29,6 +56,9 @@ const theme = extendTheme({
light: "#FFFFFF", light: "#FFFFFF",
dark: "#0C0D0E", dark: "#0C0D0E",
}, },
components: {
Accordion: accordionTheme,
},
}); });
export default theme; export default theme;