diff options
-rw-r--r-- | src/client/documents/Documents.ts | 3 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 12 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCardDeckView.tsx | 231 |
4 files changed, 149 insertions, 100 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 34407c641..a190fe11b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -479,8 +479,9 @@ export class DocumentOptions { userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)'); cardSort?: STRt = new StrInfo('way cards are sorted in deck view'); - cardSortForDropDown?: STRt = new StrInfo('needed for dropdown and i dont know why') + // cardSortForDropDown?: STRt = new StrInfo('needed for dropdown and i dont know why') cardSort_customField?: STRt = new StrInfo('field key used for sorting cards'); + cardSort_activeIcons?: List<string>; cardSort_visibleSortGroups?: List<number>; // which sorting values are being filtered (shown) } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2ca2ce9c9..94eee6711 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -660,13 +660,15 @@ pie title Minerals in my tap water } static cardTools(): Button[] { return [ - { btnList: new List<string>(["Time", "Type", "Color", "Chat GPT", "Custom 1", "Custom 2", "Custom 3" ]), - title: "Sort Type", toolTip: "Card Sort Type", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setCardSort(value, _readOnly_); }'}}, + // { btnList: new List<string>(["Time", "Type", "Color", "Chat GPT", "Custom 1", "Custom 2", "Custom 3" ]), + // title: "Sort Type", toolTip: "Card Sort Type", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: '{ return setCardSort(value, _readOnly_); }'}}, // { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(this.toolType, value, _readOnly_);}'}, // btnList: new List<string>(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, - // { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - // { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - // { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "AI Sort", icon:"palette", toolTip:"Have Chat GPT sort your cards for you !", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "AIs", icon:"Visibility", toolTip:"Filter AI labels", subMenu: this.cardGroupTools("robot"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("chat", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // { title: "Custom", icon:"heart", toolTip:"Add Like labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"like", funcs: {hidden:`showFreeform ("like", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, { title: "1st", icon:"Visibility", toolTip:"Filter likes", width: 150, subMenu: this.cardGroupTools("heart"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("like", true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f61c784df..b06d785e1 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -548,7 +548,8 @@ export class MainView extends ObservableReactComponent<{}> { fa.faRobot, fa.faSatellite, fa.faStar, - fa.faCloud + fa.faCloud, + fa.faBolt ] ); } diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index 76536ed48..2ad7f0ed1 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils'; import { emptyFunction, numberRange } from '../../../Utils'; -import { Doc, NumListCast } from '../../../fields/Doc'; +import { Doc, NumListCast, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { BoolCast, Cast, DateCast, NumCast, RTFCast, ScriptCast, StrCast } from '../../../fields/Types'; @@ -27,12 +27,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { SettingsManager } from '../../util/SettingsManager'; import { Tooltip } from '@mui/material'; import { dropActionType } from '../../util/DropActionTypes'; +import { List } from '../../../fields/List'; enum cardSortings { Time = 'time', Type = 'type', Color = 'color', Custom = 'custom', + Drag = 'drag', None = '', } @observer @@ -48,7 +50,7 @@ export class CollectionCardView extends CollectionSubView() { @observable _docRefs = new ObservableMap<Doc, DocumentView>(); _draggerRef = React.createRef<HTMLDivElement>(); @observable _maxRowCount = 10; - @observable _docsDraggedIndex: number[] = []; + @observable _docDraggedIndex: number = -1; @observable _isACardBeingDragged: boolean = false; @observable overIndex: number = -1; @@ -73,12 +75,6 @@ export class CollectionCardView extends CollectionSubView() { } }; - protected createDashEventsTarget = (ele: HTMLDivElement | null) => { - this._dropDisposer?.(); - if (ele) { - this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); - } - }; constructor(props: any) { super(props); @@ -145,12 +141,7 @@ export class CollectionCardView extends CollectionSubView() { return regularDocs; } - /** - * Determines the order in which the cards will be rendered depending on the current sort type - */ - @computed get sortedDocs() { - return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.layoutDoc.sortDesc)); - } + /** * Number of rows of cards to be rendered @@ -226,27 +217,71 @@ export class CollectionCardView extends CollectionSubView() { return Math.abs(stepMag * (apex - index - 1)) - rowOffset; }; - /** - * Translates the selected node to the middle fo the screen - * @param index - * @returns - */ - // translateSelected = (index: number): number => { - // // if (this.isSelected(index)) { - // const middleOfPanel = this._props.PanelWidth() / 2; - // const scaledNodeWidth = this.panelWidth() * 1.25; + findCardDropIndex = (mouseX: number, mouseY: number) => { + + const amCardsTotal = this.sortedDocs.length + let index = 0; + const cardWidth = amCardsTotal < this._maxRowCount ? this._props.PanelWidth() / amCardsTotal : this._props.PanelWidth() / this._maxRowCount; + + // Calculate the adjusted X position accounting for the initial offset + let adjustedX = mouseX + + const amRows = Math.ceil(amCardsTotal / this._maxRowCount); + const rowHeight = this._props.PanelHeight( ) / amRows + const currRow = Math.floor((mouseY - 100) / rowHeight) //rows start at 0 + + if (adjustedX < 0) { + return 0; // Before the first column + } + + if (amCardsTotal < this._maxRowCount) { + index = Math.floor(adjustedX / cardWidth); + } + + else if (currRow != amRows -1 ){ + index = Math.floor(adjustedX / cardWidth) + (currRow * this._maxRowCount) + } - // // Calculate the position of the node's left edge before scaling - // const nodeLeftEdge = index * this.panelWidth(); - // // Find the center of the node after scaling - // const scaledNodeCenter = nodeLeftEdge + scaledNodeWidth / 2; + else { + // console.log(amRows + "am rows") + const rowAmCards = amCardsTotal - (currRow * this._maxRowCount) + const offset = ((this._maxRowCount - rowAmCards ) / 2) * cardWidth + adjustedX = mouseX - offset - // // Calculate the translation needed to align the scaled node's center with the panel's center - // const translation = middleOfPanel - scaledNodeCenter - scaledNodeWidth - scaledNodeWidth / 4; + index = Math.floor(adjustedX / cardWidth) + (currRow * this._maxRowCount); + } + return index; + }; - // return translation; - // }; + @action + onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => { + if (DragManager.docsBeingDragged.length != 0 ) { + this._isACardBeingDragged = true + + const newIndex = this.findCardDropIndex(e.clientX, e.clientY); + + if (newIndex !== this._docDraggedIndex && newIndex != -1) { + this._docDraggedIndex = newIndex; + } + } + }; + + onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + if (de.complete.docDragData) { + this._isACardBeingDragged = false; + this._docDraggedIndex = -1; + e.stopPropagation() + const draggedDocs = de.complete.docDragData?.draggedDocuments; + return true; + } + return false; + }; + + @computed get sortedDocs() { + // console.log("hi hi hi") + return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.layoutDoc.sortDesc), this._docDraggedIndex); + } /** * Called in the sortedDocsType method. Compares the cards' value in regards to the desired sort type-- earlier cards are move to the * front, latter cards to the back @@ -255,7 +290,8 @@ export class CollectionCardView extends CollectionSubView() { * @param isDesc * @returns */ - sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean) => { + sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => { + // console.log('HIIIIIIIII') if (sortType === cardSortings.None) return docs; docs.sort((docA, docB) => { const [typeA, typeB] = (() => { @@ -281,9 +317,25 @@ export class CollectionCardView extends CollectionSubView() { return isDesc ? -out : out; // Reverse the sort order if descending is true }); + if (dragIndex != -1){ + // console.log("what what") + + const draggedDoc = DragManager.docsBeingDragged[0] + const originalIndex = docs.findIndex(doc => doc === draggedDoc); + + + // Remove the dragged document from its original position + docs.splice(originalIndex, 1); + // Insert the dragged document at the new position + docs.splice(dragIndex, 0, draggedDoc); + // } + } + return docs; }; + + displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => ( <DocumentView // eslint-disable-next-line react/jsx-props-no-spreading @@ -361,16 +413,7 @@ export class CollectionCardView extends CollectionSubView() { return trans + this.translateY(amCards, calcRowIndex, realIndex); }; - /** - * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt - * @param childPairIndex - * @param buttonID - * @param doc - */ - toggleButton = undoable((buttonID: number, doc: Doc) => { - this.cardSort_customField && (doc[this.cardSort_customField] = buttonID); - }, 'toggle custom button'); - + /** * A list of the text content of all the child docs. RTF documents will have just their text and pdf documents will have the first 50 words. * Image documents are converted to bse64 and gpt generates a description for them. all other documents use their title. This string is @@ -456,27 +499,37 @@ export class CollectionCardView extends CollectionSubView() { * @returns */ renderButtons = (doc: Doc, cardSort: cardSortings): JSX.Element | null => { - if (cardSort !== cardSortings.Custom) return null; + // if (cardSort !== cardSortings.Custom) return null; - const amButtons = Math.max( - 4, - this.childDocs?.reduce((set, d) => { - if (this.cardSort_customField) { - set.add(NumCast(d[this.cardSort_customField])); - } - return set; - }, new Set<number>()).size ?? 0 - ); + const amButtons = 4 + + // const amButtons = Math.max( + // 4, + // this.childDocs?.reduce((set, d) => { + // if (this.cardSort_customField) { + // set.add(NumCast(d[this.cardSort_customField])); + // } + // return set; + // }, new Set<number>()).size ?? 0 + // ); const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc); + const totalWidth = amButtons * 72 + amButtons * 2 * 5 + 6; + const iconMap: { [key: number]: any } = { + 0: 'star', + 1: 'heart', + 2: 'cloud', + 3: 'bolt' + }; + return ( <div className="card-button-container" style={{ width: `${totalWidth}px`, fontSize: '50px' }}> {numberRange(amButtons).map(i => ( - <Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from group {i + 1}</div>}> - <button type="button" onClick={() => this.toggleButton(i, doc)}> - {this.getButtonIcon(activeButtonIndex === i)} + <Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap[i]} group</div>}> + <button type="button" onClick={() => this.toggleButton(doc, iconMap[i] )}> + {this.getButtonIcon(doc, iconMap[i])} </button> </Tooltip> ))} @@ -484,53 +537,44 @@ export class CollectionCardView extends CollectionSubView() { ); }; - getButtonIcon = (isActive: boolean): JSX.Element => { - const iconMap: { [key: string]: any } = { - like: 'heart', - chat: 'robot', - idea: 'cloud', - }; + /** + * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt + * @param childPairIndex + * @param buttonID + * @param doc + */ + toggleButton = undoable((doc: Doc, icon: string) => { + + + + // this.cardSort_customField && (doc[this.cardSort_customField] = buttonID); + + // doc.cardSort_activeIcons = new List<string>() + - const icon = iconMap[this.cardSort_customField ?? ''] || 'star'; + const list = StrListCast(doc.cardSort_activeIcons); + doc.cardSort_activeIcons = new List<string>(list.includes(icon) ? list.filter(d => d !== icon) : [...list, icon]); + + + + // StrListCast(doc.cardSort_activeIcons).push(iconMap[buttonID]) + }, 'toggle card tag'); + + + getButtonIcon = (doc: Doc, icon: any): JSX.Element => { + + const isActive = StrListCast(doc.cardSort_activeIcons).includes(icon) + + console.log(StrListCast(doc.cardSort_activeIcons)) const color = isActive ? '#4476f7' : '#323232'; return <FontAwesomeIcon icon={icon} size="lg" style={{ color }} />; }; - // @action - // onDragStart = (index: number) => { - // this.draggedIndex = index; - // }; - - // @action - // onDragOver = (index: number) => { - // if (this.draggedIndex !== index) { - // this.overIndex = index; - // } - // }; - - // @action - // onDrop = () => { - // if (this.draggedIndex !== -1 && this.overIndex !== -1) { - // const draggedDoc = this.sortedDocs[this.draggedIndex]; - // this.sortedDocs.splice(this.draggedIndex, 1); - // this.sortedDocs.splice(this.overIndex, 0, draggedDoc); - // this.draggedIndex = -1; - // this.overIndex = -1; - // } - // }; - - // @action - // onDragEnd = () => { - // this.draggedIndex = -1; - // this.overIndex = -1; - // }; - /** * Actually renders all the cards */ renderCards = () => { - console.log(DragManager.docsBeingDragged.length + 'drag ha'); const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc)); const isEmpty = this.childDocsWithoutLinks.length === 0; @@ -599,8 +643,9 @@ export class CollectionCardView extends CollectionSubView() { render() { return ( <div + onPointerMove={e => this.onPointerMove(e)} className="collectionCardView-outer" - ref={this.createDashEventsTarget} + ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor), color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color), |