mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
past meeting transcript side
This commit is contained in:
@@ -71,21 +71,30 @@ export default function TranscriptDetails(details: TranscriptDetails) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid templateColumns="1fr" templateRows="minmax(0, 1fr) auto">
|
||||
<Grid
|
||||
templateColumns="1fr"
|
||||
templateRows="minmax(0, 1fr) auto"
|
||||
gap={4}
|
||||
mb={4}
|
||||
>
|
||||
<Grid
|
||||
templateColumns="repeat(2, 1fr)"
|
||||
templateRows="auto minmax(0, 1fr)"
|
||||
gap={4}
|
||||
gap={2}
|
||||
padding={4}
|
||||
background="gray.100"
|
||||
borderRadius={2}
|
||||
borderRadius={8}
|
||||
>
|
||||
<GridItem display="flex" flexDir="row" colSpan={2}>
|
||||
<GridItem
|
||||
display="flex"
|
||||
flexDir="row"
|
||||
alignItems={"center"}
|
||||
colSpan={2}
|
||||
>
|
||||
<TranscriptTitle
|
||||
title={transcript.response.title || "Unamed Transcript"}
|
||||
transcriptId={transcriptId}
|
||||
/>
|
||||
<IconButton icon={<FaPen />} aria-label="Edit Transcript Title" />
|
||||
</GridItem>
|
||||
<TopicList
|
||||
topics={topics.topics || []}
|
||||
|
||||
@@ -9,6 +9,18 @@ import ScrollToBottom from "./scrollToBottom";
|
||||
import { Topic } from "./webSocketTypes";
|
||||
import { generateHighContrastColor } from "../../lib/utils";
|
||||
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 = {
|
||||
topics: Topic[];
|
||||
@@ -75,11 +87,16 @@ export function TopicList({
|
||||
};
|
||||
|
||||
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 ? (
|
||||
<>
|
||||
<h2 className="ml-2 md:text-lg font-bold mb-2">Topics</h2>
|
||||
|
||||
{autoscroll && (
|
||||
<ScrollToBottom
|
||||
visible={!autoscrollEnabled}
|
||||
@@ -87,80 +104,95 @@ export function TopicList({
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
<Accordion
|
||||
id="topics-div"
|
||||
className="overflow-y-auto h-full"
|
||||
overflowY={"auto"}
|
||||
h={"100%"}
|
||||
onScroll={handleScroll}
|
||||
defaultIndex={[
|
||||
topics.findIndex((topic) => topic.id == activeTopic?.id),
|
||||
]}
|
||||
variant="custom"
|
||||
allowToggle
|
||||
>
|
||||
{topics.map((topic, index) => (
|
||||
<button
|
||||
<AccordionItem
|
||||
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"
|
||||
onClick={() =>
|
||||
setActiveTopic(activeTopic?.id == topic.id ? null : topic)
|
||||
}
|
||||
background={{
|
||||
base: "light",
|
||||
_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">
|
||||
<p>
|
||||
<span className="font-light font-mono text-slate-500 text-base md:text-lg">
|
||||
[{formatTime(topic.timestamp)}]
|
||||
</span>
|
||||
<span>{topic.title}</span>
|
||||
</p>
|
||||
<FontAwesomeIcon
|
||||
className="transform transition-transform duration-200 ml-2"
|
||||
icon={
|
||||
activeTopic?.id == topic.id
|
||||
? faChevronDown
|
||||
: faChevronRight
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{activeTopic?.id == topic.id && (
|
||||
<div className="p-2">
|
||||
{topic.segments ? (
|
||||
<>
|
||||
{topic.segments.map((segment, index: number) => (
|
||||
<p
|
||||
key={index}
|
||||
className="text-left text-slate-500 text-sm md:text-base"
|
||||
<Flex dir="row" letterSpacing={".2"}>
|
||||
<AccordionButton>
|
||||
<AccordionIcon />
|
||||
<Box as="span" textAlign="left" ml="1">
|
||||
{topic.title}{" "}
|
||||
<Text
|
||||
as="span"
|
||||
color="gray.500"
|
||||
fontSize="sm"
|
||||
fontWeight="bold"
|
||||
>
|
||||
[{formatTime(topic.timestamp)}] - [
|
||||
{formatTime(topic.timestamp + (topic.duration || 0))}]
|
||||
</Text>
|
||||
</Box>
|
||||
</AccordionButton>
|
||||
</Flex>
|
||||
<AccordionPanel>
|
||||
{topic.segments ? (
|
||||
<>
|
||||
{topic.segments.map((segment, index: number) => (
|
||||
<Text
|
||||
key={index}
|
||||
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)}]
|
||||
</span>
|
||||
<span
|
||||
className="font-bold text-slate-500"
|
||||
style={{
|
||||
color: generateHighContrastColor(
|
||||
`Speaker ${segment.speaker}`,
|
||||
[96, 165, 250],
|
||||
),
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{getSpeakerName(segment.speaker)}:
|
||||
</span>{" "}
|
||||
<span>{segment.text}</span>
|
||||
</p>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<>{topic.transcript}</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
{" "}
|
||||
{getSpeakerName(segment.speaker)}:
|
||||
</span>{" "}
|
||||
<span>{segment.text}</span>
|
||||
</Text>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<>{topic.transcript}</>
|
||||
)}
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</div>
|
||||
</Accordion>
|
||||
</>
|
||||
) : (
|
||||
<div className="text-center text-gray-500">
|
||||
Discussion topics will appear here after you start recording.
|
||||
<br />
|
||||
It may take up to 5 minutes of conversation for the first topic to
|
||||
appear.
|
||||
</div>
|
||||
<Box textAlign={"center"} textColor="gray">
|
||||
<Text>
|
||||
Discussion topics will appear here after you start recording.
|
||||
</Text>
|
||||
<Text>
|
||||
It may take up to 5 minutes of conversation for the first topic to
|
||||
appear.
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</section>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { UpdateTranscript } from "../../api";
|
||||
import useApi from "../../lib/useApi";
|
||||
import { Heading, IconButton, Input } from "@chakra-ui/react";
|
||||
import { FaPen } from "react-icons/fa";
|
||||
|
||||
type TranscriptTitle = {
|
||||
title: string;
|
||||
@@ -19,7 +21,6 @@ const TranscriptTitle = (props: TranscriptTitle) => {
|
||||
const requestBody: UpdateTranscript = {
|
||||
title: newTitle,
|
||||
};
|
||||
const api = useApi();
|
||||
const updatedTranscript = await api?.v1TranscriptUpdate(
|
||||
transcriptId,
|
||||
requestBody,
|
||||
@@ -46,6 +47,12 @@ const TranscriptTitle = (props: TranscriptTitle) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
if (displayedTitle !== preEditTitle) {
|
||||
updateTitle(displayedTitle, props.transcriptId);
|
||||
}
|
||||
setIsEditing(false);
|
||||
};
|
||||
const handleChange = (e) => {
|
||||
setDisplayedTitle(e.target.value);
|
||||
};
|
||||
@@ -63,21 +70,36 @@ const TranscriptTitle = (props: TranscriptTitle) => {
|
||||
return (
|
||||
<>
|
||||
{isEditing ? (
|
||||
<input
|
||||
<Input
|
||||
type="text"
|
||||
value={displayedTitle}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
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"
|
||||
onClick={handleTitleClick}
|
||||
>
|
||||
{displayedTitle}
|
||||
</h2>
|
||||
<>
|
||||
<Heading
|
||||
// className="text-2xl lg:text-4xl font-extrabold text-center mb-4 cursor-pointer"
|
||||
onClick={handleTitleClick}
|
||||
cursor={"pointer"}
|
||||
size={"lg"}
|
||||
noOfLines={1}
|
||||
>
|
||||
{displayedTitle}
|
||||
</Heading>
|
||||
<IconButton
|
||||
icon={<FaPen />}
|
||||
aria-label="Edit Transcript Title"
|
||||
onClick={handleTitleClick}
|
||||
fontSize={"15px"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,34 @@
|
||||
// 1. Import `extendTheme`
|
||||
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({
|
||||
colors: {
|
||||
blue: {
|
||||
@@ -29,6 +56,9 @@ const theme = extendTheme({
|
||||
light: "#FFFFFF",
|
||||
dark: "#0C0D0E",
|
||||
},
|
||||
components: {
|
||||
Accordion: accordionTheme,
|
||||
},
|
||||
});
|
||||
|
||||
export default theme;
|
||||
|
||||
Reference in New Issue
Block a user