diff options
Diffstat (limited to 'src/client/views/collections/CollectionCarousel3DView.tsx')
| -rw-r--r-- | src/client/views/collections/CollectionCarousel3DView.tsx | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index c5da8e037..1583f0e0c 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { computed, makeObservable } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { returnZero } from '../../../ClientUtils'; @@ -9,12 +9,13 @@ import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; +import { Transform } from '../../util/Transform'; import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; import './CollectionCarousel3DView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; -import { Transform } from '../../util/Transform'; +import { FlashcardPracticeUI } from './FlashcardPracticeUI'; // eslint-disable-next-line @typescript-eslint/no-require-imports const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); @@ -24,6 +25,9 @@ export class CollectionCarousel3DView extends CollectionSubView() { @computed get scrollSpeed() { return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; // default scroll speed } + _sideBtnWidth = 35; + @observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined; + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); @@ -43,7 +47,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { }; @computed get carouselItems() { - return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK); + return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK).filter(pair => !this._filterFunc?.(pair.layout)); } centerScale = Number(CAROUSEL3D_CENTER_SCALE); @@ -53,22 +57,17 @@ export class CollectionCarousel3DView extends CollectionSubView() { onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); isChildContentActive = () => !!this.isContentActive(); + contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); childScreenLeftToLocal = () => - this._props - .ScreenToLocalTransform() - .scale(this._props.NativeDimScaling?.() || 1) + this.contentScreenToLocalXf() .translate(-(this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) .scale(1 / this.sideScale); childScreenRightToLocal = () => - this._props - .ScreenToLocalTransform() - .scale(this._props.NativeDimScaling?.() || 1) + this.contentScreenToLocalXf() .translate(-2 * this.panelWidth() - (this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) .scale(1 / this.sideScale); childCenterScreenToLocal = () => - this._props - .ScreenToLocalTransform() - .scale(this._props.NativeDimScaling?.() || 1) + this.contentScreenToLocalXf() .translate( -this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, // Focused Doc is shifted right by 1/3 panel width then left by increased size percent of center * 1/2 * panel width / 3 -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2 @@ -119,7 +118,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { changeSlide = (direction: number) => { DocumentView.DeselectAll(); - this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) + direction + this.carouselItems.length) % this.carouselItems.length; + this.layoutDoc._carousel_index = !this.curDoc() ? 0 : (NumCast(this.layoutDoc._carousel_index) + direction + this.carouselItems.length) % (this.carouselItems.length || 1); }; onArrowClick = (direction: number) => { @@ -192,6 +191,35 @@ export class CollectionCarousel3DView extends CollectionSubView() { return this.panelWidth() * (1 - index); } + /** + * 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 + screenXPadding = () => (this.uiBtnScaleTransform * this._sideBtnWidth - NumCast(this.layoutDoc.xMargin)) / this._props.ScreenToLocalTransform().Scale; + + docViewProps = () => ({ + ...this._props, // + isDocumentActive: this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive, + isContentActive: this.isChildContentActive, + ScreenToLocalTransform: this.contentScreenToLocalXf, + }); + carouselItemsFunc = () => this.carouselItems.map(pair => pair.layout); + @action setFilterFunc = (func?: (doc: Doc) => boolean) => { this._filterFunc = func; }; // prettier-ignore + answered = (correct: boolean) => (!correct || !this.curDoc()) && this.changeSlide(1); + curDoc = () => this.carouselItems[NumCast(this.layoutDoc._carousel_index)]?.layout; + render() { return ( <div @@ -206,6 +234,22 @@ export class CollectionCarousel3DView extends CollectionSubView() { </div> {this.buttons} <div className="dot-bar">{this.dots}</div> + <FlashcardPracticeUI + setFilterFunc={this.setFilterFunc} + fieldKey={this.fieldKey} + sideBtnWidth={this._sideBtnWidth} + carouselItems={this.carouselItemsFunc} + childDocs={this.childDocs} + advance={this.answered} + curDoc={this.curDoc} + practiceBtnOffset={this._sideBtnWidth * 4} + layoutDoc={this.layoutDoc} + maxWidgetScale={this.maxWidgetScale} + uiBtnScaleTransform={this.uiBtnScaleTransform} + ScreenToLocalBoxXf={this.ScreenToLocalBoxXf} + renderDepth={this._props.renderDepth} + docViewProps={this.docViewProps} + /> </div> ); } |
