diff options
| author | bobzel <zzzman@gmail.com> | 2024-10-17 22:02:19 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-10-17 22:02:19 -0400 |
| commit | 4b231bbaf21939144ed8639d35f022834a406e59 (patch) | |
| tree | 7f675cbd90004742e14343921ca6237ea5d89066 /src/client/views/collections | |
| parent | dd93f5175064850c6c0e47f025cd7bbba1f23106 (diff) | |
changed layout_isFlashcard to layout_flashcardType with value of 'flashcard' to make it easy to search for flashcards. made carousel views able to focus() on a Doc. added ability for carousel and card views to have anchors so they can be pinned and linked. fixed pinning collections to save filters
Diffstat (limited to 'src/client/views/collections')
7 files changed, 116 insertions, 14 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index b86dad9d7..60305244c 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -9,7 +9,7 @@ import { Animation, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, DateCast, DocCast, NumCast, RTFCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, DateCast, DocCast, NumCast, RTFCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; import { URLField } from '../../../fields/URLField'; import { gptImageLabel } from '../../apis/gpt/GPT'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -25,6 +25,9 @@ import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import './CollectionCardDeckView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; +import { Docs } from '../../documents/Documents'; +import { PinDocView } from '../PinFuncs'; +import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere'; enum cardSortings { Time = 'time', @@ -604,6 +607,33 @@ export class CollectionCardView extends CollectionSubView() { index !== -1 && (this._curDoc = target); return undefined; }); + getAnchor = (addAsAnnotation: boolean) => { + const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document }); + anchor.config_curDoc = this.curDoc(); + PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + if (addAsAnnotation) { + // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered + Doc.AddDocToList(this.dataDoc, this._props.fieldKey + '_annotations', anchor); + } + return anchor; + }; + // pinned / linked anchor doc includes selected rows, graph titles, and graph colors + restoreView = (viewData: Doc) => { + if (viewData.config_curDoc !== undefined && this.curDoc() !== viewData.config_curDoc) { + this._curDoc = DocCast(viewData.config_curDoc); + return true; + } + return false; + }; + addDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => { + const doc = toList(docsIn).lastElement(); + const where = location.split(':')[0]; + if (where === OpenWhere.lightbox && (this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc))) { + if (doc.hidden) doc.hidden = false; + if (!location.includes(OpenWhereMod.always)) return true; + } + return this._props.addDocTab(docsIn, location); + }; /** * Actually renders all the cards diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index a71cc43ba..2be3ef48f 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -6,7 +6,7 @@ import { returnZero } from '../../../ClientUtils'; import { Utils } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { Transform } from '../../util/Transform'; @@ -16,6 +16,9 @@ import { FocusViewOptions } from '../nodes/FocusViewOptions'; import './CollectionCarousel3DView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { computedFn } from 'mobx-utils'; +import { Docs } from '../../documents/Documents'; +import { PinDocView } from '../PinFuncs'; +import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere'; // eslint-disable-next-line @typescript-eslint/no-require-imports const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); @@ -96,6 +99,33 @@ export class CollectionCarousel3DView extends CollectionSubView() { index !== -1 && (this.layoutDoc._carousel_index = index); return undefined; }; + getAnchor = (addAsAnnotation: boolean) => { + const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document }); + anchor.config_carousel_index = this.layoutDoc._carousel_index; + PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + if (addAsAnnotation) { + // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered + Doc.AddDocToList(this.dataDoc, this._props.fieldKey + '_annotations', anchor); + } + return anchor; + }; + // pinned / linked anchor doc includes selected rows, graph titles, and graph colors + restoreView = (viewData: Doc) => { + if (viewData.config_carousel_index !== undefined && this.layoutDoc._carousel_index !== viewData.config_carousel_index) { + this.layoutDoc._carousel_index = viewData.config_carousel_index; + return true; + } + return false; + }; + addDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => { + const doc = toList(docsIn).lastElement(); + const where = location.split(':')[0]; + if (where === OpenWhere.lightbox && (this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc))) { + if (doc.hidden) doc.hidden = false; + if (!location.includes(OpenWhereMod.always)) return true; + } + return this._props.addDocTab(docsIn, location); + }; @computed get content() { const currentIndex = NumCast(this.layoutDoc._carousel_index); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 1f2bc908f..b043706fd 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -3,12 +3,17 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { StopEvent, returnOne, returnZero } from '../../../ClientUtils'; -import { Doc, Opt } from '../../../fields/Doc'; -import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; +import { BoolCast, DocCast, NumCast, ScriptCast, StrCast, toList } from '../../../fields/Types'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; +import { PinDocView } from '../PinFuncs'; import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; +import { FocusViewOptions } from '../nodes/FocusViewOptions'; +import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; @@ -27,6 +32,9 @@ export class CollectionCarouselView extends CollectionSubView() { makeObservable(this); } + componentDidMount(): void { + this._props.setContentViewBox?.(this); + } componentWillUnmount() { this._dropDisposer?.(); } @@ -67,6 +75,44 @@ export class CollectionCarouselView extends CollectionSubView() { curDoc = () => this.carouselItems[this.carouselIndex]?.layout; + focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => { + const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]); + if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return undefined; + options.didMove = true; + const target = DocCast(anchor.annotationOn) ?? anchor; + const index = docs.indexOf(target); + index !== -1 && (this.layoutDoc._carousel_index = index); + return undefined; + }; + + getAnchor = (addAsAnnotation: boolean) => { + const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document }); + anchor.config_carousel_index = this.carouselIndex; + PinDocView(anchor, { pinData: { type_collection: true, filters: true } }, this.Document); + if (addAsAnnotation) { + // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered + Doc.AddDocToList(this.dataDoc, this._props.fieldKey + '_annotations', anchor); + } + return anchor; + }; + // pinned / linked anchor doc includes selected rows, graph titles, and graph colors + restoreView = (viewData: Doc) => { + if (viewData.config_carousel_index !== undefined && this.layoutDoc._carousel_index !== viewData.config_carousel_index) { + this.layoutDoc._carousel_index = viewData.config_carousel_index; + return true; + } + return false; + }; + addDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => { + const doc = toList(docsIn).lastElement(); + const where = location.split(':')[0]; + if (where === OpenWhere.lightbox && (this.childDocList?.includes(doc) || this.childLayoutPairs.map(pair => pair.layout)?.includes(doc))) { + if (doc.hidden) doc.hidden = false; + if (!location.includes(OpenWhereMod.always)) return true; + } + return this._props.addDocTab(docsIn, location); + }; + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt<FieldViewProps>, property: string) => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption_' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined; @@ -113,6 +159,7 @@ export class CollectionCarouselView extends CollectionSubView() { LayoutTemplateString={this._props.childLayoutString} TemplateDataDocument={DocCast(Doc.Layout(doc).resolvedDataDoc)} childFilters={this.childDocFilters} + focus={this.focus} hideDecorations={BoolCast(this.layoutDoc.layout_hideDecorations)} addDocument={this._props.addDocument} ScreenToLocalTransform={this.contentScreenToLocalXf} diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 486c826b6..c3047e5fb 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable no-use-before-define */ import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -59,7 +58,6 @@ export enum TrimScope { @observer export class CollectionStackedTimeline extends CollectionSubView<CollectionStackedTimelineProps>() { - // eslint-disable-next-line no-use-before-define public static SelectingRegions: Set<CollectionStackedTimeline> = new Set(); public static StopSelecting() { this.SelectingRegions.forEach( @@ -171,7 +169,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack makeDocUnfiltered = (doc: Doc) => this.childDocList?.some(item => item === doc); - getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => + getView = (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => new Promise<Opt<DocumentView>>(res => { if (doc.hidden) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentView.addViewRenderedCb(doc, dv => finish(dv)); @@ -600,7 +598,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack pointerEvents: 'none', }}> <StackedTimelineAnchor - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} mark={d.anchor} containerViewPath={this._props.containerViewPath} diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 8a24db330..5738e7ce3 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -147,7 +147,6 @@ export class CollectionTimeView extends CollectionSubView() { return ( <div className="collectionTimeView-innards" key="timeline" style={{ pointerEvents: this._props.isContentActive() ? undefined : 'none' }} onClick={this.contentsDown}> <CollectionFreeFormView - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} engineProps={{ pivotField: this.pivotField, childFilters: this.childDocFilters, childFiltersByRanges: this.childDocRangeFilters }} fitContentsToBox={returnTrue} @@ -257,7 +256,6 @@ ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBou const pivotView = DocumentView.getDocumentView(pivotDoc); if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { - // eslint-disable-next-line prefer-destructuring pivotDoc._pivotField = filterVals[0]; } } diff --git a/src/client/views/collections/FlashcardPracticeUI.tsx b/src/client/views/collections/FlashcardPracticeUI.tsx index 9e9318c0a..c298bff22 100644 --- a/src/client/views/collections/FlashcardPracticeUI.tsx +++ b/src/client/views/collections/FlashcardPracticeUI.tsx @@ -58,7 +58,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp get practiceField() { return this._props.fieldKey + "_practice"; } // prettier-ignore @computed get filterDoc() { return DocListCast(Doc.MyContextMenuBtns.data).find(doc => doc.title === 'Filter'); } // prettier-ignore - @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore + @computed get practiceMode() { return this._props.allChildDocs().some(doc => doc._flashcardType) ? StrCast(this._props.layoutDoc.practiceMode) : ''; } // prettier-ignore btnHeight = () => NumCast(this.filterDoc?.height) * Math.min(1, this._props.ScreenToLocalBoxXf().Scale); btnWidth = () => (!this.filterDoc ? 1 : (this.btnHeight() * NumCast(this.filterDoc._width)) / NumCast(this.filterDoc._height)); @@ -127,7 +127,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp const setColor = (mode: practiceMode) => (StrCast(this.practiceMode) === mode ? 'white' : 'lightgray'); const togglePracticeMode = (mode: practiceMode) => this.setPracticeMode(mode === this.practiceMode ? undefined : mode); - return !this._props.allChildDocs().some(doc => doc._layout_isFlashcard) ? null : ( + return !this._props.allChildDocs().some(doc => doc._layout_flashcardType) ? null : ( <div className="FlashcardPracticeUI-practiceModes" style={{ @@ -179,7 +179,7 @@ export class FlashcardPracticeUI extends ObservableReactComponent<PracticeUIProp </div> ); } - tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._layout_isFlashcard) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct + tryFilterOut = (doc: Doc) => (this.practiceMode && BoolCast(doc?._flashcardType) && doc[this.practiceField] === practiceVal.CORRECT ? true : false); // show only cards that aren't marked as correct render() { return ( <div className="FlashcardPracticeUI"> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d2bc8f2c2..afd662b22 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -389,7 +389,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return undefined; }; - getView = async (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => + getView = (doc: Doc, options: FocusViewOptions): Promise<Opt<DocumentView>> => new Promise<Opt<DocumentView>>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); if (doc === this.Document) { |
