diff options
Diffstat (limited to 'src/client/views/pdf/GPTPopup.tsx')
-rw-r--r-- | src/client/views/pdf/GPTPopup.tsx | 115 |
1 files changed, 107 insertions, 8 deletions
diff --git a/src/client/views/pdf/GPTPopup.tsx b/src/client/views/pdf/GPTPopup.tsx index 76f3c8187..ec4fa58dc 100644 --- a/src/client/views/pdf/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup.tsx @@ -1,30 +1,129 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import React = require('react'); import ReactLoading from 'react-loading'; import Typist from 'react-typist'; +import { Doc } from '../../../fields/Doc'; +import { Docs } from '../../documents/Documents'; import './GPTPopup.scss'; interface GPTPopupProps { visible: boolean; text: string; loadingSummary: boolean; + callApi: (e: React.PointerEvent) => Promise<void>; } @observer export class GPTPopup extends React.Component<GPTPopupProps> { + static Instance: GPTPopup; + + @observable + private summaryDone: boolean = false; + @observable + private sidebarId: string = ''; + @action + public setSummaryDone = (done: boolean) => { + this.summaryDone = done; + }; + @action + public setSidebarId = (id: string) => { + this.sidebarId = id; + }; + + public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; + + /** + * Transfers the summarization text to a sidebar annotation text document. + */ + private transferToText = () => { + const newDoc = Docs.Create.TextDocument(this.props.text.trim(), { + _width: 200, + _height: 50, + _fitWidth: true, + _autoHeight: true, + }); + this.addDoc(newDoc, this.sidebarId); + }; + + constructor(props: GPTPopupProps) { + super(props); + GPTPopup.Instance = this; + } + + componentDidUpdate = () => { + if (this.props.loadingSummary) { + this.setSummaryDone(false); + } + }; + render() { return ( - <div className="summary-box" style={{ display: this.props.visible ? 'block' : 'none' }}> + <div className="summary-box" style={{ display: this.props.visible ? 'flex' : 'none' }}> <div className="summary-heading"> <label className="summary-text">SUMMARY</label> - {this.props.loadingSummary ? <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} /> : <></>} + {this.props.loadingSummary && <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />} </div> - {!this.props.loadingSummary ? ( - <Typist key={this.props.text} avgTypingDelay={20} cursor={{ hideWhenDone: true }}> - {this.props.text} - </Typist> - ) : ( - <></> + <div className="content-wrapper"> + {!this.props.loadingSummary && + (!this.summaryDone ? ( + <Typist + key={this.props.text} + avgTypingDelay={15} + cursor={{ hideWhenDone: true }} + onTypingDone={action(() => { + setTimeout( + action(() => { + this.summaryDone = true; + }), + 500 + ); + })}> + {this.props.text} + </Typist> + ) : ( + this.props.text + ))} + </div> + {!this.props.loadingSummary && ( + <div className="btns-wrapper"> + {this.summaryDone ? ( + <> + <button className="icon-btn" onPointerDown={e => this.props.callApi(e)}> + <FontAwesomeIcon icon="redo-alt" size="lg" /> + </button> + <button + className="text-btn" + onClick={e => { + this.transferToText(); + }}> + Transfer to Text + </button> + </> + ) : ( + <div className="summarizing"> + <label>Summarizing</label> + <ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} /> + <button + className="btn-secondary" + onClick={e => { + this.setSummaryDone(true); + }}> + Stop Animation + </button> + </div> + )} + </div> + )} + {this.summaryDone && ( + <div className="ai-warning"> + <FontAwesomeIcon icon="exclamation-circle" size="sm" style={{ paddingRight: '5px' }} /> + AI generated responses can contain inaccurate or misleading content.{' '} + <a target="_blank" href="https://www.nytimes.com/2023/02/08/technology/ai-chatbots-disinformation.html"> + Learn More + </a> + </div> )} </div> ); |