aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/Import & Export/ImageUtils.ts1
-rw-r--r--src/client/views/collections/CollectionCarouselView.scss95
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx176
-rw-r--r--src/client/views/collections/TabDocView.tsx1
-rw-r--r--src/client/views/nodes/LabelBox.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
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);