Merge pull request #245 from Monadical-SAS/sara/design-improvements

UI Improvements
This commit is contained in:
Sara
2023-09-26 15:58:47 +02:00
committed by GitHub
9 changed files with 75 additions and 38 deletions

View File

@@ -7,7 +7,7 @@ export default () => (
Reflector is a transcription and summarization pipeline that transforms Reflector is a transcription and summarization pipeline that transforms
audio into knowledge. The output is meeting minutes and topic summaries audio into knowledge. The output is meeting minutes and topic summaries
enabling topic-specific analyses stored in your systems of record. This is enabling topic-specific analyses stored in your systems of record. This is
accomplished on your infrastructure - without 3rd parties - keeping your accomplished on your infrastructure without 3rd parties keeping your
data private, secure, and organized. data private, secure, and organized.
</Paragraph> </Paragraph>
<Title>FAQs</Title> <Title>FAQs</Title>
@@ -23,7 +23,7 @@ export default () => (
Monadical prioritizes safeguarding your data. Reflector operates Monadical prioritizes safeguarding your data. Reflector operates
exclusively on your infrastructure, ensuring guaranteed security. exclusively on your infrastructure, ensuring guaranteed security.
</Paragraph> </Paragraph>
<Subtitle>3. Any industry-specific use cases?</Subtitle> <Subtitle>3. Are there any industry-specific use cases?</Subtitle>
<p>Absolutely! We have two custom deployments pre-built:</p> <p>Absolutely! We have two custom deployments pre-built:</p>
<ul className="mb-2 md:mb-4"> <ul className="mb-2 md:mb-4">
<li> <li>

View File

@@ -83,9 +83,11 @@ export default function RootLayout({ children }) {
alt="Reflector" alt="Reflector"
/> />
<div className="hidden flex-col ml-2 md:block"> <div className="hidden flex-col ml-2 md:block">
<h1 className="text-4xl font-bold">Reflector</h1> <h1 className="text-[38px] font-bold tracking-wide leading-tight">
<p className="text-gray-500"> Reflector
Capture The Signal, Not The Noise </h1>
<p className="text-gray-500 text-xs tracking-tighter">
Capture the signal, not the noise
</p> </p>
</div> </div>
</Link> </Link>

View File

@@ -55,15 +55,14 @@ export default function TranscriptDetails(details: TranscriptDetails) {
useActiveTopic={useActiveTopic} useActiveTopic={useActiveTopic}
autoscroll={false} autoscroll={false}
/> />
<section className="relative w-full h-auto max-h-full bg-blue-400/20 rounded-lg md:rounded-xl px-2 md:px-4 flex flex-col justify-center align-center"> <div className="w-full h-full grid grid-rows-layout-one gap-2 lg:gap-4">
<ShareLink /> <section className=" bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4 h-full">
<div className="py-2 h-full">
{transcript?.response?.longSummary && ( {transcript?.response?.longSummary && (
<FinalSummary text={transcript?.response?.longSummary} /> <FinalSummary text={transcript?.response?.longSummary} />
)} )}
</div> </section>
</section> <ShareLink />
</div>
</div> </div>
</> </>
)} )}

View File

