From 56116231c4c0aa78d54a9ed4c1f167514596953c Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 16 Nov 2022 23:27:05 -0500 Subject: added presEffects to link anchors --- src/client/util/DocumentManager.ts | 2 +- src/client/views/MainView.tsx | 1 + .../views/collections/CollectionDockingView.tsx | 7 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/linking/LinkEditor.tsx | 74 ++++++++++++++++++- src/client/views/nodes/DocumentView.scss | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/trails/PresBox.tsx | 86 ++++++++++++---------- src/fields/Doc.ts | 7 +- 9 files changed, 136 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a60c1ed6b..00f6bc40a 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -233,7 +233,7 @@ export class DocumentManager { } } if (focusView) { - !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox + !noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, targetDoc); //TODO:glr make this a setting in PresBox if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc); const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget ?? targetDoc, { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 987bfc23d..392b4eeeb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -484,6 +484,7 @@ export class MainView extends React.Component { } globalPointerDown = action((e: PointerEvent) => { + runInAction(() => (Doc.HighlightBrush.linkFollowEffect = undefined)); AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 92319d080..434466505 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -452,7 +452,7 @@ export class CollectionDockingView extends CollectionSubView() { .map(id => DocServer.GetCachedRefField(id)) .filter(f => f) .map(f => f as Doc); - const changesMade = this.props.Document.dockcingConfig !== json; + const changesMade = this.props.Document.dockingConfig !== json; if (changesMade && !this._flush) { UndoManager.RunInBatch(() => { this.props.Document.dockingConfig = json; @@ -507,7 +507,12 @@ export class CollectionDockingView extends CollectionSubView() { action(() => { //if (confirm('really close this?')) { if ((!stack.parent.isRoot && !stack.parent.parent.isRoot) || stack.parent.contentItems.length > 1) { + const batch = UndoManager.StartBatch('close stack'); stack.remove(); + setTimeout(() => { + this.stateChanged(); + batch.end(); + }); } else { alert('cant delete the last stack'); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 7bc273d7d..b66dc0aa2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -111,7 +111,7 @@ export function CollectionSubView(moreProps?: X) { rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : []; } - const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate).map(d => d as Doc); + const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && !d.unrendered).map(d => d as Doc); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 3e8867c50..d90a91ab7 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -3,13 +3,14 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, NumListCast, StrListCast, Field } from '../../../fields/Doc'; -import { DateCast, StrCast, Cast, BoolCast } from '../../../fields/Types'; +import { DateCast, StrCast, Cast, BoolCast, DocCast, NumCast } from '../../../fields/Types'; import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import './LinkEditor.scss'; import { LinkRelationshipSearch } from './LinkRelationshipSearch'; import React = require('react'); import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; +import { PresBox, PresEffect } from '../nodes/trails'; interface LinkEditorProps { sourceDoc: Doc; @@ -24,6 +25,7 @@ export class LinkEditor extends React.Component { @observable zoomFollow = BoolCast(this.props.sourceDoc.followLinkZoom); @observable audioFollow = BoolCast(this.props.sourceDoc.followLinkAudio); @observable openDropdown: boolean = false; + @observable openEffectDropdown: boolean = false; @observable private buttonColor: string = ''; @observable private relationshipButtonColor: string = ''; @observable private relationshipSearchVisibility: string = 'none'; @@ -295,6 +297,61 @@ export class LinkEditor extends React.Component { ); } + @computed get sourceAnchor() { + const ldoc = this.props.linkDoc; + if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + } + return this.props.sourceDoc; + } + @action + changeEffectDropdown = () => { + this.openEffectDropdown = !this.openEffectDropdown; + }; + + @undoBatch + changeEffect = action((follow: string) => { + this.openEffectDropdown = false; + this.sourceAnchor.presEffect = follow; + }); + + @computed + get effectDropdown() { + return ( +
+
Transition Effect:
+
+
+ {StrCast(this.sourceAnchor.presEffect, 'default')} + +
+
+ {[ + PresEffect.None, + PresEffect.Zoom, + PresEffect.Lightspeed, + PresEffect.Fade, + PresEffect.Flip, + PresEffect.Rotate, + PresEffect.Bounce, + PresEffect.Roll, + PresEffect.Left, + PresEffect.Right, + PresEffect.Center, + PresEffect.Top, + PresEffect.Bottom, + ].map(effect => ( +
this.changeEffect(effect.toString())}> + {effect.toString()} +
+ ))} +
+
+
+ ); + } + autoMove = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove)))); }; @@ -348,7 +405,6 @@ export class LinkEditor extends React.Component { ) : null} - {this.editDescription} {this.editRelationship} {this.editZoomFollow} @@ -390,6 +446,20 @@ export class LinkEditor extends React.Component { {this.followingDropdown} + {this.effectDropdown} + {PresBox.inputter('0.1', '0.1', '10', NumCast(this.sourceAnchor.presTransition) / 1000, true, (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => (this.sourceAnchor.presTransition = timeInMS)))} +
+
Fast
+
Medium
+
Slow
+
{' '} ); } diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 01188d3fa..abf6e37ab 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -28,7 +28,7 @@ transition: outline 0.3s linear; // background: $white; //overflow: hidden; - transform-origin: left top; + transform-origin: center; &.minimized { width: 30px; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index dc468cf89..fb07f1033 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; -import { observer } from 'mobx-react'; +import { observer, renderReporter } from 'mobx-react'; import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Document } from '../../../fields/documentSchemas'; import { Id } from '../../../fields/FieldSymbols'; @@ -1394,7 +1394,7 @@ export class DocumentViewInternal extends DocComponent() { * @param presEffectDoc presentation effects document that specifies the animation effect parameters * @returns a function that will wrap a JSX animation element wrapping any JSX element */ - public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc) { + public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc, root: Doc) { const effectProps = { - left: presEffectDoc.presEffectDirection === PresEffect.Left, - right: presEffectDoc.presEffectDirection === PresEffect.Right, - top: presEffectDoc.presEffectDirection === PresEffect.Top, - bottom: presEffectDoc.presEffectDirection === PresEffect.Bottom, + left: presEffectDoc?.presEffectDirection === PresEffect.Left, + right: presEffectDoc?.presEffectDirection === PresEffect.Right, + top: presEffectDoc?.presEffectDirection === PresEffect.Top, + bottom: presEffectDoc?.presEffectDirection === PresEffect.Bottom, opposite: true, - delay: NumCast(presEffectDoc.presTransition), + delay: 0, + duration: Cast(presEffectDoc?.presTransition, 'number', null), }; //prettier-ignore - switch (StrCast(presEffectDoc.presEffect)) { + switch (StrCast(presEffectDoc?.presEffect)) { default: case PresEffect.None: return renderDoc; case PresEffect.Zoom: return {renderDoc}; @@ -386,7 +388,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes.dataannos) { const fkey = Doc.LayoutFieldKey(bestTarget); - Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List(DocListCast(activeItem.presAnnotations)); + Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List([...DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered), ...DocListCast(activeItem.presAnnotations)]); } if (pinDataTypes.dataview && activeItem.presData !== undefined) { const fkey = Doc.LayoutFieldKey(bestTarget); @@ -465,7 +467,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations'])); + pinDoc.presAnnotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered)); } if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop; @@ -1095,12 +1097,15 @@ export class PresBox extends ViewBoxBaseComponent() { getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection // Converts seconds to ms and updates presTransition - setTransitionTime = (number: String, change?: number) => { + public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)); + setter(timeInMS); + }; + setTransitionTime = (number: String, change?: number) => { + PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change); }; // Converts seconds to ms and updates presTransition @@ -1165,6 +1170,28 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + let batch: any; + return ( + { + batch = UndoManager.StartBatch('pres slider'); + e.stopPropagation(); + }} + onPointerUp={() => batch?.end()} + onChange={e => { + e.stopPropagation(); + change(e.target.value); + }} + /> + ); + }; @computed get transitionDropdown() { const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; @@ -1180,39 +1207,18 @@ export class PresBox extends ViewBoxBaseComponent() { {movement} ); - const presDirection = (diretion: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = this.activeItem.presEffectDirection === diretion || (diretion === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + const presDirection = (direction: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === direction || (direction === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( - {diretion}}> + {direction}}>
this.updateEffectDirection(diretion)}> + style={{ ...opts, border: direction === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }} + onClick={() => this.updateEffectDirection(direction)}> {icon ? : null}
); }; - const inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { - return ( - { - this._batch = UndoManager.StartBatch('pres slider'); - e.stopPropagation(); - }} - onPointerUp={() => this._batch?.end()} - onChange={e => { - e.stopPropagation(); - change(e.target.value); - }} - /> - ); - }; if (activeItem && targetDoc) { const type = targetDoc.type; const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; @@ -1263,7 +1269,7 @@ export class PresBox extends ViewBoxBaseComponent() { - {inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)} + {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
Transition Speed
@@ -1278,7 +1284,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)} + {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)}
Fast
Medium
@@ -1331,7 +1337,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)} + {PresBox.inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
Short
Medium
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 70cb10970..75801b68c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1263,11 +1263,15 @@ export namespace Doc { export function linkFollowUnhighlight() { Doc.UnhighlightAll(); document.removeEventListener('pointerdown', linkFollowUnhighlight); + runInAction(() => (HighlightBrush.linkFollowEffect = undefined)); } let _lastDate = 0; - export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true) { + export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { linkFollowUnhighlight(); + // runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = undefined)); + // setTimeout(() => runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect))); + runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect)); (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs)); document.removeEventListener('pointerdown', linkFollowUnhighlight); document.addEventListener('pointerdown', linkFollowUnhighlight); @@ -1277,6 +1281,7 @@ export namespace Doc { export class HighlightBrush { @observable HighlightedDoc: Map = new Map(); + @observable static linkFollowEffect: Doc | undefined; } const highlightManager = new HighlightBrush(); export function IsHighlighted(doc: Doc) { -- cgit v1.2.3-70-g09d2