aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ComparisonBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/ComparisonBox.tsx')
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx172
1 files changed, 71 insertions, 101 deletions
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 3d33ff862..3e1c415d6 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -25,52 +25,39 @@ import { DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import ReactLoading from 'react-loading';
-import { ContextMenu } from '../ContextMenu';
-import { ContextMenuProps } from '../ContextMenuItem';
-import { tickStep } from 'd3';
-import { CollectionCarouselView } from '../collections/CollectionCarouselView';
+enum RevealOp {
+ Hover = 'hover',
+ Flip = 'flip',
+}
+enum UsePath {
+ Alternate = 'alternate',
+}
@observer
export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ComparisonBox, fieldKey);
}
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
+ private _closeRef = React.createRef<HTMLDivElement>();
+ @observable _inputValue = '';
+ @observable _outputValue = '';
+ @observable _loading = false;
+ @observable _errorMessage = '';
+ @observable _outputMessage = '';
+ @observable _animating = '';
+ @observable private _isEmpty = false;
+ @observable _yRelativeToTop: boolean = true;
+
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
-
- @observable private _inputValue = '';
- @observable private _outputValue = '';
- @observable private _loading = false;
- @observable private _isEmpty = false;
- @observable _yRelativeToTop: boolean = true;
-
@action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
this._inputValue = e.target.value;
console.log(this._inputValue);
};
- @observable _animating = '';
-
- @computed get clipWidth() {
- return NumCast(this.layoutDoc[this.clipWidthKey], 50);
- }
- get clipWidthKey() {
- return '_' + this._props.fieldKey + '_clipWidth';
- }
-
- @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(
@@ -78,6 +65,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
selected => !selected && (this.childActive = false) // what it should update to
);
}
+
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
this._disposers[disposerId]?.();
if (ele) {
@@ -85,7 +73,20 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
}
};
- private internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+ @computed get useAlternate() { return this.layoutDoc[`_${this.fieldKey}_usePath`] === UsePath.Alternate; } // prettier-ignore
+ @computed get revealOp() { return this.layoutDoc[`_${this.fieldKey}_revealOp`] as Opt<RevealOp>; } // prettier-ignore
+ @computed get clipWidth() { return NumCast(this.layoutDoc[`_${this.fieldKey}_clipWidth`], 50); } // prettier-ignore
+ set useAlternate(alt: boolean) { this.layoutDoc[`_${this.fieldKey}_usePath`] = alt ? UsePath.Alternate : undefined; } // prettier-ignore
+ set revealOp(op: Opt<RevealOp>){ this.layoutDoc[`_${this.fieldKey}_revealOp`] = op; } // prettier-ignore
+ set clipWidth(width: number) { this.layoutDoc[`_${this.fieldKey}_clipWidth`] = width; } // prettier-ignore
+
+ animateClipWidth = action((clipWidth: number, duration = 200 /* ms */) => {
+ this._animating = `all ${duration}ms`; // turn on clip animation transition, then turn it off at end of animation
+ setTimeout(action(() => { this._animating = ''; }), duration); // prettier-ignore
+ this.clipWidth = clipWidth;
+ });
+
+ internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
if (dropEvent.complete.docDragData) {
const { droppedDocuments } = dropEvent.complete.docDragData;
const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocuments, this.Document, (doc: Doc | Doc[]) => this.addDoc(toList(doc).lastElement(), fieldKey));
@@ -98,51 +99,34 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return undefined;
}, 'internal drop');
- private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
+ registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
if (e.button !== 2) {
setupMoveUpEvents(
this,
e,
this.onPointerMove,
emptyFunction,
- action((moveEv, doubleTap) => {
+ action((clickEv, doubleTap) => {
if (doubleTap) {
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);
+ // DocumentView.addViewRenderedCb(DocCast(this.dataDoc[this.fieldKey + '_1']), dv => {
+ // dv?.select(false);
+ // });
}
}),
- false,
+ true,
undefined,
- action(() => {
- 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();
- // this.layoutDoc[this.clipHeightKey] = (targetWidth * 100) / this._props.PanelHeight();
-
- setTimeout(
- action(() => {
- this._animating = '';
- }),
- 200
- );
- })
+ () => !this._isAnyChildContentActive && this.animateClipWidth((targetWidth * 100) / this._props.PanelWidth())
);
}
};
- // private onClick(e: React.PointerEvent<HTMLDivElement>) {
- // setupMoveUpEvents(
- // this, e, this.onPointerMOve, emptyFunction(), () => {this._isAnyChildContentActive = true;}, emptyFunction(), emptyFunction()
- // )
- // }
-
- @action
- private onPointerMove = ({ movementX }: PointerEvent) => {
+ onPointerMove = ({ movementX }: PointerEvent) => {
const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth();
- if (width && width > 5 && width < this._props.PanelWidth()) {
- this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth();
+ if (width > 5 && width < this._props.PanelWidth()) {
+ this.clipWidth = (width * 100) / this._props.PanelWidth();
}
return false;
};
@@ -206,8 +190,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
};
docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
- if (property === StyleProp.PointerEvents) return 'none';
- return this._props.styleProvider?.(doc, props, property);
+ switch (property) {
+ case StyleProp.PointerEvents: return 'none';
+ default: return this._props.styleProvider?.(doc, props, property);
+ } // prettier-ignore
};
moveDoc1 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true);
moveDoc2 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true);
@@ -246,8 +232,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return layoutTemplateString;
};
- _closeRef = React.createRef<HTMLDivElement>();
-
createFlashcardPile(collectionArr: Doc[], gpt: boolean) {
const newCol = Docs.Create.CarouselDocument(collectionArr, {
_width: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 250) + 50,
@@ -287,28 +271,26 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
* Flips a flashcard to the alternate side for the user to view.
*/
flipFlashcard = () => {
- const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : undefined;
+ this.useAlternate = !this.useAlternate;
};
/**
* Changes the view option to hover for a flashcard.
*/
- hoverFlip = (side: string | undefined) => {
- if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side;
+ hoverFlip = (alternate: boolean) => {
+ if (this.revealOp === RevealOp.Hover) this.useAlternate = alternate;
};
/**
* Creates the button used to flip the flashcards.
*/
@computed get overlayAlternateIcon() {
- const usepath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
return (
<Tooltip title={<div className="dash-tooltip">flip</div>}>
<div
className="formattedTextBox-alternateButton"
onPointerDown={e =>
setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => {
- if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') {
+ if (!this.revealOp || this.revealOp === RevealOp.Flip) {
this.flipFlashcard();
// console.log('Print Front of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text ?? ''));
@@ -317,9 +299,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
})
}
style={{
- background: this.revealOp === 'hover' ? 'gray' : usepath === 'alternate' ? 'white' : 'black',
- color: this.revealOp === 'hover' ? 'black' : usepath === 'alternate' ? 'black' : 'white',
- display: 'inline-block',
+ background: this.useAlternate ? 'white' : 'black',
+ color: this.useAlternate ? 'black' : 'white',
}}>
<div key="alternate" className="formattedTextBox-flip">
<FontAwesomeIcon icon="turn-up" size="1x" />
@@ -333,13 +314,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return (
<div>
<Tooltip
- title={
- 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 based on your question on the front</div>
- )
- }>
+ title={this.useAlternate ? <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 based on your question on the front</div>}>
<div style={{ position: 'absolute', bottom: '3px', right: '50px', cursor: 'pointer' }} onPointerDown={e => (!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? this.askGPT(GPTCallType.CHATCARD) : null)}>
<FontAwesomeIcon icon="lightbulb" size="xl" />
</div>
@@ -360,7 +335,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
)}
<Tooltip title={<div className="dash-tooltip">Hover to reveal</div>}>
<div style={{ position: 'absolute', bottom: '3px', right: '25px', cursor: 'pointer' }} onClick={e => this.handleHover()}>
- <FontAwesomeIcon color={this.revealOp === 'hover' ? 'blue' : 'black'} icon="hand-point-up" size="xl" />
+ <FontAwesomeIcon color={this.revealOp === RevealOp.Hover ? 'blue' : 'black'} icon="hand-point-up" size="xl" />
</div>
</Tooltip>
{/* <Tooltip title={<div className="dash-tooltip">Remove this side of the flashcard</div>}>
@@ -381,25 +356,24 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
@action handleRenderGPTClick = () => {
// Call the GPT model and get the output
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate';
+ this.useAlternate = true;
this._outputValue = '';
if (this._inputValue) this.askGPT(GPTCallType.QUIZ);
};
@action handleHover = () => {
- if (this.revealOp === 'hover') {
- this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip';
+ if (this.revealOp === RevealOp.Hover) {
+ this.revealOp = RevealOp.Flip;
this.Document.forceActive = false;
} else {
- this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover';
+ this.revealOp = 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;
+ this.useAlternate = false;
};
animateRes = (resIndex: number, newText: string, callType: GPTCallType) => {
@@ -537,7 +511,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
if (this.Document._layout_isFlashcard) {
- const side = this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 1 : 0;
+ const side = this.useAlternate ? 1 : 0;
// add text box to each side when comparison box is first created
// (!this.dataDoc[this.fieldKey + '_0'] && this.dataDoc[this._props.fieldKey + '_0'] !== 'empty')
@@ -580,11 +554,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
<p style={{ display: text === '' ? 'flex' : 'none', color: 'white', marginLeft: '10px' }}>Return to all flashcards and add text to both sides. </p>
<div className="input-box">
<textarea
- value={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? this._outputValue : this._inputValue}
+ value={this.useAlternate ? this._outputValue : this._inputValue}
onChange={this.handleInputChange}
onScroll={e => e.stopPropagation()}
- placeholder={!this.layoutDoc[`_${this._props.fieldKey}_usePath`] ? 'Enter a response for GPT to evaluate.' : ''}
- readOnly={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate'}></textarea>
+ placeholder={!this.useAlternate ? 'Enter a response for GPT to evaluate.' : ''}
+ readOnly={this.useAlternate}
+ />
{this._loading ? (
<div className="loading-spinner" style={{ position: 'absolute' }}>
@@ -592,12 +567,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
</div>
) : null}
</div>
- <div className="submit-button" style={{ overflow: 'hidden', display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'none' : 'flex' }}>
+ <div className="submit-button" style={{ overflow: 'hidden', display: this.useAlternate ? 'none' : 'flex' }}>
<button type="button" onClick={this.handleRenderGPTClick} style={{ borderRadius: '2px', marginBottom: '3px' }}>
Submit
</button>
</div>
- <div className="submit-button" style={{ overflow: 'hidden', marginBottom: '2px', display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'flex' : 'none' }}>
+ <div className="submit-button" style={{ overflow: 'hidden', marginBottom: '2px', display: this.useAlternate ? 'flex' : 'none' }}>
<button type="button" onClick={this.handleRenderClick} style={{ borderRadius: '2px' }}>
Redo the Question
</button>
@@ -613,15 +588,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */
// onContextMenu={this.specificMenu}
style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden' }}
- onMouseEnter={() => {
- this.hoverFlip('alternate');
- }}
- onMouseLeave={() => {
- this.hoverFlip(undefined);
- }}
- // onPointerUp={() => (this._isAnyChildContentActive = true)}
- >
- {!this.layoutDoc[`_${this._props.fieldKey}_usePath`] && StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '' && !this.childActive ? <p className="explain">Enter text in the flashcard. </p> : null}
+ onMouseEnter={() => this.hoverFlip(true)}
+ onMouseLeave={() => this.hoverFlip(false)}>
+ {!this.useAlternate && StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '' && !this.childActive ? <p className="comparisonBox-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' }}>
@@ -645,9 +614,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
className="slide-bar"
style={{
left: `calc(${this.clipWidth + '%'} - 0.5px)`,
+ transition: this._animating,
cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined,
}}
- onPointerDown={e => !this.childActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
+ onPointerDown={e => this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
>
<div className="slide-handle" />
</div>