@@ -5,7 +5,7 @@ type FinalSummaryProps = {
export default function FinalSummary(props: FinalSummaryProps) { export default function FinalSummary(props: FinalSummaryProps) {
return ( return (
<div className="overflow-y-auto h-auto max-h-full"> <div className="overflow-y-auto h-auto max-h-full">
<h2 className="text-xl font-bold">Final Summary</h2> <h2 className="text-xl md:text-2xl font-bold">Final Summary</h2>
<p>{props.text}</p> <p>{props.text}</p>
</div> </div>
); );

View File

@@ -45,6 +45,12 @@ const TranscriptCreate = () => {
getAudioStream, getAudioStream,
} = useAudioDevice(); } = useAudioDevice();
const [hasRecorded, setHasRecorded] = useState(false); const [hasRecorded, setHasRecorded] = useState(false);
const [transcriptStarted, setTranscriptStarted] = useState(false);
useEffect(() => {
if (!transcriptStarted && webSockets.transcriptText.length !== 0)
setTranscriptStarted(true);
}, [webSockets.transcriptText]);
useEffect(() => { useEffect(() => {
lockWakeState(); lockWakeState();
@@ -77,13 +83,30 @@ const TranscriptCreate = () => {
useActiveTopic={useActiveTopic} useActiveTopic={useActiveTopic}
autoscroll={true} autoscroll={true}
/> />
<section className="w-full h-full bg-blue-400/20 rounded-lg md:rounded-xl px-2 md:px-4 flex flex-col justify-center align-center">
<section
className={`w-full h-full bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4`}
>
{!hasRecorded ? ( {!hasRecorded ? (
<div className="py-2 h-auto"> <>
<LiveTrancription text={webSockets.transcriptText} /> {transcriptStarted && (
</div> <h2 className="md:text-lg font-bold">Transcription</h2>
)}
<div className="flex flex-col justify-center align center text-center h-full">
<div className="py-2 h-auto">
{!transcriptStarted ? (
<div className="text-center text-gray-500">
The conversation transcript will appear here shortly
after you start recording.
</div>
) : (
<LiveTrancription text={webSockets.transcriptText} />
)}
</div>
</div>
</>
) : ( ) : (
<div className="flex flex-col justify-center align center text-center"> <div className="flex flex-col justify-center align center text-center h-full text-gray-500">
<div className="p-2 md:p-4"> <div className="p-2 md:p-4">
<FontAwesomeIcon <FontAwesomeIcon
icon={faGear} icon={faGear}
@@ -117,7 +140,7 @@ const TranscriptCreate = () => {
transforms audio into knowledge. The output is meeting transforms audio into knowledge. The output is meeting
minutes and topic summaries enabling topic-specific analyses minutes and topic summaries enabling topic-specific analyses
stored in your systems of record. This is accomplished on stored in your systems of record. This is accomplished on
your infrastructure - without 3rd parties - keeping your your infrastructure without 3rd parties keeping your
data private, secure, and organized. data private, secure, and organized.
</p> </p>
<About buttonText="Learn more" /> <About buttonText="Learn more" />
@@ -125,14 +148,12 @@ const TranscriptCreate = () => {
Audio Permissions Audio Permissions
</h2> </h2>
{loading ? ( {loading ? (
<p className="text-gray-500 text-center"> <p className="text-center">Checking permission...</p>
Checking permission...
</p>
) : ( ) : (
<> <>
<p className="text-gray-500 text-center"> <p className="text-center">
To enable Reflector, we kindly request permission to In order to use Reflector, we kindly request permission
access your microphone during meetings and events. to access your microphone during meetings and events.
<br /> <br />
<Privacy buttonText="Privacy policy" /> <Privacy buttonText="Privacy policy" />
<br /> <br />

View File

@@ -109,7 +109,7 @@ export default function Recorder(props: RecorderProps) {
const wsWrapper = _wavesurfer.getWrapper(); const wsWrapper = _wavesurfer.getWrapper();
wsWrapper.style.cursor = "pointer"; wsWrapper.style.cursor = "pointer";
wsWrapper.style.backgroundColor = "#e0c3fc42"; wsWrapper.style.backgroundColor = "RGB(240 240 240)";
wsWrapper.style.borderRadius = "15px"; wsWrapper.style.borderRadius = "15px";
_wavesurfer.on("play", () => { _wavesurfer.on("play", () => {
@@ -278,7 +278,10 @@ export default function Recorder(props: RecorderProps) {
return ( return (
<div className="flex items-center w-full relative"> <div className="flex items-center w-full relative">
<div className="flex-grow items-end relative"> <div className="flex-grow items-end relative">
<div ref={waveformRef} className="flex-grow rounded-2xl h-20"></div> <div
ref={waveformRef}
className="flex-grow rounded-lg md:rounded-xl h-20"
></div>
<div className="absolute right-2 bottom-0"> <div className="absolute right-2 bottom-0">
{isRecording && ( {isRecording && (
<div className="inline-block bg-red-500 rounded-full w-2 h-2 my-auto mr-1 animate-ping"></div> <div className="inline-block bg-red-500 rounded-full w-2 h-2 my-auto mr-1 animate-ping"></div>
@@ -336,7 +339,7 @@ export default function Recorder(props: RecorderProps) {
> >
{isRecording ? "Stop" : "Record"} {isRecording ? "Stop" : "Record"}
</button> </button>
{props.audioDevices && props.audioDevices?.length > 0 && ( {props.audioDevices && props.audioDevices?.length > 1 && (
<> <>
<button <button
className="text-center text-blue-400 hover:text-blue-700 ml-2 md:ml:4 p-2 rounded-lg focus-visible:outline outline-blue-400" className="text-center text-blue-400 hover:text-blue-700 ml-2 md:ml:4 p-2 rounded-lg focus-visible:outline outline-blue-400"

View File

@@ -1,10 +1,13 @@
import React, { useState, useRef } from "react"; import React, { useState, useRef, useEffect, use } from "react";
const ShareLink = () => { const ShareLink = () => {
const [isCopied, setIsCopied] = useState(false); const [isCopied, setIsCopied] = useState(false);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [currentUrl, setCurrentUrl] = useState<string>("");
const currentURL = window.location.href; useEffect(() => {
setCurrentUrl(window.location.href);
}, []);
const handleCopyClick = () => { const handleCopyClick = () => {
if (inputRef.current) { if (inputRef.current) {
@@ -19,7 +22,7 @@ const ShareLink = () => {
return ( return (
<div <div
className="p-2 md:p-4 mt-8 md:mt-4 rounded" className="p-2 md:p-4 rounded"
style={{ background: "rgba(96, 165, 250, 0.2)" }} style={{ background: "rgba(96, 165, 250, 0.2)" }}
> >
<p className="text-sm mb-2"> <p className="text-sm mb-2">
@@ -31,9 +34,10 @@ const ShareLink = () => {
<input <input
type="text" type="text"
readOnly readOnly
value={currentURL} value={currentUrl}
ref={inputRef} ref={inputRef}
className="border rounded p-2 flex-grow mr-2 text-sm bg-slate-100 outline-slate-400" onChange={() => {}}
className="border rounded-lg md:rounded-xl p-2 flex-grow mr-2 text-sm bg-slate-100 outline-slate-400"
/> />
<button <button
onClick={handleCopyClick} onClick={handleCopyClick}

View File

@@ -61,9 +61,11 @@ export function TopicList({
}, [activeTopic, autoscroll]); }, [activeTopic, autoscroll]);
return ( return (
<section className="relative w-full h-full bg-blue-400/20 rounded-lg md:rounded-xl px-2 md:px-4 flex flex-col justify-center align-center"> <section className="relative w-full h-full bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4 flex flex-col justify-center align-center">
{topics.length > 0 ? ( {topics.length > 0 ? (
<> <>
<h2 className="md:text-lg font-bold mb-2">Topics</h2>
{autoscroll && ( {autoscroll && (
<ScrollToBottom <ScrollToBottom
visible={!autoscrollEnabled} visible={!autoscrollEnabled}
@@ -73,13 +75,13 @@ export function TopicList({
<div <div
id="topics-div" id="topics-div"
className="overflow-y-auto py-2 h-full" className="overflow-y-auto h-full"
onScroll={handleScroll} onScroll={handleScroll}
> >
{topics.map((topic, index) => ( {topics.map((topic, index) => (
<button <button
key={index} key={index}
className="rounded-none border-solid border-0 border-b-blue-300 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" 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={() => onClick={() =>
setActiveTopic(activeTopic?.id == topic.id ? null : topic) setActiveTopic(activeTopic?.id == topic.id ? null : topic)
} }
@@ -108,9 +110,11 @@ export function TopicList({
</div> </div>
</> </>
) : ( ) : (
<div className="text-center text-gray-500 p-4"> <div className="text-center text-gray-500">
Discussion topics will appear here after you start recording. It may Discussion topics will appear here after you start recording.
take up to 5 minutes of conversation for the first topic to appear. <br />
It may take up to 5 minutes of conversation for the first topic to
appear.
</div> </div>
)} )}
</section> </section>

View File

@@ -11,10 +11,14 @@ module.exports = {
gridTemplateRows: { gridTemplateRows: {
layout: "auto auto minmax(0, 1fr)", layout: "auto auto minmax(0, 1fr)",
"mobile-inner": "minmax(0, 2fr) minmax(0, 1fr)", "mobile-inner": "minmax(0, 2fr) minmax(0, 1fr)",
"layout-one": "minmax(0, 1fr) auto",
}, },
animation: { animation: {
"spin-slow": "spin 3s linear infinite", "spin-slow": "spin 3s linear infinite",
}, },
colors: {
bluegrey: "RGB(90, 122, 158)",
},
}, },
}, },
plugins: [], plugins: [],