mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 04:39:06 +00:00
Merge pull request #245 from Monadical-SAS/sara/design-improvements
UI Improvements
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 ? (
|
||||||
|
<>
|
||||||
|
{transcriptStarted && (
|
||||||
|
<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">
|
<div className="py-2 h-auto">
|
||||||
<LiveTrancription text={webSockets.transcriptText} />
|
{!transcriptStarted ? (
|
||||||
|
<div className="text-center text-gray-500">
|
||||||
|
The conversation transcript will appear here shortly
|
||||||
|
after you start recording.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col justify-center align center text-center">
|
<LiveTrancription text={webSockets.transcriptText} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<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 />
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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: [],
|
||||||
|
|||||||
Reference in New Issue
Block a user