import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ColorResult } from 'react-color'; import { Utils, returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocumentType } from '../../documents/DocumentTypes'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu'; import { LinkPopup } from '../linking/LinkPopup'; import './AnchorMenu.scss'; import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup'; @observer export class AnchorMenu extends AntimodeMenu { static Instance: AnchorMenu; private _disposer: IReactionDisposer | undefined; private _commentRef = React.createRef(); private _cropRef = React.createRef(); constructor(props: any) { super(props); makeObservable(this); AnchorMenu.Instance = this; AnchorMenu.Instance._canFade = false; } @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)'; @observable public Status: 'marquee' | 'annotation' | '' = ''; // GPT additions @observable private selectedText: string = ''; @action public setSelectedText = (txt: string) => (this.selectedText = txt); public onMakeAnchor: () => Opt = () => undefined; // Method to get anchor from text search public OnCrop: (e: PointerEvent) => void = unimplementedFunction; public OnClick: (e: PointerEvent) => void = unimplementedFunction; public OnAudio: (e: PointerEvent) => void = unimplementedFunction; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public Highlight: (color: string) => Opt = (color: string) => undefined; public GetAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = (savedAnnotations: Opt>, addAsAnnotation: boolean) => undefined; public Delete: () => void = unimplementedFunction; public PinToPres: () => void = unimplementedFunction; public MakeTargetToggle: () => void = unimplementedFunction; public ShowTargetTrail: () => void = unimplementedFunction; public IsTargetToggler: () => boolean = returnFalse; public get Active() { return this._left > 0; } componentWillUnmount() { this._disposer?.(); } componentDidMount() { this._disposer = reaction( () => SelectionManager.Views.slice(), sel => AnchorMenu.Instance.fadeOut(true) ); } /** * Invokes the API with the selected text and stores it in the summarized text. * @param e pointer down event */ gptSummarize = async (e: React.PointerEvent) => { GPTPopup.Instance?.setSelectedText(this.selectedText); GPTPopup.Instance.generateSummary(); }; pointerDown = (e: React.PointerEvent) => { setupMoveUpEvents( this, e, (e: PointerEvent) => { this.StartDrag(e, this._commentRef.current!); return true; }, returnFalse, e => this.OnClick?.(e) ); }; audioDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnAudio?.(e)); }; cropDown = (e: React.PointerEvent) => { setupMoveUpEvents( this, e, (e: PointerEvent) => { this.StartCropDrag(e, this._cropRef.current!); return true; }, returnFalse, e => this.OnCrop?.(e) ); }; @action highlightClicked = () => { this.Highlight(this.highlightColor); AnchorMenu.Instance.fadeOut(true); }; @computed get highlighter() { return ( } tooltip={'Click to Highlight'} onClick={this.highlightClicked} colorPicker={this.highlightColor} color={SettingsManager.userColor} /> ); } @action changeHighlightColor = (color: string) => { const col: ColorResult = { hex: color, hsl: { a: 0, h: 0, s: 0, l: 0 }, rgb: { a: 0, r: 0, b: 0, g: 0 }, }; this.highlightColor = Utils.colorString(col); }; /** * Returns whether the selected text can be summarized. The goal is to have * 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 = () => SelectionManager.Docs.some(doc => [DocumentType.PDF, DocumentType.WEB].includes(doc.type as any)); render() { const buttons = this.Status === 'marquee' ? ( <> {this.highlighter}
} color={SettingsManager.userColor} />
{/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/} {AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && ( } color={SettingsManager.userColor} /> )} {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( } color={SettingsManager.userColor} /> )} } popup={} color={SettingsManager.userColor} /> {AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
} color={SettingsManager.userColor} />
)} ) : ( <> {this.Delete !== returnFalse && ( } color={SettingsManager.userColor} /> )} {this.PinToPres !== returnFalse && ( } color={SettingsManager.userColor} /> )} {this.ShowTargetTrail !== returnFalse && ( } color={SettingsManager.userColor} /> )} {this.IsTargetToggler !== returnFalse && ( } color={SettingsManager.userColor} /> )} ); return this.getElement(buttons); } }