diff options
| author | bobzel <zzzman@gmail.com> | 2024-09-18 20:46:38 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-09-18 20:46:38 -0400 |
| commit | d95730d904612640184ca6fdc00864b0c81b0c0c (patch) | |
| tree | 29176e9a4ea75fca8a146e8a49774fd1b1fb3fc9 /src/client/views/collections | |
| parent | cf13604b06b8d8cf37f6e69f19a4092bf2c29d65 (diff) | |
lots of changes to fix dragging cards, integrate iconTags with other tags, sizing docs when selected to fit window,
Diffstat (limited to 'src/client/views/collections')
6 files changed, 94 insertions, 79 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss index 5ccc3d9a8..e5fb7aba6 100644 --- a/src/client/views/collections/CollectionCardDeckView.scss +++ b/src/client/views/collections/CollectionCardDeckView.scss @@ -29,18 +29,13 @@ transition: transform 0.3s cubic-bezier(0.455, 0.03, 0.515, 0.955); } -.no-card-span{ +.no-card-span { position: relative; width: fit-content; text-align: center; font-size: 65px; - - - } - - .card-item-inactive, .card-item-active, .card-item { @@ -50,7 +45,6 @@ flex-direction: column; } - .card-item-inactive { opacity: 0.5; } diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index fced9fd37..1952cc707 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -21,6 +21,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import './CollectionCardDeckView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { List } from '../../../fields/List'; enum cardSortings { Time = 'time', @@ -42,7 +43,6 @@ enum cardSortings { @observer export class CollectionCardView extends CollectionSubView() { private _dropDisposer?: DragManager.DragDropDisposer; - private _childDocumentWidth = 600; // target width of a Doc... private _disposers: { [key: string]: IReactionDisposer } = {}; private _textToDoc = new Map<string, Doc>(); @@ -77,6 +77,12 @@ export class CollectionCardView extends CollectionSubView() { this.setRegenerateCallback(); } + protected createDashEventsTarget = (ele: HTMLDivElement | null) => { + this._dropDisposer?.(); + if (ele) { + this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); + } + }; /** * Callback to ensure gpt's text versions of the child docs are updated */ @@ -94,10 +100,7 @@ export class CollectionCardView extends CollectionSubView() { }; componentDidMount() { - this.Document.childFilters_boolean = 'OR'; - this.childDocsWithoutLinks.forEach(c => { - c[DocData].showIconTags = true; - }); + this.Document.childFilters_boolean = 'OR'; // bcz: really shouldn't be assigning to fields from within didMount -- this should be a default/override beahavior somehow // Reaction to cardSort changes this._disposers.sort = reaction( @@ -117,28 +120,24 @@ export class CollectionCardView extends CollectionSubView() { this._dropDisposer?.(); } - @computed get cardSort_customField() { - return StrCast(this.Document.cardSort_customField) as 'chat' | 'star' | 'idea' | 'like'; - } - @computed get cardSort() { return StrCast(this.Document.cardSort) as cardSortings; } /** - * how much to scale down the contents of the view so that everything will fit + * The child documents to be rendered-- either all of them except the Links or the docs in the currently active + * custom group */ - @computed get fitContentScale() { - const length = Math.min(this.childDocsWithoutLinks.length, this._maxRowCount); - return (this._childDocumentWidth * length) / this._props.PanelWidth(); + @computed get childDocsWithoutLinks() { + return (this.childDocList as Doc[]).filter(l => l.type !== DocumentType.LINK); } /** - * The child documents to be rendered-- either all of them except the Links or the docs in the currently active - * custom group + * how much to scale down the contents of the view so that everything will fit */ - @computed get childDocsWithoutLinks() { - return this.childDocs.filter(l => l.type !== DocumentType.LINK); + @computed get fitContentScale() { + const length = Math.min(this.childDocsWithoutLinks.length, this._maxRowCount); + return (this.childPanelWidth() * length) / this._props.PanelWidth(); } /** @@ -154,7 +153,7 @@ export class CollectionCardView extends CollectionSubView() { * Number of rows of cards to be rendered */ @computed get numRows() { - return Math.ceil(this.sortedDocs.length / 10); + return Math.ceil(this.sortedDocs.length / this._maxRowCount); } @action @@ -177,8 +176,7 @@ export class CollectionCardView extends CollectionSubView() { */ inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d)); - panelWidth = () => this._childDocumentWidth; - panelHeight = (layout: Doc) => () => (this.panelWidth() * NumCast(layout._height)) / NumCast(layout._width); + childPanelWidth = () => NumCast(this.layoutDoc.childPanelWidth, this._props.PanelWidth() / 2); onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); isChildContentActive = () => !!this.isContentActive(); @@ -245,6 +243,7 @@ export class CollectionCardView extends CollectionSubView() { const currRow = Math.floor((mouseY - 100) / rowHeight); //rows start at 0 if (adjustedX < 0) { + console.log('DROP INDEX NO '); return 0; // Before the first column } @@ -259,6 +258,7 @@ export class CollectionCardView extends CollectionSubView() { index = Math.floor(adjustedX / cardWidth) + currRow * this._maxRowCount; } + console.log('DROP INDEX = ' + index); return index; }; @@ -281,20 +281,41 @@ export class CollectionCardView extends CollectionSubView() { }; /** + * 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 * @param de drop event * @returns true if a card has been dropped, falls if not */ - onInternalDrop = undoable((e: Event, de: DragManager.DropEvent) => { - if (de.complete.docDragData) { - this._isACardBeingDragged = false; - this._docDraggedIndex = -1; - e.stopPropagation(); - return true; - } - return false; - }, ''); + onInternalDrop = undoable( + action((e: Event, de: DragManager.DropEvent) => { + if (de.complete.docDragData) { + this._isACardBeingDragged = false; + const dragIndex = this._docDraggedIndex; + if (dragIndex > -1) { + this._docDraggedIndex = -1; + const draggedDoc = DragManager.docsBeingDragged[0]; + const sorted = this.sortedDocs; + const originalIndex = sorted.findIndex(doc => doc === draggedDoc); + + this.Document.cardSort = ''; + sorted.splice(originalIndex, 1); + sorted.splice(dragIndex, 0, draggedDoc); + this.dataDoc[this.fieldKey] = new List<Doc>(sorted); + } + e.stopPropagation(); + return true; + } + return false; + }), + '' + ); @computed get sortedDocs() { return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.Document.cardSort_isDesc), this._docDraggedIndex); @@ -348,28 +369,29 @@ export class CollectionCardView extends CollectionSubView() { * @returns */ sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => { - 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()]; + sortType && + 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)]; } - 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)]; - } - })(); + })(); - const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0; - return isDesc ? out : -out; - }); + const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0; + return isDesc ? out : -out; + }); if (dragIndex != -1) { const draggedDoc = DragManager.docsBeingDragged[0]; const originalIndex = docs.findIndex(doc => doc === draggedDoc); @@ -396,9 +418,11 @@ export class CollectionCardView extends CollectionSubView() { 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.panelWidth} - PanelHeight={this.panelHeight(doc)} + PanelWidth={this.childPanelWidth} + PanelHeight={() => this._props.PanelHeight() * this.fitContentScale} + 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} dontHideOnDrag /> ); @@ -415,18 +439,18 @@ export class CollectionCardView extends CollectionSubView() { // 13 - 3 = 10 const totalCards = this.sortedDocs.length; // if 9 or less - if (index < totalCards - (totalCards % 10)) { + if (index < totalCards - (totalCards % this._maxRowCount)) { return this._maxRowCount; } // (3) - return totalCards % 10; + return totalCards % this._maxRowCount; }; /** * Determines the index a card is in in a row * @param realIndex * @returns */ - overflowIndexCalc = (realIndex: number) => realIndex % 10; + overflowIndexCalc = (realIndex: number) => realIndex % this._maxRowCount; /** * Translates the cards in the second rows and beyond over to the right * @param realIndex @@ -434,7 +458,7 @@ export class CollectionCardView extends CollectionSubView() { * @param calcRowCards * @returns */ - translateOverflowX = (realIndex: number, calcRowCards: number) => (realIndex < this._maxRowCount ? 0 : (10 - calcRowCards) * (this.panelWidth() / 2)); + 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 @@ -613,6 +637,9 @@ export class CollectionCardView extends CollectionSubView() { const rowCenterIndex = Math.min(this._maxRowCount, sortedDocs.length - rowIndex * this._maxRowCount) / 2; return (rowCenterIndex - indexInRow) * 100 - 50; }; + const aspect = NumCast(doc.height) / NumCast(doc.width, 1); + const vscale = ((this._props.PanelHeight() * .95) * this.fitContentScale) / (aspect * this.childPanelWidth()); + const hscale = this._maxRowCount / 2; // bcz: hack - the grid is divided evenly into maxRowCount cells, so the max scaling would be maxRowCount -- but making things that wide is ugly, so cap it off at half the window size return ( <div key={doc[Id]} @@ -629,13 +656,13 @@ export class CollectionCardView extends CollectionSubView() { ); }} style={{ - width: this.panelWidth(), + 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'})) + translateX(calc(${isSelected ? translateIfSelected() : 0}% + ${this.translateOverflowX(realIndex, amCards)}px)) rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg) - scale(${isSelected ? 2 : this._hoveredNodeIndex === index ? 1.05 : 1})`, - }} + scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`, + }} // prettier-ignore onMouseEnter={() => this.setHoveredNodeIndex(index)}> {this.displayDoc(doc, childScreenToLocal)} </div> @@ -645,14 +672,13 @@ export class CollectionCardView extends CollectionSubView() { render() { const isEmpty = this.childDocsWithoutLinks.length === 0; - const transformValue = `scale(${1 / this.fitContentScale})`; - const heightValue = `${100 * this.fitContentScale}%`; return ( <div onPointerMove={e => this.onPointerMove(e)} className="collectionCardView-outer" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} + onDrop={this.onExternalDrop.bind(this)} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string, @@ -660,8 +686,8 @@ export class CollectionCardView extends CollectionSubView() { <div className="card-wrapper" style={{ - ...(!isEmpty && { transform: transformValue }), - ...(!isEmpty && { height: heightValue }), + ...(!isEmpty && { transform: `scale(${1 / this.fitContentScale})` }), + ...(!isEmpty && { height: `${100 * this.fitContentScale}%` }), gridAutoRows: `${100 / this.numRows}%`, }} onMouseLeave={() => this.setHoveredNodeIndex(-1)}> diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index ad868fd1e..4609be374 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e97ee713e..1ac0b6d70 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as CSS from 'csstype'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; @@ -540,7 +539,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection if (this.pivotField) { const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { - // eslint-disable-next-line prefer-destructuring type = types[0]; } } @@ -577,7 +575,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection let type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined; const types = docList.length ? docList.map(d => typeof d[key]) : this.filteredChildren.map(d => typeof d[key]); if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) { - // eslint-disable-next-line prefer-destructuring type = types[0]; } const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))))); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 6aca8f2ca..99373da04 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -122,6 +122,9 @@ export function CollectionSubView<X>() { ); return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types } + /** + * This is the raw, stored list of children on a collection. If you modify this list, the database will be updated + */ @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } @@ -218,7 +221,6 @@ export function CollectionSubView<X>() { if (!cursors) { proto.cursors = cursors = new List<CursorField>(); } - // eslint-disable-next-line no-cond-assign if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.data.metadata.id === id)) > -1) { cursors[ind].setPosition(pos); } else { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dbf781e63..cbbf063b4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/jsx-props-no-spreading */ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; import { Property } from 'csstype'; @@ -1211,7 +1210,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection for (let j = 0; j < otherCtrlPts.length - 3; j += 4) { const neighboringSegment = i === j || i === j - 4 || i === j + 4; // Ensuring that the curve intersected by the eraser is not checked for further ink intersections. - // eslint-disable-next-line no-continue if (ink?.Document === otherInk.Document && neighboringSegment) continue; const otherCurve = new Bezier(otherCtrlPts.slice(j, j + 4).map(p => ({ x: p.X, y: p.Y }))); @@ -1481,8 +1479,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const childData = entry.pair.data; return ( <CollectionFreeFormDocumentView - // eslint-disable-next-line react/jsx-props-no-spreading, @typescript-eslint/no-explicit-any - {...(OmitKeys(entry, ['replica', 'pair']).omit as any)} + {...(OmitKeys(entry, ['replica', 'pair']).omit as { x: number; y: number; z: number; width: number; height: number })} key={childLayout[Id] + (entry.replica || '')} Document={childLayout} reactParent={this} |
