aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-09-18 20:46:38 -0400
committerbobzel <zzzman@gmail.com>2024-09-18 20:46:38 -0400
commitd95730d904612640184ca6fdc00864b0c81b0c0c (patch)
tree29176e9a4ea75fca8a146e8a49774fd1b1fb3fc9 /src/client/views/collections
parentcf13604b06b8d8cf37f6e69f19a4092bf2c29d65 (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')
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss8
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx152
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx3
-rw-r--r--src/client/views/collections/CollectionSubView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx5
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}