From 7594f649890d27d558be35c9d40a0aa8211aec67 Mon Sep 17 00:00:00 2001 From: alyssaf16 Date: Thu, 6 Jun 2024 22:20:24 -0400 Subject: Flashcard changes - menu added --- src/client/views/nodes/ComparisonBox.scss | 20 +---- src/client/views/nodes/ComparisonBox.tsx | 99 +++++++++++++++++----- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/FieldView.tsx | 1 + .../nodes/formattedText/FormattedTextBox.scss | 6 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 1 + 6 files changed, 87 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index f3dc0f68c..dc107b576 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -47,6 +47,7 @@ width: '91%'; height: '80%'; z-index: '-1'; + overscroll-behavior: contain; } .clip-div { @@ -241,24 +242,5 @@ } } } - - // .loading-circle { - // position: relative; - // width: 50px; - // height: 50px; - // border-radius: 50%; - // border: 3px solid #ccc; - // border-top-color: #333; - // animation: spin 1s infinite linear; - // } - - // @keyframes spin { - // 0% { - // transform: rotate(0deg); - // } - // 100% { - // transform: rotate(360deg); - // } - // } } } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 6d4af2f3e..f844892c5 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnFalse, returnNone, setupMoveUpEvents } from '../../../ClientUtils'; +import { returnFalse, returnNone, returnTrue, setupMoveUpEvents } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -27,6 +27,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox'; import ReactLoading from 'react-loading'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; +import { tickStep } from 'd3'; @observer export class ComparisonBox extends ViewBoxAnnotatableComponent() { @@ -37,7 +38,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() constructor(props: FieldViewProps) { super(props); makeObservable(this); - // this._isAnyChildContentActive = true; } @observable private _inputValue = ''; @@ -63,12 +63,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() @computed get clipHeight() { return NumCast(this.layoutDoc[this.clipHeightKey], 200); } + get revealOp() { + return this.layoutDoc[`_${this._props.fieldKey}_revealOp`]; + } get clipHeightKey() { return '_' + this._props.fieldKey + '_clipHeight'; } componentDidMount() { this._props.setContentViewBox?.(this); + reaction( + () => this._props.isSelected(), + selected => !selected && (this.childActive = false) + ); } protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => { this._disposers[disposerId]?.(); @@ -98,7 +105,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() emptyFunction, action((moveEv, doubleTap) => { if (doubleTap) { - this._isAnyChildContentActive = true; + this.childActive = true; if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); } @@ -106,7 +113,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() false, undefined, action(() => { - if (this._isAnyChildContentActive) return; + if (this.childActive) return; this._animating = 'all 200ms'; // on click, animate slider movement to the targetWidth this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth(); @@ -247,7 +254,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() hoverFlip = (side: string | undefined) => { if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side; }; - /** * Creates the button used to flip the flashcards. */ @@ -259,7 +265,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() className="formattedTextBox-alternateButton" onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => { - console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]); if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') { this.flipFlashcard(); @@ -271,6 +276,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() style={{ background: usepath === 'alternate' ? 'white' : 'black', color: usepath === 'alternate' ? 'black' : 'white', + display: 'inline-block', }}>
@@ -280,6 +286,37 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() ); } + @computed get flashcardMenu() { + return ( +
+ Flip to front side to use GPT
+ ) : ( +
Ask GPT to create an answer on the back side of the flashcard
+ ) + }> +
(!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? this.askGPT(GPTCallType.CHATCARD) : null)}> + +
+ + Hover to reveal
}> +
(this.revealOp === 'hover' ? (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip') : (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'))}> + +
+ + {this.overlayAlternateIcon} + + ); + } + + @action activateContent = () => { + this.childActive = true; + }; + @action handleRenderGPTClick = () => { // Call the GPT model and get the output this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate'; @@ -320,8 +357,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text); const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText; this._loading = true; + const doc = DocCast(this.dataDoc[this.props.fieldKey + '_0']); if (callType == GPTCallType.CHATCARD) { - DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = ''; + if (StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '') { + this._loading = false; + return; + } this.flipFlashcard(); } try { @@ -330,7 +371,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() console.error('GPT call failed'); return; } - this.animateRes(0, res, callType); + // this.animateRes(0, res, callType); + if (callType == GPTCallType.CHATCARD) { + DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res; + // this.flipFlashcard(); + } + if (callType == GPTCallType.QUIZ) this._outputValue = res; + // DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res; // this._outputValue = res; console.log(res); } catch (err) { @@ -341,10 +388,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() layoutWidth = () => NumCast(this.layoutDoc.width, 200); layoutHeight = () => NumCast(this.layoutDoc.height, 200); - specificMenu = (): void => { - const cm = ContextMenu.Instance; - cm.addItem({ description: 'Create an Answer on the Back', event: () => this.askGPT(GPTCallType.CHATCARD), icon: 'pencil' }); - }; + // specificMenu = (): void => { + // const cm = ContextMenu.Instance; + // cm.addItem({ description: 'Create an Answer on the Back', event: () => this.askGPT(GPTCallType.CHATCARD), icon: 'pencil' }); + // }; + @observable childActive = false; render() { const clearButton = (which: string) => ( @@ -378,12 +426,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2} NativeWidth={this.layoutWidth} NativeHeight={this.layoutHeight} - isContentActive={emptyFunction} + isContentActive={() => this.childActive} isDocumentActive={returnFalse} + dontSelect={returnTrue} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} - styleProvider={this._isAnyChildContentActive ? this._props.styleProvider : this.docStyleProvider} + styleProvider={this.childActive ? this._props.styleProvider : this.docStyleProvider} hideLinkButton - pointerEvents={this._isAnyChildContentActive ? undefined : returnNone} + pointerEvents={this.childActive ? undefined : returnNone} />
{layoutString ? null : clearButton(whichSlot)}
// placeholder image if doc is missingleft: `${NumCast(this.layoutDoc.width, 200) - 33}px` @@ -394,7 +443,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() ); }; const displayBox = (which: string, index: number, cover: number) => ( -
this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}> +
{ + this.registerSliding(e, cover); + this.activateContent(); + }} + ref={ele => this.createDropTarget(ele, which, index)}> {displayDoc(which)}
); @@ -431,6 +488,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() {this._loading ? ( @@ -457,7 +515,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() return (
{ this.hoverFlip('alternate'); @@ -473,7 +531,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent()
) : null} - {this.overlayAlternateIcon} + {this.flashcardMenu} + {/* {this.overlayAlternateIcon} */}
); } @@ -491,7 +550,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() left: `calc(${this.clipWidth + '%'} - 0.5px)`, cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined, }} - onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ + onPointerDown={e => !this.childActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ >
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a25249eac..2f3357791 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -503,6 +503,7 @@ export class DocumentViewInternal extends DocComponent { + if (this._props.dontSelect?.()) return; if (e && this.layoutDoc.layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); @@ -1378,7 +1379,7 @@ export class DocumentView extends DocComponent() { screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { - DocumentView.SelectView(this, extendSelection); + if (!this._props.dontSelect?.()) DocumentView.SelectView(this, extendSelection); if (focusSelection) { DocumentView.showDocument(this.Document, { willZoomCentered: true, diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 818d26956..138f00492 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,6 +50,7 @@ export interface FieldViewSharedProps { PanelHeight: () => number; isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events isContentActive: () => boolean | undefined; // whether document contents should handle pointer events + dontSelect: () => boolean | undefined; childFilters: () => string[]; childFiltersByRanges: () => string[]; styleProvider: Opt; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 8ac8c2c5f..54643b4a5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -89,14 +89,14 @@ audiotag:hover { right: 0; bottom: 0; width: 15; - height: 15; + height: 22; cursor: default; } .formattedTextBox-flip { align-items: center; position: absolute; - right: 3px; - bottom: 1px; + right: 2px; + bottom: 4px; } .formattedTextBox-outer { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 82133a06e..3e2befb5f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -816,6 +816,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent BoolCast(anchor.followLinkToggle); specificContextMenu = (e: React.MouseEvent): void => { + if (this._props.dontSelect?.()) return; const cm = ContextMenu.Instance; let target = e.target as any; // hrefs are stored on the database of the node that wraps the hyerlink -- cgit v1.2.3-70-g09d2