From c97d849a56d4642d9eb750beccb748b7d8ac15bd Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 8 Oct 2024 23:43:43 -0400
Subject: extended flashcard UI to cardDecks

---
 .../views/collections/CollectionCardDeckView.tsx   | 66 +++++++++++++++++++---
 1 file changed, 59 insertions(+), 7 deletions(-)

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

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>
         );
-- 
cgit v1.2.3-70-g09d2

