diff options
Diffstat (limited to 'src/client/views/nodes/ImageBox.tsx')
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ec5e062c8..b384e0059 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,10 +1,12 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; +import axios from 'axios'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { extname } from 'path'; import * as React from 'react'; +import ReactLoading from 'react-loading'; import { ClientUtils, DashColor, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents } from '../../../ClientUtils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -17,11 +19,11 @@ import { TraceMobx } from '../../../fields/util'; import { emptyFunction } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; -import { DocUtils } from '../../documents/DocUtils'; +import { DocUtils, FollowLinkScript } from '../../documents/DocUtils'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; -import { undoBatch } from '../../util/UndoManager'; +import { undoable, undoBatch } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; @@ -60,25 +62,31 @@ export class ImageEditorData { public static get AddDoc() { return ImageEditorData.imageData.addDoc; } // prettier-ignore public static set AddDoc(addDoc: Opt<(doc: Doc | Doc[], annotationKey?: string) => boolean>) { ImageEditorData.set(this.imageData.open, this.imageData.rootDoc, this.imageData.source, addDoc); } // prettier-ignore } + +const API_URL = 'https://api.unsplash.com/search/photos'; @observer export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } + _ffref = React.createRef<CollectionFreeFormView>(); private _ignoreScroll = false; private _forcedScroll = false; private _dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [name: string]: IReactionDisposer } = {}; private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined; private _overlayIconRef = React.createRef<HTMLDivElement>(); - private _marqueeref = React.createRef<MarqueeAnnotator>(); private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); - @observable _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean })[]>(); - @observable _curSuffix = ''; - @observable _error = ''; - @observable _isHovering = false; // flag to switch between primary and alternate images on hover - _ffref = React.createRef<CollectionFreeFormView>(); + imageRef: HTMLImageElement | null = null; // <video> ref + marqueeref = React.createRef<MarqueeAnnotator>(); + @observable Loading = false; // bcz: this should be migrated into StylProviderQuiz since it's not fundamental to the imageBox + + @observable private _searchInput = ''; + @observable private _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean })[]>(); + @observable private _curSuffix = ''; + @observable private _error = ''; + @observable private _isHovering = false; // flag to switch between primary and alternate images on hover constructor(props: FieldViewProps) { super(props); @@ -90,7 +98,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.Document)); }; - getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const visibleAnchor = this._getAnchor?.(this._savedAnnotations, true); // use marquee anchor, otherwise, save zoom/pan as anchor const anchor = @@ -149,8 +156,33 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { Object.values(this._disposers).forEach(disposer => disposer?.()); } - @undoBatch - drop = (e: Event, de: DragManager.DropEvent) => { + /** + * Find images from the unsplash api to add to flashcards. + */ + fetchImages = async () => { + try { + const { data } = await axios.get(`${API_URL}?query=${this._searchInput}&page=1&per_page=${1}&client_id=${process.env.VITE_API_KEY}`); + const imageSnapshot = Docs.Create.ImageDocument(data.results[0].urls.small, { + _nativeWidth: Doc.NativeWidth(this.layoutDoc), + _nativeHeight: Doc.NativeHeight(this.layoutDoc), + x: NumCast(this.layoutDoc.x), + y: NumCast(this.layoutDoc.y), + onClick: FollowLinkScript(), + _width: 150, + _height: 150, + title: '--snapshot' + NumCast(this.layoutDoc._layout_currentTimecode) + ' image-', + }); + this._props.addDocument?.(imageSnapshot); + } catch (error) { + console.log(error); + } + }; + + handleSelection = async (selection: string) => { + this._searchInput = selection; + }; + + drop = undoable((e: Event, de: DragManager.DropEvent) => { if (de.complete.docDragData) { let added: boolean | undefined; const targetIsBullseye = (ele: HTMLElement): boolean => { @@ -179,7 +211,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { return added; } return false; - }; + }, 'image drop'); @undoBatch resolution = () => { @@ -403,6 +435,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { <div className="imageBox-fader" style={{ opacity: backAlpha }}> <img alt="" + ref={action((r: HTMLImageElement | null) => (this.imageRef = r))} key="paths" src={srcpath} style={{ transform, transformOrigin }} @@ -443,7 +476,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { e, action(moveEv => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - this._marqueeref.current?.onInitiateSelection([moveEv.clientX, moveEv.clientY]); + this.marqueeref.current?.onInitiateSelection([moveEv.clientX, moveEv.clientY]); return true; }), returnFalse, @@ -455,7 +488,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @action finishMarquee = () => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; - this._marqueeref.current?.onTerminateSelection(); + this._props.styleProvider?.(this.Document, this._props, StyleProp.AnchorMenuItems); + AnchorMenu.Instance.addToCollection = this._props.DocumentView?.()._props.addDocument; + AnchorMenu.Instance.marqueeWidth = this.marqueeref.current?.Width ?? 0; + AnchorMenu.Instance.marqueeHeight = this.marqueeref.current?.Height ?? 0; + this.marqueeref.current?.onTerminateSelection(); this._props.select(false); }; focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); @@ -489,7 +526,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { height: this._props.PanelWidth() ? undefined : `100%`, pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, - overflow: this.layoutDoc.layout_fitWidth || this._props.fitWidth?.(this.Document) ? 'auto' : undefined, + overflow: this.layoutDoc.layout_fitWidth || this._props.fitWidth?.(this.Document) ? 'auto' : 'hidden', }}> <CollectionFreeFormView ref={this._ffref} @@ -516,11 +553,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { addDocument={this.addDocument}> {this.content} </CollectionFreeFormView> + {this.Loading ? ( + <div className="loading-spinner" style={{ position: 'absolute' }}> + <ReactLoading type="spin" height={50} width={50} color={'blue'} /> + </div> + ) : null} {this.annotationLayer} {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( <MarqueeAnnotator Document={this.Document} - ref={this._marqueeref} + ref={this.marqueeref} scrollTop={0} annotationLayerScrollTop={0} scaling={returnOne} @@ -534,6 +576,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { marqueeContainer={this._mainCont.current} highlightDragSrcColor="" anchorMenuCrop={this.crop} + // anchorMenuFlashcard={() => this.getImageDesc()} /> )} </div> |