From 22376ded1271629974bfafc31b77e3288d593c3d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 2 Oct 2024 12:24:11 -0400
Subject: added showTags button for cardView.  fixed unnecessary invalidations
 of TagsView based on child screenToLocal changing when its not rendered.

---
 src/client/views/collections/CollectionCardDeckView.tsx | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index e5a6ebc7f..101cc8082 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, trace } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
@@ -139,7 +139,7 @@ export class CollectionCardView extends CollectionSubView() {
      * custom group
      */
     @computed get childDocsWithoutLinks() {
-        return this.childDocs.filter(l => l.type !== DocumentType.LINK);
+        return this.childDocs.filter(l => !l.layout_isSvg);
     }
 
     /**
@@ -402,7 +402,7 @@ export class CollectionCardView extends CollectionSubView() {
             PanelHeight={this.childPanelHeight}
             dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
             dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
-            showTags={true}
+            showTags={BoolCast(this.layoutDoc.showChildTags)}
             dontHideOnDrag
         />
     );
@@ -607,6 +607,8 @@ export class CollectionCardView extends CollectionSubView() {
 
                 const dref = this._docRefs.get(doc);
                 const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
+                if (!scale) return new Transform(0, 0, 0);
+
                 return new Transform(-translateX + (dref?.centeringX || 0) * scale, 
                                      -translateY + (dref?.centeringY || 0) * scale, 1)
                           .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
@@ -639,7 +641,7 @@ export class CollectionCardView extends CollectionSubView() {
                                     SnappingManager.SetIsResizing(undefined);
                                     this._forceChildXf++;
                                 }),
-                                600
+                                1000
                             );
                         }
                     })}
-- 
cgit v1.2.3-70-g09d2


From f63aa4c65f6336c7708c50ced83867702a310240 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 4 Oct 2024 18:39:15 -0400
Subject: cleaning up CardDeckView so that animations work smoothly

---
 src/client/views/Main.tsx                          |   2 -
 .../views/collections/CollectionCalendarView.tsx   |  99 ----------
 .../views/collections/CollectionCardDeckView.tsx   | 199 +++++++++------------
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 src/client/views/collections/CollectionView.tsx    |   2 -
 src/client/views/nodes/DocumentView.tsx            |   1 +
 src/client/views/nodes/FieldView.tsx               |   3 +-
 src/client/views/nodes/calendarBox/CalendarBox.tsx |   2 +-
 8 files changed, 88 insertions(+), 222 deletions(-)
 delete mode 100644 src/client/views/collections/CollectionCalendarView.tsx

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 73d2872d1..17eea585a 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -18,7 +18,6 @@ import { TrackMovements } from '../util/TrackMovements';
 import { KeyManager } from './GlobalKeyHandler';
 import { InkingStroke } from './InkingStroke';
 import { MainView } from './MainView';
-import { CollectionCalendarView } from './collections/CollectionCalendarView';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { CollectionView } from './collections/CollectionView';
 import { TabDocView } from './collections/TabDocView';
@@ -128,7 +127,6 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
             CollectionFreeFormView,
             CollectionDockingView,
             CollectionSchemaView,
-            CollectionCalendarView,
             CollectionView,
             WebBox,
             KeyValueBox,
diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx
deleted file mode 100644
index 0ea9f8ebc..000000000
--- a/src/client/views/collections/CollectionCalendarView.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { computed, makeObservable } from 'mobx';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { emptyFunction } from '../../../Utils';
-import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils';
-import { Doc, DocListCast } from '../../../fields/Doc';
-import { StrCast } from '../../../fields/Types';
-import { CollectionStackingView } from './CollectionStackingView';
-import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
-
-@observer
-export class CollectionCalendarView extends CollectionSubView() {
-    constructor(props: SubCollectionViewProps) {
-        super(props);
-        makeObservable(this);
-    }
-
-    componentDidMount(): void {}
-
-    componentWillUnmount(): void {}
-
-    @computed get allCalendars() {
-        return this.childDocs; // returns a list of docs (i.e. calendars)
-    }
-
-    removeCalendar = () => {};
-
-    addCalendar = (/* doc: Doc | Doc[], annotationKey?: string | undefined */): boolean =>
-        // bring up calendar modal with option to create a calendar
-        true;
-
-    _stackRef = React.createRef<CollectionStackingView>();
-
-    panelHeight = () => this._props.PanelHeight() - 40; // this should be the height of the stacking view. For now, it's the hieight of the calendar view minus 40 to allow for a title
-
-    // most recent calendar should come first
-    sortByMostRecentDate = (calendarA: Doc, calendarB: Doc) => {
-        const aDateRangeStr = StrCast(DocListCast(calendarA.data).lastElement()?.date_range);
-        const bDateRangeStr = StrCast(DocListCast(calendarB.data).lastElement()?.date_range);
-
-        const { start: aFromDate, end: aToDate } = dateRangeStrToDates(aDateRangeStr);
-        const { start: bFromDate, end: bToDate } = dateRangeStrToDates(bDateRangeStr);
-
-        if (aFromDate > bFromDate) {
-            return -1; // a comes first
-        }
-        if (aFromDate < bFromDate) {
-            return 1; // b comes first
-        }
-        // start dates are the same
-        if (aToDate > bToDate) {
-            return -1; // a comes first
-        }
-        if (aToDate < bToDate) {
-            return 1; // b comes first
-        }
-        return 0; // same start and end dates
-    };
-
-    screenToLocalTransform = () =>
-        this._props
-            .ScreenToLocalTransform()
-            .translate(Doc.NativeWidth(this.Document), 0)
-            .scale(this._props.NativeDimScaling?.() || 1);
-
-    get calendarsKey() {
-        return this._props.fieldKey;
-    }
-
-    render() {
-        return (
-            <div className="collectionCalendarView">
-                <CollectionStackingView
-                    // eslint-disable-next-line react/jsx-props-no-spreading
-                    {...this._props}
-                    setContentViewBox={emptyFunction}
-                    ref={this._stackRef}
-                    PanelHeight={this.panelHeight}
-                    PanelWidth={this._props.PanelWidth}
-                    sortFunc={this.sortByMostRecentDate}
-                    setHeight={undefined}
-                    isAnnotationOverlay={false}
-                    // select={emptyFunction} What does this mean?
-                    isAnyChildContentActive={returnTrue} // ??
-                    dontCenter="y"
-                    // childDocumentsActive={}
-                    // whenChildContentsActiveChanged={}
-                    childHideDecorationTitle={false}
-                    removeDocument={this.removeDocument} // will calendar automatically be removed from myCalendars
-                    moveDocument={this.moveDocument}
-                    addDocument={this.addCalendar}
-                    ScreenToLocalTransform={this.screenToLocalTransform}
-                    renderDepth={this._props.renderDepth + 1}
-                    fieldKey={this.calendarsKey}
-                />
-            </div>
-        );
-    }
-}
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 101cc8082..a9ab9de26 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -2,7 +2,6 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
-import { emptyFunction } from '../../../Utils';
 import { Doc } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
