aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/trails/PresBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/trails/PresBox.tsx')
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx1893
1 files changed, 1182 insertions, 711 deletions
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 91fdb90fc..101f28ae7 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1,82 +1,74 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
+import Slider from '@mui/material/Slider';
+import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, DocListCast, Field, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
+import { AiOutlineSend } from 'react-icons/ai';
+import { BiMicrophone } from 'react-icons/bi';
+import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp } from 'react-icons/fa';
+import ReactLoading from 'react-loading';
+import ReactTextareaAutosize from 'react-textarea-autosize';
+import { lightOrDark, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../ClientUtils';
+import { Doc, DocListCast, Field, FieldResult, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc';
import { Animation, DocData, TransitionTimer } from '../../../../fields/DocSymbols';
-import { Copy, Id } from '../../../../fields/FieldSymbols';
+import { Copy } from '../../../../fields/FieldSymbols';
import { InkField } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { AudioField } from '../../../../fields/URLField';
-import { emptyFunction, emptyPath, lightOrDark, returnFalse, returnOne, setupMoveUpEvents, StopEvent, stringHash } from '../../../../Utils';
+import { BoolCast, Cast, DocCast, NumCast, StrCast, toList } from '../../../../fields/Types';
+import { emptyFunction, emptyPath, stringHash } from '../../../../Utils';
+import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization';
import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
-import { DocumentManager } from '../../../util/DocumentManager';
-import { dropActionType } from '../../../util/DragManager';
+import { DictationManager } from '../../../util/DictationManager';
+import { dropActionType } from '../../../util/DropActionTypes';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
-import { SelectionManager } from '../../../util/SelectionManager';
import { SerializationHelper } from '../../../util/SerializationHelper';
-import { SettingsManager } from '../../../util/SettingsManager';
+import { SnappingManager } from '../../../util/SnappingManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
-import { CollectionDockingView } from '../../collections/CollectionDockingView';
-import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm';
-import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
+import { CollectionFreeFormPannableContents } from '../../collections/collectionFreeForm/CollectionFreeFormPannableContents';
import { CollectionView } from '../../collections/CollectionView';
import { TreeView } from '../../collections/TreeView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
-import { LightboxView } from '../../LightboxView';
-import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
-import { FieldView, FieldViewProps, FocusViewOptions } from '../FieldView';
+import { pinDataTypes as dataTypes } from '../../PinFuncs';
+import { DocumentView } from '../DocumentView';
+import { FieldView, FieldViewProps } from '../FieldView';
+import { FocusViewOptions } from '../FocusViewOptions';
+import { OpenWhere, OpenWhereMod } from '../OpenWhere';
import { ScriptingBox } from '../ScriptingBox';
+import CubicBezierEditor, { EaseFuncToPoints, TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
-export interface pinDataTypes {
- scrollable?: boolean;
- dataviz?: number[];
- pannable?: boolean;
- type_collection?: boolean;
- inkable?: boolean;
- filters?: boolean;
- pivot?: boolean;
- temporal?: boolean;
- clippable?: boolean;
- datarange?: boolean;
- dataview?: boolean;
- poslayoutview?: boolean;
- dataannos?: boolean;
- map?: boolean;
-}
-export interface PinProps {
- audioRange?: boolean;
- activeFrame?: number;
- currentFrame?: number;
- hidePresBox?: boolean;
- pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected)
- pinDocLayout?: boolean; // pin layout info (width/height/x/y)
- pinAudioPlay?: boolean; // pin audio annotation
- pinData?: pinDataTypes;
-}
+import SlideEffect from './SlideEffect';
+import { AnimationSettings, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors, SpringSettings, SpringType } from './SpringUtils';
@observer
export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(PresBox, fieldKey);
}
+ private static _getTabDocs: () => Doc[];
+ public static Init(tabDocs: () => Doc[]) {
+ PresBox._getTabDocs = tabDocs;
+ }
static navigateToDocScript: ScriptField;
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
if (!PresBox.navigateToDocScript) {
- PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(this.presentation_targetDoc, self)')!;
+ PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(this.presentation_targetDoc, this)')!;
}
+ CollectionFreeFormPannableContents.SetOverlayPlugin((fform: Doc) => PresBox.Instance.pathLines(fform));
}
private _disposers: { [name: string]: IReactionDisposer } = {};
@@ -86,6 +78,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
_unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things
_presTimer: NodeJS.Timeout | undefined;
+ // eslint-disable-next-line no-use-before-define
@observable public static Instance: PresBox;
@observable _isChildActive = false;
@@ -104,7 +97,100 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@observable _treeViewMap: Map<Doc, number> = new Map();
@observable _presKeyEvents: boolean = false;
@observable _forceKeyEvents: boolean = false;
- @computed get isTreeOrStack() {
+
+ // GPT
+ private _inputref: HTMLTextAreaElement | null = null;
+ private _inputref2: HTMLTextAreaElement | null = null;
+ @observable chatActive: boolean = false;
+ @observable chatInput: string = '';
+ public slideToModify: Doc | null = null;
+ @observable isRecording: boolean = false;
+ @observable isLoading: boolean = false;
+
+ @observable generatedAnimations: AnimationSettings[] = [
+ // default presets
+ {
+ effect: PresEffect.Bounce,
+ direction: PresEffectDirection.Left,
+ stiffness: 400,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Fade,
+ direction: PresEffectDirection.Left,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Flip,
+ direction: PresEffectDirection.Left,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Rotate,
+ direction: PresEffectDirection.Left,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ ];
+
+ @action
+ setGeneratedAnimations = (settings: AnimationSettings[]) => {
+ this.generatedAnimations = settings;
+ };
+
+ @observable animationChat: string = '';
+
+ @action
+ setChatInput = (input: string) => {
+ this.chatInput = input;
+ };
+
+ @action
+ setAnimationChat = (input: string) => {
+ this.animationChat = input;
+ };
+
+ @action
+ setIsLoading = (isLoading: boolean) => {
+ this.isLoading = isLoading;
+ };
+
+ @action
+ public setIsRecording = (isRecording: boolean) => {
+ this.isRecording = isRecording;
+ };
+
+ @observable showBezierEditor = false;
+ @action setBezierEditorVisibility = (visible: boolean) => {
+ this.showBezierEditor = visible;
+ };
+ @observable showSpringEditor = true;
+ @action setSpringEditorVisibility = (visible: boolean) => {
+ this.showSpringEditor = visible;
+ };
+
+ // Easing function variables
+
+ @observable easeDropdownVal = 'ease';
+
+ @action setBezierControlPoints = (newPoints: { p1: number[]; p2: number[] }) => {
+ this.setEaseFunc(this.activeItem, `cubic-bezier(${newPoints.p1[0]}, ${newPoints.p1[1]}, ${newPoints.p2[0]}, ${newPoints.p2[1]})`);
+ };
+
+ @computed
+ get currCPoints() {
+ const strPoints = this.activeItem.presentation_easeFunc ? StrCast(this.activeItem.presentation_easeFunc) : 'ease';
+ return EaseFuncToPoints(strPoints);
+ }
+
+ @computed
+ get isTreeOrStack() {
return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._type_collection) as any);
}
@computed get isTree() {
@@ -126,7 +212,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return DocCast(this.childDocs[NumCast(this.Document._itemIndex)]);
}
@computed get targetDoc() {
- return Cast(this.activeItem?.presentation_targetDoc, Doc, null);
+ return DocCast(this.activeItem?.presentation_targetDoc);
}
public static targetRenderedDoc = (doc: Doc) => {
const targetDoc = Cast(doc?.presentation_targetDoc, Doc, null);
@@ -141,8 +227,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return false;
}
@computed get selectedDocumentView() {
- if (SelectionManager.Views.length) return SelectionManager.Views[0];
- if (this.selectedArray.size) return DocumentManager.Instance.getDocumentView(this.Document);
+ if (DocumentView.Selected().length) return DocumentView.Selected()[0];
+ if (this.selectedArray.size) return DocumentView.getDocumentView(this.Document);
+ return undefined;
}
@computed get isPres() {
return this.selectedDoc === this.Document;
@@ -165,6 +252,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
componentDidMount() {
+ this._disposers.pause = reaction(
+ () => SnappingManager.UserPanned,
+ () => this.pauseAutoPres()
+ );
this._disposers.keyboard = reaction(
() => this.selectedDoc,
selected => {
@@ -189,7 +280,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._unmounting = false;
this.turnOffEdit(true);
this._disposers.selection = reaction(
- () => SelectionManager.Views.slice(),
+ () => DocumentView.Selected().slice(),
views => (!PresBox.Instance || views.some(view => view.Document === this.Document)) && this.updateCurrentPresentation(),
{ fireImmediately: true }
);
@@ -197,7 +288,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
() => this.layoutDoc.presentation_status === PresStatus.Edit,
editing => editing &&
this.childDocs.filter(doc => doc.presentation_indexed !== undefined).forEach(doc => {
- this.progressivizedItems(doc)?.forEach(indexedDoc => (indexedDoc.opacity = undefined));
+ this.progressivizedItems(doc)?.forEach(indexedDoc => { indexedDoc.opacity = undefined; });
doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1);
}) // prettier-ignore
);
@@ -214,7 +305,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
startTempMedia = (targetDoc: Doc, activeItem: Doc) => {
const duration: number = NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart);
if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
- const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
+ const targMedia = DocumentView.getDocumentView(targetDoc);
targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.config_clipStart), NumCast(activeItem.config_clipStart) + duration);
}
};
@@ -222,18 +313,97 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
stopTempMedia = (targetDocField: FieldResult) => {
const targetDoc = DocCast(DocCast(targetDocField).annotationOn) ?? DocCast(targetDocField);
if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
- const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
+ const targMedia = DocumentView.getDocumentView(targetDoc);
targMedia?.ComponentView?.Pause?.();
}
};
- //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
+ // Recording for GPT customization
+
+ recordDictation = () => {
+ this.setIsRecording(true);
+ this.setChatInput('');
+ DictationManager.Controls.listen({
+ interimHandler: this.setDictationContent,
+ continuous: { indefinite: false },
+ }).then(results => {
+ if (results && [DictationManager.Controls.Infringed].includes(results)) {
+ DictationManager.Controls.stop();
+ }
+ });
+ };
+ stopDictation = () => {
+ this.setIsRecording(false);
+ DictationManager.Controls.stop();
+ };
+
+ setDictationContent = (value: string) => {
+ console.log('Dictation value', value);
+ this.setChatInput(value);
+ };
+
+ @action
+ customizeAnimations = async () => {
+ this.setIsLoading(true);
+ try {
+ const res = await getSlideTransitionSuggestions(this.animationChat);
+ if (typeof res === 'string') {
+ const resObj = JSON.parse(res);
+ console.log('Parsed GPT Result ', resObj);
+ this.setGeneratedAnimations(resObj as AnimationSettings[]);
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ this.setIsLoading(false);
+ };
+
+ @action
+ customizeWithGPT = async (input: string) => {
+ // const testInput = 'change title to Customized Slide, transition for 2.3s with fade in effect';
+ this.setIsRecording(false);
+ this.setIsLoading(true);
+
+ const currSlideProperties: { [key: string]: any } = {};
+ gptSlideProperties.forEach(key => {
+ if (this.activeItem[key]) {
+ currSlideProperties[key] = this.activeItem[key];
+ }
+ // default values
+ else if (key === 'presentation_transition') {
+ currSlideProperties[key] = 500;
+ } else if (key === 'config_zoom') {
+ currSlideProperties[key] = 1.0;
+ }
+ });
+ console.log('current slide props ', currSlideProperties);
+
+ try {
+ const res = await gptTrailSlideCustomization(input, currSlideProperties);
+ if (typeof res === 'string') {
+ const resObj = JSON.parse(res);
+ console.log('Parsed GPT Result ', resObj);
+ // eslint-disable-next-line no-restricted-syntax
+ for (const key in resObj) {
+ if (resObj[key]) {
+ console.log('typeof property', typeof resObj[key]);
+ this.activeItem[key] = resObj[key];
+ }
+ }
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ this.setIsLoading(false);
+ };
+
+ // TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
// TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
// No more frames in current doc and next slide is defined, therefore move to next slide
nextSlide = (slideNum?: number) => {
const nextSlideInd = slideNum ?? this.itemIndex + 1;
let curSlideInd = nextSlideInd;
- //CollectionStackedTimeline.CurrentlyPlaying?.map(clipView => clipView?.ComponentView?.Pause?.());
+ // CollectionStackedTimeline.CurrentlyPlaying?.map(clipView => clipView?.ComponentView?.Pause?.());
this.clearSelectedArray();
const doGroupWithUp =
(nextSelected: number, force = false) =>
@@ -245,7 +415,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (serial) {
this.gotoDocument(nextSelected, this.activeItem, true, async () => {
const waitTime = NumCast(this.activeItem.presentation_duration);
- await new Promise<void>(res => setTimeout(() => res(), Math.max(0, waitTime)));
+ await new Promise<void>(res => {
+ setTimeout(res, Math.max(0, waitTime));
+ });
doGroupWithUp(nextSelected + 1)();
});
} else {
@@ -264,14 +436,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const targetList = PresBox.targetRenderedDoc(doc);
if (doc.presentation_indexed !== undefined && targetList) {
const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '_annotations']);
- return listItems.filter(doc => !doc.layout_unrendered);
+ return listItems.filter(ldoc => !ldoc.layout_unrendered);
}
+ return undefined;
};
// go to documents chain
runSubroutines = (childrenToRun: Opt<Doc[]>, normallyNextSlide: Doc) => {
if (childrenToRun && childrenToRun[0] !== normallyNextSlide) {
- childrenToRun.forEach(child => DocumentManager.Instance.showDocument(child, {}));
+ childrenToRun.forEach(child => DocumentView.showDocument(child, {}));
}
};
@@ -284,12 +457,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem);
targetRenderedDoc._dataTransition = 'all 1s';
targetRenderedDoc.opacity = 1;
- setTimeout(() => (targetRenderedDoc._dataTransition = 'inherit'), 1000);
+ setTimeout(() => {
+ targetRenderedDoc._dataTransition = 'inherit';
+ }, 1000);
const listItems = this.progressivizedItems(this.activeItem);
if (listItems && presIndexed < listItems.length) {
if (!first) {
const listItemDoc = listItems[presIndexed];
- const targetView = listItems && DocumentManager.Instance.getFirstDocumentView(listItemDoc);
+ const targetView = listItems && DocumentView.getFirstDocumentView(listItemDoc);
Doc.linkFollowUnhighlight();
Doc.HighlightDoc(listItemDoc);
listItemDoc.presentation_effect = this.activeItem.presBulletEffect;
@@ -305,6 +480,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return true;
}
}
+ return undefined;
};
if (progressiveReveal(false)) return true;
if (this.childDocs[this.itemIndex + 1] !== undefined) {
@@ -314,7 +490,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// before moving onto next slide, run the subroutines :)
const currentDoc = this.childDocs[this.itemIndex];
- //could i do this.childDocs[this.itemIndex] for first arg?
+ // could i do this.childDocs[this.itemIndex] for first arg?
this.runSubroutines(TreeView.GetRunningChildren.get(currentDoc)?.(), this.childDocs[this.itemIndex + 1]);
this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1);
@@ -334,7 +510,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Called when the user activates 'back' - to move to the previous part of the pres. trail
@action
back = () => {
- const activeItem: Doc = this.activeItem;
+ const { activeItem } = this;
let prevSelected = this.itemIndex;
// Functionality for group with up
let didZoom = activeItem.presentation_movement;
@@ -353,8 +529,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return this.itemIndex;
};
- //The function that is called when a document is clicked or reached through next or back.
- //it'll also execute the necessary actions if presentation is playing.
+ // The function that is called when a document is clicked or reached through next or back.
+ // it'll also execute the necessary actions if presentation is playing.
@undoBatch
public gotoDocument = action((index: number, from?: Doc, group?: boolean, finished?: () => void) => {
Doc.UnBrushAllDocs();
@@ -371,13 +547,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.startTempMedia(this.targetDoc, this.activeItem);
}
if (!group) this.clearSelectedArray();
- this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array
+ this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); // Update selected array
this.turnOffEdit();
- this.navigateToActiveItem(finished); //Handles movement to element only when presentationTrail is list
- this.doHideBeforeAfter(); //Handles hide after/before
+ this.navigateToActiveItem(finished); // Handles movement to element only when presentationTrail is list
+ this.doHideBeforeAfter(); // Handles hide after/before
}
});
- static pinDataTypes(target?: Doc): pinDataTypes {
+ static pinDataTypes(target?: Doc): dataTypes {
const targetType = target?.type as any;
const inkable = [DocumentType.INK].includes(targetType);
const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._type_collection === CollectionViewType.Stacking;
@@ -388,19 +564,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const datarange = [DocumentType.FUNCPLOT].includes(targetType);
const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG, DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined;
const poslayoutview = [DocumentType.COL].includes(targetType) && target?.activeFrame === undefined;
- const type_collection = targetType === DocumentType.COL;
+ const typeCollection = targetType === DocumentType.COL;
const filters = true;
const pivot = true;
const dataannos = false;
- return { scrollable, pannable, inkable, type_collection, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
+ return { scrollable, pannable, inkable, type_collection: typeCollection, pivot, map, filters, temporal, clippable, dataview, datarange, poslayoutview, dataannos };
}
@action
- playAnnotation = (anno: AudioField) => {};
+ playAnnotation = (/* anno: AudioField */) => {
+ /* empty */
+ };
@action
- static restoreTargetDocView(bestTargetView: Opt<DocumentView>, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) {
+ // eslint-disable-next-line default-param-last
+ static restoreTargetDocView(bestTargetView: Opt<DocumentView>, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.config_pinLayout), pinDataTypes?: dataTypes, targetDoc?: Doc) {
const bestTarget = bestTargetView?.Document ?? (targetDoc?.layout_unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc);
- if (!bestTarget) return;
+ if (!bestTarget) return undefined;
let changed = false;
if (pinDocLayout) {
if (
@@ -417,20 +596,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
bestTarget.width = NumCast(activeItem.config_width, NumCast(bestTarget.width));
bestTarget.height = NumCast(activeItem.config_height, NumCast(bestTarget.height));
bestTarget[TransitionTimer] && clearTimeout(bestTarget[TransitionTimer]);
- bestTarget[TransitionTimer] = setTimeout(() => (bestTarget[TransitionTimer] = bestTarget._dataTransition = undefined), transTime + 10);
+ bestTarget[TransitionTimer] = setTimeout(() => {
+ bestTarget[TransitionTimer] = bestTarget._dataTransition = undefined;
+ }, transTime + 10);
changed = true;
}
}
const activeFrame = activeItem.config_activeFrame ?? activeItem.config_currentFrame;
if (activeFrame !== undefined) {
- const transTime = NumCast(activeItem.presentation_transition, 500);
+ const frameTime = NumCast(activeItem.presentation_transition, 500);
const acontext = activeItem.config_activeFrame !== undefined ? DocCast(DocCast(activeItem.presentation_targetDoc).embedContainer) : DocCast(activeItem.presentation_targetDoc);
const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext;
if (context) {
- const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.CollectionFreeFormView;
+ const ffview = CollectionFreeFormView.from(DocumentView.getFirstDocumentView(context));
if (ffview?.childDocs) {
- PresBox.Instance._keyTimer = CollectionFreeFormView.gotoKeyframe(PresBox.Instance._keyTimer, ffview.childDocs, transTime);
+ PresBox.Instance._keyTimer = CollectionFreeFormView.gotoKeyframe(PresBox.Instance._keyTimer, ffview.childDocs, frameTime);
ffview.layoutDoc._currentFrame = NumCast(activeFrame);
}
}
@@ -443,12 +624,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
else {
const bestTargetData = bestTarget[DocData];
const current = bestTargetData[fkey];
- const hash = bestTargetData[fkey] ? stringHash(Field.toString(bestTargetData[fkey] as Field)) : undefined;
+ const hash = bestTargetData[fkey] ? stringHash(Field.toString(bestTargetData[fkey] as FieldType)) : undefined;
if (hash) bestTargetData[fkey + '_' + hash] = current instanceof ObjectField ? current[Copy]() : current;
bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data;
}
bestTarget[fkey + '_usePath'] = activeItem.config_usePath;
- setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
+ setTimeout(() => {
+ bestTarget._dataTransition = undefined;
+ }, transTime + 10);
}
if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.config_xRange !== undefined)) {
if (bestTarget.xRange !== activeItem.config_xRange) {
@@ -590,7 +773,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
Doc.AddDocToList(bestTarget[DocData], layoutField, doc);
}
});
- setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10);
+ setTimeout(
+ () =>
+ Array.from(transitioned).forEach(
+ action(doc => {
+ doc._dataTransition = undefined;
+ })
+ ),
+ transTime + 10
+ );
}
if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.config_viewBounds !== undefined || activeItem.config_panX !== undefined || activeItem.config_viewScale !== undefined))) && !bestTarget.isGroup) {
const contentBounds = Cast(activeItem.config_viewBounds, listSpec('number'));
@@ -598,132 +789,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] };
bestTarget._freeform_panX = viewport.panX;
bestTarget._freeform_panY = viewport.panY;
- const dv = DocumentManager.Instance.getDocumentView(bestTarget);
+ const dv = DocumentView.getDocumentView(bestTarget);
if (dv) {
changed = true;
const computedScale = NumCast(activeItem.config_zoom, 1) * Math.min(dv._props.PanelWidth() / viewport.width, dv._props.PanelHeight() / viewport.height);
activeItem.presentation_movement === PresMovement.Zoom && (bestTarget._freeform_scale = computedScale);
dv.ComponentView?.brushView?.(viewport, transTime, 2500);
}
- } else {
- if (bestTarget._freeform_panX !== activeItem.config_panX || bestTarget._freeform_panY !== activeItem.config_panY || bestTarget._freeform_scale !== activeItem.config_viewScale) {
- bestTarget._freeform_panX = activeItem.config_panX ?? bestTarget._freeform_panX;
- bestTarget._freeform_panY = activeItem.config_panY ?? bestTarget._freeform_panY;
- bestTarget._freeform_scale = activeItem.config_viewScale ?? bestTarget._freeform_scale;
- changed = true;
- }
+ } else if (bestTarget._freeform_panX !== activeItem.config_panX || bestTarget._freeform_panY !== activeItem.config_panY || bestTarget._freeform_scale !== activeItem.config_viewScale) {
+ bestTarget._freeform_panX = activeItem.config_panX ?? bestTarget._freeform_panX;
+ bestTarget._freeform_panY = activeItem.config_panY ?? bestTarget._freeform_panY;
+ bestTarget._freeform_scale = activeItem.config_viewScale ?? bestTarget._freeform_scale;
+ changed = true;
}
}
if (changed) {
return bestTargetView?.setViewTransition('all', transTime);
}
- }
-
- /// copies values from the targetDoc (which is the prototype of the pinDoc) to
- /// reserved fields on the pinDoc so that those values can be restored to the
- /// target doc when navigating to it.
- @action
- static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) {
- pinDoc.presentation = true;
- pinDoc.config = '';
- if (pinProps.pinDocLayout) {
- pinDoc.config_pinLayout = true;
- pinDoc.config_x = NumCast(targetDoc.x);
- pinDoc.config_y = NumCast(targetDoc.y);
- pinDoc.config_rotation = NumCast(targetDoc.rotation);
- pinDoc.config_width = NumCast(targetDoc.width);
- pinDoc.config_height = NumCast(targetDoc.height);
- }
- if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true;
- if (pinProps.pinData) {
- pinDoc.config_pinData =
- pinProps.pinData.scrollable ||
- pinProps.pinData.temporal ||
- pinProps.pinData.pannable ||
- pinProps.pinData.type_collection ||
- pinProps.pinData.clippable ||
- pinProps.pinData.datarange ||
- pinProps.pinData.dataview ||
- pinProps.pinData.poslayoutview ||
- pinProps?.activeFrame !== undefined;
- const fkey = Doc.LayoutFieldKey(targetDoc);
- if (pinProps.pinData.dataview) {
- pinDoc.config_usePath = targetDoc[fkey + '_usePath'];
- pinDoc.config_data = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
- }
- if (pinProps.pinData.dataannos) {
- const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.config_annotations = new List<Doc>(DocListCast(targetDoc[DocData][fkey + '_annotations']).filter(doc => !doc.layout_unrendered));
- }
- if (pinProps.pinData.inkable) {
- pinDoc.config_fillColor = targetDoc.fillColor;
- pinDoc.config_color = targetDoc.color;
- pinDoc.config_width = targetDoc._width;
- pinDoc.config_height = targetDoc._height;
- }
- if (pinProps.pinData.scrollable) pinDoc.config_scrollTop = targetDoc._layout_scrollTop;
- if (pinProps.pinData.clippable) {
- const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.config_clipWidth = targetDoc[fkey + '_clipWidth'];
- }
- if (pinProps.pinData.datarange) {
- pinDoc.config_xRange = undefined; //targetDoc?.xrange;
- pinDoc.config_yRange = undefined; //targetDoc?.yrange;
- }
- if (pinProps.pinData.map) {
- // pinDoc.config_latitude = targetDoc?.latitude;
- // pinDoc.config_longitude = targetDoc?.longitude;
- pinDoc.config_map_zoom = targetDoc?.map_zoom;
- pinDoc.config_map_type = targetDoc?.map_type;
- //...
- }
- if (pinProps.pinData.poslayoutview)
- pinDoc.config_pinLayoutData = new List<string>(
- DocListCast(targetDoc[fkey] as ObjectField).map(d =>
- JSON.stringify({
- id: d[Id],
- x: NumCast(d.x),
- y: NumCast(d.y),
- w: NumCast(d._width),
- h: NumCast(d._height),
- fill: StrCast(d._fillColor),
- back: StrCast(d._backgroundColor),
- data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''),
- text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''),
- })
- )
- );
- if (pinProps.pinData.type_collection) pinDoc.config_viewType = targetDoc._type_collection;
- if (pinProps.pinData.filters) pinDoc.config_docFilters = ObjectField.MakeCopy(targetDoc.childFilters as ObjectField);
- if (pinProps.pinData.pivot) pinDoc.config_pivotField = targetDoc._pivotField;
- if (pinProps.pinData.pannable) {
- pinDoc.config_panX = NumCast(targetDoc._freeform_panX);
- pinDoc.config_panY = NumCast(targetDoc._freeform_panY);
- pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1);
- }
- if (pinProps.pinData.temporal) {
- pinDoc.config_clipStart = targetDoc._layout_currentTimecode;
- const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], NumCast(targetDoc.config_clipStart) + 0.1);
- pinDoc.config_clipEnd = NumCast(pinDoc.config_clipStart) + NumCast(targetDoc.clipEnd, duration);
- }
- }
- if (pinProps?.pinViewport) {
- // If pinWithView option set then update scale and x / y props of slide
- const bounds = pinProps.pinViewport;
- pinDoc.config_pinView = true;
- pinDoc.config_viewScale = NumCast(targetDoc._freeform_scale, 1);
- pinDoc.config_panX = bounds.left + bounds.width / 2;
- pinDoc.config_panY = bounds.top + bounds.height / 2;
- pinDoc.config_viewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
- }
- }
-
- @action
- static reversePin(pinDoc: Doc, targetDoc: Doc) {
- // const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.config_data = targetDoc.data;
-
- console.log(pinDoc.presData);
+ return undefined;
}
/**
@@ -735,8 +818,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
* on the right.
*/
navigateToActiveItem = (afterNav?: () => void) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
+ const { activeItem, targetDoc } = this;
const finished = () => {
afterNav?.();
targetDoc[Animation] = undefined;
@@ -746,8 +828,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const eleViewCache = Array.from(this._eleArray);
const resetSelection = action(() => {
if (!this._props.isSelected()) {
- const presDocView = DocumentManager.Instance.getDocumentView(this.Document);
- if (presDocView) SelectionManager.SelectView(presDocView, false);
+ const presDocView = DocumentView.getDocumentView(this.Document);
+ if (presDocView) DocumentView.SelectView(presDocView, false);
this.clearSelectedArray();
selViewCache.forEach(doc => this.addToSelectedArray(doc));
this._dragArray.splice(0, this._dragArray.length, ...dragViewCache);
@@ -762,10 +844,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) {
if (activeItem.presentation_movement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) {
- (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
+ (DocumentView.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
return;
}
const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined;
+ // default with effect: 750ms else 500ms
const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500);
const options: FocusViewOptions = {
willPan: activeItem.presentation_movement !== PresMovement.None,
@@ -775,27 +858,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
effect: activeItem,
noSelect: true,
openLocation: targetDoc.type === DocumentType.PRES ? ((OpenWhere.replace + ':' + PresBox.PanelName) as OpenWhere) : OpenWhere.addLeft,
- anchorDoc: activeItem,
- easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any,
+ easeFunc: StrCast(activeItem.presentation_easeFunc, 'ease') as any,
zoomTextSelections: BoolCast(activeItem.presentation_zoomText),
- playAudio: BoolCast(activeItem.presPlayAudio),
+ playAudio: BoolCast(activeItem.presentation_playAudio),
playMedia: activeItem.presentation_mediaStart === 'auto',
};
if (activeItem.presentation_openInLightbox) {
const context = DocCast(targetDoc.annotationOn) ?? targetDoc;
- if (!DocumentManager.Instance.getLightboxDocumentView(context)) {
- LightboxView.Instance.SetLightboxDoc(context);
+ if (!DocumentView.getLightboxDocumentView(context)) {
+ DocumentView.SetLightboxDoc(context);
}
}
if (targetDoc) {
if (activeItem.presentation_targetDoc instanceof Doc) activeItem.presentation_targetDoc[Animation] = undefined;
- DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => {
+ DocumentView.addViewRenderedCb(DocumentView.LightboxDoc(), () => {
// if target or the doc it annotates is not in the lightbox, then close the lightbox
- if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(targetDoc.annotationOn) ?? targetDoc)) {
- LightboxView.Instance.SetLightboxDoc(undefined);
+ if (!DocumentView.getLightboxDocumentView(DocCast(targetDoc.annotationOn) ?? targetDoc)) {
+ DocumentView.SetLightboxDoc(undefined);
}
- DocumentManager.Instance.showDocument(targetDoc, options, finished);
+ DocumentView.showDocument(targetDoc, options, finished);
});
} else finished?.();
}
@@ -822,7 +904,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
opacity = 0;
} else if (index === this.itemIndex || !curDoc.presentation_hideAfter) {
opacity = 1;
- setTimeout(() => (tagDoc._dataTransition = undefined), 1000);
+ setTimeout(() => {
+ tagDoc._dataTransition = undefined;
+ }, 1000);
}
}
const hidingIndAft =
@@ -848,16 +932,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
_exitTrail: Opt<() => void>;
- PlayTrail = (docs: Doc[]) => {
+ playTrail = (docs: Doc[]) => {
const savedStates = docs.map(doc => {
switch (doc.type) {
case DocumentType.COL:
- if (doc._type_collection === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.freeform_panX), y: NumCast(doc.freeform_panY), s: NumCast(doc.freeform_scale) };
+ if (doc._type_collection === CollectionViewType.Freeform) {
+ return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.freeform_panX), y: NumCast(doc.freeform_panY), s: NumCast(doc.freeform_scale) };
+ }
break;
case DocumentType.INK:
if (doc.data instanceof InkField) {
return { type: doc.type, doc, data: doc.data?.[Copy](), fillColor: doc.fillColor, color: doc.color, x: NumCast(doc.x), y: NumCast(doc.y) };
}
+ break;
+ default:
}
return undefined;
});
@@ -865,7 +953,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._exitTrail = () => {
savedStates
.filter(savedState => savedState)
- .map(savedState => {
+ .forEach(savedState => {
switch (savedState?.type) {
case CollectionViewType.Freeform:
{
@@ -885,9 +973,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
doc.color = color;
}
break;
+ default:
}
});
- LightboxView.Instance.SetLightboxDoc(undefined);
+ DocumentView.SetLightboxDoc(undefined);
Doc.RemFromMyOverlay(this.Document);
return PresStatus.Edit;
};
@@ -903,8 +992,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- //The function that resets the presentation by removing every action done by it. It also
- //stops the presentaton.
+ // The function that resets the presentation by removing every action done by it. It also
+ // stops the presentaton.
resetPresentation = () => {
this.childDocs
.map(doc => PresBox.targetRenderedDoc(doc))
@@ -921,12 +1010,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// The function allows for viewing the pres path on toggle
@action togglePath = (off?: boolean) => {
this._pathBoolean = off ? false : !this._pathBoolean;
- CollectionFreeFormView.ShowPresPaths = this._pathBoolean;
+ SnappingManager.SetShowPresPaths(this._pathBoolean);
};
// The function allows for expanding the view of pres on toggle
@action toggleExpandMode = () => {
- runInAction(() => (this._expandBoolean = !this._expandBoolean));
+ runInAction(() => {
+ this._expandBoolean = !this._expandBoolean;
+ });
this.Document.expandBoolean = this._expandBoolean;
this.childDocs.forEach(doc => {
doc.presentation_expandInlineButton = this._expandBoolean;
@@ -942,7 +1033,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const startInd = NumCast(doc.presentation_indexedStart);
this.progressivizedItems(doc)
?.slice(startInd)
- .forEach(indexedDoc => (indexedDoc.opacity = 0));
+ .forEach(indexedDoc => {
+ indexedDoc.opacity = 0;
+ });
doc.presentation_indexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd);
}
// if (doc.presentation_hide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0;
@@ -986,20 +1079,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
exitMinimize = () => {
if (Doc.IsInMyOverlay(this.layoutDoc)) {
Doc.RemFromMyOverlay(this.Document);
- CollectionDockingView.AddSplit(this.Document, OpenWhereMod.right);
+ DocumentView.addSplit(this.Document, OpenWhereMod.right);
}
return PresStatus.Edit;
};
public static minimizedWidth = 198;
public static OpenPresMinimized(doc: Doc, pt: number[]) {
- doc.overlayX = pt[0];
- doc.overlayY = pt[1];
+ [doc.overlayX, doc.overlayY] = pt;
doc._height = 30;
doc._width = PresBox.minimizedWidth;
Doc.AddToMyOverlay(doc);
PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex);
- return (doc.presentation_status = PresStatus.Manual);
+ doc.presentation_status = PresStatus.Manual;
+ return doc.presentation_status;
}
/**
@@ -1008,12 +1101,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
@undoBatch
viewChanged = action((e: React.ChangeEvent) => {
- //@ts-ignore
- const type_collection = e.target.selectedOptions[0].value as CollectionViewType;
- this.layoutDoc.presFieldKey = this.fieldKey + (type_collection === CollectionViewType.Tree ? '-linearized' : '');
+ const typeCollection = (e.target as any).selectedOptions[0].value as CollectionViewType;
+ this.layoutDoc.presFieldKey = this.fieldKey + (typeCollection === CollectionViewType.Tree ? '-linearized' : '');
// pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
- [CollectionViewType.Tree || CollectionViewType.Stacking].includes(type_collection) && (this.Document._pivotField = undefined);
- this.Document._type_collection = type_collection;
+ [CollectionViewType.Tree || CollectionViewType.Stacking].includes(typeCollection) && (this.Document._pivotField = undefined);
+ this.Document._type_collection = typeCollection;
if (this.isTreeOrStack) {
this.layoutDoc._gridGap = 0;
}
@@ -1025,10 +1117,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
// @undoBatch
mediaStopChanged = action((e: React.ChangeEvent) => {
- const activeItem: Doc = this.activeItem;
- //@ts-ignore
- const stopDoc = e.target.selectedOptions[0].value as string;
- const stopDocIndex: number = Number(stopDoc[0]);
+ const { activeItem } = this;
+ const stopDoc = (e.target as any).selectedOptions[0].value as string;
+ const stopDocIndex = Number(stopDoc[0]);
activeItem.mediaStopDoc = stopDocIndex;
if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
@@ -1049,10 +1140,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return StrCast(activeItem.presentation_movement);
});
- whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isChildActive = isActive)));
+ whenChildContentsActiveChanged = action((isActive: boolean) => {
+ this._props.whenChildContentsActiveChanged((this._isChildActive = isActive));
+ });
// For dragging documents into the presentation trail
addDocumentFilter = (docs: Doc[]) => {
- docs.forEach((doc, i) => {
+ const results = docs.map(doc => {
if (doc.presentation_targetDoc) return true;
if (doc.type === DocumentType.LABEL) {
const audio = Cast(doc.annotationOn, Doc, null);
@@ -1065,17 +1158,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return false;
}
} else if (doc.type !== DocumentType.PRES) {
+ // eslint-disable-next-line operator-assignment
if (!doc.presentation_targetDoc) doc.title = doc.title + ' - Slide';
doc.presentation_targetDoc = doc.createdFrom ?? doc; // dropped document will be a new embedding of an embedded document somewhere else.
doc.presentation_movement = PresMovement.Zoom;
if (this._expandBoolean) doc.presentation_expandInlineButton = true;
}
+ return false;
});
- return true;
+ return !results.some(r => !r);
};
childLayoutTemplate = () => Docs.Create.PresElementBoxDocument();
- removeDocument = (doc: Doc | Doc[]) => !(doc instanceof Doc ? [doc] : doc).map(d => Doc.RemoveDocFromList(this.Document, this.fieldKey, d)).some(p => !p);
+ removeDocument = (doc: Doc | Doc[]) =>
+ !toList(doc)
+ .map(d => Doc.RemoveDocFromList(this.Document, this.fieldKey, d))
+ .some(p => !p);
getTransform = () => this.ScreenToLocalBoxXf().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight
panelHeight = () => this._props.PanelHeight() - 40;
/**
@@ -1092,42 +1190,46 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null);
if (curDoc && curDoc === this.activeItem)
return (
+ // eslint-disable-next-line react/no-array-index-key
<div key={index} className="selectedList-items">
<b>
{index + 1}. {curDoc.title}
</b>
</div>
);
- else if (tagDoc)
+ if (tagDoc)
return (
+ // eslint-disable-next-line react/no-array-index-key
<div key={index} className="selectedList-items">
{index + 1}. {curDoc.title}
</div>
);
- else if (curDoc)
+ if (curDoc)
return (
+ // eslint-disable-next-line react/no-array-index-key
<div key={index} className="selectedList-items">
{index + 1}. {curDoc.title}
</div>
);
+ return null;
});
}
@action
selectPres = () => {
- const presDocView = DocumentManager.Instance.getDocumentView(this.Document);
- presDocView && SelectionManager.SelectView(presDocView, false);
+ const presDocView = DocumentView.getDocumentView(this.Document);
+ presDocView && DocumentView.SelectView(presDocView, false);
};
- focusElement = (doc: Doc, options: FocusViewOptions) => {
+ focusElement = (doc: Doc) => {
this.selectElement(doc);
return undefined;
};
- //Regular click
+ // Regular click
@action
selectElement = (doc: Doc, noNav = false) => {
- CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => clip?.ComponentView?.Pause?.());
+ DocumentView.CurrentlyPlaying?.map(clip => clip?.ComponentView?.Pause?.());
if (noNav) {
const index = this.childDocs.indexOf(doc);
if (index >= 0 && index < this.childDocs.length) {
@@ -1139,7 +1241,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.updateCurrentPresentation(DocCast(doc.embedContainer));
};
- //Command click
+ // Command click
@action
multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
if (!this.selectedArray.has(doc)) {
@@ -1154,7 +1256,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.selectPres();
};
- //Shift click
+ // Shift click
@action
shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
this.clearSelectedArray();
@@ -1169,7 +1271,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.selectPres();
};
- //regular click
+ // regular click
@action
regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, selectPres = true) => {
this.clearSelectedArray();
@@ -1192,6 +1294,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
keyEvents = (e: KeyboardEvent) => {
if (e.target instanceof HTMLInputElement) return;
+ if (e.target instanceof HTMLTextAreaElement) return;
let handled = false;
const anchorNode = document.activeElement as HTMLDivElement;
if (anchorNode && anchorNode.className?.includes('lm_title')) return;
@@ -1200,9 +1303,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (this.layoutDoc.presentation_status === 'edit') {
undoBatch(
action(() => {
- for (const doc of this.selectedArray) {
- this.removeDocument(doc);
- }
+ Array.from(this.selectedArray).forEach(doc => this.removeDocument(doc));
this.clearSelectedArray();
this._eleArray.length = 0;
this._dragArray.length = 0;
@@ -1269,8 +1370,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.childDocs.forEach(doc => this.addToSelectedArray(doc));
handled = true;
}
- default:
break;
+ default:
}
if (handled) {
e.stopPropagation();
@@ -1285,11 +1386,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const order: JSX.Element[] = [];
const docs = new Set<Doc>();
const presCollection = collection;
- const dv = DocumentManager.Instance.getDocumentView(presCollection);
+ const dv = DocumentView.getDocumentView(presCollection);
this.childDocs.forEach((doc, index) => {
const tagDoc = PresBox.targetRenderedDoc(doc);
const srcContext = Cast(tagDoc.embedContainer, Doc, null);
const labelCreator = (top: number, left: number, edge: number, fontSize: number) => (
+ // eslint-disable-next-line react/no-array-index-key
<div className="pathOrder" key={tagDoc.id + 'pres' + index} style={{ top, left, width: edge, height: edge, fontSize }} onClick={() => this.selectElement(doc)}>
<div className="pathOrder-frame">{index + 1}</div>
</div>
@@ -1322,7 +1424,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
order.push(
<>
{labelCreator(top - indEdge / 2, left - indEdge / 2, indEdge, indFontSize)}
- <div className="pathOrder-presPinView" style={{ top, left, width, height, borderWidth: indEdge / 10 }}></div>
+ <div className="pathOrder-presPinView" style={{ top, left, width, height, borderWidth: indEdge / 10 }} />
</>
);
}
@@ -1345,17 +1447,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
.filter(doc => PresBox.targetRenderedDoc(doc)?.embedContainer === collection)
.forEach((doc, index) => {
const tagDoc = PresBox.targetRenderedDoc(doc);
- if (tagDoc) {
- const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2;
- const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2;
- if ((index = 0)) pathPoints = n1x + ',' + n1y;
- else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
- } else if (doc.config_pinView) {
- const n1x = NumCast(doc.config_panX);
- const n1y = NumCast(doc.config_panY);
- if ((index = 0)) pathPoints = n1x + ',' + n1y;
- else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
- }
+ const [n1x, n1y] = tagDoc //
+ ? [NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2, NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2]
+ : [NumCast(doc.config_panX), NumCast(doc.config_panY)];
+
+ if (index === 0) pathPoints = n1x + ',' + n1y;
+ else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
});
return (
<>
@@ -1401,7 +1498,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
updateTransitionTime = (number: String, change?: number) => {
- PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presentation_transition = timeInMS)), change);
+ PresBox.SetTransitionTime(
+ number,
+ (timeInMS: number) =>
+ this.selectedArray.forEach(doc => {
+ doc.presentation_transition = timeInMS;
+ }),
+ change
+ );
};
// Converts seconds to ms and updates presentation_transition
@@ -1411,7 +1515,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (change) scale += change;
if (scale < 0.01) scale = 0.01;
if (scale > 1) scale = 1;
- this.selectedArray.forEach(doc => (doc.config_zoom = scale));
+ this.selectedArray.forEach(doc => {
+ doc.config_zoom = scale;
+ });
};
/*
@@ -1423,257 +1529,290 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 20000) timeInMS = 20000;
- this.selectedArray.forEach(doc => (doc.presentation_duration = timeInMS));
+ this.selectedArray.forEach(doc => {
+ doc.presentation_duration = timeInMS;
+ });
};
@undoBatch
- updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_movement = movement)));
+ updateMovement = action((movement: PresMovement, all?: boolean) =>
+ (all ? this.childDocs : this.selectedArray).forEach(doc => {
+ doc.presentation_movement = movement;
+ })
+ );
@undoBatch
updateHideBefore = (activeItem: Doc) => {
activeItem.presentation_hideBefore = !activeItem.presentation_hideBefore;
- this.selectedArray.forEach(doc => (doc.presentation_hideBefore = activeItem.presentation_hideBefore));
+ this.selectedArray.forEach(doc => {
+ doc.presentation_hideBefore = activeItem.presentation_hideBefore;
+ });
};
@undoBatch
updateHide = (activeItem: Doc) => {
activeItem.presentation_hide = !activeItem.presentation_hide;
- this.selectedArray.forEach(doc => (doc.presentation_hide = activeItem.presentation_hide));
+ this.selectedArray.forEach(doc => {
+ doc.presentation_hide = activeItem.presentation_hide;
+ });
};
@undoBatch
updateHideAfter = (activeItem: Doc) => {
activeItem.presentation_hideAfter = !activeItem.presentation_hideAfter;
- this.selectedArray.forEach(doc => (doc.presentation_hideAfter = activeItem.presentation_hideAfter));
+ this.selectedArray.forEach(doc => {
+ doc.presentation_hideAfter = activeItem.presentation_hideAfter;
+ });
};
@undoBatch
updateOpenDoc = (activeItem: Doc) => {
activeItem.presentation_openInLightbox = !activeItem.presentation_openInLightbox;
- this.selectedArray.forEach(doc => (doc.presentation_openInLightbox = activeItem.presentation_openInLightbox));
+ this.selectedArray.forEach(doc => {
+ doc.presentation_openInLightbox = activeItem.presentation_openInLightbox;
+ });
};
@undoBatch
updateEaseFunc = (activeItem: Doc) => {
- activeItem.presEaseFunc = activeItem.presEaseFunc === 'linear' ? 'ease' : 'linear';
- this.selectedArray.forEach(doc => (doc.presEaseFunc = activeItem.presEaseFunc));
+ activeItem.presentation_easeFunc = activeItem.presentation_easeFunc === 'linear' ? 'ease' : 'linear';
+ this.selectedArray.forEach(doc => {
+ doc.presentation_easeFunc = activeItem.presentation_easeFunc;
+ });
};
+ setEaseFunc = (activeItem: Doc, easeFunc: string) => {
+ activeItem.presentation_easeFunc = easeFunc;
+ this.selectedArray.forEach(doc => {
+ doc.presentation_easeFunc = activeItem.presentation_easeFunc;
+ });
+ };
+
+ @undoBatch
+ updateEffectDirection = (effect: PresEffectDirection, all?: boolean) =>
+ (all ? this.childDocs : this.selectedArray).forEach(doc => {
+ doc.presentation_effectDirection = effect;
+ });
+
@undoBatch
- updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presentation_effectDirection = effect));
+ updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) =>
+ (all ? this.childDocs : this.selectedArray).forEach(doc => {
+ bullet ? (doc.presBulletEffect = effect) : (doc.presentation_effect = effect);
+ });
@undoBatch
- updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presentation_effect = effect)));
+ updateEffectTiming = (activeItem: Doc, timing: SpringSettings) => {
+ activeItem.presentation_effectTiming = JSON.stringify(timing);
+ this.selectedArray.forEach(doc => {
+ doc.presentation_effectTiming = activeItem.presentation_effectTiming;
+ });
+ };
static _sliderBatch: any;
static endBatch = () => {
PresBox._sliderBatch.end();
document.removeEventListener('pointerup', PresBox.endBatch, true);
};
- public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => {
- return (
- <input
- type="range"
- step={step}
- min={min}
- max={max}
- value={value}
- readOnly={true}
- style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)`, background: SettingsManager.userColor, color: SettingsManager.userVariantColor }}
- className={`toolbar-slider ${active ? '' : 'none'}`}
- onPointerDown={e => {
- PresBox._sliderBatch = UndoManager.StartBatch('pres slider');
- document.addEventListener('pointerup', PresBox.endBatch, true);
- e.stopPropagation();
- }}
- onChange={e => {
- e.stopPropagation();
- change(e.target.value);
- }}
- />
- );
- };
-
+ public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => (
+ <input
+ type="range"
+ step={step}
+ min={min}
+ max={max}
+ value={value}
+ readOnly
+ style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)`, background: SnappingManager.userColor, color: SnappingManager.userVariantColor }}
+ className={`toolbar-slider ${active ? '' : 'none'}`}
+ onPointerDown={e => {
+ PresBox._sliderBatch = UndoManager.StartBatch('pres slider');
+ document.addEventListener('pointerup', PresBox.endBatch, true);
+ e.stopPropagation();
+ }}
+ onChange={e => {
+ e.stopPropagation();
+ change(e.target.value);
+ }}
+ />
+ );
+
+ // Applies the slide transiiton settings to all docs in the array
@undoBatch
applyTo = (array: Doc[]) => {
this.updateMovement(this.activeItem.presentation_movement as PresMovement, true);
this.updateEffect(this.activeItem.presentation_effect as PresEffect, false, true);
this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true);
this.updateEffectDirection(this.activeItem.presentation_effectDirection as PresEffectDirection, true);
- const { presentation_transition, presentation_duration, presentation_hideBefore, presentation_hideAfter } = this.activeItem;
+ // eslint-disable-next-line camelcase
+ const { presentation_transition: pt, presentation_duration: pd, presentation_hideBefore: ph, presentation_hideAfter: pa } = this.activeItem;
array.forEach(curDoc => {
- curDoc.presentation_transition = presentation_transition;
- curDoc.presentation_duration = presentation_duration;
- curDoc.presentation_hideBefore = presentation_hideBefore;
- curDoc.presentation_hideAfter = presentation_hideAfter;
+ curDoc.presentation_transition = pt;
+ curDoc.presentation_duration = pd;
+ curDoc.presentation_hideBefore = ph;
+ curDoc.presentation_hideAfter = pa;
});
};
@computed get visibilityDurationDropdown() {
- const activeItem = this.activeItem;
+ const { activeItem } = this;
if (activeItem && this.targetDoc) {
const targetType = this.targetDoc.type;
let duration = activeItem.presentation_duration ? NumCast(activeItem.presentation_duration) / 1000 : 0;
if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
return (
- <div className="presBox-ribbon">
- <div className="ribbon-doubleButton">
- <Tooltip title={<div className="dash-tooltip">Hide before presented</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hideBefore ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hideBefore ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHideBefore(activeItem)}>
- Hide before
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hide ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hide ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHide(activeItem)}>
- Hide
- </div>
- </Tooltip>
-
- <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
- <div
- className={`ribbon-toggle ${activeItem.presentation_hideAfter ? 'active' : ''}`}
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presentation_hideAfter ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateHideAfter(activeItem)}>
- Hide after
- </div>
- </Tooltip>
-
- <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
- <div
- className="ribbon-toggle"
- style={{
- border: `solid 1px ${SettingsManager.userColor}`,
- color: SettingsManager.userColor,
- background: activeItem.presentation_openInLightbox ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor,
- }}
- onClick={() => this.updateOpenDoc(activeItem)}>
- Lightbox
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">Transition movement style</div>}>
- <div
- className="ribbon-toggle"
- style={{ border: `solid 1px ${SettingsManager.userColor}`, color: SettingsManager.userColor, background: activeItem.presEaseFunc === 'ease' ? SettingsManager.userVariantColor : SettingsManager.userBackgroundColor }}
- onClick={() => this.updateEaseFunc(activeItem)}>
- {`${StrCast(activeItem.presEaseFunc, 'ease')}`}
- </div>
- </Tooltip>
- </div>
- {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : (
- <>
- <div className="ribbon-doubleButton">
- <div className="presBox-subheading">Slide Duration</div>
- <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
- <input className="presBox-input" type="number" readOnly={true} value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
+ <div className="presBox-option-block">
+ <div className="presBox-ribbon">
+ <div className="presBox-toggles">
+ <Tooltip title={<div className="dash-tooltip">Hide before presented</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hideBefore ? 'active' : ''}`}
+ style={{
+ border: `solid 1px ${SnappingManager.userColor}`,
+ color: SnappingManager.userColor,
+ background: activeItem.presentation_hideBefore ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor,
+ }}
+ onClick={() => this.updateHideBefore(activeItem)}>
+ Hide before
</div>
- <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), 1000)}>
- <FontAwesomeIcon icon={'caret-up'} />
- </div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), -1000)}>
- <FontAwesomeIcon icon={'caret-down'} />
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">Hide while presented</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hide ? 'active' : ''}`}
+ style={{ border: `solid 1px ${SnappingManager.userColor}`, color: SnappingManager.userColor, background: activeItem.presentation_hide ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor }}
+ onClick={() => this.updateHide(activeItem)}>
+ Hide
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">Hide after presented</div>}>
+ <div
+ className={`ribbon-toggle ${activeItem.presentation_hideAfter ? 'active' : ''}`}
+ style={{ border: `solid 1px ${SnappingManager.userColor}`, color: SnappingManager.userColor, background: activeItem.presentation_hideAfter ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor }}
+ onClick={() => this.updateHideAfter(activeItem)}>
+ Hide after
+ </div>
+ </Tooltip>
+
+ <Tooltip title={<div className="dash-tooltip">Open in lightbox view</div>}>
+ <div
+ className="ribbon-toggle"
+ style={{
+ border: `solid 1px ${SnappingManager.userColor}`,
+ color: SnappingManager.userColor,
+ background: activeItem.presentation_openInLightbox ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor,
+ }}
+ onClick={() => this.updateOpenDoc(activeItem)}>
+ Lightbox
+ </div>
+ </Tooltip>
+ </div>
+ {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : (
+ <>
+ <div className="ribbon-doubleButton">
+ <div className="presBox-subheading">Slide Duration</div>
+ <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}>
+ <input className="presBox-input" type="number" readOnly value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
</div>
</div>
- </div>
- {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
- <div className={'slider-headers'} style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}>
- <div className="slider-text">Short</div>
- <div className="slider-text">Medium</div>
- <div className="slider-text">Long</div>
- </div>
- </>
- )}
+ {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
+ <div className="slider-headers" style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}>
+ <div className="slider-text">Short</div>
+ <div className="slider-text">Medium</div>
+ <div className="slider-text">Long</div>
+ </div>
+ </>
+ )}
+ </div>
</div>
);
}
+ return undefined;
}
@computed get progressivizeDropdown() {
- const activeItem = this.activeItem;
+ const { activeItem } = this;
if (activeItem && this.targetDoc) {
const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None;
- const bulletEffect = (effect: PresEffect) => (
+ const bulletEffect = (presEffect: PresEffect) => (
<div
- className={`presBox-dropdownOption ${activeItem.presentation_effect === effect || (effect === PresEffect.None && !activeItem.presentation_effect) ? 'active' : ''}`}
+ className={`presBox-dropdownOption ${activeItem.presentation_effect === presEffect || (presEffect === PresEffect.None && !activeItem.presentation_effect) ? 'active' : ''}`}
onPointerDown={StopEvent}
- onClick={() => this.updateEffect(effect, true)}>
- {effect}
+ onClick={() => this.updateEffect(presEffect, true)}>
+ {presEffect}
</div>
);
return (
- <div className="presBox-ribbon">
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Progressivize Collection</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => {
- activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined;
- activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined;
- const tagDoc = PresBox.targetRenderedDoc(this.activeItem);
- const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type;
- activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0;
- // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
- // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
- let dataField = Doc.LayoutFieldKey(tagDoc);
- if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '_annotations';
-
- if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`);
- else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`);
- }}
- checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined ? true : false}
- />
- </div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Progressivize First Bullet</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1)}
- checked={!NumCast(activeItem.presentation_indexedStart)}
- />
- </div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Expand Current Bullet</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)}
- checked={BoolCast(activeItem.presBulletExpand)}
- />
- </div>
+ <div className="presBox-option-block">
+ <div className="presBox-ribbon">
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize Collection</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SnappingManager.userColor}` }}
+ type="checkbox"
+ onChange={() => {
+ activeItem.presentation_indexed = activeItem.presentation_indexed === undefined ? 0 : undefined;
+ activeItem.presentation_hideBefore = activeItem.presentation_indexed !== undefined;
+ const tagDoc = PresBox.targetRenderedDoc(this.activeItem);
+ const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type;
+ activeItem.presentation_indexedStart = type === DocumentType.COL ? 1 : 0;
+ // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
+ // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
+ let dataField = Doc.LayoutFieldKey(tagDoc);
+ if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField += '_annotations';
+
+ if (DocCast(activeItem.presentation_targetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc.annotationOn?.["${dataField}"]`);
+ else activeItem.data = ComputedField.MakeFunction(`this.presentation_targetDoc?.["${dataField}"]`);
+ }}
+ checked={Cast(activeItem.presentation_indexed, 'number', null) !== undefined}
+ />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize First Bullet</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SnappingManager.userColor}` }}
+ type="checkbox"
+ onChange={() => {
+ activeItem.presentation_indexedStart = activeItem.presentation_indexedStart ? 0 : 1;
+ }}
+ checked={!NumCast(activeItem.presentation_indexedStart)}
+ />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Expand Current Bullet</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10, border: `solid 1px ${SnappingManager.userColor}` }}
+ type="checkbox"
+ onChange={() => {
+ activeItem.presBulletExpand = !activeItem.presBulletExpand;
+ }}
+ checked={BoolCast(activeItem.presBulletExpand)}
+ />
+ </div>
- <div className="ribbon-box">
- Bullet Effect
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this._openBulletEffectDropdown = !this._openBulletEffectDropdown;
- })}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userVariantColor,
- borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5,
- border: this._openBulletEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`,
- }}>
- {effect?.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className="ribbon-box">
+ Bullet Effect
<div
- className={'presBox-dropdownOptions'}
- style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none', color: SettingsManager.userColor, background: SettingsManager.userBackgroundColor }}
- onPointerDown={e => e.stopPropagation()}>
- {Object.values(PresEffect)
- .filter(v => isNaN(Number(v)))
- .map(effect => bulletEffect(effect))}
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openBulletEffectDropdown = !this._openBulletEffectDropdown;
+ })}
+ style={{
+ color: SnappingManager.userColor,
+ background: SnappingManager.userVariantColor,
+ borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5,
+ border: this._openBulletEffectDropdown ? `solid 2px ${SnappingManager.userVariantColor}` : `solid 1px ${SnappingManager.userColor}`,
+ }}>
+ {effect?.toString()}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon="angle-down" />
+ <div
+ className="presBox-dropdownOptions"
+ style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none', color: SnappingManager.userColor, background: SnappingManager.userBackgroundColor }}
+ onPointerDown={e => e.stopPropagation()}>
+ {Object.values(PresEffect)
+ .filter(v => isNaN(Number(v)))
+ .map(pEffect => bulletEffect(pEffect))}
+ </div>
</div>
</div>
</div>
@@ -1682,215 +1821,460 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
return null;
}
+
+ @computed get gptDropdown() {
+ return <div />;
+ }
+
@computed get transitionDropdown() {
- const activeItem = this.activeItem;
- const preseEffect = (effect: PresEffect) => (
- <div
- className={`presBox-dropdownOption ${activeItem.presentation_effect === effect || (effect === PresEffect.None && !activeItem.presentation_effect) ? 'active' : ''}`}
- onPointerDown={StopEvent}
- onClick={() => this.updateEffect(effect, false)}>
- {effect}
- </div>
- );
- const presMovement = (movement: PresMovement) => (
- <div className={`presBox-dropdownOption ${activeItem.presentation_movement === movement ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateMovement(movement)}>
- {movement}
- </div>
- );
- const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => {
- const color = activeItem.presentation_effectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presentation_effectDirection) ? SettingsManager.userVariantColor : SettingsManager.userColor;
- return (
- <Tooltip title={<div className="dash-tooltip">{direction}</div>}>
- <div
- style={{ ...opts, border: direction === PresEffectDirection.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }}
- onClick={() => this.updateEffectDirection(direction)}>
- {icon ? <FontAwesomeIcon icon={icon as any} /> : null}
- </div>
- </Tooltip>
- );
- };
+ const { activeItem } = this;
+ // Retrieving spring timing properties
+ const timing = StrCast(activeItem.presentation_effectTiming);
+ let timingConfig: SpringSettings | undefined;
+ if (timing) {
+ timingConfig = JSON.parse(timing);
+ }
+
+ if (!timingConfig) {
+ timingConfig = {
+ type: SpringType.GENTLE,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ };
+ }
+
if (activeItem && this.targetDoc) {
const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5;
const zoom = NumCast(activeItem.config_zoom, 1) * 100;
- const effect = activeItem.presentation_effect ? activeItem.presentation_effect : PresMovement.None;
+ const effect = StrCast(activeItem.presentation_effect) ? (StrCast(activeItem.presentation_effect) as any as PresEffect) : PresEffect.None;
+ const direction = StrCast(activeItem.presentation_effectDirection) as PresEffectDirection;
+
return (
- <div
- className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`}
- onPointerDown={StopEvent}
- onPointerUp={StopEvent}
- onClick={action(e => {
- e.stopPropagation();
- this._openMovementDropdown = false;
- this._openEffectDropdown = false;
- this._openBulletEffectDropdown = false;
- })}>
- <div className="ribbon-box">
- Movement
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this._openMovementDropdown = !this._openMovementDropdown;
- })}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userVariantColor,
- borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5,
- border: this._openMovementDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`,
- }}>
- {this.movementName(activeItem)}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div
- className="presBox-dropdownOptions"
- id={'presBoxMovementDropdown'}
- onPointerDown={StopEvent}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userBackgroundColor,
- display: this._openMovementDropdown ? 'grid' : 'none',
- }}>
- {presMovement(PresMovement.None)}
- {presMovement(PresMovement.Center)}
- {presMovement(PresMovement.Zoom)}
- {presMovement(PresMovement.Pan)}
- {presMovement(PresMovement.Jump)}
+ <>
+ {/* This chatbox is for customizing the properties of trails, like transition time, movement type (zoom, pan) using GPT */}
+ <div className="presBox-gpt-chat">
+ <span style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
+ Customize Slide Properties{' '}
+ <div className="propertiesView-info" onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/features/trails/#slide-customization')}>
+ <IconButton icon={<FontAwesomeIcon icon="info-circle" />} color={SnappingManager.userColor} />
</div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: activeItem.presentation_movement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Zoom (% screen filled)</div>
- <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
- <input className="presBox-input" type="number" readOnly={true} value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
+ </span>
+ <div className="pres-chat">
+ <div className="pres-chatbox-container">
+ <ReactTextareaAutosize
+ placeholder="Describe how you would like to modify the slide properties."
+ className="pres-chatbox"
+ value={this.chatInput}
+ onChange={e => {
+ this.setChatInput(e.target.value);
+ }}
+ onKeyDown={e => {
+ this.stopDictation();
+ e.stopPropagation();
+ }}
+ />
+ <IconButton
+ type={Type.TERT}
+ color={this.isRecording ? '#2bcaff' : SnappingManager.userVariantColor}
+ tooltip="Record"
+ icon={<BiMicrophone size="16px" />}
+ onClick={() => {
+ if (!this.isRecording) {
+ this.recordDictation();
+ } else {
+ this.stopDictation();
+ }
+ }}
+ />
</div>
- <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), 0.1)}>
- <FontAwesomeIcon icon={'caret-up'} />
+ <Button
+ style={{ alignSelf: 'flex-end' }}
+ text="Send"
+ type={Type.TERT}
+ icon={this.isLoading ? <ReactLoading type="spin" color="#ffffff" width={20} height={20} /> : <AiOutlineSend />}
+ iconPlacement="right"
+ color={SnappingManager.userVariantColor}
+ onClick={() => {
+ this.stopDictation();
+ this.customizeWithGPT(this.chatInput);
+ }}
+ />
+ </div>
+ </div>
+ {/* Movement */}
+ <div
+ className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`}
+ onPointerDown={StopEvent}
+ onPointerUp={StopEvent}
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openMovementDropdown = false;
+ this._openEffectDropdown = false;
+ this._openBulletEffectDropdown = false;
+ })}>
+ <div
+ className="presBox-option-block"
+ // style={{ padding: '16px' }}
+ >
+ Movement
+ <Dropdown
+ color={SnappingManager.userColor}
+ formLabel="Movement"
+ closeOnSelect
+ items={movementItems}
+ selectedVal={this.movementName(activeItem)}
+ setSelectedVal={val => {
+ this.updateMovement(val as PresMovement);
+ }}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ />
+ <div className="ribbon-doubleButton" style={{ display: activeItem.presentation_movement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
+ <div className="presBox-subheading">Zoom (% screen filled)</div>
+ <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}>
+ <input className="presBox-input" readOnly type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
</div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), -0.1)}>
- <FontAwesomeIcon icon={'caret-down'} />
+ </div>
+ {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Transition Time</div>
+ <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}>
+ <input className="presBox-input" type="number" readOnly value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
</div>
</div>
- </div>
- {PresBox.inputter('0', '1', '100', zoom, activeItem.presentation_movement === PresMovement.Zoom, this.updateZoom)}
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Transition Time</div>
- <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
- <input className="presBox-input" type="number" readOnly={true} value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
+ {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.updateTransitionTime)}
+ <div className="slider-headers">
+ <div className="slider-text">Fast</div>
+ <div className="slider-text">Medium</div>
+ <div className="slider-text">Slow</div>
</div>
- <div className="ribbon-propertyUpDown" style={{ color: SettingsManager.userBackgroundColor, background: SettingsManager.userColor }}>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), 1000)}>
- <FontAwesomeIcon icon={'caret-up'} />
- </div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), -1000)}>
- <FontAwesomeIcon icon={'caret-down'} />
- </div>
+ {/* Easing function */}
+ <Dropdown
+ color={SnappingManager.userColor}
+ formLabel="Easing Function"
+ closeOnSelect
+ items={easeItems}
+ selectedVal={this.activeItem.presentation_easeFunc ? (StrCast(this.activeItem.presentation_easeFunc).startsWith('cubic') ? 'custom' : StrCast(this.activeItem.presentation_easeFunc)) : 'ease'}
+ setSelectedVal={val => {
+ if (typeof val === 'string') {
+ if (val !== 'custom') {
+ this.setEaseFunc(this.activeItem, val);
+ } else {
+ this.setBezierEditorVisibility(true);
+ this.setEaseFunc(this.activeItem, TIMING_DEFAULT_MAPPINGS.ease);
+ }
+ }
+ }}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ />
+ {/* Custom */}
+ <div
+ className="presBox-show-hide-dropdown"
+ style={{ alignSelf: 'flex-start' }}
+ onClick={e => {
+ e.stopPropagation();
+ this.setBezierEditorVisibility(!this.showBezierEditor);
+ }}>
+ {`${this.showBezierEditor ? 'Hide' : 'Show'} Timing Editor`}
+ <FontAwesomeIcon icon={this.showBezierEditor ? 'chevron-up' : 'chevron-down'} />
</div>
</div>
- {PresBox.inputter('0.1', '0.1', '100', transitionSpeed, true, this.updateTransitionTime)}
- <div className={'slider-headers'}>
- <div className="slider-text">Fast</div>
- <div className="slider-text">Medium</div>
- <div className="slider-text">Slow</div>
- </div>
</div>
- <div className="ribbon-box">
+
+ {/* Cubic bezier editor */}
+ {this.showBezierEditor && (
+ <div className="presBox-option-block" style={{ paddingTop: 0 }}>
+ <p className="presBox-submenu-label" style={{ alignSelf: 'flex-start' }}>
+ Custom Timing Function
+ </p>
+ <CubicBezierEditor setFunc={this.setBezierControlPoints} currPoints={this.currCPoints} />
+ </div>
+ )}
+
+ {/* This chatbox is for getting slide effect transition suggestions from gpt and visualizing them */}
+ <div className="presBox-gpt-chat">
Effects
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Play Audio Annotation</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))}
- checked={BoolCast(activeItem.presPlayAudio)}
+ <div className="pres-chat">
+ <div className="pres-chatbox-container">
+ <ReactTextareaAutosize
+ placeholder="Customize prompt for effect suggestions. Leave blank for random results."
+ className="pres-chatbox"
+ value={this.animationChat}
+ onChange={e => {
+ this.setAnimationChat(e.target.value);
+ }}
+ onKeyDown={e => {
+ this.stopDictation();
+ e.stopPropagation();
+ }}
+ />
+ </div>
+ <Button
+ style={{ alignSelf: 'flex-end' }}
+ text="Send"
+ type={Type.TERT}
+ icon={this.isLoading ? <ReactLoading type="spin" color="#ffffff" width={20} height={20} /> : <AiOutlineSend />}
+ iconPlacement="right"
+ color={SnappingManager.userVariantColor}
+ onClick={this.customizeAnimations}
/>
</div>
- <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
- <div className="presBox-subheading">Zoom Text Selections</div>
- <input
- className="presBox-checkbox"
- style={{ margin: 10, border: `solid 1px ${SettingsManager.userColor}` }}
- type="checkbox"
- onChange={() => (activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText))}
- checked={BoolCast(activeItem.presentation_zoomText)}
+ </div>
+
+ <div
+ className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presentation_status === PresStatus.Edit ? 'active' : ''}`}
+ onPointerDown={StopEvent}
+ onPointerUp={StopEvent}
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openMovementDropdown = false;
+ this._openEffectDropdown = false;
+ this._openBulletEffectDropdown = false;
+ })}>
+ <div className="presBox-option-block">
+ Click on a box to apply the effect.
+ <div className="presBox-option-block presBox-option-center">
+ {/* Preview Animations */}
+ <div className="presBox-effects">
+ {this.generatedAnimations.map((elem, i) => (
+ <div
+ // eslint-disable-next-line react/no-array-index-key
+ key={i}
+ className="presBox-effect-container"
+ onClick={() => {
+ this.updateEffect(elem.effect, false);
+ this.updateEffectDirection(elem.direction);
+ this.updateEffectTiming(this.activeItem, {
+ type: SpringType.CUSTOM,
+ stiffness: elem.stiffness,
+ damping: elem.damping,
+ mass: elem.mass,
+ });
+ }}>
+ <SlideEffect dir={elem.direction} presEffect={elem.effect} springSettings={elem} infinite>
+ <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[i] }} />
+ </SlideEffect>
+ </div>
+ ))}
+ </div>
+ </div>
+ {/* Effect dropdown */}
+ <Dropdown
+ color={SnappingManager.userColor}
+ formLabel="Slide Effect"
+ closeOnSelect
+ items={effectItems}
+ selectedVal={effect?.toString()}
+ setSelectedVal={val => {
+ this.updateEffect(val as PresEffect, false);
+ // set default spring options for that effect
+ this.updateEffectTiming(activeItem, presEffectDefaultTimings[val as keyof typeof presEffectDefaultTimings]);
+ }}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
/>
+ {/* Effect direction */}
+ {/* Only applies to certain effects */}
+ {(effect === PresEffect.Flip || effect === PresEffect.Bounce || effect === PresEffect.Roll) && (
+ <>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Effect direction</div>
+ <div className="ribbon-property" style={{ border: `solid 1px ${SnappingManager.userColor}` }}>
+ {StrCast(this.activeItem.presentation_effectDirection)}
+ </div>
+ </div>
+ <div className="presBox-icon-list">
+ <IconButton
+ type={Type.TERT}
+ color={activeItem.presentation_effectDirection === PresEffectDirection.Left ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor}
+ tooltip="Left"
+ icon={<FaArrowRight size="16px" />}
+ onClick={() => this.updateEffectDirection(PresEffectDirection.Left)}
+ />
+ <IconButton
+ type={Type.TERT}
+ color={activeItem.presentation_effectDirection === PresEffectDirection.Right ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor}
+ tooltip="Right"
+ icon={<FaArrowLeft size="16px" />}
+ onClick={() => this.updateEffectDirection(PresEffectDirection.Right)}
+ />
+ {effect !== PresEffect.Roll && (
+ <>
+ <IconButton
+ type={Type.TERT}
+ color={activeItem.presentation_effectDirection === PresEffectDirection.Top ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor}
+ tooltip="Top"
+ icon={<FaArrowDown size="16px" />}
+ onClick={() => this.updateEffectDirection(PresEffectDirection.Top)}
+ />
+ <IconButton
+ type={Type.TERT}
+ color={activeItem.presentation_effectDirection === PresEffectDirection.Bottom ? SnappingManager.userVariantColor : SnappingManager.userBackgroundColor}
+ tooltip="Bottom"
+ icon={<FaArrowUp size="16px" />}
+ onClick={() => this.updateEffectDirection(PresEffectDirection.Bottom)}
+ />
+ </>
+ )}
+ </div>
+ </>
+ )}
+ {/* Spring settings */}
+ {/* No spring settings for jackinthebox (lightspeed) */}
+ {effect !== PresEffect.Lightspeed && (
+ <>
+ <Dropdown
+ color={SnappingManager.userColor}
+ formLabel="Effect Timing"
+ closeOnSelect
+ items={effectTimings}
+ selectedVal={timingConfig.type}
+ setSelectedVal={val => {
+ this.updateEffectTiming(activeItem, {
+ type: val as SpringType,
+ ...springMappings[val],
+ });
+ }}
+ dropdownType={DropdownType.SELECT}
+ type={Type.TERT}
+ />
+ <div
+ className="presBox-show-hide-dropdown"
+ onClick={e => {
+ e.stopPropagation();
+ this.setSpringEditorVisibility(!this.showSpringEditor);
+ }}>
+ {`${this.showSpringEditor ? 'Hide' : 'Show'} Spring Settings`}
+ <FontAwesomeIcon icon={this.showSpringEditor ? 'chevron-up' : 'chevron-down'} />
+ </div>
+ {this.showSpringEditor && (
+ <>
+ <div>Tension</div>
+ <div
+ onPointerDown={e => {
+ e.stopPropagation();
+ }}>
+ <Slider
+ min={1}
+ max={1000}
+ step={5}
+ size="small"
+ value={timingConfig.stiffness}
+ onChange={(e, val) => {
+ if (!timingConfig) return;
+ this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, stiffness: val as number });
+ }}
+ valueLabelDisplay="auto"
+ />
+ </div>
+ <div>Damping</div>
+ <div
+ onPointerDown={e => {
+ e.stopPropagation();
+ }}>
+ <Slider
+ min={1}
+ max={100}
+ step={1}
+ size="small"
+ value={timingConfig.damping}
+ onChange={(e, val) => {
+ if (!timingConfig) return;
+ this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, damping: val as number });
+ }}
+ valueLabelDisplay="auto"
+ />
+ </div>
+ <div>Mass</div>
+ <div
+ onPointerDown={e => {
+ e.stopPropagation();
+ }}>
+ <Slider
+ min={1}
+ max={10}
+ step={1}
+ size="small"
+ value={timingConfig.mass}
+ onChange={(e, val) => {
+ if (!timingConfig) return;
+ this.updateEffectTiming(activeItem, { ...timingConfig, type: SpringType.CUSTOM, mass: val as number });
+ }}
+ valueLabelDisplay="auto"
+ />
+ </div>
+ Preview Effect
+ <div className="presBox-option-block presBox-option-center">
+ <div className="presBox-effect-container">
+ <SlideEffect dir={direction} presEffect={effect} springSettings={timingConfig} infinite>
+ <div className="presBox-effect-demo-box" style={{ backgroundColor: springPreviewColors[0] }} />
+ </SlideEffect>
+ </div>
+ </div>
+ </>
+ )}
+ </>
+ )}
</div>
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this._openEffectDropdown = !this._openEffectDropdown;
- })}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userVariantColor,
- borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5,
- border: this._openEffectDropdown ? `solid 2px ${SettingsManager.userVariantColor}` : `solid 1px ${SettingsManager.userColor}`,
- }}>
- {effect?.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div
- className="presBox-dropdownOptions"
- id={'presBoxMovementDropdown'}
- style={{
- color: SettingsManager.userColor,
- background: SettingsManager.userBackgroundColor,
- display: this._openEffectDropdown ? 'grid' : 'none',
+
+ {/* Toggles */}
+ <div className="presBox-option-block">
+ <Toggle
+ formLabel="Play Audio Annotation"
+ toggleType={ToggleType.SWITCH}
+ toggleStatus={BoolCast(activeItem.presentation_playAudio)}
+ onClick={() => {
+ activeItem.presentation_playAudio = !BoolCast(activeItem.presentation_playAudio);
}}
- onPointerDown={e => e.stopPropagation()}>
- {Object.values(PresEffect)
- .filter(v => isNaN(Number(v)))
- .map(effect => preseEffect(effect))}
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}>
- <div className="presBox-subheading">Effect direction</div>
- <div className="ribbon-property" style={{ border: `solid 1px ${SettingsManager.userColor}` }}>
- {StrCast(this.activeItem.presentation_effectDirection)}
- </div>
- </div>
- <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}>
- {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
- {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
- {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
- {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
- {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
- </div>
- </div>
- <div className="ribbon-final-box">
- <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
- Apply to all
+ color={SnappingManager.userColor}
+ />
+ <Toggle
+ formLabel="Zoom Text Selections"
+ toggleType={ToggleType.SWITCH}
+ toggleStatus={BoolCast(activeItem.presentation_zoomText)}
+ onClick={() => {
+ activeItem.presentation_zoomText = !BoolCast(activeItem.presentation_zoomText);
+ }}
+ color={SnappingManager.userColor}
+ />
+ <Button text="Apply to all" type={Type.TERT} color={SnappingManager.userVariantColor} onClick={() => this.applyTo(this.childDocs)} />
</div>
</div>
- </div>
+ </>
);
}
+ return undefined;
}
@computed get mediaOptionsDropdown() {
- const activeItem = this.activeItem;
+ const { activeItem } = this;
if (activeItem && this.targetDoc) {
const renderTarget = PresBox.targetRenderedDoc(this.activeItem);
const clipStart = NumCast(renderTarget.clipStart);
const clipEnd = NumCast(renderTarget.clipEnd, clipStart + NumCast(renderTarget[Doc.LayoutFieldKey(renderTarget) + '_duration']));
- const config_clipEnd = NumCast(activeItem.config_clipEnd) < NumCast(activeItem.config_clipStart) ? clipEnd - clipStart : NumCast(activeItem.config_clipEnd);
+ const configClipEnd = NumCast(activeItem.config_clipEnd) < NumCast(activeItem.config_clipStart) ? clipEnd - clipStart : NumCast(activeItem.config_clipEnd);
return (
- <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="presBox-ribbon" onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div>
<div className="ribbon-box">
- Start {'&'} End Time
- <div className={'slider-headers'}>
+ Start & End Time
+ <div className="slider-headers">
<div className="slider-block">
<div className="slider-text" style={{ fontWeight: 500 }}>
Start time (s)
</div>
- <div id="startTime" className="slider-number" style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }}>
+ <div id="startTime" className="slider-number" style={{ color: SnappingManager.userColor, backgroundColor: SnappingManager.userBackgroundColor }}>
<input
className="presBox-input"
style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
type="number"
- readOnly={true}
+ readOnly
value={NumCast(activeItem.config_clipStart).toFixed(2)}
onKeyDown={e => e.stopPropagation()}
- onChange={action(e => (activeItem.config_clipStart = Number(e.target.value)))}
+ onChange={action(e => {
+ activeItem.config_clipStart = Number(e.target.value);
+ })}
/>
</div>
</div>
@@ -1898,23 +2282,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="slider-text" style={{ fontWeight: 500 }}>
Duration (s)
</div>
- <div className="slider-number" style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }}>
- {Math.round((config_clipEnd - NumCast(activeItem.config_clipStart)) * 10) / 10}
+ <div className="slider-number" style={{ color: SnappingManager.userColor, backgroundColor: SnappingManager.userBackgroundColor }}>
+ {Math.round((configClipEnd - NumCast(activeItem.config_clipStart)) * 10) / 10}
</div>
</div>
<div className="slider-block">
<div className="slider-text" style={{ fontWeight: 500 }}>
End time (s)
</div>
- <div id="endTime" className="slider-number" style={{ color: SettingsManager.userColor, backgroundColor: SettingsManager.userBackgroundColor }}>
+ <div id="endTime" className="slider-number" style={{ color: SnappingManager.userColor, backgroundColor: SnappingManager.userBackgroundColor }}>
<input
className="presBox-input"
onKeyDown={e => e.stopPropagation()}
style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
type="number"
- readOnly={true}
- value={config_clipEnd.toFixed(2)}
- onChange={action(e => (activeItem.config_clipEnd = Number(e.target.value)))}
+ readOnly
+ value={configClipEnd.toFixed(2)}
+ onChange={action(e => {
+ activeItem.config_clipEnd = Number(e.target.value);
+ })}
/>
</div>
</div>
@@ -1925,15 +2311,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
step="0.1"
min={clipStart}
max={clipEnd}
- value={config_clipEnd}
- style={{ gridColumn: 1, gridRow: 1, background: SettingsManager.userColor, color: SettingsManager.userVariantColor }}
+ value={configClipEnd}
+ style={{ gridColumn: 1, gridRow: 1, background: SnappingManager.userColor, color: SnappingManager.userVariantColor }}
className={`toolbar-slider ${'end'}`}
id="toolbar-slider"
onPointerDown={e => {
this._batch = UndoManager.StartBatch('config_clipEnd');
const endBlock = document.getElementById('endTime');
if (endBlock) {
- endBlock.style.backgroundColor = SettingsManager.userVariantColor;
+ endBlock.style.backgroundColor = SnappingManager.userVariantColor ?? '';
}
e.stopPropagation();
}}
@@ -1941,7 +2327,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._batch?.end();
const endBlock = document.getElementById('endTime');
if (endBlock) {
- endBlock.style.backgroundColor = SettingsManager.userBackgroundColor;
+ endBlock.style.backgroundColor = SnappingManager.userBackgroundColor ?? '';
}
}}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -1962,7 +2348,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._batch = UndoManager.StartBatch('config_clipStart');
const startBlock = document.getElementById('startTime');
if (startBlock) {
- startBlock.style.backgroundColor = SettingsManager.userVariantColor;
+ startBlock.style.backgroundColor = SnappingManager.userVariantColor ?? '';
}
e.stopPropagation();
}}
@@ -1970,7 +2356,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this._batch?.end();
const startBlock = document.getElementById('startTime');
if (startBlock) {
- startBlock.style.backgroundColor = SettingsManager.userBackgroundColor;
+ startBlock.style.backgroundColor = SnappingManager.userBackgroundColor ?? '';
}
}}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -1981,7 +2367,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
<div className="slider-headers">
<div className="slider-text">{clipStart.toFixed(2)} s</div>
- <div className="slider-text"></div>
+ <div className="slider-text" />
<div className="slider-text">{clipEnd.toFixed(2)} s</div>
</div>
</div>
@@ -1993,8 +2379,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<input
className="presBox-checkbox"
type="checkbox"
- style={{ border: `solid 1px ${SettingsManager.userColor}` }}
- onChange={() => (activeItem.presentation_mediaStart = 'manual')}
+ style={{ border: `solid 1px ${SnappingManager.userColor}` }}
+ onChange={() => {
+ activeItem.presentation_mediaStart = 'manual';
+ }}
checked={activeItem.presentation_mediaStart === 'manual'}
/>
<div>On click</div>
@@ -2002,9 +2390,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="checkbox-container">
<input
className="presBox-checkbox"
- style={{ border: `solid 1px ${SettingsManager.userColor}` }}
+ style={{ border: `solid 1px ${SnappingManager.userColor}` }}
type="checkbox"
- onChange={() => (activeItem.presentation_mediaStart = 'auto')}
+ onChange={() => {
+ activeItem.presentation_mediaStart = 'auto';
+ }}
checked={activeItem.presentation_mediaStart === 'auto'}
/>
<div>Automatically</div>
@@ -2016,8 +2406,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<input
className="presBox-checkbox"
type="checkbox"
- style={{ border: `solid 1px ${SettingsManager.userColor}` }}
- onChange={() => (activeItem.presentation_mediaStop = 'manual')}
+ style={{ border: `solid 1px ${SnappingManager.userColor}` }}
+ onChange={() => {
+ activeItem.presentation_mediaStop = 'manual';
+ }}
checked={activeItem.presentation_mediaStop === 'manual'}
/>
<div>At media end time</div>
@@ -2026,35 +2418,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<input
className="presBox-checkbox"
type="checkbox"
- style={{ border: `solid 1px ${SettingsManager.userColor}` }}
- onChange={() => (activeItem.presentation_mediaStop = 'auto')}
+ style={{ border: `solid 1px ${SnappingManager.userColor}` }}
+ onChange={() => {
+ activeItem.presentation_mediaStop = 'auto';
+ }}
checked={activeItem.presentation_mediaStop === 'auto'}
/>
<div>On slide change</div>
</div>
- {/* <div className="checkbox-container">
- <input className="presBox-checkbox"
- type="checkbox"
- onChange={() => activeItem.mediaStop = "afterSlide"}
- checked={activeItem.mediaStop === "afterSlide"}
- />
- <div className="checkbox-dropdown">
- After chosen slide
- <select className="presBox-viewPicker"
- style={{ opacity: activeItem.mediaStop === "afterSlide" && this.itemIndex !== this.childDocs.length - 1 ? 1 : 0.3 }}
- onPointerDown={e => e.stopPropagation()}
- onChange={this.mediaStopChanged}
- value={mediaStopDocStr}>
- {this.mediaStopSlides}
- </select>
- </div>
- </div> */}
</div>
</div>
</div>
</div>
);
}
+ return undefined;
}
@computed get newDocumentToolbarDropdown() {
return (
@@ -2118,9 +2496,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get newDocumentDropdown() {
return (
- <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="presBox-ribbon" onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div className="ribbon-box">
- Slide Title: <br></br>
+ Slide Title: <br />
<input
className="ribbon-textInput"
placeholder="..."
@@ -2129,16 +2507,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
onChange={e => {
e.stopPropagation();
e.preventDefault();
- runInAction(() => (this.title = e.target.value));
- }}></input>
+ runInAction(() => {
+ this.title = e.target.value;
+ });
+ }}
+ />
</div>
<div className="ribbon-box">
Choose type:
<div className="ribbon-doubleButton">
- <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ <div
+ title="Text"
+ className="ribbon-toggle"
+ style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }}
+ onClick={action(() => {
+ this.addFreeform = !this.addFreeform;
+ })}>
Text
</div>
- <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ <div
+ title="Freeform"
+ className="ribbon-toggle"
+ style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }}
+ onClick={action(() => {
+ this.addFreeform = !this.addFreeform;
+ })}>
Freeform
</div>
</div>
@@ -2146,23 +2539,49 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
Preset layouts:
<div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
- <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
- <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'blank';
+ })}
+ />
+ <div
+ className="layout"
+ style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'title';
+ })}>
<div className="title">Title</div>
<div className="subtitle">Subtitle</div>
</div>
- <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'header';
+ })}>
<div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
Section header
</div>
</div>
- <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'content';
+ })}>
<div className="title" style={{ alignSelf: 'center' }}>
Title
</div>
<div className="content">Text goes here</div>
</div>
- <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'twoColumns';
+ })}>
<div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
Title
</div>
@@ -2174,8 +2593,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
- <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
+ <div
+ className="open-layout"
+ onClick={action(() => {
+ this.openLayouts = !this.openLayouts;
+ })}>
+ <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon="caret-down" size="lg" />
</div>
</div>
<div className="ribbon-final-box">
@@ -2190,17 +2613,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
createNewSlide = (layout?: string, title?: string, freeform?: boolean) => {
- let doc = undefined;
+ let doc;
if (layout) doc = this.createTemplate(layout);
if (freeform && layout) doc = this.createTemplate(layout, title);
if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title });
if (doc) {
- const tabMap = CollectionDockingView.Instance?.tabMap;
- const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc;
- const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentation_targetDoc ?? tab;
+ const docTab = PresBox._getTabDocs().find(tdoc => tdoc.type === DocumentType.COL);
+ const presCollection = DocCast(DocumentView.getContextPath(this.activeItem).reverse().lastElement().presentation_targetDoc, docTab);
const data = Cast(presCollection?.data, listSpec(Doc));
- const config_data = Cast(this.Document.data, listSpec(Doc));
- if (data && config_data) {
+ const configData = Cast(this.Document.data, listSpec(Doc));
+ if (data && configData) {
data.push(doc);
this._props.pinToPres(doc, {});
this.gotoDocument(this.childDocs.length, this.activeItem);
@@ -2222,12 +2644,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const content2 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _text_fontSize: '14pt' });
// prettier-ignore
switch (layout) {
- case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
- case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
- case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
- case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
- case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y })
+ case 'blank': return Docs.Create.FreeformDocument([], { title: input || 'Blank slide', _width: 400, _height: 225, x, y });
+ case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input || 'Title slide', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
+ case 'header': return Docs.Create.FreeformDocument([header()], { title: input || 'Section header', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
+ case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input || 'Title and content', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y });
+ case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input || 'Title and two columns', _width: 400, _height: 225, _freeform_fitContentsToBox: true, x, y })
+ default:
}
+ return undefined;
};
// Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
@@ -2270,17 +2694,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@action
- toggleProperties = () => (SettingsManager.Instance.propertiesWidth = SettingsManager.Instance.propertiesWidth > 0 ? 0 : 250);
+ toggleProperties = () => {
+ SnappingManager.SetPropertiesWidth(SnappingManager.PropertiesWidth > 0 ? 0 : 250);
+ };
+
+ @action
+ openProperties = () => {
+ // need to also focus slide
+ SnappingManager.SetPropertiesWidth(250);
+ };
@computed get toolbar() {
- const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
- const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel';
+ const propIcon = SnappingManager.PropertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
+ const propTitle = SnappingManager.PropertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel';
const mode = StrCast(this.Document._type_collection) as CollectionViewType;
const isMini: boolean = this.toolbarWidth <= 100;
- const activeColor = SettingsManager.userVariantColor;
- const inactiveColor = lightOrDark(SettingsManager.userBackgroundColor) === Colors.WHITE ? Colors.WHITE : SettingsManager.userBackgroundColor;
+ const activeColor = SnappingManager.userVariantColor;
+ const inactiveColor = lightOrDark(SnappingManager.userBackgroundColor) === Colors.WHITE ? Colors.WHITE : SnappingManager.userBackgroundColor;
return mode === CollectionViewType.Carousel3D || Doc.IsInMyOverlay(this.Document) ? null : (
- <div id="toolbarContainer" className={'presBox-toolbar'}>
+ <div id="toolbarContainer" className="presBox-toolbar">
{/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
<FontAwesomeIcon icon={"plus"} />
<FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
@@ -2290,7 +2722,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }}
className="toolbar-button"
onClick={this.childDocs.length > 1 ? () => this.togglePath() : undefined}>
- <FontAwesomeIcon icon={'exchange-alt'} />
+ <FontAwesomeIcon icon="exchange-alt" />
</div>
</Tooltip>
{isMini ? null : (
@@ -2298,12 +2730,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="toolbar-divider" />
<Tooltip title={<div className="dash-tooltip">{this._presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>}>
<div className="toolbar-button" style={{ cursor: this._presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
- <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: this._presKeyEvents ? activeColor : inactiveColor }} />
+ <FontAwesomeIcon className="toolbar-thumbtack" icon="keyboard" style={{ color: this._presKeyEvents ? activeColor : inactiveColor }} />
</div>
</Tooltip>
<Tooltip title={<div className="dash-tooltip">{propTitle}</div>}>
<div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
- <FontAwesomeIcon className={'toolbar-thumbtack'} icon={propIcon} style={{ color: SettingsManager.Instance.propertiesWidth > 0 ? activeColor : inactiveColor }} />
+ <FontAwesomeIcon className="toolbar-thumbtack" icon={propIcon} style={{ color: SnappingManager.PropertiesWidth > 0 ? activeColor : inactiveColor }} />
</div>
</Tooltip>
</>
@@ -2348,7 +2780,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.gotoDocument(this.itemIndex, this.activeItem);
}
})}>
- <FontAwesomeIcon icon={'play-circle'} />
+ <FontAwesomeIcon icon="play-circle" />
<div style={{ display: this._props.PanelWidth() > 200 ? 'inline-flex' : 'none' }}>&nbsp; Present</div>
</div>
{mode === CollectionViewType.Carousel3D || isMini ? null : (
@@ -2357,7 +2789,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
onClick={action(() => {
if (this.childDocs.length) this._presentTools = !this._presentTools;
})}>
- <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this._presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
+ <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this._presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon="angle-down" />
{this.presentDropdown}
</div>
)}
@@ -2378,12 +2810,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Case 1: There are still other frames and should go through all frames before going to next slide
return (
<div className="presPanelOverlay" style={{ display: this.layoutDoc.presentation_status !== 'edit' ? 'inline-flex' : 'none' }}>
- <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
+ <Tooltip title={<div className="dash-tooltip">Loop</div>}>
<div
className="presPanel-button"
style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }}
- onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}>
- <FontAwesomeIcon icon={'redo-alt'} />
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ () => {
+ this.layoutDoc.presLoop = !this.layoutDoc.presLoop;
+ },
+ false,
+ false
+ )
+ }>
+ <FontAwesomeIcon icon="redo-alt" />
</div>
</Tooltip>
<div className="presPanel-divider" />
@@ -2408,7 +2852,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
false
)
}>
- <FontAwesomeIcon icon={'arrow-left'} />
+ <FontAwesomeIcon icon="arrow-left" />
</div>
<Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
<div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}>
@@ -2436,10 +2880,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
false
)
}>
- <FontAwesomeIcon icon={'arrow-right'} />
+ <FontAwesomeIcon icon="arrow-right" />
</div>
- <div className="presPanel-divider"></div>
- <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
+ <div className="presPanel-divider" />
+ <Tooltip title={<div className="dash-tooltip">Click to return to 1st slide</div>}>
<div
className="presPanel-button"
style={{ border: 'solid 1px white' }}
@@ -2463,7 +2907,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
{inOverlay ? '' : 'Slide'} {this.itemIndex + 1}
{this.activeItem?.presentation_indexed !== undefined ? `(${this.activeItem.presentation_indexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
</div>
- <div className="presPanel-divider"></div>
+ <div className="presPanel-divider" />
{this._props.PanelWidth() > 250 ? (
<div
className="presPanel-button-text"
@@ -2477,7 +2921,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
) : (
<div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.exitClicked, false, false)}>
- <FontAwesomeIcon icon={'times'} />
+ <FontAwesomeIcon icon="times" />
</div>
)}
</div>
@@ -2492,7 +2936,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
@action
- prevClicked = (e: PointerEvent) => {
+ prevClicked = () => {
this.back();
if (this._presTimer) {
clearTimeout(this._presTimer);
@@ -2501,7 +2945,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
@action
- nextClicked = (e: PointerEvent) => {
+ nextClicked = () => {
this.next();
if (this._presTimer) {
clearTimeout(this._presTimer);
@@ -2517,7 +2961,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
AddToMap = (treeViewDoc: Doc, index: number[]) => {
if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element.
- var indexNum = 0;
+ let indexNum = 0;
for (let i = 0; i < index.length; i++) {
indexNum += index[i] * 10 ** -i;
}
@@ -2529,19 +2973,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.dataDoc[this.presFieldKey] = new List<Doc>(sorted); // this is a flat array of Docs
}
}
+ return undefined;
};
SlideIndex = (slideDoc: Doc) => DocListCast(this.dataDoc[this.presFieldKey]).indexOf(slideDoc);
- RemFromMap = (treeViewDoc: Doc, index: number[]) => {
+ RemFromMap = (treeViewDoc: Doc) => {
if (!treeViewDoc.presentation_targetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element.
if (!this._unmounting && this.isTree) {
this._treeViewMap.delete(treeViewDoc);
this.dataDoc[this.presFieldKey] = new List<Doc>(this.sort(this._treeViewMap));
}
+ return undefined;
};
- sort = (treeView_Map: Map<Doc, number>) => [...treeView_Map.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]);
+ sort = (treeViewMap: Map<Doc, number>) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]);
render() {
// needed to ensure that the childDocs are loaded for looking up fields
@@ -2553,21 +2999,38 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
(this.activeItem.presentation_indexed === undefined || NumCast(this.activeItem.presentation_indexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0));
const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0;
return this._props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
- <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
+ <div
+ className="miniPres"
+ onClick={e => e.stopPropagation()}
+ onPointerEnter={action(() => {
+ this._forceKeyEvents = true;
+ })}>
<div
className="presPanelOverlay"
style={{ display: 'inline-flex', height: 30, background: Doc.ActivePresentation === this.Document ? 'green' : '#323232', top: 0, zIndex: 3000000, boxShadow: this._presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
- <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
+ <Tooltip title={<div className="dash-tooltip">Loop</div>}>
<div
className="presPanel-button"
style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
- onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}>
- <FontAwesomeIcon icon={'redo-alt'} />
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ returnFalse,
+ () => {
+ this.layoutDoc.presLoop = !this.layoutDoc.presLoop;
+ },
+ false,
+ false
+ )
+ }>
+ <FontAwesomeIcon icon="redo-alt" />
</div>
</Tooltip>
- <div className="presPanel-divider"></div>
+ <div className="presPanel-divider" />
<div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
- <FontAwesomeIcon icon={'arrow-left'} />
+ <FontAwesomeIcon icon="arrow-left" />
</div>
<Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presentation_status === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
<div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.startOrPause(true), false, false)}>
@@ -2575,10 +3038,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</Tooltip>
<div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}>
- <FontAwesomeIcon icon={'arrow-right'} />
+ <FontAwesomeIcon icon="arrow-right" />
</div>
- <div className="presPanel-divider"></div>
- <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
+ <div className="presPanel-divider" />
+ <Tooltip title={<div className="dash-tooltip">Click to return to 1st slide</div>}>
<div className="presPanel-button" style={{ border: 'solid 1px white' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>
<b>1</b>
</div>
@@ -2602,31 +3065,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="Slide">
{mode !== CollectionViewType.Invalid ? (
<CollectionView
+ // eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
PanelWidth={this._props.PanelWidth}
PanelHeight={this.panelHeight}
- childIgnoreNativeSize={true}
+ childIgnoreNativeSize
moveDocument={returnFalse}
- ignoreUnrendered={true}
+ ignoreUnrendered
childDragAction={dropActionType.move}
setContentViewBox={emptyFunction}
- //childLayoutFitWidth={returnTrue}
+ // childLayoutFitWidth={returnTrue}
childOpacity={returnOne}
childClickScript={PresBox.navigateToDocScript}
childLayoutTemplate={this.childLayoutTemplate}
childXPadding={Doc.IsComicStyle(this.Document) ? 20 : undefined}
filterAddDocument={this.addDocumentFilter}
removeDocument={returnFalse}
- dontRegisterView={true}
+ dontRegisterView
focus={this.focusElement}
ScreenToLocalTransform={this.getTransform}
AddToMap={this.AddToMap}
RemFromMap={this.RemFromMap}
- hierarchyIndex={emptyPath as any as number[]}
+ hierarchyIndex={emptyPath}
/>
) : null}
</div>
-
{/* {
// if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack
<Tooltip title={<div className="dash-tooltip">{'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}</div>}>
@@ -2636,11 +3099,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</Tooltip>
} */}
</div>
+ {/* presbox chatbox */}
+ {this.chatActive && <div className="presBox-chatbox" />}
</div>
);
}
}
+// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) {
PresBox.NavigateToTarget(bestTarget, activeItem);
});
+
+Docs.Prototypes.TemplateMap.set(DocumentType.PRES, {
+ layout: { view: PresBox, dataField: 'data' },
+ options: { acl: '', defaultDoubleClick: 'ignore', hideClickBehaviors: true, layout_hideLinkAnchors: true },
+});