11import { useContext , useEffect , useRef , useState } from "react" ;
22import localforage from "localforage" ;
3- import { useWindowSize } from "@uidotdev/usehooks" ;
3+ import { useCopyToClipboard , useWindowSize } from "@uidotdev/usehooks" ;
44import { deviceWidthEnum , truncateWords } from "../helpers" ;
55import { dummySummary , getSummary } from "../helpers/loaders" ;
66import { SummaryGroup , SummaryGroupItem , SummarySingleItem } from "../components/SummaryItem" ;
@@ -334,6 +334,8 @@ const Summary = ({ summary }) => {
334334
335335
336336 const size = useWindowSize ( ) ;
337+ const [ copiedGeneratedText , copyGeneratedTextToClipboard ] = useCopyToClipboard ( ) ;
338+ const hasCopiedGeneratedText = Boolean ( copiedGeneratedText ) ;
337339 // const searchQuery = useSearchParams();
338340 // const searchParams = new URLSearchParams(window.location.search);
339341 // const searchQuery = searchParams.get('search_query');
@@ -591,6 +593,18 @@ const Summary = ({ summary }) => {
591593 updateShowOnlySummaries ( ) ;
592594 }
593595
596+ const handleCopyGeneratedText = ( text ) => {
597+ copyGeneratedTextToClipboard ( text ) ;
598+ }
599+
600+ useEffect ( ( ) => {
601+ if ( hasCopiedGeneratedText ) {
602+ setTimeout ( ( ) => {
603+ copyGeneratedTextToClipboard ( "" ) ;
604+ } , 2000 ) ;
605+ }
606+ } , [ hasCopiedGeneratedText ] ) ;
607+
594608 // useEffect(() => {
595609 // setData(data);
596610 // console.log("Updating summaryData");
@@ -616,13 +630,43 @@ const Summary = ({ summary }) => {
616630 ? < section
617631 className = { "relative flex flex-col h-full flex-basis flex-grow every:color-454545 dark:every:color-lightgray" } >
618632 < section className = { "w-full h-[400]" } >
633+ {
634+ hasCopiedGeneratedText
635+ && < div role = "alert" className = "alert alert-success flex flex-row" >
636+ < svg xmlns = "http://www.w3.org/2000/svg"
637+ className = "stroke-current shrink-0 h-6 w-6" fill = "none"
638+ viewBox = "0 0 24 24" >
639+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = "2"
640+ d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
641+ </ svg >
642+ < span > Text Copied</ span >
643+ </ div >
644+ }
619645 < div
620- className = { "bg-gray -100 w-full min-h-80 rounded-md my-2 py-2 overflow-x-auto dark:bg-27CE8E1A dark:bg-base-100 " } >
646+ className = { "relative bg-green -100 w-full rounded-md my-2 py-2 overflow-x-auto dark:bg-27CE8E1A dark:bg-green-800/20 " } >
621647 {
622- aiGeneratedData . length > 0 && aiGeneratedData [ 0 ] . finish_reason &&
648+ aiGeneratedData ?. length < 1 &&
649+ < div className = { "flex flex-row items-center gap-x-8 p-8" } >
650+ < span className = "loading loading-dots loading-md" > </ span >
651+ Generating AI response ...
652+ </ div >
653+ }
654+ {
655+ aiGeneratedData ?. length > 0 && aiGeneratedData [ 0 ] . finish_reason &&
623656 < div
624- className = { "bg-clip-text bg-gradient-to-l from-[#27CE8E] to-[#FFDE52] text-transparent px-5 py-4 font-bold text-sm" } > AI
625- Generated</ div >
657+ className = { "bg-clip-text bg-gradient-to-l from-[#27CE8E] to-[#FFDE52] text-transparent px-5 py-4 font-bold text-sm" } >
658+ AI Generated
659+ </ div >
660+ }
661+ {
662+ aiGeneratedData ?. length > 0
663+ ? hasCopiedGeneratedText
664+ ? < button className = "fa fa-check absolute top-6 right-5" > </ button >
665+ : < button
666+ className = "far fa-copy absolute top-6 right-5"
667+ onClick = { ( ) => handleCopyGeneratedText ( baseData ?. aiGeneratedData [ 0 ] ?. text ) } >
668+ </ button >
669+ : null
626670 }
627671 < div className = { "summary-list px-5 py-2 leading-normal list-disc" } >
628672 {
@@ -633,7 +677,8 @@ const Summary = ({ summary }) => {
633677 rehypePlugins = { [ rehypeRaw ] } > { truncateWords ( eachAiGeneratedData ?. text , 0 , 80 ) } </ Markdown >
634678 {
635679 eachAiGeneratedData ?. text . split ( " " ) . length > 80
636- && < button onClick = { ( ) => aiGeneratedContentModal . current ?. showModal ( ) } >
680+ && < button
681+ onClick = { ( ) => aiGeneratedContentModal . current ?. showModal ( ) } >
637682 < div className = { "btn btn-sm flex justify-center mx-auto mt-4" } >
638683 Show more
639684 </ div >
@@ -782,15 +827,44 @@ const Summary = ({ summary }) => {
782827 </ section >
783828 { /* 30% of the container width. i.e., 35% of 1280 == 448 */ }
784829 < section className = { "border:0px_solid_lightgray w-[560px] h-[400] px-8 pt-32" } >
830+ {
831+ hasCopiedGeneratedText
832+ && < div role = "alert" className = "alert alert-success" >
833+ < svg xmlns = "http://www.w3.org/2000/svg"
834+ className = "stroke-current shrink-0 h-6 w-6" fill = "none"
835+ viewBox = "0 0 24 24" >
836+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = "2"
837+ d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
838+ </ svg >
839+ < span > Text Copied</ span >
840+ </ div >
841+ }
785842 < div
786- className = { "bg-gray-100 w-full min-h-80 rounded-md my-2 py-4 dark:bg-27CE8E1A dark:bg-base-100" } >
843+ className = { "relative bg-gray-100 w-full rounded-md my-2 py-4 dark:bg-27CE8E1A dark:bg-base-100" } >
844+ {
845+ aiGeneratedData ?. length < 1 &&
846+ < div className = { "flex flex-row items-center gap-x-8 p-8" } >
847+ < span className = "loading loading-dots loading-md" > </ span >
848+ Generating AI response ...
849+ </ div >
850+ }
787851 {
788852 aiGeneratedData . length > 0 && aiGeneratedData [ 0 ] . finish_reason &&
789853 < div
790854 className = { "bg-clip-text bg-gradient-to-l from-[#27CE8E] to-[#FFDE52] text-transparent px-8 py-4 font-bold text-sm" } > AI
791855 Generated
792856 </ div >
793857 }
858+ {
859+ aiGeneratedData ?. length > 0
860+ ? hasCopiedGeneratedText
861+ ? < button className = "fa fa-check absolute top-6 right-5" > </ button >
862+ : < button
863+ className = "far fa-copy absolute top-6 right-5"
864+ onClick = { ( ) => handleCopyGeneratedText ( baseData ?. aiGeneratedData [ 0 ] ?. text ) } >
865+ </ button >
866+ : null
867+ }
794868 < div className = { "summary-list px-8 py-2 leading-normal list-disc" } >
795869 {
796870 aiGeneratedData . length > 0
0 commit comments