aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionCardDeckView.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-10-08 23:43:43 -0400
committerbobzel <zzzman@gmail.com>2024-10-08 23:43:43 -0400
commitc97d849a56d4642d9eb750beccb748b7d8ac15bd (patch)
tree6c154ba800f355df30d4590f727023927533eaab /src/client/views/collections/CollectionCardDeckView.tsx
parentca67414c9da685070c1143ce3b771edda2fdc191 (diff)
extended flashcard UI to cardDecks
Diffstat (limited to 'src/client/views/collections/CollectionCardDeckView.tsx')
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx66
1 files changed, 59 insertions, 7 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 5d39dc1ca..7272b22e2 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -22,6 +22,7 @@ import { DocumentView } from '../nodes/DocumentView';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { FlashcardPracticeUI } from './FlashcardPracticeUI';
enum cardSortings {
Time = 'time',
@@ -46,6 +47,8 @@ export class CollectionCardView extends CollectionSubView() {
private _textToDoc = new Map<string, Doc>();
private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
+ _sideBtnWidth = 35;
+ @observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined;
@observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
@@ -117,7 +120,7 @@ export class CollectionCardView extends CollectionSubView() {
* The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's)
*/
@computed get childDocsWithoutLinks() {
- return this.childDocs.filter(l => !l.layout_isSvg);
+ return this.childDocs.filter(l => !l.layout_isSvg).filter(doc => !this._filterFunc?.(doc));
}
/**
@@ -565,11 +568,7 @@ export class CollectionCardView extends CollectionSubView() {
*/
@computed get renderCards() {
if (!this.childDocsWithoutLinks.length) {
- return (
- <span className="no-card-span" style={{ width: ` ${this._props.PanelWidth()}px`, height: ` ${this._props.PanelHeight()}px` }}>
- Sorry ! There are no cards in this group
- </span>
- );
+ return null;
}
// Map sorted documents to their rendered components
@@ -611,6 +610,34 @@ export class CollectionCardView extends CollectionSubView() {
});
}
+ contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1);
+ docViewProps = () => ({
+ ...this._props, //
+ isDocumentActive: this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive,
+ isContentActive: this.isChildContentActive,
+ ScreenToLocalTransform: this.contentScreenToLocalXf,
+ });
+ carouselItemsFunc = () => this.childDocsWithoutLinks;
+ @action setFilterFunc = (func?: (doc: Doc) => boolean) => { this._filterFunc = func; }; // prettier-ignore
+ answered = (correct: boolean) => !correct || !this.curDoc();
+ curDoc = () => this.sortedDocs.find(doc => DocumentView.getDocumentView(doc, this.DocumentView?.())?.IsSelected);
+ /**
+ * How much the content of the carousel view is being scaled based on its nesting and its fit-to-width settings
+ */
+ @computed get contentScaling() { return this.ScreenToLocalBoxXf().Scale * (this._props.NativeDimScaling?.() ?? 1); } // prettier-ignore
+
+ /**
+ * The maximum size a UI widget can be scaled so that it won't be bigger in screen pixels than its normal 35 pixel size.
+ */
+ @computed get maxWidgetScale() {
+ const maxWidgetSize = Math.min(this._sideBtnWidth * this.contentScaling, 0.1 * NumCast(this.layoutDoc.width, 1));
+ return Math.max(maxWidgetSize / this._sideBtnWidth, 1);
+ }
+ /**
+ * How much to reactively scale a UI element so that it is as big as it can be (up to its normal 35pixel size) without being too big for the Doc content
+ */
+ @computed get uiBtnScaleTransform() { return this.maxWidgetScale * Math.min(1, this.contentScaling); } // prettier-ignore
+
render() {
const isEmpty = this.childDocsWithoutLinks.length === 0;
@@ -629,10 +656,35 @@ export class CollectionCardView extends CollectionSubView() {
className="card-wrapper"
style={{
...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }),
- ...(!isEmpty && { height: `${100 * this.fitContentScale}%` }),
+ ...{ height: `${100 * (isEmpty ? 1 : this.fitContentScale)}%` },
+ ...{ width: `${100 * (isEmpty ? 1 : this.fitContentScale)}%` },
gridAutoRows: `${100 / this.numRows}%`,
}}>
{this.renderCards}
+ <div
+ className="collectionCardDeckView-flashcards"
+ style={{
+ transform: `scale(${this.fitContentScale || 1})`,
+ width: `${100 / (this.fitContentScale || 1)}%`,
+ height: `${100 / (this.fitContentScale || 1)}%`,
+ pointerEvents: !this.childDocsWithoutLinks.length ? 'unset' : undefined,
+ }}>
+ <FlashcardPracticeUI
+ setFilterFunc={this.setFilterFunc}
+ fieldKey={this.fieldKey}
+ sideBtnWidth={this._sideBtnWidth}
+ carouselItems={this.carouselItemsFunc}
+ childDocs={this.childDocs}
+ advance={this.answered}
+ curDoc={this.curDoc}
+ layoutDoc={this.layoutDoc}
+ maxWidgetScale={this.maxWidgetScale}
+ uiBtnScaleTransform={this.uiBtnScaleTransform}
+ ScreenToLocalBoxXf={this.ScreenToLocalBoxXf}
+ renderDepth={this._props.renderDepth}
+ docViewProps={this.docViewProps}
+ />
+ </div>
</div>
</div>
);