diff options
| author | Sophie Zhang <sophie_zhang@brown.edu> | 2023-09-26 16:49:43 -0400 |
|---|---|---|
| committer | Sophie Zhang <sophie_zhang@brown.edu> | 2023-09-26 16:49:43 -0400 |
| commit | f2958fd4d7dab5369c9e68c5d8f3b50332391aac (patch) | |
| tree | 633e77c196ad4c8c51fb7244e4af22c88168e10d /src/client/views/pdf | |
| parent | aa3dc83bdd723db2597dc36fe09ae288ce3641da (diff) | |
| parent | 78edc744c77e378728d033001331737df0b2f393 (diff) | |
Merge branch 'master' into sophie-ai-images
Diffstat (limited to 'src/client/views/pdf')
| -rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 151 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 10 |
2 files changed, 43 insertions, 118 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index b0924888a..85c1cce8c 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -1,85 +1,37 @@ import React = require('react'); import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Tooltip } from '@material-ui/core'; +import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState } from 'react-color'; import { Doc, Opt } from '../../../fields/Doc'; +import { StrCast } from '../../../fields/Types'; import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils'; +import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; +import { DocumentType } from '../../documents/DocumentTypes'; import { SelectionManager } from '../../util/SelectionManager'; import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu'; import { LinkPopup } from '../linking/LinkPopup'; -import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu'; -import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; -import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup'; -import { LightboxView } from '../LightboxView'; -import { EditorView } from 'prosemirror-view'; import './AnchorMenu.scss'; -import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; -import { StrCast } from '../../../fields/Types'; -import { DocumentType } from '../../documents/DocumentTypes'; +import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup'; +import { SettingsManager } from '../../util/SettingsManager'; @observer export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { static Instance: AnchorMenu; private _disposer: IReactionDisposer | undefined; - private _disposer2: IReactionDisposer | undefined; - private _commentCont = React.createRef<HTMLButtonElement>(); - private _palette = [ - 'rgba(208, 2, 27, 0.8)', - 'rgba(238, 0, 0, 0.8)', - 'rgba(245, 166, 35, 0.8)', - 'rgba(248, 231, 28, 0.8)', - 'rgba(245, 230, 95, 0.616)', - 'rgba(139, 87, 42, 0.8)', - 'rgba(126, 211, 33, 0.8)', - 'rgba(65, 117, 5, 0.8)', - 'rgba(144, 19, 254, 0.8)', - 'rgba(238, 169, 184, 0.8)', - 'rgba(224, 187, 228, 0.8)', - 'rgba(225, 223, 211, 0.8)', - 'rgba(255, 255, 255, 0.8)', - 'rgba(155, 155, 155, 0.8)', - 'rgba(0, 0, 0, 0.8)', - ]; + private _commentRef = React.createRef<HTMLDivElement>(); + private _cropRef = React.createRef<HTMLDivElement>(); @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)'; @observable public Status: 'marquee' | 'annotation' | '' = ''; // GPT additions - @observable private GPTMode: GPTPopupMode = GPTPopupMode.SUMMARY; @observable private selectedText: string = ''; - @observable private editorView?: EditorView; - @observable private textDoc?: Doc; - @observable private highlightRange: number[] | undefined; - private selectionRange: number[] | undefined; - - @action - setGPTMode = (mode: GPTPopupMode) => { - this.GPTMode = mode; - }; - - @action - setHighlightRange(r: number[] | undefined) { - this.highlightRange = r; - } - - @action - public setSelectedText = (txt: string) => { - this.selectedText = txt; - }; - @action - public setEditorView = (editor: EditorView) => { - this.editorView = editor; - }; - - @action - public setTextDoc = (textDoc: Doc) => { - this.textDoc = textDoc; - }; + public setSelectedText = (txt: string) => (this.selectedText = txt); public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search @@ -108,20 +60,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { componentWillUnmount() { this._disposer?.(); - this._disposer2?.(); } componentDidMount() { - this._disposer2 = reaction( - () => this._opacity, - opacity => {}, - { fireImmediately: true } - ); this._disposer = reaction( () => SelectionManager.Views().slice(), - selected => { - AnchorMenu.Instance.fadeOut(true); - } + selected => AnchorMenu.Instance.fadeOut(true) ); } @@ -132,17 +76,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { gptSummarize = async (e: React.PointerEvent) => { // move this logic to gptpopup, need to implement generate again GPTPopup.Instance.setVisible(true); - this.setHighlightRange(undefined); GPTPopup.Instance.setMode(GPTPopupMode.SUMMARY); GPTPopup.Instance.setLoading(true); try { const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY); - if (res) { - GPTPopup.Instance.setText(res); - } else { - GPTPopup.Instance.setText('Something went wrong.'); - } + GPTPopup.Instance.setText(res || 'Something went wrong.'); } catch (err) { console.error(err); } @@ -154,7 +93,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { this, e, (e: PointerEvent) => { - this.StartDrag(e, this._commentCont.current!); + this.StartDrag(e, this._commentRef.current!); return true; }, returnFalse, @@ -171,7 +110,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { this, e, (e: PointerEvent) => { - this.StartCropDrag(e, this._commentCont.current!); + this.StartCropDrag(e, this._cropRef.current!); return true; }, returnFalse, @@ -193,7 +132,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { tooltip={'Click to Highlight'} onClick={this.highlightClicked} colorPicker={this.highlightColor} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> <ColorPicker selectedColor={this.highlightColor} setFinalColor={this.changeHighlightColor} setSelectedColor={this.changeHighlightColor} size={Size.XSMALL} /> </Group> @@ -217,44 +156,28 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { * all selected text available to summarize but its only supported for pdf and web ATM. * @returns Whether the GPT icon for summarization should appear */ - canSummarize = (): boolean => { - const docs = SelectionManager.Docs(); - if (docs.length > 0) { - return docs.some(doc => doc.type === DocumentType.PDF || doc.type === DocumentType.WEB); - } - return false; - }; - - /** - * Returns whether the selected text can be edited. - * @returns Whether the GPT icon for summarization should appear - */ - canEdit = (): boolean => { - const docs = SelectionManager.Docs(); - if (docs.length > 0) { - return docs.some(doc => doc.type === 'rtf'); - } - return false; - }; + canSummarize = () => SelectionManager.Docs().some(doc => [DocumentType.PDF, DocumentType.WEB].includes(doc.type as any)); render() { const buttons = this.Status === 'marquee' ? ( <> {this.highlighter} - <IconButton - tooltip="Drag to Place Annotation" // - onPointerDown={this.pointerDown} - icon={<FontAwesomeIcon icon="comment-alt" />} - color={StrCast(Doc.UserDoc().userColor)} - /> + <div ref={this._commentRef}> + <IconButton + tooltip="Drag to Place Annotation" // + onPointerDown={this.pointerDown} + icon={<FontAwesomeIcon icon="comment-alt" />} + color={SettingsManager.userColor} + /> + </div> {/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/} {AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && ( <IconButton tooltip="Summarize with AI" // onPointerDown={this.gptSummarize} icon={<FontAwesomeIcon icon="comment-dots" size="lg" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( @@ -262,7 +185,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { tooltip="Click to Record Annotation" // onPointerDown={this.audioDown} icon={<FontAwesomeIcon icon="microphone" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} <Popup @@ -270,15 +193,17 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { type={Type.PRIM} icon={<FontAwesomeIcon icon={'search'} />} popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : ( - <IconButton - tooltip="Click/Drag to create cropped image" // - onPointerDown={this.cropDown} - icon={<FontAwesomeIcon icon="image" />} - color={StrCast(Doc.UserDoc().userColor)} - /> + <div ref={this._cropRef}> + <IconButton + tooltip="Click/Drag to create cropped image" // + onPointerDown={this.cropDown} + icon={<FontAwesomeIcon icon="image" />} + color={SettingsManager.userColor} + /> + </div> )} </> ) : ( @@ -288,7 +213,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { tooltip="Remove Link Anchor" // onPointerDown={this.Delete} icon={<FontAwesomeIcon icon="trash-alt" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.PinToPres !== returnFalse && ( @@ -296,7 +221,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { tooltip="Pin to Presentation" // onPointerDown={this.PinToPres} icon={<FontAwesomeIcon icon="map-pin" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.ShowTargetTrail !== returnFalse && ( @@ -304,7 +229,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { tooltip="Show Linked Trail" // onPointerDown={this.ShowTargetTrail} icon={<FontAwesomeIcon icon="taxi" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} {this.IsTargetToggler !== returnFalse && ( @@ -315,7 +240,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { toggleStatus={this.IsTargetToggler()} onClick={this.MakeTargetToggle} icon={<FontAwesomeIcon icon="thumbtack" />} - color={StrCast(Doc.UserDoc().userColor)} + color={SettingsManager.userColor} /> )} </> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 395fbd1ca..2a191477b 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -46,7 +46,7 @@ interface IViewerProps extends FieldViewProps { sidebarAddDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean; loaded?: (nw: number, nh: number, np: number) => void; setPdfViewer: (view: PDFViewer) => void; - anchorMenuClick?: () => undefined | ((anchor: Doc, summarize?: boolean) => void); + anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: (region: Doc | undefined, addCrop?: boolean) => Doc | undefined; } @@ -67,7 +67,7 @@ export class PDFViewer extends React.Component<IViewerProps> { private _pdfViewer: any; private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer - private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void); + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; @@ -375,7 +375,7 @@ export class PDFViewer extends React.Component<IViewerProps> { this._downY = e.clientY; if ((this.props.Document._freeform_scale || 1) !== 1) return; if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) { - this._setPreviewCursor?.(e.clientX, e.clientY, true, false); + this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this.props.Document); } if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this.props.select(false); @@ -464,12 +464,12 @@ export class PDFViewer extends React.Component<IViewerProps> { onClick = (e: React.MouseEvent) => { this._scrollStopper?.(); if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - this._setPreviewCursor(e.clientX, e.clientY, false, false); + this._setPreviewCursor(e.clientX, e.clientY, false, false, this.props.Document); } // e.stopPropagation(); // bcz: not sure why this was here. We need to allow the DocumentView to get clicks to process doubleClicks }; - setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func); + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => (this._setPreviewCursor = func); setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void) => (this._setBrushViewer = func); @action |