@@ -13,7 +12,6 @@ import { gptImageLabel } from '../../apis/gpt/GPT';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
 import { dropActionType } from '../../util/DropActionTypes';
-import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoable } from '../../util/UndoManager';
@@ -23,12 +21,12 @@ import { DocumentView } from '../nodes/DocumentView';
 import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
 import './CollectionCardDeckView.scss';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { computedFn } from 'mobx-utils';
 
 enum cardSortings {
     Time = 'time',
     Type = 'type',
     Color = 'color',
-    Custom = 'custom',
     Chat = 'chat',
     Tag = 'tag',
     None = '',
@@ -46,14 +44,13 @@ export class CollectionCardView extends CollectionSubView() {
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _disposers: { [key: string]: IReactionDisposer } = {};
     private _textToDoc = new Map<string, Doc>();
-    private _dropped = false; // indicate when a card doc has just moved;
+    private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
 
     @observable _forceChildXf = 0;
     @observable _hoveredNodeIndex = -1;
     @observable _docRefs = new ObservableMap<Doc, DocumentView>();
     @observable _maxRowCount = 10;
     @observable _docDraggedIndex: number = -1;
-    @observable overIndex: number = -1;
 
     static imageUrlToBase64 = async (imageUrl: string): Promise<string> => {
         try {
@@ -101,7 +98,6 @@ export class CollectionCardView extends CollectionSubView() {
 
     componentDidMount() {
         this._props.setContentViewBox?.(this);
-        // Reaction to cardSort changes
         this._disposers.sort = reaction(
             () => GPTPopup.Instance.visible,
             isVis => {
@@ -135,8 +131,7 @@ export class CollectionCardView extends CollectionSubView() {
     }
 
     /**
-     * The child documents to be rendered-- either all of them except the Links or the docs in the currently active
-     * custom group
+     * The child documents to be rendered-- everything other than ink/link docs (which are marks as being svg's)
      */
     @computed get childDocsWithoutLinks() {
         return this.childDocs.filter(l => !l.layout_isSvg);
@@ -155,8 +150,7 @@ export class CollectionCardView extends CollectionSubView() {
      */
     quizMode = () => {
         const randomIndex = Math.floor(Math.random() * this.childDocs.length);
-        SelectionManager.DeselectAll();
-        DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false);
+        DocumentView.getDocumentView(this.childDocs[randomIndex])?.select(false);
     };
 
     /**
@@ -168,29 +162,15 @@ export class CollectionCardView extends CollectionSubView() {
 
     @action
     setHoveredNodeIndex = (index: number) => {
-        if (!DocumentView.SelectedDocs().includes(this.childDocs[index])) {
-            this._hoveredNodeIndex = index;
-        }
+        if (!SnappingManager.IsDragging) this._hoveredNodeIndex = index;
     };
-    /**
-     * Translates the hovered node to the center of the screen
-     * @param index
-     * @returns
-     */
-    translateHover = (index: number) => (this._hoveredNodeIndex === index && !DocumentView.SelectedDocs().includes(this.childDocs[index]) ? -50 : 0);
-
-    isSelected = (index: number) => DocumentView.SelectedDocs().includes(this.childDocs[index]);
-
-    /**
-     * Returns all the documents except the one that's currently selected
-     */
-    inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d));
 
+    isSelected = (doc: Doc) => this._docRefs.get(doc)?.IsSelected;
     childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2);
     childPanelHeight = () => this._props.PanelHeight() * this.fitContentScale;
     onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
-    isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive();
-    isChildContentActive = () => !!this.isContentActive();
+    isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this.isAnyChildContentActive();
+    isAnyChildContentActive = this._props.isAnyChildContentActive;
 
     /**
      * Returns the degree to rotate a card dependind on the amount of cards in their row and their index in said row
@@ -202,13 +182,14 @@ export class CollectionCardView extends CollectionSubView() {
         if (amCards == 1) return 0;
 
         const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2));
-        const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
-
-        if (amCards % 2 === 0 && possRotate === 0) {
-            return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
-        }
-        if (amCards % 2 === 0 && index > (amCards + 1) / 2) {
-            return possRotate + stepMag;
+        if (amCards % 2 === 0) {
+            if (possRotate === 0) {
+                return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2)));
+            }
+            if (index > (amCards + 1) / 2) {
+                const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2)));
+                return possRotate + stepMag;
+            }
         }
 
         return possRotate;
@@ -274,21 +255,12 @@ export class CollectionCardView extends CollectionSubView() {
 
     /**
      * Checks to see if a card is being dragged and calls the appropriate methods if so
-     * @param e the current pointer event
      */
-
     @action
     onPointerMove = (x: number, y: number) => {
         this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1;
     };
 
-    /**
-     * Handles external drop of images/PDFs etc from outside Dash.
-     */
-    onExternalDrop = async (e: React.DragEvent): Promise<void> => {
-        super.onExternalDrop(e, {});
-    };
-
     /**
      * Resets all the doc dragging vairables once a card is dropped
      * @param e
@@ -326,7 +298,7 @@ export class CollectionCardView extends CollectionSubView() {
     }
 
     /**
-     * Used to determine how to sort cards based on tags. The lestmost tags are given lower values while cards to the right are
+     * Used to determine how to sort cards based on tags. The leftmost tags are given lower values while cards to the right are
      * given higher values. Decimals are used to determine placement for cards with multiple tags
      * @param doc the doc whose value is being determined
      * @returns its value based on its tags
@@ -352,24 +324,14 @@ export class CollectionCardView extends CollectionSubView() {
             docs.sort((docA, docB) => {
                 const [typeA, typeB] = (() => {
                     switch (sortType) {
-                        case cardSortings.Time:
-                            return [DateCast(docA.author_date)?.date ?? Date.now(), DateCast(docB.author_date)?.date ?? Date.now()];
-                        case cardSortings.Color: {
-                            const d1 = DashColor(StrCast(docA.backgroundColor));
-                            const d2 = DashColor(StrCast(docB.backgroundColor));
-                            return [d1.hsv().hue(), d2.hsv().hue()];
-                        }
-                        case cardSortings.Tag:
-                            return [this.tagValue(docA) ?? 9999, this.tagValue(docB) ?? 9999];
-                        case cardSortings.Chat:
-                            return [NumCast(docA.chatIndex) ?? 9999, NumCast(docB.chatIndex) ?? 9999];
-                        default:
-                            return [StrCast(docA.type), StrCast(docB.type)];
+                        default:                
+                        case cardSortings.Type: return [StrCast(docA.type),                                   StrCast(docB.type)];
+                        case cardSortings.Chat: return [NumCast(docA.chatIndex, 9999),                        NumCast(docB.chatIndex,9999)];
+                        case cardSortings.Time: return [DateCast(docA.author_date)?.date ?? Date.now(),       DateCast(docB.author_date)?.date ?? Date.now()];
+                        case cardSortings.Color:return [DashColor(StrCast(docA.backgroundColor)).hsv().hue(), DashColor(StrCast(docB.backgroundColor)).hsv().hue()];
                     }
-                })();
-
-                const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0;
-                return isDesc ? out : -out;
+                })(); //prettier-ignore
+                return (typeA < typeB ? -1 : typeA > typeB ? 1 : 0) * (isDesc ? 1 : -1);
             });
         if (dragIndex !== -1) {
             const draggedDoc = DragManager.docsBeingDragged[0];
@@ -382,6 +344,15 @@ export class CollectionCardView extends CollectionSubView() {
         return docs;
     };
 
+    isChildContentActive = () =>
+        this._props.isContentActive?.() === false
+            ? false
+            : this._props.isDocumentActive?.() && (this._props.childDocumentsActive?.() || BoolCast(this.Document.childDocumentsActive))
+              ? true
+              : this._props.childDocumentsActive?.() === false || this.Document.childDocumentsActive === false
+                ? false
+                : undefined;
+
     displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => (
         <DocumentView
             {...this._props}
@@ -396,13 +367,14 @@ export class CollectionCardView extends CollectionSubView() {
             LayoutTemplateString={this._props.childLayoutString}
             containerViewPath={this.childContainerViewPath}
             ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot
-            isContentActive={emptyFunction}
             isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive}
             PanelWidth={this.childPanelWidth}
             PanelHeight={this.childPanelHeight}
             dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
             dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
             showTags={BoolCast(this.layoutDoc.showChildTags)}
+            whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
+            isContentActive={this.isChildContentActive}
             dontHideOnDrag
         />
     );
@@ -416,13 +388,11 @@ export class CollectionCardView extends CollectionSubView() {
         if (this.sortedDocs.length < this._maxRowCount) {
             return this.sortedDocs.length;
         }
-        // 13 - 3 = 10
         const totalCards = this.sortedDocs.length;
         // if 9 or less
         if (index < totalCards - (totalCards % this._maxRowCount)) {
             return this._maxRowCount;
         }
-        // (3)
         return totalCards % this._maxRowCount;
     };
     /**
@@ -443,17 +413,17 @@ export class CollectionCardView extends CollectionSubView() {
     /**
      * Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected
      * @param isHovered
-     * @param isSelected
+     * @param isActive
      * @param realIndex
      * @param amCards
      * @param calcRowIndex
      * @returns
      */
-    calculateTranslateY = (isHovered: boolean, isSelected: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
+    calculateTranslateY = (isHovered: boolean, isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
         const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows;
         const rowIndex = Math.trunc(realIndex / this._maxRowCount);
         const rowToCenterShift = this.numRows / 2 - rowIndex;
-        if (isSelected) return rowToCenterShift * rowHeight - rowHeight / 2;
+        if (isActive) return rowToCenterShift * rowHeight - rowHeight / 2;
         if (amCards == 1) return 50 * this.fitContentScale;
         return this.translateY(amCards, calcRowIndex, realIndex);
     };
@@ -576,15 +546,43 @@ export class CollectionCardView extends CollectionSubView() {
         await this.childPairStringListAndUpdateSortDesc();
     };
 
+    childScreenToLocal = computedFn((doc: Doc, index: number, calcRowIndex: number, isSelected: boolean, amCards: number) => () => {
+        // need to explicitly trigger an invalidation since we're reading everything from the Dom
+        this._forceChildXf;
+        this._props.ScreenToLocalTransform();
+
+        const dref = this._docRefs.get(doc);
+        const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
+        if (!scale) return new Transform(0, 0, 0);
+
+        return new Transform(-translateX + (dref?.centeringX || 0) * scale, 
+                             -translateY + (dref?.centeringY || 0) * scale, 1)
+                  .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
+    });
+
+    cardPointerUp = action((doc: Doc) => {
+        // if a card doc has just moved, or a card is selected and in front, then ignore this event
+        if (this.isSelected(doc) || this._dropped) {
+            this._dropped = false;
+        } else {
+            // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
+            // Turn them back on when the animation has completed and the render and backend structures are in synch
+            SnappingManager.SetIsResizing(doc[Id]);
+            setTimeout(
+                action(() => {
+                    SnappingManager.SetIsResizing(undefined);
+                    this._forceChildXf++;
+                }),
+                1000
+            );
+        }
+    });
+
     /**
      * Actually renders all the cards
      */
     @computed get renderCards() {
-        const sortedDocs = this.sortedDocs;
-        const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
-        const isEmpty = this.childDocsWithoutLinks.length === 0;
-
-        if (isEmpty) {
+        if (!this.childDocsWithoutLinks.length) {
             return (
                 <span className="no-card-span" style={{ width: ` ${this._props.PanelWidth()}px`, height: ` ${this._props.PanelHeight()}px` }}>
                     Sorry ! There are no cards in this group
@@ -593,31 +591,18 @@ export class CollectionCardView extends CollectionSubView() {
         }
 
         // Map sorted documents to their rendered components
-        return sortedDocs.map((doc, index) => {
-            const realIndex = sortedDocs.indexOf(doc);
+        return this.sortedDocs.map((doc, index) => {
+            const realIndex = this.sortedDocs.indexOf(doc);
             const calcRowIndex = this.overflowIndexCalc(realIndex);
             const amCards = this.overflowAmCardsCalc(realIndex);
             const view = DocumentView.getDocumentView(doc, this.DocumentView?.());
-            const isSelected = view?.ComponentView?.isAnyChildContentActive?.() || view?.IsSelected ? true : false;
 
-            const childScreenToLocal = () => {
-                // need to explicitly trigger an invalidation since we're reading everything from the Dom
-                this._forceChildXf;
-                this._props.ScreenToLocalTransform();
-
-                const dref = this._docRefs.get(doc);
-                const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
-                if (!scale) return new Transform(0, 0, 0);
-
-                return new Transform(-translateX + (dref?.centeringX || 0) * scale, 
-                                     -translateY + (dref?.centeringY || 0) * scale, 1)
-                          .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
-            };
+            const childScreenToLocal = this.childScreenToLocal(doc, index, calcRowIndex, !!view?.IsContentActive, amCards);
 
             const translateIfSelected = () => {
                 const indexInRow = index % this._maxRowCount;
                 const rowIndex = Math.trunc(index / this._maxRowCount);
-                const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2;
+                const rowCenterIndex = Math.min(this._maxRowCount, this.sortedDocs.length - rowIndex * this._maxRowCount) / 2;
                 return (rowCenterIndex - indexInRow) * 100 - 50;
             };
             const aspect = NumCast(doc.height) / NumCast(doc.width, 1);
@@ -627,33 +612,18 @@ export class CollectionCardView extends CollectionSubView() {
             return (
                 <div
                     key={doc[Id]}
-                    className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`}
-                    onPointerUp={action(() => {
-                        // if a card doc has just moved, or a card is selected and in front, then ignore this event
-                        if (DocumentView.SelectedDocs().includes(doc) || this._dropped) {
-                            this._dropped = false;
-                        } else {
-                            // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
-                            // Turn them back on when the animation has completed and the render and backend structures are in synch
-                            SnappingManager.SetIsResizing(doc[Id]);
-                            setTimeout(
-                                action(() => {
-                                    SnappingManager.SetIsResizing(undefined);
-                                    this._forceChildXf++;
-                                }),
-                                1000
-                            );
-                        }
-                    })}
+                    className={`card-item${view?.IsContentActive ? '-active' : this.isAnyChildContentActive() ? '-inactive' : ''}`}
+                    onPointerUp={() => this.cardPointerUp(doc)}
                     style={{
                         width: this.childPanelWidth(),
                         height: 'max-content',
-                        transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, isSelected, realIndex, amCards, calcRowIndex)}px)
-                                    translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
-                                    rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg)
-                                    scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`,
+                        transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, !!view?.IsContentActive, realIndex, amCards, calcRowIndex)}px)
+                                    translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
+                                    rotate(${!view?.IsContentActive ? this.rotate(amCards, calcRowIndex) : 0}deg)
+                                    scale(${view?.IsContentActive ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
                     }} // prettier-ignore
-                    onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}>
+                    onPointerEnter={() => this.setHoveredNodeIndex(index)}
+                    onPointerLeave={() => this.setHoveredNodeIndex(-1)}>
                     {this.displayDoc(doc, childScreenToLocal)}
                 </div>
             );
@@ -680,8 +650,7 @@ export class CollectionCardView extends CollectionSubView() {
                         ...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }),
                         ...(!isEmpty && { height: `${100 * this.fitContentScale}%` }),
                         gridAutoRows: `${100 / this.numRows}%`,
-                    }}
-                    onMouseLeave={() => this.setHoveredNodeIndex(-1)}>
+                    }}>
                     {this.renderCards}
                 </div>
             </div>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5d32482c3..581201a20 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -296,7 +296,7 @@ export function CollectionSubView<X>() {
             return false;
         }
 
-        protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: (docs: Doc[]) => void) {
+        protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions = {}, completed?: (docs: Doc[]) => void) {
             if (e.ctrlKey) {
                 e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
                 return;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c9e934448..7418d4360 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable react/jsx-props-no-spreading */
 import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -16,7 +15,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxAnnotatableComponent } from '../DocComponent';
 import { FieldView } from '../nodes/FieldView';
 import { OpenWhere } from '../nodes/OpenWhere';
-import { CollectionCalendarView } from './CollectionCalendarView';
 import { CollectionCardView } from './CollectionCardDeckView';
 import { CollectionCarousel3DView } from './CollectionCarousel3DView';
 import { CollectionCarouselView } from './CollectionCarouselView';
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d730e661b..81b5f946a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1206,6 +1206,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
 
     public set IsSelected(val)  { runInAction(() => { this._selected = val; }); } // prettier-ignore
     public get IsSelected()     { return this._selected; } // prettier-ignore
+    public get IsContentActive(){ return this._docViewInternal?.isContentActive(); } // prettier-ignore
     public get topMost()        { return this._props.renderDepth === 0; } // prettier-ignore
     public get ContentDiv()     { return this._docViewInternal?._contentDiv; } // prettier-ignore
     public get ComponentView()  { return this._docViewInternal?._componentView; } // prettier-ignore
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 683edba16..f6eb4009c 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -6,7 +6,6 @@ import { DateField } from '../../../fields/DateField';
 import { Doc, Field, FieldType, Opt } from '../../../fields/Doc';
 import { List } from '../../../fields/List';
 import { ScriptField } from '../../../fields/ScriptField';
-import { WebField } from '../../../fields/URLField';
 import { dropActionType } from '../../util/DropActionTypes';
 import { Transform } from '../../util/Transform';
 import { PinProps } from '../PinFuncs';
@@ -14,9 +13,9 @@ import { ViewBoxInterface } from '../ViewBoxInterface';
 import { DocumentView } from './DocumentView';
 import { FocusViewOptions } from './FocusViewOptions';
 import { OpenWhere } from './OpenWhere';
+import { WebField } from '../../../fields/URLField';
 
 export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>;
-// eslint-disable-next-line no-use-before-define
 export type StyleProviderFuncType = (
     doc: Opt<Doc>,
     // eslint-disable-next-line no-use-before-define
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index 678b7dd0b..d38cb5423 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -1,4 +1,4 @@
-import { Calendar, DateInput, EventClickArg, EventSourceInput } from '@fullcalendar/core';
+import { Calendar, EventClickArg, EventSourceInput } from '@fullcalendar/core';
 import dayGridPlugin from '@fullcalendar/daygrid';
 import multiMonthPlugin from '@fullcalendar/multimonth';
 import timeGrid from '@fullcalendar/timegrid';
-- 
cgit v1.2.3-70-g09d2


From cd7e213e7e0b9b6606ae068c29412bb64cdf6f2d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 7 Oct 2024 10:43:48 -0400
Subject: comment cleanup

---
 .../views/collections/CollectionCardDeckView.tsx   | 24 ++++++++++------------
 1 file changed, 11 insertions(+), 13 deletions(-)

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index a9ab9de26..0c2bcc580 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -411,15 +411,14 @@ export class CollectionCardView extends CollectionSubView() {
     translateOverflowX = (realIndex: number, calcRowCards: number) => (realIndex < this._maxRowCount ? 0 : (this._maxRowCount - calcRowCards) * (this.childPanelWidth() / 2));
 
     /**
-     * Determines how far to translate a card in the y direction depending on its index, whether or not its being hovered, or if it's selected
-     * @param isHovered
-     * @param isActive
-     * @param realIndex
-     * @param amCards
-     * @param calcRowIndex
-     * @returns
+     * Determines how far to translate a card in the y direction depending on its index and if it's selected
+     * @param isActive whether the card is focused for interaction
+     * @param realIndex index of card from start of deck
+     * @param amCards ??
+     * @param calcRowIndex index of card from start of row
+     * @returns Y translation of card
      */
-    calculateTranslateY = (isHovered: boolean, isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
+    calculateTranslateY = (isActive: boolean, realIndex: number, amCards: number, calcRowIndex: number) => {
         const rowHeight = (this._props.PanelHeight() * this.fitContentScale) / this.numRows;
         const rowIndex = Math.trunc(realIndex / this._maxRowCount);
         const rowToCenterShift = this.numRows / 2 - rowIndex;
@@ -592,9 +591,8 @@ export class CollectionCardView extends CollectionSubView() {
 
         // Map sorted documents to their rendered components
         return this.sortedDocs.map((doc, index) => {
-            const realIndex = this.sortedDocs.indexOf(doc);
-            const calcRowIndex = this.overflowIndexCalc(realIndex);
-            const amCards = this.overflowAmCardsCalc(realIndex);
+            const calcRowIndex = this.overflowIndexCalc(index);
+            const amCards = this.overflowAmCardsCalc(index);
             const view = DocumentView.getDocumentView(doc, this.DocumentView?.());
 
             const childScreenToLocal = this.childScreenToLocal(doc, index, calcRowIndex, !!view?.IsContentActive, amCards);
@@ -617,8 +615,8 @@ export class CollectionCardView extends CollectionSubView() {
                     style={{
                         width: this.childPanelWidth(),
                         height: 'max-content',
-                        transform: `translateY(${this.calculateTranslateY(this._hoveredNodeIndex === index, !!view?.IsContentActive, realIndex, amCards, calcRowIndex)}px)
-                                    translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px))
+                        transform: `translateY(${this.calculateTranslateY(!!view?.IsContentActive, index, amCards, calcRowIndex)}px)
+                                    translateX(calc(${view?.IsContentActive ? translateIfSelected() : 0}% + ${this.translateOverflowX(index, amCards)}px))
                                     rotate(${!view?.IsContentActive ? this.rotate(amCards, calcRowIndex) : 0}deg)
                                     scale(${view?.IsContentActive ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.1 : 1})`,
                     }} // prettier-ignore
-- 
cgit v1.2.3-70-g09d2


From b9fda86731a01ebfc3f21ebdd4eaf43a1c9eccc6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 8 Oct 2024 23:07:52 -0400
Subject: yet another fix to cardView to make animations smooth - need to
 specifically target hidingDecorations without going using  IsResizing as a
 hack

---
 src/client/util/SnappingManager.ts                               | 3 +++
 src/client/views/DocumentDecorations.tsx                         | 9 +++------
 src/client/views/collections/CollectionCardDeckView.tsx          | 5 +++--
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx    | 2 +-
 4 files changed, 10 insertions(+), 9 deletions(-)

(limited to 'src/client/views/collections/CollectionCardDeckView.tsx')

diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index 95ccc7735..5f6c7d9ac 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -28,6 +28,7 @@ export class SnappingManager {
     @observable _lastBtnId: string = '';
     @observable _propertyWid: number = 0;
     @observable _printToConsole: boolean = false;
+    @observable _hideDecorations: boolean = false;
 
     private constructor() {
         SnappingManager._manager = this;
@@ -59,6 +60,7 @@ export class SnappingManager {
     public static get LastPressedBtn() { return this.Instance._lastBtnId; } // prettier-ignore
     public static get PropertiesWidth(){ return this.Instance._propertyWid; } // prettier-ignore
     public static get PrintToConsole() { return this.Instance._printToConsole; } // prettier-ignore
+    public static get HideDecorations(){ return this.Instance._hideDecorations; } // prettier-ignore
 
     public static SetLongPress      = (press: boolean) => runInAction(() => {this.Instance._longPress = press}); // prettier-ignore
     public static SetShiftKey       = (down: boolean) => runInAction(() => {this.Instance._shiftKey = down}); // prettier-ignore
@@ -75,6 +77,7 @@ export class SnappingManager {
     public static SetLastPressedBtn = (id:string)      =>runInAction(() => {this.Instance._lastBtnId = id}); // prettier-ignore
     public static SetPropertiesWidth= (wid:number)     =>runInAction(() => {this.Instance._propertyWid = wid}); // prettier-ignore
     public static SetPrintToConsole = (state:boolean)  =>runInAction(() => {this.Instance._printToConsole = state}); // prettier-ignore
+    public static SetHideDecorations= (state:boolean)  =>runInAction(() => {this.Instance._hideDecorations = state}); // prettier-ignore
 
     public static userColor: string | undefined;
     public static userVariantColor: string | undefined;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 1c0d51e17..62f2de776 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -63,7 +63,6 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
     @observable private _accumulatedTitle = '';
     @observable private _titleControlString: string = '$title';
     @observable private _editingTitle = false;
-    @observable private _hidden = false;
     @observable private _isRotating: boolean = false;
     @observable private _isRounding: boolean = false;
     @observable private _showLayoutAcl: boolean = false;
@@ -202,16 +201,14 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         dragData.removeDocument = dragDocView._props.removeDocument;
         dragData.isDocDecorationMove = true;
         dragData.canEmbed = dragTitle;
-        this._hidden = true;
+        SnappingManager.SetHideDecorations(true);
         DragManager.StartDocumentDrag(
             DocumentView.Selected().map(dv => dv.ContentDiv!),
             dragData,
             e.x,
             e.y,
             {
-                dragComplete: action(() => {
-                    this._hidden = false;
-                }),
+                dragComplete: () => SnappingManager.SetHideDecorations(false),
                 hideSource: true,
             }
         );
@@ -653,7 +650,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         this._forceRender;
         const { b, r, x, y } = this.Bounds;
         const seldocview = DocumentView.Selected().lastElement();
-        if (SnappingManager.IsDragging || r - x < 1 || x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) {
+        if (SnappingManager.IsDragging || r - x < 1 || x === Number.MAX_VALUE || !seldocview || SnappingManager.HideDecorations || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) {
             setTimeout(
                 action(() => {
                     this._editingTitle = false;
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 0c2bcc580..92c69c3cf 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -22,6 +22,7 @@ import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
 import './CollectionCardDeckView.scss';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 import { computedFn } from 'mobx-utils';
+import { DocumentDecorations } from '../DocumentDecorations';
 
 enum cardSortings {
     Time = 'time',
@@ -566,10 +567,10 @@ export class CollectionCardView extends CollectionSubView() {
         } else {
             // otherwise, turn off documentDecorations becase we're in a selection transition and want to avoid artifacts.
             // Turn them back on when the animation has completed and the render and backend structures are in synch
-            SnappingManager.SetIsResizing(doc[Id]);
+            SnappingManager.SetHideDecorations(true);
             setTimeout(
                 action(() => {
-                    SnappingManager.SetIsResizing(undefined);
+                    SnappingManager.SetHideDecorations(false);
                     this._forceChildXf++;
                 }),
                 1000
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0cc63d632..d8678eebc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -138,7 +138,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return this._props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine);
     }
     @computed get childPointerEvents() {
-        return SnappingManager.IsResizing
+        return falseSnappingManager.IsResizing
             ? 'none'
             : (this._props.childPointerEvents?.() ??
                   (this._props.viewDefDivClick || //
-- 
cgit v1.2.3-70-g09d2

