From 972839216c14baa5c9eaf80e1fb2fb2694bbb72c Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 8 Oct 2024 22:51:46 -0400 Subject: modified how buttons are laid out on carousel and comparison views so that text boxes can reflow around them. extracted flashcard pratice into its own component and applied it to carousel3D and carousel --- src/client/views/nodes/ComparisonBox.scss | 15 ++++ src/client/views/nodes/ComparisonBox.tsx | 92 +++++++++++++++------- src/client/views/nodes/FieldView.tsx | 1 + .../nodes/formattedText/FormattedTextBox.scss | 6 -- .../views/nodes/formattedText/FormattedTextBox.tsx | 16 ++-- 5 files changed, 86 insertions(+), 44 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index b7307f3a3..8156c50f6 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -296,3 +296,18 @@ } } } +.comparisonBox-bottomMenu { + transform-origin: bottom right; + width: max-content; + justify-content: space-between; + height: max-content; + position: absolute; + bottom: 0; + right: 2; + flex-direction: row-reverse; + display: flex; + cursor: pointer; + .comparisonBox-button { + padding-right: 8px; + } +} diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index ef66c2b11..81e223028 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -68,7 +68,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() return ( flip}>
setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => { if (!this.revealOp || this.revealOp === 'flip') { @@ -81,42 +81,74 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() color: this.revealOp === 'hover' ? 'black' : this._frontSide ? 'black' : 'white', display: 'inline-block', }}> -
- -
+
); } + _sideBtnWidth = 30; + /** + * How much the content of the 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); + } + /** + * 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.25 * Math.min(NumCast(this.Document.width), NumCast(this.Document.height))); + 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); + } + @computed get flashcardMenu() { return ( -
- Flip to front side to use GPT
:
Ask GPT to create an answer on the back side of the flashcard based on your question on the front
}> -
(!this._frontSide ? this.findImageTags() : null)}> - -
- - {DocCast(this.Document.embedContainer)?.type_collection === CollectionViewType.Carousel ? null : ( -
- Create a flashcard pile
}> -
this.createFlashcardPile([this.Document], false)}> - -
- - Create new flashcard stack based on text}> -
this.gptFlashcardPile()}> - +
+ {this.overlayAlternateIcon} + {!this._props.isContentActive() ? null : ( + <> + {' '} + {!this._frontSide ? null : ( + { + !this._frontSide ? "Flip to front side to use GPT": + "Ask GPT to create an answer on the back side of the flashcard based on your question on the front"} +
// prettier-ignore + }> +
(this._frontSide ? this.findImageTags() : null)}> + +
+ + )} + {DocCast(this.Document.embedContainer)?.type_collection === CollectionViewType.Carousel ? null : ( + <> + Create a flashcard pile
}> +
this.createFlashcardPile([this.Document], false)}> + +
+
+ Create new flashcard stack based on text}> +
+ +
+
+ + )} + Hover to reveal}> +
+
- + )} - Hover to reveal}> -
this.handleHover()}> - -
-
); } @@ -478,7 +510,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() this._loading = false; return; } - this.flipFlashcard(); } try { console.log(queryText); @@ -655,6 +686,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() childActiveFunc = () => this._childActive; + contentScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); render() { const clearButton = (which: string) => ( remove}> @@ -687,6 +719,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2} NativeWidth={returnZero} NativeHeight={returnZero} + ScreenToLocalTransform={this.contentScreenToLocalXf} isContentActive={this.childActiveFunc} isDocumentActive={returnFalse} dontSelect={returnTrue} @@ -808,8 +841,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() ) : null} - {this._props.isContentActive() ? this.flashcardMenu : null} - {this.overlayAlternateIcon} + {this.flashcardMenu} ); } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 170966471..c81631baa 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -51,6 +51,7 @@ export interface FieldViewSharedProps { LayoutTemplate?: () => Opt; renderDepth: number; scriptContext?: unknown; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document + screenXPadding?: () => number; // padding in screen space coordinates (used by text box to reflow around UI buttons in carouselView) xPadding?: number; yPadding?: number; dontRegisterView?: boolean; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index d6f13d9ee..f1ae1151f 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -101,12 +101,6 @@ audiotag:hover { height: 22; cursor: default; } -.formattedTextBox-flip { - align-items: center; - position: absolute; - right: 2px; - bottom: 4px; -} .formattedTextBox-outer { position: relative; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c89737e1e..93153b453 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -763,10 +763,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const localDelta = this._props - .ScreenToLocalTransform() - .scale(this._props.NativeDimScaling?.() || 1) - .transformDirection(delta[0], delta[1]); + const localDelta = this.DocumentView?.().screenToViewTransform().transformDirection(delta[0], delta[1]) ?? delta; const sidebarWidth = (NumCast(this.layoutDoc._width) * Number(this.layout_sidebarWidthPercent.replace('%', ''))) / 100; const width = NumCast(this.layoutDoc._width) + localDelta[0]; this.layoutDoc._layout_sidebarWidthPercent = Math.max(0, (sidebarWidth + localDelta[0]) / width) * 100 + '%'; @@ -1264,7 +1261,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Doc.RecordingEvent, this.breakupDictation); this._disposers.layout_autoHeight = reaction( - () => ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize, css: this.Document[DocCss] }), + () => ({ autoHeight: this.layout_autoHeight, fontSize: this.fontSize, css: this.Document[DocCss], xMargin: this.Document.xMargin, yMargin: this.Document.yMargin }), autoHeight => setTimeout(() => autoHeight && this.tryUpdateScrollHeight()) ); this._disposers.highlights = reaction( @@ -2088,8 +2085,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent !this._props.isContentActive() && FormattedTextBoxComment.textBox === this && FormattedTextBoxComment.Hide); - const paddingX = Math.max(this._props.xPadding ?? 0, NumCast(this.layoutDoc._xMargin)); - const paddingY = Math.max(this._props.yPadding ?? 0, NumCast(this.layoutDoc._yMargin)); + + const scrSize = (which: number, view = this._props.docViewPath().slice(-which)[0]) => + [view._props.PanelWidth() / view.screenToLocalScale(), view._props.PanelHeight() / view.screenToLocalScale()]; // prettier-ignore + const scrMargin = [Math.max(0, (scrSize(2)[0] - scrSize(1)[0]) / 2), Math.max(0, (scrSize(2)[1] - scrSize(1)[1]) / 2)]; + const paddingX = Math.max(NumCast(this.layoutDoc._xMargin), this._props.xPadding ?? 0, 0, ((this._props.screenXPadding?.() ?? 0) - scrMargin[0]) * this.ScreenToLocalBoxXf().Scale); + const paddingY = Math.max(NumCast(this.layoutDoc._yMargin), 0, ((this._props.yPadding ?? 0) - scrMargin[1]) * this.ScreenToLocalBoxXf().Scale); const styleFromLayout = styleFromLayoutString(this.Document, this._props, scale); // this converts any expressions in the format string to style props. e.g., return styleFromLayout?.height === '0px' ? null : (