diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 2 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 11 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCardDeckView.tsx | 83 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarousel3DView.tsx | 35 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.scss | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.tsx | 66 | ||||
-rw-r--r-- | src/client/views/global/globalScripts.ts | 2 | ||||
-rw-r--r-- | src/client/views/linking/LinkMenuItem.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/IconTagBox.tsx | 2 | ||||
-rw-r--r-- | src/fields/Doc.ts | 6 |
12 files changed, 133 insertions, 81 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e72acf93f..3e7921a08 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -706,8 +706,6 @@ pie title Minerals in my tap water { title: "Fit All", icon: "object-group", toolTip: "Fit Docs to View (double click to make sticky)",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - ] } static textTools():Button[] { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c3bcfdcca..fc4b1f0af 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaUndo } from 'react-icons/fa'; @@ -36,6 +36,7 @@ import { ImageBox } from './nodes/ImageBox'; import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { TagsView } from './TagsView'; +import { setTime } from 'react-datepicker/dist/date_utils'; interface DocumentDecorationsProps { PanelWidth: number; @@ -643,7 +644,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora return this._rotCenter; } + @observable forceRender = 0; render() { + 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)) { @@ -656,6 +659,12 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora return null; } + if (seldocview && !seldocview?.ContentDiv?.getBoundingClientRect().width) { + setTimeout(action(() => this.forceRender++)); + return null; + } + console.log('Renderedr'); + // sharing const acl = GetEffectiveAcl(!this._showLayoutAcl ? Doc.GetProto(seldocview.Document) : seldocview.Document); const docShareMode = HierarchyMapping.get(acl)!.name; diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index 8a9cc46f6..66014a1e0 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 } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils'; @@ -46,8 +46,9 @@ 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; - @observable _forceChildXf = false; + @observable _forceChildXf = 0; @observable _hoveredNodeIndex = -1; @observable _docRefs = new ObservableMap<Doc, DocumentView>(); @observable _maxRowCount = 10; @@ -99,6 +100,7 @@ export class CollectionCardView extends CollectionSubView() { }; componentDidMount() { + this._props.setContentViewBox?.(this); // Reaction to cardSort changes this._disposers.sort = reaction( () => GPTPopup.Instance.visible, @@ -110,6 +112,17 @@ export class CollectionCardView extends CollectionSubView() { } } ); + // if card deck moves, then the child doc views are hidden so their screen to local transforms will return empty rectangles + // when inquired from the dom (below in childScreenToLocal). When the doc is actually renders, we need to act like the + // dash data just changed and trigger a React involidation with the correct data (read from the dom). + this._disposers.child = reaction( + () => [this.Document.x, this.Document.y], + () => { + if (!Array.from(this._docRefs.values()).every(dv => dv.ContentDiv?.getBoundingClientRect().width)) { + setTimeout(action(() => this._forceChildXf++)); + } + } + ); } componentWillUnmount() { @@ -174,6 +187,7 @@ export class CollectionCardView extends CollectionSubView() { inactiveDocs = () => this.childDocsWithoutLinks.filter(d => !DocumentView.SelectedDocs().includes(d)); 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(); @@ -265,14 +279,7 @@ export class CollectionCardView extends CollectionSubView() { @action onPointerMove = (x: number, y: number) => { - this._docDraggedIndex = -1; - if (DragManager.docsBeingDragged.length) { - const newIndex = this.findCardDropIndex(x, y); - - if (newIndex !== this._docDraggedIndex && newIndex != -1) { - this._docDraggedIndex = newIndex; - } - } + this._docDraggedIndex = DragManager.docsBeingDragged.length ? this.findCardDropIndex(x, y) : -1; }; /** @@ -304,6 +311,7 @@ export class CollectionCardView extends CollectionSubView() { if (de.complete.docDragData.removeDocument?.(draggedDoc)) { this.dataDoc[this.fieldKey] = new List<Doc>(sorted); } + this._dropped = true; } e.stopPropagation(); return true; @@ -338,7 +346,8 @@ export class CollectionCardView extends CollectionSubView() { * @param isDesc * @returns */ - sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => { + sort = (docsIn: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => { + const docs = docsIn.slice(); // need make new object list since sort() modifies the incoming list which confuses mobx caching sortType && docs.sort((docA, docB) => { const [typeA, typeB] = (() => { @@ -362,21 +371,21 @@ export class CollectionCardView extends CollectionSubView() { const out = typeA < typeB ? -1 : typeA > typeB ? 1 : 0; return isDesc ? out : -out; }); - if (dragIndex != -1) { + if (dragIndex !== -1) { const draggedDoc = DragManager.docsBeingDragged[0]; const originalIndex = docs.findIndex(doc => doc === draggedDoc); originalIndex !== -1 && docs.splice(originalIndex, 1); - docs.splice(dragIndex, 0, draggedDoc); + draggedDoc && docs.splice(dragIndex, 0, draggedDoc); } - return [...docs]; // need to spread docs into a new object list since sort() modifies the incoming list which confuses mobx caching + return docs; }; displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => ( <DocumentView {...this._props} - ref={action((r: DocumentView) => r?.ContentDiv && this._docRefs.set(doc, r))} + ref={action((r: DocumentView) => (!r?.ContentDiv ? this._docRefs.delete(doc) : this._docRefs.set(doc, r)))} Document={doc} NativeWidth={returnZero} NativeHeight={returnZero} @@ -385,11 +394,12 @@ export class CollectionCardView extends CollectionSubView() { renderDepth={this._props.renderDepth + 1} LayoutTemplate={this._props.childLayoutTemplate} 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._props.PanelHeight() * this.fitContentScale} + 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} @@ -591,7 +601,10 @@ export class CollectionCardView extends CollectionSubView() { 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); return new Transform(-translateX + (dref?.centeringX || 0) * scale, @@ -606,25 +619,30 @@ export class CollectionCardView extends CollectionSubView() { return (rowCenterIndex - indexInRow) * 100 - 50; }; const aspect = NumCast(doc.height) / NumCast(doc.width, 1); - const vscale = Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale) / (aspect * this.childPanelWidth()), - (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10))); // prettier-ignore + const vscale = Math.max(1,Math.min((this._props.PanelHeight() * 0.95 * this.fitContentScale) / (aspect * this.childPanelWidth()), + (this._props.PanelHeight() - 80) / (aspect * (this._props.PanelWidth() / 10)))); // prettier-ignore const hscale = Math.min(this.sortedDocs.length, 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]} className={`card-item${isSelected ? '-active' : anySelected ? '-inactive' : ''}`} - onPointerUp={() => { - if (DocumentView.SelectedDocs().includes(doc)) return; - // this turns off documentDecorations during a transition, then turns them back on afterward. - SnappingManager.SetIsResizing(doc[Id]); - setTimeout( - action(() => { - SnappingManager.SetIsResizing(undefined); - this._forceChildXf = !this._forceChildXf; - }), - 900 - ); - }} + 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++; + }), + 600 + ); + } + })} style={{ width: this.childPanelWidth(), height: 'max-content', @@ -633,7 +651,7 @@ export class CollectionCardView extends CollectionSubView() { rotate(${!isSelected ? this.rotate(amCards, calcRowIndex) : 0}deg) scale(${isSelected ? `${Math.min(hscale, vscale) * 100}%` : this._hoveredNodeIndex === index ? 1.05 : 1})`, }} // prettier-ignore - onMouseEnter={() => this.setHoveredNodeIndex(index)}> + onPointerEnter={() => !SnappingManager.IsDragging && this.setHoveredNodeIndex(index)}> {this.displayDoc(doc, childScreenToLocal)} </div> ); @@ -647,7 +665,8 @@ export class CollectionCardView extends CollectionSubView() { <div className="collectionCardView-outer" ref={(ele: HTMLDivElement | null) => this.createDashEventsTarget(ele)} - onPointerMove={e => this.onPointerMove(e.clientX, e.clientY)} + onPointerLeave={action(() => (this._docDraggedIndex = -1))} + onPointerMove={e => this.onPointerMove(...this._props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY))} onDrop={this.onExternalDrop.bind(this)} style={{ background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 54cc02825..139aebb02 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -14,6 +14,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; import './CollectionCarousel3DView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { Transform } from '../../util/Transform'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); @@ -46,15 +47,32 @@ export class CollectionCarousel3DView extends CollectionSubView() { } centerScale = Number(CAROUSEL3D_CENTER_SCALE); + sideScale = Number(CAROUSEL3D_SIDE_SCALE); panelWidth = () => this._props.PanelWidth() / 3; - panelHeight = () => this._props.PanelHeight() * Number(CAROUSEL3D_SIDE_SCALE); + panelHeight = () => this._props.PanelHeight() * this.sideScale; onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); isChildContentActive = () => !!this.isContentActive(); - childScreenToLocal = () => - this._props // document's left is the panel shifted by the doc's index * panelWidth/#docs. But it scales by centerScale around its center, so it's left moves left by the distance of the left from the center (panelwidth/2) * the scale delta (centerScale-1) - .ScreenToLocalTransform() // the top behaves the same way ecept it's shifted by the 'top' amount specified for the panel in css and then by the scale factor. - .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2) + childScreenLeftToLocal = () => + this._props + .ScreenToLocalTransform() + .scale(this._props.NativeDimScaling?.() || 1) + .translate(-(this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + .scale(1 / this.sideScale); + childScreenRightToLocal = () => + this._props + .ScreenToLocalTransform() + .scale(this._props.NativeDimScaling?.() || 1) + .translate(-2 * this.panelWidth() - (this.panelWidth() - this.panelWidth() * this.sideScale) / 2, -(this.panelHeight() - this.panelHeight() * this.sideScale) / 2 - (Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + .scale(1 / this.sideScale); + childCenterScreenToLocal = () => + this._props + .ScreenToLocalTransform() + .scale(this._props.NativeDimScaling?.() || 1) + .translate( + -this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, // Focused Doc is shifted right by 1/3 panel width then left by increased size percent of center * 1/2 * panel width / 3 + -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2 + ) // top is top margin % of panelHeight - increased size percent of center * panelHeight / 2 .scale(1 / this.centerScale); focus = (anchor: Doc, options: FocusViewOptions): Opt<number> => { @@ -66,9 +84,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { index !== -1 && (this.layoutDoc._carousel_index = index); return undefined; }; + @computed get content() { const currentIndex = NumCast(this.layoutDoc._carousel_index); - const displayDoc = (childPair: { layout: Doc; data: Doc }) => ( + const displayDoc = (childPair: { layout: Doc; data: Doc }, dxf: () => Transform) => ( <DocumentView // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} @@ -84,7 +103,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} focus={this.focus} - ScreenToLocalTransform={this.childScreenToLocal} + ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} PanelWidth={this.panelWidth} @@ -94,7 +113,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { return this.carouselItems.map((childPair, index) => ( <div key={childPair.layout[Id]} className={`collectionCarousel3DView-item${index === currentIndex ? '-active' : ''} ${index}`} style={{ width: this.panelWidth() }}> - {displayDoc(childPair)} + {displayDoc(childPair, index < currentIndex ? this.childScreenLeftToLocal : index === currentIndex ? this.childCenterScreenToLocal : this.childScreenRightToLocal)} </div> )); } diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss index c40f471d6..af617254a 100644 --- a/src/client/views/collections/CollectionCarouselView.scss +++ b/src/client/views/collections/CollectionCarouselView.scss @@ -85,7 +85,6 @@ .carouselView-quiz { position: relative; display: flex; - flex-direction: column; height: 20px; align-items: center; margin: auto; @@ -127,7 +126,7 @@ align-items: center; display: flex; top: 2px; - right: 2px; + left: 2px; width: 30; border-radius: 5px; color: rgba(255, 255, 255, 0.5); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index e0cee2126..43ab4462b 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -63,7 +63,7 @@ export class CollectionCarouselView extends CollectionSubView() { @computed get practiceMessage() { const cardCount = this.carouselItems.length; if (this.practiceMode) { - if (!Doc.hasDocFilter(this.layoutDoc, 'tags', this.starField) && !cardCount) { + if (!Doc.hasDocFilter(this.layoutDoc, 'tags', Doc.FilterAny) && !cardCount) { return 'Finished! Click here to view all flashcards.'; } } @@ -73,8 +73,8 @@ export class CollectionCarouselView extends CollectionSubView() { @computed get filterMessage() { const cardCount = this.carouselItems.length; if (!this.practiceMessage) { - if (Doc.hasDocFilter(this.layoutDoc, 'tags', this.starField) && !cardCount) { - return 'No starred items. Click here to view all flash cards.'; + if (Doc.hasDocFilter(this.layoutDoc, 'tags', Doc.FilterAny) && !cardCount) { + return 'No tagged items. Click here to view all flash cards.'; } if (this.practiceMode) { if (!cardCount) return 'No flashcards to show! Click here to leave practice mode'; @@ -168,6 +168,8 @@ export class CollectionCarouselView extends CollectionSubView() { ? false : undefined; + childScreenToLocalXf = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); + renderDoc = (doc: Doc, showCaptions: boolean, overlayFunc?: (r: DocumentView | null) => void) => { return ( <DocumentView @@ -177,8 +179,10 @@ export class CollectionCarouselView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} fitWidth={undefined} + showTags={true} containerViewPath={this.childContainerViewPath} setContentViewBox={undefined} + ScreenToLocalTransform={this.childScreenToLocalXf} onDoubleClickScript={this.onContentDoubleClick} onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} @@ -273,11 +277,6 @@ export class CollectionCarouselView extends CollectionSubView() { return ( <> <div> - <Tooltip title="star"> - <div key="star" className="carouselView-star" onClick={this.toggleStar}> - <FontAwesomeIcon icon="star" color={TagItem.docHasTag(this.carouselItems?.[this.carouselIndex], this.starField) ? 'yellow' : 'gray'} size="1x" /> - </div> - </Tooltip> {/* <Tooltip title="add new flashcard to pile"> <div key="add" className="carouselView-add" onClick={this.addFlashcard}> <FontAwesomeIcon icon="plus" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" /> @@ -310,12 +309,13 @@ export class CollectionCarouselView extends CollectionSubView() { togglePracticeMode = (mode: practiceMode) => this.setPracticeMode(mode === this.practiceMode ? undefined : mode); toggleFilterMode = () => Doc.setDocFilter(this.Document, 'tags', this.starField, 'check', true); - setColor = (mode: practiceMode | cardMode, which: string) => { return which === mode ? 'white' : 'light gray'}; //prettier-ignore + setColor = (mode: practiceMode | cardMode, which: string) => (which === mode ? 'white' : 'light gray'); @computed get menu() { const curDoc = this.carouselItems?.[this.carouselIndex]; return ( <div className="carouselView-menu"> + {/* NOTE: this should really show the same filter as in the workspace View menu, not just something hardwire for 'star' */} <Tooltip title={Doc.hasDocFilter(this.Document, 'tags', this.starField) ? 'Show all cards' : 'Show only starred cards'}> <div key="back" className="carouselView-starFilter" onClick={e => this.toggleFilterMode()}> <FontAwesomeIcon icon="filter" color={Doc.hasDocFilter(this.Document, 'tags', this.starField) ? 'white' : 'lightgray'} size="1x" /> @@ -339,27 +339,33 @@ export class CollectionCarouselView extends CollectionSubView() { render() { return ( - <div - className="collectionCarouselView-outer" - ref={this.createDashEventsTarget} - 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, - }}> - {!this.practiceMessage && !this.filterMessage ? ( - this.content - ) : ( - <p - className="message" - onClick={e => { - if (this.filterMessage || this.practiceMessage) { - this.setPracticeMode(undefined); - Doc.setDocFilter(this.layoutDoc, 'tags', this.starField, 'remove'); - } - }}> - {this.filterMessage || this.practiceMessage} - </p> - )} + <div> + <div + className="collectionCarouselView-outer" + ref={this.createDashEventsTarget} + 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, + width: `calc(100% - ${NumCast(this.layoutDoc._xMargin)}px)`, + height: `calc(100% - ${NumCast(this.layoutDoc._yMargin)}px)`, + left: NumCast(this.layoutDoc._xMargin), + top: NumCast(this.layoutDoc._yMargin), + }}> + {!this.practiceMessage && !this.filterMessage ? ( + this.content + ) : ( + <p + className="message" + onClick={e => { + if (this.filterMessage || this.practiceMessage) { + this.setPracticeMode(undefined); + Doc.setDocFilter(this.layoutDoc, 'tags', Doc.FilterAny, 'remove'); + } + }}> + {this.filterMessage || this.practiceMessage} + </p> + )} + </div> {!this.Document._chromeHidden ? this.menu : null} {!this.Document._chromeHidden ? this.buttons : null} </div> diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 588073568..47cc07ce1 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -143,7 +143,7 @@ ScriptingGlobals.add(function showFreeform(attr: 'hcenter' | 'vcenter' | 'grid' } // prettier-ignore - const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag', + const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag', { waitForRender?: boolean; checkResult: (doc: Doc) => boolean; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index f54d8311d..b24fca8e2 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -90,7 +90,7 @@ export class LinkMenuItem extends ObservableReactComponent<LinkMenuItemProps> { moveEv => { const dragData = new DragManager.DocumentDragData([this._props.linkDoc], dropActionType.embed); dragData.dropPropertiesToRemove = ['hidden']; - DragManager.StartDocumentDrag([this._editRef.current!], dragData, moveEv.x, moveEv.y); + DragManager.StartDocumentDrag([this._editRef.current!], dragData, moveEv.x, moveEv.y, undefined, e => (this._props.linkDoc._layout_isSvg = true)); return true; }, emptyFunction, diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 9d9535abd..5ca4d048e 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -638,6 +638,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <DocumentView // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} + showTags={undefined} fitWidth={undefined} NativeHeight={returnZero} NativeWidth={returnZero} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index afc160297..9aa000ba7 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -129,6 +129,7 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte 'childContentPointerEvents', 'LayoutTemplateString', 'LayoutTemplate', + 'showTags', 'layoutFieldKey', 'dontCenter', 'DataTransition', diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx index 8faf8ffa5..ddabd61e1 100644 --- a/src/client/views/nodes/IconTagBox.tsx +++ b/src/client/views/nodes/IconTagBox.tsx @@ -67,7 +67,7 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> { render() { const buttons = Doc.MyFilterHotKeys .map(key => ({ key, tag: StrCast(key.toolType) })) - .filter(({ tag }) => this._props.IsEditing || TagItem.docHasTag(this.View.Document, tag) || (DocumentView.Selected.length === 1 && this.View.IsSelected)) + .filter(({ tag }) => this._props.IsEditing || TagItem.docHasTag(this.View.Document, tag) || (DocumentView.Selected().length === 1 && this.View.IsSelected)) .map(({ key, tag }) => ( <Tooltip key={tag} title={<div className="dash-tooltip">Click to add/remove this card from the {tag} group</div>}> <button diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 0dd9a9fc8..0f1609711 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1371,7 +1371,7 @@ export namespace Doc { if (!container) return; const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters'; const childFilters = StrListCast(container[filterField]); - return childFilters.some(filter => filter.split(FilterSep)[0] === key && (value === undefined || filter.split(FilterSep)[1] === value)); + return childFilters.some(filter => filter.split(FilterSep)[0] === key && (value === undefined || value === Doc.FilterAny || filter.split(FilterSep)[1] === value)); } // filters document in a container collection: @@ -1384,8 +1384,8 @@ export namespace Doc { runInAction(() => { for (let i = 0; i < childFilters.length; i++) { const fields = childFilters[i].split(FilterSep); // split key:value:modifier - if (fields[0] === key && (fields[1] === value?.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) { - if (fields[2] === modifiers && modifiers && fields[1] === value?.toString()) { + if (fields[0] === key && (fields[1] === value?.toString() || value === Doc.FilterAny || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) { + if (fields[2] === modifiers && modifiers && (fields[1] === value?.toString() || value === Doc.FilterAny)) { // eslint-disable-next-line no-param-reassign if (toggle) modifiers = 'remove'; else return; |