diff options
author | bobzel <zzzman@gmail.com> | 2024-10-08 03:30:21 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-10-08 03:30:21 -0400 |
commit | fc3e2b18b9dad38920e1cec5e58bf9fbd06f4aaf (patch) | |
tree | 9b75d7907ab39b76cb4637d6b8105c03c6f8cd12 | |
parent | a6c2194cdf3b6a35574526826a4053f650445e1b (diff) |
changed carousel view to resize ui buttons based on screen scaling and document dimensions. lint errors.
-rw-r--r-- | src/client/util/Import & Export/ImageUtils.ts | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.scss | 95 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.tsx | 176 | ||||
-rw-r--r-- | src/client/views/collections/TabDocView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/LabelBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 2 |
6 files changed, 142 insertions, 135 deletions
diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 266e05f08..8d4eefa7e 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-namespace */ import { ClientUtils } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss index af617254a..97952822e 100644 --- a/src/client/views/collections/CollectionCarouselView.scss +++ b/src/client/views/collections/CollectionCarouselView.scss @@ -40,7 +40,6 @@ } .carouselView-back, .carouselView-fwd, -.carouselView-star, .carouselView-remove, .carouselView-check, .carouselView-add { @@ -58,16 +57,14 @@ } } .carouselView-fwd { - top: 42.5%; - right: 20; + top: calc(50% - 15px); + right: 0; + transform-origin: right top; } .carouselView-back { - top: 42.5%; - left: 20; -} -.carouselView-star { - top: 0; + top: calc(50% - 15px); left: 0; + transform-origin: top left; } .carouselView-add { position: absolute; @@ -75,62 +72,60 @@ left: 0; } .carouselView-remove { - top: 80%; left: 52%; } .carouselView-check { - top: 80%; right: 52%; } -.carouselView-quiz { - position: relative; - display: flex; - height: 20px; - align-items: center; - margin: auto; - &:hover { - color: white; - } -} - -.carouselView-practice { - position: relative; - display: flex; - flex-direction: column; - height: 20px; - align-items: center; - margin: auto; - &:hover { - color: white; - } -} -.carouselView-starFilter { - position: relative; - display: flex; - height: 20px; - align-items: center; - &:hover { - color: white; - } -} - -.carouselView-practiceModes { - width: 100%; - height: 40px; - display: flex; - flex-direction: column; -} .carouselView-menu { position: absolute; flex-direction: column; align-items: center; display: flex; - top: 2px; - left: 2px; + top: 0px; + left: 0px; width: 30; + transform-origin: top left; border-radius: 5px; color: rgba(255, 255, 255, 0.5); background: rgba(0, 0, 0, 0.1); + .carouselView-practiceModes { + width: 100%; + display: flex; + flex-direction: column; + top: 0; + position: relative; + .carouselView-quiz { + position: relative; + display: flex; + height: 20px; + align-items: center; + margin: auto; + &:hover { + color: white; + } + & > svg { + height: 100%; + width: 100%; + } + } + + .carouselView-practice { + position: relative; + display: flex; + flex-direction: column; + height: 20px; + align-items: center; + margin: auto; + &:hover { + color: white; + } + & > svg { + height: 100%; + width: 100%; + } + } + } } .carouselView-back:hover, diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 936226baf..559dcfe2a 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -7,7 +7,6 @@ import { StopEvent, returnOne, returnZero } from '../../../ClientUtils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; -import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { StyleProp } from '../StyleProp'; import { TagItem } from '../TagsView'; @@ -36,6 +35,8 @@ export class CollectionCarouselView extends CollectionSubView() { get sideField() { return "_" + this.fieldKey + "_usePath"; } // prettier-ignore get starField() { return "#star"; } // prettier-ignore + _sideBtnWidth = 35; + _fadeTimer: NodeJS.Timeout | undefined; constructor(props: SubCollectionViewProps) { @@ -155,7 +156,11 @@ export class CollectionCarouselView extends CollectionSubView() { onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); onContentClick = () => ScriptCast(this.layoutDoc.onChildClick); captionWidth = () => this._props.PanelWidth() - 2 * this.marginX; - contentScreentToLocalXf = () => this._props.ScreenToLocalTransform().translate(-NumCast(this.layoutDoc.xMargin), -NumCast(this.layoutDoc.yMargin)); + contentScreenToLocalXf = () => + this._props + .ScreenToLocalTransform() + .translate(-NumCast(this.layoutDoc.xMargin), -NumCast(this.layoutDoc.yMargin)) + .scale(this._props.NativeDimScaling?.() || 1); contentPanelWidth = () => this._props.PanelWidth() - 2 * NumCast(this.layoutDoc.xMargin); @@ -168,9 +173,9 @@ export class CollectionCarouselView extends CollectionSubView() { ? false : undefined; - childScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); - renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => { + const screenScale = this.ScreenToLocalBoxXf().Scale; + const fitWidthScale = (NumCast(this.Document.width, 1) / NumCast(this.carouselItems[this.carouselIndex]?._width)) * (this._props.NativeDimScaling?.() || 1); return ( <DocumentView {...this._props} @@ -195,10 +200,10 @@ export class CollectionCarouselView extends CollectionSubView() { childFilters={this.childDocFilters} hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)} addDocument={this._props.addDocument} - ScreenToLocalTransform={this.contentScreentToLocalXf} + ScreenToLocalTransform={this.contentScreenToLocalXf} PanelWidth={this.contentPanelWidth} PanelHeight={this.contentPanelHeight} - xPadding={35} + xPadding={(this._sideBtnWidth * Math.min(this.maxWidgetScale, screenScale * screenScale)) / fitWidthScale} // padding shrinks based on screenScale to maintain its size, and then again by screenSize to get smaller /> ); }; @@ -259,46 +264,6 @@ export class CollectionCarouselView extends CollectionSubView() { ); } - addFlashcard() { - const newDoc = Docs.Create.ComparisonDocument('', { _layout_isFlashcard: true, _width: 300, _height: 300 }); - this.addDocument?.(newDoc); - } - - @computed get buttons() { - if (!this.carouselItems?.[this.carouselIndex]) return null; - return ( - <> - <div> - {/* <Tooltip title="add new flashcard to pile"> - <div key="add" className="carouselView-add" onClick={this.addFlashcard}> - <FontAwesomeIcon icon="plus" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" /> - </div> - </Tooltip> */} - </div> - <div key="back" className="carouselView-back" onClick={this.goback}> - <FontAwesomeIcon icon="chevron-left" size="2x" /> - </div> - <div key="fwd" className="carouselView-fwd" onClick={this.advance}> - <FontAwesomeIcon icon="chevron-right" size="2x" /> - </div> - {this.practiceMode == practiceMode.PRACTICE ? ( - <div> - <Tooltip title="Incorrect. View again later."> - <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}> - <FontAwesomeIcon icon="xmark" color="red" size="1x" /> - </div> - </Tooltip> - <Tooltip title="Correct"> - <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}> - <FontAwesomeIcon icon="check" color="green" size="1x" /> - </div> - </Tooltip> - </div> - ) : null} - </> - ); - } - togglePracticeMode = (mode: practiceMode) => this.setPracticeMode(mode === this.practiceMode ? undefined : mode); toggleFilterMode = () => Doc.setDocFilter(this.Document, 'tags', this.starField, 'check', true); setColor = (mode: practiceMode | cardMode, which: string) => (which === mode ? 'white' : 'light gray'); @@ -306,50 +271,75 @@ export class CollectionCarouselView extends CollectionSubView() { @computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } - filterHeight = () => NumCast(this.filterDoc?.height); + filterHeight = () => NumCast(this.filterDoc?.height) * Math.min(1, this.ScreenToLocalBoxXf().Scale); filterWidth = () => (!this.filterDoc ? 1 : (this.filterHeight() * NumCast(this.filterDoc._width)) / NumCast(this.filterDoc._height)); + + /** + * 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); + } + + /** + * 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.Document.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 `scale(${this.maxWidgetScale * Math.min(1, this.contentScaling)})`; + } @computed get menu() { const curDoc = this.carouselItems?.[this.carouselIndex]; return ( - <div className="carouselView-menu"> + <div className="carouselView-menu" style={{ height: this.filterHeight(), width: this.filterHeight(), transform: this.uiBtnScaleTransform }}> {!this.filterDoc ? null : ( - <div style={{ height: this.filterHeight(), width: this.filterHeight() }}> - <DocumentView - {...this._props} - Document={this.filterDoc} - TemplateDataDocument={undefined} - LayoutTemplate={this._props.childLayoutTemplate} - LayoutTemplateString={this._props.childLayoutString} - renderDepth={this._props.renderDepth + 1} - NativeWidth={returnZero} - NativeHeight={returnZero} - fitWidth={undefined} - showTags={false} - hideFilterStatus={true} - containerViewPath={this.childContainerViewPath} - setContentViewBox={undefined} - onDoubleClickScript={this.onContentDoubleClick} - onClickScript={this.onContentClick} - isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} - isContentActive={this.isChildContentActive} - hideCaptions={true} - childFilters={this.childDocFilters} - hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)} - addDocument={this._props.addDocument} - ScreenToLocalTransform={this.contentScreentToLocalXf} - PanelWidth={this.filterWidth} - PanelHeight={this.filterHeight} - /> - </div> + <DocumentView + {...this._props} + Document={this.filterDoc} + TemplateDataDocument={undefined} + LayoutTemplate={this._props.childLayoutTemplate} + LayoutTemplateString={this._props.childLayoutString} + renderDepth={this._props.renderDepth + 1} + NativeWidth={returnZero} + NativeHeight={returnZero} + fitWidth={undefined} + showTags={false} + hideFilterStatus={true} + containerViewPath={this.childContainerViewPath} + setContentViewBox={undefined} + onDoubleClickScript={this.onContentDoubleClick} + onClickScript={this.onContentClick} + isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} + isContentActive={this.isChildContentActive} + hideCaptions={true} + childFilters={this.childDocFilters} + hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)} + addDocument={this._props.addDocument} + ScreenToLocalTransform={this.contentScreenToLocalXf} + PanelWidth={this.filterWidth} + PanelHeight={this.filterHeight} + /> )} - <div className="carouselView-practiceModes" style={{ display: BoolCast(curDoc?._layout_isFlashcard) ? undefined : 'none' }}> + <div + className="carouselView-practiceModes" + style={{ + transformOrigin: `0px ${-this.filterHeight()}px`, + transform: `scale(${Math.max(1, 1 / this.ScreenToLocalBoxXf().Scale / this.maxWidgetScale)})`, + display: BoolCast(curDoc?._layout_isFlashcard) ? undefined : 'none', + }}> <Tooltip title="Practice flashcards using GPT"> - <div key="back" className="carouselView-quiz" onClick={() => this.togglePracticeMode(practiceMode.QUIZ)}> + <div key="back" className="carouselView-quiz" style={{ width: this.filterWidth(), height: this.filterHeight() }} onClick={() => this.togglePracticeMode(practiceMode.QUIZ)}> <FontAwesomeIcon icon="file-pen" color={this.setColor(practiceMode.QUIZ, StrCast(this.practiceMode))} size="1x" /> </div> </Tooltip> <Tooltip title={this.practiceMode === practiceMode.PRACTICE ? 'Exit practice mode' : 'Practice flashcards manually'}> - <div key="back" className="carouselView-practice" onClick={() => this.togglePracticeMode(practiceMode.PRACTICE)}> + <div key="back" className="carouselView-practice" style={{ width: this.filterWidth(), height: this.filterHeight() }} onClick={() => this.togglePracticeMode(practiceMode.PRACTICE)}> <FontAwesomeIcon icon="check" color={this.setColor(practiceMode.PRACTICE, StrCast(this.practiceMode))} size="1x" /> </div> </Tooltip> @@ -357,6 +347,32 @@ export class CollectionCarouselView extends CollectionSubView() { </div> ); } + @computed get buttons() { + return ( + <> + <div key="back" className="carouselView-back" style={{ transform: this.uiBtnScaleTransform }} onClick={this.goback}> + <FontAwesomeIcon icon="chevron-left" size="2x" /> + </div> + <div key="fwd" className="carouselView-fwd" style={{ transform: this.uiBtnScaleTransform }} onClick={this.advance}> + <FontAwesomeIcon icon="chevron-right" size="2x" /> + </div> + {this.practiceMode == practiceMode.PRACTICE ? ( + <div style={{ transform: this.uiBtnScaleTransform, bottom: `${this._sideBtnWidth}px`, height: `${this._sideBtnWidth}px`, position: 'absolute', width: `100%` }}> + <Tooltip title="Incorrect. View again later."> + <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}> + <FontAwesomeIcon icon="xmark" color="red" size="1x" /> + </div> + </Tooltip> + <Tooltip title="Correct"> + <div key="check" className="carouselView-check" onClick={e => this.setPracticeVal(e, practiceVal.CORRECT)}> + <FontAwesomeIcon icon="check" color="green" size="1x" /> + </div> + </Tooltip> + </div> + ) : null} + </> + ); + } render() { return ( @@ -388,7 +404,7 @@ export class CollectionCarouselView extends CollectionSubView() { )} </div> {!this.Document._chromeHidden ? this.menu : null} - {!this.Document._chromeHidden ? this.buttons : null} + {!this.Document._chromeHidden && this.carouselItems?.[this.carouselIndex] ? this.buttons : null} </div> ); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f56ea9d76..5bfdee1f5 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -478,7 +478,6 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> { componentDidMount() { new ResizeObserver( action(entries => { - // eslint-disable-next-line no-restricted-syntax for (const entry of entries) { this._panelWidth = entry.contentRect.width; this._panelHeight = entry.contentRect.height; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 696ba5697..94a9541f2 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -138,7 +138,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() { onBlur={() => { this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? ''; }} - contentEditable={this._props.onClickScript?.() ? false : true} + contentEditable={this._props.onClickScript?.() ? undefined : true} ref={r => { this._divRef = r; this.fitTextToBox(r); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index fc74a480e..5743b17c6 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -498,8 +498,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { // } this._loading = true; try { - if (this._selectionText === '') { - } const res = await gptAPICall(queryText, GPTCallType.FLASHCARD); console.log(res); |