aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/FlashcardPracticeUI.tsx
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2024-10-30 19:39:46 -0400
committereleanor-park <eleanor_park@brown.edu>2024-10-30 19:39:46 -0400
commitc11c760db62f78a07b624b98b209e6ee86036c8e (patch)
treec9587b50042a5115373e91ba8ecf9b76913cd321 /src/client/views/collections/FlashcardPracticeUI.tsx
parentb5944e87f9d4f3149161de4de0d76db486461c76 (diff)
parent4c768162e0436115a05b9c8b0e4d837d626d45ba (diff)
Merge branch 'master' into eleanor-gptdraw
Diffstat (limited to 'src/client/views/collections/FlashcardPracticeUI.tsx')
-rw-r--r--src/client/views/collections/FlashcardPracticeUI.tsx59
1 files changed, 36 insertions, 23 deletions
diff --git a/src/client/views/collections/FlashcardPracticeUI.tsx b/src/client/views/collections/FlashcardPracticeUI.tsx
index 7697d308b..c298bff22 100644
--- a/src/client/views/collections/FlashcardPracticeUI.tsx
+++ b/src/client/views/collections/FlashcardPracticeUI.tsx
@@ -1,19 +1,19 @@
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
+import { MultiToggle, Type } from 'browndash-components';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { returnFalse, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
+import { emptyFunction } from '../../../Utils';
import { Doc, DocListCast } from '../../../fields/Doc';
import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
+import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import './FlashcardPracticeUI.scss';
-import { IconButton, MultiToggle, Type } from 'browndash-components';
-import { SnappingManager } from '../../util/SnappingManager';
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { emptyFunction } from '../../../Utils';
export enum practiceMode {
PRACTICE = 'practice',
@@ -24,6 +24,11 @@ enum practiceVal {
CORRECT = 'correct',
}
+export enum flashcardRevealOp {
+ FLIP = 'flip',
+ SLIDE = 'slide',
+}
+
interface PracticeUIProps {
fieldKey: string;
layoutDoc: Doc;
@@ -53,7 +58,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
get practiceField() { return this._props.fieldKey + "_practice"; } // prettier-ignore
@computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } // prettier-ignore
- @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore
+ @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._flashcardType) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore
btnHeight = () => NumCast(this.filterDoc?.height) * Math.min(1, this._props.ScreenToLocalBoxXf().Scale);
btnWidth = () => (!this.filterDoc ? 1 : (this.btnHeight() * NumCast(this.filterDoc._width)) / NumCast(this.filterDoc._height));
@@ -99,8 +104,8 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
const setPracticeVal = (e: React.MouseEvent, val: string) => {
e.stopPropagation();
const curDoc = this._props.curDoc();
- curDoc && (curDoc[this.practiceField] = val);
this._props.advance?.(val === practiceVal.CORRECT);
+ curDoc && (curDoc[this.practiceField] = val);
};
return this.practiceMode == practiceMode.PRACTICE && this._props.curDoc() ? (
@@ -122,11 +127,11 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
const setColor = (mode: practiceMode) => (StrCast(this.practiceMode) === mode ? 'white' : 'lightgray');
const togglePracticeMode = (mode: practiceMode) => this.setPracticeMode(mode === this.practiceMode ? undefined : mode);
- return !this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? null : (
+ return !this._props.allChildDocs().some(doc => doc._layout_flashcardType) ? null : (
<div
className="FlashcardPracticeUI-practiceModes"
style={{
- transform: `translateY(${(this.btnHeight() * (1 - Math.min(1, this._props.uiBtnScaling))) / this._props.ScreenToLocalBoxXf().Scale}px)`,
+ transform: this._props.ScreenToLocalBoxXf().Scale >= 1 ? undefined : `translateY(${this.btnHeight() / this._props.ScreenToLocalBoxXf().Scale - this.btnHeight()}px)`,
}}>
<MultiToggle
tooltip="Practice flashcards one at a time"
@@ -148,28 +153,36 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
selectedItems={this.practiceMode}
onSelectionChange={(val: (string | number) | (string | number)[]) => togglePracticeMode(val as practiceMode)}
/>
- <IconButton
- tooltip="hover over card to reveal answer"
- type={Type.TERT}
- text={StrCast(this._props.layoutDoc.revealOp)}
+ <MultiToggle
+ tooltip="How to reveal flashcard answer"
+ type={Type.PRIM}
color={SnappingManager.userColor}
background={SnappingManager.userVariantColor}
- icon={<FontAwesomeIcon color={SnappingManager.userColor} icon={this._props.layoutDoc.revealOp === 'hover' ? 'hand-point-up' : 'question'} size="sm" />}
- label={StrCast(this._props.layoutDoc.revealOp)}
- onPointerDown={e =>
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => {
- this._props.layoutDoc.revealOp = this._props.layoutDoc.revealOp === 'hover' ? 'flip' : 'hover';
- this._props.layoutDoc.childDocumentsActive = this._props.layoutDoc.revealOp === 'hover' ? true : undefined;
- })
- }
+ multiSelect={false}
+ isToggle={false}
+ toggleStatus={!!this.practiceMode}
+ label={StrCast(this._props.layoutDoc.revealOp, flashcardRevealOp.FLIP)}
+ items={[
+ ['reveal', StrCast(this._props.layoutDoc.revealOp) === flashcardRevealOp.SLIDE ? 'expand' : 'question', StrCast(this._props.layoutDoc.revealOp, flashcardRevealOp.FLIP)],
+ ['trigger', this._props.layoutDoc.revealOp_hover ? 'hand-point-up' : 'hand', this._props.layoutDoc.revealOp_hover ? 'show on hover' : 'show on click'],
+ ].map(([item, icon, tooltip]) => ({
+ icon: <FontAwesomeIcon className={`FlashcardPracticeUI-${item}`} color={setColor(item as practiceMode)} icon={icon as IconProp} size="sm" />,
+ tooltip: tooltip,
+ val: item,
+ }))}
+ selectedItems={this._props.layoutDoc.revealOp_hover ? ['reveal', 'trigger'] : 'reveal'}
+ onSelectionChange={(val: (string | number) | (string | number)[]) => {
+ if (val === 'reveal') this._props.layoutDoc.revealOp = this._props.layoutDoc.revealOp === flashcardRevealOp.SLIDE ? flashcardRevealOp.FLIP : flashcardRevealOp.SLIDE;
+ if (val === 'trigger') this._props.layoutDoc.revealOp_hover = !this._props.layoutDoc.revealOp_hover;
+ }}
/>
</div>
);
}
- tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._layout_isFlashcard) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct
+ tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._flashcardType) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct
render() {
return (
- <>
+ <div className="FlashcardPracticeUI">
{this.emptyMessage}
{this.practiceButtons}
{this._props.layoutDoc._chromeHidden ? null : (
@@ -195,7 +208,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp
{this.practiceModesMenu}
</div>
)}
- </>
+ </div>
);
}
}