diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.scss | 11 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.tsx | 55 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.scss | 13 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 62 | ||||
-rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 21 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 1 |
6 files changed, 124 insertions, 39 deletions
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss index c4679e888..b402a7a32 100644 --- a/src/client/views/collections/CollectionCarouselView.scss +++ b/src/client/views/collections/CollectionCarouselView.scss @@ -27,10 +27,10 @@ .carouselView-fwd, .carouselView-star, .carouselView-remove, -.carouselView-check { +.carouselView-check, +.carouselView-add { position: absolute; display: flex; - top: 42.5%; width: 30; height: 30; align-items: center; @@ -43,15 +43,22 @@ } } .carouselView-fwd { + top: 42.5%; right: 20; } .carouselView-back { + top: 42.5%; left: 20; } .carouselView-star { top: 0; left: 0; } +.carouselView-add { + position: absolute; + bottom: 0; + left: 0; +} .carouselView-remove { top: 80%; left: 52%; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 9cf7765dd..b5b6e1f4b 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -4,6 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import { Docs } from '../../documents/Documents'; import * as React from 'react'; import { StopEvent, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; @@ -48,7 +49,8 @@ export class CollectionCarouselView extends CollectionSubView() { constructor(props: any) { super(props); makeObservable(this); - this.layoutDoc.filterOp = cardMode.ALL; + // this.layoutDoc.filterOp = cardMode.ALL; + Doc.setDocFilter(this.Document, 'data_star', undefined, 'match'); this.layoutDoc.practiceMode = practiceMode.NORMAL; this.layoutDoc._carousel_index = 0; } @@ -177,9 +179,12 @@ export class CollectionCarouselView extends CollectionSubView() { this.layoutDoc.filterOp = mode; switch (mode) { case cardMode.STAR: + Doc.setDocFilter(this.Document, 'data_star', true, 'match'); this.move(1); break; - default: this.setFilterMessage(undefined); // prettier-ignore + default: + this.setFilterMessage(undefined); // prettier-ignore + Doc.setDocFilter(this.Document, 'data_star', true, 'remove'); } }; @@ -197,6 +202,7 @@ export class CollectionCarouselView extends CollectionSubView() { NativeHeight={returnZero} fitWidth={undefined} setContentViewBox={undefined} + childFilters={this.childDocFilters} onDoubleClickScript={this.onContentDoubleClick} onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} @@ -227,6 +233,16 @@ export class CollectionCarouselView extends CollectionSubView() { </> ); } + + containsDifTypes = (): boolean => { + return this.carouselItems.filter(doc => !doc.layout.isFlashcard).length === 0; + }; + + addFlashcard() { + const newDoc = Docs.Create.ComparisonDocument('', { _layout_isFlashcard: true, _width: 300, _height: 300 }); + this.addDocument?.(newDoc); + } + @computed get buttons() { if (!this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)]) return null; return ( @@ -237,17 +253,32 @@ export class CollectionCarouselView extends CollectionSubView() { <div key="fwd" className="carouselView-fwd" onClick={this.advance}> <FontAwesomeIcon icon="chevron-right" size="2x" /> </div> - <div key="star" className="carouselView-star" onClick={this.star}> - <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" /> - </div> + {!this.containsDifTypes() ? ( + <div> + <Tooltip title="star"> + <div key="star" className="carouselView-star" onClick={this.star}> + <FontAwesomeIcon icon="star" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" /> + </div> + </Tooltip> + <Tooltip title="add new flashcard to pile"> + <div key="add" className="carouselView-add" onClick={this.addFlashcard}> + <FontAwesomeIcon icon="plus" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" /> + </div> + </Tooltip> + </div> + ) : null} {this.layoutDoc.practiceMode === practiceMode.PRACTICE ? ( <div> - <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}> - <FontAwesomeIcon icon="xmark" color="red" size="1x" /> - </div> - <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}> - <FontAwesomeIcon icon="check" color="green" size="1x" /> - </div> + <Tooltip title="Incorrect. View again later."> + <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}> + <FontAwesomeIcon icon="xmark" color="red" size="1x" /> + </div> + </Tooltip> + <Tooltip title="Correct"> + <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}> + <FontAwesomeIcon icon="check" color="green" size="1x" /> + </div> + </Tooltip> </div> ) : null} </> @@ -320,7 +351,7 @@ export class CollectionCarouselView extends CollectionSubView() { }}> Recently missed! </p> - {this.menu} + {!this.containsDifTypes() ? this.menu : null} {this.Document._chromeHidden || (!this._filterMessage && !this._practiceMessage) ? this.buttons : null} </div> ); diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index dc107b576..0b2c356e5 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -14,9 +14,8 @@ -webkit-text-stroke-color: black; -webkit-text-stroke-width: 0.2px; } - .input-box { - position: relative; + position: absolute; padding: 10px; width: 100%; height: 100%; @@ -145,6 +144,15 @@ } } +.explain { + position: absolute; + top: 10px; + left: 10px; + z-index: 200; + padding: 5px; + background: #dfdfdf; +} + .comparisonBox-interactive { pointer-events: unset; cursor: ew-resize; @@ -154,6 +162,7 @@ display: flex; } } + // .input-box { // position: absolute; // padding: 10px; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 02ab76c2a..9eb5f6ca2 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -43,9 +43,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() @observable private _inputValue = ''; @observable private _outputValue = ''; @observable private _loading = false; - @observable private _errorMessage = ''; - @observable private _outputMessage = ''; @observable private _isEmpty = false; + @observable _yRelativeToTop: boolean = true; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; @@ -76,8 +75,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() componentDidMount() { this._props.setContentViewBox?.(this); reaction( - () => this._props.isSelected(), - selected => !selected && (this.childActive = false) + () => this._props.isSelected(), // when this reaction should update + selected => !selected && (this.childActive = false) // what it should update to ); } protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => { @@ -283,8 +282,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }) } style={{ - background: usepath === 'alternate' ? 'white' : 'black', - color: usepath === 'alternate' ? 'black' : 'white', + background: this.revealOp === 'hover' ? 'gray' : usepath === 'alternate' ? 'white' : 'black', + color: this.revealOp === 'hover' ? 'black' : usepath === 'alternate' ? 'black' : 'white', display: 'inline-block', }}> <div key="alternate" className="formattedTextBox-flip"> @@ -303,7 +302,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? ( <div className="dash-tooltip">Flip to front side to use GPT</div> ) : ( - <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard</div> + <div className="dash-tooltip">Ask GPT to create an answer on the back side of the flashcard based on your question on the front</div> ) }> <div style={{ position: 'absolute', bottom: '3px', right: '56px', cursor: 'pointer' }} onPointerDown={e => (!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? this.askGPT(GPTCallType.CHATCARD) : null)}> @@ -314,16 +313,17 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <div style={{ position: 'absolute', bottom: '3px', right: '80px', cursor: 'pointer' }} onPointerDown={e => { + // this.displayLabelHandler(e.target.value, e.clientY); const collectionArr: Doc[] = []; collectionArr.push(this.Document); const newCol = Docs.Create.CarouselDocument(collectionArr, { - _width: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 250), - _height: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 200), + _width: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 250) + 50, + _height: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 200) + 50, _layout_fitWidth: false, _layout_autoHeight: true, }); - newCol['x'] = e.clientX - 820; - newCol['y'] = e.clientY - 640; + newCol['x'] = this.layoutDoc['x']; + newCol['y'] = NumCast(this.layoutDoc['y']) + 50; this._props.addDocument?.(newCol); this._props.removeDocument?.(this.Document); this.Document.embedContainer = newCol; @@ -332,9 +332,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() </div> </Tooltip> <Tooltip title={<div className="dash-tooltip">Hover to reveal</div>}> - <div - style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }} - onClick={e => (this.revealOp === 'hover' ? (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip') : (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'))}> + <div style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }} onClick={e => this.handleHover()}> <FontAwesomeIcon color={this.revealOp === 'hover' ? 'blue' : 'black'} icon="layer-group" size="xl" /> </div> </Tooltip> @@ -361,6 +359,17 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() if (this._inputValue) this.askGPT(GPTCallType.QUIZ); }; + @action handleHover = () => { + if (this.revealOp === 'hover') { + this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip'; + this.Document.forceActive = false; + } else { + this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'; + this.Document.forceActive = true; + } + //this.revealOp === 'hover' ? (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip') : (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'); + }; + @action handleRenderClick = () => { // Call the GPT model and get the output this.layoutDoc[`_${this._props.fieldKey}_usePath`] = undefined; @@ -448,6 +457,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() const whichDoc = DocCast(this.dataDoc[whichSlot]); const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc); const layoutString = targetDoc ? '' : this.testForTextFields(whichSlot); + // whichDoc['backgroundColor'] = this.layoutDoc['backgroundColor']; return targetDoc || layoutString ? ( <> @@ -500,20 +510,32 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() // add text box to each side when comparison box is first created // (!this.dataDoc[this.fieldKey + '_0'] && this.dataDoc[this._props.fieldKey + '_0'] !== 'empty') if (!this.dataDoc[this.fieldKey + '_0'] && !this._isEmpty) { - const dataSplit = StrCast(this.dataDoc.data).split('Answer'); + const dataSplit = StrCast(this.dataDoc.data).split('Answer: '); const newDoc = Docs.Create.TextDocument(dataSplit[1]); // if there is text from the pdf ai cards, put the question on the front side. // eslint-disable-next-line prefer-destructuring - newDoc[DocData].text = dataSplit[1]; + // newDoc.text = dataSplit[1]; + newDoc['backgroundColor'] = 'lightgray'; this.addDoc(newDoc, this.fieldKey + '_0'); + // DocCast(this.dataDoc[this.fieldKey + '_0'])[DocData].text = dataSplit[1]; + // DocCast(this.dataDoc[this.fieldKey + '_0']).text = dataSplit[1]; + // console.log('HI' + DocCast(this.dataDoc[this.fieldKey + '_0']).text); + console.log('HEREEE' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text)); } + if (!this.dataDoc[this.fieldKey + '_1'] && !this._isEmpty) { - const dataSplit = StrCast(this.dataDoc.data).split('Answer'); + const dataSplit = StrCast(this.dataDoc.data).split('Answer: '); const newDoc = Docs.Create.TextDocument(dataSplit[0]); + this.addDoc(newDoc, this.fieldKey + '_1'); // if there is text from the pdf ai cards, put the answer on the alternate side. // eslint-disable-next-line prefer-destructuring - newDoc[DocData].text = dataSplit[0]; - this.addDoc(newDoc, this.fieldKey + '_1'); + + // newDoc[DocData].text = dataSplit[0]; + // console.log('HEREEE' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)); + // console.log('HI' + DocCast(this.dataDoc[this.fieldKey + '_1']).text); + // DocCast(this.dataDoc[this.props.fieldKey + '_1'])[DocData].text = dataSplit[0]; + // console.log('HEREEE' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text)); + // DocCast(this.dataDoc[this.fieldKey + '_1'])[DocData].text = dataSplit[0]; } // render the QuizCards @@ -552,6 +574,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() ); } + console.log('HEREEE2' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)); // render a normal flashcard when not a QuizCard return ( <div @@ -566,6 +589,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }} // onPointerUp={() => (this._isAnyChildContentActive = true)} > + {StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '' && !this.childActive ? <p className="explain">Enter text in the flashcard. </p> : null} {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)} {this._loading ? ( <div className="loading-spinner" style={{ position: 'absolute' }}> diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 2f6824466..cedd3c7c3 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -24,6 +24,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { private _disposer: IReactionDisposer | undefined; private _commentRef = React.createRef<HTMLDivElement>(); private _cropRef = React.createRef<HTMLDivElement>(); + // @observable protected _top: number = -300; + // @observable protected _left: number = -300; constructor(props: any) { super(props); @@ -38,10 +40,17 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { // GPT additions @observable private _selectedText: string = ''; + @observable private _x: number = 0; + @observable private _y: number = 0; @action public setSelectedText = (txt: string) => { this._selectedText = txt.trim(); }; + @action + public setLocation = (x: number, y: number) => { + this._x = x; + this._y = y; + }; public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search @@ -99,7 +108,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { * Invokes the API with the selected text and stores it in the selected text. * @param e pointer down event */ - gptFlashcards = async () => { + gptFlashcards = async (e: React.PointerEvent) => { const queryText = this._selectedText; try { const res = await gptAPICall(queryText, GPTCallType.FLASHCARD); @@ -117,8 +126,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { */ transferToFlashcard = (text: string) => { // put each question generated by GPT on the front of the flashcard - const senArr = text.split('Question'); - const collectionArr: Doc[] = []; + var senArr = text.trim().split('Question: '); + var collectionArr: Doc[] = []; for (let i = 1; i < senArr.length; i++) { console.log('Arr ' + i + ': ' + senArr[i]); const newDoc = Docs.Create.ComparisonDocument(senArr[i], { _layout_isFlashcard: true, _width: 300, _height: 300 }); @@ -133,6 +142,10 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { _layout_autoHeight: true, }); + newCol.x = this._x; + newCol.y = this._y; + newCol.zIndex = 100; + this.addToCollection?.(newCol); }; @@ -221,7 +234,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { {/* Adds a create flashcards option to the anchor menu, which calls the gptFlashcard method. */} <IconButton tooltip="Create flashcards" // - onPointerDown={this.gptFlashcards} + onPointerDown={e => this.gptFlashcards(e)} icon={<FontAwesomeIcon icon="id-card" size="lg" />} color={SettingsManager.userColor} /> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 6c1617c38..92f890e70 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -425,6 +425,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { const sel = window.getSelection(); if (sel) { AnchorMenu.Instance.setSelectedText(sel.toString()); + AnchorMenu.Instance.setLocation(NumCast(this._props.layoutDoc['x']), NumCast(this._props.layoutDoc['y'])); } if (sel?.type === 'Range') { |